Uploaded Porject Files
Browse files- README.md +2 -2
- app.py +143 -0
- requirements.txt +8 -0
README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
---
|
2 |
title: CoinSage
|
3 |
-
emoji:
|
4 |
colorFrom: red
|
5 |
colorTo: gray
|
6 |
sdk: streamlit
|
@@ -9,4 +9,4 @@ app_file: app.py
|
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
-
|
|
|
1 |
---
|
2 |
title: CoinSage
|
3 |
+
emoji: 🪙
|
4 |
colorFrom: red
|
5 |
colorTo: gray
|
6 |
sdk: streamlit
|
|
|
9 |
pinned: false
|
10 |
---
|
11 |
|
12 |
+
# Coin Sage
|
app.py
ADDED
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import yfinance as yf
|
2 |
+
import os
|
3 |
+
|
4 |
+
import tensorflow as tf
|
5 |
+
|
6 |
+
import streamlit as st
|
7 |
+
|
8 |
+
import pandas as pd
|
9 |
+
import numpy as np
|
10 |
+
import matplotlib.pyplot as plt
|
11 |
+
import matplotlib as mpl
|
12 |
+
|
13 |
+
# from utils import StackLayer,BlockLayer
|
14 |
+
|
15 |
+
|
16 |
+
plt.style.use("dark_background")
|
17 |
+
mpl.rcParams['figure.facecolor'] = '#121212'
|
18 |
+
mpl.rcParams['axes.facecolor'] = '#121212'
|
19 |
+
mpl.rcParams['grid.color'] = 'gray'
|
20 |
+
mpl.rcParams['grid.linestyle'] = ':'
|
21 |
+
|
22 |
+
mpl.rcParams['text.color'] = 'white'
|
23 |
+
mpl.rcParams['axes.labelcolor'] = 'white'
|
24 |
+
mpl.rcParams['axes.edgecolor'] = 'white'
|
25 |
+
mpl.rcParams['xtick.color'] = 'white'
|
26 |
+
mpl.rcParams['ytick.color'] = 'white'
|
27 |
+
|
28 |
+
class BlockLayer(tf.keras.layers.Layer):
|
29 |
+
def __init__(self,lookback_period,horizon,n_layers,n_units,**kwargs):
|
30 |
+
super().__init__(**kwargs)
|
31 |
+
self.lookback_period=lookback_period
|
32 |
+
self.horizon=horizon
|
33 |
+
self.n_layers=n_layers
|
34 |
+
self.n_units=n_units
|
35 |
+
|
36 |
+
self.fully_connected=tf.keras.Sequential([tf.keras.layers.Dense(n_units,activation='relu') for _ in range(n_layers)],name="Fully_Connected_Layer")
|
37 |
+
self.theta_layer=tf.keras.layers.Dense(lookback_period+horizon,activation='linear',name="Theta_Layer")
|
38 |
+
|
39 |
+
def call(self,input):
|
40 |
+
|
41 |
+
x=self.fully_connected(input)
|
42 |
+
backcast_forecast=self.theta_layer(x)
|
43 |
+
|
44 |
+
backcast=backcast_forecast[:,:-self.horizon]
|
45 |
+
forecast=backcast_forecast[:,-self.horizon:]
|
46 |
+
|
47 |
+
return backcast,forecast
|
48 |
+
|
49 |
+
class StackLayer(tf.keras.layers.Layer):
|
50 |
+
def __init__(self,lookback_period,horizon,n_layers,n_units,num_blocks=4,**kwargs):
|
51 |
+
super().__init__(**kwargs)
|
52 |
+
self.num_blocks=num_blocks
|
53 |
+
self.horizon=horizon
|
54 |
+
self.first_block=BlockLayer(lookback_period=lookback_period,horizon=horizon,n_layers=n_layers,n_units=n_units,name="Initial_Block")
|
55 |
+
self.block_list=[BlockLayer(lookback_period=lookback_period,horizon=horizon,n_layers=n_layers,n_units=n_units,name=f"Block_{i}") for i in range(1,num_blocks)]
|
56 |
+
|
57 |
+
def call(self,input):
|
58 |
+
|
59 |
+
block_backcast,block_forecast=self.first_block(input)
|
60 |
+
stack_forecast_residual=tf.zeros(shape=(self.horizon),dtype=tf.float32)
|
61 |
+
stack_forecast_residual=tf.expand_dims(stack_forecast_residual,axis=0)
|
62 |
+
stack_forecast_residual=tf.keras.layers.Add()([stack_forecast_residual,block_forecast])
|
63 |
+
stack_backcast_residual=tf.keras.layers.Subtract()([input,block_backcast])
|
64 |
+
|
65 |
+
for block in self.block_list:
|
66 |
+
block_backcast,block_forecast=block(stack_backcast_residual)
|
67 |
+
stack_forecast_residual=tf.keras.layers.Add()([block_forecast,stack_forecast_residual])
|
68 |
+
stack_backcast_residual=tf.keras.layers.Subtract()([stack_backcast_residual,block_backcast])
|
69 |
+
|
70 |
+
return stack_backcast_residual,stack_forecast_residual
|
71 |
+
|
72 |
+
def initialize_session():
|
73 |
+
if "yesterday" not in st.session_state:
|
74 |
+
st.session_state.yesterday="Available"
|
75 |
+
|
76 |
+
def load_data():
|
77 |
+
BTC_ticker=yf.Ticker("BTC-USD")
|
78 |
+
BT_data=BTC_ticker.history(period="1wk")
|
79 |
+
df=pd.DataFrame({"Close":BT_data["Close"]})
|
80 |
+
if len(df)<=7:
|
81 |
+
st.session_state.yesterday="Not Available"
|
82 |
+
st.error("Yesterday's Price has not yet been updated. Please come back later to predict the price of Bitcoin tomorrow.")
|
83 |
+
else:
|
84 |
+
st.session_state.yesterday="Available"
|
85 |
+
return df[-7:]
|
86 |
+
|
87 |
+
@st.cache_data
|
88 |
+
def load_results():
|
89 |
+
app_directory = os.path.dirname(os.path.abspath(__file__))
|
90 |
+
results_path = os.path.join(app_directory, 'Results.csv')
|
91 |
+
results=pd.read_csv(results_path)
|
92 |
+
results.rename(columns={"Unnamed: 0":"Model"},inplace=True)
|
93 |
+
return results
|
94 |
+
|
95 |
+
@st.cache_resource(show_spinner=False)
|
96 |
+
def load_model():
|
97 |
+
app_directory = os.path.dirname(os.path.abspath(__file__))
|
98 |
+
model_path = os.path.join(app_directory, 'final_n_beats_v1')
|
99 |
+
model = tf.keras.models.load_model(model_path,custom_objects={"BlockLayer":BlockLayer,
|
100 |
+
"StackLayer":StackLayer})
|
101 |
+
return model
|
102 |
+
|
103 |
+
|
104 |
+
df=load_data()
|
105 |
+
info=st.container()
|
106 |
+
|
107 |
+
with info:
|
108 |
+
st.header("CoinSage")
|
109 |
+
st.subheader("How It Works ?🤔")
|
110 |
+
st.markdown("CoinSage uses the [NBeats](https://arxiv.org/abs/1905.10437) , a pure Deep Learning Model created by ElementAI that won the M4 Competition. The model uses a Stack of Blocks with residual connections (to prevent overfitting), where each Block consists of Fully Connected Layers. I have trained the model on closing Bitcoin Prices of the Last Five Years, with a window of 7 (it predicts the price of the BitCoin tomorrow using the prices of BitCoin in the previous week) starting from July 2nd,2018 till July 1st 2023. The model acheived a stunning MAE of 400 USD of the Test Set. However, since forecasting the price of BitCoin is linked with Aleatory Uncertainty, the model is not expected to be 100% accurate and we recommed to you not heavily rely on the model's predictions but rather use it as a reference. I am constantly working on finding better models to deal with Aleatory Uncertainty and Im currently working on understanding Bayesian Neural Networks. I will update the app once I build and test the model.")
|
111 |
+
st.subheader("Other Models I Trained")
|
112 |
+
st.markdown("In the process of creating this app, I have trained other Deep Learning Models suchs as DNNs, CNNs, LSTMs and also an Ensemble of DNNs trained on different loss functions. However (although not by much), I have found that NBeats outperforms all of them. The below plot shows the MAE of the different models on the Test Set.")
|
113 |
+
results=load_results()
|
114 |
+
fig,ax=plt.subplots(figsize=(15,12))
|
115 |
+
ax=plt.bar(results["Model"],results["MAE"],width=0.3,label="MAE",color=(0.1,0.6,0.6,0.9))
|
116 |
+
for i in range(len(results["Model"])):
|
117 |
+
plt.text(i,results["MAE"][i]+2,round(results["MAE"][i],2),ha="center",fontsize=13)
|
118 |
+
plt.xticks(rotation=90,fontsize=15)
|
119 |
+
plt.xlabel("Model",fontsize=15)
|
120 |
+
plt.ylabel("MAE (in USD)",fontsize=15)
|
121 |
+
plt.title("MAE of Different Models",fontsize=20)
|
122 |
+
st.pyplot(fig)
|
123 |
+
|
124 |
+
col1,col2,col3=st.columns(3)
|
125 |
+
if st.session_state.yesterday=="Available":
|
126 |
+
if col2.button("Predict Tomorrow's Bitcoin"):
|
127 |
+
fig, ax = plt.subplots(figsize=(10,7))
|
128 |
+
ax=plt.plot(df["Close"])
|
129 |
+
ax=plt.title("BTC-USD Closing Prices For Last Week")
|
130 |
+
ax=plt.xlabel("Date")
|
131 |
+
ax=plt.ylabel("Price(USD)")
|
132 |
+
st.pyplot(fig)
|
133 |
+
with st.spinner("Loading Model..."):
|
134 |
+
model=load_model()
|
135 |
+
st.success("Model Loaded Successfully!!")
|
136 |
+
with st.spinner("Predicting..."):
|
137 |
+
prediction=model.predict(df["Close"].values.reshape(1,7))
|
138 |
+
st.success("Prediction Done!!")
|
139 |
+
st.subheader(f"Tomorrow's Bitcoin Price is expected to be {prediction[0][0]:.2f} USD")
|
140 |
+
|
141 |
+
|
142 |
+
|
143 |
+
|
requirements.txt
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
tensorflow
|
3 |
+
|
4 |
+
pandas
|
5 |
+
numpy
|
6 |
+
matplotlib
|
7 |
+
|
8 |
+
yfinance
|