Skip to content

Commit

Permalink
FIX: bitcoin model has a good fit, all others do not
Browse files Browse the repository at this point in the history
  • Loading branch information
bszek213 committed Jun 5, 2023
1 parent cc7bead commit 3d1e2ee
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 66 deletions.
Binary file added BCH_model.h5
Binary file not shown.
Binary file modified BTC_model.h5
Binary file not shown.
60 changes: 30 additions & 30 deletions BTC_pred.csv
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
pred,date
0.004028864,2023-05-11
0.008211962,2023-05-12
-0.0018429629,2023-05-13
0.012187836,2023-05-14
0.00871268,2023-05-15
0.0032500885,2023-05-16
0.004007733,2023-05-17
0.0021548618,2023-05-18
-0.0072371,2023-05-19
-0.004542134,2023-05-20
0.007893241,2023-05-21
0.004462952,2023-05-22
-0.0034028955,2023-05-23
-0.00042644888,2023-05-24
-0.0062668393,2023-05-25
-8.667154e-05,2023-05-26
0.0025053164,2023-05-27
0.0018349511,2023-05-28
-0.0014419118,2023-05-29
-0.0019848933,2023-05-30
0.0050445506,2023-05-31
-0.0015416909,2023-06-01
-0.00027406434,2023-06-02
0.00860453,2023-06-03
-0.0033413242,2023-06-04
-0.0029593213,2023-06-05
0.0025385763,2023-06-06
0.0055752923,2023-06-07
0.0035589128,2023-06-08
0.0050881156,2023-06-09
26684.455,2023-06-06
27196.402,2023-06-07
26558.908,2023-06-08
26092.266,2023-06-09
26824.906,2023-06-10
26762.963,2023-06-11
26639.43,2023-06-12
26979.488,2023-06-13
27048.166,2023-06-14
26505.604,2023-06-15
26570.623,2023-06-16
26059.28,2023-06-17
26676.938,2023-06-18
26578.068,2023-06-19
26608.857,2023-06-20
26432.084,2023-06-21
26420.959,2023-06-22
26136.01,2023-06-23
26279.582,2023-06-24
26366.021,2023-06-25
26089.229,2023-06-26
26236.379,2023-06-27
26274.172,2023-06-28
25796.844,2023-06-29
25903.676,2023-06-30
25920.299,2023-07-01
25629.947,2023-07-02
25829.39,2023-07-03
25678.662,2023-07-04
25482.604,2023-07-05
Binary file removed DOGE_model.h5
Binary file not shown.
Binary file modified ETH_model.h5
Binary file not shown.
Binary file modified LTC_model.h5
Binary file not shown.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
Deep learning, mainly LSTMs, for cryptocurrency with yfinance

Current MAPE on test data for different cryptocurrencies:
BTC: 127.45% error
BTC: 2.21% error
ETH: 184.52% error
DOGE: 307.97% error
DOGE: 245.15% error
TRX: 108.81% error
MANA: 171.94% error
LTC: 114.19% error
DOT: 105.18% error
BCH: 136.55% error

