{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## G-Research Cryptocurrencies : Models","metadata":{}},{"cell_type":"markdown","source":"### 1. Imports & Preprocessing","metadata":{}},{"cell_type":"code","source":"# system libraries\nimport glob\nimport warnings\nwarnings.filterwarnings('ignore')\nwarnings.simplefilter(action='ignore', category=FutureWarning)\nimport gc\n\n# data manipulation libraries\nimport pandas as pd\nimport numpy as np\n\n# graphical libraries\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport plotly.express as px\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\n\n# modelisation libraries\nfrom sklearn.preprocessing import OneHotEncoder, StandardScaler, MinMaxScaler\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.impute import SimpleImputer\nfrom sklearn.pipeline import Pipeline\nfrom sklearn.compose import ColumnTransformer\nfrom sklearn.linear_model import LinearRegression\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.metrics import mean_absolute_error, mean_squared_error, mean_absolute_percentage_error\nfrom keras.models import Sequential\nfrom keras.layers import Dense, LSTM, Dropout, GRU, Bidirectional\nimport tensorflow as tf\nfrom sklearn.metrics import mean_squared_error\nfrom keras.callbacks import ModelCheckpoint\nfrom livelossplot import PlotLossesKeras\nfrom statsmodels.tsa.seasonal import seasonal_decompose","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def regression_metrics(y_test, y_pred):\n    \"\"\"Function which contains differents metrics about regression\n    Input: y_test, prediction\n    \n    Output: MAE, MSE, RMSE & MAPE \n    \"\"\"\n    mae = mean_absolute_error(y_test, y_pred)\n    mse = mean_squared_error(y_test, y_pred)\n    rmse = np.sqrt(mse)\n    mape = mean_absolute_percentage_error(y_test, y_pred)\n    print(\"MAE: \",mae.round(5))\n    print(\"MSE: \", mse.round(5))\n    print(\"RMSE: \", rmse)\n    print(\"MAPE: \", mape.round(5))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATA_PATH = 'g-research-crypto-forecasting/prep'","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_files = glob.glob(DATA_PATH + \"/*.parquet.gzip\")\n\nli = []\n\nfor filename in all_files:\n    df = pd.read_parquet(filename)\n    li.append(df)\n\nmerged_df = pd.concat(li,\n                  axis=0,\n                  ignore_index=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(merged_df)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del li, all_files\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"merged_df.fillna(0, inplace=True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"merged_df.drop([\"vwap\", \"count\",\n          \"open\", \"close\", \"high\",\n          \"low\", \"volume\", \"log_open\",\n          \"log_close\",\n          \"log_low\", \"log_high\",\n          \"vwap\", \"count\",\n          \"open\", \"close\", \"high\",\n          \"low\", \"volume\", \"log_open\",\n          \"log_close\", \"log_low\",\n          \"log_high\"],\n          axis=1, inplace=True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"merged_df = merged_df.sort_index()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y = merged_df[\"target\"].values\nX = merged_df.drop(\"target\", axis=1)\n\nX_train, X_test, y_train, y_test = train_test_split(X, y, \n                                                    train_size=0.7,\n                                                    random_state=42,\n                                                    shuffle = False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.DataFrame(X_train).nunique()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_timestamp = X_train.index","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_timestamp","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_test","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_train","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_test","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del X,\\\n    y,\\\n    merged_df\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"idx = X_test.index","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cat_var = [\"asset_name\"]\nnum_var = [\"H-L\", \"O-C\", \"MA_7d\",\n           \"MA_14d\", \"MA_21d\", \"STD_7d\"]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cat_pipe = Pipeline([\n    ('encoder', OneHotEncoder())\n])\n\nnum_pipe = Pipeline([\n    ('impute', SimpleImputer(strategy=\"mean\")),\n    ('scaler', StandardScaler())\n])\n\npreprocessing_pipe = ColumnTransformer(\n    transformers=[\n    (\"cat\", cat_pipe, cat_var),\n    ('num', num_pipe, num_var)\n])","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train = preprocessing_pipe.fit_transform(X_train)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 2. Modelisation","metadata":{}},{"cell_type":"markdown","source":"#### 2.1 Linear Regression","metadata":{}},{"cell_type":"code","source":"lin_reg = LinearRegression()\nlin_reg.fit(X_train, y_train)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_test","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_test = preprocessing_pipe.transform(X_test)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = lin_reg.predict(X_test)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"regression_metrics(y_test, y_pred)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.DataFrame(y_pred).index = idx","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Visualizing the results for Linear reg\nfig = go.Figure()\nfig.add_trace(go.Scatter(x=pd.DataFrame(y_test).index, y=y_test,\n                    mode='lines',\n                    name='True'))\nfig.add_trace(go.Scatter(x=pd.DataFrame(y_pred).index, y=y_pred,\n                    mode='lines',\n                    name='Predicted'))\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del y_pred, lin_reg\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### 2.2 Random Forest","metadata":{}},{"cell_type":"code","source":"rf_reg = RandomForestRegressor(random_state=42)\nrf_reg.fit(X_train, y_train)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = rf_reg.predict(X_test)\nregression_metrics(y_test, y_pred)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Visualizing the results for Linear reg\nfig = go.Figure()\nfig.add_trace(go.Scatter(x=pd.DataFrame(y_test).index, y=y_test,\n                    mode='lines',\n                    name='True'))\nfig.add_trace(go.Scatter(x=pd.DataFrame(y_pred).index, y=y_pred,\n                    mode='lines',\n                    name='Predicted'))\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del y_pred,\\\n    rf_reg\ngc.collect()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### 2.3 LSTM","metadata":{}},{"cell_type":"code","source":"# Some functions to help out with\ndef plot_predictions(test,predicted):\n    fig = px.line(x=test.index(), y=\"Close\")\n    #fig.add_trace(px.line(predicted))\n    fig.show()\n\ndef return_rmse(test,predicted):\n    rmse = math.sqrt(mean_squared_error(test, predicted))\n    print(\"The root mean squared error is {}.\".format(rmse))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_train[60]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Since LSTMs store long term memory state, we create a data structure with 60 timesteps and 1 output\n# So for each element of training set, we have 60 previous training set elements\nhistory_points = 5\nX_train_lstm = []\ny_train_lstm = []\nfor i in range(history_points*14,X_train.shape[0]):\n    X_train_lstm.append(X_train[i-history_points:i,0])\n    y_train_lstm.append(y_train[i])\nX_train_lstm, y_train_lstm = np.array(X_train_lstm), np.array(y_train_lstm)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# The LSTM architecture\nregressor = Sequential()\n\n# First LSTM layer with Dropout regularisation\nregressor.add(LSTM(units=32, return_sequences=True, input_shape=(X_train.shape[1],1)))\nregressor.add(Dropout(0.3))\n# Fifth LSTM layer\nregressor.add(LSTM(units=32, return_sequences=False))\nregressor.add(Dropout(0.3))\n# The output layer\nregressor.add(Dense(units=1))\n\n# Compiling the RNN\nregressor.compile(optimizer='adam',loss='mean_squared_error')\nfilepath = \"model.h5\"\nplotloss_cb = PlotLossesKeras()\ncheckpoint = ModelCheckpoint(filepath, monitor=\"loss\", verbose=2, save_best_only=True, mode='min')\ncallbacks_list = [checkpoint, plotloss_cb]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\nhistory = regressor.fit(\n    X_train,\n    y_train,\n    shuffle = False,\n    callbacks = callbacks_list,\n    batch_size = 32,\n    validation_split = 0.2,\n    verbose = 1, epochs = 50)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = regressor.predict(X_test).flatten()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"regression_metrics(y_pred, y_test)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Visualizing the results for LSTM\nfig = go.Figure()\nfig.add_trace(go.Scatter(x=pd.DataFrame(y_test).index, y=y_test,\n                    mode='lines',\n                    name='True'))\nfig.add_trace(go.Scatter(x=pd.DataFrame(y_pred).index, y=y_pred,\n                    mode='lines',\n                    name='Predicted'))","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"error = y_pred - y_test\nplt.hist(error, bins=100)\nplt.xlabel('Prediction Error [USD]')\n_ = plt.ylabel('Count')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### 2.4 Statistical Methods (SARIMA)","metadata":{}},{"cell_type":"markdown","source":"##### 2.4.1 Seasonal Decomposition","metadata":{}},{"cell_type":"code","source":"X_train = pd.DataFrame(X_train)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train.index = train_timestamp","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"X_train.resample('M').mean()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#function to plot\nplt.rcParams[\"figure.figsize\"]=(15,7)\n\ndef season_df(data,label,time):\n    df = data.resample(time).mean()\n    \n    seasonal_decompose(df[15]).plot()\n    print(label)\n    return plt.show()\n\nseason_df(X_train, \"Seasonal Decomposition\", 'M')\nseason_df(X_train, \"Seasonal Decomposition\", 'D')\nseason_df(X_train, \"Seasonal Decomposition\", 'H')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from scipy import stats\nfrom itertools import product\nimport warnings\nfrom statsmodels.tsa.statespace.sarimax import SARIMAX","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hourly = X_train.resample('H').mean()\ndaily = X_train.resample('D').mean()\nmonthly = X_train.resample('M').mean()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hourly.head(5)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hourly = hourly.rename(columns={15: \"O-C\"})\ndaily = daily.rename(columns={15: \"O-C\"})\nmonthly = monthly.rename(columns={15: \"O-C\"})","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def sarimax_function(df):\n    qs = range(0, 3)\n    ps = range(0, 3)\n    d=1\n    parameters = product(ps, qs)\n    parameters_list = list(parameters)\n    len(parameters_list)\n\n    # Model Selection\n    results = []\n    best_aic = float(\"inf\")\n    warnings.filterwarnings('ignore')\n    for param in parameters_list:\n        try:\n            model = SARIMAX(df['O-C'], order=(param[0], d, param[1])).fit(disp=-1)\n        except ValueError:\n            print('bad parameter combination:', param)\n            continue\n        aic = model.aic\n        if aic < best_aic:\n            best_model = model\n            best_aic = aic\n            best_param = param\n        results.append([param, model.aic])\n\n    result_table = pd.DataFrame(results)\n    result_table.columns = ['parameters', 'aic']\n    print(result_table.sort_values(by = 'aic', ascending=True).head())\n    print(best_model.summary())\n    return best_model\n    ","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"hrmodel = sarimax_function(hourly)\nhrmodel.plot_diagnostics(figsize=(15, 12))\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dymodel = sarimax_function(daily)\ndymodel.plot_diagnostics(figsize=(15, 12))\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mtmodel = sarimax_function(monthly)\nmtmodel.plot_diagnostics(figsize=(15, 12))\nplt.show()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_true_sarimax = y_test.copy()\ny_true_sarimax = pd.DataFrame(y_true_sarimax)\ny_true_sarimax.index = idx\ny_true_sarimax = y_true_sarimax.resample('H').mean()","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_true_sarimax","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_sarimax = hrmodel.predict(start = '2020-08-30 23:00:00', end = '2021-09-20 23:00:00', dynamic = True)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred_sarimax","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"regression_metrics(y_pred_sarimax, y_true_sarimax)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Visualizing the results for Linear reg\nfig = go.Figure()\nfig.add_trace(go.Scatter(x=pd.DataFrame(y_pred_sarimax).index, y=y_true_sarimax[0],\n                    mode='lines',\n                    name='True'))\nfig.add_trace(go.Scatter(x=pd.DataFrame(y_pred_sarimax).index, y=y_pred_sarimax,\n                    mode='lines',\n                    name='Predicted'))","metadata":{},"execution_count":null,"outputs":[]}]}