{"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":"**About the Notebook:** \n\nData Science project, entry for the G-Research Crypto Forecasting Kaggle Competition. I will be performing some data analysis as well as using Light Gradient Boosting Machine to forecast short term returns in 14 popular cryptocurrencies using millions of high-frequency market data 2018-2021.","metadata":{}},{"cell_type":"markdown","source":"### Table Of Contents\n\n1. [About LGBM](#about-lgbm)\n2. [Data Description](#data-description)\n3. [EDA](#eda)\n4. [Feature Extraction](#feature-extraction)\n5. [Hyperparameter Tuning](#hyperparameter-tuning)\n6. [Submission](#submission)\n7. [Conclusion](#conclusion)","metadata":{}},{"cell_type":"markdown","source":"<a id=\"about-lgbm\"></a>\n# (0) About LGBM\nExplore more in the doc: (https://lightgbm.readthedocs.io/en/latest/)\n\nLightGBM is a gradient boosting framework that uses tree based learning algorithms. It is designed to be distributed and efficient with the following advantages:\n* Faster training speed and higher efficiency (6 times faster than XGBoost)\n* Lower memory usage.\n* Better accuracy.\n* Support of parallel, distributed, and GPU learning.\n* Capable of handling large-scale data.\n\nOnly situation where LGBM is not advised is with small datasets because of its sensitivity to overfitting.\n\nWe will make harness this powerful ML model to make predictions based on a large dataset containing 4 years worth of cryptocurrency data.","metadata":{}},{"cell_type":"markdown","source":"<a id=\"data-description\"></a>\n# (1) Data Description\n\n**train.csv**\n* timestamp: All timestamps are returned as second Unix timestamps (the number of seconds elapsed since 1970-01-01 00:00:00.000 UTC). Timestamps in this dataset are multiple of 60, indicating minute-by-minute data.\n* Asset_ID: The asset ID corresponding to one of the crytocurrencies (e.g. Asset_ID = 1 for Bitcoin). The mapping from Asset_ID to crypto asset is contained in asset_details.csv.\n* Count: Total number of trades in the time interval (last minute).\n* Open: Opening price of the time interval (in USD).\n* High: Highest price reached during time interval (in USD).\n* Low: Lowest price reached during time interval (in USD).\n* Close: Closing price of the time interval (in USD).\n* Volume: Quantity of asset bought or sold, displayed in base currency USD.\n* VWAP: The average price of the asset over the time interval, weighted by volume. VWAP is an aggregated form of trade data.\n* Target: Residual log-returns for the asset over a 15 minute horizon.\n\n**supplemental_train.csv**\nAfter the submission period is over this file's data will be replaced with cryptoasset prices from the submission period. In the Evaluation phase, the train, train supplement, and test set will be contiguous in time, apart from any missing data. The current copy, which is just filled approximately the right amount of data from train.csv is provided as a placeholder.\n\n**asset_details.csv**\nProvides the real name and of the cryptoasset for each Asset_ID and the weight each cryptoasset receives in the metric. Weights are determined by the logarithm of each product's market cap (in USD), of the cryptocurrencies at a fixed point in time. Weights were assigned to give more relevance to cryptocurrencies with higher market volumes to ensure smaller cryptocurrencies do not disproportionately impact the models.\n\n**example_sample_submission.csv**\nAn example of the data that will be delivered by the time series API. The data is just copied from train.csv.\n\n**example_test.csv**\nAn example of the data that will be delivered by the time series API.","metadata":{}},{"cell_type":"code","source":"### Importing libraries\nimport pandas as pd\nimport numpy as np\nfrom datetime import datetime\nfrom lightgbm import LGBMRegressor\nimport gresearch_crypto\nimport traceback\nimport time\nfrom datetime import datetime\nimport matplotlib.pyplot as plt\nimport plotly.graph_objects as go\nfrom sklearn.model_selection import GridSearchCV\nimport seaborn as sns\nfrom sklearn.model_selection import train_test_split","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-12-28T13:27:38.155440Z","iopub.execute_input":"2021-12-28T13:27:38.155712Z","iopub.status.idle":"2021-12-28T13:28:06.349910Z","shell.execute_reply.started":"2021-12-28T13:27:38.155683Z","shell.execute_reply":"2021-12-28T13:28:06.348866Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"### Loading datasets\n\npath = \"/kaggle/input/g-research-crypto-forecasting/\"\ndf_train = pd.read_csv(path + \"train.csv\")\ndf_test = pd.read_csv(path + \"example_test.csv\")\ndf_asset_details = pd.read_csv(path + \"asset_details.csv\")\ndf_supp_train = pd.read_csv(path + \"supplemental_train.csv\")","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:23:51.580437Z","iopub.execute_input":"2021-12-28T13:23:51.581172Z","iopub.status.idle":"2021-12-28T13:24:22.436446Z","shell.execute_reply.started":"2021-12-28T13:23:51.581131Z","shell.execute_reply":"2021-12-28T13:24:22.435684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:22.437779Z","iopub.execute_input":"2021-12-28T13:24:22.438021Z","iopub.status.idle":"2021-12-28T13:24:22.452781Z","shell.execute_reply.started":"2021-12-28T13:24:22.437994Z","shell.execute_reply":"2021-12-28T13:24:22.452003Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"supplemental_train.csv is the same as above (train.csv) except contains less rows.","metadata":{}},{"cell_type":"code","source":"df_test.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:22.453788Z","iopub.execute_input":"2021-12-28T13:24:22.454138Z","iopub.status.idle":"2021-12-28T13:24:22.473249Z","shell.execute_reply.started":"2021-12-28T13:24:22.454110Z","shell.execute_reply":"2021-12-28T13:24:22.472472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"eda\"></a>\n# (2) Exploratory Data Analysis\n\nLet's continue describing and analyzing the data to draw interesting inferences.","metadata":{}},{"cell_type":"code","source":"df_train.describe()","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:22.475391Z","iopub.execute_input":"2021-12-28T13:24:22.475822Z","iopub.status.idle":"2021-12-28T13:24:30.811283Z","shell.execute_reply.started":"2021-12-28T13:24:22.475785Z","shell.execute_reply":"2021-12-28T13:24:30.810179Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"seems like the VWAP column has NaN values we need to handle later.","metadata":{}},{"cell_type":"markdown","source":"### Timestamp\nWe define a helper function that will turn a date format into a timestamp to use for indexing. ","metadata":{}},{"cell_type":"code","source":"# auxiliary function, from datetime to timestamp\ntotimestamp = lambda s: np.int32(time.mktime(datetime.strptime(s, \"%d/%m/%Y\").timetuple()))","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:30.813613Z","iopub.execute_input":"2021-12-28T13:24:30.813822Z","iopub.status.idle":"2021-12-28T13:24:30.817718Z","shell.execute_reply.started":"2021-12-28T13:24:30.813796Z","shell.execute_reply":"2021-12-28T13:24:30.816880Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_asset_details","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:30.818775Z","iopub.execute_input":"2021-12-28T13:24:30.818990Z","iopub.status.idle":"2021-12-28T13:24:30.834302Z","shell.execute_reply.started":"2021-12-28T13:24:30.818964Z","shell.execute_reply":"2021-12-28T13:24:30.833464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"There is a total of 14 unique coins in this dataset.","metadata":{}},{"cell_type":"code","source":"## Checking Time Range\nbtc = df_train[df_train[\"Asset_ID\"]==1].set_index(\"timestamp\") # Asset_ID = 1 for Bitcoin\neth = df_train[df_train[\"Asset_ID\"]==6].set_index(\"timestamp\") # Asset_ID = 6 for Ethereum\nbnb = df_train[df_train[\"Asset_ID\"]==0].set_index(\"timestamp\") # Asset_ID = 0 for Binance Coin\nada = df_train[df_train[\"Asset_ID\"]==3].set_index(\"timestamp\") # Asset_ID = 3 for Cardano\n\nbeg_btc = datetime.fromtimestamp(btc.index[0]).strftime(\"%A, %B %d, %Y %I:%M:%S\") \nend_btc = datetime.fromtimestamp(btc.index[-1]).strftime(\"%A, %B %d, %Y %I:%M:%S\") \nbeg_eth = datetime.fromtimestamp(eth.index[0]).strftime(\"%A, %B %d, %Y %I:%M:%S\") \nend_eth = datetime.fromtimestamp(eth.index[-1]).strftime(\"%A, %B %d, %Y %I:%M:%S\")\nbeg_bnb = datetime.fromtimestamp(eth.index[0]).strftime(\"%A, %B %d, %Y %I:%M:%S\") \nend_bnb = datetime.fromtimestamp(eth.index[-1]).strftime(\"%A, %B %d, %Y %I:%M:%S\")\nbeg_ada = datetime.fromtimestamp(eth.index[0]).strftime(\"%A, %B %d, %Y %I:%M:%S\") \nend_ada = datetime.fromtimestamp(eth.index[-1]).strftime(\"%A, %B %d, %Y %I:%M:%S\")\n\nprint('Bitcoin data goes from ', beg_btc, ' to ', end_btc) \nprint('Ethereum data goes from ', beg_eth, ' to ', end_eth)\nprint('Binance coin data goes from ', beg_bnb, ' to ', end_bnb) \nprint('Cardano data goes from ', beg_ada, ' to ', end_ada)","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:30.836015Z","iopub.execute_input":"2021-12-28T13:24:30.836240Z","iopub.status.idle":"2021-12-28T13:24:32.112665Z","shell.execute_reply.started":"2021-12-28T13:24:30.836206Z","shell.execute_reply":"2021-12-28T13:24:32.111760Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The data extends 4 years.","metadata":{}},{"cell_type":"markdown","source":"### Heatmap: Features of BTC","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8,6))\nsns.heatmap(btc[['Count','Open','High','Low','Close','Volume','VWAP','Target']].corr(), \n            vmin=-1.0, vmax=1.0, annot=True, cmap='coolwarm', linewidths=0.1)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:32.114140Z","iopub.execute_input":"2021-12-28T13:24:32.114428Z","iopub.status.idle":"2021-12-28T13:24:33.117511Z","shell.execute_reply.started":"2021-12-28T13:24:32.114391Z","shell.execute_reply":"2021-12-28T13:24:33.116054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Candlesticks Charts for BTC & ETH, Last 200 Minutes","metadata":{}},{"cell_type":"code","source":"btc_mini = btc.iloc[-200:] # Select recent data rows\neth_mini = eth.iloc[-200:]\n\nfig = go.Figure(data=[go.Candlestick(x=btc_mini.index, open=btc_mini['Open'], high=btc_mini['High'], low=btc_mini['Low'], close=btc_mini['Close'])])\nfig.update_xaxes(title_text=\"$\")\nfig.update_yaxes(title_text=\"Index\")\nfig.update_layout(title=\"Bitcoin Price, 200 Last Minutes\")\nfig.show()\n\nfig = go.Figure(data=[go.Candlestick(x=eth_mini.index, open=eth_mini['Open'], high=eth_mini['High'], low=eth_mini['Low'], close=eth_mini['Close'])])\nfig.update_xaxes(title_text=\"$\")\nfig.update_yaxes(title_text=\"Index\")\nfig.update_layout(title=\"Ethereum Price, 200 Last Minutes\")\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:33.118524Z","iopub.execute_input":"2021-12-28T13:24:33.118715Z","iopub.status.idle":"2021-12-28T13:24:33.147022Z","shell.execute_reply.started":"2021-12-28T13:24:33.118691Z","shell.execute_reply":"2021-12-28T13:24:33.146488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Interestingly, we can visually observe a correlation between BTC and ETH prices. ","metadata":{}},{"cell_type":"markdown","source":"### Plotting BTC and ETH closing prices","metadata":{}},{"cell_type":"code","source":"f = plt.figure(figsize=(15,4))\n\n# fill NAs for BTC and ETH\nbtc = btc.reindex(range(btc.index[0],btc.index[-1]+60,60),method='pad')\neth = eth.reindex(range(eth.index[0],eth.index[-1]+60,60),method='pad')\n\nax = f.add_subplot(121)\nplt.plot(btc['Close'], color='yellow', label='BTC')\nplt.legend()\nplt.xlabel('Time (timestamp)')\nplt.ylabel('Bitcoin')\n\nax2 = f.add_subplot(122)\nax2.plot(eth['Close'], color='purple', label='ETH')\nplt.legend()\nplt.xlabel('Time (timestamp)')\nplt.ylabel('Ethereum')\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:33.148860Z","iopub.execute_input":"2021-12-28T13:24:33.149119Z","iopub.status.idle":"2021-12-28T13:24:36.304392Z","shell.execute_reply.started":"2021-12-28T13:24:33.149095Z","shell.execute_reply":"2021-12-28T13:24:36.303579Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can also confirm through another visual observation that, within the 4 recent years, BTC and ETH prices are correlated.","metadata":{}},{"cell_type":"markdown","source":"### Heatmap: Coin Correlation (Last 10000 Minutes)","metadata":{}},{"cell_type":"code","source":"data =df_train[-10000:]\ncheck = pd.DataFrame()\nfor i in data.Asset_ID.unique():\n    check[i] = data[data.Asset_ID==i]['Target'].reset_index(drop=True) \n    \nplt.figure(figsize=(10,8))\nsns.heatmap(check.dropna().corr(), vmin=-1.0, vmax=1.0, annot=True, cmap='coolwarm', linewidths=0.1)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:36.305927Z","iopub.execute_input":"2021-12-28T13:24:36.306258Z","iopub.status.idle":"2021-12-28T13:24:37.275587Z","shell.execute_reply.started":"2021-12-28T13:24:36.306219Z","shell.execute_reply":"2021-12-28T13:24:37.274724Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Interestingly, in the last 10000 minutes we have several coins that are highly correlated with one another.","metadata":{}},{"cell_type":"markdown","source":"<a id=\"feature-extraction\"></a>\n## (3) Feature Extraction\n\nWe define a few functions to add to our list of features used for prediction.","metadata":{}},{"cell_type":"code","source":"def hlco_ratio(df): \n    return (df['High'] - df['Low'])/(df['Close']-df['Open'])\ndef upper_shadow(df):\n    return df['High'] - np.maximum(df['Close'], df['Open'])\ndef lower_shadow(df):\n    return np.minimum(df['Close'], df['Open']) - df['Low']\n\ndef get_features(df):\n    df_feat = df[['Count', 'Open', 'High', 'Low', 'Close', 'Volume', 'VWAP']].copy()\n    df_feat['Upper_Shadow'] = upper_shadow(df_feat)\n    df_feat['hlco_ratio'] = hlco_ratio(df_feat)\n    df_feat['Lower_Shadow'] = lower_shadow(df_feat)\n    return df_feat","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:37.277176Z","iopub.execute_input":"2021-12-28T13:24:37.277477Z","iopub.status.idle":"2021-12-28T13:24:37.284836Z","shell.execute_reply.started":"2021-12-28T13:24:37.277441Z","shell.execute_reply":"2021-12-28T13:24:37.284287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## (4) Prediction\n\n","metadata":{}},{"cell_type":"code","source":"# train test split df_train into 80% train rows and 20% valid rows\ntrain_data = df_train\n# train_data = df_train.sample(frac = 0.8)\n# valid_data = df_train.drop(train_data.index)\n\ndef get_Xy_and_model_for_asset(df_train, asset_id):\n    df = df_train[df_train[\"Asset_ID\"] == asset_id]\n    \n    df = df.sample(frac=0.2)\n    df_proc = get_features(df)\n    df_proc['y'] = df['Target']\n    df_proc.replace([np.inf, -np.inf], np.nan, inplace=True)\n    df_proc = df_proc.dropna(how=\"any\")\n    \n    \n    X = df_proc.drop(\"y\", axis=1)\n    y = df_proc[\"y\"]   \n    model = LGBMRegressor()\n    model.fit(X, y)\n    return X, y, model\n\nXs = {}\nys = {}\nmodels = {}\n\nfor asset_id, asset_name in zip(df_asset_details['Asset_ID'], df_asset_details['Asset_Name']):\n    print(f\"Training model for {asset_name:<16} (ID={asset_id:<2})\")\n    X, y, model = get_Xy_and_model_for_asset(train_data, asset_id)       \n    try:\n        Xs[asset_id], ys[asset_id], models[asset_id] = X, y, model\n    except: \n        Xs[asset_id], ys[asset_id], models[asset_id] = None, None, None ","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:30:13.305958Z","iopub.execute_input":"2021-12-28T13:30:13.307856Z","iopub.status.idle":"2021-12-28T13:30:31.079784Z","shell.execute_reply.started":"2021-12-28T13:30:13.307763Z","shell.execute_reply":"2021-12-28T13:30:31.078915Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"hyperparameter-tuning\"></a>\n## (5) Evaluation, Hyperparam Tuning\n\nWe will perform GridSearch for each LGBM model of 14 coins.","metadata":{}},{"cell_type":"markdown","source":"### (5.1) Hyperparam Tuning","metadata":{}},{"cell_type":"code","source":"parameters = {\n    # 'max_depth': range (2, 10, 1),\n    'num_leaves': range(21, 161, 10),\n    'learning_rate': [0.1, 0.01, 0.05]\n}\n\nnew_models = {}\nfor asset_id, asset_name in zip(df_asset_details['Asset_ID'], df_asset_details['Asset_Name']):\n    print(\"GridSearchCV for: \" + asset_name)\n    grid_search = GridSearchCV(\n        estimator=get_Xy_and_model_for_asset(df_train, asset_id)[2], # bitcoin\n        param_grid=parameters,\n        n_jobs = -1,\n        cv = 5,\n        verbose=True\n    )\n    grid_search.fit(Xs[asset_id], ys[asset_id])\n    new_models[asset_id] = grid_search.best_estimator_\n    grid_search.best_estimator_\n","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:37:34.570243Z","iopub.execute_input":"2021-12-28T13:37:34.571357Z","iopub.status.idle":"2021-12-28T14:19:12.110569Z","shell.execute_reply.started":"2021-12-28T13:37:34.571309Z","shell.execute_reply":"2021-12-28T14:19:12.109845Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for asset_id, asset_name in zip(df_asset_details['Asset_ID'], df_asset_details['Asset_Name']):\n    print(f\"Tuned model for {asset_name:<1} (ID={asset_id:})\")\n    print(new_models[asset_id])","metadata":{"execution":{"iopub.status.busy":"2021-12-28T14:28:49.740137Z","iopub.execute_input":"2021-12-28T14:28:49.740798Z","iopub.status.idle":"2021-12-28T14:28:49.756513Z","shell.execute_reply.started":"2021-12-28T14:28:49.740753Z","shell.execute_reply":"2021-12-28T14:28:49.755438Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Evaluation\n\nThis forecasting competition aims to predict returns in the near future for prices $P^a$, for each asset $a$. For each row in the dataset, we include the target for prediction, `Target`. `Target` is derived from log returns ($R^a$) over 15 minutes.\n\n$$R^a(t) = log (P^a(t+16)\\ /\\ P^a(t+1))$$\n\nCrypto asset returns are highly correlated, following to a large extend the overall crypto market. As we want to test your ability to predict returns for individual assets, we perform a linear residualization, removing the market signal from individual asset returns when creating the target. In more detail, if $M(t)$ is the weighted average market returns, the target is:\n\n$$M(t) = \\frac{\\sum_a w^a R^a(t)}{\\sum_a w^a}  \\\\\n\\beta^a = \\frac{\\langle M \\cdot R^a \\rangle}{\\langle M^2 \\rangle} \\\\\n\\text{Target}^a(t) = R^a(t) - \\beta^a M(t)$$\n\nwhere the bracket $\\langle .\\rangle$ represent the rolling average over time (3750 minute windows), and same asset weights $w^a$ used for the evaluation metric.","metadata":{}},{"cell_type":"code","source":"# df_pred = []\n\n# for j , row in valid_data.iterrows():        \n#     if new_models[row['Asset_ID']] is not None:\n#         model = new_models[row['Asset_ID']]\n#         x_test = get_features(row)\n#         y_pred = model.predict(pd.DataFrame([x_test]))[0]\n#         df_pred.append(y_pred)\n#     else: \n#         df_pred.append(0)\n\n# print(df_pred)\n    ","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:37.990335Z","iopub.status.idle":"2021-12-28T13:24:37.990618Z","shell.execute_reply.started":"2021-12-28T13:24:37.990476Z","shell.execute_reply":"2021-12-28T13:24:37.990491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# # We will simplify things and use correlation (without weights) for evaluation, and consider only BTC.\n# print('Test score for BTC: ', f\"{np.corrcoef(df_pred[df_pred[\"Asset_ID\"]==1].set_index(\"timestamp\")[\"Target\"], valid_data[valid_data[\"Asset_ID\"]==1].set_index(\"timestamp\")[\"Target\"]):.2f}\")","metadata":{"execution":{"iopub.status.busy":"2021-12-28T13:24:37.991866Z","iopub.status.idle":"2021-12-28T13:24:37.992189Z","shell.execute_reply.started":"2021-12-28T13:24:37.992038Z","shell.execute_reply":"2021-12-28T13:24:37.992056Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"submission\"></a>\n## (6) Submission","metadata":{}},{"cell_type":"code","source":"env = 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        if new_models[row['Asset_ID']] is not None:\n            try:\n                model = new_models[row['Asset_ID']]\n                x_test = get_features(row)\n                y_pred = model.predict(pd.DataFrame([x_test]))[0]\n                df_pred.loc[df_pred['row_id'] == row['row_id'], 'Target'] = y_pred\n            except:\n                df_pred.loc[df_pred['row_id'] == row['row_id'], 'Target'] = 0\n                traceback.print_exc()\n        else: \n            df_pred.loc[df_pred['row_id'] == row['row_id'], 'Target'] = 0  \n    \n    env.predict(df_pred)","metadata":{"execution":{"iopub.status.busy":"2021-12-28T14:29:04.167171Z","iopub.execute_input":"2021-12-28T14:29:04.167464Z","iopub.status.idle":"2021-12-28T14:29:04.506231Z","shell.execute_reply.started":"2021-12-28T14:29:04.167431Z","shell.execute_reply":"2021-12-28T14:29:04.505380Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id=\"conclusion\"></a>\n# (7) Personal Conclusion\n\nAs my first public contribution to Kaggle, this inspired me to participate in more competitions, perform regular data science projects, and learn about trading strategies and develop my own crypto algo trading bot.","metadata":{}}]}