{"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":"# Let's discover our data\n\nTo forecast cryptocurrency prices, we should use all the trading features like price, volume, open, high, low values which are presents in the dataset.\n\n* Close Price — It is the market close price for currency for that particular day.\n* High Price — It is highest price of currency for the day.\n* Low Price — It is the lowest price for currency for that day.\n* Open Price — It is market open price for currency for that day.\n* Volume — The volume of currency that is being in trade for that day.","metadata":{}},{"cell_type":"code","source":"# Import necessary libraries\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import mean_absolute_error\nimport gc\nimport gresearch_crypto\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\n# Constants definition\nDATA_PATH = \"../input/g-research-crypto-forecasting/train.csv\"\nASSET_DETAILS = \"../input/g-research-crypto-forecasting/asset_details.csv\"","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:04:14.500439Z","iopub.execute_input":"2022-01-23T14:04:14.501281Z","iopub.status.idle":"2022-01-23T14:04:15.564140Z","shell.execute_reply.started":"2022-01-23T14:04:14.501175Z","shell.execute_reply":"2022-01-23T14:04:15.563327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Some EDA and visualizations","metadata":{}},{"cell_type":"code","source":"# Read train data\nraw_data = pd.read_csv(DATA_PATH)\nraw_data.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:04:15.566014Z","iopub.execute_input":"2022-01-23T14:04:15.566250Z","iopub.status.idle":"2022-01-23T14:05:10.831563Z","shell.execute_reply.started":"2022-01-23T14:04:15.566222Z","shell.execute_reply":"2022-01-23T14:05:10.830526Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Read asset information (containing more details about each cryptocurrency)\nasset_data = pd.read_csv(ASSET_DETAILS)\nasset_data.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:10.833313Z","iopub.execute_input":"2022-01-23T14:05:10.833879Z","iopub.status.idle":"2022-01-23T14:05:10.856584Z","shell.execute_reply.started":"2022-01-23T14:05:10.833822Z","shell.execute_reply":"2022-01-23T14:05:10.855588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Let's join them on Asset_ID\ndata = pd.merge(raw_data, asset_data, on='Asset_ID', how='inner')\ndata.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:10.860531Z","iopub.execute_input":"2022-01-23T14:05:10.861463Z","iopub.status.idle":"2022-01-23T14:05:15.457298Z","shell.execute_reply.started":"2022-01-23T14:05:10.861415Z","shell.execute_reply":"2022-01-23T14:05:15.456515Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# For the visualization we'll only use the bitcoin Cash (which have an asset_id = 2)\nbitcoin_cash_data = data.loc[data['Asset_ID'] == 2][-10000:]","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:15.458807Z","iopub.execute_input":"2022-01-23T14:05:15.459668Z","iopub.status.idle":"2022-01-23T14:05:17.898029Z","shell.execute_reply.started":"2022-01-23T14:05:15.459618Z","shell.execute_reply":"2022-01-23T14:05:17.897024Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(len(bitcoin_cash_data))\nbitcoin_cash_data.head()","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:17.899443Z","iopub.execute_input":"2022-01-23T14:05:17.899824Z","iopub.status.idle":"2022-01-23T14:05:17.918614Z","shell.execute_reply.started":"2022-01-23T14:05:17.899781Z","shell.execute_reply":"2022-01-23T14:05:17.917750Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Let's see the pattern of each feature individually\ndef plot_features(df):\n    fig, axs = plt.subplots(3, 2)\n    fig.set_size_inches(18.5, 10.5)\n    axs[0, 0].plot(df[\"timestamp\"], df[\"Open\"], 'tab:blue')\n    axs[0, 0].set_title('Open')\n    axs[0, 1].plot(df[\"timestamp\"], df[\"High\"], 'tab:orange')\n    axs[0, 1].set_title('High')\n    axs[1, 0].plot(df[\"timestamp\"], df[\"Low\"], 'tab:green')\n    axs[1, 0].set_title('Low')\n    axs[1, 1].plot(df[\"timestamp\"], df[\"Close\"], 'tab:red')\n    axs[1, 1].set_title('Close')\n    axs[2, 0].plot(df[\"timestamp\"], df[\"Volume\"], 'tab:red')\n    axs[2, 0].set_title('Volume')\n    axs[2, 1].plot(df[\"timestamp\"], df[\"VWAP\"], 'tab:red')\n    axs[2, 1].set_title('VWAP')","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:17.919991Z","iopub.execute_input":"2022-01-23T14:05:17.920221Z","iopub.status.idle":"2022-01-23T14:05:17.932162Z","shell.execute_reply.started":"2022-01-23T14:05:17.920193Z","shell.execute_reply":"2022-01-23T14:05:17.931137Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_features(bitcoin_cash_data)","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:17.933542Z","iopub.execute_input":"2022-01-23T14:05:17.934345Z","iopub.status.idle":"2022-01-23T14:05:18.908853Z","shell.execute_reply.started":"2022-01-23T14:05:17.934300Z","shell.execute_reply":"2022-01-23T14:05:18.908143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot the evolution of bitcoin cash\ndef evolution_split(df, test_size=0.2):\n    split_row = len(df) - int(test_size * len(df))\n    train_data = df.iloc[:split_row]\n    test_data = df.iloc[split_row:]\n    return train_data, test_data\ntrain, test = evolution_split(bitcoin_cash_data, test_size=0.2)\n\ndef plot_evolution(x1, x2, line1, line2, label1=None, label2=None, title='', lw=2):\n    fig, ax = plt.subplots(1, figsize=(13, 7))\n    ax.plot(x1, line1, label=label1, linewidth=lw)\n    ax.plot(x2, line2, label=label2, linewidth=lw)\n    ax.set_ylabel('Target', fontsize=14)\n    ax.set_title(title, fontsize=16)\n    ax.legend(loc='best', fontsize=16)\nplot_evolution(train[\"timestamp\"], test[\"timestamp\"], train[\"Target\"], test[\"Target\"], 'training', 'test', title='')","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:18.909768Z","iopub.execute_input":"2022-01-23T14:05:18.910274Z","iopub.status.idle":"2022-01-23T14:05:19.207474Z","shell.execute_reply.started":"2022-01-23T14:05:18.910241Z","shell.execute_reply":"2022-01-23T14:05:19.206647Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prepare features","metadata":{}},{"cell_type":"code","source":"def get_features(df):\n    df_feat = df[['Count', 'Open', 'High', 'Low', 'Close', 'Volume', 'VWAP']].copy()\n    df_feat['Upper_Shadow'] = df_feat['High'] - np.maximum(df_feat['Close'], df_feat['Open'])\n    df_feat['Lower_Shadow'] = np.minimum(df_feat['Close'], df_feat['Open']) - df_feat['Low']\n    \n    df_feat['lower_shadow'] = np.minimum(df_feat['Close'], df_feat['Open']) - df_feat['Low']\n    df_feat['high2low'] = df_feat['High'] / df_feat['Low']\n    df_feat['volume2count'] = df_feat['Volume'] / (df_feat['Count'] + 1)\n    \n    return df_feat","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:19.209491Z","iopub.execute_input":"2022-01-23T14:05:19.210167Z","iopub.status.idle":"2022-01-23T14:05:19.216023Z","shell.execute_reply.started":"2022-01-23T14:05:19.210130Z","shell.execute_reply":"2022-01-23T14:05:19.215349Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_data_for_asset(df_train, asset_id):\n   \n    df = df_train[df_train[\"Asset_ID\"] == asset_id]    \n    df_proc = get_features(df)\n    df_proc['y'] = df['Target']\n    df_proc = df_proc.dropna(how=\"any\")\n    \n    X = df_proc.drop(\"y\", axis=1)\n    y = df_proc[\"y\"]\n    \n    return X, y","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:19.216947Z","iopub.execute_input":"2022-01-23T14:05:19.217428Z","iopub.status.idle":"2022-01-23T14:05:19.228607Z","shell.execute_reply.started":"2022-01-23T14:05:19.217380Z","shell.execute_reply":"2022-01-23T14:05:19.227960Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Experiment some regression models","metadata":{}},{"cell_type":"code","source":"from sklearn.linear_model import LinearRegression\nfrom sklearn.ensemble import RandomForestRegressor\nfrom sklearn.tree import DecisionTreeRegressor\nfrom xgboost import XGBRegressor\nfrom lightgbm import LGBMRegressor","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:19.229712Z","iopub.execute_input":"2022-01-23T14:05:19.230324Z","iopub.status.idle":"2022-01-23T14:05:20.585802Z","shell.execute_reply.started":"2022-01-23T14:05:19.230289Z","shell.execute_reply":"2022-01-23T14:05:20.584920Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"benchmarking_models = {\n    \"lr\": LinearRegression(),\n    \"dt\": DecisionTreeRegressor(max_depth=2),\n    \"rf\": RandomForestRegressor(n_estimators = 2000, random_state = 42),\n    \"xgboost\": XGBRegressor(n_estimators=2000, max_depth=7, eta=0.1, subsample=0.7, colsample_bytree=0.8),\n    \"lgbm\": LGBMRegressor(n_estimators=2000, num_leaves=500, learning_rate=0.1)\n}","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:20.587014Z","iopub.execute_input":"2022-01-23T14:05:20.587232Z","iopub.status.idle":"2022-01-23T14:05:20.593056Z","shell.execute_reply.started":"2022-01-23T14:05:20.587206Z","shell.execute_reply":"2022-01-23T14:05:20.592157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def model_training(X,y, model_name):\n    # Model training\n    model = benchmarking_models[model_name]\n    model.fit(X, y)\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:05:20.594097Z","iopub.execute_input":"2022-01-23T14:05:20.594294Z","iopub.status.idle":"2022-01-23T14:05:20.606996Z","shell.execute_reply.started":"2022-01-23T14:05:20.594270Z","shell.execute_reply":"2022-01-23T14:05:20.606432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nXs = {}\nys = {}\nmodels = {}\nmodel_name = \"lgbm\" # You can switch to any other model\n\nfor asset_id, asset_name in zip(asset_data['Asset_ID'], asset_data['Asset_Name']):\n    print(f\"Training model for {asset_name:<16} (ID={asset_id:<2})\")\n    X, y = get_data_for_asset(raw_data, asset_id)\n    X_train, X_test, y_train, y_test = train_test_split(X, y.tolist(), test_size=0.2)   \n    model = model_training(X_train,y_train, model_name)\n    Xs[asset_id], ys[asset_id], models[asset_id] = X, y, model\n    preds = model.predict(X_test).squeeze()\n    print(\"MAE of \" +model_name + \"on \" + asset_name+ \"dataset: \", mean_absolute_error(preds, y_test))\n    gc.collect()","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:13:06.285240Z","iopub.execute_input":"2022-01-23T14:13:06.286204Z","iopub.status.idle":"2022-01-23T14:43:35.917853Z","shell.execute_reply.started":"2022-01-23T14:13:06.286158Z","shell.execute_reply":"2022-01-23T14:43:35.916848Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"# Prediction and submission\nenv = gresearch_crypto.make_env()\niter_test = env.iter_test()\n\nfor i, (df_test, df_pred) in enumerate(iter_test):\n    for j, row in df_test.iterrows():\n        \n        try:\n            model = models[row['Asset_ID']]\n            x_test = get_features(row)\n            y_pred = model.predict([x_test])[0]\n\n            df_pred.loc[df_pred['row_id'] == row['row_id'], 'Target'] = y_pred\n        \n        except:\n            print(f'{i}-th iteration of the test dataset, {j}-th row - there was the exception, then set Target = 0')\n            df_pred.loc[df_pred['row_id'] == row['row_id'], 'Target'] = 0\n            \n        # Print just one sample row to get a feeling of what it looks like        \n        if i == 0 and j == 0:\n            print('Example of the x_test data')\n            display(x_test)\n    # Display the first prediction dataframe\n    if i == 0:\n        print('Example of the prediction for test data')\n        display(df_pred)\n    df_pred['Target'] = df_pred['Target'].fillna(0)\n\n    # Send submissions\n    env.predict(df_pred)","metadata":{"execution":{"iopub.status.busy":"2022-01-23T14:43:35.919791Z","iopub.execute_input":"2022-01-23T14:43:35.920644Z","iopub.status.idle":"2022-01-23T14:43:35.980492Z","shell.execute_reply.started":"2022-01-23T14:43:35.920576Z","shell.execute_reply":"2022-01-23T14:43:35.979343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can add cross validation to fine-tune the selected model base on the available hyperparameters for each one.","metadata":{}}]}