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
|