## Installation
```bash
Expand Down
Binary file modified TRX_model.h5
Binary file not shown.
131 changes: 97 additions & 34 deletions crypto_deep_many_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from tensorflow.keras.models import load_model
from datetime import datetime, timedelta
import os
from sklearn.metrics import mean_absolute_percentage_error, mean_squared_error
from sklearn.metrics import mean_absolute_percentage_error, mean_squared_error, r2_score
from colorama import Fore, Style
from sys import argv

Expand All @@ -24,13 +24,58 @@ def __init__(self, crypt, n_features, n_steps, n_outputs, n_epochs, batch_size):
temp = yf.Ticker(crypt_name)
price_data = temp.history(period = 'max', interval="1d")
print(Fore.GREEN,f'NUMBER OF SAMPLES FOR {crypt_name}: {len(price_data)}',Style.RESET_ALL)
self.features = ['Close', 'Low', 'High',
'momentum_stoch_rsi', 'trend_aroon_down', 'volume_vpt',
'volume_em', 'trend_aroon_up',
'volume_obv','volatility_bbp']
self.non_close_features = ['Low', 'High', 'momentum_stoch_rsi',
'trend_aroon_down', 'volume_vpt', 'volume_em',
'trend_aroon_up', 'volume_obv']
self.features = ['Close','Open', 'High', 'Low','Volume', 'Dividends', 'Stock Splits',
'volume_adi', 'volume_obv', 'volume_cmf', 'volume_fi', 'volume_em',
'volume_sma_em', 'volume_vpt', 'volume_vwap', 'volume_mfi',
'volume_nvi', 'volatility_bbm', 'volatility_bbh', 'volatility_bbl',
'volatility_bbw', 'volatility_bbp', 'volatility_bbhi',
'volatility_bbli', 'volatility_kcc', 'volatility_kch', 'volatility_kcl',
'volatility_kcw', 'volatility_kcp', 'volatility_kchi',
'volatility_kcli', 'volatility_dcl', 'volatility_dch', 'volatility_dcm',
'volatility_dcw', 'volatility_dcp', 'volatility_atr', 'volatility_ui',
'trend_macd', 'trend_macd_signal', 'trend_macd_diff', 'trend_sma_fast',
'trend_sma_slow', 'trend_ema_fast', 'trend_ema_slow',
'trend_vortex_ind_pos', 'trend_vortex_ind_neg', 'trend_vortex_ind_diff',
'trend_trix', 'trend_mass_index', 'trend_dpo', 'trend_kst',
'trend_kst_sig', 'trend_kst_diff', 'trend_ichimoku_conv',
'trend_ichimoku_base', 'trend_ichimoku_a', 'trend_ichimoku_b',
'trend_stc', 'trend_adx', 'trend_adx_pos', 'trend_adx_neg', 'trend_cci',
'trend_visual_ichimoku_a', 'trend_visual_ichimoku_b', 'trend_aroon_up',
'trend_aroon_down', 'trend_aroon_ind', 'trend_psar_up',
'trend_psar_down', 'trend_psar_up_indicator',
'trend_psar_down_indicator', 'momentum_rsi', 'momentum_stoch_rsi',
'momentum_stoch_rsi_k', 'momentum_stoch_rsi_d', 'momentum_tsi',
'momentum_uo', 'momentum_stoch', 'momentum_stoch_signal', 'momentum_wr',
'momentum_ao', 'momentum_roc', 'momentum_ppo', 'momentum_ppo_signal',
'momentum_ppo_hist', 'momentum_pvo', 'momentum_pvo_signal',
'momentum_pvo_hist', 'momentum_kama', 'others_dr', 'others_dlr',
'others_cr']
self.non_close_features = ['Open', 'High', 'Low','Volume', 'Dividends', 'Stock Splits',
'volume_adi', 'volume_obv', 'volume_cmf', 'volume_fi', 'volume_em',
'volume_sma_em', 'volume_vpt', 'volume_vwap', 'volume_mfi',
'volume_nvi', 'volatility_bbm', 'volatility_bbh', 'volatility_bbl',
'volatility_bbw', 'volatility_bbp', 'volatility_bbhi',
'volatility_bbli', 'volatility_kcc', 'volatility_kch', 'volatility_kcl',
'volatility_kcw', 'volatility_kcp', 'volatility_kchi',
'volatility_kcli', 'volatility_dcl', 'volatility_dch', 'volatility_dcm',
'volatility_dcw', 'volatility_dcp', 'volatility_atr', 'volatility_ui',
'trend_macd', 'trend_macd_signal', 'trend_macd_diff', 'trend_sma_fast',
'trend_sma_slow', 'trend_ema_fast', 'trend_ema_slow',
'trend_vortex_ind_pos', 'trend_vortex_ind_neg', 'trend_vortex_ind_diff',
'trend_trix', 'trend_mass_index', 'trend_dpo', 'trend_kst',
'trend_kst_sig', 'trend_kst_diff', 'trend_ichimoku_conv',
'trend_ichimoku_base', 'trend_ichimoku_a', 'trend_ichimoku_b',
'trend_stc', 'trend_adx', 'trend_adx_pos', 'trend_adx_neg', 'trend_cci',
'trend_visual_ichimoku_a', 'trend_visual_ichimoku_b', 'trend_aroon_up',
'trend_aroon_down', 'trend_aroon_ind', 'trend_psar_up',
'trend_psar_down', 'trend_psar_up_indicator',
'trend_psar_down_indicator', 'momentum_rsi', 'momentum_stoch_rsi',
'momentum_stoch_rsi_k', 'momentum_stoch_rsi_d', 'momentum_tsi',
'momentum_uo', 'momentum_stoch', 'momentum_stoch_signal', 'momentum_wr',
'momentum_ao', 'momentum_roc', 'momentum_ppo', 'momentum_ppo_signal',
'momentum_ppo_hist', 'momentum_pvo', 'momentum_pvo_signal',
'momentum_pvo_hist', 'momentum_kama', 'others_dr', 'others_dlr',
'others_cr']
self.n_features = len(self.features)
self.data = ta.add_all_ta_features(
price_data,
Expand All @@ -41,19 +86,24 @@ def __init__(self, crypt, n_features, n_steps, n_outputs, n_epochs, batch_size):
volume='Volume',
fillna=True
)
# print(self.data.columns)
print(self.data.columns)

def prepare_data(self, data):
# Extract relevant features
data = self.data[self.features]

# Scale data
# self.scaler1 = MinMaxScaler(feature_range=(0, 1))
self.scaler2 = MinMaxScaler(feature_range=(-1, 1))
# Scale data
data_close = data['Close'].pct_change().fillna(method='bfill').to_numpy().reshape(-1, 1)
# data_close = data[['Close']]
# data_close = self.scaler1.fit_transform(data_close)
self.scaler2 = MinMaxScaler(feature_range=(0, 1))
self.scaler1 = MinMaxScaler(feature_range=(0, 1))
# self.scaler2 = StandardScaler()
# self.scaler1 = StandardScaler()

# data_close = data['Close'].pct_change().fillna(method='bfill').to_numpy().reshape(-1, 1) #pct_change

#Close price
data_close = data['Close'].to_numpy().reshape(-1, 1) #close price
data_close = self.scaler1.fit_transform(data_close)

data_non_close = data[self.non_close_features]
data_non_close = self.scaler2.fit_transform(data_non_close)
data = np.concatenate((data_close, data_non_close), axis=1)
Expand All @@ -80,16 +130,16 @@ def create_model(self):
initial_learning_rate=0.01,
decay_steps=1000,
decay_rate=0.9,
staircase=True
# staircase=True
)
drop_val = 0.25
drop_val = 0.3
model = tf.keras.models.Sequential([
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(9, activation='relu',return_sequences=True, input_shape=(self.n_steps, self.n_features))),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Dropout(drop_val),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(8, activation='relu',return_sequences=True)),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(10, activation='relu',return_sequences=True, input_shape=(self.n_steps, self.n_features))),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Dropout(drop_val),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(5, activation='relu',return_sequences=False)),
# tf.keras.layers.BatchNormalization(),
# tf.keras.layers.Dropout(drop_val),
# tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(7, activation='relu',return_sequences=True,)),
# tf.keras.layers.BatchNormalization(),
# tf.keras.layers.Dropout(drop_val),
Expand All @@ -99,9 +149,10 @@ def create_model(self):
# tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(5, activation='relu',return_sequences=True,)),
# tf.keras.layers.BatchNormalization(),
# tf.keras.layers.Dropout(drop_val),
tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(4, activation='relu')),
# tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(4, activation='relu')),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Dense(self.n_outputs,activation="tanh")
# tf.keras.layers.Flatten(),
tf.keras.layers.Dense(self.n_outputs,activation="relu")
])
model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=lr_schedule),loss='mean_squared_error')
return model
Expand All @@ -117,6 +168,7 @@ def train_model(self, X_train, y_train, X_val, y_val):
batch_size=self.batch_size,
validation_data=(X_val, y_val),
callbacks=[es],
shuffle=False,
verbose=2)
model.summary()
self.model = model
Expand All @@ -129,32 +181,37 @@ def evaluate_model(self, X_test, y_test):

def predict(self, data):
#save data for test
test = data['Close'].pct_change().fillna(method='bfill').to_numpy().reshape(-1, 1)[-self.n_steps:]
# test = data['Close'].pct_change().fillna(method='bfill').to_numpy().reshape(-1, 1)[-self.n_steps:] #pct_change
test = data['Close'].to_numpy().reshape(-1, 1)[-self.n_steps:] #close
# Prepare data for prediction
data = data[self.features]
data_close = data['Close'].pct_change().fillna(method='bfill').to_numpy().reshape(-1, 1)
# data_close = data['Close'].pct_change().fillna(method='bfill').to_numpy().reshape(-1, 1) #pct_change
data_close = data['Close'].to_numpy().reshape(-1, 1) #close
data_close = self.scaler1.transform(data_close)
data_non_close = data[self.non_close_features]
# data_close = self.scaler1.transform(data_close)
data_non_close = self.scaler2.transform(data_non_close)
data = np.concatenate((data_close, data_non_close), axis=1)

#Predict the future after test data
if argv[2] == "test":
# Make prediction on test data
X_pred = np.array([data[-self.n_steps*2:-self.n_steps, :]])
#pct-change
# y_pred = self.model.predict(X_pred)
# y_pred = y_pred.flatten()
#close
y_pred = self.model.predict(X_pred)
y_pred = y_pred.flatten()
y_pred = self.scaler1.inverse_transform(y_pred)[0]

print(Fore.RED,y_pred,Style.RESET_ALL)
print(Fore.GREEN,test.flatten(),Style.RESET_ALL)
plt.hist(y_pred,color='r',alpha=0.3)
plt.hist(test.flatten(),color='g',alpha=0.3)
plt.show()
# y_pred = self.scaler1.inverse_transform(y_pred)[0]

#check accuracy of prediction
correct = 0
incorrect = 0
for test_val, pred_val in zip(test.flatten(),y_pred):
test_pct = np.diff(test.flatten())
y_pred_pct = np.diff(y_pred)
for test_val, pred_val in zip(test_pct,y_pred_pct):
if test_val < 0 and pred_val < 0:
correct += 1
elif test_val > 0 and pred_val > 0:
Expand All @@ -166,10 +223,15 @@ def predict(self, data):
print('=======================================')
print(Fore.YELLOW, f'MAPE test data: {round(mean_absolute_percentage_error(test.flatten(),y_pred)*100,2)} %',Style.RESET_ALL)
print(Fore.YELLOW, f'RMSE test data: {round(mean_squared_error(test.flatten(),y_pred,squared=False),10)}',Style.RESET_ALL)
print(Fore.YELLOW, "R2 score test data:", r2_score(test.flatten(),y_pred),Style.RESET_ALL)
print('=======================================')
print(Fore.GREEN,f'correct direction: {correct / (correct + incorrect)}',Style.RESET_ALL,
Fore.RED,f'incorrect direction: {incorrect / (correct + incorrect)}',Style.RESET_ALL)
print('=======================================')
plt.plot(y_pred,color='r',marker='*',alpha=0.3,label='pred')
plt.plot(test.flatten(),marker='*',color='g',alpha=0.3,label='test')
plt.legend()
plt.show()
# # Prepare data for prediction
# data = data[['Close', 'Low', 'High', 'MACD', 'RSI']]
# data = self.scaler.transform(data)
Expand All @@ -183,6 +245,7 @@ def predict(self, data):
else:
X_pred = np.array([data[-self.n_steps:, :]])
y_pred = self.model.predict(X_pred)
y_pred = self.scaler1.inverse_transform(y_pred)[0]
y_pred = y_pred.flatten()
print(Fore.GREEN,f'next {self.n_steps} days for {self.crypt_name}: {y_pred}',Style.RESET_ALL)

Expand All @@ -191,11 +254,11 @@ def predict(self, data):
def plot_results(self):
pred = pd.read_csv(f'{self.crypt_name}_pred.csv')
# plt.plot(self.data['Close'], label='Actual')
plt.plot(pred['date'],pred['pred'], label='Predicted')
plt.plot(pred['date'],pred['pred'], marker='*',label='Predicted')
plt.title(f'{self.crypt_name} Close Price Prediction')
plt.xlabel('Date')
plt.ylabel('Close Price (USD)')
plt.xticks(rotation=90)
plt.xticks(rotation=45)
plt.legend()
plt.show()

Expand Down

0 comments on commit 3d1e2ee

Please sign in to comment.