{"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":"code","source":"from IPython.core.display import display, HTML, Javascript\n\n# ----- Notebook Theme -----\n\nnotebook_theme = 'carrot'\ncolor_maps = {'turquoise': ['#1abc9c', '#e8f8f5', '#d1f2eb', '#a3e4d7', '#76d7c4', '#48c9b0', '#1abc9c', '#17a589', '#148f77', '#117864', '#0e6251'], 'green': ['#16a085', '#e8f6f3', '#d0ece7', '#a2d9ce', '#73c6b6', '#45b39d', '#16a085', '#138d75', '#117a65', '#0e6655', '#0b5345'], 'emerald': ['#2ecc71', '#eafaf1', '#d5f5e3', '#abebc6', '#82e0aa', '#58d68d', '#2ecc71', '#28b463', '#239b56', '#1d8348', '#186a3b'], 'nephritis': ['#27ae60', '#e9f7ef', '#d4efdf', '#a9dfbf', '#7dcea0', '#52be80', '#27ae60', '#229954', '#1e8449', '#196f3d', '#145a32'], 'peter': ['#3498db', '#ebf5fb', '#d6eaf8', '#aed6f1', '#85c1e9', '#5dade2', '#3498db', '#2e86c1', '#2874a6', '#21618c', '#1b4f72'], 'belize': ['#2980b9', '#eaf2f8', '#d4e6f1', '#a9cce3', '#7fb3d5', '#5499c7', '#2980b9', '#2471a3', '#1f618d', '#1a5276', '#154360'], 'amethyst': ['#9b59b6', '#f5eef8', '#ebdef0', '#d7bde2', '#c39bd3', '#af7ac5', '#9b59b6', '#884ea0', '#76448a', '#633974', '#512e5f'], 'wisteria': ['#8e44ad', '#f4ecf7', '#e8daef', '#d2b4de', '#bb8fce', '#a569bd', '#8e44ad', '#7d3c98', '#6c3483', '#5b2c6f', '#4a235a'], 'wet': ['#34495e', '#ebedef', '#d6dbdf', '#aeb6bf', '#85929e', '#5d6d7e', '#34495e', '#2e4053', '#283747', '#212f3c', '#1b2631'], 'midnight': ['#2c3e50', '#eaecee', '#d5d8dc', '#abb2b9', '#808b96', '#566573', '#2c3e50', '#273746', '#212f3d', '#1c2833', '#17202a'], 'sunflower': ['#f1c40f', '#fef9e7', '#fcf3cf', '#f9e79f', '#f7dc6f', '#f4d03f', '#f1c40f', '#d4ac0d', '#b7950b', '#9a7d0a', '#7d6608'], 'orange': ['#f39c12', '#fef5e7', '#fdebd0', '#fad7a0', '#f8c471', '#f5b041', '#f39c12', '#d68910', '#b9770e', '#9c640c', '#7e5109'], 'carrot': ['#e67e22', '#fdf2e9', '#fae5d3', '#f5cba7', '#f0b27a', '#eb984e', '#e67e22', '#ca6f1e', '#af601a', '#935116', '#784212'], 'pumpkin': ['#d35400', '#fbeee6', '#f6ddcc', '#edbb99', '#e59866', '#dc7633', '#d35400', '#ba4a00', '#a04000', '#873600', '#6e2c00'], 'alizarin': ['#e74c3c', '#fdedec', '#fadbd8', '#f5b7b1', '#f1948a', '#ec7063', '#e74c3c', '#cb4335', '#b03a2e', '#943126', '#78281f'], 'pomegranate': ['#c0392b', '#f9ebea', '#f2d7d5', '#e6b0aa', '#d98880', '#cd6155', '#c0392b', '#a93226', '#922b21', '#7b241c', '#641e16'], 'clouds': ['#ecf0f1', '#fdfefe', '#fbfcfc', '#f7f9f9', '#f4f6f7', '#f0f3f4', '#ecf0f1', '#d0d3d4', '#b3b6b7', '#979a9a', '#7b7d7d'], 'silver': ['#bdc3c7', '#f8f9f9', '#f2f3f4', '#e5e7e9', '#d7dbdd', '#cacfd2', '#bdc3c7', '#a6acaf', '#909497', '#797d7f', '#626567'], 'concrete': ['#95a5a6', '#f4f6f6', '#eaeded', '#d5dbdb', '#bfc9ca', '#aab7b8', '#95a5a6', '#839192', '#717d7e', '#5f6a6a', '#4d5656'], 'asbestos': ['#7f8c8d', '#f2f4f4', '#e5e8e8', '#ccd1d1', '#b2babb', '#99a3a4', '#7f8c8d', '#707b7c', '#616a6b', '#515a5a', '#424949']}\n# color_maps = {'red': ['#f44336', '#ffebee', '#ffcdd2', '#ef9a9a', '#e57373', '#ef5350', '#f44336', '#e53935', '#d32f2f', '#c62828', '#b71c1c', '#ff8a80', '#ff5252', '#ff1744', '#d50000'], 'pink': ['#e91e63', '#fce4ec', '#f8bbd0', '#f48fb1', '#f06292', '#ec407a', '#e91e63', '#d81b60', '#c2185b', '#ad1457', '#880e4f', '#ff80ab', '#ff4081', '#f50057', '#c51162'], 'purple': ['#9c27b0', '#f3e5f5', '#e1bee7', '#ce93d8', '#ba68c8', '#ab47bc', '#9c27b0', '#8e24aa', '#7b1fa2', '#6a1b9a', '#4a148c', '#ea80fc', '#e040fb', '#d500f9', '#aa00ff'], 'deep': ['#673ab7', '#ede7f6', '#d1c4e9', '#b39ddb', '#9575cd', '#7e57c2', '#673ab7', '#5e35b1', '#512da8', '#4527a0', '#311b92', '#b388ff', '#7c4dff', '#651fff', '#6200ea', '#ff5722', '#fbe9e7', '#ffccbc', '#ffab91', '#ff8a65', '#ff7043', '#ff5722', '#f4511e', '#e64a19', '#d84315', '#bf360c', '#ff9e80', '#ff6e40', '#ff3d00', '#dd2c00'], 'indigo': ['#3f51b5', '#e8eaf6', '#c5cae9', '#9fa8da', '#7986cb', '#5c6bc0', '#3f51b5', '#3949ab', '#303f9f', '#283593', '#1a237e', '#8c9eff', '#536dfe', '#3d5afe', '#304ffe'], 'blue': ['#2196f3', '#e3f2fd', '#bbdefb', '#90caf9', '#64b5f6', '#42a5f5', '#2196f3', '#1e88e5', '#1976d2', '#1565c0', '#0d47a1', '#82b1ff', '#448aff', '#2979ff', '#2962ff', '#607d8b', '#eceff1', '#cfd8dc', '#b0bec5', '#90a4ae', '#78909c', '#607d8b', '#546e7a', '#455a64', '#37474f', '#263238'], 'light': ['#03a9f4', '#e1f5fe', '#b3e5fc', '#81d4fa', '#4fc3f7', '#29b6f6', '#03a9f4', '#039be5', '#0288d1', '#0277bd', '#01579b', '#80d8ff', '#40c4ff', '#00b0ff', '#0091ea', '#8bc34a', '#f1f8e9', '#dcedc8', '#c5e1a5', '#aed581', '#9ccc65', '#8bc34a', '#7cb342', '#689f38', '#558b2f', '#33691e', '#ccff90', '#b2ff59', '#76ff03', '#64dd17'], 'cyan': ['#00bcd4', '#e0f7fa', '#b2ebf2', '#80deea', '#4dd0e1', '#26c6da', '#00bcd4', '#00acc1', '#0097a7', '#00838f', '#006064', '#84ffff', '#18ffff', '#00e5ff', '#00b8d4'], 'teal': ['#009688', '#e0f2f1', '#b2dfdb', '#80cbc4', '#4db6ac', '#26a69a', '#009688', '#00897b', '#00796b', '#00695c', '#004d40', '#a7ffeb', '#64ffda', '#1de9b6', '#00bfa5'], 'green': ['#4caf50', '#e8f5e9', '#c8e6c9', '#a5d6a7', '#81c784', '#66bb6a', '#4caf50', '#43a047', '#388e3c', '#2e7d32', '#1b5e20', '#b9f6ca', '#69f0ae', '#00e676', '#00c853'], 'lime': ['#cddc39', '#f9fbe7', '#f0f4c3', '#e6ee9c', '#dce775', '#d4e157', '#cddc39', '#c0ca33', '#afb42b', '#9e9d24', '#827717', '#f4ff81', '#eeff41', '#c6ff00', '#aeea00'], 'yellow': ['#ffeb3b', '#fffde7', '#fff9c4', '#fff59d', '#fff176', '#ffee58', '#ffeb3b', '#fdd835', '#fbc02d', '#f9a825', '#f57f17', '#ffff8d', '#ffff00', '#ffea00', '#ffd600'], 'amber': ['#ffc107', '#fff8e1', '#ffecb3', '#ffe082', '#ffd54f', '#ffca28', '#ffc107', '#ffb300', '#ffa000', '#ff8f00', '#ff6f00', '#ffe57f', '#ffd740', '#ffc400', '#ffab00'], 'orange': ['#ff9800', '#fff3e0', '#ffe0b2', '#ffcc80', '#ffb74d', '#ffa726', '#ff9800', '#fb8c00', '#f57c00', '#ef6c00', '#e65100', '#ffd180', '#ffab40', '#ff9100', '#ff6d00'], 'brown': ['#795548', '#efebe9', '#d7ccc8', '#bcaaa4', '#a1887f', '#8d6e63', '#795548', '#6d4c41', '#5d4037', '#4e342e', '#3e2723'], 'grey': ['#9e9e9e', '#fafafa', '#f5f5f5', '#eeeeee', '#e0e0e0', '#bdbdbd', '#9e9e9e', '#757575', '#616161', '#424242', '#212121'], 'white': ['#ffffff'], 'black': ['#000000']}\n\ncolor_maps = {i: color_maps[i] for i in color_maps if i not in ['clouds', 'silver', 'concrete', 'asbestos', 'wet asphalt', 'midnight blue', 'wet']}\n\nCMAP = 'Oranges'\nprompt = '#1DBCCD'\nmain_color = '#E58F65' # color_maps[notebook_theme]\nstrong_main_color = '#EB9514' # = color_maps[notebook_theme] \ncustom_colors = [strong_main_color, main_color]\n\n# ----- Notebook Theme -----\n\nhtml_contents =\"\"\"\n<!DOCTYPE html>\n<html lang=\"en\">\n    <head>\n        <link rel=\"stylesheet\" href=\"https://www.w3schools.com/w3css/4/w3.css\">\n        <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Raleway\">\n        <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Oswald\">\n        <link rel=\"stylesheet\" href=\"https://fonts.googleapis.com/css?family=Open Sans\">\n        <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css\">\n        <style>\n        .title-section{\n            font-family: \"Oswald\", Arial, sans-serif;\n            font-weight: bold;\n            color: \"#6A8CAF\";\n            letter-spacing: 6px;\n        }\n        hr { border: 1px solid #E58F65 !important;\n             color: #E58F65 !important;\n             background: #E58F65 !important;\n           }\n        body {\n            font-family: \"Open Sans\", sans-serif;\n            }        \n        </style>\n    </head>    \n</html>\n\"\"\"\n\nHTML(html_contents)\nimport os\nif not os.path.exists(\"../input/g-research-crypto-forecasting/\"): os.chdir('/t/Datasets/kaggle_crypto/internal')","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"papermill":{"duration":0.055522,"end_time":"2021-11-21T16:43:56.152505","exception":false,"start_time":"2021-11-21T16:43:56.096983","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-28T09:49:12.034353Z","iopub.execute_input":"2021-11-28T09:49:12.035049Z","iopub.status.idle":"2021-11-28T09:49:12.063442Z","shell.execute_reply.started":"2021-11-28T09:49:12.035Z","shell.execute_reply":"2021-11-28T09:49:12.062483Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<br><br>\n<div>    \n<!--     <div style = \"float:left; width:55%; overflow:hidden;\">         -->\n        <center><img src=\"https://i.ibb.co/hHpTy3c/g-research-logo6.png\" style = \"max-height:300px;\"></center> \n<!--     </div> -->\n<!--     <div style = \"float:right; width:35%; overflow:hidden;\"> -->\n<!--         <img src=\"img/meditation/Meditation3.gif\">  -->\n<!--     </div> -->\n</div>","metadata":{"_cell_guid":"42a2c92b-00e6-4c13-b99e-408266d1b964","_uuid":"9b3904ae-5fd7-432b-a10a-1a2446fbcc4b","papermill":{"duration":0.024323,"end_time":"2021-11-21T16:43:56.201853","exception":false,"start_time":"2021-11-21T16:43:56.17753","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"<hr>","metadata":{"_cell_guid":"3208562a-4f7a-45d5-b8e2-67da427cd906","_uuid":"d7276e81-829f-4be5-967d-0a641fb1adbf","papermill":{"duration":0.024094,"end_time":"2021-11-21T16:43:56.250315","exception":false,"start_time":"2021-11-21T16:43:56.226221","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"<div>    \n    <div style = \"float:left; width:55%; overflow:hidden;\">        \n        <br><br><br><br>        \n        <span style = \"float:right;\">\n        <h2>Reinforcement Learning Starter</h2>\n        <p>G-Research Crypto Forecasting Competition</p>\n        <br>\n        <b></b>\n        <b>\n        - 🌎 <a href=\"https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/284903\">Discussion Thread</a>\n        <br>\n        - 🇰 <a href=\"https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/285726\">The dataset</a>\n        </b>            \n        </span>\n    </div>\n    <div style=\"float:right; width:35%; max-height:300px; overflow: hidden;\">        \n        <img src=\"https://i.ibb.co/9YFyhT8/Bitcoin2.gif\" style = \"max-height: 300px;\">         \n    </div>\n</div>","metadata":{"_cell_guid":"241ce292-edca-4688-a665-c6321e80b438","_uuid":"79576405-5d2f-465f-bb01-10eee623172c","papermill":{"duration":0.023974,"end_time":"2021-11-21T16:43:56.298919","exception":false,"start_time":"2021-11-21T16:43:56.274945","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"<span id=\"introduction\"></span>\n<hr>","metadata":{"_cell_guid":"ca79faf7-ca73-4e9b-8552-be96bdc881f9","_uuid":"4e428101-c977-488b-aa10-fe96d228224f","papermill":{"duration":0.024862,"end_time":"2021-11-21T16:43:56.348112","exception":false,"start_time":"2021-11-21T16:43:56.32325","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":">### Reinforcement Learning Starter\n>This is a simple starter notebook for Kaggle's Crypto Comp showing purged group timeseries KFold with extra data. Purged Times Series is explained [here][2]. There are many configuration variables below to allow you to experiment. Use either CPU or GPU. You can control which years are loaded, which neural networks are used, and whether to use feature engineering. You can experiment with different data preprocessing, model hyperparameters, loss, and number of seeds to ensemble. The extra datasets contain the full history of the assets at the same format of the competition, so you can input that into your model too.\n>\n>This notebook follows the ideas presented in my \"Initial Thoughts\" [here][1].\n\n[1]: https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/284903\n[2]: https://www.kaggle.com/yamqwe/let-s-talk-validation-grouptimeseriessplit\n[3]: https://www.kaggle.com/cdeotte/triple-stratified-kfold-with-tfrecords\n\n<div class=\"alert alert-block alert-warning\">\n<b>References:</b>\n<ul>\n    <li><a href = \"https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/285726\">Dataset Thread</a></li>\n    <li><a href = \"https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/284903\">Initial Thoughts Thread\n</a></li>\n    <li><a href = \"https://www.kaggle.com/yamqwe/let-s-talk-validation-grouptimeseriessplit\">Validation Thread\n</a></li>\n</ul>\n</div>","metadata":{"_cell_guid":"8af163ff-915a-4fae-aefe-6447e64952e5","_uuid":"b328cc9e-a536-4347-beed-d033e9f5ac6a","papermill":{"duration":0.024057,"end_time":"2021-11-21T16:43:56.396747","exception":false,"start_time":"2021-11-21T16:43:56.37269","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"____\n\n#### <center>All notebooks in the series 👇</center>\n\n| CV + Model | Hyperparam Optimization  | Time Series Models | Feature Engineering |\n| --- | --- | --- | --- |\n| [Neural Network Starter](https://www.kaggle.com/yamqwe/purgedgrouptimeseries-cv-with-extra-data-nn) | [MLP + AE](https://www.kaggle.com/yamqwe/bottleneck-encoder-mlp-keras-tuner)        | [LSTM](https://www.kaggle.com/yamqwe/time-series-modeling-lstm) | [Technical Analysis #1](https://www.kaggle.com/yamqwe/crypto-prediction-technical-analysis-features) |\n| [LightGBM Starter](https://www.kaggle.com/yamqwe/purgedgrouptimeseries-cv-with-extra-data-lgbm)     | [LightGBM](https://www.kaggle.com/yamqwe/purged-time-series-cv-lightgbm-optuna)     | [Wavenet](https://www.kaggle.com/yamqwe/time-series-modeling-wavenet)  | [Technical Analysis #2](https://www.kaggle.com/yamqwe/crypto-prediction-technical-analysis-feats-2) |\n| [Catboost Starter](https://www.kaggle.com/yamqwe/purgedgrouptimeseries-cv-extra-data-catboost)      | [Catboost](https://www.kaggle.com/yamqwe/purged-time-series-cv-catboost-gpu-optuna) | [Multivariate-Transformer [written from scratch]](https://www.kaggle.com/yamqwe/time-series-modeling-multivariate-transformer) | [Time Series Agg](https://www.kaggle.com/yamqwe/features-all-time-series-aggregations-ever) | \n| [XGBoost Starter](https://www.kaggle.com/yamqwe/xgb-extra-data)                                            | [XGboost](https://www.kaggle.com/yamqwe/purged-time-series-cv-xgboost-gpu-optuna) | [N-BEATS](https://www.kaggle.com/yamqwe/crypto-forecasting-n-beats) |  [Neutralization](https://www.kaggle.com/yamqwe/g-research-avoid-overfit-feature-neutralization/) |\n| [Supervised AE [Janestreet 1st]](https://www.kaggle.com/yamqwe/1st-place-of-jane-street-adapted-to-crypto) | [Supervised AE [Janestreet 1st]](https://www.kaggle.com/yamqwe/1st-place-of-jane-street-keras-tuner) | [DeepAR](https://www.kaggle.com/yamqwe/probabilistic-forecasting-deepar/) | [Quant's Volatility Features](https://www.kaggle.com/yamqwe/crypto-prediction-volatility-features) |\n| [Transformer)](https://www.kaggle.com/yamqwe/let-s-test-a-transformer)                                     | [Transformer](https://www.kaggle.com/yamqwe/sh-tcoins-transformer-baseline)  |  | ⏳Target Engineering |\n| [TabNet Starter](https://www.kaggle.com/yamqwe/tabnet-cv-extra-data)                                       |  |  |⏳Fourier Analysis | \n| [Reinforcement Learning (PPO) Starter](https://www.kaggle.com/yamqwe/g-research-reinforcement-learning-starter) | | | ⏳Wavelets | \n\n____","metadata":{"papermill":{"duration":0.025127,"end_time":"2021-11-21T16:43:56.446868","exception":false,"start_time":"2021-11-21T16:43:56.421741","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"outline\">Table Of Content 📑</span>\n<hr >","metadata":{"_cell_guid":"3208562a-4f7a-45d5-b8e2-67da427cd906","_uuid":"d7276e81-829f-4be5-967d-0a641fb1adbf","papermill":{"duration":0.025677,"end_time":"2021-11-21T16:43:56.498922","exception":false,"start_time":"2021-11-21T16:43:56.473245","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"#### Table Of Content\n\n1. [📝 Introduction](#introduction)\n\n2. [📑 Table Of Content](#outline) \n\n3. [🤿 Diving into the Data](#diving) \n\n4. [💾 Installations](#imports) \n\n5. [📚 Imports](#imports) \n\n6. [🎚️ Configurations](#config) \n\n7. [🗃️ Data Loading](#loading)  \n\n8. [⚙️ Defining the GYM Environment](#modelconf)\n\n9. [🏋️ Reinforcement Learning](#training)\n\n10. [🇰 Submit To Kaggle](#submit)","metadata":{"_cell_guid":"d70815a1-3398-43b2-be85-2230fffd89a9","_uuid":"e9b980c5-036c-4e25-992b-115169a95ba4","papermill":{"duration":0.024186,"end_time":"2021-11-21T16:43:56.5491","exception":false,"start_time":"2021-11-21T16:43:56.524914","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"outline\">Diving into the Data 🤿</span>\n<hr >","metadata":{"_cell_guid":"310c5bce-3fab-4a82-b70e-d5e8a0e5e594","_uuid":"ce509f90-2ae9-4ea3-94ad-39479b72ca12","papermill":{"duration":0.0242,"end_time":"2021-11-21T16:43:56.597884","exception":false,"start_time":"2021-11-21T16:43:56.573684","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"\n#### **<span>Dataset Structure</span>**\n\n> **train.csv** - The training set\n> \n> 1.  timestamp - A timestamp for the minute covered by the row.\n> 2.  Asset_ID - An ID code for the cryptoasset.\n> 3.  Count - The number of trades that took place this minute.\n> 4.  Open - The USD price at the beginning of the minute.\n> 5.  High - The highest USD price during the minute.\n> 6.  Low - The lowest USD price during the minute.\n> 7.  Close - The USD price at the end of the minute.\n> 8.  Volume - The number of cryptoasset u units traded during the minute.\n> 9.  VWAP - The volume-weighted average price for the minute.\n> 10. Target - 15 minute residualized returns. See the 'Prediction and Evaluation section of this notebook for details of how the target is calculated.\n> 11. Weight - Weight, defined by the competition hosts [here](https://www.kaggle.com/cstein06/tutorial-to-the-g-research-crypto-competition)\n> 12. Asset_Name - Human readable Asset name.\n> \n>\n> **example_test.csv** - An example of the data that will be delivered by the time series API.\n> \n> **example_sample_submission.csv** - An example of the data that will be delivered by the time series API. The data is just copied from train.csv.\n> \n> **asset_details.csv** - Provides the real name and of the cryptoasset for each Asset_ID and the weight each cryptoasset receives in the metric.\n> \n> **supplemental_train.csv** - After 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> - 📌 There are 14 coins in the dataset\n>\n> - 📌 There are 4 years  in the [full] dataset","metadata":{"_cell_guid":"ca6da936-954f-427b-af0c-f04517c4d4ed","_uuid":"a91494a0-a071-49e5-bcc0-9c7b7566ad75","papermill":{"duration":0.024809,"end_time":"2021-11-21T16:43:56.647106","exception":false,"start_time":"2021-11-21T16:43:56.622297","status":"completed"},"tags":[]}},{"cell_type":"code","source":"css_file = '''\ndiv #notebook {\nbackground-color: white;\nfont-family: 'Open Sans', Helvetica, sans-serif;\nline-height: 20px;\n}\n\n#notebook-container {\nmargin-top: 2em;\npadding-top: 2em;\nborder-top: 4px solid %s; /* light orange */\n-webkit-box-shadow: 0px 0px 8px 2px rgba(224, 212, 226, 0.5); /* pink */\n    box-shadow: 0px 0px 8px 2px rgba(224, 212, 226, 0.5); /* pink */\n}\n\ndiv .input {\nmargin-bottom: 1em;\n}\n\n.rendered_html h1, .rendered_html h2, .rendered_html h3, .rendered_html h4, .rendered_html h5, .rendered_html h6 {\ncolor: %s; /* light orange */\nfont-weight: 600;\n}\n\n.rendered_html code {\n    background-color: #efefef; /* light gray */\n}\n\n.CodeMirror {\ncolor: #8c8c8c; /* dark gray */\npadding: 0.7em;\n}\n\ndiv.input_area {\nborder: none;\n    background-color: %s; /* rgba(229, 143, 101, 0.1); light orange [exactly #E58F65] */\n    border-top: 2px solid %s; /* light orange */\n}\n\ndiv.input_prompt {\ncolor: %s; /* light blue */\n}\n\ndiv.output_prompt {\ncolor: %s; /* strong orange */\n}\n\ndiv.cell.selected:before, div.cell.selected.jupyter-soft-selected:before {\nbackground: %s; /* light orange */\n}\n\ndiv.cell.selected, div.cell.selected.jupyter-soft-selected {\n    border-color: %s; /* light orange */\n}\n\n.edit_mode div.cell.selected:before {\nbackground: %s; /* light orange */\n}\n\n.edit_mode div.cell.selected {\nborder-color: %s; /* light orange */\n\n}\n'''\ndef to_rgb(h): return tuple(int(h[i:i+2], 16) for i in (0, 2, 4))\nmain_color_rgba = 'rgba(%s, %s, %s, 0.1)' % (to_rgb(main_color[1:])[0], to_rgb(main_color[1:])[1], to_rgb(main_color[1:])[2])\nopen('notebook.css', 'w').write(css_file % (main_color, main_color, main_color_rgba, main_color,  prompt, strong_main_color, main_color, main_color, main_color, main_color))\nfrom IPython.core.display import display, HTML, Javascript\ndef nb(): return HTML(\"<style>\" + open(\"notebook.css\", \"r\").read() + \"</style>\")\nnb()","metadata":{"_cell_guid":"75405d52-594f-4791-a45a-16354bc24cfa","_kg_hide-input":true,"_kg_hide-output":true,"_uuid":"775496bb-f633-46f4-a642-10e6cd29c1bb","jupyter":{"outputs_hidden":false},"papermill":{"duration":0.041763,"end_time":"2021-11-21T16:43:56.713952","exception":false,"start_time":"2021-11-21T16:43:56.672189","status":"completed"},"tags":[],"collapsed":false,"execution":{"iopub.status.busy":"2021-11-28T09:49:12.065587Z","iopub.execute_input":"2021-11-28T09:49:12.065881Z","iopub.status.idle":"2021-11-28T09:49:12.086225Z","shell.execute_reply.started":"2021-11-28T09:49:12.065845Z","shell.execute_reply":"2021-11-28T09:49:12.085258Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from IPython.core.display import display, HTML, Javascript\n# def nb(): return HTML(\"<style>\" + open(\"../input/starter-utils/css_oranges.css\", \"r\").read() + \"</style>\")\ndef nb(): return HTML(\"<style>\" + open(\"notebook.css\", \"r\").read() + \"</style>\")\nnb()","metadata":{"_cell_guid":"75d3e80e-0c31-48f5-88dd-5b6a3c79cf38","_kg_hide-input":true,"_kg_hide-output":true,"_uuid":"968efaca-ede8-4817-b3aa-baedaba3205e","jupyter":{"outputs_hidden":false},"papermill":{"duration":0.03575,"end_time":"2021-11-21T16:43:56.775107","exception":false,"start_time":"2021-11-21T16:43:56.739357","status":"completed"},"tags":[],"collapsed":false,"execution":{"iopub.status.busy":"2021-11-28T09:49:12.124135Z","iopub.execute_input":"2021-11-28T09:49:12.124479Z","iopub.status.idle":"2021-11-28T09:49:12.134266Z","shell.execute_reply.started":"2021-11-28T09:49:12.124437Z","shell.execute_reply":"2021-11-28T09:49:12.133339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"codebook\">Reinforcement Learning Starter</span>\nThis is a simple starter notebook for Kaggle's Crypto Comp showing the usage of reinforcement learning for crypto trading. It uses an up-to-date (auto-updating daily) dataset for all assets discussed [here][4].  There are many configuration variables below to allow you to experiment. Use a different stable-baseline agent. You can control which years are loaded, which models are used, and whether to use feature engineering. You can experiment with different data preprocessing, model hyperparameters, losses, and number of seeds to ensemble. The extra datasets contain the full history of the assets at the same format of the competition, so you can input that into your model too.\n\nThis notebook follows the ideas presented in my \"Initial Thoughts\" [here][1]. Some code sections have been reused from Chris' great notebook series on SIIM ISIC melanoma detection competition [here][3]\n\n____\n**Credits:**\n\nNotebook this is baseline is based on: \n- [Jane Street: Deep Reinforcement Learning Approach](https://www.kaggle.com/gogo827jz/jane-street-deep-reinforcement-learning-approach) by Yirun Zhang\n- [🤖 Deep RL: PPO2 with GPU Baseline 🦾](https://www.kaggle.com/metathesis/deep-rl-ppo2-with-gpu-baseline) by Jim Eric Skogman\n- [Triple Stratified Kfold with TFrecords](https://www.kaggle.com/cdeotte/triple-stratified-kfold-with-tfrecords) by Chris Deotte\n\nIf you find this notebook useful, don't forget about them and drop them some upvotes! \nThey've all earned it!\n____\n\n\n[1]: https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/284903\n[2]: https://www.kaggle.com/yamqwe/let-s-talk-validation-grouptimeseriessplit\n[3]: https://www.kaggle.com/cdeotte/triple-stratified-kfold-with-tfrecords\n[4]: https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/285726","metadata":{"papermill":{"duration":0.024984,"end_time":"2021-11-21T16:43:56.825656","exception":false,"start_time":"2021-11-21T16:43:56.800672","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"codebook\">Why Reinforcement Learning?</span>\n\n\n> Credit: Huge credit to the original kaggle learn tutorial for providing the skeleton for this intro\n\n\n### Introduction\nSo far, on this competition, most notebooks only implemented supervised learning solutions. These solutions have relied on detailed information about how to trade the assets. \nHowever, do to the nature of financial trading [specifically speaking: No \"clearly defined\" target]. A reinforcement learning approach might fit the problem of cryptocurrency trading well.\n\nIn this baseline notebook, I'll try and use reinforcement learning to build an intelligent agent without the use of a supervised target. Instead, we will gradually refine the agent's strategy over time, simply by trading the assets historicly  trying to maximize the the prediction of the target.\n\nSince this is a starter notebook, we won't be able to explore this complex field in detail, but I hope to share about the big picture and explore some code that you can then use and improve yourself.\n\n### From Supervised Neural Networks to Deep Reinforcement Learning\n\nIt's difficult to come up with a perfect heuristic. Improving the heuristic generally entails trading the assets many times, to determine specific cases where the agent could have made better choices. And, it can prove challenging to interpret what exactly is going wrong, and ultimately to fix old mistakes without accidentally introducing new ones.\n\nWouldn't it be much easier if we had a more systematic way of improving the agent with trading experience?\nWe'll just replace the supervised target with a neural network to estimate what should have been the target at the current observation state. \nThe network accepts the current market features as input. And, it outputs a value that is then used for trading.\n\nThis way, to encode a trading strategy, we need only amend the weights of the network so that for every possible market condition, it assigns higher probabilities to better trades.\nAt least in theory, that's our goal. In practice, we won't actually check if that's the case -- since remember that there are infinite possibilies for market conditions.\n\n\n### Reinforcement Learning\nThere are many different reinforcement learning algorithms, such as DQN, A2C, and PPO, among others. All of these algorithms use a similar process to produce an agent:\n\nInitially, the weights are set to random values.\nAs the agent plays the game [Or trades the assets], the algorithm continually tries out new values for the weights, to see how the cumulative reward is affected, on average. Over time, after playing many games, we get a good idea of how the weights affect cumulative reward, and the algorithm settles towards weights that performed better.\n\nOf course, we have glossed over the details here, and there's a lot of complexity involved in this process. For now, we focus on the big picture!\nThis way, we'll end up with an agent that tries to win the game (so it gets the final reward of +1, and avoids the -1 and -10) and tries to make the game last as long as possible (so that it collects the 1/42 bonus as many times as it can).\nYou might argue that it doesn't really make sense to want the game to last as long as possible -- this might result in a very inefficient agent that doesn't play obvious winning moves early in gameplay. And, your intuition would be correct -- this will make the agent take longer to play a winning move! The reason we include the 1/42 bonus is to help the algorithms we'll use to converge better. Further discussion is outside of the scope of this course, but you can learn more by reading about the \"temporal credit assignment problem\" and \"reward shaping\".\nIn the next section, we'll use the Proximal Policy Optimization (PPO) algorithm to create an agent.\n\n### Code\nThere are a lot of great implementations of reinforcement learning algorithms online. In this course, we'll use Stable Baselines.\nCurrently, Stable Baselines is not yet compatible with TensorFlow 2.0. So, we begin by downgrading to TensorFlow 1.0.","metadata":{"papermill":{"duration":0.024996,"end_time":"2021-11-21T16:43:56.875927","exception":false,"start_time":"2021-11-21T16:43:56.850931","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"install\">Installations 💾</span>\n<hr>","metadata":{"papermill":{"duration":0.06695,"end_time":"2021-11-21T16:45:26.796892","exception":false,"start_time":"2021-11-21T16:45:26.729942","status":"completed"},"tags":[]}},{"cell_type":"code","source":"!pip install 'tensorflow==1.15.0'\n!apt-get update\n!apt-get install -y cmake libopenmpi-dev python3-dev zlib1g-dev\n!pip install \"stable-baselines[mpi]==2.9.0\"","metadata":{"_kg_hide-output":true,"papermill":{"duration":147.815702,"end_time":"2021-11-21T16:47:54.681759","exception":false,"start_time":"2021-11-21T16:45:26.866057","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-28T09:49:12.136014Z","iopub.execute_input":"2021-11-28T09:49:12.136487Z","iopub.status.idle":"2021-11-28T09:52:00.499169Z","shell.execute_reply.started":"2021-11-28T09:49:12.136438Z","shell.execute_reply":"2021-11-28T09:52:00.497879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"outline\">Libraries 📚</span>\n<hr>\n\n#### Code starts here ⬇","metadata":{"papermill":{"duration":0.264372,"end_time":"2021-11-21T16:47:55.206423","exception":false,"start_time":"2021-11-21T16:47:54.942051","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import os\nimport json\nimport random\nimport datetime\nimport traceback\nimport numpy as np\nimport pandas as pd\nfrom tqdm import tqdm\nimport gresearch_crypto\n\nimport gym\nfrom gym import spaces\nfrom stable_baselines import PPO2\nfrom stable_baselines.common.policies import MlpPolicy, MlpLnLstmPolicy\nfrom stable_baselines.common.vec_env import DummyVecEnv","metadata":{"papermill":{"duration":4.395419,"end_time":"2021-11-21T16:47:59.885802","exception":false,"start_time":"2021-11-21T16:47:55.490383","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-28T09:52:00.501291Z","iopub.execute_input":"2021-11-28T09:52:00.50167Z","iopub.status.idle":"2021-11-28T09:52:06.676178Z","shell.execute_reply.started":"2021-11-28T09:52:00.501626Z","shell.execute_reply":"2021-11-28T09:52:06.674733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"WINDOW_SIZE = 5","metadata":{"papermill":{"duration":0.263455,"end_time":"2021-11-21T16:48:00.405765","exception":false,"start_time":"2021-11-21T16:48:00.14231","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-28T09:52:06.67892Z","iopub.execute_input":"2021-11-28T09:52:06.67924Z","iopub.status.idle":"2021-11-28T09:52:06.686102Z","shell.execute_reply.started":"2021-11-28T09:52:06.6792Z","shell.execute_reply":"2021-11-28T09:52:06.684893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"loading\">Data Loading 🗃️</span>\n<hr>\n\nThe data organisation has already been done and saved to Kaggle datasets. Here we choose which years to load. We can use either 2017, 2018, 2019, 2020, 2021, Original, Supplement by changing the `INC2021`, `INC2020`, `INC2019`, `INC2018`, `INC2017`, `INCCOMP`, `INCSUPP` variables in the preceeding code section. These datasets are discussed [here][1].\n\n[1]: https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/285726\n","metadata":{"papermill":{"duration":0.253542,"end_time":"2021-11-21T16:48:00.916841","exception":false,"start_time":"2021-11-21T16:48:00.663299","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import datatable as dt\nextra_data_files = {0: '../input/cryptocurrency-extra-data-binance-coin', 2: '../input/cryptocurrency-extra-data-bitcoin-cash', 1: '../input/cryptocurrency-extra-data-bitcoin', 3: '../input/cryptocurrency-extra-data-cardano', 4: '../input/cryptocurrency-extra-data-dogecoin', 5: '../input/cryptocurrency-extra-data-eos-io', 6: '../input/cryptocurrency-extra-data-ethereum', 7: '../input/cryptocurrency-extra-data-ethereum-classic', 8: '../input/cryptocurrency-extra-data-iota', 9: '../input/cryptocurrency-extra-data-litecoin', 11: '../input/cryptocurrency-extra-data-monero', 10: '../input/cryptocurrency-extra-data-maker', 12: '../input/cryptocurrency-extra-data-stellar', 13: '../input/cryptocurrency-extra-data-tron'}\n\n# Uncomment to load the original csv [slower]\n# orig_df_train = pd.read_csv(data_path + 'train.csv') \n# supp_df_train = pd.read_csv(data_path + 'supplemental_train.csv')\n# df_asset_details = pd.read_csv(data_path  + 'asset_details.csv').sort_values(\"Asset_ID\")\n\norig_df_train = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_train.jay').to_pandas()\ndf_asset_details = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_asset_details.jay').to_pandas()\nsupp_df_train = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_supplemental_train.jay').to_pandas()\nassets_details = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_asset_details.jay').to_pandas()\nasset_weight_dict = {assets_details['Asset_ID'].tolist()[idx]: assets_details['Weight'].tolist()[idx] for idx in range(len(assets_details))}\nasset_name_dict = {assets_details['Asset_ID'].tolist()[idx]: assets_details['Asset_Name'].tolist()[idx] for idx in range(len(assets_details))}\n\ndef load_training_data_for_asset(asset_id, load_jay = True):\n    dfs = []\n    if INCCOMP: dfs.append(orig_df_train[orig_df_train[\"Asset_ID\"] == asset_id].copy())\n    if INCSUPP: dfs.append(supp_df_train[supp_df_train[\"Asset_ID\"] == asset_id].copy())\n    \n    if load_jay:\n        if INC2017 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2017) + '.csv'): dfs.append(dt.fread(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2017) + '.jay').to_pandas())\n        if INC2018 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2018) + '.csv'): dfs.append(dt.fread(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2018) + '.jay').to_pandas())\n        if INC2019 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2019) + '.csv'): dfs.append(dt.fread(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2019) + '.jay').to_pandas())\n        if INC2020 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2020) + '.csv'): dfs.append(dt.fread(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2020) + '.jay').to_pandas())\n        if INC2021 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2021) + '.csv'): dfs.append(dt.fread(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2021) + '.jay').to_pandas())\n    else: \n        if INC2017 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2017) + '.csv'): dfs.append(pd.read_csv(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2017) + '.csv'))\n        if INC2018 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2018) + '.csv'): dfs.append(pd.read_csv(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2018) + '.csv'))\n        if INC2019 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2019) + '.csv'): dfs.append(pd.read_csv(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2019) + '.csv'))\n        if INC2020 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2020) + '.csv'): dfs.append(pd.read_csv(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2020) + '.csv'))\n        if INC2021 and os.path.exists(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2021) + '.csv'): dfs.append(pd.read_csv(extra_data_files[asset_id] + '/full_data__' + str(asset_id) + '__' + str(2021) + '.csv'))\n    df = pd.concat(dfs, axis = 0) if len(dfs) > 1 else dfs[0]\n    df['date'] = pd.to_datetime(df['timestamp'], unit = 's')\n    if LOAD_STRICT: df = df.loc[df['date'] < \"2021-06-13 00:00:00\"]    \n    df = df.sort_values('date')\n    return df\n\ndef load_data_for_all_assets():\n    dfs = []\n    for asset_id in list(extra_data_files.keys()): dfs.append(load_training_data_for_asset(asset_id))\n    return pd.concat(dfs)","metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_kg_hide-input":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","papermill":{"duration":1.360085,"end_time":"2021-11-21T16:48:02.531492","exception":false,"start_time":"2021-11-21T16:48:01.171407","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-28T09:52:06.691864Z","iopub.execute_input":"2021-11-28T09:52:06.692359Z","iopub.status.idle":"2021-11-28T09:52:31.606452Z","shell.execute_reply.started":"2021-11-28T09:52:06.692136Z","shell.execute_reply":"2021-11-28T09:52:31.605456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# LOAD STRICT? YES=1 NO=0 | see: https://www.kaggle.com/julian3833/proposal-for-a-meaningful-lb-strict-lgbm\nLOAD_STRICT = True\n\n# WHICH YEARS TO INCLUDE? YES=1 NO=0\nINC2021 = 0\nINC2020 = 0\nINC2019 = 0\nINC2018 = 0\nINC2017 = 0\nINCCOMP = 1\nINCSUPP = 0\n\ntrain = load_data_for_all_assets()\ntest = pd.read_csv('../input/g-research-crypto-forecasting/example_test.csv')\nsample_prediction_df = pd.read_csv('../input/g-research-crypto-forecasting/example_sample_submission.csv')\nprint (\"Loaded all data!\")","metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","papermill":{"duration":10.85542,"end_time":"2021-11-21T16:48:13.644252","exception":false,"start_time":"2021-11-21T16:48:02.788832","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2021-11-28T09:52:31.607851Z","iopub.execute_input":"2021-11-28T09:52:31.608102Z","iopub.status.idle":"2021-11-28T09:52:45.39751Z","shell.execute_reply.started":"2021-11-28T09:52:31.60807Z","shell.execute_reply":"2021-11-28T09:52:45.396608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Data Analysis (from Nov 21 version of this kaggle notebook):\nimport gc\nimport numpy as np\nimport pandas as pd\nimport datatable as dt\npd.set_option(\"display.max_columns\", None)\nfrom datetime import datetime\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nplt.rcParams.update({'font.size': 14})\ndata_folder = \"../input/g-research-crypto-forecasting/\"\n# data_folder = \"/t/Datasets/kaggle_crypto/\"\n# asset_details = pd.read_csv(data_folder + 'asset_details.csv', low_memory=False) \n# train = pd.read_csv(data_folder + 'train.csv', low_memory=False)\nasset_details = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_asset_details.jay').to_pandas()\ntrain = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_train.jay').to_pandas()\nrename_dict = {}\nfor a in asset_details['Asset_ID']: rename_dict[a] = asset_details[asset_details.Asset_ID == a].Asset_Name.values[0]\ntrain['timestamp'] = train['timestamp'].astype('datetime64[s]')\ntrain_daily = pd.DataFrame()\nfor asset_id in asset_details.Asset_ID:\n    train_single = train[train.Asset_ID == asset_id].copy()\n    train_single_new = train_single[['timestamp','Count']].resample('D', on='timestamp').sum()\n    train_single_new['Open'] = train_single[['timestamp','Open']].resample('D', on='timestamp').first()['Open']\n    train_single_new['High'] = train_single[['timestamp','High']].resample('D', on='timestamp').max()['High']\n    train_single_new['Low'] = train_single[['timestamp','Low']].resample('D', on='timestamp').min()['Low']\n    train_single_new['Close'] = train_single[['timestamp','Close']].resample('D', on='timestamp').last()['Close']\n    train_single_new['Volume'] = train_single[['timestamp','Volume']].resample('D', on='timestamp').sum()['Volume']\n    train_single_new['Asset_ID'] = asset_id\n    train_daily = train_daily.append(train_single_new.reset_index(drop=False))\ntrain_daily = train_daily.sort_values(by = ['timestamp', 'Asset_ID']).reset_index(drop=True)\ntrain_daily = train_daily.pivot(index='timestamp', columns='Asset_ID')[['Count', 'Open', 'High', 'Low', 'Close', 'Volume']]\ntrain_daily = train_daily.reset_index(drop=False)\ntrain_daily['year'] = pd.DatetimeIndex(train_daily['timestamp']).year\nfig = make_subplots( rows=len(asset_details.Asset_ID), cols=1, subplot_titles=(asset_details.Asset_Name) )\nfor i, asset_id in enumerate(asset_details.Asset_ID):\n    fig.append_trace(go.Candlestick(x=train_daily.timestamp, open=train_daily[('Open', asset_id)], high=train_daily[('High', asset_id)], low=train_daily[('Low', asset_id)], close=train_daily[('Close', asset_id)]),row=i+1, col=1,)\n    fig.update_xaxes(range=[train_daily.timestamp.iloc[0], train_daily.timestamp.iloc[-1]], row=i+1, col=1)\nfig.update_layout(xaxis_rangeslider_visible = False, \n                  xaxis2_rangeslider_visible = False, \n                  xaxis3_rangeslider_visible = False,\n                  xaxis4_rangeslider_visible = False,\n                  xaxis5_rangeslider_visible = False,\n                  xaxis6_rangeslider_visible = False,\n                  xaxis7_rangeslider_visible = False,\n                  xaxis8_rangeslider_visible = False,\n                  xaxis9_rangeslider_visible = False,\n                  xaxis10_rangeslider_visible = False,\n                  xaxis11_rangeslider_visible = False,\n                  xaxis12_rangeslider_visible = False,\n                  xaxis13_rangeslider_visible = False,\n                  xaxis14_rangeslider_visible = False,\n                  height=3000, width=800, \n                  #title_text=\"Subplots with Annotations\"\n                      margin = dict(\n        l = 0,\n        r = 0,\n        b = 0,\n        t = 30,\n        pad = 0)\n                 )                \nfig.show()\ndel train, train_daily,train_single, asset_details\ngc.collect()\nplt.close()","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:52:45.399317Z","iopub.execute_input":"2021-11-28T09:52:45.399638Z","iopub.status.idle":"2021-11-28T09:53:02.86055Z","shell.execute_reply.started":"2021-11-28T09:52:45.399588Z","shell.execute_reply":"2021-11-28T09:53:02.859543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport plotly.graph_objects as go\nfrom plotly.subplots import make_subplots","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:02.861855Z","iopub.execute_input":"2021-11-28T09:53:02.862544Z","iopub.status.idle":"2021-11-28T09:53:02.867052Z","shell.execute_reply.started":"2021-11-28T09:53:02.862493Z","shell.execute_reply":"2021-11-28T09:53:02.866363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# crypto_df = pd.read_csv(\"../input/g-research-crypto-forecasting/\" + 'train.csv')\n# assets = pd.read_csv('../input/g-research-crypto-forecasting/asset_details.csv')\nassets = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_asset_details.jay').to_pandas()\ncrypto_df = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_train.jay').to_pandas()\nassets_names = dict(zip(assets.Asset_ID, assets.Asset_Name))\nassets_order = dt.fread('../input/cryptocurrency-extra-data-binance-coin/orig_supplemental_train.jay').to_pandas().Asset_ID[:14]\nassets_order = dict((t,i) for i,t in enumerate(assets_order))\nbtc = crypto_df[crypto_df[\"Asset_ID\"]==1].set_index(\"timestamp\")\nbtc_mini = btc.iloc[-200:]\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.show()\ndel btc","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:02.86842Z","iopub.execute_input":"2021-11-28T09:53:02.868797Z","iopub.status.idle":"2021-11-28T09:53:04.882299Z","shell.execute_reply.started":"2021-11-28T09:53:02.868765Z","shell.execute_reply":"2021-11-28T09:53:04.881599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"crypto_df.describe()","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:04.883623Z","iopub.execute_input":"2021-11-28T09:53:04.883973Z","iopub.status.idle":"2021-11-28T09:53:16.497472Z","shell.execute_reply.started":"2021-11-28T09:53:04.883943Z","shell.execute_reply":"2021-11-28T09:53:16.4965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset_details = pd.read_csv('../input/g-research-crypto-forecasting/asset_details.csv')  ","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:16.499034Z","iopub.execute_input":"2021-11-28T09:53:16.499299Z","iopub.status.idle":"2021-11-28T09:53:16.511835Z","shell.execute_reply.started":"2021-11-28T09:53:16.499268Z","shell.execute_reply":"2021-11-28T09:53:16.510804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset_df = crypto_df[crypto_df[\"Asset_ID\"] == 0].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == 0]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:16.513794Z","iopub.execute_input":"2021-11-28T09:53:16.514127Z","iopub.status.idle":"2021-11-28T09:53:17.618402Z","shell.execute_reply.started":"2021-11-28T09:53:16.514081Z","shell.execute_reply":"2021-11-28T09:53:17.617481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 1\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:17.623244Z","iopub.execute_input":"2021-11-28T09:53:17.623876Z","iopub.status.idle":"2021-11-28T09:53:18.698323Z","shell.execute_reply.started":"2021-11-28T09:53:17.623819Z","shell.execute_reply":"2021-11-28T09:53:18.697088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 2\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:18.69976Z","iopub.execute_input":"2021-11-28T09:53:18.70002Z","iopub.status.idle":"2021-11-28T09:53:19.762803Z","shell.execute_reply.started":"2021-11-28T09:53:18.699987Z","shell.execute_reply":"2021-11-28T09:53:19.762028Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 3\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:19.763793Z","iopub.execute_input":"2021-11-28T09:53:19.764024Z","iopub.status.idle":"2021-11-28T09:53:20.735805Z","shell.execute_reply.started":"2021-11-28T09:53:19.763995Z","shell.execute_reply":"2021-11-28T09:53:20.735106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 4\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:20.736823Z","iopub.execute_input":"2021-11-28T09:53:20.737396Z","iopub.status.idle":"2021-11-28T09:53:21.352329Z","shell.execute_reply.started":"2021-11-28T09:53:20.737343Z","shell.execute_reply":"2021-11-28T09:53:21.351329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 5\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:21.353616Z","iopub.execute_input":"2021-11-28T09:53:21.353853Z","iopub.status.idle":"2021-11-28T09:53:22.403495Z","shell.execute_reply.started":"2021-11-28T09:53:21.353824Z","shell.execute_reply":"2021-11-28T09:53:22.402441Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 6\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:22.404869Z","iopub.execute_input":"2021-11-28T09:53:22.405115Z","iopub.status.idle":"2021-11-28T09:53:23.514556Z","shell.execute_reply.started":"2021-11-28T09:53:22.405084Z","shell.execute_reply":"2021-11-28T09:53:23.513824Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 7\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:23.515745Z","iopub.execute_input":"2021-11-28T09:53:23.516413Z","iopub.status.idle":"2021-11-28T09:53:24.593989Z","shell.execute_reply.started":"2021-11-28T09:53:23.516371Z","shell.execute_reply":"2021-11-28T09:53:24.593109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 8\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:24.595316Z","iopub.execute_input":"2021-11-28T09:53:24.595595Z","iopub.status.idle":"2021-11-28T09:53:25.423338Z","shell.execute_reply.started":"2021-11-28T09:53:24.595559Z","shell.execute_reply":"2021-11-28T09:53:25.42231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 9\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:25.42463Z","iopub.execute_input":"2021-11-28T09:53:25.424859Z","iopub.status.idle":"2021-11-28T09:53:26.499489Z","shell.execute_reply.started":"2021-11-28T09:53:25.42483Z","shell.execute_reply":"2021-11-28T09:53:26.498591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 10\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:26.500777Z","iopub.execute_input":"2021-11-28T09:53:26.500996Z","iopub.status.idle":"2021-11-28T09:53:26.893556Z","shell.execute_reply.started":"2021-11-28T09:53:26.500968Z","shell.execute_reply":"2021-11-28T09:53:26.892679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 11\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:26.894828Z","iopub.execute_input":"2021-11-28T09:53:26.895586Z","iopub.status.idle":"2021-11-28T09:53:27.778592Z","shell.execute_reply.started":"2021-11-28T09:53:26.895535Z","shell.execute_reply":"2021-11-28T09:53:27.777646Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 12\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:27.779766Z","iopub.execute_input":"2021-11-28T09:53:27.779997Z","iopub.status.idle":"2021-11-28T09:53:28.728391Z","shell.execute_reply.started":"2021-11-28T09:53:27.779968Z","shell.execute_reply":"2021-11-28T09:53:28.727571Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"asset = 13\nasset_df = crypto_df[crypto_df[\"Asset_ID\"] == asset].dropna() \nprint(asset_details[asset_details[\"Asset_ID\"] == asset]['Asset_Name'])\ncorr = asset_df[['Count', 'Open', 'High', 'Low', 'Close','Volume', 'VWAP', 'Target']].corr()\ncorr.style.background_gradient(cmap='coolwarm').set_precision(5)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:28.729749Z","iopub.execute_input":"2021-11-28T09:53:28.729982Z","iopub.status.idle":"2021-11-28T09:53:29.765787Z","shell.execute_reply.started":"2021-11-28T09:53:28.729953Z","shell.execute_reply":"2021-11-28T09:53:29.764992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(asset_details)","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:29.766852Z","iopub.execute_input":"2021-11-28T09:53:29.767109Z","iopub.status.idle":"2021-11-28T09:53:29.774613Z","shell.execute_reply.started":"2021-11-28T09:53:29.767076Z","shell.execute_reply":"2021-11-28T09:53:29.773492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = crypto_df.copy().set_index(\"timestamp\")\ntrain['assets'] = 1\ntrain['assets'] = train.groupby(by = train.index)['assets'].sum()\ntrain['asset_name'] = train.Asset_ID.map(assets_names)\ntrain['asset_name'].value_counts()\nall_same_time = train[train['assets'] == 14][['Asset_ID', 'Count', 'Open', 'High', 'Low', 'Close', 'Volume', 'asset_name','VWAP','Target']]\ncorr_target = all_same_time.reset_index().pivot(index = 'asset_name', columns = 'timestamp')['Target'].transpose().corr()\ncorr_matrix = all_same_time.reset_index().drop(['Target', 'Asset_ID'], axis=1).pivot(index = 'asset_name', columns = 'timestamp').transpose().corr()\nfig, ax = plt.subplots(1, 2, figsize = (20, 8))\nsns.heatmap(np.round(corr_target, 2), annot = True, ax = ax[0], square = True)\nsns.heatmap(np.round(corr_matrix, 2), annot = True, ax = ax[1], square = True)\nax[0].title.set_text('Asset Targets correlation')\nax[1].title.set_text('Asset Features correlation')","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:53:29.775753Z","iopub.execute_input":"2021-11-28T09:53:29.775988Z","iopub.status.idle":"2021-11-28T09:54:32.274987Z","shell.execute_reply.started":"2021-11-28T09:53:29.775958Z","shell.execute_reply":"2021-11-28T09:54:32.27378Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"try: plt.close()\nexcept: pass\nfig = make_subplots(rows=7, cols=2,shared_xaxes=True, vertical_spacing=0.03, subplot_titles=tuple([assets_names[i] for i in range(14)]))\ndata = all_same_time\ndata['time'] = [pd.to_datetime(x, unit='s') for x in data.index]\nfor i in range(14):   \n    coin = data[data.Asset_ID == i]\n    name = assets_names[i]\n    fig.add_trace(go.Scatter(x=coin['time'], y=coin['VWAP'], name = name + ', VWAP'),row=i//2+1, col= i%2 +1)\nfig.update_layout(height=1000, title_text=' Weighted average prices')\nfig.show()\n# del data, train, crypto_df, all_same_time, corr_target","metadata":{"execution":{"iopub.status.busy":"2021-11-28T09:54:32.27672Z","iopub.execute_input":"2021-11-28T09:54:32.277547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"features\">Feature Engineering 🔬</span>\n<hr>\n\nThis notebook uses upper_shadow, lower_shadow, high_div_low, open_sub_close, seasonality/datetime features first shown in this notebook [here][1] and successfully used by julian3833 [here][2].\n\nAdditionally we can decide to use external data by changing the variables `INC2021`, `INC2020`, `INC2019`, `INC2018`, `INC2017`, `INCCOMP`, `INCSUPP` in the preceeding code section. These variables respectively indicate whether to load last year 2021 data and/or year 2020, 2019, 2018, 2017, the original, supplemented data. These datasets are discussed [here][3]\n\nConsider experimenting with different feature engineering and/or external data. The code to extract features out of the dataset is taken from julian3833' notebook [here][2]. Thank you julian3833, this is great work.\n\n[1]: https://www.kaggle.com/cstein06/tutorial-to-the-g-research-crypto-competition\n[2]: https://www.kaggle.com/julian3833\n[3]: TBD","metadata":{"papermill":{"duration":0.258454,"end_time":"2021-11-21T16:48:14.163215","exception":false,"start_time":"2021-11-21T16:48:13.904761","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# Two features from the competition tutorial\ndef upper_shadow(df): return df['High'] - np.maximum(df['Close'], df['Open'])\ndef lower_shadow(df): return np.minimum(df['Close'], df['Open']) - df['Low']\n\n# A utility function to build features from the original df\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['lower_Shadow'] = lower_shadow(df_feat)\n    df_feat[\"high_div_low\"] = df_feat[\"High\"] / df_feat[\"Low\"]\n    df_feat[\"open_sub_close\"] = df_feat[\"Open\"] - df_feat[\"Close\"]\n    return df_feat","metadata":{"jupyter":{"outputs_hidden":false},"papermill":{"duration":0.268144,"end_time":"2021-11-21T16:48:14.689012","exception":false,"start_time":"2021-11-21T16:48:14.420868","status":"completed"},"pycharm":{"name":"#%%\n"},"tags":[],"collapsed":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def reduce_mem_usage(df,do_categoricals=False):\n    \"\"\" iterate through all the columns of a dataframe and modify the data type\n        to reduce memory usage.\n    \"\"\"\n    start_mem = df.memory_usage().sum() / 1024**2\n    print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))\n\n    for col in df.columns:\n        col_type = df[col].dtype\n\n        if col_type != object:\n            c_min = df[col].min()\n            c_max = df[col].max()\n            if str(col_type)[:3] == 'int':\n                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                    df[col] = df[col].astype(np.int8)\n                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                    df[col] = df[col].astype(np.int16)\n                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                    df[col] = df[col].astype(np.int32)\n                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                    df[col] = df[col].astype(np.int64)\n            else:\n                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n                    df[col] = df[col].astype(np.float16)\n                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n                    df[col] = df[col].astype(np.float32)\n                else:\n                    df[col] = df[col].astype(np.float64)\n        else:\n            if do_categoricals==True:\n                df[col] = df[col].astype('category')\n\n    end_mem = df.memory_usage().sum() / 1024**2\n    print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))\n    print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))\n    return df","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"jupyter":{"outputs_hidden":false},"papermill":{"duration":0.282344,"end_time":"2021-11-21T16:48:15.227263","exception":false,"start_time":"2021-11-21T16:48:14.944919","status":"completed"},"pycharm":{"name":"#%%\n"},"tags":[],"collapsed":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train = train.sort_values('timestamp')\ntrain.drop(columns = 'timestamp', inplace = True)\ntrain.drop(columns = 'date', inplace = True)\ntarget = train['Target'].copy()\ntrain.drop(columns = 'Target', inplace = True)\ntrain = reduce_mem_usage(train)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"jupyter":{"outputs_hidden":false},"papermill":{"duration":9.274865,"end_time":"2021-11-21T16:48:24.758894","exception":false,"start_time":"2021-11-21T16:48:15.484029","status":"completed"},"pycharm":{"name":"#%%\n"},"tags":[],"collapsed":false,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trian = get_features(train)\ntrain = reduce_mem_usage(train)\ntrain.head()","metadata":{"papermill":{"duration":6.245992,"end_time":"2021-11-21T16:48:31.267866","exception":false,"start_time":"2021-11-21T16:48:25.021874","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"timestamp = datetime.datetime.now()\nMODEL_ID = f\"g_research_ppo_{timestamp.strftime('%s')}\"","metadata":{"papermill":{"duration":0.264276,"end_time":"2021-11-21T16:48:31.792307","exception":false,"start_time":"2021-11-21T16:48:31.528031","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"config\">Defining the GYM Environment 🎚️</span>\n<hr >","metadata":{"papermill":{"duration":0.287788,"end_time":"2021-11-21T16:48:32.339661","exception":false,"start_time":"2021-11-21T16:48:32.051873","status":"completed"},"tags":[]}},{"cell_type":"code","source":"class GResearchEnv(gym.Env):\n\n    def __init__(self, df, target, window_size = 5):\n        super(GResearchEnv, self).__init__()\n        self.idx = 0\n        self.df = df\n        self.n_samples = df.shape[0]\n        self.window_size = window_size\n        self.target = target.values\n        self.features = [col for col in list(self.df.columns)]\n        self.states = df[[col for col in list(self.df.columns)]].values\n        # Possible actions = target estimate\n        self.action_space = spaces.Box( np.array([-1.0]), np.array([+1.0])) \n        # Prices contains the technical feature values for the last five prices\n        self.observation_space = spaces.Box(low=-8.215050, high=5.872849e+01, shape=(df[self.features].shape[1], self.window_size))\n\n    def _next_observation(self):         \n        return np.array([self.df[self.idx: self.idx + self.window_size][feature].values for feature in self.features])\n\n    def step(self, action):\n        obs = self._next_observation()\n        reward = -1.0 * (action - self.target[self.idx]) # Rewarding the agent inversely proportional to it's error\n        self.idx += 1\n        if self.idx >= self.n_samples - self.window_size:\n            done = True\n            self.idx = 0\n        else: done = False\n        return obs, reward, done, {}\n\n    def reset(self):\n        self.idx = 0\n        return self._next_observation()\n\n    def render(self):\n        print(f'Step: {self.idx}')\n\n        \nclass GResearchPredictEnv(gym.Env):\n\n    def __init__(self, df, target, window_size = 5):\n        super(GResearchPredictEnv, self).__init__()\n        self.idx = 0\n        self.df = df\n        self.n_samples = df.shape[0]\n        self.window_size = window_size\n        self.target = target.values\n        self.features = [col for col in list(self.df.columns)]\n        self.states = df[[col for col in list(self.df.columns)]].values\n        # Possible actions = target estimate\n        self.action_space = spaces.Box( np.array([-1.0]), np.array([+1.0])) \n        # Prices contains the technical feature values for the last five prices\n        self.observation_space = spaces.Box(low=-8.215050, high=5.872849e+01, shape=(df[self.features].shape[1], self.window_size))\n\n    def _next_observation(self):         \n        return np.array([self.df[self.idx: self.idx + self.window_size][feature].values for feature in self.features])\n\n    def step(self, action):\n        obs = self._next_observation()\n        reward = -1.0 * (action - self.target[self.idx]) # Rewarding the agent inversely proportional to it's error\n        self.idx += 1\n        if self.idx >= self.n_samples - self.window_size:\n            done = True\n            self.idx = 0\n        else: done = False\n        return obs, reward, done, {}\n\n    def reset(self):\n        self.idx = 0\n        return self._next_observation()\n\n    def render(self):\n        print(f'Step: {self.idx}')\n        \nfeatures, window_size = [col for col in list(train.columns)], WINDOW_SIZE\nenv = DummyVecEnv([lambda: GResearchEnv(train, target, window_size = WINDOW_SIZE)])","metadata":{"papermill":{"duration":2.260823,"end_time":"2021-11-21T16:48:34.860252","exception":false,"start_time":"2021-11-21T16:48:32.599429","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"training\">Reinforcement Learning 🏋️</span>\n<hr>","metadata":{"papermill":{"duration":0.263682,"end_time":"2021-11-21T16:48:35.397076","exception":false,"start_time":"2021-11-21T16:48:35.133394","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## Network architecture <a name=\"architecture\"></a>\n\nWe are going to train a neural network, which is structured in the following way:\n\n\n                                -------> Actor ---> Logits (𝜋)\n                              /\n    State (𝑠) ---> Encoder --- --------> Critic-1 ---> Value-1 (𝑉-1)\n                              \\\n                                -------> Critic-2 ---> Value-2 (𝑉-2)\n\n\nEach critic head predicts state-value $V_\\theta(s)$ (estimate of discounted return from this point onwards), where $\\theta$ stands for neural net parameters. Actor updates policy parameters for $\\pi_\\theta$, in the direction suggested by Critics.\n\nI won't go into details here, for more reading visit this amazing notebook: https://www.kaggle.com/alexandersamarin/training-resnet-agent-from-scratch","metadata":{"papermill":{"duration":0.262672,"end_time":"2021-11-21T16:48:35.920902","exception":false,"start_time":"2021-11-21T16:48:35.65823","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## PPO algorithm explained <a name=\"ppo\"></a>\n\nFirstly, we will define policy gradient loss:\n\n$$\\mathcal{L}^{\\text{PG}}(\\theta) = \\mathbb{E}[\\log \\pi_\\theta(a|s) \\hat{A}_\\theta(s,a) ],$$\n\nwhere first term $\\log \\pi_\\theta(a|s)$ are log-probabilities from the output of policy network (actor head), and the second one is an estimate of `advantage function`, the relative value of selected action $a$. The value of $\\hat{A}_\\theta(s,a)$ is equal to `return` (or `discounted reward`) minus `baseline estimate`. Return at given time $t$ is calculated as follows:\n\n$$ V_{\\text{target}}(t) = R_{t+1} + \\gamma R_{t+2} + \\gamma^2 R_{t+3} + \\dots = \\sum_{k=0}^\\infty \\gamma^k R_{t+k+1},$$\n\nwhere $R^i_t$ is a reward at timestep $t$. Baseline estimate is the output of value network $V_\\theta(s)$. Therefore,\n\n$$ \\hat{A}_\\theta(t) = V_{\\text{target}}(t) - V_\\theta(s_t). $$\n\nThere also exists a generalized version of advantage estimation, that we are going to use:\n\n$$\\hat{A}_\\theta(t) = \\delta_t + (\\gamma \\lambda) \\delta_{t+1} + \\dots = \\sum_{k=0}^\\infty (\\gamma \\lambda)^k \\delta_{t+k+1},$$\n$$ \\text{where } \\delta_t = R_t + \\gamma V_\\theta(s_{t+1}) - V_\\theta(s_t),$$\n\nwhich is reduced to previous equation when $\\lambda = 1$.\n\nNow, when $\\hat{A}_\\theta$ is positive, meaning that the action agent took resulted in a better than average return, we will increase probabilities of selecting it again in the future. On the other hand, if an advantage was negative, we will reduce the likelihood of selected actions.","metadata":{"papermill":{"duration":0.264227,"end_time":"2021-11-21T16:48:36.44746","exception":false,"start_time":"2021-11-21T16:48:36.183233","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"However, as PPO-paper quotes:\n\n`While it is appealing to perform multiple steps of optimization on this loss using the same trajectory, doing so is not well-justified, and empirically it often leads to destructively large policy updates.`\n\nIn other words, we have to impose the constraint which won't allow our new policy to move too far away from an old one. Let’s denote the probability ratio between old and new policies as\n\n$$r(\\theta) = \\frac{\\pi_{\\theta}(a|s)}{\\pi_{\\theta_{\\text{old}}}(a|s)}. $$\n\nThen, take a look at our new `surrogate` objective function:\n\n$$\\mathcal{L}^{\\text{CPI}}(\\theta) = \\mathbb{E}[r(\\theta) \\hat{A}_\\theta(s,a)].$$\n\nIt can be derived that maximimizing $\\mathcal{L}^{\\text{CPI}}(\\theta)$ is identical to vanilla policy gradient method, but I'll bravely skip the proof. Now, we would like to insert the aforementioned constraint into this loss function. The main objective which PPO-parer proposes is the following.\n\n$$J^{\\text{CLIP}}(\\theta) = \\mathbb{E}[\\min (r(\\theta) \\hat{A}_{\\theta_{\\text{old}}}(s,a), \\text{clip}(r(\\theta), 1-\\epsilon, 1+\\epsilon)\\hat{A}_{\\theta_{\\text{old}}}(s,a)],$$\n\nwhere $\\epsilon$ is a `clip ratio` hyperparameter. The first term inside $min$ function, $r(\\theta) \\hat{A}_{\\theta_{\\text{old}}}(s,a)$ is a normal policy gradient objective. And the second one is its clipped version, which doesn't allow us to destroy our current policy based on a single estimate, because the value of $\\hat{A}_{\\theta_{\\text{old}}}(s,a)$ is noisy (as it is based on an output of our network).\n\nWhen applying PPO on the network architecture with shared parameters for both policy and value functions, in addition to the clipped reward, the objective function is augmented with an error term on the value estimation and an entropy term to encourage sufficient exploration. Final loss then becomes:\n\n$$\\mathcal{L}(\\theta) = \\mathbb{E}[-J(\\theta) + c  (V_\\theta(s) - V_{\\text{target}})^2 - c_{\\text{ent}}  H(s, \\pi_{\\theta}(\\cdot))], $$\n\nwhere $c$ and $c_{\\text{ent}}$ are both hyperparameter constants.","metadata":{"papermill":{"duration":0.259346,"end_time":"2021-11-21T16:48:36.969861","exception":false,"start_time":"2021-11-21T16:48:36.710515","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## OpenAI's stable baselines\nTo use this on the competition, we should implement it from scratch since we are not allowed to use internet on the final submissions. \nCurrently, to get things up and running: We are simply going to use OpenAI's stable-baselines. \nAs this is a work in progress: The next versions of this notebok will contain an ecapsulated implementation of the PPO agent. ","metadata":{"papermill":{"duration":0.257497,"end_time":"2021-11-21T16:48:37.486055","exception":false,"start_time":"2021-11-21T16:48:37.228558","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## Training and evaluation","metadata":{"papermill":{"duration":0.259718,"end_time":"2021-11-21T16:48:38.006141","exception":false,"start_time":"2021-11-21T16:48:37.746423","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def learn(timesteps=1000):\n    model = PPO2(MlpLnLstmPolicy, env, verbose=1, nminibatches=1)\n    model.learn(total_timesteps=timesteps)\n    model.save(MODEL_ID)\n    print(f\"Saved model: {MODEL_ID}\")\nlearn()","metadata":{"papermill":{"duration":58.593833,"end_time":"2021-11-21T16:49:36.860775","exception":false,"start_time":"2021-11-21T16:48:38.266942","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\" id=\"submit\">Submit To Kaggle 🇰</span>\n<hr>","metadata":{"papermill":{"duration":0.256822,"end_time":"2021-11-21T16:49:37.377265","exception":false,"start_time":"2021-11-21T16:49:37.120443","status":"completed"},"tags":[]}},{"cell_type":"code","source":"all_df_test = []\n\npredict_df = pd.DataFrame()\ngr_env = gresearch_crypto.make_env() # initialize the environment\niter_test = gr_env.iter_test()       # an iterator which loops over the test set\nmodel = PPO2.load(MODEL_ID)\nfor i, (df_test, df_pred) in enumerate(iter_test):\n    for j, row in df_test.iterrows():\n        try:                        \n            row_feats = get_features(row)\n            predict_df.append(row_feats)\n            if len(predict_df) > window_size:\n                obs = np.array([predict_df[idx: idx + window_size][feature].values for feature in features])\n                action, _states = model.predict(np.expand_dims(obs, axis = 0)) # _states are only useful when using LSTM policies\n            else: action = 0.0\n            y_pred = action             \n        except: \n            y_pred = 0.0\n            traceback.print_exc()\n        df_pred.loc[df_pred['row_id'] == row['row_id'], 'Target'] = y_pred\n    all_df_test.append(df_test)\n    gr_env.predict(df_pred)    ","metadata":{"papermill":{"duration":24.72817,"end_time":"2021-11-21T16:50:02.364116","exception":false,"start_time":"2021-11-21T16:49:37.635946","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# <span class=\"title-section w3-xxlarge\">References</span>\n\n<span id=\"f1\">1.</span> [Initial baseline notebook](https://www.kaggle.com/julian3833)<br>\n<span id=\"f2\">2.</span> [Competition tutorial](https://www.kaggle.com/cstein06/tutorial-to-the-g-research-crypto-competition)<br>\n<span id=\"f3\">3.</span> [Competition Overview](https://www.kaggle.com/c/g-research-crypto-forecasting/overview)</span><br>\n<span id=\"f4\">4.</span> [My Initial Ideas for this competition](https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/284903)</span><br>\n<span id=\"f5\">5.</span> [My post notebook about cross validation](https://www.kaggle.com/yamqwe/let-s-talk-validation-grouptimeseriessplit)</span><br>\n<span id=\"f5\">6.</span> [Chris original notebook from SIIM ISIC](https://www.kaggle.com/cdeotte/triple-stratified-kfold-with-tfrecords)</span><br>\n\n<span class=\"title-section w3-large w3-tag\">WORK IN PROGRESS! 🚧</span>","metadata":{"papermill":{"duration":0.266664,"end_time":"2021-11-21T16:50:02.897328","exception":false,"start_time":"2021-11-21T16:50:02.630664","status":"completed"},"tags":[]}}]}