{"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":"![Screenshot-2020-10-21-at-18.12.57.png](attachment:6372a40f-c121-4aca-a795-1effdf50eeb2.png)","metadata":{},"attachments":{"6372a40f-c121-4aca-a795-1effdf50eeb2.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAA5gAAAI+CAMAAADuJFXIAAABnWlUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogICA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPgogICAgICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgICAgICAgICB4bWxuczpleGlmPSJodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyI+CiAgICAgICAgIDxleGlmOlBpeGVsWERpbWVuc2lvbj45MjA8L2V4aWY6UGl4ZWxYRGltZW5zaW9uPgogICAgICAgICA8ZXhpZjpQaXhlbFlEaW1lbnNpb24+NTc0PC9leGlmOlBpeGVsWURpbWVuc2lvbj4KICAgICAgPC9yZGY6RGVzY3JpcHRpb24+CiAgIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CmwPiyoAAAAJcEhZcwAAFiUAABYlAUlSJPAAAAIrUExURf///4ODg35+fgkJCZXDgKysrKSkpAAAAO7u7llZWcjIyMnJyS0tLY+Pj/7+/vr6+nNzcx0dHWNjYxUVFWlpaQ8PD11dXQICAri4uAwMDMzMzGtra2ZmZqOjoz4+PkBAQO3t7djY2M7OzuPj43Z2dhsbG4uLi1JSUs/Pz46OjigoKN3d3RISEh8fH7u7u39/f0lJSfHx8Z+fn3V1dVBQUNLS0gcHB2VlZampqZKSkvv7+/j4+GFhYfDw8PT09Pb29uHh4TQ0NLq6ut/f33JycsPDw8bGxiQkJEdHR4WFhcXFxbSztDY2Nnx8fNnZ2dvb2wQEBEVFRa+vr3h4eObm5p2dnVZWVrCwsNHR0ZiYmEJCQnl5eW5ubjg4OLy8vKKiohcXFyoqKiYmJr+/vzExMSEhIWBgYOrq6mpqaoiIiPLy8js7O5aWljMzM7W1tYaGhpycnJmZmevr6+Li4i4uLktLS76+vre3t6amphkZGSsrK6ioqP39/VpaWoyMjNbW1tTU1AEBATk5OYmJiaqqqiIiIpWVlXt7e01NTcHBwVxdW56eno+4fOXl5ejo6FhYWIKCgqWlpV9fX5GRkVVVVZPAf3mRbneObXBwcFFRUaenp36bcWl3ZICecmVuYcfHx4Ggc19kXW1tbWNrYIuxeYOjdOzs7Ieqd5G7fbKysomueHKGaWt5ZY21e3uUb2x6ZXSJa3GEaV5hXIWndn2YcHqUb2hzYm5+Z2BlXhpV1ekAACAASURBVHja7N3pUxTXHsbxA5QOSNhFFhFJgIgXEEElOiMgrojIorjGq17Bq4UoEomJBBVwJZQouXmhvvGdVf6Xt3/n9Dr0tFrX61DJ91Ml03O655yBzEP3WZooBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAV5OosRSk2tspez+hktwz5x78drh2xivqqnF0dMWT26upyU713Oiwilo/6/uIV463Ha75xIM/8dsCvor1zZbZYNnumKU81St+kL0zITuO5Xvb74qbYsa9B2NOYV3MM1dS3dZpl18yRWVOEl+b50XB6v9hFf3zM76zmaosXc2FT/xByLEJPhBYHbbI57HhCwTzYU/MDWZBXZkvg02LIcEUpesCwYytsY/75ksEM3+vXes4wcTfNpgdrwdjbjBrR4MBLPstPJixpoeBYK43hy3NfYlg5jqNvCOY+NsGU5+e7GDGb5hEtE9tn27XW4MjXjArSi0Vg+aQvkAwj5jX/xr7EsHcI1VsyW28mCCY+GsEM7vS0vpZwfy3L5jmxDj6TsZ3lg7q09+Qt8O+Xh24Puh2K51gxg7oXcVfJJgtUsXDTz/+jnzT+XwgsHqDGe1jwdylo1jojOqe00M9jcnBVGqnPDvhBrPI+ndb72i2n/1vwdwhlb7nPzD+OsHsz7McsJ+MZOysPnmrSzVYZbd9wewf/32+6vawPmZNXp8Ubs3Ly7bHVPu8c8+QdVHbfWtlMBflWZsbzA3Wv5f6XCpXwX9GB7P18cmezRcWv/X2xk9sfNPXPZQzfkeedeblbZZKj+bl9fqOke/rO/PbQzbNKPAJa2utUnelxEzi5J+py5nve151e8x77coWgfT1MTv/MJeV3UvSZ6v3gjlueokld6XovDuc81AVlMjjIa+2huXZuFIrg1klzyrdYJ6S2iTOk9bG5g2RwexttkeVWpzp0PJm5x0MtliV1HoDTM98VcigVI7XuB6Tmmkyw05eH/OuO3ZVMeG8cmWLQPqC+dMV5zP65EIgmHvdEddDScEc0R3M0LYCwXxX6h6ngzmbZb+R09bjq8hgPvAmY6qXdMlClm+s92jKYGbISLC+Cj8iu6pk67BsbfMFs8Ff13GVokUgjcHcqD+L9dX2agEvmFYiu4v0486kYLbJw+nUwTzd0tKS+eygvvYt2uUFs18qeWBdR8oZdyEqmA06JU/Mm9LhmtE5y6qeL42Z826KYM460ycH9K4rUnZcwhr3BfNfcqp8WXd9WvrKZf3hLQJpDOa3cr1a8dbayhtMCuZ6q4P2i3xey1qtHtvCdilbWFjo0mel2I+pg+nTbXqodjDlhT1WCCRiiahgVsubOqFUQrI0KH3hD3q4yUrV2Kh9Pd3QIDXERhoahv11SIAzrcdT5g28sC9v/1BeMF/IY64cvCzVZ4S3CKQxmLontkc5JxZfMKvjbk/trGx5o7K67JypqPCyoy8smBse+oN5SD79CfXAejivIoJ5LGZOrdaJUkK119oYXtPyZkj3D7e6HdxC2UpabquHarutx/vmDay1c/jBF8xt8vhYH711sVJXGtIikMZgypmiqUuXZWcFgvlBF+5xY+AFU1/92oMmP7gZvBoWzNjchC+YBdLCiOqxvmZEBTNTju7QRf+RC1f/MYmnsvNYMJgFXba47lDOXVPqsnWmtzaLlbotvw66fMEcNrOwLSPeYoOoFoGvH8x663HeLvwmEEw9KWH6k9uCwZzw9cPCgvlnZmbms8KNW8ww5/deMGVeJXa8oEJnPSKYLyVKuVqef7VO9q2Wngpd6ZlgMJ0FC9ZJL/+e9XBJ9zW3WP3RJ0q9cXrEbh/TGe/K2m6mXlK3CKQlmF1zvnGcnwPBNDN8b91RIi+Yl7yVPqHBdEZlC+qk9oqfvGAeleQt6C5mVDBvJp129dqFF6+m5tySDymDqeOXoyRek7LAYV+iwpk28UZlS70zeo7uT4a2CKQrmO/1ctPQYMaThm+9YDboe73Mup+lfsvZ8GAqpZfUTnrB7JWhpAsm1hHBvJcUE7mUriyxz3LdIZey/mCW6wmT59bXAbnqbbsoqxnGAsFU76a9yrO+S9EikL5L2Qp3nblS08EFBimDaS4FffdadaUK5is9luoFU1/FtpuJyIhgSvaaij2VSuXKK8uGvs8tWCdV/ZI6mAVyOjxkfWlW/TL8JMuUflbBYKr8hY1XnddcyQ9tEUhjMCWMpeZ25mvtHw+mKdSrxy93fjyYG5wZfDuYupMpeiODKQsQSoO7rkuRjsuC+468YC5vtF20x2OHzLhPkdXEFWdZYPLdJQOLe+ud69aQFoE0BvO+O0+gLsQig1nsfaz36RGYHmeBTHZhimCO6b7cfl8wJ+yFcAWRwXwmx5iVCbtPrdOXoTI9eV+XbAoJZsAaO/xv7VvVYrHBmkAwxyp/bTmoz/0ze+3KQloEvkIwD7V64r686ZuNszYpFf9xLjqY+mNtz+XrKYvY5cfXrNedfdSUNPizSRrJvjYwqXtuZWO+YB42SRlSkcEckImO89LJbZSz+M24isvqh6vylsaOhAz+BHSaO0Tnltz7Ps+rQDD14vdNukhGo2K1YS0CXyOYfvv9eas2K9X7spKX5CUH86RedZDZMytdNOeStH603al11A1mULHyBTNuZjsmooOpcuSgG9vuLN90Tuh6vU9hrZo1LS9HBFM914dMKfcvJTwNBlOvJih51JDfult+pzSHtwikM5iNT5ziqdHIYDpXiHpAtPN0cqXPa8KDWZ3wB1MvLjCLWaOC2e8fJZ2WxQEZZvWu8/e/MqKCqedeY69lc0qfO4eDwcx/Y//9BVPnxfAWgXQGUw1P2QnqGHJOH6HBTNihsNfibfXfoRHrO2NKVwRz3tzI7AZTdzIr4h8Jphqed2uYknlQFe9z7nWp2+wMJKcK5vuy4IyKs4DCHfwp8P1I2s16xJUtAmkNpuqY3HC1/v5kQg+ZTqcMpprVk3/32uxqO8admxqvvF5w2nKDWTaYVXpv9NWAXe4GU0929KiPBVMldkzrRfVFW+2RmM6TcoIrG+1V41I+EBFM3Ykc1K8r91+Y+kZly3vMRe7gXne9+ooWgdWh2jenGSa/8UR54FbF7F23Ftf01v6f3k6icnl/v28UZqzy7cKXy4z13jfdbYxHtgiky9Oh4oxL9nR6szslASCt1uoLun2y+Ug28/iRAOnXaGZLtrwqvCG9rpJsfiTAKnAyMC60yA8EWA1mqga9/9PIBH8OGVglagtvPMmS+6l2XOOHAawqY9yzDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/svemX9VcWRxnO3R/WVJ2NfHokR8KAgCD0WNBATXIIoGVBwiEgkiokxiRpMQPMFlIGgEFPeciMk4JtHMTCYz/970UzQcfF29VfWrN30/P8VDdzh1uZ+u6r61EARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEARBEAThCklFqXGFKGyvqO0domi8ZsUXw7vStmxJ2zX8RQdF4zXrW2or2ildhFMwPIAlNLZRsEOU+eqWhiXNR26GGPpsApQubmhZrUV3f19VZrwSn1nVd0T7V2EehWXovBaIu807LmTv25d9YUdzfSgHt1Fc8gopXdzg2ihQsiZf+YP4HSXAmaDH49J/B6ubVy0Ji3Lso9WY9W32dliCZyhd3Oku/fjrZWU5VTuBTk/HZQ74U/bysOQ3Az3XvRyWbmBnVdh06SaXuD4AZ3E6XnmT3D7Ay+OTUdSkhwmLklmMuPXeDcsk0Jerky67ySZ+dGQhRQnPCaDfs3EpQk12+LDkluCkZ0ezwRyc0E2XnHHyiRdqmq6XinIcKPBoXHy6XipKw36kejVdWrGGkS6tpWQUtwTU91JRUlDu0QT0r87WD0t2vVcfWEbpUkRG8UrA+nhGpOO9moHsBPTsA8s4XfaSU24koFczUM1iJqBnH1jG6ZJKTnGh51tmAirxXXjXg2HZbZCAWgZ+6Ml06aJ0cYUm1LATUDmHtR6MyyVUscNyAl9RulC6CKMDxQaRLkGyB+NSjkp2WDJxgNKF0kUYvThtEOnTGPFgXAbRwA5LAzIoXShdKNIkJqULjU1obEJDWUoXepunjz+ULsQyqFwSFiqX6KQLlUtcgiYYhIUmGNhNF5pgwCkD/XdpSp71DKQpeTQlL6IZSJPYaRK7pXShSezcMjDKln35jia5lIFRt+yrFD7x6ULLvtwiyhZK+wB3zIy+hdLjcMFMWijtGlqoo2hrEU1Ml8xkbC3SLuXWIuNodcFM2lrENa5CbzMujEsoZq9LZh6C3mZcqIiRU8zEOy6YuaC7GRdoZ0+elCFDZ/vKw+iRUMzkde6Y2YjG8NtXJvoxKamYF48KN3MvsnS2r5zDDbKJI4mY0dvwORaJEoqptrhh5p+R06Sz4XMbMkrlFFMNCjdzFJ16Gz5fdaG/9g5fZqAsRueIhPeAgIRiqnkumOnDBzF6RySMSvlVNiSmGlwQa8cQoOodkbACWEFC8eKz16XKMIcKjaB1k4Riqn8Rb2bhq1mfYQ4ValrAOknFVAOFQs3cgysv/yPcoUI+XCWheBHHXA9Q/qLfkE5MdUS0mdsRy/hpAXIOSiqmGhgUaWYaLjJ+egPnyShef807rB9fn3WpOGFRTHWPYDPPoI3141qclFVMNZAlzswCdp+4DThETnHhsMGJE70o3Or0d8yAJy/FFGzmNmSx38zTsIfH70niGpqXYqoBvzAzKwzG8HuQ9iVJxedd3mCdTiOGnf6SWMTxY05d5KlIM2uxkX1BkE/VzsczNHGLzyxxZh7ElrfZV0yglqziwFND7VTnVbvYV70cXwSa+fYAjE70uocbXMRMFBGawAYxZn5huAz1YA7tYcCDVuPJPc6rdoLEFGhmi4l6CJeqnSAx1UCGEDOzjIcJ67DQJFuW9yZFm5cFaDe+yHHVTpSY4szswUrDa/byqNqJElMNbBFg5iTOGF+UisOypTmibubDV+g1vqhpAS1yiinKzIuoM3FVJ4cZi8LEFGLmDWw3vqg0g/1BOyJiRpmZ2ru8mfkDTqt24sQUZOYVc59cOVTtxImpBmZ5Z2MHFsz1q35VOjGjy8zzJreUcli1EyimEDNVjJkqEXGo2gkUUw3kcM7Gsyb/f8OYk03MxOgy049PTF33lrOqnUgxRZjZiVFzF44gbZO8YvI2s2kKfzN14dZCM29IroqpRpWZ/aY7QmdVO6FiCjDzqOktpRxX7YSKqQbGeGbjCBpNXpmM2euSiRlVZlabz2hHVTuxYobM/JhnWJJQbfol3WnVTqyYITP5LR19B0Gzl36DCdnEjCIz9+Ko+YudVO2Ei1nHdauPCQs7HTmdsShaTI6jiYCFUyE2tUp1hskLMaPHzNCSVwsW26/aiRWzG3VlPMPyCfwWrk51NmNRrJgreY7yU63sAKU9Ed6TTcxoMXPrGEotfRHpkVLMTs5exhRZKoKoGxxV7YSKWcDTy4+RY2VrwBnmsjkzYxEfPxbFjBIzXy95Na3XjIRi+nh7uSkDloq2bdigyilmMtevYpfwjaXre6yMx8L2cjxRo8jMOuaS1zfZZnufEYFiXuLtpfbWaPEcr2EnMxYFipnE92v1oMVzvMbh7LgEIJEfvWr0mLnS8tDUdtVOnJgbuXsZ025183lHVTtxYm7n62Wb5aGpz8w8bMP3Qt7Ib2aq9QmwExZHM8LFvMffy3G0Wr0l2cGMRWFi7uZc3d1l/VW6GvfkE1N6M69jwPI2/3ardqLEnOHvpTYwfWr5HgdVO1FitnH2ci0GbdxjvvDpnpiym7nRzpwVm1U7QWImCvDyXcB6TXRTmu2qnSAxJ3nPhqrFJTufF+vekk9Myc3MsjXHbs5W1S6W5/e1AysEehnTbWsx4SHbMxZ9XL89Pl0MTT9vLzfPws4cu5MOZiyKE1NqM9vMLHl9E3WDnSlevliOvOp9hXgZc8fecS0zuGHzlZZraBZ7X/6nu+TZ+/J8bcr+MY4CxZTZzFibJzM5q9px4NX2lWK8LECcvRudVu34fLdKFOSl1jx7lbIWHG2SUEx5zVyLQpt3Ho7w6QCLYorxMqbcbuVjBSJ/yPmimAK8DOIdm3emml1B566YMppZ5js7cSAHGdWNRVaHGVvX1Vb0jCFj6a74kRFTgJdJRY3VhWNjBybO+qyuVQkdouDH1NJDFCInJmcvF9PFH3vFcttChygcGMMGe+kiVsyQmTJZea27fenHgoxaCyOUpNQw58hERkzuXhYMb1natvLJIQuZG+7YoYiJydXLZelipW3hjx2iHjN8sEKnyk39+vz7n/5+64ff7t/+TvtntcluU+egvoiIydvLF207l3L5WH5uQ2X68VNd5tumc1BfxMTk6eWLtnUVH0+vbMjNP3Y5pcZC214c1Pef+YdPphOmnzycf2A9XTz0jtmfBvz3/q2EP/hhXnNz9JqJR6fO0bbBSIjJ2ctQ23Z+Wrn01PL0r022rT/80ba+zRESk6eXoXT5+vLSU92zP9+JHDNtC54BHvz+bEmmTf/7gcV08c5X2Ubg1ycJy7g1/y/4DcezBX69w+A73ReTs5da21b35S5v24UjZto2p3cYfI8aGTE5eqm1rThzedv2ffotegwrmt3Adw+XZ1rCQ60T6JZCTLm8LMLjN4Ol8exnZBlsyRWcxel45U1y+4A818Xk62VwAM35YdqmrDFu2yhq0sPdmlkckbPAxsHRy1Gcq9JpW5zB3KhJYP5WmEy7NQ8LRTqvzPwZwaOfEsLzD8QxX8w7/EhRwnMCFrbh4CQmVy87BvGRTtvSjdpWhJrs8LfmluBsRMTk5mUR6it14nIKJ5mj2WAO7utk2n3kjEdcTLm8LMDUbwl6/JNZm1TTdL1UlOOwP7fDFodieXqpte193bals9vm0/VSURr2R+CP31SXxO/xd/OYblxOMdOltBXPdTPtOVrVCIspWQUzFt8n6PMLKwN9DC8VJeX1SfFupR/f/reY0bZ0VttU/+ps/Vuz7w6Uuf5H5vYb1UGkM+JSzEqXItxmZNpt01Z4Yz1mC35hRCvhR0YGqv76eMYfKb7e5S6TJ1oCrlJsZiD7eaU9sEajNiwGzytlFSNd9uLRNCPTph9lqWbF9MAOBuvv4EeWmKwu0yAB3e8y3UtAVgaqWcznVeiBdej/9XnFemClMjtMC12mJ/b8ScYDZrS0LvMDvXt7upgJqMR3GZ1JLS/tBgmoHNFd7bTb4HmlPbA+jNawJKNEMXhg6aXLekxNMzNtesrktFtP7JKXh5/ZYj7T3Xy8CTXsP5JyzuIuTRLhRz67be/rdg2XUMW+9YTVTb1kSpdmdtvyddNlGx6zMy3hMba63iBp95VNxO8G4Zoa0Lm1w2C0pyglUXu29xBuGrTtc91ZBuWoZN+aaWHj8hjZ0mWNQVxu6qVLAftjhsYDDsf92hNTwhUlFcxvsv9j70z/mjqXOA4Chh/CFYLsW2WpooDIptBcqoAioiiCKJoLiIqICNiKcEGBKrJZl7ZaaW2tWtxftPX6af3zbiICWc6ShOSc5Jzf9w3knPEF48wzT555ZmZxHRM50mvDRZn/pIt+1Q3fHXbJ7gZiRAfKdaNM+p+WwRiojpkrt8M3FIqZy5Dc3iz0LQrUcUx/rMGkY9Ix9e6Yflkbza0st7I638r6Z88CHv7w8Effhz9+2kuE6RJhmC4RMRc/SJd41zH9tMcPLxiI/W28YCD0t/nDBQMvO6afdsXjlTyPLJBX8tS7kuddx/TbPrLaucSuoAUG2iV2by5Yql9i9yZtEX6ras2UfXnZArVU9uXVBUv1si+9oJVCaS+jpUJpb6J+obRu0EhrEW+jodYiXkX11iL6QRvNuLy/yddMMy7vonYzLh2hifaV3mdV7SvNftS+0gfmomL7Sj2hhYbPPgmazg2fuwOw4bNPzEW1hs/6IvBHJPjINbUwIsHn5lKj5IgE3fFxSkxqvNnDoUIHU5Ci5lAhn2EdKmSOT/V0qFC0yaT2UCFfmsu8h0OFNGsuRDl+q1j+jcqwYblGoYdnqkQF+k2fpmUP4GdqY5nNCP60XHWn/pvqIEqzCxuWQgTA88NlopbzuVMopzqI0rSvxMl6FP+LClnkDrqWEiQ93bhChRBlqTChefnDeRRRI4vstFFFBLruUCNEUQpsOw7cngvou/nepBs2qcuBgK4lIoHItJ0rVsH8JXViYQ/6bT6tn8cQdUIUZALRdp+jArnQ2YsE29873wx8TaUQ5ZhCvd3nF0ZWQgRZD6hT7B+kLSVPCFGAcMDhcsosmLULCrqFSYcnTSwRIcpxxHnn2susXdCX8fjK4dE4cIj2QhRiHg2OjyqZtQtKFOhEP4mDtBeiDOuEOhgza2fZtwr04NyGnbQYogg3BNv7HNV71q4UQt2ZtwITNBmiAFnYIXQFr6JG51m7cuG//xiyaTNEAdbiO8HnOs/afYV44VsW/YE7/oEEEFeNYlPl1uo6axcmNqIk6xpvLBLfc0X8u+RJDfQB9JgU0cRIIsxf0G6Ij1kjPuFTz1m7vRLbhbFA72hN/J+NmBd/qeOsXT9mxb9+mrCXlkN8SqvkJbNtGNWnWqqXOzoIcRobttN0iA/pgeTkXd1m7YqkV6QpTNF2iA95jV6Z97rM2q03QfLeU8+GAJ8nRfycGozLfdfSY9auCrnSAnthOkfrIb4iWfZ0R59Zu2lkykgM2DZjIcS7jKFNTkSPWbsJFMuJfDEPjiMhPqIZpgpZoVz99Rlx7OggRCauZdGCiE8YduUL5Auj3rJ24bhWKS/VjjpaEPEJqS5dU9dd1u6Ia3uEbPYZIT5h1sWh7HqbDmB27ugg/E2UfUaIL7iHCJfkerp1lbWLEOroIMROrKEREa9zCGYXJX/TVdbuhsvL0BqnNnqErIassLSB8hRE97ZPyu7GxifbW81IjWptn9yq+WA5WtRbh/jyge9kp81urxo+2o9ra6aODrexbz3xAg4zzCXns29MM9vKnqxv1q5eHEbeS81nd5zlPsDSabJawiyG1JLeGZNXlpDUcTOy0PKxV2Sjeq7X8vLp2/fPF169Wnj+/u0Hy8cwjaplPNjyxxVG3uxISijLi+m80AKYxSq/Zq2rVeOp/NgQQ0hs/qkTlk/B47Qsskr7u34zwbBC3EghUmZF7O/d2+ehNvzvz3iNmqBlucrYEmejloSY6yIrlnW5ytiSZCMbUpuh3RWLKGR/jTkGB8p2Q6jIxGJ//yyEOvDmFy2aYFYwWrY4qsUQM4gU53PrCDN+qnWS3dKCYN4EIp775eUEgzP5M4hylG3Fh0ehAvyoPc/MKsaJWAG1hByAU0YpwrLjSBKQjT2BaHom8dQv8w2CxBU6emY7PiyECvJEa55p8csMYbUYLjt6psUvz4jIXqBnEk/9slPEqJw8MwxzL0NDdeGZ4cVoLBPTi2WXb1sBlgkcEBO1eGZxOK2MuEvlM4yIGpXVM0tXZO+k4nloqLhnPqvUjl6OoTBJXC/X7RasKFwQF7V4Jm/PErfpwz4JozLU2t6ITcNfoRL8hT7NqOWLGtRKqCVuk02Th3EgT0I2jx1nidtczZY0QINh38qd7Op4vJFyzDcovqoVvVRJr1eGEbQuy7ZKbGStHEAVDY24R6aMAVpC5tol2Z+lA6Y1ZK7Til62yaxXCfuwtG+vlA6Y1pC5jYZG3KNAZrU3xK00H5/CI2nHfK+dMZHdiJPWy3VUfxL9GoPSooaZ+PW0NOIWw9giY1UtxiXZg3gp7ZgvcUMrR2JokVFL5HI7skzRtMoSGSzRJG4ShRgZqyrE7U+yO/BK2jFfSXYqDyR2oVBGLTHLJ12JuCgju1u+uxkhduQiR9YxlxLkRjqmkGMOyTrmRRTQ0ohbrJXdyt7vWpI9KX0oa93K9mtELT24L6OWkeWDrmSky25lN9LSiFskYre0USWtHClG4Vdpx3wkMoY6ANmBJINMDmSpQLxaNroOopKWRtxindzJRc7KDOU0PJR2zIfYoxW9HJTb4p9Ynru0HS0hkqIhLdk0NOIe4d0yFpi+MgzhOJ5+K+WX3z7doJlboWEy+9OzNiO3P0ekzAEuqzKJly0wx3bm+yXpkPlQQwYYvkFywTpcaDO8JRklUiEzpCSVt9iJBxYY41rADArKMj1dEPfLBQ0FTLkFK9J2vZIJmQyYxDMLvN8hURnhUPb1WDRjsvC7tsq+oiXuRHXCbtpZMiTOtiMRzYBJPCANJXmifnnevjDiEn55IOqXazWllkOposXPZ+HQZPY0cFbUL1O30saIJ1zCoOBuNi4dBx3nk9ThD8Fk5vPfMaAxtZR+jzOHReKl47C9PpGYefgM5iZoYcQzfgB2Ox9f1G5Ck9No8/AmzP3o5JYP/gR+0Jxako1odN7lJ10AjjjJHgEynBsEdTTiWjTti3hKnwkznfYZ9Y7/AO0CefHKduDvR3bfNB/8+jeMfRpUS/UYEGnvbkmdJWgSauSc3IS7DrJ5kcDYvHZK4Yg6JojGzryPXW6+SYo9MwNh+1s0Qcz98WTh45fNBwtP/pmz2F+1RlcsIzCzOzbpm48NPfOsnWIFl6tPKxYKL8cubj1CYkf2wbpcnWYxJlkN+1u7rW397w82llh/dk21iV4jq6wa67LKvHv8+J31Z+qAdmfYVh+593HcQUnj4H3rz+nR46Kym9OyrSJ3S07MVA5rXwAABXlJREFU3LX+EnzMulxlM2SS1dEQNnAj2xhvDp4aLZXpEXJ182hvXbTJVFPXO6r1MQDb96SVb0uJ39E0divxjoxsc2JR7nQ8jNO5RVUvFh8xZBLiD2Q5FL8VM2QSoj6TSLP7zJBJiB8wD4cbBcXgPD5CVKYU0w5PruAe1UKIurQ6t72OZsgkRF3Wx8PpznobQyYh6nIaY84PGTIJUZd+OE+1ZcgkRF2akSr0uIYhkxAVCUOR0OO2lUEThBDFiUZDkHDIzKRyCFGJCTQJvyhgyCRENQbwWuTNPEMmISpRYcKLIIZMQvyLWbuulo4hczMVRIganMd+0XdVqKOCCFGBczBKvDUzZBKiBsdWBjAJkKiZIYWEBBTZkGyzYsZx6ogQpdmIYsn3DJmEqMAtgUbQDJmEqIwRMk30GDIJUZz9OC8n8gyl1BMhivI5ZuVEhuR9lxDiTT5DV4WsEEMmIcpSj0vyQn24QU0RoiAnMeGCVApDJiEK0oAaV8QYMglRkiKEuSSX4lJgJYR4hVQ0uyTHkEmIckS4XNTVzZBJiFLk4rSLkvUSxdSEEG+xPblgshzXbtXvkR/hmxUxNPw96oaHIm5TcYT4ziur6rBCzessKa8Ma7KRXZPYTPUR4gteFJmAksjOmzEd/82vPZVu8bexBhHZhjHL28KRzrM5sTlnO0capWQJIZ6TmAKk5xtWCDlVCAz3CIj2DAObDsTayOad+UlElhDiOc3/b+9uXuI6ozgAk7q4HmtAZ0xTA42BTIgklkgRQ9EmlFCUVhSjhJIBE4PtRmqldShpQ0LtZkIWAyUL6bK7/pd1phPrOHPvhM6bVZ9nMy7O6sCPcz+O7/0+Yvd01Fq2X8fY+121l8YidobOlA7tRIz5pgmkNFyN9fGs24XD+ODs2t1aqUeEj5V3o3RTKyGZu+diKuttNG6vdWa4Ejs5tQexMayZkMrzWJ/PcpN51PF09rdYySvNPvdaE5LZitnJ3LAdJ3P/VO1e7OaXZoexpZ2QRjWWCsKWLce/t45XJmKmoHQmKtoJiQbmclEus6VTI/OjggvZphUjE9K4VTwwmyPzs3bp3SgcmM2ReUtDIYU/40JxMA9PTiq4GvXi0qz++zMdhcEtRONicdgOYq9d+3Xua5U3HsY9LYXBbUatT9i+OTmaa6vPLWbzJvOllsLg1mK9T9ienhxU8FfucsEbO/GVlsLghuN6n7DdiD/atSNxuU/tZZ80gSQWY6jf5ekX7dLVmO0TzNmwlQcpVOJpcdim4sd26ZV4MF9YOv/gSEMhhf3CLbssexzVk9r3Yruwdrtjfw/4z25GlLO3XIAdiVrRu5WLtfCfX5BqZK4ULvNUT9WeL1wTWjIwIeHIHM3NWrnesf66GjGeWzseBiYkM5KfzGvXz3wu4WV+Mo9zabsAkibzu56PW580uj5j8lPEjZzXnfGhVkLKZC5G7eOuqE3uRo/PC92PmOp+WlSeirivkZDUvecRK9c6Y/lkrvfBd5c2ojHaGc2Z0UZsOCQPktsrRcytlCd/bS0KzCwdT8B4dKdn6Z1HzfOeD8r/bAwNlX9ezq8FBhuav4y1vncwt1573fxdfDWdWzu9f7tZ0qg/rDeaf0x8Mq2B8I68eFWdaIXz26NzXy70uS09Xym1akuVT6US3rFnP6xefdur0oXNF5sLWgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPxP/Q1aIBvO5d67PwAAAABJRU5ErkJggg=="}}},{"cell_type":"markdown","source":"**LightGBM** is a gradient boosting framework that uses tree based learning algorithms. It is designed to be distributed and efficient with the following advantages:\n\n- Faster training speed and higher efficiency.\n\n- Lower memory usage.\n\n- Better accuracy.\n\n- Support of parallel, distributed, and GPU learning.\n\n- Capable of handling large-scale data.\n\nFor more details, please refer to [LightGBM’s documentation!](https://lightgbm.readthedocs.io/en/latest/)","metadata":{}},{"cell_type":"markdown","source":"## The Previous Notebook : <br>\n### [Questions and answers📝EDA to Forecasting](https://www.kaggle.com/yassershrief/questions-and-answers-eda-to-forecasting/edit)<br>\n## The RNN-LSTM Model  : <br>\n### [Stock-LSTM-Deep Learning](https://www.kaggle.com/yassershrief/crypo-lstm-2022-actual-price-91-acc/edit)","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport datatable as dt\nimport random\nfrom lightgbm import LGBMRegressor\nimport gresearch_crypto\nimport traceback\nfrom sklearn.metrics import mean_absolute_error, mean_squared_error\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-02-03T12:18:04.072091Z","iopub.execute_input":"2022-02-03T12:18:04.072439Z","iopub.status.idle":"2022-02-03T12:18:06.409590Z","shell.execute_reply.started":"2022-02-03T12:18:04.072350Z","shell.execute_reply":"2022-02-03T12:18:06.407840Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Datatable** (heavily inspired by R's data.table) can read large datasets fairly quickly and is often faster than pandas. It is specifically meant for data processing of tabular datasets with emphasis on speed and support for large sized data. 👌","metadata":{}},{"cell_type":"code","source":"df = dt.fread('../input/g-research-crypto-forecasting/train.csv').to_pandas()\ndf['datetime'] = pd.to_datetime(df['timestamp'], unit='s')\ndf = df.set_index('datetime').drop('timestamp', axis=1)\n\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:18:06.411708Z","iopub.execute_input":"2022-02-03T12:18:06.411942Z","iopub.status.idle":"2022-02-03T12:18:39.340568Z","shell.execute_reply.started":"2022-02-03T12:18:06.411912Z","shell.execute_reply":"2022-02-03T12:18:39.339753Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_asset_details = pd.read_csv('../input/g-research-crypto-forecasting/asset_details.csv').sort_values(\"Asset_ID\")\ndf_asset_details","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:19:23.949581Z","iopub.execute_input":"2022-02-03T12:19:23.949874Z","iopub.status.idle":"2022-02-03T12:19:23.972848Z","shell.execute_reply.started":"2022-02-03T12:19:23.949843Z","shell.execute_reply":"2022-02-03T12:19:23.971825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# preprocessing","metadata":{}},{"cell_type":"markdown","source":"## Split data\nTraning data before `13-06-2021` and validation data from `14-06-2021` to the end<br>\nKindly refer to the [topic](https://www.kaggle.com/c/g-research-crypto-forecasting/discussion/285505)","metadata":{}},{"cell_type":"code","source":"df_train = df[(df.index< '2021-06-13 00:00:00')]\ndf_val = df[(df.index > '2021-06-13 00:00:00')]\ndisplay(df_train.tail(1))\ndisplay(df_val.head(1))","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:19:26.040155Z","iopub.execute_input":"2022-02-03T12:19:26.040418Z","iopub.status.idle":"2022-02-03T12:19:27.104459Z","shell.execute_reply.started":"2022-02-03T12:19:26.040391Z","shell.execute_reply":"2022-02-03T12:19:27.103716Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### features Engineering","metadata":{}},{"cell_type":"code","source":"def get_features(df):\n\n    df['upper_shadow'] = df['High'] / df[['Close', 'Open']].max(axis=1)\n    df['lower_shadow'] = df[['Close', 'Open']].min(axis=1) / df['Low']\n    df['open2close'] = df['Close'] / df['Open']\n    df['high2low'] = df['High'] / df['Low']\n    mean_price = df[['Open', 'High', 'Low', 'Close']].mean(axis=1)\n    median_price = df[['Open', 'High', 'Low', 'Close']].median(axis=1)\n    df['high2mean'] = df['High'] / mean_price\n    df['low2mean'] = df['Low'] / mean_price\n    df['high2median'] = df['High'] / median_price\n    df['low2median'] = df['Low'] / median_price\n    df['volume2count'] = df['Volume'] / (df['Count'] + 1)\n    return df   ","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:19:28.544071Z","iopub.execute_input":"2022-02-03T12:19:28.544517Z","iopub.status.idle":"2022-02-03T12:19:28.554537Z","shell.execute_reply.started":"2022-02-03T12:19:28.544488Z","shell.execute_reply":"2022-02-03T12:19:28.553702Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_Xy_and_model_for_asset(df_train, asset_id):\n    df = df_train[df_train[\"Asset_ID\"] == asset_id]\n    \n    df_proc = get_features(df)\n    df_proc['y'] = df['Target']\n    df_proc = df_proc.replace([np.inf, -np.inf], np.nan).dropna(how=\"any\")\n    \n    X = df_proc.drop(['Open', 'High', 'Low', 'Close', 'Volume', 'VWAP',\"y\",'Target'], axis=1)\n    y = df_proc[\"y\"]\n\n    model = LGBMRegressor( \n                          n_estimators = 800, \n                          learning_rate = 0.01, \n                          max_bin = 15, \n                          num_leaves = 100\n                        \n                          )\n    model.fit(X, y)\n    return X, y, model","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:19:32.152110Z","iopub.execute_input":"2022-02-03T12:19:32.152443Z","iopub.status.idle":"2022-02-03T12:19:32.161224Z","shell.execute_reply.started":"2022-02-03T12:19:32.152413Z","shell.execute_reply":"2022-02-03T12:19:32.159953Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Models Traning","metadata":{}},{"cell_type":"markdown","source":"There are two ways to try out:<br>\n- 1- modelling each asset separately\n- 2- the multiple asset LGBM model\n","metadata":{}},{"cell_type":"markdown","source":"## 1- Loop over all assets","metadata":{}},{"cell_type":"code","source":"Xs = {}\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(df_train, asset_id)    \n    Xs[asset_id], ys[asset_id], models[asset_id] = X, y, model\nprint(\"Models training finished\")","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:22:41.877325Z","iopub.execute_input":"2022-02-03T12:22:41.877599Z","iopub.status.idle":"2022-02-03T12:32:01.531431Z","shell.execute_reply.started":"2022-02-03T12:22:41.877570Z","shell.execute_reply":"2022-02-03T12:32:01.530496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Evaluate all models on the validation set:","metadata":{}},{"cell_type":"code","source":"def Evaluate(ID):   \n    \n    crypto_model=models[ID]\n    df_all = get_features(df_val)\n    df_crypto=df_all[df_all['Asset_ID']==ID]\n    \n    df_crypto['y'] = df_crypto['Target']\n    df_crypto = df_crypto.replace([np.inf, -np.inf], np.nan).dropna(how=\"any\")\n    \n    X_crypto = df_crypto.drop(['y','Target','Open', 'High', 'Low', 'Close', 'Volume', 'VWAP'], axis=1)\n    y_crypto = df_crypto[\"y\"]\n\n    print(f'MAE Of model : {mean_absolute_error(y_crypto, crypto_model.predict(X_crypto)):.6f}')\n    print(f'MSE Of model : {mean_squared_error(y_crypto, crypto_model.predict(X_crypto)):.6f}')\nfor asset_id, asset_name in zip(df_asset_details['Asset_ID'], df_asset_details['Asset_Name']):\n    print(f\"The mean and abs squared errorfor {asset_name:<16} (ID={asset_id:<2})\")\n    Evaluate(asset_id)\n    print('-'*40)\nprint('*'*15,'The evaluation done','*'*15)    ","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:32:35.129173Z","iopub.execute_input":"2022-02-03T12:32:35.130470Z","iopub.status.idle":"2022-02-03T12:33:46.208287Z","shell.execute_reply.started":"2022-02-03T12:32:35.130395Z","shell.execute_reply":"2022-02-03T12:33:46.207574Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 2-Full Model","metadata":{}},{"cell_type":"code","source":"df = df_train.copy()\n    \ndf_all = get_features(df)\ndf_all['y'] = df['Target']\ndf_all = df_all.replace([np.inf, -np.inf], np.nan).dropna(how=\"any\")\n    \nX = df_all.drop(['Open', 'High', 'Low', 'Close', 'Volume', 'VWAP',\"y\",'Target'], axis=1)\ny = df_all[\"y\"]","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = LGBMRegressor( \n                        n_estimators = 100, \n                          learning_rate = 0.01, \n                            max_bin = 15, \n                              num_leaves = 100\n                          )\nmodel.fit(X, y)","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:19:59.493705Z","iopub.execute_input":"2022-02-03T12:19:59.494249Z","iopub.status.idle":"2022-02-03T12:21:57.562799Z","shell.execute_reply.started":"2022-02-03T12:19:59.494214Z","shell.execute_reply":"2022-02-03T12:21:57.562132Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Evaluate:","metadata":{}},{"cell_type":"code","source":"df_all = get_features(df_val)\n    \ndf_all['y'] = df_all['Target']\ndf_all = df_all.replace([np.inf, -np.inf], np.nan).dropna(how=\"any\")\n    \nX_crypto = df_all.drop(['y','Target','Open', 'High', 'Low', 'Close', 'Volume', 'VWAP'], axis=1)\ny_crypto = df_all[\"y\"]\n\nprint(f'MAE Of model : {mean_absolute_error(y_crypto, model.predict(X_crypto)):.6f}')\nprint(f'MSE Of model : {mean_squared_error(y_crypto, model.predict(X_crypto)):.6f}')\nprint('*'*15,'The evaluation done','*'*15) ","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:22:02.492816Z","iopub.execute_input":"2022-02-03T12:22:02.493256Z","iopub.status.idle":"2022-02-03T12:22:09.467601Z","shell.execute_reply.started":"2022-02-03T12:22:02.493224Z","shell.execute_reply":"2022-02-03T12:22:09.466904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# feature importance\nfi_df = pd.DataFrame()\nfi_df['features'] = X_crypto.columns\nfi_df['importance'] = model.booster_.feature_importance(importance_type=\"gain\")","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:22:32.392992Z","iopub.execute_input":"2022-02-03T12:22:32.393691Z","iopub.status.idle":"2022-02-03T12:22:32.402769Z","shell.execute_reply.started":"2022-02-03T12:22:32.393656Z","shell.execute_reply":"2022-02-03T12:22:32.401615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# plot feature importance\nfig, ax = plt.subplots(1, 1, figsize=(7, 15))\nsns.barplot(\n    x='importance'\n    , y='features'\n    , data=fi_df.sort_values(by=['importance'], ascending=False)\n    , ax=ax\n)","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:22:34.956129Z","iopub.execute_input":"2022-02-03T12:22:34.956917Z","iopub.status.idle":"2022-02-03T12:22:35.279170Z","shell.execute_reply.started":"2022-02-03T12:22:34.956850Z","shell.execute_reply":"2022-02-03T12:22:35.278281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predict & submit","metadata":{}},{"cell_type":"code","source":"# #**********For submit sepretly models for each asset*************\n# env = gresearch_crypto.make_env()\n# iter_test = env.iter_test()\n\n# for i, (df_test, df_pred) in enumerate(iter_test):\n#     for j , row in df_test.iterrows():\n        \n#         model = models[row['Asset_ID']]\n#         x_test = get_features(row)\n#         y_pred = model.predict([x_test])[0]\n        \n#         df_pred.loc[df_pred['row_id'] == row['row_id'], 'Target'] = y_pred\n        \n        \n#         # Print just one sample row to get a feeling of what it looks like\n#         if i == 0 and j == 0:\n#             display(x_test)\n\n#     # Display the first prediction dataframe\n#     if i == 0:\n#         display(df_pred)\n\n#     # Send submissions\n#     env.predict(df_pred)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Submit the full model.**","metadata":{}},{"cell_type":"code","source":"features = ['Asset_ID', 'Count', 'upper_shadow', 'lower_shadow', 'open2close', 'high2low', 'high2mean', 'low2mean', 'high2median', 'low2median', 'volume2count']","metadata":{"execution":{"iopub.status.busy":"2022-02-03T12:36:04.429906Z","iopub.execute_input":"2022-02-03T12:36:04.430388Z","iopub.status.idle":"2022-02-03T12:36:04.436556Z","shell.execute_reply.started":"2022-02-03T12:36:04.430356Z","shell.execute_reply":"2022-02-03T12:36:04.435938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gresearch_crypto\nenv = gresearch_crypto.make_env()   # initialize the environment\niter_test = env.iter_test()    # an iterator which loops over the test set and sample submission\nfor (test_df, sample_prediction_df) in iter_test:\n    # feature engineering\n    test_df = get_features(test_df)\n    \n    # inference\n    sample_prediction_df['Target'] = model.predict(test_df[features])  # make your predictions here\n    \n    # register your predictions\n    env.predict(sample_prediction_df)  ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}