From 9f47d57754803e8ecc6e0cbd69b771bd8adc4e90 Mon Sep 17 00:00:00 2001 From: Bruce Yang FinTech Date: Fri, 15 Mar 2024 15:50:48 +0800 Subject: [PATCH 01/11] Update LICENSE --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index df41d1ccc..cbeb60a10 100755 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2020 AI4Finance Foundation +Copyright (c) 2024 AI4Finance Foundation Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 7b114915bf8091e0e65f836ff7bb0fc10461d4d9 Mon Sep 17 00:00:00 2001 From: "Duc M. Nguyen" <56928903+kurone02@users.noreply.github.com> Date: Wed, 20 Mar 2024 18:26:30 +0900 Subject: [PATCH 02/11] Fixing tuple, and 'UTC has no key' errors in examples/FinRL_PaperTrading_Demo.ipynb (#1186) * fix: tuple and 'UTC has no key' errors * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- examples/FinRL_PaperTrading_Demo.ipynb | 29 ++++++++++++++------------ requirements.txt | 2 +- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/examples/FinRL_PaperTrading_Demo.ipynb b/examples/FinRL_PaperTrading_Demo.ipynb index 7a0913277..f9f5fb09d 100644 --- a/examples/FinRL_PaperTrading_Demo.ipynb +++ b/examples/FinRL_PaperTrading_Demo.ipynb @@ -317,9 +317,9 @@ " action, logprob = [t.squeeze(0) for t in get_action(state.unsqueeze(0))[:2]]\n", "\n", " ary_action = convert(action).detach().cpu().numpy()\n", - " ary_state, reward, done, _ = env.step(ary_action)\n", + " ary_state, reward, done, _, _ = env.step(ary_action)\n", " if done:\n", - " ary_state = env.reset()\n", + " ary_state, _ = env.reset()\n", "\n", " states[i] = state\n", " actions[i] = action\n", @@ -411,11 +411,12 @@ " self.if_discrete = False # discrete action or continuous action\n", "\n", " def reset(self) -> np.ndarray: # reset the agent in env\n", - " return self.env.reset()\n", + " resetted_env, _ = self.env.reset()\n", + " return resetted_env\n", "\n", " def step(self, action: np.ndarray) -> (np.ndarray, float, bool, dict): # agent interacts in env\n", " # We suggest that adjust action space to (-1, +1) when designing a custom env.\n", - " state, reward, done, info_dict = self.env.step(action * 2)\n", + " state, reward, done, info_dict, _ = self.env.step(action * 2)\n", " return state.reshape(self.state_dim), float(reward), done, info_dict\n", "\n", " \n", @@ -424,7 +425,9 @@ "\n", " env = build_env(args.env_class, args.env_args)\n", " agent = args.agent_class(args.net_dims, args.state_dim, args.action_dim, gpu_id=args.gpu_id, args=args)\n", - " agent.states = env.reset()[np.newaxis, :]\n", + "\n", + " new_env, _ = env.reset()\n", + " agent.states = new_env[np.newaxis, :]\n", "\n", " evaluator = Evaluator(eval_env=build_env(args.env_class, args.env_args),\n", " eval_per_step=args.eval_per_step,\n", @@ -502,14 +505,14 @@ "def get_rewards_and_steps(env, actor, if_render: bool = False) -> (float, int): # cumulative_rewards and episode_steps\n", " device = next(actor.parameters()).device # net.parameters() is a Python generator.\n", "\n", - " state = env.reset()\n", + " state, _ = env.reset()\n", " episode_steps = 0\n", " cumulative_returns = 0.0 # sum of rewards in an episode\n", " for episode_steps in range(12345):\n", " tensor_state = torch.as_tensor(state, dtype=torch.float32, device=device).unsqueeze(0)\n", " tensor_action = actor(tensor_state)\n", " action = tensor_action.detach().cpu().numpy()[0] # not need detach(), because using torch.no_grad() outside\n", - " state, reward, done, _ = env.step(action)\n", + " state, reward, done, _, _ = env.step(action)\n", " cumulative_returns += reward\n", "\n", " if if_render:\n", @@ -525,7 +528,7 @@ "id": "9tzAw9k26nAC" }, "source": [ - "##DRL Agent Class" + "## DRL Agent Class" ] }, { @@ -634,7 +637,7 @@ "\n", " # test on the testing env\n", " _torch = torch\n", - " state = environment.reset()\n", + " state, _ = environment.reset()\n", " episode_returns = [] # the cumulative_return / initial_account\n", " episode_total_assets = [environment.initial_total_asset]\n", " with _torch.no_grad():\n", @@ -644,7 +647,7 @@ " action = (\n", " a_tensor.detach().cpu().numpy()[0]\n", " ) # not need detach(), because with torch.no_grad() outside\n", - " state, reward, done, _ = environment.step(action)\n", + " state, reward, done, _, _ = environment.step(action)\n", "\n", " total_asset = (\n", " environment.amount\n", @@ -1693,8 +1696,8 @@ "source": [ "def get_trading_days(start, end):\n", " nyse = tc.get_calendar('NYSE')\n", - " df = nyse.sessions_in_range(pd.Timestamp(start,tz=pytz.UTC),\n", - " pd.Timestamp(end,tz=pytz.UTC))\n", + " df = nyse.sessions_in_range(pd.Timestamp(start),\n", + " pd.Timestamp(end))\n", " trading_days = []\n", " for day in df:\n", " trading_days.append(str(day)[:10])\n", @@ -1889,7 +1892,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.10" + "version": "3.10.11" }, "vscode": { "interpreter": { diff --git a/requirements.txt b/requirements.txt index 78291dd7c..2c62a4345 100644 --- a/requirements.txt +++ b/requirements.txt @@ -43,7 +43,7 @@ swig tensorboardX wheel>=0.33.6 +wrds # market data & paper trading API yfinance -wrds From 239e9327d9b672051d7b743f5d09557f79962228 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 17:28:52 +0800 Subject: [PATCH 03/11] [pre-commit.ci] pre-commit autoupdate (#1187) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/psf/black: 24.2.0 → 24.3.0](https://github.com/psf/black/compare/24.2.0...24.3.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f298d1b2c..3f7545eac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -21,7 +21,7 @@ repos: - id: pyupgrade args: [--py37-plus] - repo: https://github.com/psf/black - rev: 24.2.0 + rev: 24.3.0 hooks: - id: black - repo: https://github.com/PyCQA/flake8 From 5fc7fee8f1e1afb2d82ee18e902ba7eb42ba5692 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 21 Mar 2024 07:49:14 +0800 Subject: [PATCH 04/11] Bump black from 23.3.0 to 24.3.0 (#1188) Bumps [black](https://github.com/psf/black) from 23.3.0 to 24.3.0. - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/compare/23.3.0...24.3.0) --- updated-dependencies: - dependency-name: black dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 56 ++++++++++++++++++++++++-------------------------- pyproject.toml | 2 +- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8c5cc9e32..bb5c95b32 100644 --- a/poetry.lock +++ b/poetry.lock @@ -441,36 +441,33 @@ lxml = ["lxml"] [[package]] name = "black" -version = "23.3.0" +version = "24.3.0" description = "The uncompromising code formatter." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, - {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, - {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, - {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, - {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, - {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, - {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, - {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, - {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, - {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, - {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, - {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, - {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, - {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, + {file = "black-24.3.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7d5e026f8da0322b5662fa7a8e752b3fa2dac1c1cbc213c3d7ff9bdd0ab12395"}, + {file = "black-24.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9f50ea1132e2189d8dff0115ab75b65590a3e97de1e143795adb4ce317934995"}, + {file = "black-24.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2af80566f43c85f5797365077fb64a393861a3730bd110971ab7a0c94e873e7"}, + {file = "black-24.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:4be5bb28e090456adfc1255e03967fb67ca846a03be7aadf6249096100ee32d0"}, + {file = "black-24.3.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4f1373a7808a8f135b774039f61d59e4be7eb56b2513d3d2f02a8b9365b8a8a9"}, + {file = "black-24.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:aadf7a02d947936ee418777e0247ea114f78aff0d0959461057cae8a04f20597"}, + {file = "black-24.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c02e4ea2ae09d16314d30912a58ada9a5c4fdfedf9512d23326128ac08ac3d"}, + {file = "black-24.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:bf21b7b230718a5f08bd32d5e4f1db7fc8788345c8aea1d155fc17852b3410f5"}, + {file = "black-24.3.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:2818cf72dfd5d289e48f37ccfa08b460bf469e67fb7c4abb07edc2e9f16fb63f"}, + {file = "black-24.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4acf672def7eb1725f41f38bf6bf425c8237248bb0804faa3965c036f7672d11"}, + {file = "black-24.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7ed6668cbbfcd231fa0dc1b137d3e40c04c7f786e626b405c62bcd5db5857e4"}, + {file = "black-24.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:56f52cfbd3dabe2798d76dbdd299faa046a901041faf2cf33288bc4e6dae57b5"}, + {file = "black-24.3.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:79dcf34b33e38ed1b17434693763301d7ccbd1c5860674a8f871bd15139e7837"}, + {file = "black-24.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e19cb1c6365fd6dc38a6eae2dcb691d7d83935c10215aef8e6c38edee3f77abd"}, + {file = "black-24.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65b76c275e4c1c5ce6e9870911384bff5ca31ab63d19c76811cb1fb162678213"}, + {file = "black-24.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5991d523eee14756f3c8d5df5231550ae8993e2286b8014e2fdea7156ed0959"}, + {file = "black-24.3.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c45f8dff244b3c431b36e3224b6be4a127c6aca780853574c00faf99258041eb"}, + {file = "black-24.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6905238a754ceb7788a73f02b45637d820b2f5478b20fec82ea865e4f5d4d9f7"}, + {file = "black-24.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7de8d330763c66663661a1ffd432274a2f92f07feeddd89ffd085b5744f85e7"}, + {file = "black-24.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:7bb041dca0d784697af4646d3b62ba4a6b028276ae878e53f6b4f74ddd6db99f"}, + {file = "black-24.3.0-py3-none-any.whl", hash = "sha256:41622020d7120e01d377f74249e677039d20e6344ff5851de8a10f11f513bf93"}, + {file = "black-24.3.0.tar.gz", hash = "sha256:a0c9c4a0771afc6919578cec71ce82a3e31e054904e7197deacbc9382671c41f"}, ] [package.dependencies] @@ -480,10 +477,11 @@ packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] +d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -5890,4 +5888,4 @@ requests = ">=2.26" [metadata] lock-version = "2.0" python-versions = "~3.10" -content-hash = "51478a21cd71f289aaaaa2b3ea1566a7abaad093a8c0f924c84d3d2136940225" +content-hash = "1c717b2307a2927ae4ebb4502a99a280827fa2c342849ea794c7970e37973a97" diff --git a/pyproject.toml b/pyproject.toml index 54ed8ddbe..ac963aa8e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -41,7 +41,7 @@ wrds = "^3" yfinance = "^0.2" [tool.poetry.group.dev.dependencies] -black = "^23" +black = "^24" isort = "^5" jupyter = "^1" mypy = "^1" From 8b57ea306ac5f5a448e34550ab67ac15b5a392ae Mon Sep 17 00:00:00 2001 From: Tri Cao <72780544+tricao7@users.noreply.github.com> Date: Fri, 22 Mar 2024 20:09:58 -0700 Subject: [PATCH 05/11] Update models.py (#1189) * Update models.py Added Support for Ensembling with TD3 and A2C. Streamlined the Training of the Windows and consolidated the model's parameters and variables. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- finrl/agents/stablebaselines3/models.py | 321 +++++++++--------------- 1 file changed, 119 insertions(+), 202 deletions(-) diff --git a/finrl/agents/stablebaselines3/models.py b/finrl/agents/stablebaselines3/models.py index 628c21648..c4297310a 100644 --- a/finrl/agents/stablebaselines3/models.py +++ b/finrl/agents/stablebaselines3/models.py @@ -349,19 +349,101 @@ def DRL_prediction( df_last_state.to_csv(f"results/last_state_{name}_{i}.csv", index=False) return last_state + def _train_window( + self, + model_name, + model_kwargs, + sharpe_list, + validation_start_date, + validation_end_date, + timesteps_dict, + i, + validation, + turbulence_threshold, + ): + """ + Train the model for a single window. + """ + if model_kwargs is None: + return None, sharpe_list, -1 + + print(f"======{model_name} Training========") + model = self.get_model( + model_name, self.train_env, policy="MlpPolicy", model_kwargs=model_kwargs + ) + model = self.train_model( + model, + model_name, + tb_log_name=f"{model_name}_{i}", + iter_num=i, + total_timesteps=timesteps_dict[model_name], + ) # 100_000 + print( + f"======{model_name} Validation from: ", + validation_start_date, + "to ", + validation_end_date, + ) + val_env = DummyVecEnv( + [ + lambda: StockTradingEnv( + df=validation, + stock_dim=self.stock_dim, + hmax=self.hmax, + initial_amount=self.initial_amount, + num_stock_shares=[0] * self.stock_dim, + buy_cost_pct=[self.buy_cost_pct] * self.stock_dim, + sell_cost_pct=[self.sell_cost_pct] * self.stock_dim, + reward_scaling=self.reward_scaling, + state_space=self.state_space, + action_space=self.action_space, + tech_indicator_list=self.tech_indicator_list, + turbulence_threshold=turbulence_threshold, + iteration=i, + model_name=model_name, + mode="validation", + print_verbosity=self.print_verbosity, + ) + ] + ) + val_obs = val_env.reset() + self.DRL_validation( + model=model, + test_data=validation, + test_env=val_env, + test_obs=val_obs, + ) + sharpe = self.get_validation_sharpe(i, model_name=model_name) + print(f"{model_name} Sharpe Ratio: ", sharpe) + sharpe_list.append(sharpe) + return model, sharpe_list, sharpe + def run_ensemble_strategy( - self, A2C_model_kwargs, PPO_model_kwargs, DDPG_model_kwargs, timesteps_dict + self, + A2C_model_kwargs, + PPO_model_kwargs, + DDPG_model_kwargs, + SAC_model_kwargs, + TD3_model_kwargs, + timesteps_dict, ): - """Ensemble Strategy that combines PPO, A2C and DDPG""" + # Model Parameters + kwargs = { + "a2c": A2C_model_kwargs, + "ppo": PPO_model_kwargs, + "ddpg": DDPG_model_kwargs, + "sac": SAC_model_kwargs, + "td3": TD3_model_kwargs, + } + # Model Sharpe Ratios + model_dct = {k: {"sharpe_list": [], "sharpe": -1} for k in MODELS.keys()} + + """Ensemble Strategy that combines A2C, PPO, DDPG, SAC, and TD3""" print("============Start Ensemble Strategy============") # for ensemble model, it's necessary to feed the last state # of the previous model to the current model as the initial state last_state_ensemble = [] - ppo_sharpe_list = [] - ddpg_sharpe_list = [] - a2c_sharpe_list = [] - model_use = [] validation_start_date_list = [] validation_end_date_list = [] @@ -489,159 +571,24 @@ def run_ensemble_strategy( ) # print("training: ",len(data_split(df, start=20090000, end=test.datadate.unique()[i-rebalance_window]) )) # print("==============Model Training===========") - print("======A2C Training========") - model_a2c = self.get_model( - "a2c", self.train_env, policy="MlpPolicy", model_kwargs=A2C_model_kwargs - ) - model_a2c = self.train_model( - model_a2c, - "a2c", - tb_log_name=f"a2c_{i}", - iter_num=i, - total_timesteps=timesteps_dict["a2c"], - ) # 100_000 - - print( - "======A2C Validation from: ", - validation_start_date, - "to ", - validation_end_date, - ) - val_env_a2c = DummyVecEnv( - [ - lambda: StockTradingEnv( - df=validation, - stock_dim=self.stock_dim, - hmax=self.hmax, - initial_amount=self.initial_amount, - num_stock_shares=[0] * self.stock_dim, - buy_cost_pct=[self.buy_cost_pct] * self.stock_dim, - sell_cost_pct=[self.sell_cost_pct] * self.stock_dim, - reward_scaling=self.reward_scaling, - state_space=self.state_space, - action_space=self.action_space, - tech_indicator_list=self.tech_indicator_list, - turbulence_threshold=turbulence_threshold, - iteration=i, - model_name="A2C", - mode="validation", - print_verbosity=self.print_verbosity, - ) - ] - ) - val_obs_a2c = val_env_a2c.reset() - self.DRL_validation( - model=model_a2c, - test_data=validation, - test_env=val_env_a2c, - test_obs=val_obs_a2c, - ) - sharpe_a2c = self.get_validation_sharpe(i, model_name="A2C") - print("A2C Sharpe Ratio: ", sharpe_a2c) - - print("======PPO Training========") - model_ppo = self.get_model( - "ppo", self.train_env, policy="MlpPolicy", model_kwargs=PPO_model_kwargs - ) - model_ppo = self.train_model( - model_ppo, - "ppo", - tb_log_name=f"ppo_{i}", - iter_num=i, - total_timesteps=timesteps_dict["ppo"], - ) # 100_000 - print( - "======PPO Validation from: ", - validation_start_date, - "to ", - validation_end_date, - ) - val_env_ppo = DummyVecEnv( - [ - lambda: StockTradingEnv( - df=validation, - stock_dim=self.stock_dim, - hmax=self.hmax, - initial_amount=self.initial_amount, - num_stock_shares=[0] * self.stock_dim, - buy_cost_pct=[self.buy_cost_pct] * self.stock_dim, - sell_cost_pct=[self.sell_cost_pct] * self.stock_dim, - reward_scaling=self.reward_scaling, - state_space=self.state_space, - action_space=self.action_space, - tech_indicator_list=self.tech_indicator_list, - turbulence_threshold=turbulence_threshold, - iteration=i, - model_name="PPO", - mode="validation", - print_verbosity=self.print_verbosity, - ) - ] - ) - val_obs_ppo = val_env_ppo.reset() - self.DRL_validation( - model=model_ppo, - test_data=validation, - test_env=val_env_ppo, - test_obs=val_obs_ppo, - ) - sharpe_ppo = self.get_validation_sharpe(i, model_name="PPO") - print("PPO Sharpe Ratio: ", sharpe_ppo) - - print("======DDPG Training========") - model_ddpg = self.get_model( - "ddpg", - self.train_env, - policy="MlpPolicy", - model_kwargs=DDPG_model_kwargs, - ) - model_ddpg = self.train_model( - model_ddpg, - "ddpg", - tb_log_name=f"ddpg_{i}", - iter_num=i, - total_timesteps=timesteps_dict["ddpg"], - ) # 50_000 - print( - "======DDPG Validation from: ", - validation_start_date, - "to ", - validation_end_date, - ) - val_env_ddpg = DummyVecEnv( - [ - lambda: StockTradingEnv( - df=validation, - stock_dim=self.stock_dim, - hmax=self.hmax, - initial_amount=self.initial_amount, - num_stock_shares=[0] * self.stock_dim, - buy_cost_pct=[self.buy_cost_pct] * self.stock_dim, - sell_cost_pct=[self.sell_cost_pct] * self.stock_dim, - reward_scaling=self.reward_scaling, - state_space=self.state_space, - action_space=self.action_space, - tech_indicator_list=self.tech_indicator_list, - turbulence_threshold=turbulence_threshold, - iteration=i, - model_name="DDPG", - mode="validation", - print_verbosity=self.print_verbosity, - ) - ] - ) - val_obs_ddpg = val_env_ddpg.reset() - self.DRL_validation( - model=model_ddpg, - test_data=validation, - test_env=val_env_ddpg, - test_obs=val_obs_ddpg, - ) - sharpe_ddpg = self.get_validation_sharpe(i, model_name="DDPG") - - ppo_sharpe_list.append(sharpe_ppo) - a2c_sharpe_list.append(sharpe_a2c) - ddpg_sharpe_list.append(sharpe_ddpg) + # Train Each Model + for model_name in MODELS.keys(): + # Train The Model + model, sharpe_list, sharpe = self._train_window( + model_name, + kwargs[model_name], + model_dct[model_name]["sharpe_list"], + validation_start_date, + validation_end_date, + timesteps_dict, + i, + validation, + turbulence_threshold, + ) + # Save the model's sharpe ratios, and the model itself + model_dct[model_name]["sharpe_list"] = sharpe_list + model_dct[model_name]["model"] = model + model_dct[model_name]["sharpe"] = sharpe print( "======Best Model Retraining from: ", @@ -665,46 +612,12 @@ def run_ensemble_strategy( # print_verbosity=self.print_verbosity # )]) # Model Selection based on sharpe ratio - if (sharpe_ppo >= sharpe_a2c) & (sharpe_ppo >= sharpe_ddpg): - model_use.append("PPO") - model_ensemble = model_ppo - - # model_ensemble = self.get_model("ppo", - # self.train_full_env, - # policy="MlpPolicy", - # model_kwargs=PPO_model_kwargs) - # model_ensemble = self.train_model(model_ensemble, - # "ensemble", - # tb_log_name="ensemble_{}".format(i), - # iter_num = i, - # total_timesteps=timesteps_dict['ppo']) #100_000 - elif (sharpe_a2c > sharpe_ppo) & (sharpe_a2c > sharpe_ddpg): - model_use.append("A2C") - model_ensemble = model_a2c - - # model_ensemble = self.get_model("a2c", - # self.train_full_env, - # policy="MlpPolicy", - # model_kwargs=A2C_model_kwargs) - # model_ensemble = self.train_model(model_ensemble, - # "ensemble", - # tb_log_name="ensemble_{}".format(i), - # iter_num = i, - # total_timesteps=timesteps_dict['a2c']) #100_000 - else: - model_use.append("DDPG") - model_ensemble = model_ddpg - - # model_ensemble = self.get_model("ddpg", - # self.train_full_env, - # policy="MlpPolicy", - # model_kwargs=DDPG_model_kwargs) - # model_ensemble = self.train_model(model_ensemble, - # "ensemble", - # tb_log_name="ensemble_{}".format(i), - # iter_num = i, - # total_timesteps=timesteps_dict['ddpg']) #50_000 - + # Same order as MODELS: {"a2c": A2C, "ddpg": DDPG, "td3": TD3, "sac": SAC, "ppo": PPO} + sharpes = [model_dct[k]["sharpe"] for k in MODELS.keys()] + # Find the model with the highest sharpe ratio + max_mod = list(MODELS.keys())[np.argmax(sharpes)] + model_use.append(max_mod.upper()) + model_ensemble = model_dct[max_mod]["model"] # Training and Validation ends # Trading starts @@ -734,9 +647,11 @@ def run_ensemble_strategy( validation_start_date_list, validation_end_date_list, model_use, - a2c_sharpe_list, - ppo_sharpe_list, - ddpg_sharpe_list, + model_dct["a2c"]["sharpe_list"], + model_dct["ppo"]["sharpe_list"], + model_dct["ddpg"]["sharpe_list"], + model_dct["sac"]["sharpe_list"], + model_dct["td3"]["sharpe_list"], ] ).T df_summary.columns = [ @@ -747,6 +662,8 @@ def run_ensemble_strategy( "A2C Sharpe", "PPO Sharpe", "DDPG Sharpe", + "SAC Sharpe", + "TD3 Sharpe", ] return df_summary From 50049b7d48ed4a71ac4dba93ad56f55d116bb0d1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 27 Mar 2024 08:28:12 +0800 Subject: [PATCH 06/11] [pre-commit.ci] pre-commit autoupdate (#1190) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v3.15.1 → v3.15.2](https://github.com/asottile/pyupgrade/compare/v3.15.1...v3.15.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3f7545eac..1f4adba88 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,7 +16,7 @@ repos: - id: reorder-python-imports args: [--py37-plus, --add-import, "from __future__ import annotations"] - repo: https://github.com/asottile/pyupgrade - rev: v3.15.1 + rev: v3.15.2 hooks: - id: pyupgrade args: [--py37-plus] From 58560b502b7dfcba23260665b40318fd898c8cbb Mon Sep 17 00:00:00 2001 From: keonho-kim <70115629+keonho-kim@users.noreply.github.com> Date: Thu, 4 Apr 2024 10:24:15 +0900 Subject: [PATCH 07/11] Crawl the most recent US stock ticker from Wikipedia (#1195) * ADD TICKER CRAWLER * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- finrl/config_tickers.py | 751 ++++++---------------------------------- 1 file changed, 110 insertions(+), 641 deletions(-) diff --git a/finrl/config_tickers.py b/finrl/config_tickers.py index 6d55e1583..355e61614 100644 --- a/finrl/config_tickers.py +++ b/finrl/config_tickers.py @@ -1,650 +1,119 @@ from __future__ import annotations +import requests +from bs4 import BeautifulSoup + SINGLE_TICKER = ["AAPL"] -# Dow 30 constituents in 2021/10 -# check https://wrds-www.wharton.upenn.edu/ for U.S. index constituents -DOW_30_TICKER = [ - "AXP", - "AMGN", - "AAPL", - "BA", - "CAT", - "CSCO", - "CVX", - "GS", - "HD", - "HON", - "IBM", - "INTC", - "JNJ", - "KO", - "JPM", - "MCD", - "MMM", - "MRK", - "MSFT", - "NKE", - "PG", - "TRV", - "UNH", - "CRM", - "VZ", - "V", - "WBA", - "WMT", - "DIS", - "DOW", -] -# Nasdaq 100 constituents at 2019/01 -NAS_100_TICKER = [ - "AMGN", - "AAPL", - "AMAT", - "INTC", - "PCAR", - "PAYX", - "MSFT", - "ADBE", - "CSCO", - "XLNX", - "QCOM", - "COST", - "SBUX", - "FISV", - "CTXS", - "INTU", - "AMZN", - "EBAY", - "BIIB", - "CHKP", - "GILD", - "NLOK", - "CMCSA", - "FAST", - "ADSK", - "CTSH", - "NVDA", - "GOOGL", - "ISRG", - "VRTX", - "HSIC", - "BIDU", - "ATVI", - "ADP", - "ROST", - "ORLY", - "CERN", - "BKNG", - "MYL", - "MU", - "DLTR", - "ALXN", - "SIRI", - "MNST", - "AVGO", - "TXN", - "MDLZ", - "FB", - "ADI", - "WDC", - "REGN", - "LBTYK", - "VRSK", - "NFLX", - "TSLA", - "CHTR", - "MAR", - "ILMN", - "LRCX", - "EA", - "AAL", - "WBA", - "KHC", - "BMRN", - "JD", - "SWKS", - "INCY", - "PYPL", - "CDW", - "FOXA", - "MXIM", - "TMUS", - "EXPE", - "TCOM", - "ULTA", - "CSX", - "NTES", - "MCHP", - "CTAS", - "KLAC", - "HAS", - "JBHT", - "IDXX", - "WYNN", - "MELI", - "ALGN", - "CDNS", - "WDAY", - "SNPS", - "ASML", - "TTWO", - "PEP", - "NXPI", - "XEL", - "AMD", - "NTAP", - "VRSN", - "LULU", - "WLTW", - "UAL", -] +# Get the most recent Dow 30 constituents from Wikipedia +def DOW_30_TICKERS(): + """ + Fetches and returns a list of ticker symbols for the Dow 30 companies. + + This function scrapes the Wikipedia page for the Dow Jones Industrial Average + to find the table of Dow 30 companies and extracts the ticker symbol from it. + + Returns: + list: A list of strings where each string is a ticker symbol for one of the + Dow 30 companies. + + Raises: + requests.exceptions.RequestException: If the request to Wikipedia fails. + AttributeError: If the parsing logic fails to find the expected table or data within the page. + + Note: + This function requires the `requests` and `BeautifulSoup` (from `bs4`) modules to be imported. + It assumes that the Wikipedia page structure and the table id `constituents` do not change. + """ + url = "https://en.wikipedia.org/wiki/Dow_Jones_Industrial_Average" + response = requests.get(url) + soup = BeautifulSoup(response.text, "html.parser") + + table = soup.find("table", {"id": "constituents"}) + + tickers = [] + for row in table.findAll("tr")[1:]: + ticker = row.findAll("td")[1].text.strip() + tickers.append(ticker) + + return tickers + + +# Get the most recent Nasdaq 100 constituents from Wikipedia +def NAS_100_TICKERS(): + """ + Fetches and returns a list of ticker symbols for the NASDAQ-100 companies. + + This function scrapes the Wikipedia page for the NASDAQ-100 index to locate + the table of NASDAQ-100 companies and extract the ticker symbols from it. + + The function assumes that the table's ID is 'constituents', but note that the + precise structure of the webpage and the position of ticker symbols within the table + can vary over time. This implementation specifically retrieves the ticker from the second + column (index 1) of each table row, which is where ticker symbols are typically found. + + Returns: + list: A list of strings, each string being a ticker symbol for one of the NASDAQ-100 companies. + + Raises: + requests.exceptions.RequestException: If the request to Wikipedia fails. + AttributeError: If the parsing logic fails to find the expected table or data on the page. + + Note: + This function requires the `requests` and `BeautifulSoup` (from `bs4`) modules to be imported. + It is dependent on the structure of the Wikipedia page at the time of writing. Changes to the + page structure could necessitate updates to the parsing logic. + """ + url = "https://en.wikipedia.org/wiki/NASDAQ-100" + response = requests.get(url) + soup = BeautifulSoup(response.text, "html.parser") + + table = soup.find("table", {"id": "constituents"}) + + tickers = [] + for row in table.findAll("tr")[1:]: + ticker = row.findAll("td")[1].text.strip() + tickers.append(ticker) + + return tickers + + +def SP_500_TICKERS(): + """ + Retrieves and returns a list of ticker symbols for the S&P 500 companies. + + This function scrapes the Wikipedia page for the list of S&P 500 companies, specifically targeting + a table marked with the "wikitable sortable" class. It iterates through the table rows, extracting + the ticker symbols located in the first column of each row, assuming this column structure remains constant. + + Returns: + list: A list containing the ticker symbols as strings for each company currently listed + in the S&P 500 index. + + Raises: + requests.exceptions.RequestException: If the request to Wikipedia fails, indicating a problem with + the network connection or the server. + AttributeError: If the function cannot find the table or data expected based on the specified HTML + structure, which may occur if Wikipedia changes the layout or class names of the table. + + Note: + This function relies on the `requests` library for fetching the webpage and `BeautifulSoup` from `bs4` + for parsing the HTML. It assumes that the structure of the Wikipedia page and the class name of the + target table (`"wikitable sortable"`) do not change, which may not hold true indefinitely. + """ + url = "https://en.wikipedia.org/wiki/List_of_S%26P_500_companies" + resp = requests.get(url) + soup = BeautifulSoup(resp.text, "lxml") + table = soup.find("table", {"class": "wikitable sortable"}) + + tickers = [] + rows = table.findAll("tr")[1:] + for row in rows: + ticker = row.findAll("td")[0].text.strip() + tickers.append(ticker) + return tickers -# SP 500 constituents at 2019 -SP_500_TICKER = [ - "A", - "AAL", - "AAP", - "AAPL", - "ABBV", - "ABC", - "ABMD", - "ABT", - "ACN", - "ADBE", - "ADI", - "ADM", - "ADP", - "ADS", - "ADSK", - "AEE", - "AEP", - "AES", - "AFL", - "AGN", - "AIG", - "AIV", - "AIZ", - "AJG", - "AKAM", - "ALB", - "ALGN", - "ALK", - "ALL", - "ALLE", - "ALXN", - "AMAT", - "AMCR", - "AMD", - "AME", - "AMG", - "AMGN", - "AMP", - "AMT", - "AMZN", - "ANET", - "ANSS", - "ANTM", - "AON", - "AOS", - "APA", - "APD", - "APH", - "APTV", - "ARE", - "ARNC", - "ATO", - "ATVI", - "AVB", - "AVGO", - "AVY", - "AWK", - "AXP", - "AZO", - "BA", - "BAC", - "BAX", - "BBT", - "BBY", - "BDX", - "BEN", - "BF.B", - "BHGE", - "BIIB", - "BK", - "BKNG", - "BLK", - "BLL", - "BMY", - "BR", - "BRK.B", - "BSX", - "BWA", - "BXP", - "C", - "CAG", - "CAH", - "CAT", - "CB", - "CBOE", - "CBRE", - "CBS", - "CCI", - "CCL", - "CDNS", - "CE", - "CELG", - "CERN", - "CF", - "CFG", - "CHD", - "CHRW", - "CHTR", - "CI", - "CINF", - "CL", - "CLX", - "CMA", - "CMCSA", - "CME", - "CMG", - "CMI", - "CMS", - "CNC", - "CNP", - "COF", - "COG", - "COO", - "COP", - "COST", - "COTY", - "CPB", - "CPRI", - "CPRT", - "CRM", - "CSCO", - "CSX", - "CTAS", - "CTL", - "CTSH", - "CTVA", - "CTXS", - "CVS", - "CVX", - "CXO", - "D", - "DAL", - "DD", - "DE", - "DFS", - "DG", - "DGX", - "DHI", - "DHR", - "DIS", - "DISCK", - "DISH", - "DLR", - "DLTR", - "DOV", - "DOW", - "DRE", - "DRI", - "DTE", - "DUK", - "DVA", - "DVN", - "DXC", - "EA", - "EBAY", - "ECL", - "ED", - "EFX", - "EIX", - "EL", - "EMN", - "EMR", - "EOG", - "EQIX", - "EQR", - "ES", - "ESS", - "ETFC", - "ETN", - "ETR", - "EVRG", - "EW", - "EXC", - "EXPD", - "EXPE", - "EXR", - "F", - "FANG", - "FAST", - "FB", - "FBHS", - "FCX", - "FDX", - "FE", - "FFIV", - "FIS", - "FISV", - "FITB", - "FLIR", - "FLS", - "FLT", - "FMC", - "FOXA", - "FRC", - "FRT", - "FTI", - "FTNT", - "FTV", - "GD", - "GE", - "GILD", - "GIS", - "GL", - "GLW", - "GM", - "GOOG", - "GPC", - "GPN", - "GPS", - "GRMN", - "GS", - "GWW", - "HAL", - "HAS", - "HBAN", - "HBI", - "HCA", - "HCP", - "HD", - "HES", - "HFC", - "HIG", - "HII", - "HLT", - "HOG", - "HOLX", - "HON", - "HP", - "HPE", - "HPQ", - "HRB", - "HRL", - "HSIC", - "HST", - "HSY", - "HUM", - "IBM", - "ICE", - "IDXX", - "IEX", - "IFF", - "ILMN", - "INCY", - "INFO", - "INTC", - "INTU", - "IP", - "IPG", - "IPGP", - "IQV", - "IR", - "IRM", - "ISRG", - "IT", - "ITW", - "IVZ", - "JBHT", - "JCI", - "JEC", - "JEF", - "JKHY", - "JNJ", - "JNPR", - "JPM", - "JWN", - "K", - "KEY", - "KEYS", - "KHC", - "KIM", - "KLAC", - "KMB", - "KMI", - "KMX", - "KO", - "KR", - "KSS", - "KSU", - "L", - "LB", - "LDOS", - "LEG", - "LEN", - "LH", - "LHX", - "LIN", - "LKQ", - "LLY", - "LMT", - "LNC", - "LNT", - "LOW", - "LRCX", - "LUV", - "LW", - "LYB", - "M", - "MA", - "MAA", - "MAC", - "MAR", - "MAS", - "MCD", - "MCHP", - "MCK", - "MCO", - "MDLZ", - "MDT", - "MET", - "MGM", - "MHK", - "MKC", - "MKTX", - "MLM", - "MMC", - "MMM", - "MNST", - "MO", - "MOS", - "MPC", - "MRK", - "MRO", - "MS", - "MSCI", - "MSFT", - "MSI", - "MTB", - "MTD", - "MU", - "MXIM", - "MYL", - "NBL", - "NCLH", - "NDAQ", - "NEE", - "NEM", - "NFLX", - "NI", - "NKE", - "NKTR", - "NLSN", - "NOC", - "NOV", - "NRG", - "NSC", - "NTAP", - "NTRS", - "NUE", - "NVDA", - "NWL", - "NWS", - "O", - "OI", - "OKE", - "OMC", - "ORCL", - "ORLY", - "OXY", - "PAYX", - "PBCT", - "PCAR", - "PEG", - "PEP", - "PFE", - "PFG", - "PG", - "PGR", - "PH", - "PHM", - "PKG", - "PKI", - "PLD", - "PM", - "PNC", - "PNR", - "PNW", - "PPG", - "PPL", - "PRGO", - "PRU", - "PSA", - "PSX", - "PVH", - "PWR", - "PXD", - "PYPL", - "QCOM", - "QRVO", - "RCL", - "RE", - "REG", - "REGN", - "RF", - "RHI", - "RJF", - "RL", - "RMD", - "ROK", - "ROL", - "ROP", - "ROST", - "RSG", - "RTN", - "SBAC", - "SBUX", - "SCHW", - "SEE", - "SHW", - "SIVB", - "SJM", - "SLB", - "SLG", - "SNA", - "SNPS", - "SO", - "SPG", - "SPGI", - "SRE", - "STI", - "STT", - "STX", - "STZ", - "SWK", - "SWKS", - "SYF", - "SYK", - "SYMC", - "SYY", - "T", - "TAP", - "TDG", - "TEL", - "TFX", - "TGT", - "TIF", - "TJX", - "TMO", - "TMUS", - "TPR", - "TRIP", - "TROW", - "TRV", - "TSCO", - "TSN", - "TSS", - "TTWO", - "TWTR", - "TXN", - "TXT", - "UA", - "UAL", - "UDR", - "UHS", - "ULTA", - "UNH", - "UNM", - "UNP", - "UPS", - "URI", - "USB", - "UTX", - "V", - "VAR", - "VFC", - "VIAB", - "VLO", - "VMC", - "VNO", - "VRSK", - "VRSN", - "VRTX", - "VTR", - "VZ", - "WAB", - "WAT", - "WBA", - "WCG", - "WDC", - "WEC", - "WELL", - "WFC", - "WHR", - "WLTW", - "WM", - "WMB", - "WMT", - "WRK", - "WU", - "WY", - "WYNN", - "XEC", - "XEL", - "XLNX", - "XOM", - "XRAY", - "XRX", - "XYL", - "YUM", - "ZBH", - "ZION", - "ZTS", -] # Hang Seng Index constituents at 2019/01 HSI_50_TICKER = [ From 8fca340a5b904c11520036aafaaf7b0303a28370 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Apr 2024 09:24:39 +0800 Subject: [PATCH 08/11] Bump pillow from 10.2.0 to 10.3.0 (#1197) Bumps [pillow](https://github.com/python-pillow/Pillow) from 10.2.0 to 10.3.0. - [Release notes](https://github.com/python-pillow/Pillow/releases) - [Changelog](https://github.com/python-pillow/Pillow/blob/main/CHANGES.rst) - [Commits](https://github.com/python-pillow/Pillow/compare/10.2.0...10.3.0) --- updated-dependencies: - dependency-name: pillow dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 141 ++++++++++++++++++++++++++-------------------------- 1 file changed, 71 insertions(+), 70 deletions(-) diff --git a/poetry.lock b/poetry.lock index bb5c95b32..3eda1bc2c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "absl-py" @@ -3560,79 +3560,80 @@ files = [ [[package]] name = "pillow" -version = "10.2.0" +version = "10.3.0" description = "Python Imaging Library (Fork)" optional = false python-versions = ">=3.8" files = [ - {file = "pillow-10.2.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:7823bdd049099efa16e4246bdf15e5a13dbb18a51b68fa06d6c1d4d8b99a796e"}, - {file = "pillow-10.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:83b2021f2ade7d1ed556bc50a399127d7fb245e725aa0113ebd05cfe88aaf588"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fad5ff2f13d69b7e74ce5b4ecd12cc0ec530fcee76356cac6742785ff71c452"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da2b52b37dad6d9ec64e653637a096905b258d2fc2b984c41ae7d08b938a67e4"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:47c0995fc4e7f79b5cfcab1fc437ff2890b770440f7696a3ba065ee0fd496563"}, - {file = "pillow-10.2.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:322bdf3c9b556e9ffb18f93462e5f749d3444ce081290352c6070d014c93feb2"}, - {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:51f1a1bffc50e2e9492e87d8e09a17c5eea8409cda8d3f277eb6edc82813c17c"}, - {file = "pillow-10.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:69ffdd6120a4737710a9eee73e1d2e37db89b620f702754b8f6e62594471dee0"}, - {file = "pillow-10.2.0-cp310-cp310-win32.whl", hash = "sha256:c6dafac9e0f2b3c78df97e79af707cdc5ef8e88208d686a4847bab8266870023"}, - {file = "pillow-10.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:aebb6044806f2e16ecc07b2a2637ee1ef67a11840a66752751714a0d924adf72"}, - {file = "pillow-10.2.0-cp310-cp310-win_arm64.whl", hash = "sha256:7049e301399273a0136ff39b84c3678e314f2158f50f517bc50285fb5ec847ad"}, - {file = "pillow-10.2.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:35bb52c37f256f662abdfa49d2dfa6ce5d93281d323a9af377a120e89a9eafb5"}, - {file = "pillow-10.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c23f307202661071d94b5e384e1e1dc7dfb972a28a2310e4ee16103e66ddb67"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773efe0603db30c281521a7c0214cad7836c03b8ccff897beae9b47c0b657d61"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11fa2e5984b949b0dd6d7a94d967743d87c577ff0b83392f17cb3990d0d2fd6e"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:716d30ed977be8b37d3ef185fecb9e5a1d62d110dfbdcd1e2a122ab46fddb03f"}, - {file = "pillow-10.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a086c2af425c5f62a65e12fbf385f7c9fcb8f107d0849dba5839461a129cf311"}, - {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:c8de2789052ed501dd829e9cae8d3dcce7acb4777ea4a479c14521c942d395b1"}, - {file = "pillow-10.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:609448742444d9290fd687940ac0b57fb35e6fd92bdb65386e08e99af60bf757"}, - {file = "pillow-10.2.0-cp311-cp311-win32.whl", hash = "sha256:823ef7a27cf86df6597fa0671066c1b596f69eba53efa3d1e1cb8b30f3533068"}, - {file = "pillow-10.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:1da3b2703afd040cf65ec97efea81cfba59cdbed9c11d8efc5ab09df9509fc56"}, - {file = "pillow-10.2.0-cp311-cp311-win_arm64.whl", hash = "sha256:edca80cbfb2b68d7b56930b84a0e45ae1694aeba0541f798e908a49d66b837f1"}, - {file = "pillow-10.2.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:1b5e1b74d1bd1b78bc3477528919414874748dd363e6272efd5abf7654e68bef"}, - {file = "pillow-10.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0eae2073305f451d8ecacb5474997c08569fb4eb4ac231ffa4ad7d342fdc25ac"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7c2286c23cd350b80d2fc9d424fc797575fb16f854b831d16fd47ceec078f2c"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e23412b5c41e58cec602f1135c57dfcf15482013ce6e5f093a86db69646a5aa"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:52a50aa3fb3acb9cf7213573ef55d31d6eca37f5709c69e6858fe3bc04a5c2a2"}, - {file = "pillow-10.2.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:127cee571038f252a552760076407f9cff79761c3d436a12af6000cd182a9d04"}, - {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8d12251f02d69d8310b046e82572ed486685c38f02176bd08baf216746eb947f"}, - {file = "pillow-10.2.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:54f1852cd531aa981bc0965b7d609f5f6cc8ce8c41b1139f6ed6b3c54ab82bfb"}, - {file = "pillow-10.2.0-cp312-cp312-win32.whl", hash = "sha256:257d8788df5ca62c980314053197f4d46eefedf4e6175bc9412f14412ec4ea2f"}, - {file = "pillow-10.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:154e939c5f0053a383de4fd3d3da48d9427a7e985f58af8e94d0b3c9fcfcf4f9"}, - {file = "pillow-10.2.0-cp312-cp312-win_arm64.whl", hash = "sha256:f379abd2f1e3dddb2b61bc67977a6b5a0a3f7485538bcc6f39ec76163891ee48"}, - {file = "pillow-10.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:8373c6c251f7ef8bda6675dd6d2b3a0fcc31edf1201266b5cf608b62a37407f9"}, - {file = "pillow-10.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:870ea1ada0899fd0b79643990809323b389d4d1d46c192f97342eeb6ee0b8483"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4b6b1e20608493548b1f32bce8cca185bf0480983890403d3b8753e44077129"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3031709084b6e7852d00479fd1d310b07d0ba82765f973b543c8af5061cf990e"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:3ff074fc97dd4e80543a3e91f69d58889baf2002b6be64347ea8cf5533188213"}, - {file = "pillow-10.2.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:cb4c38abeef13c61d6916f264d4845fab99d7b711be96c326b84df9e3e0ff62d"}, - {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b1b3020d90c2d8e1dae29cf3ce54f8094f7938460fb5ce8bc5c01450b01fbaf6"}, - {file = "pillow-10.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:170aeb00224ab3dc54230c797f8404507240dd868cf52066f66a41b33169bdbe"}, - {file = "pillow-10.2.0-cp38-cp38-win32.whl", hash = "sha256:c4225f5220f46b2fde568c74fca27ae9771536c2e29d7c04f4fb62c83275ac4e"}, - {file = "pillow-10.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:0689b5a8c5288bc0504d9fcee48f61a6a586b9b98514d7d29b840143d6734f39"}, - {file = "pillow-10.2.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b792a349405fbc0163190fde0dc7b3fef3c9268292586cf5645598b48e63dc67"}, - {file = "pillow-10.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c570f24be1e468e3f0ce7ef56a89a60f0e05b30a3669a459e419c6eac2c35364"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8ecd059fdaf60c1963c58ceb8997b32e9dc1b911f5da5307aab614f1ce5c2fb"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c365fd1703040de1ec284b176d6af5abe21b427cb3a5ff68e0759e1e313a5e7e"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:70c61d4c475835a19b3a5aa42492409878bbca7438554a1f89d20d58a7c75c01"}, - {file = "pillow-10.2.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:b6f491cdf80ae540738859d9766783e3b3c8e5bd37f5dfa0b76abdecc5081f13"}, - {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9d189550615b4948f45252d7f005e53c2040cea1af5b60d6f79491a6e147eef7"}, - {file = "pillow-10.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:49d9ba1ed0ef3e061088cd1e7538a0759aab559e2e0a80a36f9fd9d8c0c21591"}, - {file = "pillow-10.2.0-cp39-cp39-win32.whl", hash = "sha256:babf5acfede515f176833ed6028754cbcd0d206f7f614ea3447d67c33be12516"}, - {file = "pillow-10.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:0304004f8067386b477d20a518b50f3fa658a28d44e4116970abfcd94fac34a8"}, - {file = "pillow-10.2.0-cp39-cp39-win_arm64.whl", hash = "sha256:0fb3e7fc88a14eacd303e90481ad983fd5b69c761e9e6ef94c983f91025da869"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:322209c642aabdd6207517e9739c704dc9f9db943015535783239022002f054a"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3eedd52442c0a5ff4f887fab0c1c0bb164d8635b32c894bc1faf4c618dd89df2"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb28c753fd5eb3dd859b4ee95de66cc62af91bcff5db5f2571d32a520baf1f04"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:33870dc4653c5017bf4c8873e5488d8f8d5f8935e2f1fb9a2208c47cdd66efd2"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3c31822339516fb3c82d03f30e22b1d038da87ef27b6a78c9549888f8ceda39a"}, - {file = "pillow-10.2.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a2b56ba36e05f973d450582fb015594aaa78834fefe8dfb8fcd79b93e64ba4c6"}, - {file = "pillow-10.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:d8e6aeb9201e655354b3ad049cb77d19813ad4ece0df1249d3c793de3774f8c7"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:2247178effb34a77c11c0e8ac355c7a741ceca0a732b27bf11e747bbc950722f"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15587643b9e5eb26c48e49a7b33659790d28f190fc514a322d55da2fb5c2950e"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753cd8f2086b2b80180d9b3010dd4ed147efc167c90d3bf593fe2af21265e5a5"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7c8f97e8e7a9009bcacbe3766a36175056c12f9a44e6e6f2d5caad06dcfbf03b"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:d1b35bcd6c5543b9cb547dee3150c93008f8dd0f1fef78fc0cd2b141c5baf58a"}, - {file = "pillow-10.2.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:fe4c15f6c9285dc54ce6553a3ce908ed37c8f3825b5a51a15c91442bb955b868"}, - {file = "pillow-10.2.0.tar.gz", hash = "sha256:e87f0b2c78157e12d7686b27d63c070fd65d994e8ddae6f328e0dcf4a0cd007e"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, + {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, + {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, + {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, + {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, + {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, + {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, + {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, + {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, + {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, + {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, + {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, + {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, + {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, + {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, + {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, ] [package.extras] From 7b2f30302e787e9276f52823c87b7c2ade4203cf Mon Sep 17 00:00:00 2001 From: Ming Zhu Date: Thu, 4 Apr 2024 14:57:25 +0800 Subject: [PATCH 09/11] Revert "Crawl the most recent US stock ticker from Wikipedia (#1195)" (#1198) This reverts commit 58560b502b7dfcba23260665b40318fd898c8cbb. --- finrl/config_tickers.py | 751 ++++++++++++++++++++++++++++++++++------ 1 file changed, 641 insertions(+), 110 deletions(-) diff --git a/finrl/config_tickers.py b/finrl/config_tickers.py index 355e61614..6d55e1583 100644 --- a/finrl/config_tickers.py +++ b/finrl/config_tickers.py @@ -1,119 +1,650 @@ from __future__ import annotations -import requests -from bs4 import BeautifulSoup - SINGLE_TICKER = ["AAPL"] +# Dow 30 constituents in 2021/10 +# check https://wrds-www.wharton.upenn.edu/ for U.S. index constituents +DOW_30_TICKER = [ + "AXP", + "AMGN", + "AAPL", + "BA", + "CAT", + "CSCO", + "CVX", + "GS", + "HD", + "HON", + "IBM", + "INTC", + "JNJ", + "KO", + "JPM", + "MCD", + "MMM", + "MRK", + "MSFT", + "NKE", + "PG", + "TRV", + "UNH", + "CRM", + "VZ", + "V", + "WBA", + "WMT", + "DIS", + "DOW", +] -# Get the most recent Dow 30 constituents from Wikipedia -def DOW_30_TICKERS(): - """ - Fetches and returns a list of ticker symbols for the Dow 30 companies. - - This function scrapes the Wikipedia page for the Dow Jones Industrial Average - to find the table of Dow 30 companies and extracts the ticker symbol from it. - - Returns: - list: A list of strings where each string is a ticker symbol for one of the - Dow 30 companies. - - Raises: - requests.exceptions.RequestException: If the request to Wikipedia fails. - AttributeError: If the parsing logic fails to find the expected table or data within the page. - - Note: - This function requires the `requests` and `BeautifulSoup` (from `bs4`) modules to be imported. - It assumes that the Wikipedia page structure and the table id `constituents` do not change. - """ - url = "https://en.wikipedia.org/wiki/Dow_Jones_Industrial_Average" - response = requests.get(url) - soup = BeautifulSoup(response.text, "html.parser") - - table = soup.find("table", {"id": "constituents"}) - - tickers = [] - for row in table.findAll("tr")[1:]: - ticker = row.findAll("td")[1].text.strip() - tickers.append(ticker) - - return tickers - - -# Get the most recent Nasdaq 100 constituents from Wikipedia -def NAS_100_TICKERS(): - """ - Fetches and returns a list of ticker symbols for the NASDAQ-100 companies. - - This function scrapes the Wikipedia page for the NASDAQ-100 index to locate - the table of NASDAQ-100 companies and extract the ticker symbols from it. - - The function assumes that the table's ID is 'constituents', but note that the - precise structure of the webpage and the position of ticker symbols within the table - can vary over time. This implementation specifically retrieves the ticker from the second - column (index 1) of each table row, which is where ticker symbols are typically found. - - Returns: - list: A list of strings, each string being a ticker symbol for one of the NASDAQ-100 companies. - - Raises: - requests.exceptions.RequestException: If the request to Wikipedia fails. - AttributeError: If the parsing logic fails to find the expected table or data on the page. - - Note: - This function requires the `requests` and `BeautifulSoup` (from `bs4`) modules to be imported. - It is dependent on the structure of the Wikipedia page at the time of writing. Changes to the - page structure could necessitate updates to the parsing logic. - """ - url = "https://en.wikipedia.org/wiki/NASDAQ-100" - response = requests.get(url) - soup = BeautifulSoup(response.text, "html.parser") - - table = soup.find("table", {"id": "constituents"}) - - tickers = [] - for row in table.findAll("tr")[1:]: - ticker = row.findAll("td")[1].text.strip() - tickers.append(ticker) - - return tickers - - -def SP_500_TICKERS(): - """ - Retrieves and returns a list of ticker symbols for the S&P 500 companies. - - This function scrapes the Wikipedia page for the list of S&P 500 companies, specifically targeting - a table marked with the "wikitable sortable" class. It iterates through the table rows, extracting - the ticker symbols located in the first column of each row, assuming this column structure remains constant. - - Returns: - list: A list containing the ticker symbols as strings for each company currently listed - in the S&P 500 index. - - Raises: - requests.exceptions.RequestException: If the request to Wikipedia fails, indicating a problem with - the network connection or the server. - AttributeError: If the function cannot find the table or data expected based on the specified HTML - structure, which may occur if Wikipedia changes the layout or class names of the table. - - Note: - This function relies on the `requests` library for fetching the webpage and `BeautifulSoup` from `bs4` - for parsing the HTML. It assumes that the structure of the Wikipedia page and the class name of the - target table (`"wikitable sortable"`) do not change, which may not hold true indefinitely. - """ - url = "https://en.wikipedia.org/wiki/List_of_S%26P_500_companies" - resp = requests.get(url) - soup = BeautifulSoup(resp.text, "lxml") - table = soup.find("table", {"class": "wikitable sortable"}) - - tickers = [] - rows = table.findAll("tr")[1:] - for row in rows: - ticker = row.findAll("td")[0].text.strip() - tickers.append(ticker) - return tickers +# Nasdaq 100 constituents at 2019/01 +NAS_100_TICKER = [ + "AMGN", + "AAPL", + "AMAT", + "INTC", + "PCAR", + "PAYX", + "MSFT", + "ADBE", + "CSCO", + "XLNX", + "QCOM", + "COST", + "SBUX", + "FISV", + "CTXS", + "INTU", + "AMZN", + "EBAY", + "BIIB", + "CHKP", + "GILD", + "NLOK", + "CMCSA", + "FAST", + "ADSK", + "CTSH", + "NVDA", + "GOOGL", + "ISRG", + "VRTX", + "HSIC", + "BIDU", + "ATVI", + "ADP", + "ROST", + "ORLY", + "CERN", + "BKNG", + "MYL", + "MU", + "DLTR", + "ALXN", + "SIRI", + "MNST", + "AVGO", + "TXN", + "MDLZ", + "FB", + "ADI", + "WDC", + "REGN", + "LBTYK", + "VRSK", + "NFLX", + "TSLA", + "CHTR", + "MAR", + "ILMN", + "LRCX", + "EA", + "AAL", + "WBA", + "KHC", + "BMRN", + "JD", + "SWKS", + "INCY", + "PYPL", + "CDW", + "FOXA", + "MXIM", + "TMUS", + "EXPE", + "TCOM", + "ULTA", + "CSX", + "NTES", + "MCHP", + "CTAS", + "KLAC", + "HAS", + "JBHT", + "IDXX", + "WYNN", + "MELI", + "ALGN", + "CDNS", + "WDAY", + "SNPS", + "ASML", + "TTWO", + "PEP", + "NXPI", + "XEL", + "AMD", + "NTAP", + "VRSN", + "LULU", + "WLTW", + "UAL", +] +# SP 500 constituents at 2019 +SP_500_TICKER = [ + "A", + "AAL", + "AAP", + "AAPL", + "ABBV", + "ABC", + "ABMD", + "ABT", + "ACN", + "ADBE", + "ADI", + "ADM", + "ADP", + "ADS", + "ADSK", + "AEE", + "AEP", + "AES", + "AFL", + "AGN", + "AIG", + "AIV", + "AIZ", + "AJG", + "AKAM", + "ALB", + "ALGN", + "ALK", + "ALL", + "ALLE", + "ALXN", + "AMAT", + "AMCR", + "AMD", + "AME", + "AMG", + "AMGN", + "AMP", + "AMT", + "AMZN", + "ANET", + "ANSS", + "ANTM", + "AON", + "AOS", + "APA", + "APD", + "APH", + "APTV", + "ARE", + "ARNC", + "ATO", + "ATVI", + "AVB", + "AVGO", + "AVY", + "AWK", + "AXP", + "AZO", + "BA", + "BAC", + "BAX", + "BBT", + "BBY", + "BDX", + "BEN", + "BF.B", + "BHGE", + "BIIB", + "BK", + "BKNG", + "BLK", + "BLL", + "BMY", + "BR", + "BRK.B", + "BSX", + "BWA", + "BXP", + "C", + "CAG", + "CAH", + "CAT", + "CB", + "CBOE", + "CBRE", + "CBS", + "CCI", + "CCL", + "CDNS", + "CE", + "CELG", + "CERN", + "CF", + "CFG", + "CHD", + "CHRW", + "CHTR", + "CI", + "CINF", + "CL", + "CLX", + "CMA", + "CMCSA", + "CME", + "CMG", + "CMI", + "CMS", + "CNC", + "CNP", + "COF", + "COG", + "COO", + "COP", + "COST", + "COTY", + "CPB", + "CPRI", + "CPRT", + "CRM", + "CSCO", + "CSX", + "CTAS", + "CTL", + "CTSH", + "CTVA", + "CTXS", + "CVS", + "CVX", + "CXO", + "D", + "DAL", + "DD", + "DE", + "DFS", + "DG", + "DGX", + "DHI", + "DHR", + "DIS", + "DISCK", + "DISH", + "DLR", + "DLTR", + "DOV", + "DOW", + "DRE", + "DRI", + "DTE", + "DUK", + "DVA", + "DVN", + "DXC", + "EA", + "EBAY", + "ECL", + "ED", + "EFX", + "EIX", + "EL", + "EMN", + "EMR", + "EOG", + "EQIX", + "EQR", + "ES", + "ESS", + "ETFC", + "ETN", + "ETR", + "EVRG", + "EW", + "EXC", + "EXPD", + "EXPE", + "EXR", + "F", + "FANG", + "FAST", + "FB", + "FBHS", + "FCX", + "FDX", + "FE", + "FFIV", + "FIS", + "FISV", + "FITB", + "FLIR", + "FLS", + "FLT", + "FMC", + "FOXA", + "FRC", + "FRT", + "FTI", + "FTNT", + "FTV", + "GD", + "GE", + "GILD", + "GIS", + "GL", + "GLW", + "GM", + "GOOG", + "GPC", + "GPN", + "GPS", + "GRMN", + "GS", + "GWW", + "HAL", + "HAS", + "HBAN", + "HBI", + "HCA", + "HCP", + "HD", + "HES", + "HFC", + "HIG", + "HII", + "HLT", + "HOG", + "HOLX", + "HON", + "HP", + "HPE", + "HPQ", + "HRB", + "HRL", + "HSIC", + "HST", + "HSY", + "HUM", + "IBM", + "ICE", + "IDXX", + "IEX", + "IFF", + "ILMN", + "INCY", + "INFO", + "INTC", + "INTU", + "IP", + "IPG", + "IPGP", + "IQV", + "IR", + "IRM", + "ISRG", + "IT", + "ITW", + "IVZ", + "JBHT", + "JCI", + "JEC", + "JEF", + "JKHY", + "JNJ", + "JNPR", + "JPM", + "JWN", + "K", + "KEY", + "KEYS", + "KHC", + "KIM", + "KLAC", + "KMB", + "KMI", + "KMX", + "KO", + "KR", + "KSS", + "KSU", + "L", + "LB", + "LDOS", + "LEG", + "LEN", + "LH", + "LHX", + "LIN", + "LKQ", + "LLY", + "LMT", + "LNC", + "LNT", + "LOW", + "LRCX", + "LUV", + "LW", + "LYB", + "M", + "MA", + "MAA", + "MAC", + "MAR", + "MAS", + "MCD", + "MCHP", + "MCK", + "MCO", + "MDLZ", + "MDT", + "MET", + "MGM", + "MHK", + "MKC", + "MKTX", + "MLM", + "MMC", + "MMM", + "MNST", + "MO", + "MOS", + "MPC", + "MRK", + "MRO", + "MS", + "MSCI", + "MSFT", + "MSI", + "MTB", + "MTD", + "MU", + "MXIM", + "MYL", + "NBL", + "NCLH", + "NDAQ", + "NEE", + "NEM", + "NFLX", + "NI", + "NKE", + "NKTR", + "NLSN", + "NOC", + "NOV", + "NRG", + "NSC", + "NTAP", + "NTRS", + "NUE", + "NVDA", + "NWL", + "NWS", + "O", + "OI", + "OKE", + "OMC", + "ORCL", + "ORLY", + "OXY", + "PAYX", + "PBCT", + "PCAR", + "PEG", + "PEP", + "PFE", + "PFG", + "PG", + "PGR", + "PH", + "PHM", + "PKG", + "PKI", + "PLD", + "PM", + "PNC", + "PNR", + "PNW", + "PPG", + "PPL", + "PRGO", + "PRU", + "PSA", + "PSX", + "PVH", + "PWR", + "PXD", + "PYPL", + "QCOM", + "QRVO", + "RCL", + "RE", + "REG", + "REGN", + "RF", + "RHI", + "RJF", + "RL", + "RMD", + "ROK", + "ROL", + "ROP", + "ROST", + "RSG", + "RTN", + "SBAC", + "SBUX", + "SCHW", + "SEE", + "SHW", + "SIVB", + "SJM", + "SLB", + "SLG", + "SNA", + "SNPS", + "SO", + "SPG", + "SPGI", + "SRE", + "STI", + "STT", + "STX", + "STZ", + "SWK", + "SWKS", + "SYF", + "SYK", + "SYMC", + "SYY", + "T", + "TAP", + "TDG", + "TEL", + "TFX", + "TGT", + "TIF", + "TJX", + "TMO", + "TMUS", + "TPR", + "TRIP", + "TROW", + "TRV", + "TSCO", + "TSN", + "TSS", + "TTWO", + "TWTR", + "TXN", + "TXT", + "UA", + "UAL", + "UDR", + "UHS", + "ULTA", + "UNH", + "UNM", + "UNP", + "UPS", + "URI", + "USB", + "UTX", + "V", + "VAR", + "VFC", + "VIAB", + "VLO", + "VMC", + "VNO", + "VRSK", + "VRSN", + "VRTX", + "VTR", + "VZ", + "WAB", + "WAT", + "WBA", + "WCG", + "WDC", + "WEC", + "WELL", + "WFC", + "WHR", + "WLTW", + "WM", + "WMB", + "WMT", + "WRK", + "WU", + "WY", + "WYNN", + "XEC", + "XEL", + "XLNX", + "XOM", + "XRAY", + "XRX", + "XYL", + "YUM", + "ZBH", + "ZION", + "ZTS", +] # Hang Seng Index constituents at 2019/01 HSI_50_TICKER = [ From 3368fe4b09047adb66bff4d80a4533920746d2a2 Mon Sep 17 00:00:00 2001 From: RAVI KUMAR GAUTAM <69303731+RGIIST@users.noreply.github.com> Date: Tue, 9 Apr 2024 12:22:19 +0530 Subject: [PATCH 10/11] issue-2230941451 by manu1dcb on 8 April 2024 resolved (#1203) * issue-2230941451(**TypeError:** DRLEnsembleAgent.run_ensemble_strategy() missing 1 required positional argument: 'timesteps_dict') in file examples/FinRL_Ensemble_StockTrading_ICAIF_2020.ipynb created by manu1dcb resolved * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: Ubuntu Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- ...nRL_Ensemble_StockTrading_ICAIF_2020.ipynb | 7419 +++++++---------- 1 file changed, 3099 insertions(+), 4320 deletions(-) diff --git a/examples/FinRL_Ensemble_StockTrading_ICAIF_2020.ipynb b/examples/FinRL_Ensemble_StockTrading_ICAIF_2020.ipynb index 76c22fb27..e11a18620 100644 --- a/examples/FinRL_Ensemble_StockTrading_ICAIF_2020.ipynb +++ b/examples/FinRL_Ensemble_StockTrading_ICAIF_2020.ipynb @@ -1,4389 +1,3168 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "Lb9q2_QZgdNk" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "gXaoZs2lh1hi" - }, - "source": [ - "# Deep Reinforcement Learning for Stock Trading from Scratch: Multiple Stock Trading Using Ensemble Strategy\n", - "\n", - "Tutorials to use OpenAI DRL to trade multiple stocks using ensemble strategy in one Jupyter Notebook | Presented at ICAIF 2020\n", - "\n", - "* This notebook is the reimplementation of our paper: Deep Reinforcement Learning for Automated Stock Trading: An Ensemble Strategy, using FinRL.\n", - "* Check out medium blog for detailed explanations: https://medium.com/@ai4finance/deep-reinforcement-learning-for-automated-stock-trading-f1dad0126a02\n", - "* Please report any issues to our Github: https://github.com/AI4Finance-LLC/FinRL-Library/issues\n", - "* **Pytorch Version** \n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "lGunVt8oLCVS" - }, - "source": [ - "# Content" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HOzAKQ-SLGX6" - }, - "source": [ - "* [1. Problem Definition](#0)\n", - "* [2. Getting Started - Load Python packages](#1)\n", - " * [2.1. Install Packages](#1.1) \n", - " * [2.2. Check Additional Packages](#1.2)\n", - " * [2.3. Import Packages](#1.3)\n", - " * [2.4. Create Folders](#1.4)\n", - "* [3. Download Data](#2)\n", - "* [4. Preprocess Data](#3) \n", - " * [4.1. Technical Indicators](#3.1)\n", - " * [4.2. Perform Feature Engineering](#3.2)\n", - "* [5.Build Environment](#4) \n", - " * [5.1. Training & Trade Data Split](#4.1)\n", - " * [5.2. User-defined Environment](#4.2) \n", - " * [5.3. Initialize Environment](#4.3) \n", - "* [6.Implement DRL Algorithms](#5) \n", - "* [7.Backtesting Performance](#6) \n", - " * [7.1. BackTestStats](#6.1)\n", - " * [7.2. BackTestPlot](#6.2) \n", - " * [7.3. Baseline Stats](#6.3) \n", - " * [7.3. Compare to Stock Market Index](#6.4) " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "sApkDlD9LIZv" - }, - "source": [ - "\n", - "# Part 1. Problem Definition" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HjLD2TZSLKZ-" - }, - "source": [ - "This problem is to design an automated trading solution for single stock trading. We model the stock trading process as a Markov Decision Process (MDP). We then formulate our trading goal as a maximization problem.\n", - "\n", - "The algorithm is trained using Deep Reinforcement Learning (DRL) algorithms and the components of the reinforcement learning environment are:\n", - "\n", - "\n", - "* Action: The action space describes the allowed actions that the agent interacts with the\n", - "environment. Normally, a ∈ A includes three actions: a ∈ {−1, 0, 1}, where −1, 0, 1 represent\n", - "selling, holding, and buying one stock. Also, an action can be carried upon multiple shares. We use\n", - "an action space {−k, ..., −1, 0, 1, ..., k}, where k denotes the number of shares. For example, \"Buy\n", - "10 shares of AAPL\" or \"Sell 10 shares of AAPL\" are 10 or −10, respectively\n", - "\n", - "* Reward function: r(s, a, s′) is the incentive mechanism for an agent to learn a better action. The change of the portfolio value when action a is taken at state s and arriving at new state s', i.e., r(s, a, s′) = v′ − v, where v′ and v represent the portfolio\n", - "values at state s′ and s, respectively\n", - "\n", - "* State: The state space describes the observations that the agent receives from the environment. Just as a human trader needs to analyze various information before executing a trade, so\n", - "our trading agent observes many different features to better learn in an interactive environment.\n", - "\n", - "* Environment: Dow 30 consituents\n", - "\n", - "\n", - "The data of the single stock that we will be using for this case study is obtained from Yahoo Finance API. The data contains Open-High-Low-Close price and volume.\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Ffsre789LY08" - }, - "source": [ - "\n", - "# Part 2. Getting Started- Load Python Packages" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Uy5_PTmOh1hj" - }, - "source": [ - "\n", - "## 2.1. Install all the packages through FinRL library\n" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "Lb9q2_QZgdNk" + }, + "source": [ + "\n", + " \"Open\n", + "" + ] }, - "id": "mPT0ipYE28wL", - "outputId": "75fcd958-c29f-44f0-85ea-4b4f6ae180ec" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Requirement already satisfied: wrds in /usr/local/lib/python3.9/dist-packages (3.1.6)\n", - "Requirement already satisfied: pandas in /usr/local/lib/python3.9/dist-packages (from wrds) (1.4.4)\n", - "Requirement already satisfied: scipy in /usr/local/lib/python3.9/dist-packages (from wrds) (1.10.1)\n", - "Requirement already satisfied: sqlalchemy<2 in /usr/local/lib/python3.9/dist-packages (from wrds) (1.4.46)\n", - "Requirement already satisfied: psycopg2-binary in /usr/local/lib/python3.9/dist-packages (from wrds) (2.9.5)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.9/dist-packages (from wrds) (1.22.4)\n", - "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.9/dist-packages (from sqlalchemy<2->wrds) (2.0.2)\n", - "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.9/dist-packages (from pandas->wrds) (2022.7.1)\n", - "Requirement already satisfied: python-dateutil>=2.8.1 in /usr/local/lib/python3.9/dist-packages (from pandas->wrds) (2.8.2)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.9/dist-packages (from python-dateutil>=2.8.1->pandas->wrds) (1.15.0)\n", - "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Requirement already satisfied: swig in /usr/local/lib/python3.9/dist-packages (4.1.1)\n", - "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", - "Collecting git+https://github.com/AI4Finance-Foundation/FinRL.git\n", - " Cloning https://github.com/AI4Finance-Foundation/FinRL.git to /tmp/pip-req-build-2ihswrjo\n", - " Running command git clone --filter=blob:none --quiet https://github.com/AI4Finance-Foundation/FinRL.git /tmp/pip-req-build-2ihswrjo\n", - " Resolved https://github.com/AI4Finance-Foundation/FinRL.git to commit 423f45f39d31df862e20b1d95a4da714e94e3a72\n", - " Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n", - " Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n", - " Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", - "Collecting elegantrl@ git+https://github.com/AI4Finance-Foundation/ElegantRL.git#egg=elegantrl\n", - " Cloning https://github.com/AI4Finance-Foundation/ElegantRL.git to /tmp/pip-install-q5365wtv/elegantrl_579ae2d134a7495d92a8bd717980c98a\n", - " Running command git clone --filter=blob:none --quiet https://github.com/AI4Finance-Foundation/ElegantRL.git /tmp/pip-install-q5365wtv/elegantrl_579ae2d134a7495d92a8bd717980c98a\n", - " Resolved https://github.com/AI4Finance-Foundation/ElegantRL.git to commit 68bf0ea4ef3fb461026ece8897deabb92aeead32\n", - " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - "Collecting pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2\n", - " Cloning https://github.com/quantopian/pyfolio.git to /tmp/pip-install-q5365wtv/pyfolio_a7685a5fd5424c79a8c4dea10a308d9a\n", - " Running command git clone --filter=blob:none --quiet https://github.com/quantopian/pyfolio.git /tmp/pip-install-q5365wtv/pyfolio_a7685a5fd5424c79a8c4dea10a308d9a\n", - " Resolved https://github.com/quantopian/pyfolio.git to commit 4b901f6d73aa02ceb6d04b7d83502e5c6f2e81aa\n", - " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (3.5.3)\n", - "Requirement already satisfied: exchange_calendars==3.6.3 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (3.6.3)\n", - "Requirement already satisfied: ray[default,tune]>=2.0.0 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (2.3.0)\n", - "Requirement already satisfied: scikit-learn>=0.21.0 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (1.2.2)\n", - "Requirement already satisfied: stable-baselines3<2.0.0,>=1.6.2 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (1.7.0)\n", - "Requirement already satisfied: gputil in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (1.4.0)\n", - "Requirement already satisfied: stockstats>=0.4.0 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (0.5.2)\n", - "Requirement already satisfied: jqdatasdk in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (1.8.11)\n", - "Requirement already satisfied: ccxt>=1.66.32 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (3.0.4)\n", - "Requirement already satisfied: yfinance in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (0.2.12)\n", - "Requirement already satisfied: tensorboardX in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (2.6)\n", - "Requirement already satisfied: alpaca_trade_api>=2.1.0 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (3.0.0)\n", - "Requirement already satisfied: importlib-metadata==4.13.0 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (4.13.0)\n", - "Requirement already satisfied: gym>=0.17 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (0.21.0)\n", - "Requirement already satisfied: pandas>=1.1.5 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (1.4.4)\n", - "Requirement already satisfied: lz4 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (4.3.2)\n", - "Requirement already satisfied: numpy>=1.17.3 in /usr/local/lib/python3.9/dist-packages (from finrl==0.3.5) (1.22.4)\n", - "Requirement already satisfied: pyluach in /usr/local/lib/python3.9/dist-packages (from exchange_calendars==3.6.3->finrl==0.3.5) (2.2.0)\n", - "Requirement already satisfied: korean-lunar-calendar in /usr/local/lib/python3.9/dist-packages (from exchange_calendars==3.6.3->finrl==0.3.5) (0.3.1)\n", - "Requirement already satisfied: toolz in /usr/local/lib/python3.9/dist-packages (from exchange_calendars==3.6.3->finrl==0.3.5) (0.12.0)\n", - "Requirement already satisfied: pytz in /usr/local/lib/python3.9/dist-packages (from exchange_calendars==3.6.3->finrl==0.3.5) (2022.7.1)\n", - "Requirement already satisfied: python-dateutil in /usr/local/lib/python3.9/dist-packages (from exchange_calendars==3.6.3->finrl==0.3.5) (2.8.2)\n", - "Requirement already satisfied: zipp>=0.5 in /usr/local/lib/python3.9/dist-packages (from importlib-metadata==4.13.0->finrl==0.3.5) (3.15.0)\n", - "Requirement already satisfied: urllib3<2,>1.24 in /usr/local/lib/python3.9/dist-packages (from alpaca_trade_api>=2.1.0->finrl==0.3.5) (1.26.14)\n", - "Requirement already satisfied: msgpack==1.0.3 in /usr/local/lib/python3.9/dist-packages (from alpaca_trade_api>=2.1.0->finrl==0.3.5) (1.0.3)\n", - "Requirement already satisfied: requests<3,>2 in /usr/local/lib/python3.9/dist-packages (from alpaca_trade_api>=2.1.0->finrl==0.3.5) (2.28.2)\n", - "Requirement already satisfied: deprecation==2.1.0 in /usr/local/lib/python3.9/dist-packages (from alpaca_trade_api>=2.1.0->finrl==0.3.5) (2.1.0)\n", - "Requirement already satisfied: websockets<11,>=9.0 in /usr/local/lib/python3.9/dist-packages (from alpaca_trade_api>=2.1.0->finrl==0.3.5) (10.4)\n", - "Requirement already satisfied: aiohttp==3.8.1 in /usr/local/lib/python3.9/dist-packages (from alpaca_trade_api>=2.1.0->finrl==0.3.5) (3.8.1)\n", - "Requirement already satisfied: PyYAML==6.0 in /usr/local/lib/python3.9/dist-packages (from alpaca_trade_api>=2.1.0->finrl==0.3.5) (6.0)\n", - "Requirement already satisfied: websocket-client<2,>=0.56.0 in /usr/local/lib/python3.9/dist-packages (from alpaca_trade_api>=2.1.0->finrl==0.3.5) (1.5.1)\n", - "Requirement already satisfied: async-timeout<5.0,>=4.0.0a3 in /usr/local/lib/python3.9/dist-packages (from aiohttp==3.8.1->alpaca_trade_api>=2.1.0->finrl==0.3.5) (4.0.2)\n", - "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.9/dist-packages (from aiohttp==3.8.1->alpaca_trade_api>=2.1.0->finrl==0.3.5) (1.3.1)\n", - "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.9/dist-packages (from aiohttp==3.8.1->alpaca_trade_api>=2.1.0->finrl==0.3.5) (22.2.0)\n", - "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.9/dist-packages (from aiohttp==3.8.1->alpaca_trade_api>=2.1.0->finrl==0.3.5) (6.0.4)\n", - "Requirement already satisfied: yarl<2.0,>=1.0 in /usr/local/lib/python3.9/dist-packages (from aiohttp==3.8.1->alpaca_trade_api>=2.1.0->finrl==0.3.5) (1.8.2)\n", - "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.9/dist-packages (from aiohttp==3.8.1->alpaca_trade_api>=2.1.0->finrl==0.3.5) (1.3.3)\n", - "Requirement already satisfied: charset-normalizer<3.0,>=2.0 in /usr/local/lib/python3.9/dist-packages (from aiohttp==3.8.1->alpaca_trade_api>=2.1.0->finrl==0.3.5) (2.1.1)\n", - "Requirement already satisfied: packaging in /usr/local/lib/python3.9/dist-packages (from deprecation==2.1.0->alpaca_trade_api>=2.1.0->finrl==0.3.5) (23.0)\n", - "Requirement already satisfied: setuptools>=60.9.0 in /usr/local/lib/python3.9/dist-packages (from ccxt>=1.66.32->finrl==0.3.5) (67.6.0)\n", - "Requirement already satisfied: cryptography>=2.6.1 in /usr/local/lib/python3.9/dist-packages (from ccxt>=1.66.32->finrl==0.3.5) (39.0.2)\n", - "Requirement already satisfied: certifi>=2018.1.18 in /usr/local/lib/python3.9/dist-packages (from ccxt>=1.66.32->finrl==0.3.5) (2022.12.7)\n", - "Requirement already satisfied: aiodns>=1.1.1 in /usr/local/lib/python3.9/dist-packages (from ccxt>=1.66.32->finrl==0.3.5) (3.0.0)\n", - "Requirement already satisfied: cloudpickle>=1.2.0 in /usr/local/lib/python3.9/dist-packages (from gym>=0.17->finrl==0.3.5) (2.2.1)\n", - "Requirement already satisfied: virtualenv>=20.0.24 in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (20.21.0)\n", - "Requirement already satisfied: grpcio>=1.32.0 in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (1.51.3)\n", - "Requirement already satisfied: filelock in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (3.9.0)\n", - "Requirement already satisfied: protobuf!=3.19.5,>=3.15.3 in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (3.19.6)\n", - "Requirement already satisfied: jsonschema in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (4.3.3)\n", - "Requirement already satisfied: click>=7.0 in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (8.1.3)\n", - "Requirement already satisfied: tabulate in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (0.8.10)\n", - "Requirement already satisfied: smart-open in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (6.3.0)\n", - "Requirement already satisfied: pydantic in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (1.10.6)\n", - "Requirement already satisfied: opencensus in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (0.11.2)\n", - "Requirement already satisfied: py-spy>=0.2.0 in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (0.3.14)\n", - "Requirement already satisfied: aiohttp-cors in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (0.7.0)\n", - "Requirement already satisfied: prometheus-client>=0.7.1 in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (0.16.0)\n", - "Requirement already satisfied: gpustat>=1.0.0 in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (1.0.0)\n", - "Requirement already satisfied: colorful in /usr/local/lib/python3.9/dist-packages (from ray[default,tune]>=2.0.0->finrl==0.3.5) (0.5.5)\n", - "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.9/dist-packages (from scikit-learn>=0.21.0->finrl==0.3.5) (3.1.0)\n", - "Requirement already satisfied: joblib>=1.1.1 in /usr/local/lib/python3.9/dist-packages (from scikit-learn>=0.21.0->finrl==0.3.5) (1.1.1)\n", - "Requirement already satisfied: scipy>=1.3.2 in /usr/local/lib/python3.9/dist-packages (from scikit-learn>=0.21.0->finrl==0.3.5) (1.10.1)\n", - "Requirement already satisfied: torch>=1.11 in /usr/local/lib/python3.9/dist-packages (from stable-baselines3<2.0.0,>=1.6.2->finrl==0.3.5) (1.13.1+cu116)\n", - "Requirement already satisfied: pymysql>=0.7.6 in /usr/local/lib/python3.9/dist-packages (from jqdatasdk->finrl==0.3.5) (1.0.2)\n", - "Requirement already satisfied: SQLAlchemy>=1.2.8 in /usr/local/lib/python3.9/dist-packages (from jqdatasdk->finrl==0.3.5) (1.4.46)\n", - "Requirement already satisfied: six in /usr/local/lib/python3.9/dist-packages (from jqdatasdk->finrl==0.3.5) (1.15.0)\n", - "Requirement already satisfied: thriftpy2>=0.3.9 in /usr/local/lib/python3.9/dist-packages (from jqdatasdk->finrl==0.3.5) (0.4.16)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->finrl==0.3.5) (1.4.4)\n", - "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->finrl==0.3.5) (8.4.0)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.9/dist-packages (from matplotlib->finrl==0.3.5) (4.39.0)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.9/dist-packages (from matplotlib->finrl==0.3.5) (0.11.0)\n", - "Requirement already satisfied: pyparsing>=2.2.1 in /usr/local/lib/python3.9/dist-packages (from matplotlib->finrl==0.3.5) (3.0.9)\n", - "Requirement already satisfied: ipython>=3.2.3 in /usr/local/lib/python3.9/dist-packages (from pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (7.9.0)\n", - "Requirement already satisfied: seaborn>=0.7.1 in /usr/local/lib/python3.9/dist-packages (from pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (0.11.2)\n", - "Requirement already satisfied: empyrical>=0.5.0 in /usr/local/lib/python3.9/dist-packages (from pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (0.5.5)\n", - "Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.9/dist-packages (from yfinance->finrl==0.3.5) (0.0.11)\n", - "Requirement already satisfied: appdirs>=1.4.4 in /usr/local/lib/python3.9/dist-packages (from yfinance->finrl==0.3.5) (1.4.4)\n", - "Requirement already satisfied: beautifulsoup4>=4.11.1 in /usr/local/lib/python3.9/dist-packages (from yfinance->finrl==0.3.5) (4.11.2)\n", - "Requirement already satisfied: frozendict>=2.3.4 in /usr/local/lib/python3.9/dist-packages (from yfinance->finrl==0.3.5) (2.3.5)\n", - "Requirement already satisfied: html5lib>=1.1 in /usr/local/lib/python3.9/dist-packages (from yfinance->finrl==0.3.5) (1.1)\n", - "Requirement already satisfied: lxml>=4.9.1 in /usr/local/lib/python3.9/dist-packages (from yfinance->finrl==0.3.5) (4.9.2)\n", - "Requirement already satisfied: pycares>=4.0.0 in /usr/local/lib/python3.9/dist-packages (from aiodns>=1.1.1->ccxt>=1.66.32->finrl==0.3.5) (4.3.0)\n", - "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.9/dist-packages (from beautifulsoup4>=4.11.1->yfinance->finrl==0.3.5) (2.4)\n", - "Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.9/dist-packages (from cryptography>=2.6.1->ccxt>=1.66.32->finrl==0.3.5) (1.15.1)\n", - "Requirement already satisfied: pandas-datareader>=0.2 in /usr/local/lib/python3.9/dist-packages (from empyrical>=0.5.0->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (0.10.0)\n", - "Requirement already satisfied: nvidia-ml-py<=11.495.46,>=11.450.129 in /usr/local/lib/python3.9/dist-packages (from gpustat>=1.0.0->ray[default,tune]>=2.0.0->finrl==0.3.5) (11.495.46)\n", - "Requirement already satisfied: psutil>=5.6.0 in /usr/local/lib/python3.9/dist-packages (from gpustat>=1.0.0->ray[default,tune]>=2.0.0->finrl==0.3.5) (5.9.4)\n", - "Requirement already satisfied: blessed>=1.17.1 in /usr/local/lib/python3.9/dist-packages (from gpustat>=1.0.0->ray[default,tune]>=2.0.0->finrl==0.3.5) (1.20.0)\n", - "Requirement already satisfied: webencodings in /usr/local/lib/python3.9/dist-packages (from html5lib>=1.1->yfinance->finrl==0.3.5) (0.5.1)\n", - "Requirement already satisfied: pickleshare in /usr/local/lib/python3.9/dist-packages (from ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (0.7.5)\n", - "Requirement already satisfied: prompt-toolkit<2.1.0,>=2.0.0 in /usr/local/lib/python3.9/dist-packages (from ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (2.0.10)\n", - "Requirement already satisfied: backcall in /usr/local/lib/python3.9/dist-packages (from ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (0.2.0)\n", - "Requirement already satisfied: pexpect in /usr/local/lib/python3.9/dist-packages (from ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (4.8.0)\n", - "Requirement already satisfied: jedi>=0.10 in /usr/local/lib/python3.9/dist-packages (from ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (0.18.2)\n", - "Requirement already satisfied: traitlets>=4.2 in /usr/local/lib/python3.9/dist-packages (from ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (5.7.1)\n", - "Requirement already satisfied: decorator in /usr/local/lib/python3.9/dist-packages (from ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (4.4.2)\n", - "Requirement already satisfied: pygments in /usr/local/lib/python3.9/dist-packages (from ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (2.6.1)\n", - "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.9/dist-packages (from requests<3,>2->alpaca_trade_api>=2.1.0->finrl==0.3.5) (2.10)\n", - "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.9/dist-packages (from SQLAlchemy>=1.2.8->jqdatasdk->finrl==0.3.5) (2.0.2)\n", - "Requirement already satisfied: ply<4.0,>=3.4 in /usr/local/lib/python3.9/dist-packages (from thriftpy2>=0.3.9->jqdatasdk->finrl==0.3.5) (3.11)\n", - "Requirement already satisfied: typing-extensions in /usr/local/lib/python3.9/dist-packages (from torch>=1.11->stable-baselines3<2.0.0,>=1.6.2->finrl==0.3.5) (4.5.0)\n", - "Requirement already satisfied: distlib<1,>=0.3.6 in /usr/local/lib/python3.9/dist-packages (from virtualenv>=20.0.24->ray[default,tune]>=2.0.0->finrl==0.3.5) (0.3.6)\n", - "Requirement already satisfied: platformdirs<4,>=2.4 in /usr/local/lib/python3.9/dist-packages (from virtualenv>=20.0.24->ray[default,tune]>=2.0.0->finrl==0.3.5) (3.1.0)\n", - "Requirement already satisfied: pyglet>=1.4.0 in /usr/local/lib/python3.9/dist-packages (from gym>=0.17->finrl==0.3.5) (2.0.5)\n", - "Requirement already satisfied: box2d-py==2.3.5 in /usr/local/lib/python3.9/dist-packages (from gym>=0.17->finrl==0.3.5) (2.3.5)\n", - "Requirement already satisfied: pyrsistent!=0.17.0,!=0.17.1,!=0.17.2,>=0.14.0 in /usr/local/lib/python3.9/dist-packages (from jsonschema->ray[default,tune]>=2.0.0->finrl==0.3.5) (0.19.3)\n", - "Requirement already satisfied: opencensus-context>=0.1.3 in /usr/local/lib/python3.9/dist-packages (from opencensus->ray[default,tune]>=2.0.0->finrl==0.3.5) (0.1.3)\n", - "Requirement already satisfied: google-api-core<3.0.0,>=1.0.0 in /usr/local/lib/python3.9/dist-packages (from opencensus->ray[default,tune]>=2.0.0->finrl==0.3.5) (2.11.0)\n", - "Requirement already satisfied: wcwidth>=0.1.4 in /usr/local/lib/python3.9/dist-packages (from blessed>=1.17.1->gpustat>=1.0.0->ray[default,tune]>=2.0.0->finrl==0.3.5) (0.2.6)\n", - "Requirement already satisfied: pycparser in /usr/local/lib/python3.9/dist-packages (from cffi>=1.12->cryptography>=2.6.1->ccxt>=1.66.32->finrl==0.3.5) (2.21)\n", - "Requirement already satisfied: googleapis-common-protos<2.0dev,>=1.56.2 in /usr/local/lib/python3.9/dist-packages (from google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]>=2.0.0->finrl==0.3.5) (1.58.0)\n", - "Requirement already satisfied: google-auth<3.0dev,>=2.14.1 in /usr/local/lib/python3.9/dist-packages (from google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]>=2.0.0->finrl==0.3.5) (2.16.2)\n", - "Requirement already satisfied: parso<0.9.0,>=0.8.0 in /usr/local/lib/python3.9/dist-packages (from jedi>=0.10->ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (0.8.3)\n", - "Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.9/dist-packages (from pexpect->ipython>=3.2.3->pyfolio@ git+https://github.com/quantopian/pyfolio.git#egg=pyfolio-0.9.2->finrl==0.3.5) (0.7.0)\n", - "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.9/dist-packages (from google-auth<3.0dev,>=2.14.1->google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]>=2.0.0->finrl==0.3.5) (5.3.0)\n", - "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.9/dist-packages (from google-auth<3.0dev,>=2.14.1->google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]>=2.0.0->finrl==0.3.5) (0.2.8)\n", - "Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.9/dist-packages (from google-auth<3.0dev,>=2.14.1->google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]>=2.0.0->finrl==0.3.5) (4.9)\n", - "Requirement already satisfied: pyasn1<0.5.0,>=0.4.6 in /usr/local/lib/python3.9/dist-packages (from pyasn1-modules>=0.2.1->google-auth<3.0dev,>=2.14.1->google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]>=2.0.0->finrl==0.3.5) (0.4.8)\n" - ] - } - ], - "source": [ - "# ## install finrl library\n", - "!pip install wrds\n", - "!pip install swig\n", - "!pip install -q condacolab\n", - "import condacolab\n", - "condacolab.install()\n", - "!apt-get update -y -qq && apt-get install -y -qq cmake libopenmpi-dev python3-dev zlib1g-dev libgl1-mesa-glx swig\n", - "!pip install git+https://github.com/AI4Finance-Foundation/FinRL.git" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "osBHhVysOEzi" - }, - "source": [ - "\n", - "\n", - "## 2.2. Check if the additional packages needed are present, if not install them. \n", - "* Yahoo Finance API\n", - "* pandas\n", - "* numpy\n", - "* matplotlib\n", - "* stockstats\n", - "* OpenAI gym\n", - "* stable-baselines\n", - "* tensorflow\n", - "* pyfolio" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "nGv01K8Sh1hn" - }, - "source": [ - "\n", - "## 2.3. Import Packages" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "id": "EeMK7Uentj1V" - }, - "outputs": [], - "source": [ - "import warnings\n", - "warnings.filterwarnings(\"ignore\")" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": { - "id": "lPqeTTwoh1hn" - }, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "import matplotlib\n", - "import matplotlib.pyplot as plt\n", - "# matplotlib.use('Agg')\n", - "import datetime\n", - "\n", - "%matplotlib inline\n", - "from finrl.config_tickers import DOW_30_TICKER\n", - "from finrl.meta.preprocessor.yahoodownloader import YahooDownloader\n", - "from finrl.meta.preprocessor.preprocessors import FeatureEngineer, data_split\n", - "from finrl.meta.env_stock_trading.env_stocktrading import StockTradingEnv\n", - "from finrl.agents.stablebaselines3.models import DRLAgent,DRLEnsembleAgent\n", - "from finrl.plot import backtest_stats, backtest_plot, get_daily_return, get_baseline\n", - "\n", - "from pprint import pprint\n", - "\n", - "import sys\n", - "sys.path.append(\"../FinRL-Library\")\n", - "\n", - "import itertools" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "T2owTj985RW4" - }, - "source": [ - "\n", - "## 2.4. Create Folders" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": { - "id": "w9A8CN5R5PuZ" - }, - "outputs": [], - "source": [ - "import os\n", - "from finrl.main import check_and_make_directories\n", - "from finrl.config import (\n", - " DATA_SAVE_DIR,\n", - " TRAINED_MODEL_DIR,\n", - " TENSORBOARD_LOG_DIR,\n", - " RESULTS_DIR,\n", - " INDICATORS,\n", - " TRAIN_START_DATE,\n", - " TRAIN_END_DATE,\n", - " TEST_START_DATE,\n", - " TEST_END_DATE,\n", - " TRADE_START_DATE,\n", - " TRADE_END_DATE,\n", - ")\n", - "\n", - "check_and_make_directories([DATA_SAVE_DIR, TRAINED_MODEL_DIR, TENSORBOARD_LOG_DIR, RESULTS_DIR])" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "A289rQWMh1hq" - }, - "source": [ - "\n", - "# Part 3. Download Data\n", - "Yahoo Finance is a website that provides stock data, financial news, financial reports, etc. All the data provided by Yahoo Finance is free.\n", - "* FinRL uses a class **YahooDownloader** to fetch data from Yahoo Finance API\n", - "* Call Limit: Using the Public API (without authentication), you are limited to 2,000 requests per hour per IP (or up to a total of 48,000 requests a day).\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "NPeQ7iS-LoMm" - }, - "source": [ - "\n", - "\n", - "-----\n", - "class YahooDownloader:\n", - " Provides methods for retrieving daily stock data from\n", - " Yahoo Finance API\n", - "\n", - " Attributes\n", - " ----------\n", - " start_date : str\n", - " start date of the data (modified from config.py)\n", - " end_date : str\n", - " end date of the data (modified from config.py)\n", - " ticker_list : list\n", - " a list of stock tickers (modified from config.py)\n", - "\n", - " Methods\n", - " -------\n", - " fetch_data()\n", - " Fetches data from yahoo API\n" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "metadata": { + "id": "gXaoZs2lh1hi" + }, + "source": [ + "# Deep Reinforcement Learning for Stock Trading from Scratch: Multiple Stock Trading Using Ensemble Strategy\n", + "\n", + "Tutorials to use OpenAI DRL to trade multiple stocks using ensemble strategy in one Jupyter Notebook | Presented at ICAIF 2020\n", + "\n", + "* This notebook is the reimplementation of our paper: Deep Reinforcement Learning for Automated Stock Trading: An Ensemble Strategy, using FinRL.\n", + "* Check out medium blog for detailed explanations: https://medium.com/@ai4finance/deep-reinforcement-learning-for-automated-stock-trading-f1dad0126a02\n", + "* Please report any issues to our Github: https://github.com/AI4Finance-LLC/FinRL-Library/issues\n", + "* **Pytorch Version**\n", + "\n" + ] }, - "id": "JzqRRTOX6aFu", - "outputId": "178c70ab-72e5-4ed7-cfa8-fd6ea7b1e8ad" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "['AXP', 'AMGN', 'AAPL', 'BA', 'CAT', 'CSCO', 'CVX', 'GS', 'HD', 'HON', 'IBM', 'INTC', 'JNJ', 'KO', 'JPM', 'MCD', 'MMM', 'MRK', 'MSFT', 'NKE', 'PG', 'TRV', 'UNH', 'CRM', 'VZ', 'V', 'WBA', 'WMT', 'DIS', 'DOW']\n" - ] - } - ], - "source": [ - "print(DOW_30_TICKER)" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "metadata": { + "id": "lGunVt8oLCVS" + }, + "source": [ + "# Content" + ] }, - "id": "yCKm4om-s9kE", - "outputId": "0a5b0405-7c4f-4afd-c3e1-1dabd55c81fb" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "[*********************100%***********************] 1 of 1 completed\n", - "Shape of DataFrame: (97013, 8)\n" - ] - } - ], - "source": [ - "# TRAIN_START_DATE = '2009-04-01'\n", - "# TRAIN_END_DATE = '2021-01-01'\n", - "# TEST_START_DATE = '2021-01-01'\n", - "# TEST_END_DATE = '2022-06-01'\n", - "\n", - "TRAIN_START_DATE = '2010-01-01'\n", - "TRAIN_END_DATE = '2021-10-01'\n", - "TEST_START_DATE = '2021-10-01'\n", - "TEST_END_DATE = '2023-03-01'\n", - "\n", - "df = YahooDownloader(start_date = TRAIN_START_DATE,\n", - " end_date = TEST_END_DATE,\n", - " ticker_list = DOW_30_TICKER).fetch_data()" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 206 + "cell_type": "markdown", + "metadata": { + "id": "HOzAKQ-SLGX6" + }, + "source": [ + "* [1. Problem Definition](#0)\n", + "* [2. Getting Started - Load Python packages](#1)\n", + " * [2.1. Install Packages](#1.1) \n", + " * [2.2. Check Additional Packages](#1.2)\n", + " * [2.3. Import Packages](#1.3)\n", + " * [2.4. Create Folders](#1.4)\n", + "* [3. Download Data](#2)\n", + "* [4. Preprocess Data](#3) \n", + " * [4.1. Technical Indicators](#3.1)\n", + " * [4.2. Perform Feature Engineering](#3.2)\n", + "* [5.Build Environment](#4) \n", + " * [5.1. Training & Trade Data Split](#4.1)\n", + " * [5.2. User-defined Environment](#4.2) \n", + " * [5.3. Initialize Environment](#4.3) \n", + "* [6.Implement DRL Algorithms](#5) \n", + "* [7.Backtesting Performance](#6) \n", + " * [7.1. BackTestStats](#6.1)\n", + " * [7.2. BackTestPlot](#6.2) \n", + " * [7.3. Baseline Stats](#6.3) \n", + " * [7.3. Compare to Stock Market Index](#6.4) " + ] }, - "id": "GiRuFOTOtj1Y", - "outputId": "402874c0-b13f-437b-a67f-a83f88de66eb" - }, - "outputs": [ { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dateopenhighlowclosevolumeticday
02010-01-047.6225007.6607147.5850006.505280493729600AAPL0
12010-01-0456.63000157.86999956.56000142.8889585277400AMGN0
22010-01-0440.81000141.09999840.38999933.6759726894300AXP0
32010-01-0455.72000156.38999954.79999943.7775466186700BA0
42010-01-0457.65000259.18999957.50999841.1569147325600CAT0
\n", - "
\n", - " \n", - " \n", - " \n", - "\n", - " \n", - "
\n", - "
\n", - " " - ], - "text/plain": [ - " date open high low close volume tic \\\n", - "0 2010-01-04 7.622500 7.660714 7.585000 6.505280 493729600 AAPL \n", - "1 2010-01-04 56.630001 57.869999 56.560001 42.888958 5277400 AMGN \n", - "2 2010-01-04 40.810001 41.099998 40.389999 33.675972 6894300 AXP \n", - "3 2010-01-04 55.720001 56.389999 54.799999 43.777546 6186700 BA \n", - "4 2010-01-04 57.650002 59.189999 57.509998 41.156914 7325600 CAT \n", - "\n", - " day \n", - "0 0 \n", - "1 0 \n", - "2 0 \n", - "3 0 \n", - "4 0 " + "cell_type": "markdown", + "metadata": { + "id": "sApkDlD9LIZv" + }, + "source": [ + "\n", + "# Part 1. Problem Definition" ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 206 }, - "id": "DSw4ZEzVtj1Z", - "outputId": "94617d16-432c-40eb-f758-16d2fdab09e0" - }, - "outputs": [ { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dateopenhighlowclosevolumeticday
970082023-02-28482.670013483.359985473.920013474.2508543902100UNH1
970092023-02-28220.000000221.770004219.500000219.9400025385400V1
970102023-02-2838.70000138.97000138.54999938.81000116685300VZ1
970112023-02-2835.48000035.77999935.32000035.5299998847000WBA1
970122023-02-28141.000000142.649994140.949997142.1300056018000WMT1
\n", - "
\n", - " \n", - " \n", - " \n", - "\n", - " \n", - "
\n", - "
\n", - " " - ], - "text/plain": [ - " date open high low close volume \\\n", - "97008 2023-02-28 482.670013 483.359985 473.920013 474.250854 3902100 \n", - "97009 2023-02-28 220.000000 221.770004 219.500000 219.940002 5385400 \n", - "97010 2023-02-28 38.700001 38.970001 38.549999 38.810001 16685300 \n", - "97011 2023-02-28 35.480000 35.779999 35.320000 35.529999 8847000 \n", - "97012 2023-02-28 141.000000 142.649994 140.949997 142.130005 6018000 \n", - "\n", - " tic day \n", - "97008 UNH 1 \n", - "97009 V 1 \n", - "97010 VZ 1 \n", - "97011 WBA 1 \n", - "97012 WMT 1 " + "cell_type": "markdown", + "metadata": { + "id": "HjLD2TZSLKZ-" + }, + "source": [ + "This problem is to design an automated trading solution for single stock trading. We model the stock trading process as a Markov Decision Process (MDP). We then formulate our trading goal as a maximization problem.\n", + "\n", + "The algorithm is trained using Deep Reinforcement Learning (DRL) algorithms and the components of the reinforcement learning environment are:\n", + "\n", + "\n", + "* Action: The action space describes the allowed actions that the agent interacts with the\n", + "environment. Normally, a ∈ A includes three actions: a ∈ {−1, 0, 1}, where −1, 0, 1 represent\n", + "selling, holding, and buying one stock. Also, an action can be carried upon multiple shares. We use\n", + "an action space {−k, ..., −1, 0, 1, ..., k}, where k denotes the number of shares. For example, \"Buy\n", + "10 shares of AAPL\" or \"Sell 10 shares of AAPL\" are 10 or −10, respectively\n", + "\n", + "* Reward function: r(s, a, s′) is the incentive mechanism for an agent to learn a better action. The change of the portfolio value when action a is taken at state s and arriving at new state s', i.e., r(s, a, s′) = v′ − v, where v′ and v represent the portfolio\n", + "values at state s′ and s, respectively\n", + "\n", + "* State: The state space describes the observations that the agent receives from the environment. Just as a human trader needs to analyze various information before executing a trade, so\n", + "our trading agent observes many different features to better learn in an interactive environment.\n", + "\n", + "* Environment: Dow 30 consituents\n", + "\n", + "\n", + "The data of the single stock that we will be using for this case study is obtained from Yahoo Finance API. The data contains Open-High-Low-Close price and volume.\n" ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.tail()" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" }, - "id": "CV3HrZHLh1hy", - "outputId": "73944c23-5a4e-49f8-b9e5-da382b4fc7f5" - }, - "outputs": [ { - "data": { - "text/plain": [ - "(97013, 8)" + "cell_type": "markdown", + "metadata": { + "id": "Ffsre789LY08" + }, + "source": [ + "\n", + "# Part 2. Getting Started- Load Python Packages" ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.shape" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 206 }, - "id": "4hYkeaPiICHS", - "outputId": "87cca0b1-8d3c-4a61-e061-ea0d9989daa1" - }, - "outputs": [ { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dateopenhighlowclosevolumeticday
02010-01-047.6225007.6607147.5850006.505280493729600AAPL0
12010-01-0456.63000157.86999956.56000142.8889585277400AMGN0
22010-01-0440.81000141.09999840.38999933.6759726894300AXP0
32010-01-0455.72000156.38999954.79999943.7775466186700BA0
42010-01-0457.65000259.18999957.50999841.1569147325600CAT0
\n", - "
\n", - " \n", - " \n", - " \n", - "\n", - " \n", - "
\n", - "
\n", - " " + "cell_type": "markdown", + "metadata": { + "id": "Uy5_PTmOh1hj" + }, + "source": [ + "\n", + "## 2.1. Install all the packages through FinRL library\n" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "mPT0ipYE28wL", + "outputId": "31d6a8ab-c43f-4558-fbc2-6b633ef7654b" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Requirement already satisfied: wrds in /usr/local/lib/python3.10/site-packages (3.2.0)\n", + "Requirement already satisfied: numpy<1.27,>=1.26 in /usr/local/lib/python3.10/site-packages (from wrds) (1.26.4)\n", + "Requirement already satisfied: packaging<23.3 in /usr/local/lib/python3.10/site-packages (from wrds) (23.2)\n", + "Requirement already satisfied: pandas<2.3,>=2.2 in /usr/local/lib/python3.10/site-packages (from wrds) (2.2.1)\n", + "Requirement already satisfied: psycopg2-binary<2.10,>=2.9 in /usr/local/lib/python3.10/site-packages (from wrds) (2.9.9)\n", + "Requirement already satisfied: scipy<1.13,>=1.12 in /usr/local/lib/python3.10/site-packages (from wrds) (1.12.0)\n", + "Requirement already satisfied: sqlalchemy<2.1,>=2 in /usr/local/lib/python3.10/site-packages (from wrds) (2.0.29)\n", + "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.10/site-packages (from pandas<2.3,>=2.2->wrds) (2.9.0.post0)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/site-packages (from pandas<2.3,>=2.2->wrds) (2024.1)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/site-packages (from pandas<2.3,>=2.2->wrds) (2024.1)\n", + "Requirement already satisfied: typing-extensions>=4.6.0 in /usr/local/lib/python3.10/site-packages (from sqlalchemy<2.1,>=2->wrds) (4.11.0)\n", + "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/site-packages (from sqlalchemy<2.1,>=2->wrds) (3.0.3)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/site-packages (from python-dateutil>=2.8.2->pandas<2.3,>=2.2->wrds) (1.16.0)\n", + "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0mRequirement already satisfied: swig in /usr/local/lib/python3.10/site-packages (4.2.1)\n", + "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m✨🍰✨ Everything looks OK!\n", + "Collecting git+https://github.com/AI4Finance-Foundation/FinRL.git\n", + " Cloning https://github.com/AI4Finance-Foundation/FinRL.git to /tmp/pip-req-build-xp3z2_tj\n", + " Running command git clone --filter=blob:none --quiet https://github.com/AI4Finance-Foundation/FinRL.git /tmp/pip-req-build-xp3z2_tj\n", + " Resolved https://github.com/AI4Finance-Foundation/FinRL.git to commit 7b2f30302e787e9276f52823c87b7c2ade4203cf\n", + " Installing build dependencies ... \u001b[?25l\u001b[?25hdone\n", + " Getting requirements to build wheel ... \u001b[?25l\u001b[?25hdone\n", + " Preparing metadata (pyproject.toml) ... \u001b[?25l\u001b[?25hdone\n", + "Collecting elegantrl@ git+https://github.com/AI4Finance-Foundation/ElegantRL.git#egg=elegantrl (from finrl==0.3.6)\n", + " Cloning https://github.com/AI4Finance-Foundation/ElegantRL.git to /tmp/pip-install-fh0kgi8h/elegantrl_9258375a89e84ebb973a8518f78e4a92\n", + " Running command git clone --filter=blob:none --quiet https://github.com/AI4Finance-Foundation/ElegantRL.git /tmp/pip-install-fh0kgi8h/elegantrl_9258375a89e84ebb973a8518f78e4a92\n", + " Resolved https://github.com/AI4Finance-Foundation/ElegantRL.git to commit 87cf325af4c0608f1e74941091a3bc277dfaf739\n", + " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: alpaca-trade-api<4,>=3 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (3.2.0)\n", + "Requirement already satisfied: ccxt<4,>=3 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (3.1.60)\n", + "Requirement already satisfied: exchange-calendars<5,>=4 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (4.5.3)\n", + "Requirement already satisfied: jqdatasdk<2,>=1 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (1.9.3)\n", + "Requirement already satisfied: pyfolio<0.10,>=0.9 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (0.9.2)\n", + "Requirement already satisfied: pyportfolioopt<2,>=1 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (1.5.5)\n", + "Requirement already satisfied: ray<3,>=2 in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (2.10.0)\n", + "Requirement already satisfied: scikit-learn<2,>=1 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (1.4.1.post1)\n", + "Requirement already satisfied: stable-baselines3>=2.0.0a5 in /usr/local/lib/python3.10/site-packages (from stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (2.3.0)\n", + "Requirement already satisfied: stockstats<0.6,>=0.5 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (0.5.4)\n", + "Requirement already satisfied: wrds<4,>=3 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (3.2.0)\n", + "Requirement already satisfied: yfinance<0.3,>=0.2 in /usr/local/lib/python3.10/site-packages (from finrl==0.3.6) (0.2.37)\n", + "Requirement already satisfied: pandas>=0.18.1 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (2.2.1)\n", + "Requirement already satisfied: numpy>=1.11.1 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (1.26.4)\n", + "Requirement already satisfied: requests<3,>2 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (2.31.0)\n", + "Requirement already satisfied: urllib3<2,>1.24 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (1.26.18)\n", + "Requirement already satisfied: websocket-client<2,>=0.56.0 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (1.7.0)\n", + "Requirement already satisfied: websockets<11,>=9.0 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (10.4)\n", + "Requirement already satisfied: msgpack==1.0.3 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (1.0.3)\n", + "Requirement already satisfied: aiohttp<4,>=3.8.3 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (3.9.3)\n", + "Requirement already satisfied: PyYAML==6.0.1 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (6.0.1)\n", + "Requirement already satisfied: deprecation==2.1.0 in /usr/local/lib/python3.10/site-packages (from alpaca-trade-api<4,>=3->finrl==0.3.6) (2.1.0)\n", + "Requirement already satisfied: packaging in /usr/local/lib/python3.10/site-packages (from deprecation==2.1.0->alpaca-trade-api<4,>=3->finrl==0.3.6) (23.2)\n", + "Requirement already satisfied: setuptools>=60.9.0 in /usr/local/lib/python3.10/site-packages (from ccxt<4,>=3->finrl==0.3.6) (68.2.2)\n", + "Requirement already satisfied: certifi>=2018.1.18 in /usr/local/lib/python3.10/site-packages (from ccxt<4,>=3->finrl==0.3.6) (2023.11.17)\n", + "Requirement already satisfied: cryptography>=2.6.1 in /usr/local/lib/python3.10/site-packages (from ccxt<4,>=3->finrl==0.3.6) (42.0.5)\n", + "Requirement already satisfied: aiodns>=1.1.1 in /usr/local/lib/python3.10/site-packages (from ccxt<4,>=3->finrl==0.3.6) (3.2.0)\n", + "Requirement already satisfied: yarl>=1.7.2 in /usr/local/lib/python3.10/site-packages (from ccxt<4,>=3->finrl==0.3.6) (1.9.4)\n", + "Requirement already satisfied: pyluach in /usr/local/lib/python3.10/site-packages (from exchange-calendars<5,>=4->finrl==0.3.6) (2.2.0)\n", + "Requirement already satisfied: toolz in /usr/local/lib/python3.10/site-packages (from exchange-calendars<5,>=4->finrl==0.3.6) (0.12.1)\n", + "Requirement already satisfied: tzdata in /usr/local/lib/python3.10/site-packages (from exchange-calendars<5,>=4->finrl==0.3.6) (2024.1)\n", + "Requirement already satisfied: korean-lunar-calendar in /usr/local/lib/python3.10/site-packages (from exchange-calendars<5,>=4->finrl==0.3.6) (0.3.1)\n", + "Requirement already satisfied: six in /usr/local/lib/python3.10/site-packages (from jqdatasdk<2,>=1->finrl==0.3.6) (1.16.0)\n", + "Requirement already satisfied: SQLAlchemy>=1.2.8 in /usr/local/lib/python3.10/site-packages (from jqdatasdk<2,>=1->finrl==0.3.6) (2.0.29)\n", + "Requirement already satisfied: thriftpy2>=0.3.9 in /usr/local/lib/python3.10/site-packages (from jqdatasdk<2,>=1->finrl==0.3.6) (0.4.20)\n", + "Requirement already satisfied: pymysql>=0.7.6 in /usr/local/lib/python3.10/site-packages (from jqdatasdk<2,>=1->finrl==0.3.6) (1.1.0)\n", + "Requirement already satisfied: ipython>=3.2.3 in /usr/local/lib/python3.10/site-packages (from pyfolio<0.10,>=0.9->finrl==0.3.6) (8.23.0)\n", + "Requirement already satisfied: matplotlib>=1.4.0 in /usr/local/lib/python3.10/site-packages (from pyfolio<0.10,>=0.9->finrl==0.3.6) (3.8.4)\n", + "Requirement already satisfied: pytz>=2014.10 in /usr/local/lib/python3.10/site-packages (from pyfolio<0.10,>=0.9->finrl==0.3.6) (2024.1)\n", + "Requirement already satisfied: scipy>=0.14.0 in /usr/local/lib/python3.10/site-packages (from pyfolio<0.10,>=0.9->finrl==0.3.6) (1.12.0)\n", + "Requirement already satisfied: seaborn>=0.7.1 in /usr/local/lib/python3.10/site-packages (from pyfolio<0.10,>=0.9->finrl==0.3.6) (0.13.2)\n", + "Requirement already satisfied: empyrical>=0.5.0 in /usr/local/lib/python3.10/site-packages (from pyfolio<0.10,>=0.9->finrl==0.3.6) (0.5.5)\n", + "Requirement already satisfied: cvxpy<2.0.0,>=1.1.19 in /usr/local/lib/python3.10/site-packages (from pyportfolioopt<2,>=1->finrl==0.3.6) (1.4.2)\n", + "Requirement already satisfied: click>=7.0 in /usr/local/lib/python3.10/site-packages (from ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (8.1.7)\n", + "Requirement already satisfied: filelock in /usr/local/lib/python3.10/site-packages (from ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (3.13.3)\n", + "Requirement already satisfied: jsonschema in /usr/local/lib/python3.10/site-packages (from ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (4.21.1)\n", + "Requirement already satisfied: protobuf!=3.19.5,>=3.15.3 in /usr/local/lib/python3.10/site-packages (from ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (4.25.3)\n", + "Requirement already satisfied: aiosignal in /usr/local/lib/python3.10/site-packages (from ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (1.3.1)\n", + "Requirement already satisfied: frozenlist in /usr/local/lib/python3.10/site-packages (from ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (1.4.1)\n", + "Requirement already satisfied: aiohttp-cors in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (0.7.0)\n", + "Requirement already satisfied: colorful in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (0.5.6)\n", + "Requirement already satisfied: py-spy>=0.2.0 in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (0.3.14)\n", + "Requirement already satisfied: opencensus in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (0.11.4)\n", + "Requirement already satisfied: pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<3 in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (2.6.4)\n", + "Requirement already satisfied: prometheus-client>=0.7.1 in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (0.20.0)\n", + "Requirement already satisfied: smart-open in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (7.0.4)\n", + "Requirement already satisfied: virtualenv!=20.21.1,>=20.0.24 in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (20.25.1)\n", + "Requirement already satisfied: grpcio>=1.42.0 in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (1.62.1)\n", + "Requirement already satisfied: tensorboardX>=1.9 in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (2.6.2.2)\n", + "Requirement already satisfied: pyarrow>=6.0.1 in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (15.0.2)\n", + "Requirement already satisfied: fsspec in /usr/local/lib/python3.10/site-packages (from ray[default,tune]<3,>=2->finrl==0.3.6) (2024.3.1)\n", + "Requirement already satisfied: joblib>=1.2.0 in /usr/local/lib/python3.10/site-packages (from scikit-learn<2,>=1->finrl==0.3.6) (1.4.0)\n", + "Requirement already satisfied: threadpoolctl>=2.0.0 in /usr/local/lib/python3.10/site-packages (from scikit-learn<2,>=1->finrl==0.3.6) (3.4.0)\n", + "Requirement already satisfied: gymnasium<0.30,>=0.28.1 in /usr/local/lib/python3.10/site-packages (from stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (0.29.1)\n", + "Requirement already satisfied: torch>=1.13 in /usr/local/lib/python3.10/site-packages (from stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (2.2.2)\n", + "Requirement already satisfied: cloudpickle in /usr/local/lib/python3.10/site-packages (from stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (3.0.0)\n", + "Requirement already satisfied: opencv-python in /usr/local/lib/python3.10/site-packages (from stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (4.9.0.80)\n", + "Requirement already satisfied: pygame in /usr/local/lib/python3.10/site-packages (from stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (2.1.0)\n", + "Requirement already satisfied: tensorboard>=2.9.1 in /usr/local/lib/python3.10/site-packages (from stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (2.16.2)\n", + "Requirement already satisfied: psutil in /usr/local/lib/python3.10/site-packages (from stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (5.9.8)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/site-packages (from stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (4.66.1)\n", + "Requirement already satisfied: rich in /usr/local/lib/python3.10/site-packages (from stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (13.7.1)\n", + "Requirement already satisfied: shimmy~=1.3.0 in /usr/local/lib/python3.10/site-packages (from shimmy[atari]~=1.3.0; extra == \"extra\"->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (1.3.0)\n", + "Requirement already satisfied: pillow in /usr/local/lib/python3.10/site-packages (from stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (10.3.0)\n", + "Requirement already satisfied: autorom~=0.6.1 in /usr/local/lib/python3.10/site-packages (from autorom[accept-rom-license]~=0.6.1; extra == \"extra\"->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (0.6.1)\n", + "Requirement already satisfied: psycopg2-binary<2.10,>=2.9 in /usr/local/lib/python3.10/site-packages (from wrds<4,>=3->finrl==0.3.6) (2.9.9)\n", + "Requirement already satisfied: multitasking>=0.0.7 in /usr/local/lib/python3.10/site-packages (from yfinance<0.3,>=0.2->finrl==0.3.6) (0.0.11)\n", + "Requirement already satisfied: lxml>=4.9.1 in /usr/local/lib/python3.10/site-packages (from yfinance<0.3,>=0.2->finrl==0.3.6) (5.2.1)\n", + "Requirement already satisfied: appdirs>=1.4.4 in /usr/local/lib/python3.10/site-packages (from yfinance<0.3,>=0.2->finrl==0.3.6) (1.4.4)\n", + "Requirement already satisfied: frozendict>=2.3.4 in /usr/local/lib/python3.10/site-packages (from yfinance<0.3,>=0.2->finrl==0.3.6) (2.4.1)\n", + "Requirement already satisfied: peewee>=3.16.2 in /usr/local/lib/python3.10/site-packages (from yfinance<0.3,>=0.2->finrl==0.3.6) (3.17.1)\n", + "Requirement already satisfied: beautifulsoup4>=4.11.1 in /usr/local/lib/python3.10/site-packages (from yfinance<0.3,>=0.2->finrl==0.3.6) (4.12.3)\n", + "Requirement already satisfied: html5lib>=1.1 in /usr/local/lib/python3.10/site-packages (from yfinance<0.3,>=0.2->finrl==0.3.6) (1.1)\n", + "Requirement already satisfied: gym in /usr/local/lib/python3.10/site-packages (from elegantrl@ git+https://github.com/AI4Finance-Foundation/ElegantRL.git#egg=elegantrl->finrl==0.3.6) (0.26.2)\n", + "Requirement already satisfied: pycares>=4.0.0 in /usr/local/lib/python3.10/site-packages (from aiodns>=1.1.1->ccxt<4,>=3->finrl==0.3.6) (4.4.0)\n", + "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.10/site-packages (from aiohttp<4,>=3.8.3->alpaca-trade-api<4,>=3->finrl==0.3.6) (23.2.0)\n", + "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.10/site-packages (from aiohttp<4,>=3.8.3->alpaca-trade-api<4,>=3->finrl==0.3.6) (6.0.5)\n", + "Requirement already satisfied: async-timeout<5.0,>=4.0 in /usr/local/lib/python3.10/site-packages (from aiohttp<4,>=3.8.3->alpaca-trade-api<4,>=3->finrl==0.3.6) (4.0.3)\n", + "Requirement already satisfied: AutoROM.accept-rom-license in /usr/local/lib/python3.10/site-packages (from autorom[accept-rom-license]~=0.6.1; extra == \"extra\"->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (0.6.1)\n", + "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.10/site-packages (from beautifulsoup4>=4.11.1->yfinance<0.3,>=0.2->finrl==0.3.6) (2.5)\n", + "Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.10/site-packages (from cryptography>=2.6.1->ccxt<4,>=3->finrl==0.3.6) (1.16.0)\n", + "Requirement already satisfied: osqp>=0.6.2 in /usr/local/lib/python3.10/site-packages (from cvxpy<2.0.0,>=1.1.19->pyportfolioopt<2,>=1->finrl==0.3.6) (0.6.4)\n", + "Requirement already satisfied: ecos>=2 in /usr/local/lib/python3.10/site-packages (from cvxpy<2.0.0,>=1.1.19->pyportfolioopt<2,>=1->finrl==0.3.6) (2.0.13)\n", + "Requirement already satisfied: clarabel>=0.5.0 in /usr/local/lib/python3.10/site-packages (from cvxpy<2.0.0,>=1.1.19->pyportfolioopt<2,>=1->finrl==0.3.6) (0.7.1)\n", + "Requirement already satisfied: scs>=3.0 in /usr/local/lib/python3.10/site-packages (from cvxpy<2.0.0,>=1.1.19->pyportfolioopt<2,>=1->finrl==0.3.6) (3.2.4.post1)\n", + "Requirement already satisfied: pybind11 in /usr/local/lib/python3.10/site-packages (from cvxpy<2.0.0,>=1.1.19->pyportfolioopt<2,>=1->finrl==0.3.6) (2.12.0)\n", + "Requirement already satisfied: pandas-datareader>=0.2 in /usr/local/lib/python3.10/site-packages (from empyrical>=0.5.0->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.10.0)\n", + "Requirement already satisfied: typing-extensions>=4.3.0 in /usr/local/lib/python3.10/site-packages (from gymnasium<0.30,>=0.28.1->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (4.11.0)\n", + "Requirement already satisfied: farama-notifications>=0.0.1 in /usr/local/lib/python3.10/site-packages (from gymnasium<0.30,>=0.28.1->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (0.0.4)\n", + "Requirement already satisfied: webencodings in /usr/local/lib/python3.10/site-packages (from html5lib>=1.1->yfinance<0.3,>=0.2->finrl==0.3.6) (0.5.1)\n", + "Requirement already satisfied: decorator in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (5.1.1)\n", + "Requirement already satisfied: jedi>=0.16 in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.19.1)\n", + "Requirement already satisfied: matplotlib-inline in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.1.6)\n", + "Requirement already satisfied: prompt-toolkit<3.1.0,>=3.0.41 in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (3.0.43)\n", + "Requirement already satisfied: pygments>=2.4.0 in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (2.17.2)\n", + "Requirement already satisfied: stack-data in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.6.3)\n", + "Requirement already satisfied: traitlets>=5.13.0 in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (5.14.2)\n", + "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (1.2.0)\n", + "Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.10/site-packages (from ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (4.9.0)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/site-packages (from matplotlib>=1.4.0->pyfolio<0.10,>=0.9->finrl==0.3.6) (1.2.1)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/site-packages (from matplotlib>=1.4.0->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/site-packages (from matplotlib>=1.4.0->pyfolio<0.10,>=0.9->finrl==0.3.6) (4.51.0)\n", + "Requirement already satisfied: kiwisolver>=1.3.1 in /usr/local/lib/python3.10/site-packages (from matplotlib>=1.4.0->pyfolio<0.10,>=0.9->finrl==0.3.6) (1.4.5)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/site-packages (from matplotlib>=1.4.0->pyfolio<0.10,>=0.9->finrl==0.3.6) (3.1.2)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/site-packages (from matplotlib>=1.4.0->pyfolio<0.10,>=0.9->finrl==0.3.6) (2.9.0.post0)\n", + "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/site-packages (from pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<3->ray[default,tune]<3,>=2->finrl==0.3.6) (0.6.0)\n", + "Requirement already satisfied: pydantic-core==2.16.3 in /usr/local/lib/python3.10/site-packages (from pydantic!=2.0.*,!=2.1.*,!=2.2.*,!=2.3.*,!=2.4.*,<3->ray[default,tune]<3,>=2->finrl==0.3.6) (2.16.3)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/site-packages (from requests<3,>2->alpaca-trade-api<4,>=3->finrl==0.3.6) (3.3.2)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/site-packages (from requests<3,>2->alpaca-trade-api<4,>=3->finrl==0.3.6) (3.6)\n", + "Requirement already satisfied: ale-py~=0.8.1 in /usr/local/lib/python3.10/site-packages (from shimmy[atari]~=1.3.0; extra == \"extra\"->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (0.8.1)\n", + "Requirement already satisfied: greenlet!=0.4.17 in /usr/local/lib/python3.10/site-packages (from SQLAlchemy>=1.2.8->jqdatasdk<2,>=1->finrl==0.3.6) (3.0.3)\n", + "Requirement already satisfied: absl-py>=0.4 in /usr/local/lib/python3.10/site-packages (from tensorboard>=2.9.1->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (2.1.0)\n", + "Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.10/site-packages (from tensorboard>=2.9.1->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (3.6)\n", + "Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /usr/local/lib/python3.10/site-packages (from tensorboard>=2.9.1->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (0.7.2)\n", + "Requirement already satisfied: werkzeug>=1.0.1 in /usr/local/lib/python3.10/site-packages (from tensorboard>=2.9.1->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (3.0.2)\n", + "Requirement already satisfied: ply<4.0,>=3.4 in /usr/local/lib/python3.10/site-packages (from thriftpy2>=0.3.9->jqdatasdk<2,>=1->finrl==0.3.6) (3.11)\n", + "Requirement already satisfied: sympy in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (1.12)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (3.3)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (3.1.3)\n", + "Requirement already satisfied: nvidia-cuda-nvrtc-cu12==12.1.105 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (12.1.105)\n", + "Requirement already satisfied: nvidia-cuda-runtime-cu12==12.1.105 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (12.1.105)\n", + "Requirement already satisfied: nvidia-cuda-cupti-cu12==12.1.105 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (12.1.105)\n", + "Requirement already satisfied: nvidia-cudnn-cu12==8.9.2.26 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (8.9.2.26)\n", + "Requirement already satisfied: nvidia-cublas-cu12==12.1.3.1 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (12.1.3.1)\n", + "Requirement already satisfied: nvidia-cufft-cu12==11.0.2.54 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (11.0.2.54)\n", + "Requirement already satisfied: nvidia-curand-cu12==10.3.2.106 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (10.3.2.106)\n", + "Requirement already satisfied: nvidia-cusolver-cu12==11.4.5.107 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (11.4.5.107)\n", + "Requirement already satisfied: nvidia-cusparse-cu12==12.1.0.106 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (12.1.0.106)\n", + "Requirement already satisfied: nvidia-nccl-cu12==2.19.3 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (2.19.3)\n", + "Requirement already satisfied: nvidia-nvtx-cu12==12.1.105 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (12.1.105)\n", + "Requirement already satisfied: triton==2.2.0 in /usr/local/lib/python3.10/site-packages (from torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (2.2.0)\n", + "Requirement already satisfied: nvidia-nvjitlink-cu12 in /usr/local/lib/python3.10/site-packages (from nvidia-cusolver-cu12==11.4.5.107->torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (12.4.127)\n", + "Requirement already satisfied: distlib<1,>=0.3.7 in /usr/local/lib/python3.10/site-packages (from virtualenv!=20.21.1,>=20.0.24->ray[default,tune]<3,>=2->finrl==0.3.6) (0.3.8)\n", + "Requirement already satisfied: platformdirs<5,>=3.9.1 in /usr/local/lib/python3.10/site-packages (from virtualenv!=20.21.1,>=20.0.24->ray[default,tune]<3,>=2->finrl==0.3.6) (4.1.0)\n", + "Requirement already satisfied: gym-notices>=0.0.4 in /usr/local/lib/python3.10/site-packages (from gym->elegantrl@ git+https://github.com/AI4Finance-Foundation/ElegantRL.git#egg=elegantrl->finrl==0.3.6) (0.0.8)\n", + "Requirement already satisfied: box2d-py==2.3.5 in /usr/local/lib/python3.10/site-packages (from gym[box2d]->elegantrl@ git+https://github.com/AI4Finance-Foundation/ElegantRL.git#egg=elegantrl->finrl==0.3.6) (2.3.5)\n", + "Requirement already satisfied: swig==4.* in /usr/local/lib/python3.10/site-packages (from gym[box2d]->elegantrl@ git+https://github.com/AI4Finance-Foundation/ElegantRL.git#egg=elegantrl->finrl==0.3.6) (4.2.1)\n", + "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /usr/local/lib/python3.10/site-packages (from jsonschema->ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (2023.12.1)\n", + "Requirement already satisfied: referencing>=0.28.4 in /usr/local/lib/python3.10/site-packages (from jsonschema->ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (0.34.0)\n", + "Requirement already satisfied: rpds-py>=0.7.1 in /usr/local/lib/python3.10/site-packages (from jsonschema->ray<3,>=2->ray[default,tune]<3,>=2->finrl==0.3.6) (0.18.0)\n", + "Requirement already satisfied: opencensus-context>=0.1.3 in /usr/local/lib/python3.10/site-packages (from opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (0.1.3)\n", + "Requirement already satisfied: google-api-core<3.0.0,>=1.0.0 in /usr/local/lib/python3.10/site-packages (from opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (2.18.0)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/site-packages (from rich->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (3.0.0)\n", + "Requirement already satisfied: wrapt in /usr/local/lib/python3.10/site-packages (from smart-open->ray[default,tune]<3,>=2->finrl==0.3.6) (1.16.0)\n", + "Requirement already satisfied: importlib-resources in /usr/local/lib/python3.10/site-packages (from ale-py~=0.8.1->shimmy[atari]~=1.3.0; extra == \"extra\"->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (6.4.0)\n", + "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/site-packages (from cffi>=1.12->cryptography>=2.6.1->ccxt<4,>=3->finrl==0.3.6) (2.21)\n", + "Requirement already satisfied: googleapis-common-protos<2.0.dev0,>=1.56.2 in /usr/local/lib/python3.10/site-packages (from google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (1.63.0)\n", + "Requirement already satisfied: proto-plus<2.0.0dev,>=1.22.3 in /usr/local/lib/python3.10/site-packages (from google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (1.23.0)\n", + "Requirement already satisfied: google-auth<3.0.dev0,>=2.14.1 in /usr/local/lib/python3.10/site-packages (from google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (2.29.0)\n", + "Requirement already satisfied: parso<0.9.0,>=0.8.3 in /usr/local/lib/python3.10/site-packages (from jedi>=0.16->ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.8.4)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (0.1.2)\n", + "Requirement already satisfied: qdldl in /usr/local/lib/python3.10/site-packages (from osqp>=0.6.2->cvxpy<2.0.0,>=1.1.19->pyportfolioopt<2,>=1->finrl==0.3.6) (0.1.7.post1)\n", + "Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.10/site-packages (from pexpect>4.3->ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.7.0)\n", + "Requirement already satisfied: wcwidth in /usr/local/lib/python3.10/site-packages (from prompt-toolkit<3.1.0,>=3.0.41->ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.2.13)\n", + "Requirement already satisfied: MarkupSafe>=2.1.1 in /usr/local/lib/python3.10/site-packages (from werkzeug>=1.0.1->tensorboard>=2.9.1->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (2.1.5)\n", + "Requirement already satisfied: executing>=1.2.0 in /usr/local/lib/python3.10/site-packages (from stack-data->ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (2.0.1)\n", + "Requirement already satisfied: asttokens>=2.1.0 in /usr/local/lib/python3.10/site-packages (from stack-data->ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (2.4.1)\n", + "Requirement already satisfied: pure-eval in /usr/local/lib/python3.10/site-packages (from stack-data->ipython>=3.2.3->pyfolio<0.10,>=0.9->finrl==0.3.6) (0.2.2)\n", + "Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/site-packages (from sympy->torch>=1.13->stable-baselines3>=2.0.0a5->stable-baselines3[extra]>=2.0.0a5->finrl==0.3.6) (1.3.0)\n", + "Requirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.10/site-packages (from google-auth<3.0.dev0,>=2.14.1->google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (5.3.3)\n", + "Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.10/site-packages (from google-auth<3.0.dev0,>=2.14.1->google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (0.4.0)\n", + "Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.10/site-packages (from google-auth<3.0.dev0,>=2.14.1->google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (4.9)\n", + "Requirement already satisfied: pyasn1<0.7.0,>=0.4.6 in /usr/local/lib/python3.10/site-packages (from pyasn1-modules>=0.2.1->google-auth<3.0.dev0,>=2.14.1->google-api-core<3.0.0,>=1.0.0->opencensus->ray[default,tune]<3,>=2->finrl==0.3.6) (0.6.0)\n", + "\u001b[33mWARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv\u001b[0m\u001b[33m\n", + "\u001b[0m" + ] + } ], - "text/plain": [ - " date open high low close volume tic \\\n", - "0 2010-01-04 7.622500 7.660714 7.585000 6.505280 493729600 AAPL \n", - "1 2010-01-04 56.630001 57.869999 56.560001 42.888958 5277400 AMGN \n", - "2 2010-01-04 40.810001 41.099998 40.389999 33.675972 6894300 AXP \n", - "3 2010-01-04 55.720001 56.389999 54.799999 43.777546 6186700 BA \n", - "4 2010-01-04 57.650002 59.189999 57.509998 41.156914 7325600 CAT \n", - "\n", - " day \n", - "0 0 \n", - "1 0 \n", - "2 0 \n", - "3 0 \n", - "4 0 " + "source": [ + "# ## install finrl library\n", + "!pip install wrds\n", + "!pip install swig\n", + "!pip install -q condacolab\n", + "import condacolab\n", + "condacolab.install()\n", + "!apt-get update -y -qq && apt-get install -y -qq cmake libopenmpi-dev python3-dev zlib1g-dev libgl1-mesa-glx swig\n", + "!pip install git+https://github.com/AI4Finance-Foundation/FinRL.git\n" ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.sort_values(['date','tic']).head()" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" }, - "id": "a2vryMsdNL9H", - "outputId": "6691ba9b-e613-412b-dba5-dee592bb0ff2" - }, - "outputs": [ { - "data": { - "text/plain": [ - "30" + "cell_type": "markdown", + "metadata": { + "id": "osBHhVysOEzi" + }, + "source": [ + "\n", + "\n", + "## 2.2. Check if the additional packages needed are present, if not install them.\n", + "* Yahoo Finance API\n", + "* pandas\n", + "* numpy\n", + "* matplotlib\n", + "* stockstats\n", + "* OpenAI gym\n", + "* stable-baselines\n", + "* tensorflow\n", + "* pyfolio" ] - }, - "execution_count": 41, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "len(df.tic.unique())" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" }, - "id": "XcNyXa7RNPrF", - "outputId": "edb04575-9b82-4d5e-f13a-55c884214725" - }, - "outputs": [ { - "data": { - "text/plain": [ - "AAPL 3311\n", - "AMGN 3311\n", - "WMT 3311\n", - "WBA 3311\n", - "VZ 3311\n", - "V 3311\n", - "UNH 3311\n", - "TRV 3311\n", - "PG 3311\n", - "NKE 3311\n", - "MSFT 3311\n", - "MRK 3311\n", - "MMM 3311\n", - "MCD 3311\n", - "KO 3311\n", - "JPM 3311\n", - "JNJ 3311\n", - "INTC 3311\n", - "IBM 3311\n", - "HON 3311\n", - "HD 3311\n", - "GS 3311\n", - "DIS 3311\n", - "CVX 3311\n", - "CSCO 3311\n", - "CRM 3311\n", - "CAT 3311\n", - "BA 3311\n", - "AXP 3311\n", - "DOW 994\n", - "Name: tic, dtype: int64" + "cell_type": "markdown", + "metadata": { + "id": "nGv01K8Sh1hn" + }, + "source": [ + "\n", + "## 2.3. Import Packages" ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df.tic.value_counts()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "uqC6c40Zh1iH" - }, - "source": [ - "# Part 4: Preprocess Data\n", - "Data preprocessing is a crucial step for training a high quality machine learning model. We need to check for missing data and do feature engineering in order to convert the data into a model-ready state.\n", - "* Add technical indicators. In practical trading, various information needs to be taken into account, for example the historical stock prices, current holding shares, technical indicators, etc. In this article, we demonstrate two trend-following technical indicators: MACD and RSI.\n", - "* Add turbulence index. Risk-aversion reflects whether an investor will choose to preserve the capital. It also influences one's trading strategy when facing different market volatility level. To control the risk in a worst-case scenario, such as financial crisis of 2007–2008, FinRL employs the financial turbulence index that measures extreme asset price fluctuation." - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": { - "id": "kM5bH9uroCeg" - }, - "outputs": [], - "source": [ - "# INDICATORS = ['macd',\n", - "# 'rsi_30',\n", - "# 'cci_30',\n", - "# 'dx_30']" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" }, - "id": "jgXfBcjxtj1a", - "outputId": "bd80d5c7-6ab7-4938-e1aa-f60ff642dc02" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Successfully added technical indicators\n", - "Successfully added turbulence index\n" - ] - } - ], - "source": [ - "fe = FeatureEngineer(use_technical_indicator=True,\n", - " tech_indicator_list = INDICATORS,\n", - " use_turbulence=True,\n", - " user_defined_feature = False)\n", - "\n", - "processed = fe.preprocess_data(df)\n", - "processed = processed.copy()\n", - "processed = processed.fillna(0)\n", - "processed = processed.replace(np.inf,0)" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 337 + "cell_type": "code", + "execution_count": 3, + "metadata": { + "id": "EeMK7Uentj1V" + }, + "outputs": [], + "source": [ + "import warnings\n", + "warnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "id": "lPqeTTwoh1hn" + }, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib\n", + "import matplotlib.pyplot as plt\n", + "# matplotlib.use('Agg')\n", + "import datetime\n", + "\n", + "%matplotlib inline\n", + "from finrl.config_tickers import DOW_30_TICKER\n", + "from finrl.meta.preprocessor.yahoodownloader import YahooDownloader\n", + "from finrl.meta.preprocessor.preprocessors import FeatureEngineer, data_split\n", + "from finrl.meta.env_stock_trading.env_stocktrading import StockTradingEnv\n", + "from finrl.agents.stablebaselines3.models import DRLAgent,DRLEnsembleAgent\n", + "from finrl.plot import backtest_stats, backtest_plot, get_daily_return, get_baseline\n", + "\n", + "from pprint import pprint\n", + "\n", + "import sys\n", + "sys.path.append(\"../FinRL-Library\")\n", + "\n", + "import itertools" + ] }, - "id": "grvhGJJII3Xn", - "outputId": "06a440dc-bb85-4ce9-83ab-53b3a62f0cc6" - }, - "outputs": [ { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
dateopenhighlowclosevolumeticdaymacdboll_ubboll_lbrsi_30cci_30dx_30close_30_smaclose_60_smaturbulence
215932012-12-1789.13999989.93000089.01000267.9656075956500MCD00.61337068.62918863.25992257.005648131.19576819.37403065.30205066.72609216.053989
284532013-11-2584.40000284.94000283.87000364.9717648111400CAT0-0.24727565.32331163.54632750.8316991.1295901.35351664.97878164.96185326.720482
567562017-10-11261.320007261.649994259.019989247.8182372890300BA24.730902249.028021234.86781873.02704597.55360440.628626236.822640228.71353334.994260
34892010-06-25136.990005140.899994135.429993113.39267014332300GS4-1.861536117.944122106.55569345.166489-11.34781316.836801112.760951121.3682660.000000
614122018-06-0157.14694658.02481156.88931349.89007211556925MRK40.42621150.01673546.95009258.446491129.70837612.75920448.50634247.06326218.057435
\n", - "
\n", - " \n", - " \n", - " \n", - "\n", - " \n", - "
\n", - "
\n", - " " + "cell_type": "markdown", + "metadata": { + "id": "T2owTj985RW4" + }, + "source": [ + "\n", + "## 2.4. Create Folders" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "id": "w9A8CN5R5PuZ" + }, + "outputs": [], + "source": [ + "import os\n", + "from finrl.main import check_and_make_directories\n", + "from finrl.config import (\n", + " DATA_SAVE_DIR,\n", + " TRAINED_MODEL_DIR,\n", + " TENSORBOARD_LOG_DIR,\n", + " RESULTS_DIR,\n", + " INDICATORS,\n", + " TRAIN_START_DATE,\n", + " TRAIN_END_DATE,\n", + " TEST_START_DATE,\n", + " TEST_END_DATE,\n", + " TRADE_START_DATE,\n", + " TRADE_END_DATE,\n", + ")\n", + "\n", + "check_and_make_directories([DATA_SAVE_DIR, TRAINED_MODEL_DIR, TENSORBOARD_LOG_DIR, RESULTS_DIR])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "A289rQWMh1hq" + }, + "source": [ + "\n", + "# Part 3. Download Data\n", + "Yahoo Finance is a website that provides stock data, financial news, financial reports, etc. All the data provided by Yahoo Finance is free.\n", + "* FinRL uses a class **YahooDownloader** to fetch data from Yahoo Finance API\n", + "* Call Limit: Using the Public API (without authentication), you are limited to 2,000 requests per hour per IP (or up to a total of 48,000 requests a day).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "NPeQ7iS-LoMm" + }, + "source": [ + "\n", + "\n", + "-----\n", + "class YahooDownloader:\n", + " Provides methods for retrieving daily stock data from\n", + " Yahoo Finance API\n", + "\n", + " Attributes\n", + " ----------\n", + " start_date : str\n", + " start date of the data (modified from config.py)\n", + " end_date : str\n", + " end date of the data (modified from config.py)\n", + " ticker_list : list\n", + " a list of stock tickers (modified from config.py)\n", + "\n", + " Methods\n", + " -------\n", + " fetch_data()\n", + " Fetches data from yahoo API\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "JzqRRTOX6aFu" + }, + "outputs": [], + "source": [ + "print(DOW_30_TICKER)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "yCKm4om-s9kE", + "outputId": "ee98004d-3f47-4daf-f73a-867e5faf268e" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n", + "[*********************100%%**********************] 1 of 1 completed\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Shape of DataFrame: (97013, 8)\n" + ] + } ], - "text/plain": [ - " date open high low close volume \\\n", - "21593 2012-12-17 89.139999 89.930000 89.010002 67.965607 5956500 \n", - "28453 2013-11-25 84.400002 84.940002 83.870003 64.971764 8111400 \n", - "56756 2017-10-11 261.320007 261.649994 259.019989 247.818237 2890300 \n", - "3489 2010-06-25 136.990005 140.899994 135.429993 113.392670 14332300 \n", - "61412 2018-06-01 57.146946 58.024811 56.889313 49.890072 11556925 \n", - "\n", - " tic day macd boll_ub boll_lb rsi_30 cci_30 \\\n", - "21593 MCD 0 0.613370 68.629188 63.259922 57.005648 131.195768 \n", - "28453 CAT 0 -0.247275 65.323311 63.546327 50.831699 1.129590 \n", - "56756 BA 2 4.730902 249.028021 234.867818 73.027045 97.553604 \n", - "3489 GS 4 -1.861536 117.944122 106.555693 45.166489 -11.347813 \n", - "61412 MRK 4 0.426211 50.016735 46.950092 58.446491 129.708376 \n", - "\n", - " dx_30 close_30_sma close_60_sma turbulence \n", - "21593 19.374030 65.302050 66.726092 16.053989 \n", - "28453 1.353516 64.978781 64.961853 26.720482 \n", - "56756 40.628626 236.822640 228.713533 34.994260 \n", - "3489 16.836801 112.760951 121.368266 0.000000 \n", - "61412 12.759204 48.506342 47.063262 18.057435 " + "source": [ + "# TRAIN_START_DATE = '2009-04-01'\n", + "# TRAIN_END_DATE = '2021-01-01'\n", + "# TEST_START_DATE = '2021-01-01'\n", + "# TEST_END_DATE = '2022-06-01'\n", + "from finrl.meta.preprocessor.yahoodownloader import YahooDownloader\n", + "from finrl.config_tickers import DOW_30_TICKER\n", + "\n", + "TRAIN_START_DATE = '2010-01-01'\n", + "TRAIN_END_DATE = '2021-10-01'\n", + "TEST_START_DATE = '2021-10-01'\n", + "TEST_END_DATE = '2023-03-01'\n", + "\n", + "df = YahooDownloader(start_date = TRAIN_START_DATE,\n", + " end_date = TEST_END_DATE,\n", + " ticker_list = DOW_30_TICKER).fetch_data()" ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "processed.sample(5)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "-QsYaY0Dh1iw" - }, - "source": [ - "\n", - "# Part 5. Design Environment\n", - "Considering the stochastic and interactive nature of the automated stock trading tasks, a financial task is modeled as a **Markov Decision Process (MDP)** problem. The training process involves observing stock price change, taking an action and reward's calculation to have the agent adjusting its strategy accordingly. By interacting with the environment, the trading agent will derive a trading strategy with the maximized rewards as time proceeds.\n", - "\n", - "Our trading environments, based on OpenAI Gym framework, simulate live stock markets with real market data according to the principle of time-driven simulation.\n", - "\n", - "The action space describes the allowed actions that the agent interacts with the environment. Normally, action a includes three actions: {-1, 0, 1}, where -1, 0, 1 represent selling, holding, and buying one share. Also, an action can be carried upon multiple shares. We use an action space {-k,…,-1, 0, 1, …, k}, where k denotes the number of shares to buy and -k denotes the number of shares to sell. For example, \"Buy 10 shares of AAPL\" or \"Sell 10 shares of AAPL\" are 10 or -10, respectively. The continuous action space needs to be normalized to [-1, 1], since the policy is defined on a Gaussian distribution, which needs to be normalized and symmetric." - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" }, - "id": "Q2zqII8rMIqn", - "outputId": "e16902dc-86b3-488e-ec15-234a3d6039c2" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Stock Dimension: 29, State Space: 291\n" - ] - } - ], - "source": [ - "stock_dimension = len(processed.tic.unique())\n", - "state_space = 1 + 2*stock_dimension + len(INDICATORS)*stock_dimension\n", - "print(f\"Stock Dimension: {stock_dimension}, State Space: {state_space}\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": { - "id": "AWyp84Ltto19" - }, - "outputs": [], - "source": [ - "env_kwargs = {\n", - " \"hmax\": 100, \n", - " \"initial_amount\": 1000000, \n", - " \"buy_cost_pct\": 0.001, \n", - " \"sell_cost_pct\": 0.001, \n", - " \"state_space\": state_space, \n", - " \"stock_dim\": stock_dimension, \n", - " \"tech_indicator_list\": INDICATORS,\n", - " \"action_space\": stock_dimension, \n", - " \"reward_scaling\": 1e-4,\n", - " \"print_verbosity\":5\n", - " \n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "HMNR5nHjh1iz" - }, - "source": [ - "\n", - "# Part 6: Implement DRL Algorithms\n", - "* The implementation of the DRL algorithms are based on **OpenAI Baselines** and **Stable Baselines**. Stable Baselines is a fork of OpenAI Baselines, with a major structural refactoring, and code cleanups.\n", - "* FinRL library includes fine-tuned standard DRL algorithms, such as DQN, DDPG,\n", - "Multi-Agent DDPG, PPO, SAC, A2C and TD3. We also allow users to\n", - "design their own DRL algorithms by adapting these DRL algorithms.\n", - "\n", - "* In this notebook, we are training and validating 3 agents (A2C, PPO, DDPG) using Rolling-window Ensemble Method ([reference code](https://github.com/AI4Finance-LLC/Deep-Reinforcement-Learning-for-Automated-Stock-Trading-Ensemble-Strategy-ICAIF-2020/blob/80415db8fa7b2179df6bd7e81ce4fe8dbf913806/model/models.py#L92))" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": { - "id": "v-gthCxMtj1d" - }, - "outputs": [], - "source": [ - "rebalance_window = 63 # rebalance_window is the number of days to retrain the model\n", - "validation_window = 63 # validation_window is the number of days to do validation and trading (e.g. if validation_window=63, then both validation and trading period will be 63 days)\n", - "\n", - "ensemble_agent = DRLEnsembleAgent(df=processed,\n", - " train_period=(TRAIN_START_DATE,TRAIN_END_DATE),\n", - " val_test_period=(TEST_START_DATE,TEST_END_DATE),\n", - " rebalance_window=rebalance_window, \n", - " validation_window=validation_window, \n", - " **env_kwargs)\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": { - "id": "KsfEHa_Etj1d", - "scrolled": false - }, - "outputs": [], - "source": [ - "A2C_model_kwargs = {\n", - " 'n_steps': 5,\n", - " 'ent_coef': 0.005,\n", - " 'learning_rate': 0.0007\n", - " }\n", - "\n", - "PPO_model_kwargs = {\n", - " \"ent_coef\":0.01,\n", - " \"n_steps\": 2048,\n", - " \"learning_rate\": 0.00025,\n", - " \"batch_size\": 128\n", - " }\n", - "\n", - "DDPG_model_kwargs = {\n", - " #\"action_noise\":\"ornstein_uhlenbeck\",\n", - " \"buffer_size\": 10_000,\n", - " \"learning_rate\": 0.0005,\n", - " \"batch_size\": 64\n", - " }\n", - "\n", - "timesteps_dict = {'a2c' : 10_000, \n", - " 'ppo' : 10_000, \n", - " 'ddpg' : 10_000\n", - " }" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "markdown", + "metadata": { + "id": "uqC6c40Zh1iH" + }, + "source": [ + "# Part 4: Preprocess Data\n", + "Data preprocessing is a crucial step for training a high quality machine learning model. We need to check for missing data and do feature engineering in order to convert the data into a model-ready state.\n", + "* Add technical indicators. In practical trading, various information needs to be taken into account, for example the historical stock prices, current holding shares, technical indicators, etc. In this article, we demonstrate two trend-following technical indicators: MACD and RSI.\n", + "* Add turbulence index. Risk-aversion reflects whether an investor will choose to preserve the capital. It also influences one's trading strategy when facing different market volatility level. To control the risk in a worst-case scenario, such as financial crisis of 2007–2008, FinRL employs the financial turbulence index that measures extreme asset price fluctuation." + ] }, - "id": "_1lyCECstj1e", - "outputId": "73e2d3f8-463a-42d5-d49f-c71385a26c92", - "scrolled": true - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "============Start Ensemble Strategy============\n", - "============================================\n", - "turbulence_threshold: 201.7187555549738\n", - "======Model training from: 2010-01-01 to 2021-10-04\n", - "======A2C Training========\n", - "{'n_steps': 5, 'ent_coef': 0.005, 'learning_rate': 0.0007}\n", - "Using cpu device\n", - "Logging to tensorboard_log/a2c/a2c_126_2\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 100 |\n", - "| time_elapsed | 7 |\n", - "| total_timesteps | 500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -1.35 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 99 |\n", - "| policy_loss | -43.4 |\n", - "| reward | -0.27635357 |\n", - "| std | 1 |\n", - "| value_loss | 1.99 |\n", - "---------------------------------------\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 74 |\n", - "| iterations | 200 |\n", - "| time_elapsed | 13 |\n", - "| total_timesteps | 1000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.1 |\n", - "| explained_variance | 0.0198 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 199 |\n", - "| policy_loss | -44.2 |\n", - "| reward | -0.69077545 |\n", - "| std | 1 |\n", - "| value_loss | 2.39 |\n", - "---------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 300 |\n", - "| time_elapsed | 21 |\n", - "| total_timesteps | 1500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 299 |\n", - "| policy_loss | -63.4 |\n", - "| reward | -3.8374188 |\n", - "| std | 1 |\n", - "| value_loss | 9.3 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 71 |\n", - "| iterations | 400 |\n", - "| time_elapsed | 27 |\n", - "| total_timesteps | 2000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -1.19e-07 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 399 |\n", - "| policy_loss | 68.9 |\n", - "| reward | 2.8538136 |\n", - "| std | 1 |\n", - "| value_loss | 15.2 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 500 |\n", - "| time_elapsed | 37 |\n", - "| total_timesteps | 2500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 499 |\n", - "| policy_loss | -42.4 |\n", - "| reward | -1.5924244 |\n", - "| std | 1 |\n", - "| value_loss | 2.17 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 69 |\n", - "| iterations | 600 |\n", - "| time_elapsed | 43 |\n", - "| total_timesteps | 3000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 599 |\n", - "| policy_loss | -5.29 |\n", - "| reward | 0.37984964 |\n", - "| std | 1 |\n", - "| value_loss | 0.0543 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 700 |\n", - "| time_elapsed | 51 |\n", - "| total_timesteps | 3500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 699 |\n", - "| policy_loss | 30.9 |\n", - "| reward | 0.4515791 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.19 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 800 |\n", - "| time_elapsed | 58 |\n", - "| total_timesteps | 4000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -1.19e-07 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 799 |\n", - "| policy_loss | 69.7 |\n", - "| reward | -2.0704892 |\n", - "| std | 1.01 |\n", - "| value_loss | 4.95 |\n", - "--------------------------------------\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 900 |\n", - "| time_elapsed | 67 |\n", - "| total_timesteps | 4500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 899 |\n", - "| policy_loss | -389 |\n", - "| reward | 0.045353033 |\n", - "| std | 1.01 |\n", - "| value_loss | 97.1 |\n", - "---------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1000 |\n", - "| time_elapsed | 74 |\n", - "| total_timesteps | 5000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 999 |\n", - "| policy_loss | -267 |\n", - "| reward | 2.150004 |\n", - "| std | 1.01 |\n", - "| value_loss | 118 |\n", - "------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1100 |\n", - "| time_elapsed | 81 |\n", - "| total_timesteps | 5500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | -0.00165 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1099 |\n", - "| policy_loss | -119 |\n", - "| reward | 1.6224911 |\n", - "| std | 1.01 |\n", - "| value_loss | 30.3 |\n", - "-------------------------------------\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1200 |\n", - "| time_elapsed | 88 |\n", - "| total_timesteps | 6000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 1.9e-05 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1199 |\n", - "| policy_loss | -60.1 |\n", - "| reward | -0.42283824 |\n", - "| std | 1.01 |\n", - "| value_loss | 3.21 |\n", - "---------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 1300 |\n", - "| time_elapsed | 94 |\n", - "| total_timesteps | 6500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 1.19e-07 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1299 |\n", - "| policy_loss | 35.1 |\n", - "| reward | 0.5786151 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.4 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1400 |\n", - "| time_elapsed | 103 |\n", - "| total_timesteps | 7000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.124 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1399 |\n", - "| policy_loss | 116 |\n", - "| reward | -2.6670487 |\n", - "| std | 1.01 |\n", - "| value_loss | 11.6 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 1500 |\n", - "| time_elapsed | 109 |\n", - "| total_timesteps | 7500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0.00479 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1499 |\n", - "| policy_loss | 185 |\n", - "| reward | -1.7990365 |\n", - "| std | 1 |\n", - "| value_loss | 19.9 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 1600 |\n", - "| time_elapsed | 117 |\n", - "| total_timesteps | 8000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0.0023 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1599 |\n", - "| policy_loss | -210 |\n", - "| reward | 3.3459637 |\n", - "| std | 1 |\n", - "| value_loss | 57.1 |\n", - "-------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 1700 |\n", - "| time_elapsed | 123 |\n", - "| total_timesteps | 8500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.0133 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1699 |\n", - "| policy_loss | -273 |\n", - "| reward | 2.110951 |\n", - "| std | 1 |\n", - "| value_loss | 133 |\n", - "------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1800 |\n", - "| time_elapsed | 134 |\n", - "| total_timesteps | 9000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.00431 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1799 |\n", - "| policy_loss | -38.8 |\n", - "| reward | 0.13515049 |\n", - "| std | 1 |\n", - "| value_loss | 1.57 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1900 |\n", - "| time_elapsed | 140 |\n", - "| total_timesteps | 9500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.367 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1899 |\n", - "| policy_loss | 6.24 |\n", - "| reward | 1.2570244 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.44 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 2000 |\n", - "| time_elapsed | 147 |\n", - "| total_timesteps | 10000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1999 |\n", - "| policy_loss | 25.1 |\n", - "| reward | 0.39758784 |\n", - "| std | 1.01 |\n", - "| value_loss | 0.717 |\n", - "--------------------------------------\n", - "======A2C Validation from: 2021-10-04 to 2022-01-03\n", - "A2C Sharpe Ratio: 0.13187465121153122\n", - "======PPO Training========\n", - "{'ent_coef': 0.01, 'n_steps': 2048, 'learning_rate': 0.00025, 'batch_size': 128}\n", - "Using cpu device\n", - "Logging to tensorboard_log/ppo/ppo_126_2\n", - "----------------------------------\n", - "| time/ | |\n", - "| fps | 73 |\n", - "| iterations | 1 |\n", - "| time_elapsed | 27 |\n", - "| total_timesteps | 2048 |\n", - "| train/ | |\n", - "| reward | 0.9620594 |\n", - "----------------------------------\n", - "day: 2957, episode: 5\n", - "begin_total_asset: 1000000.00\n", - "end_total_asset: 2615253.69\n", - "total_reward: 1615253.69\n", - "total_cost: 390237.91\n", - "total_trades: 81491\n", - "Sharpe: 0.577\n", - "=================================\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 69 |\n", - "| iterations | 2 |\n", - "| time_elapsed | 58 |\n", - "| total_timesteps | 4096 |\n", - "| train/ | |\n", - "| approx_kl | 0.013597676 |\n", - "| clip_fraction | 0.198 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.0129 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 5.39 |\n", - "| n_updates | 10 |\n", - "| policy_gradient_loss | -0.0336 |\n", - "| reward | 0.861756 |\n", - "| std | 1 |\n", - "| value_loss | 9.61 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 71 |\n", - "| iterations | 3 |\n", - "| time_elapsed | 86 |\n", - "| total_timesteps | 6144 |\n", - "| train/ | |\n", - "| approx_kl | 0.038683757 |\n", - "| clip_fraction | 0.288 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.000747 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 11.5 |\n", - "| n_updates | 20 |\n", - "| policy_gradient_loss | -0.0211 |\n", - "| reward | 0.24697599 |\n", - "| std | 1 |\n", - "| value_loss | 25.9 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 71 |\n", - "| iterations | 4 |\n", - "| time_elapsed | 114 |\n", - "| total_timesteps | 8192 |\n", - "| train/ | |\n", - "| approx_kl | 0.016881496 |\n", - "| clip_fraction | 0.193 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.0123 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 13 |\n", - "| n_updates | 30 |\n", - "| policy_gradient_loss | -0.0225 |\n", - "| reward | 3.372088 |\n", - "| std | 1.01 |\n", - "| value_loss | 39 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 70 |\n", - "| iterations | 5 |\n", - "| time_elapsed | 145 |\n", - "| total_timesteps | 10240 |\n", - "| train/ | |\n", - "| approx_kl | 0.021627448 |\n", - "| clip_fraction | 0.232 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | -0.056 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 5.26 |\n", - "| n_updates | 40 |\n", - "| policy_gradient_loss | -0.0305 |\n", - "| reward | 0.116851896 |\n", - "| std | 1.01 |\n", - "| value_loss | 10.4 |\n", - "-----------------------------------------\n", - "======PPO Validation from: 2021-10-04 to 2022-01-03\n", - "PPO Sharpe Ratio: 0.22362176881826468\n", - "======DDPG Training========\n", - "{'buffer_size': 10000, 'learning_rate': 0.0005, 'batch_size': 64}\n", - "Using cpu device\n", - "Logging to tensorboard_log/ddpg/ddpg_126_2\n", - "day: 2957, episode: 10\n", - "begin_total_asset: 1000000.00\n", - "end_total_asset: 4354807.99\n", - "total_reward: 3354807.99\n", - "total_cost: 1579.60\n", - "total_trades: 32659\n", - "Sharpe: 0.761\n", - "=================================\n", - "----------------------------------\n", - "| time/ | |\n", - "| episodes | 4 |\n", - "| fps | 28 |\n", - "| time_elapsed | 412 |\n", - "| total_timesteps | 11832 |\n", - "| train/ | |\n", - "| actor_loss | 19.9 |\n", - "| critic_loss | 1.8e+03 |\n", - "| learning_rate | 0.0005 |\n", - "| n_updates | 8874 |\n", - "| reward | 6.1323853 |\n", - "----------------------------------\n", - "======DDPG Validation from: 2021-10-04 to 2022-01-03\n", - "======Best Model Retraining from: 2010-01-01 to 2022-01-03\n", - "======Trading from: 2022-01-03 to 2022-04-04\n", - "============================================\n", - "turbulence_threshold: 201.7187555549738\n", - "======Model training from: 2010-01-01 to 2022-01-03\n", - "======A2C Training========\n", - "{'n_steps': 5, 'ent_coef': 0.005, 'learning_rate': 0.0007}\n", - "Using cpu device\n", - "Logging to tensorboard_log/a2c/a2c_189_2\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 52 |\n", - "| iterations | 100 |\n", - "| time_elapsed | 9 |\n", - "| total_timesteps | 500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.1 |\n", - "| explained_variance | -1.43 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 99 |\n", - "| policy_loss | -43.6 |\n", - "| reward | -0.2118732 |\n", - "| std | 1 |\n", - "| value_loss | 2.23 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 57 |\n", - "| iterations | 200 |\n", - "| time_elapsed | 17 |\n", - "| total_timesteps | 1000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0.0546 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 199 |\n", - "| policy_loss | -73.9 |\n", - "| reward | 1.2174044 |\n", - "| std | 1 |\n", - "| value_loss | 8.88 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 60 |\n", - "| iterations | 300 |\n", - "| time_elapsed | 24 |\n", - "| total_timesteps | 1500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.0778 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 299 |\n", - "| policy_loss | -42.2 |\n", - "| reward | -3.4313393 |\n", - "| std | 1 |\n", - "| value_loss | 5.7 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 64 |\n", - "| iterations | 400 |\n", - "| time_elapsed | 31 |\n", - "| total_timesteps | 2000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 399 |\n", - "| policy_loss | -4.48 |\n", - "| reward | 1.7602888 |\n", - "| std | 1.01 |\n", - "| value_loss | 6.45 |\n", - "-------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 63 |\n", - "| iterations | 500 |\n", - "| time_elapsed | 39 |\n", - "| total_timesteps | 2500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0.266 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 499 |\n", - "| policy_loss | -222 |\n", - "| reward | -2.694985 |\n", - "| std | 1.01 |\n", - "| value_loss | 28.9 |\n", - "-------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 600 |\n", - "| time_elapsed | 45 |\n", - "| total_timesteps | 3000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0.000681 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 599 |\n", - "| policy_loss | -53.9 |\n", - "| reward | 15.781989 |\n", - "| std | 1.01 |\n", - "| value_loss | 12.9 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 64 |\n", - "| iterations | 700 |\n", - "| time_elapsed | 54 |\n", - "| total_timesteps | 3500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.452 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 699 |\n", - "| policy_loss | -102 |\n", - "| reward | 0.12392411 |\n", - "| std | 1.01 |\n", - "| value_loss | 7.42 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 800 |\n", - "| time_elapsed | 60 |\n", - "| total_timesteps | 4000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.554 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 799 |\n", - "| policy_loss | 88.8 |\n", - "| reward | 0.65661675 |\n", - "| std | 1.01 |\n", - "| value_loss | 5.75 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 900 |\n", - "| time_elapsed | 68 |\n", - "| total_timesteps | 4500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | -0.0118 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 899 |\n", - "| policy_loss | -86.3 |\n", - "| reward | 0.37854615 |\n", - "| std | 1.01 |\n", - "| value_loss | 5.04 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 1000 |\n", - "| time_elapsed | 76 |\n", - "| total_timesteps | 5000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 999 |\n", - "| policy_loss | 146 |\n", - "| reward | 1.2392796 |\n", - "| std | 1.01 |\n", - "| value_loss | 12.9 |\n", - "-------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 64 |\n", - "| iterations | 1100 |\n", - "| time_elapsed | 85 |\n", - "| total_timesteps | 5500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1099 |\n", - "| policy_loss | 78.8 |\n", - "| reward | 1.468812 |\n", - "| std | 1.01 |\n", - "| value_loss | 9.99 |\n", - "------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 1200 |\n", - "| time_elapsed | 91 |\n", - "| total_timesteps | 6000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1199 |\n", - "| policy_loss | 265 |\n", - "| reward | 4.0976543 |\n", - "| std | 1.01 |\n", - "| value_loss | 55.4 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 1300 |\n", - "| time_elapsed | 98 |\n", - "| total_timesteps | 6500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1299 |\n", - "| policy_loss | -27.5 |\n", - "| reward | 0.33550623 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.21 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 1400 |\n", - "| time_elapsed | 105 |\n", - "| total_timesteps | 7000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 5.96e-08 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1399 |\n", - "| policy_loss | 43.8 |\n", - "| reward | 0.22739449 |\n", - "| std | 1.01 |\n", - "| value_loss | 3.49 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1500 |\n", - "| time_elapsed | 111 |\n", - "| total_timesteps | 7500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.000254 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1499 |\n", - "| policy_loss | 118 |\n", - "| reward | 0.8682677 |\n", - "| std | 1.01 |\n", - "| value_loss | 11.7 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 1600 |\n", - "| time_elapsed | 120 |\n", - "| total_timesteps | 8000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1599 |\n", - "| policy_loss | 149 |\n", - "| reward | -1.1531851 |\n", - "| std | 1.01 |\n", - "| value_loss | 15 |\n", - "--------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1700 |\n", - "| time_elapsed | 126 |\n", - "| total_timesteps | 8500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1699 |\n", - "| policy_loss | -471 |\n", - "| reward | 5.611761 |\n", - "| std | 1.01 |\n", - "| value_loss | 133 |\n", - "------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1800 |\n", - "| time_elapsed | 134 |\n", - "| total_timesteps | 9000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 5.96e-08 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1799 |\n", - "| policy_loss | 468 |\n", - "| reward | -4.3675895 |\n", - "| std | 1.01 |\n", - "| value_loss | 166 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 1900 |\n", - "| time_elapsed | 142 |\n", - "| total_timesteps | 9500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1899 |\n", - "| policy_loss | 61.8 |\n", - "| reward | 0.7370295 |\n", - "| std | 1.01 |\n", - "| value_loss | 4.11 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 2000 |\n", - "| time_elapsed | 151 |\n", - "| total_timesteps | 10000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1999 |\n", - "| policy_loss | 13.2 |\n", - "| reward | -0.6354028 |\n", - "| std | 1.01 |\n", - "| value_loss | 0.207 |\n", - "--------------------------------------\n", - "======A2C Validation from: 2022-01-03 to 2022-04-04\n", - "A2C Sharpe Ratio: -0.14692977408785243\n", - "======PPO Training========\n", - "{'ent_coef': 0.01, 'n_steps': 2048, 'learning_rate': 0.00025, 'batch_size': 128}\n", - "Using cpu device\n", - "Logging to tensorboard_log/ppo/ppo_189_2\n", - "-----------------------------------\n", - "| time/ | |\n", - "| fps | 81 |\n", - "| iterations | 1 |\n", - "| time_elapsed | 25 |\n", - "| total_timesteps | 2048 |\n", - "| train/ | |\n", - "| reward | 0.74725425 |\n", - "-----------------------------------\n", - "day: 3020, episode: 5\n", - "begin_total_asset: 1000000.00\n", - "end_total_asset: 3925200.88\n", - "total_reward: 2925200.88\n", - "total_cost: 430221.22\n", - "total_trades: 84336\n", - "Sharpe: 0.810\n", - "=================================\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 76 |\n", - "| iterations | 2 |\n", - "| time_elapsed | 53 |\n", - "| total_timesteps | 4096 |\n", - "| train/ | |\n", - "| approx_kl | 0.013422785 |\n", - "| clip_fraction | 0.208 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0.0149 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 3.49 |\n", - "| n_updates | 10 |\n", - "| policy_gradient_loss | -0.0223 |\n", - "| reward | -1.5507116 |\n", - "| std | 1 |\n", - "| value_loss | 8.79 |\n", - "-----------------------------------------\n", - "----------------------------------------\n", - "| time/ | |\n", - "| fps | 72 |\n", - "| iterations | 3 |\n", - "| time_elapsed | 84 |\n", - "| total_timesteps | 6144 |\n", - "| train/ | |\n", - "| approx_kl | 0.01622951 |\n", - "| clip_fraction | 0.16 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0.00521 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 37.9 |\n", - "| n_updates | 20 |\n", - "| policy_gradient_loss | -0.0167 |\n", - "| reward | -0.5528202 |\n", - "| std | 1 |\n", - "| value_loss | 38.9 |\n", - "----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 72 |\n", - "| iterations | 4 |\n", - "| time_elapsed | 112 |\n", - "| total_timesteps | 8192 |\n", - "| train/ | |\n", - "| approx_kl | 0.012930675 |\n", - "| clip_fraction | 0.141 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0.0179 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 20.8 |\n", - "| n_updates | 30 |\n", - "| policy_gradient_loss | -0.0192 |\n", - "| reward | -3.1334524 |\n", - "| std | 1 |\n", - "| value_loss | 54.1 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 72 |\n", - "| iterations | 5 |\n", - "| time_elapsed | 142 |\n", - "| total_timesteps | 10240 |\n", - "| train/ | |\n", - "| approx_kl | 0.021723783 |\n", - "| clip_fraction | 0.203 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.0591 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 4.79 |\n", - "| n_updates | 40 |\n", - "| policy_gradient_loss | -0.0265 |\n", - "| reward | 0.13939004 |\n", - "| std | 1 |\n", - "| value_loss | 10.7 |\n", - "-----------------------------------------\n", - "======PPO Validation from: 2022-01-03 to 2022-04-04\n", - "PPO Sharpe Ratio: -0.2534042983305311\n", - "======DDPG Training========\n", - "{'buffer_size': 10000, 'learning_rate': 0.0005, 'batch_size': 64}\n", - "Using cpu device\n", - "Logging to tensorboard_log/ddpg/ddpg_189_2\n", - "day: 3020, episode: 10\n", - "begin_total_asset: 1000000.00\n", - "end_total_asset: 3397006.36\n", - "total_reward: 2397006.36\n", - "total_cost: 1206.97\n", - "total_trades: 45405\n", - "Sharpe: 0.650\n", - "=================================\n", - "-----------------------------------\n", - "| time/ | |\n", - "| episodes | 4 |\n", - "| fps | 29 |\n", - "| time_elapsed | 406 |\n", - "| total_timesteps | 12084 |\n", - "| train/ | |\n", - "| actor_loss | 19.2 |\n", - "| critic_loss | 533 |\n", - "| learning_rate | 0.0005 |\n", - "| n_updates | 9063 |\n", - "| reward | 0.69024736 |\n", - "-----------------------------------\n", - "======DDPG Validation from: 2022-01-03 to 2022-04-04\n", - "======Best Model Retraining from: 2010-01-01 to 2022-04-04\n", - "======Trading from: 2022-04-04 to 2022-07-06\n", - "============================================\n", - "turbulence_threshold: 201.7187555549738\n", - "======Model training from: 2010-01-01 to 2022-04-04\n", - "======A2C Training========\n", - "{'n_steps': 5, 'ent_coef': 0.005, 'learning_rate': 0.0007}\n", - "Using cpu device\n", - "Logging to tensorboard_log/a2c/a2c_252_2\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 61 |\n", - "| iterations | 100 |\n", - "| time_elapsed | 8 |\n", - "| total_timesteps | 500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0.147 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 99 |\n", - "| policy_loss | -28.4 |\n", - "| reward | 0.039200645 |\n", - "| std | 1 |\n", - "| value_loss | 0.88 |\n", - "---------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 69 |\n", - "| iterations | 200 |\n", - "| time_elapsed | 14 |\n", - "| total_timesteps | 1000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.711 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 199 |\n", - "| policy_loss | -16.3 |\n", - "| reward | 0.658065 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.09 |\n", - "------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 64 |\n", - "| iterations | 300 |\n", - "| time_elapsed | 23 |\n", - "| total_timesteps | 1500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 299 |\n", - "| policy_loss | -44.5 |\n", - "| reward | -3.0449631 |\n", - "| std | 1 |\n", - "| value_loss | 4.59 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 64 |\n", - "| iterations | 400 |\n", - "| time_elapsed | 31 |\n", - "| total_timesteps | 2000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.0593 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 399 |\n", - "| policy_loss | 37.9 |\n", - "| reward | 0.97243613 |\n", - "| std | 1.01 |\n", - "| value_loss | 2.41 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 62 |\n", - "| iterations | 500 |\n", - "| time_elapsed | 40 |\n", - "| total_timesteps | 2500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 499 |\n", - "| policy_loss | 5.83 |\n", - "| reward | -1.3074468 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.34 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 64 |\n", - "| iterations | 600 |\n", - "| time_elapsed | 46 |\n", - "| total_timesteps | 3000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 599 |\n", - "| policy_loss | 167 |\n", - "| reward | -1.185758 |\n", - "| std | 1.01 |\n", - "| value_loss | 21.5 |\n", - "-------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 63 |\n", - "| iterations | 700 |\n", - "| time_elapsed | 54 |\n", - "| total_timesteps | 3500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0.0197 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 699 |\n", - "| policy_loss | -85.5 |\n", - "| reward | 1.0330775 |\n", - "| std | 1.01 |\n", - "| value_loss | 4.86 |\n", - "-------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 800 |\n", - "| time_elapsed | 61 |\n", - "| total_timesteps | 4000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 799 |\n", - "| policy_loss | -133 |\n", - "| reward | 1.8058649 |\n", - "| std | 1.01 |\n", - "| value_loss | 10.1 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 900 |\n", - "| time_elapsed | 68 |\n", - "| total_timesteps | 4500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | -0.0436 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 899 |\n", - "| policy_loss | -121 |\n", - "| reward | -1.1275363 |\n", - "| std | 1.01 |\n", - "| value_loss | 12.5 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 1000 |\n", - "| time_elapsed | 75 |\n", - "| total_timesteps | 5000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | 0.0219 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 999 |\n", - "| policy_loss | -37.7 |\n", - "| reward | 1.0679476 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.13 |\n", - "-------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 1100 |\n", - "| time_elapsed | 82 |\n", - "| total_timesteps | 5500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1099 |\n", - "| policy_loss | -218 |\n", - "| reward | 0.2276968 |\n", - "| std | 1.01 |\n", - "| value_loss | 33.1 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 1200 |\n", - "| time_elapsed | 90 |\n", - "| total_timesteps | 6000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0.00369 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1199 |\n", - "| policy_loss | -4.55 |\n", - "| reward | -2.5717678 |\n", - "| std | 1.01 |\n", - "| value_loss | 2.14 |\n", - "--------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 1300 |\n", - "| time_elapsed | 99 |\n", - "| total_timesteps | 6500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | -0.615 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1299 |\n", - "| policy_loss | 56.1 |\n", - "| reward | 1.006533 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.76 |\n", - "------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 64 |\n", - "| iterations | 1400 |\n", - "| time_elapsed | 108 |\n", - "| total_timesteps | 7000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | -0.000236 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1399 |\n", - "| policy_loss | -61.6 |\n", - "| reward | -0.1536156 |\n", - "| std | 1.01 |\n", - "| value_loss | 3.55 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 1500 |\n", - "| time_elapsed | 114 |\n", - "| total_timesteps | 7500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0.27 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1499 |\n", - "| policy_loss | 44.7 |\n", - "| reward | -1.1611226 |\n", - "| std | 1.01 |\n", - "| value_loss | 1.42 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 64 |\n", - "| iterations | 1600 |\n", - "| time_elapsed | 123 |\n", - "| total_timesteps | 8000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1599 |\n", - "| policy_loss | -80.8 |\n", - "| reward | -2.1431527 |\n", - "| std | 1.01 |\n", - "| value_loss | 5.55 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 1700 |\n", - "| time_elapsed | 129 |\n", - "| total_timesteps | 8500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0.0298 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1699 |\n", - "| policy_loss | 294 |\n", - "| reward | 0.79167354 |\n", - "| std | 1.01 |\n", - "| value_loss | 77.3 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 1800 |\n", - "| time_elapsed | 137 |\n", - "| total_timesteps | 9000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1799 |\n", - "| policy_loss | 272 |\n", - "| reward | -1.5589284 |\n", - "| std | 1.01 |\n", - "| value_loss | 65.4 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 1900 |\n", - "| time_elapsed | 144 |\n", - "| total_timesteps | 9500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.19 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1899 |\n", - "| policy_loss | -22 |\n", - "| reward | 0.05272026 |\n", - "| std | 1.01 |\n", - "| value_loss | 0.295 |\n", - "--------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 2000 |\n", - "| time_elapsed | 151 |\n", - "| total_timesteps | 10000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | -0.0144 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1999 |\n", - "| policy_loss | -74.1 |\n", - "| reward | -1.1719905 |\n", - "| std | 1.01 |\n", - "| value_loss | 4.47 |\n", - "--------------------------------------\n", - "======A2C Validation from: 2022-04-04 to 2022-07-06\n", - "A2C Sharpe Ratio: -0.30272110471506264\n", - "======PPO Training========\n", - "{'ent_coef': 0.01, 'n_steps': 2048, 'learning_rate': 0.00025, 'batch_size': 128}\n", - "Using cpu device\n", - "Logging to tensorboard_log/ppo/ppo_252_2\n", - "----------------------------------\n", - "| time/ | |\n", - "| fps | 69 |\n", - "| iterations | 1 |\n", - "| time_elapsed | 29 |\n", - "| total_timesteps | 2048 |\n", - "| train/ | |\n", - "| reward | 1.2733731 |\n", - "----------------------------------\n", - "day: 3083, episode: 5\n", - "begin_total_asset: 1000000.00\n", - "end_total_asset: 3852282.74\n", - "total_reward: 2852282.74\n", - "total_cost: 450259.06\n", - "total_trades: 85874\n", - "Sharpe: 0.747\n", - "=================================\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 69 |\n", - "| iterations | 2 |\n", - "| time_elapsed | 58 |\n", - "| total_timesteps | 4096 |\n", - "| train/ | |\n", - "| approx_kl | 0.010443365 |\n", - "| clip_fraction | 0.146 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0.00319 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 3.82 |\n", - "| n_updates | 10 |\n", - "| policy_gradient_loss | -0.022 |\n", - "| reward | -0.17186709 |\n", - "| std | 1 |\n", - "| value_loss | 10.9 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 3 |\n", - "| time_elapsed | 90 |\n", - "| total_timesteps | 6144 |\n", - "| train/ | |\n", - "| approx_kl | 0.017388577 |\n", - "| clip_fraction | 0.214 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.000876 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 23 |\n", - "| n_updates | 20 |\n", - "| policy_gradient_loss | -0.0163 |\n", - "| reward | -7.161404 |\n", - "| std | 1 |\n", - "| value_loss | 53.5 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 69 |\n", - "| iterations | 4 |\n", - "| time_elapsed | 117 |\n", - "| total_timesteps | 8192 |\n", - "| train/ | |\n", - "| approx_kl | 0.015766393 |\n", - "| clip_fraction | 0.219 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0.00125 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 24.6 |\n", - "| n_updates | 30 |\n", - "| policy_gradient_loss | -0.0168 |\n", - "| reward | 0.39508805 |\n", - "| std | 1.01 |\n", - "| value_loss | 70.1 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 69 |\n", - "| iterations | 5 |\n", - "| time_elapsed | 146 |\n", - "| total_timesteps | 10240 |\n", - "| train/ | |\n", - "| approx_kl | 0.016418885 |\n", - "| clip_fraction | 0.211 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.134 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 4.06 |\n", - "| n_updates | 40 |\n", - "| policy_gradient_loss | -0.0252 |\n", - "| reward | -1.1459538 |\n", - "| std | 1.01 |\n", - "| value_loss | 8.91 |\n", - "-----------------------------------------\n", - "======PPO Validation from: 2022-04-04 to 2022-07-06\n", - "PPO Sharpe Ratio: -0.23230320730861076\n", - "======DDPG Training========\n", - "{'buffer_size': 10000, 'learning_rate': 0.0005, 'batch_size': 64}\n", - "Using cpu device\n", - "Logging to tensorboard_log/ddpg/ddpg_252_2\n", - "day: 3083, episode: 10\n", - "begin_total_asset: 1000000.00\n", - "end_total_asset: 4156114.54\n", - "total_reward: 3156114.54\n", - "total_cost: 999.00\n", - "total_trades: 46201\n", - "Sharpe: 0.765\n", - "=================================\n", - "---------------------------------\n", - "| time/ | |\n", - "| episodes | 4 |\n", - "| fps | 30 |\n", - "| time_elapsed | 406 |\n", - "| total_timesteps | 12336 |\n", - "| train/ | |\n", - "| actor_loss | 25.9 |\n", - "| critic_loss | 706 |\n", - "| learning_rate | 0.0005 |\n", - "| n_updates | 9252 |\n", - "| reward | 1.779895 |\n", - "---------------------------------\n", - "======DDPG Validation from: 2022-04-04 to 2022-07-06\n", - "======Best Model Retraining from: 2010-01-01 to 2022-07-06\n", - "======Trading from: 2022-07-06 to 2022-10-04\n", - "============================================\n", - "turbulence_threshold: 201.7187555549738\n", - "======Model training from: 2010-01-01 to 2022-07-06\n", - "======A2C Training========\n", - "{'n_steps': 5, 'ent_coef': 0.005, 'learning_rate': 0.0007}\n", - "Using cpu device\n", - "Logging to tensorboard_log/a2c/a2c_315_2\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 58 |\n", - "| iterations | 100 |\n", - "| time_elapsed | 8 |\n", - "| total_timesteps | 500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.252 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 99 |\n", - "| policy_loss | 13.4 |\n", - "| reward | -0.06586392 |\n", - "| std | 1 |\n", - "| value_loss | 0.423 |\n", - "---------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 200 |\n", - "| time_elapsed | 14 |\n", - "| total_timesteps | 1000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.191 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 199 |\n", - "| policy_loss | -83.1 |\n", - "| reward | 0.9938539 |\n", - "| std | 1 |\n", - "| value_loss | 7.42 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 63 |\n", - "| iterations | 300 |\n", - "| time_elapsed | 23 |\n", - "| total_timesteps | 1500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 299 |\n", - "| policy_loss | -29.5 |\n", - "| reward | -2.4282768 |\n", - "| std | 1 |\n", - "| value_loss | 3.32 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 400 |\n", - "| time_elapsed | 29 |\n", - "| total_timesteps | 2000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.0464 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 399 |\n", - "| policy_loss | 19.1 |\n", - "| reward | 1.5293065 |\n", - "| std | 1 |\n", - "| value_loss | 1.94 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 65 |\n", - "| iterations | 500 |\n", - "| time_elapsed | 38 |\n", - "| total_timesteps | 2500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.235 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 499 |\n", - "| policy_loss | -203 |\n", - "| reward | -2.0757396 |\n", - "| std | 1 |\n", - "| value_loss | 22.3 |\n", - "--------------------------------------\n", - "-------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 600 |\n", - "| time_elapsed | 44 |\n", - "| total_timesteps | 3000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 599 |\n", - "| policy_loss | -95.1 |\n", - "| reward | 10.333564 |\n", - "| std | 1 |\n", - "| value_loss | 7.44 |\n", - "-------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 700 |\n", - "| time_elapsed | 52 |\n", - "| total_timesteps | 3500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.0484 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 699 |\n", - "| policy_loss | -26.3 |\n", - "| reward | 0.36432812 |\n", - "| std | 1 |\n", - "| value_loss | 0.536 |\n", - "--------------------------------------\n", - "----------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 800 |\n", - "| time_elapsed | 59 |\n", - "| total_timesteps | 4000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 1.46e-05 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 799 |\n", - "| policy_loss | 11 |\n", - "| reward | -0.093770415 |\n", - "| std | 1 |\n", - "| value_loss | 1.75 |\n", - "----------------------------------------\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 900 |\n", - "| time_elapsed | 66 |\n", - "| total_timesteps | 4500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.056 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 899 |\n", - "| policy_loss | -1.19 |\n", - "| reward | -0.33609682 |\n", - "| std | 1 |\n", - "| value_loss | 1.87 |\n", - "---------------------------------------\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1000 |\n", - "| time_elapsed | 74 |\n", - "| total_timesteps | 5000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 999 |\n", - "| policy_loss | -41.8 |\n", - "| reward | -0.32722506 |\n", - "| std | 1.01 |\n", - "| value_loss | 2.4 |\n", - "---------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 1100 |\n", - "| time_elapsed | 80 |\n", - "| total_timesteps | 5500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1099 |\n", - "| policy_loss | -109 |\n", - "| reward | 2.058874 |\n", - "| std | 1.01 |\n", - "| value_loss | 19.8 |\n", - "------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1200 |\n", - "| time_elapsed | 89 |\n", - "| total_timesteps | 6000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -1.19e-07 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1199 |\n", - "| policy_loss | -42.6 |\n", - "| reward | -1.5882981 |\n", - "| std | 1.01 |\n", - "| value_loss | 13.8 |\n", - "--------------------------------------\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 68 |\n", - "| iterations | 1300 |\n", - "| time_elapsed | 95 |\n", - "| total_timesteps | 6500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | -0.137 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1299 |\n", - "| policy_loss | 17.1 |\n", - "| reward | -0.36645696 |\n", - "| std | 1.01 |\n", - "| value_loss | 0.653 |\n", - "---------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 66 |\n", - "| iterations | 1400 |\n", - "| time_elapsed | 104 |\n", - "| total_timesteps | 7000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1399 |\n", - "| policy_loss | -49.2 |\n", - "| reward | -1.3474209 |\n", - "| std | 1.01 |\n", - "| value_loss | 2.52 |\n", - "--------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1500 |\n", - "| time_elapsed | 110 |\n", - "| total_timesteps | 7500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1499 |\n", - "| policy_loss | -162 |\n", - "| reward | 4.36321 |\n", - "| std | 1.01 |\n", - "| value_loss | 21.9 |\n", - "------------------------------------\n", - "---------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1600 |\n", - "| time_elapsed | 119 |\n", - "| total_timesteps | 8000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.4 |\n", - "| explained_variance | -0.849 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1599 |\n", - "| policy_loss | 30.8 |\n", - "| reward | -0.37719268 |\n", - "| std | 1.01 |\n", - "| value_loss | 2.09 |\n", - "---------------------------------------\n", - "------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1700 |\n", - "| time_elapsed | 126 |\n", - "| total_timesteps | 8500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | -0.341 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1699 |\n", - "| policy_loss | 56.3 |\n", - "| reward | 2.325285 |\n", - "| std | 1.01 |\n", - "| value_loss | 2.05 |\n", - "------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1800 |\n", - "| time_elapsed | 133 |\n", - "| total_timesteps | 9000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | 5.96e-08 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1799 |\n", - "| policy_loss | -81 |\n", - "| reward | -4.1168823 |\n", - "| std | 1.01 |\n", - "| value_loss | 27.3 |\n", - "--------------------------------------\n", - "----------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 1900 |\n", - "| time_elapsed | 141 |\n", - "| total_timesteps | 9500 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | -0.848 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1899 |\n", - "| policy_loss | 58.9 |\n", - "| reward | -0.021594923 |\n", - "| std | 1.01 |\n", - "| value_loss | 2.52 |\n", - "----------------------------------------\n", - "--------------------------------------\n", - "| time/ | |\n", - "| fps | 67 |\n", - "| iterations | 2000 |\n", - "| time_elapsed | 147 |\n", - "| total_timesteps | 10000 |\n", - "| train/ | |\n", - "| entropy_loss | -41.5 |\n", - "| explained_variance | 0 |\n", - "| learning_rate | 0.0007 |\n", - "| n_updates | 1999 |\n", - "| policy_loss | 164 |\n", - "| reward | 0.23247483 |\n", - "| std | 1.01 |\n", - "| value_loss | 19.9 |\n", - "--------------------------------------\n", - "======A2C Validation from: 2022-07-06 to 2022-10-04\n", - "A2C Sharpe Ratio: -0.1503383996215036\n", - "======PPO Training========\n", - "{'ent_coef': 0.01, 'n_steps': 2048, 'learning_rate': 0.00025, 'batch_size': 128}\n", - "Using cpu device\n", - "Logging to tensorboard_log/ppo/ppo_315_2\n", - "----------------------------------\n", - "| time/ | |\n", - "| fps | 72 |\n", - "| iterations | 1 |\n", - "| time_elapsed | 28 |\n", - "| total_timesteps | 2048 |\n", - "| train/ | |\n", - "| reward | 1.5695434 |\n", - "----------------------------------\n", - "day: 3146, episode: 5\n", - "begin_total_asset: 1000000.00\n", - "end_total_asset: 4182243.76\n", - "total_reward: 3182243.76\n", - "total_cost: 466157.32\n", - "total_trades: 87748\n", - "Sharpe: 0.765\n", - "=================================\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 71 |\n", - "| iterations | 2 |\n", - "| time_elapsed | 57 |\n", - "| total_timesteps | 4096 |\n", - "| train/ | |\n", - "| approx_kl | 0.017112536 |\n", - "| clip_fraction | 0.185 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.014 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 4.08 |\n", - "| n_updates | 10 |\n", - "| policy_gradient_loss | -0.0225 |\n", - "| reward | 3.3138163 |\n", - "| std | 1 |\n", - "| value_loss | 13.1 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 70 |\n", - "| iterations | 3 |\n", - "| time_elapsed | 87 |\n", - "| total_timesteps | 6144 |\n", - "| train/ | |\n", - "| approx_kl | 0.015279966 |\n", - "| clip_fraction | 0.137 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.00321 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 23.4 |\n", - "| n_updates | 20 |\n", - "| policy_gradient_loss | -0.0181 |\n", - "| reward | 0.16200532 |\n", - "| std | 1 |\n", - "| value_loss | 61.4 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 71 |\n", - "| iterations | 4 |\n", - "| time_elapsed | 115 |\n", - "| total_timesteps | 8192 |\n", - "| train/ | |\n", - "| approx_kl | 0.017391961 |\n", - "| clip_fraction | 0.171 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.2 |\n", - "| explained_variance | -0.0126 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 13.4 |\n", - "| n_updates | 30 |\n", - "| policy_gradient_loss | -0.0216 |\n", - "| reward | 0.8665643 |\n", - "| std | 1 |\n", - "| value_loss | 27.9 |\n", - "-----------------------------------------\n", - "-----------------------------------------\n", - "| time/ | |\n", - "| fps | 71 |\n", - "| iterations | 5 |\n", - "| time_elapsed | 143 |\n", - "| total_timesteps | 10240 |\n", - "| train/ | |\n", - "| approx_kl | 0.024849283 |\n", - "| clip_fraction | 0.246 |\n", - "| clip_range | 0.2 |\n", - "| entropy_loss | -41.3 |\n", - "| explained_variance | 0.00239 |\n", - "| learning_rate | 0.00025 |\n", - "| loss | 4.06 |\n", - "| n_updates | 40 |\n", - "| policy_gradient_loss | -0.0285 |\n", - "| reward | 0.7721387 |\n", - "| std | 1.01 |\n", - "| value_loss | 12.5 |\n", - "-----------------------------------------\n", - "======PPO Validation from: 2022-07-06 to 2022-10-04\n", - "PPO Sharpe Ratio: -0.17703202932495948\n", - "======DDPG Training========\n", - "{'buffer_size': 10000, 'learning_rate': 0.0005, 'batch_size': 64}\n", - "Using cpu device\n", - "Logging to tensorboard_log/ddpg/ddpg_315_2\n", - "day: 3146, episode: 10\n", - "begin_total_asset: 1000000.00\n", - "end_total_asset: 3375712.96\n", - "total_reward: 2375712.96\n", - "total_cost: 1382.57\n", - "total_trades: 43739\n", - "Sharpe: 0.633\n", - "=================================\n", - "-----------------------------------\n", - "| time/ | |\n", - "| episodes | 4 |\n", - "| fps | 30 |\n", - "| time_elapsed | 415 |\n", - "| total_timesteps | 12588 |\n", - "| train/ | |\n", - "| actor_loss | -58.1 |\n", - "| critic_loss | 947 |\n", - "| learning_rate | 0.0005 |\n", - "| n_updates | 9441 |\n", - "| reward | -2.3450632 |\n", - "-----------------------------------\n", - "======DDPG Validation from: 2022-07-06 to 2022-10-04\n", - "======Best Model Retraining from: 2010-01-01 to 2022-10-04\n", - "======Trading from: 2022-10-04 to 2023-01-04\n", - "Ensemble Strategy took: 52.93895851373672 minutes\n" - ] - } - ], - "source": [ - "df_summary = ensemble_agent.run_ensemble_strategy(A2C_model_kwargs,\n", - " PPO_model_kwargs,\n", - " DDPG_model_kwargs,\n", - " timesteps_dict)" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 175 + "cell_type": "code", + "execution_count": 19, + "metadata": { + "id": "kM5bH9uroCeg" + }, + "outputs": [], + "source": [ + " INDICATORS = ['macd',\n", + " 'rsi_30',\n", + " 'cci_30',\n", + " 'dx_30']" + ] }, - "id": "-0qd8acMtj1f", - "outputId": "9f0cbf89-5f4b-4691-9e43-daa093ebceae" - }, - "outputs": [ { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
IterVal StartVal EndModel UsedA2C SharpePPO SharpeDDPG Sharpe
01262021-10-042022-01-03DDPG0.1318750.2236220.327114
11892022-01-032022-04-04A2C-0.14693-0.253404-0.238802
22522022-04-042022-07-06DDPG-0.302721-0.232303-0.168003
33152022-07-062022-10-04DDPG-0.150338-0.177032-0.138149
\n", - "
\n", - " \n", - " \n", - " \n", - "\n", - " \n", - "
\n", - "
\n", - " " + "cell_type": "code", + "execution_count": 20, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "jgXfBcjxtj1a", + "outputId": "07518687-7a3a-43ee-d500-ac50095b512a" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Successfully added technical indicators\n", + "Successfully added turbulence index\n" + ] + } ], - "text/plain": [ - " Iter Val Start Val End Model Used A2C Sharpe PPO Sharpe DDPG Sharpe\n", - "0 126 2021-10-04 2022-01-03 DDPG 0.131875 0.223622 0.327114\n", - "1 189 2022-01-03 2022-04-04 A2C -0.14693 -0.253404 -0.238802\n", - "2 252 2022-04-04 2022-07-06 DDPG -0.302721 -0.232303 -0.168003\n", - "3 315 2022-07-06 2022-10-04 DDPG -0.150338 -0.177032 -0.138149" + "source": [ + "from finrl.meta.preprocessor.preprocessors import FeatureEngineer\n", + "fe = FeatureEngineer(use_technical_indicator=True,\n", + " tech_indicator_list = INDICATORS,\n", + " use_turbulence=True,\n", + " user_defined_feature = False)\n", + "\n", + "processed = fe.preprocess_data(df)\n", + "processed = processed.copy()\n", + "processed = processed.fillna(0)\n", + "processed = processed.replace(np.inf,0)" ] - }, - "execution_count": 51, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_summary" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "W6vvNSC6h1jZ" - }, - "source": [ - "\n", - "# Part 7: Backtest Our Strategy\n", - "Backtesting plays a key role in evaluating the performance of a trading strategy. Automated backtesting tool is preferred because it reduces the human error. We usually use the Quantopian pyfolio package to backtest our trading strategies. It is easy to use and consists of various individual plots that provide a comprehensive image of the performance of a trading strategy." - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": { - "id": "X4JKB--8tj1g" - }, - "outputs": [], - "source": [ - "unique_trade_date = processed[(processed.date > TEST_START_DATE)&(processed.date <= TEST_END_DATE)].date.unique()" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" }, - "id": "q9mKF7GGtj1g", - "outputId": "99c5e5f8-2e3f-49c3-e5a6-4e66ed92e40a", - "scrolled": true - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Sharpe Ratio: -0.11910800246459344\n" - ] - } - ], - "source": [ - "df_trade_date = pd.DataFrame({'datadate':unique_trade_date})\n", - "\n", - "df_account_value=pd.DataFrame()\n", - "for i in range(rebalance_window+validation_window, len(unique_trade_date)+1,rebalance_window):\n", - " temp = pd.read_csv('results/account_value_trade_{}_{}.csv'.format('ensemble',i))\n", - " df_account_value = pd.concat([df_account_value,temp],ignore_index=True)\n", - "sharpe=(252**0.5)*df_account_value.account_value.pct_change(1).mean()/df_account_value.account_value.pct_change(1).std()\n", - "print('Sharpe Ratio: ',sharpe)\n", - "df_account_value=df_account_value.join(df_trade_date[validation_window:].reset_index(drop=True))" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 206 + "cell_type": "code", + "source": [ + "len(state), len(data)" + ], + "metadata": { + "id": "tiFA3pRWPQMO", + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "94bbe31e-af8d-4489-d23f-6803a990c3e8" + }, + "execution_count": 13, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "(7, 13)" + ] + }, + "metadata": {}, + "execution_count": 13 + } + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "-QsYaY0Dh1iw" + }, + "source": [ + "\n", + "# Part 5. Design Environment\n", + "Considering the stochastic and interactive nature of the automated stock trading tasks, a financial task is modeled as a **Markov Decision Process (MDP)** problem. The training process involves observing stock price change, taking an action and reward's calculation to have the agent adjusting its strategy accordingly. By interacting with the environment, the trading agent will derive a trading strategy with the maximized rewards as time proceeds.\n", + "\n", + "Our trading environments, based on OpenAI Gym framework, simulate live stock markets with real market data according to the principle of time-driven simulation.\n", + "\n", + "The action space describes the allowed actions that the agent interacts with the environment. Normally, action a includes three actions: {-1, 0, 1}, where -1, 0, 1 represent selling, holding, and buying one share. Also, an action can be carried upon multiple shares. We use an action space {-k,…,-1, 0, 1, …, k}, where k denotes the number of shares to buy and -k denotes the number of shares to sell. For example, \"Buy 10 shares of AAPL\" or \"Sell 10 shares of AAPL\" are 10 or -10, respectively. The continuous action space needs to be normalized to [-1, 1], since the policy is defined on a Gaussian distribution, which needs to be normalized and symmetric." + ] }, - "id": "oyosyW7_tj1g", - "outputId": "0e54f2d5-6057-4a14-c94a-5f2af26ad171" - }, - "outputs": [ { - "data": { - "text/html": [ - "\n", - "
\n", - "
\n", - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
account_valuedatedaily_returndatadate
01000000.0000002022-01-03NaN2022-01-03
1999006.1778902022-01-04-0.0009942022-01-04
2992190.3751432022-01-05-0.0068232022-01-05
3986549.9187762022-01-06-0.0056852022-01-06
4984951.5226952022-01-07-0.0016202022-01-07
\n", - "
\n", - " \n", - " \n", - " \n", - "\n", - " \n", - "
\n", - "
\n", - " " + "cell_type": "code", + "execution_count": 21, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Q2zqII8rMIqn", + "outputId": "47edb3e0-2d83-4063-b2e8-c1d988e61da0" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Stock Dimension: 29, State Space: 175\n" + ] + } ], - "text/plain": [ - " account_value date daily_return datadate\n", - "0 1000000.000000 2022-01-03 NaN 2022-01-03\n", - "1 999006.177890 2022-01-04 -0.000994 2022-01-04\n", - "2 992190.375143 2022-01-05 -0.006823 2022-01-05\n", - "3 986549.918776 2022-01-06 -0.005685 2022-01-06\n", - "4 984951.522695 2022-01-07 -0.001620 2022-01-07" + "source": [ + "stock_dimension = len(processed.tic.unique())\n", + "state_space = 1 + 2*stock_dimension + len(INDICATORS)*stock_dimension\n", + "print(f\"Stock Dimension: {stock_dimension}, State Space: {state_space}\")\n" ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df_account_value.head()" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 293 }, - "id": "wLsRdw2Ctj1h", - "outputId": "0e2b0bc2-840c-47fd-87d4-01201d8e4e3d" - }, - "outputs": [ { - "data": { - "text/plain": [ - "" + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "AWyp84Ltto19" + }, + "outputs": [], + "source": [ + "env_kwargs = {\n", + " \"hmax\": 100,\n", + " \"initial_amount\": 1000000,\n", + " \"buy_cost_pct\": 0.001,\n", + " \"sell_cost_pct\": 0.001,\n", + " \"state_space\": state_space,\n", + " \"stock_dim\": stock_dimension,\n", + " \"tech_indicator_list\": INDICATORS,\n", + " \"action_space\": stock_dimension,\n", + " \"reward_scaling\": 1e-4,\n", + " \"print_verbosity\":5\n", + "\n", + "}\n", + "\n", + "# buy_cost_list = sell_cost_list = [0.001] * stock_dimension\n", + "# num_stock_shares = [0] * stock_dimension\n", + "# env_kwargs = {\n", + "# \"hmax\": 100,\n", + "# \"initial_amount\": 1000000,\n", + "# \"num_stock_shares\": num_stock_shares,\n", + "# \"buy_cost_pct\": buy_cost_list,\n", + "# \"sell_cost_pct\": sell_cost_list,\n", + "# \"state_space\": state_space,\n", + "# \"stock_dim\": stock_dimension,\n", + "# \"tech_indicator_list\": INDICATORS,\n", + "# \"action_space\": stock_dimension,\n", + "# \"reward_scaling\": 1e-4\n", + "# }" ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" }, { - "data": { - "image/png": "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", - "text/plain": [ - "
" + "cell_type": "markdown", + "metadata": { + "id": "HMNR5nHjh1iz" + }, + "source": [ + "\n", + "# Part 6: Implement DRL Algorithms\n", + "* The implementation of the DRL algorithms are based on **OpenAI Baselines** and **Stable Baselines**. Stable Baselines is a fork of OpenAI Baselines, with a major structural refactoring, and code cleanups.\n", + "* FinRL library includes fine-tuned standard DRL algorithms, such as DQN, DDPG,\n", + "Multi-Agent DDPG, PPO, SAC, A2C and TD3. We also allow users to\n", + "design their own DRL algorithms by adapting these DRL algorithms.\n", + "\n", + "* In this notebook, we are training and validating 3 agents (A2C, PPO, DDPG) using Rolling-window Ensemble Method ([reference code](https://github.com/AI4Finance-LLC/Deep-Reinforcement-Learning-for-Automated-Stock-Trading-Ensemble-Strategy-ICAIF-2020/blob/80415db8fa7b2179df6bd7e81ce4fe8dbf913806/model/models.py#L92))" ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "%matplotlib inline\n", - "df_account_value.account_value.plot()" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Lr2zX7ZxNyFQ" - }, - "source": [ - "\n", - "## 7.1 BackTestStats\n", - "pass in df_account_value, this information is stored in env class\n" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" }, - "id": "Nzkr9yv-AdV_", - "outputId": "ab0971b8-10b0-4fb1-a151-71a1de89cdf2", - "scrolled": true - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "==============Get Backtest Results===========\n", - "Annual return -0.039389\n", - "Cumulative returns -0.039389\n", - "Annual volatility 0.189054\n", - "Sharpe ratio -0.119108\n", - "Calmar ratio -0.226725\n", - "Stability 0.009971\n", - "Max drawdown -0.173731\n", - "Omega ratio 0.980324\n", - "Sortino ratio -0.165730\n", - "Skew NaN\n", - "Kurtosis NaN\n", - "Tail ratio 0.958268\n", - "Daily value at risk -0.023908\n", - "dtype: float64\n" - ] - } - ], - "source": [ - "print(\"==============Get Backtest Results===========\")\n", - "now = datetime.datetime.now().strftime('%Y%m%d-%Hh%M')\n", - "\n", - "perf_stats_all = backtest_stats(account_value=df_account_value)\n", - "perf_stats_all = pd.DataFrame(perf_stats_all)" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "v-gthCxMtj1d" + }, + "outputs": [], + "source": [ + "rebalance_window = 63 # rebalance_window is the number of days to retrain the model\n", + "validation_window = 63 # validation_window is the number of days to do validation and trading (e.g. if validation_window=63, then both validation and trading period will be 63 days)\n", + "\n", + "ensemble_agent = DRLEnsembleAgent(df=processed,\n", + " train_period=(TRAIN_START_DATE,TRAIN_END_DATE),\n", + " val_test_period=(TEST_START_DATE,TEST_END_DATE),\n", + " rebalance_window=rebalance_window,\n", + " validation_window=validation_window,\n", + " **env_kwargs)\n", + "# e_train_gym = StockTradingEnv(df = processed, **env_kwargs)\n", + "# agent = DRLAgent(e_train_gym)\n", + "# if_using_a2c = True\n", + "# model_a2c = agent.get_model(\"a2c\")\n", + "# # if if_using_a2c:\n", + "# # tmp_path = RESULTS_DIR + '/a2c'\n", + "# # new_logger_a2c = configure(tmp_path, [\"stdout\", \"csv\", \"tensorboard\"])\n", + "# # model_a2c.set_logger(new_logger_a2c)\n", + "# trained_a2c = agent.train_model(model=model_a2c,\n", + "# tb_log_name='a2c',\n", + "# total_timesteps=50000)" + ] }, - "id": "DiHhM1YkoCel", - "outputId": "c233f613-67a3-4882-8710-c1839247590e" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "==============Get Baseline Stats===========\n", - "\r[*********************100%***********************] 1 of 1 completed\n", - "Shape of DataFrame: (251, 8)\n", - "Annual return -0.094324\n", - "Cumulative returns -0.093968\n", - "Annual volatility 0.198502\n", - "Sharpe ratio -0.402058\n", - "Calmar ratio -0.429901\n", - "Stability 0.236972\n", - "Max drawdown -0.219408\n", - "Omega ratio 0.936015\n", - "Sortino ratio -0.559755\n", - "Skew NaN\n", - "Kurtosis NaN\n", - "Tail ratio 1.014390\n", - "Daily value at risk -0.025326\n", - "dtype: float64\n" - ] - } - ], - "source": [ - "#baseline stats\n", - "print(\"==============Get Baseline Stats===========\")\n", - "df_dji_ = get_baseline(\n", - " ticker=\"^DJI\", \n", - " start = df_account_value.loc[0,'date'],\n", - " end = df_account_value.loc[len(df_account_value)-1,'date'])\n", - "\n", - "stats = backtest_stats(df_dji_, value_col_name = 'close')" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" + "cell_type": "code", + "execution_count": 24, + "metadata": { + "id": "KsfEHa_Etj1d", + "scrolled": false + }, + "outputs": [], + "source": [ + "A2C_model_kwargs = {\n", + " 'n_steps': 5,\n", + " 'ent_coef': 0.005,\n", + " 'learning_rate': 0.0007\n", + " }\n", + "\n", + "PPO_model_kwargs = {\n", + " \"ent_coef\":0.01,\n", + " \"n_steps\": 2048,\n", + " \"learning_rate\": 0.00025,\n", + " \"batch_size\": 128\n", + " }\n", + "\n", + "DDPG_model_kwargs = {\n", + " #\"action_noise\":\"ornstein_uhlenbeck\",\n", + " \"buffer_size\": 10_000,\n", + " \"learning_rate\": 0.0005,\n", + " \"batch_size\": 64\n", + " }\n", + "\n", + "SAC_model_kwargs = {\n", + " \"batch_size\": 64,\n", + " \"buffer_size\": 100000,\n", + " \"learning_rate\": 0.0001,\n", + " \"learning_starts\": 100,\n", + " \"ent_coef\": \"auto_0.1\",\n", + "}\n", + "\n", + "TD3_model_kwargs = {\"batch_size\": 100, \"buffer_size\": 1000000, \"learning_rate\": 0.0001}\n", + "\n", + "\n", + "\n", + "\n", + "timesteps_dict = {'a2c' : 10_000,\n", + " 'ppo' : 10_000,\n", + " 'ddpg' : 10_000,\n", + " 'sac' : 10_000,\n", + " 'td3' : 10_000\n", + " }" + ] }, - "id": "RhJ9whD75WTs", - "outputId": "8ae25787-8400-4357-ecc0-af7538689cee" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "df_dji: date dji\n", - "0 2022-01-03 1.000000e+06\n", - "1 2022-01-04 1.005866e+06\n", - "2 2022-01-05 9.951360e+05\n", - "3 2022-01-06 9.904718e+05\n", - "4 2022-01-07 9.903404e+05\n", - ".. ... ...\n", - "247 2022-12-27 9.086102e+05\n", - "248 2022-12-28 8.986103e+05\n", - "249 2022-12-29 9.080428e+05\n", - "250 2022-12-30 9.060324e+05\n", - "251 2023-01-03 NaN\n", - "\n", - "[252 rows x 2 columns]\n", - "df_dji: dji\n", - "date \n", - "2022-01-03 1.000000e+06\n", - "2022-01-04 1.005866e+06\n", - "2022-01-05 9.951360e+05\n", - "2022-01-06 9.904718e+05\n", - "2022-01-07 9.903404e+05\n", - "... ...\n", - "2022-12-27 9.086102e+05\n", - "2022-12-28 8.986103e+05\n", - "2022-12-29 9.080428e+05\n", - "2022-12-30 9.060324e+05\n", - "2023-01-03 NaN\n", - "\n", - "[252 rows x 1 columns]\n" - ] - } - ], - "source": [ - "df_dji = pd.DataFrame()\n", - "df_dji['date'] = df_account_value['date']\n", - "df_dji['dji'] = df_dji_['close'] / df_dji_['close'][0] * env_kwargs[\"initial_amount\"]\n", - "print(\"df_dji: \", df_dji)\n", - "df_dji.to_csv(\"df_dji.csv\")\n", - "df_dji = df_dji.set_index(df_dji.columns[0])\n", - "print(\"df_dji: \", df_dji)\n", - "df_dji.to_csv(\"df_dji+.csv\")\n", - "\n", - "df_account_value.to_csv('df_account_value.csv')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "9U6Suru3h1jc" - }, - "source": [ - "\n", - "## 7.2 BackTestPlot" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 1000 + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "_1lyCECstj1e", + "scrolled": true, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "outputId": "056b50cd-f8e8-4192-edd9-f570587ed923" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "============Start Ensemble Strategy============\n", + "============================================\n", + "turbulence_threshold: 201.74162030011615\n", + "======Model training from: 2010-01-01 to 2021-10-04\n", + "======a2c Training========\n", + "{'n_steps': 5, 'ent_coef': 0.005, 'learning_rate': 0.0007}\n", + "Using cuda device\n", + "Logging to tensorboard_log/a2c/a2c_126_1\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 83 |\n", + "| iterations | 100 |\n", + "| time_elapsed | 5 |\n", + "| total_timesteps | 500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.589 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 99 |\n", + "| policy_loss | -62.2 |\n", + "| reward | -0.13443886 |\n", + "| std | 0.998 |\n", + "| value_loss | 3.54 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 93 |\n", + "| iterations | 200 |\n", + "| time_elapsed | 10 |\n", + "| total_timesteps | 1000 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | -0.3 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 199 |\n", + "| policy_loss | -58.5 |\n", + "| reward | 0.42441055 |\n", + "| std | 0.996 |\n", + "| value_loss | 6.11 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 300 |\n", + "| time_elapsed | 16 |\n", + "| total_timesteps | 1500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 299 |\n", + "| policy_loss | -27.8 |\n", + "| reward | -3.0476444 |\n", + "| std | 0.998 |\n", + "| value_loss | 2.41 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 400 |\n", + "| time_elapsed | 21 |\n", + "| total_timesteps | 2000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 399 |\n", + "| policy_loss | 24 |\n", + "| reward | 1.1522169 |\n", + "| std | 0.999 |\n", + "| value_loss | 2.67 |\n", + "-------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 500 |\n", + "| time_elapsed | 25 |\n", + "| total_timesteps | 2500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 499 |\n", + "| policy_loss | -9.18 |\n", + "| reward | 0.008832613 |\n", + "| std | 0.999 |\n", + "| value_loss | 3.65 |\n", + "---------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 96 |\n", + "| iterations | 600 |\n", + "| time_elapsed | 31 |\n", + "| total_timesteps | 3000 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 599 |\n", + "| policy_loss | -0.0801 |\n", + "| reward | 0.8033523 |\n", + "| std | 0.997 |\n", + "| value_loss | 0.0839 |\n", + "-------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 700 |\n", + "| time_elapsed | 35 |\n", + "| total_timesteps | 3500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0.0154 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 699 |\n", + "| policy_loss | -10.3 |\n", + "| reward | 0.056252044 |\n", + "| std | 0.999 |\n", + "| value_loss | 0.266 |\n", + "---------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 96 |\n", + "| iterations | 800 |\n", + "| time_elapsed | 41 |\n", + "| total_timesteps | 4000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0.0216 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 799 |\n", + "| policy_loss | 102 |\n", + "| reward | -0.17337318 |\n", + "| std | 1 |\n", + "| value_loss | 7.78 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 900 |\n", + "| time_elapsed | 46 |\n", + "| total_timesteps | 4500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 899 |\n", + "| policy_loss | -150 |\n", + "| reward | -0.7243548 |\n", + "| std | 1 |\n", + "| value_loss | 16.4 |\n", + "--------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 96 |\n", + "| iterations | 1000 |\n", + "| time_elapsed | 51 |\n", + "| total_timesteps | 5000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -0.0375 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 999 |\n", + "| policy_loss | -510 |\n", + "| reward | -0.63908553 |\n", + "| std | 1 |\n", + "| value_loss | 240 |\n", + "---------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 1100 |\n", + "| time_elapsed | 56 |\n", + "| total_timesteps | 5500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0.00788 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1099 |\n", + "| policy_loss | -248 |\n", + "| reward | 3.7405448 |\n", + "| std | 1 |\n", + "| value_loss | 48.9 |\n", + "-------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 1200 |\n", + "| time_elapsed | 61 |\n", + "| total_timesteps | 6000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0.346 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1199 |\n", + "| policy_loss | -16.7 |\n", + "| reward | -0.7040105 |\n", + "| std | 1 |\n", + "| value_loss | 0.666 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 1300 |\n", + "| time_elapsed | 66 |\n", + "| total_timesteps | 6500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.0607 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1299 |\n", + "| policy_loss | 21.4 |\n", + "| reward | 0.14980054 |\n", + "| std | 0.999 |\n", + "| value_loss | 0.792 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 1400 |\n", + "| time_elapsed | 71 |\n", + "| total_timesteps | 7000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0.15 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1399 |\n", + "| policy_loss | 148 |\n", + "| reward | -1.891962 |\n", + "| std | 0.999 |\n", + "| value_loss | 17.6 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 1500 |\n", + "| time_elapsed | 77 |\n", + "| total_timesteps | 7500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.0336 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1499 |\n", + "| policy_loss | 91.2 |\n", + "| reward | -2.299666 |\n", + "| std | 1 |\n", + "| value_loss | 5.62 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 1600 |\n", + "| time_elapsed | 81 |\n", + "| total_timesteps | 8000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1599 |\n", + "| policy_loss | -19.3 |\n", + "| reward | 2.7779486 |\n", + "| std | 0.999 |\n", + "| value_loss | 13.9 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 1700 |\n", + "| time_elapsed | 86 |\n", + "| total_timesteps | 8500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1699 |\n", + "| policy_loss | 36.7 |\n", + "| reward | 5.3634834 |\n", + "| std | 0.998 |\n", + "| value_loss | 29.5 |\n", + "-------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 1800 |\n", + "| time_elapsed | 91 |\n", + "| total_timesteps | 9000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0.0493 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1799 |\n", + "| policy_loss | -60.4 |\n", + "| reward | 0.34657776 |\n", + "| std | 0.999 |\n", + "| value_loss | 4.15 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1900 |\n", + "| time_elapsed | 96 |\n", + "| total_timesteps | 9500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.229 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1899 |\n", + "| policy_loss | 29.5 |\n", + "| reward | 1.0733021 |\n", + "| std | 1 |\n", + "| value_loss | 2.12 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 2000 |\n", + "| time_elapsed | 102 |\n", + "| total_timesteps | 10000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1999 |\n", + "| policy_loss | 41.5 |\n", + "| reward | 0.5164767 |\n", + "| std | 1 |\n", + "| value_loss | 1.16 |\n", + "-------------------------------------\n", + "======a2c Validation from: 2021-10-04 to 2022-01-03\n", + "a2c Sharpe Ratio: 0.12016203130695303\n", + "======ddpg Training========\n", + "{'buffer_size': 10000, 'learning_rate': 0.0005, 'batch_size': 64}\n", + "Using cuda device\n", + "Logging to tensorboard_log/ddpg/ddpg_126_1\n", + "day: 2957, episode: 5\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 4002721.16\n", + "total_reward: 3002721.16\n", + "total_cost: 6360.02\n", + "total_trades: 48784\n", + "Sharpe: 0.828\n", + "=================================\n", + "======ddpg Validation from: 2021-10-04 to 2022-01-03\n", + "ddpg Sharpe Ratio: 0.23149939361322536\n", + "======td3 Training========\n", + "{'batch_size': 100, 'buffer_size': 1000000, 'learning_rate': 0.0001}\n", + "Using cuda device\n", + "Logging to tensorboard_log/td3/td3_126_1\n", + "day: 2957, episode: 10\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 5945616.62\n", + "total_reward: 4945616.62\n", + "total_cost: 2786.02\n", + "total_trades: 38732\n", + "Sharpe: 0.922\n", + "=================================\n", + "======td3 Validation from: 2021-10-04 to 2022-01-03\n", + "td3 Sharpe Ratio: 0.12034224444593176\n", + "======sac Training========\n", + "{'batch_size': 64, 'buffer_size': 100000, 'learning_rate': 0.0001, 'learning_starts': 100, 'ent_coef': 'auto_0.1'}\n", + "Using cuda device\n", + "Logging to tensorboard_log/sac/sac_126_1\n", + "day: 2957, episode: 15\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 4555559.85\n", + "total_reward: 3555559.85\n", + "total_cost: 238769.98\n", + "total_trades: 66550\n", + "Sharpe: 0.861\n", + "=================================\n", + "======sac Validation from: 2021-10-04 to 2022-01-03\n", + "sac Sharpe Ratio: 0.08822857821789602\n", + "======ppo Training========\n", + "{'ent_coef': 0.01, 'n_steps': 2048, 'learning_rate': 0.00025, 'batch_size': 128}\n", + "Using cuda device\n", + "Logging to tensorboard_log/ppo/ppo_126_1\n", + "----------------------------------\n", + "| time/ | |\n", + "| fps | 108 |\n", + "| iterations | 1 |\n", + "| time_elapsed | 18 |\n", + "| total_timesteps | 2048 |\n", + "| train/ | |\n", + "| reward | 1.2595656 |\n", + "----------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 107 |\n", + "| iterations | 2 |\n", + "| time_elapsed | 38 |\n", + "| total_timesteps | 4096 |\n", + "| train/ | |\n", + "| approx_kl | 0.016799435 |\n", + "| clip_fraction | 0.204 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -0.0259 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 3.89 |\n", + "| n_updates | 10 |\n", + "| policy_gradient_loss | -0.0262 |\n", + "| reward | 1.0748519 |\n", + "| std | 1 |\n", + "| value_loss | 9.71 |\n", + "-----------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 106 |\n", + "| iterations | 3 |\n", + "| time_elapsed | 57 |\n", + "| total_timesteps | 6144 |\n", + "| train/ | |\n", + "| approx_kl | 0.014081008 |\n", + "| clip_fraction | 0.135 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | 0.0159 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 13.2 |\n", + "| n_updates | 20 |\n", + "| policy_gradient_loss | -0.0211 |\n", + "| reward | -0.25309741 |\n", + "| std | 1 |\n", + "| value_loss | 41.8 |\n", + "-----------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 106 |\n", + "| iterations | 4 |\n", + "| time_elapsed | 77 |\n", + "| total_timesteps | 8192 |\n", + "| train/ | |\n", + "| approx_kl | 0.014428517 |\n", + "| clip_fraction | 0.148 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | -0.0206 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 30.4 |\n", + "| n_updates | 30 |\n", + "| policy_gradient_loss | -0.0176 |\n", + "| reward | 3.6489613 |\n", + "| std | 1.01 |\n", + "| value_loss | 63.9 |\n", + "-----------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 106 |\n", + "| iterations | 5 |\n", + "| time_elapsed | 95 |\n", + "| total_timesteps | 10240 |\n", + "| train/ | |\n", + "| approx_kl | 0.018376704 |\n", + "| clip_fraction | 0.215 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | 0.0272 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 5.93 |\n", + "| n_updates | 40 |\n", + "| policy_gradient_loss | -0.0251 |\n", + "| reward | -0.09722769 |\n", + "| std | 1.01 |\n", + "| value_loss | 14.7 |\n", + "-----------------------------------------\n", + "======ppo Validation from: 2021-10-04 to 2022-01-03\n", + "ppo Sharpe Ratio: 0.30010210770044654\n", + "======Best Model Retraining from: 2010-01-01 to 2022-01-03\n", + "======Trading from: 2022-01-03 to 2022-04-04\n", + "============================================\n", + "turbulence_threshold: 201.74162030011615\n", + "======Model training from: 2010-01-01 to 2022-01-03\n", + "======a2c Training========\n", + "{'n_steps': 5, 'ent_coef': 0.005, 'learning_rate': 0.0007}\n", + "Using cuda device\n", + "Logging to tensorboard_log/a2c/a2c_189_1\n", + "----------------------------------------\n", + "| time/ | |\n", + "| fps | 90 |\n", + "| iterations | 100 |\n", + "| time_elapsed | 5 |\n", + "| total_timesteps | 500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0.213 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 99 |\n", + "| policy_loss | -82.9 |\n", + "| reward | -0.023693616 |\n", + "| std | 0.998 |\n", + "| value_loss | 4.94 |\n", + "----------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 200 |\n", + "| time_elapsed | 10 |\n", + "| total_timesteps | 1000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 199 |\n", + "| policy_loss | -64.3 |\n", + "| reward | -0.38760617 |\n", + "| std | 1 |\n", + "| value_loss | 6.33 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 300 |\n", + "| time_elapsed | 15 |\n", + "| total_timesteps | 1500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0.0205 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 299 |\n", + "| policy_loss | 54.3 |\n", + "| reward | -4.1570683 |\n", + "| std | 1 |\n", + "| value_loss | 4.02 |\n", + "--------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 400 |\n", + "| time_elapsed | 20 |\n", + "| total_timesteps | 2000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0.00152 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 399 |\n", + "| policy_loss | 91.3 |\n", + "| reward | -0.37606463 |\n", + "| std | 0.999 |\n", + "| value_loss | 14.6 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 99 |\n", + "| iterations | 500 |\n", + "| time_elapsed | 25 |\n", + "| total_timesteps | 2500 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 499 |\n", + "| policy_loss | -72.9 |\n", + "| reward | -1.6318904 |\n", + "| std | 0.996 |\n", + "| value_loss | 4.7 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 600 |\n", + "| time_elapsed | 30 |\n", + "| total_timesteps | 3000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 599 |\n", + "| policy_loss | 250 |\n", + "| reward | 6.0129476 |\n", + "| std | 0.997 |\n", + "| value_loss | 57.9 |\n", + "-------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 99 |\n", + "| iterations | 700 |\n", + "| time_elapsed | 35 |\n", + "| total_timesteps | 3500 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | -0.138 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 699 |\n", + "| policy_loss | -199 |\n", + "| reward | -0.07948906 |\n", + "| std | 0.996 |\n", + "| value_loss | 24.3 |\n", + "---------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 800 |\n", + "| time_elapsed | 40 |\n", + "| total_timesteps | 4000 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0.00106 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 799 |\n", + "| policy_loss | 35.2 |\n", + "| reward | 1.1223269 |\n", + "| std | 0.995 |\n", + "| value_loss | 1.4 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 900 |\n", + "| time_elapsed | 45 |\n", + "| total_timesteps | 4500 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0.104 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 899 |\n", + "| policy_loss | -61.6 |\n", + "| reward | 0.8920734 |\n", + "| std | 0.995 |\n", + "| value_loss | 4.01 |\n", + "-------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1000 |\n", + "| time_elapsed | 50 |\n", + "| total_timesteps | 5000 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 999 |\n", + "| policy_loss | 11.4 |\n", + "| reward | -0.36836326 |\n", + "| std | 0.993 |\n", + "| value_loss | 1.83 |\n", + "---------------------------------------\n", + "------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1100 |\n", + "| time_elapsed | 55 |\n", + "| total_timesteps | 5500 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1099 |\n", + "| policy_loss | -33.7 |\n", + "| reward | 3.212918 |\n", + "| std | 0.994 |\n", + "| value_loss | 3.55 |\n", + "------------------------------------\n", + "----------------------------------------\n", + "| time/ | |\n", + "| fps | 99 |\n", + "| iterations | 1200 |\n", + "| time_elapsed | 60 |\n", + "| total_timesteps | 6000 |\n", + "| train/ | |\n", + "| entropy_loss | -40.9 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1199 |\n", + "| policy_loss | -6.33 |\n", + "| reward | -0.099947825 |\n", + "| std | 0.993 |\n", + "| value_loss | 2.43 |\n", + "----------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1300 |\n", + "| time_elapsed | 65 |\n", + "| total_timesteps | 6500 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0.439 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1299 |\n", + "| policy_loss | -32.1 |\n", + "| reward | 2.2411277 |\n", + "| std | 0.994 |\n", + "| value_loss | 0.802 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1400 |\n", + "| time_elapsed | 70 |\n", + "| total_timesteps | 7000 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0.136 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1399 |\n", + "| policy_loss | 105 |\n", + "| reward | -1.403822 |\n", + "| std | 0.994 |\n", + "| value_loss | 10 |\n", + "-------------------------------------\n", + "------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1500 |\n", + "| time_elapsed | 76 |\n", + "| total_timesteps | 7500 |\n", + "| train/ | |\n", + "| entropy_loss | -40.9 |\n", + "| explained_variance | -0.1 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1499 |\n", + "| policy_loss | 179 |\n", + "| reward | 1.388676 |\n", + "| std | 0.993 |\n", + "| value_loss | 21.9 |\n", + "------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1600 |\n", + "| time_elapsed | 81 |\n", + "| total_timesteps | 8000 |\n", + "| train/ | |\n", + "| entropy_loss | -40.9 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1599 |\n", + "| policy_loss | 122 |\n", + "| reward | -1.1750767 |\n", + "| std | 0.993 |\n", + "| value_loss | 11.6 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1700 |\n", + "| time_elapsed | 86 |\n", + "| total_timesteps | 8500 |\n", + "| train/ | |\n", + "| entropy_loss | -40.9 |\n", + "| explained_variance | 1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1699 |\n", + "| policy_loss | -644 |\n", + "| reward | 5.2921677 |\n", + "| std | 0.993 |\n", + "| value_loss | 260 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1800 |\n", + "| time_elapsed | 91 |\n", + "| total_timesteps | 9000 |\n", + "| train/ | |\n", + "| entropy_loss | -40.9 |\n", + "| explained_variance | -1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1799 |\n", + "| policy_loss | 674 |\n", + "| reward | 3.8561575 |\n", + "| std | 0.993 |\n", + "| value_loss | 382 |\n", + "-------------------------------------\n", + "------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 1900 |\n", + "| time_elapsed | 96 |\n", + "| total_timesteps | 9500 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0.107 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1899 |\n", + "| policy_loss | 4.04 |\n", + "| reward | 1.178899 |\n", + "| std | 0.995 |\n", + "| value_loss | 1.83 |\n", + "------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 98 |\n", + "| iterations | 2000 |\n", + "| time_elapsed | 101 |\n", + "| total_timesteps | 10000 |\n", + "| train/ | |\n", + "| entropy_loss | -41 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1999 |\n", + "| policy_loss | 91 |\n", + "| reward | -0.9507761 |\n", + "| std | 0.995 |\n", + "| value_loss | 5.67 |\n", + "--------------------------------------\n", + "======a2c Validation from: 2022-01-03 to 2022-04-04\n", + "a2c Sharpe Ratio: -0.14881682635553525\n", + "======ddpg Training========\n", + "{'buffer_size': 10000, 'learning_rate': 0.0005, 'batch_size': 64}\n", + "Using cuda device\n", + "Logging to tensorboard_log/ddpg/ddpg_189_1\n", + "day: 3020, episode: 5\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 4134941.46\n", + "total_reward: 3134941.46\n", + "total_cost: 6531.55\n", + "total_trades: 35218\n", + "Sharpe: 0.730\n", + "=================================\n", + "======ddpg Validation from: 2022-01-03 to 2022-04-04\n", + "ddpg Sharpe Ratio: -0.23323576348385744\n", + "======td3 Training========\n", + "{'batch_size': 100, 'buffer_size': 1000000, 'learning_rate': 0.0001}\n", + "Using cuda device\n", + "Logging to tensorboard_log/td3/td3_189_1\n", + "day: 3020, episode: 10\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 6393593.18\n", + "total_reward: 5393593.18\n", + "total_cost: 1548.11\n", + "total_trades: 66333\n", + "Sharpe: 1.008\n", + "=================================\n", + "======td3 Validation from: 2022-01-03 to 2022-04-04\n", + "td3 Sharpe Ratio: -0.22726474272699887\n", + "======sac Training========\n", + "{'batch_size': 64, 'buffer_size': 100000, 'learning_rate': 0.0001, 'learning_starts': 100, 'ent_coef': 'auto_0.1'}\n", + "Using cuda device\n", + "Logging to tensorboard_log/sac/sac_189_1\n", + "day: 3020, episode: 15\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 4134489.29\n", + "total_reward: 3134489.29\n", + "total_cost: 268303.08\n", + "total_trades: 69219\n", + "Sharpe: 0.757\n", + "=================================\n", + "======sac Validation from: 2022-01-03 to 2022-04-04\n", + "sac Sharpe Ratio: -0.12984590976077562\n", + "======ppo Training========\n", + "{'ent_coef': 0.01, 'n_steps': 2048, 'learning_rate': 0.00025, 'batch_size': 128}\n", + "Using cuda device\n", + "Logging to tensorboard_log/ppo/ppo_189_1\n", + "----------------------------------\n", + "| time/ | |\n", + "| fps | 102 |\n", + "| iterations | 1 |\n", + "| time_elapsed | 19 |\n", + "| total_timesteps | 2048 |\n", + "| train/ | |\n", + "| reward | 0.6000615 |\n", + "----------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 100 |\n", + "| iterations | 2 |\n", + "| time_elapsed | 40 |\n", + "| total_timesteps | 4096 |\n", + "| train/ | |\n", + "| approx_kl | 0.015176104 |\n", + "| clip_fraction | 0.199 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0.0105 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 4.55 |\n", + "| n_updates | 10 |\n", + "| policy_gradient_loss | -0.0282 |\n", + "| reward | -0.84197414 |\n", + "| std | 1 |\n", + "| value_loss | 9.05 |\n", + "-----------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 101 |\n", + "| iterations | 3 |\n", + "| time_elapsed | 60 |\n", + "| total_timesteps | 6144 |\n", + "| train/ | |\n", + "| approx_kl | 0.010344334 |\n", + "| clip_fraction | 0.12 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | -0.00571 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 15.5 |\n", + "| n_updates | 20 |\n", + "| policy_gradient_loss | -0.0171 |\n", + "| reward | -0.52176756 |\n", + "| std | 1 |\n", + "| value_loss | 44.1 |\n", + "-----------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 101 |\n", + "| iterations | 4 |\n", + "| time_elapsed | 80 |\n", + "| total_timesteps | 8192 |\n", + "| train/ | |\n", + "| approx_kl | 0.013163242 |\n", + "| clip_fraction | 0.146 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | -0.00859 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 15.3 |\n", + "| n_updates | 30 |\n", + "| policy_gradient_loss | -0.0224 |\n", + "| reward | -2.1821563 |\n", + "| std | 1 |\n", + "| value_loss | 45.5 |\n", + "-----------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 100 |\n", + "| iterations | 5 |\n", + "| time_elapsed | 101 |\n", + "| total_timesteps | 10240 |\n", + "| train/ | |\n", + "| approx_kl | 0.014408065 |\n", + "| clip_fraction | 0.187 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | -0.0553 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 9.32 |\n", + "| n_updates | 40 |\n", + "| policy_gradient_loss | -0.0217 |\n", + "| reward | 0.40127692 |\n", + "| std | 1.01 |\n", + "| value_loss | 16.7 |\n", + "-----------------------------------------\n", + "======ppo Validation from: 2022-01-03 to 2022-04-04\n", + "ppo Sharpe Ratio: -0.10733817017427076\n", + "======Best Model Retraining from: 2010-01-01 to 2022-04-04\n", + "======Trading from: 2022-04-04 to 2022-07-06\n", + "============================================\n", + "turbulence_threshold: 201.74162030011615\n", + "======Model training from: 2010-01-01 to 2022-04-04\n", + "======a2c Training========\n", + "{'n_steps': 5, 'ent_coef': 0.005, 'learning_rate': 0.0007}\n", + "Using cuda device\n", + "Logging to tensorboard_log/a2c/a2c_252_1\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 96 |\n", + "| iterations | 100 |\n", + "| time_elapsed | 5 |\n", + "| total_timesteps | 500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 99 |\n", + "| policy_loss | -38.8 |\n", + "| reward | 0.15574819 |\n", + "| std | 1 |\n", + "| value_loss | 1.31 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 91 |\n", + "| iterations | 200 |\n", + "| time_elapsed | 10 |\n", + "| total_timesteps | 1000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.0432 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 199 |\n", + "| policy_loss | -27.8 |\n", + "| reward | 0.48102596 |\n", + "| std | 0.999 |\n", + "| value_loss | 2.17 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 94 |\n", + "| iterations | 300 |\n", + "| time_elapsed | 15 |\n", + "| total_timesteps | 1500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.0275 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 299 |\n", + "| policy_loss | -32.8 |\n", + "| reward | -2.3948188 |\n", + "| std | 1 |\n", + "| value_loss | 4.81 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 400 |\n", + "| time_elapsed | 21 |\n", + "| total_timesteps | 2000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0.113 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 399 |\n", + "| policy_loss | -105 |\n", + "| reward | -0.2406286 |\n", + "| std | 1 |\n", + "| value_loss | 12.2 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 94 |\n", + "| iterations | 500 |\n", + "| time_elapsed | 26 |\n", + "| total_timesteps | 2500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 499 |\n", + "| policy_loss | -83.1 |\n", + "| reward | -1.0310625 |\n", + "| std | 1 |\n", + "| value_loss | 9.53 |\n", + "--------------------------------------\n", + "------------------------------------\n", + "| time/ | |\n", + "| fps | 93 |\n", + "| iterations | 600 |\n", + "| time_elapsed | 32 |\n", + "| total_timesteps | 3000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 599 |\n", + "| policy_loss | -2.08 |\n", + "| reward | 9.404537 |\n", + "| std | 1 |\n", + "| value_loss | 15.6 |\n", + "------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 700 |\n", + "| time_elapsed | 37 |\n", + "| total_timesteps | 3500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.0019 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 699 |\n", + "| policy_loss | -203 |\n", + "| reward | 1.8093679 |\n", + "| std | 1 |\n", + "| value_loss | 27 |\n", + "-------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 93 |\n", + "| iterations | 800 |\n", + "| time_elapsed | 42 |\n", + "| total_timesteps | 4000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 799 |\n", + "| policy_loss | -155 |\n", + "| reward | 0.29696387 |\n", + "| std | 1 |\n", + "| value_loss | 18.6 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 900 |\n", + "| time_elapsed | 48 |\n", + "| total_timesteps | 4500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 5.96e-08 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 899 |\n", + "| policy_loss | -86.9 |\n", + "| reward | -1.6688259 |\n", + "| std | 1 |\n", + "| value_loss | 8.07 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 1000 |\n", + "| time_elapsed | 54 |\n", + "| total_timesteps | 5000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -2.38e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 999 |\n", + "| policy_loss | 109 |\n", + "| reward | 3.7493455 |\n", + "| std | 1 |\n", + "| value_loss | 15.6 |\n", + "-------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 91 |\n", + "| iterations | 1100 |\n", + "| time_elapsed | 60 |\n", + "| total_timesteps | 5500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1099 |\n", + "| policy_loss | -399 |\n", + "| reward | -1.8209955 |\n", + "| std | 0.999 |\n", + "| value_loss | 126 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 1200 |\n", + "| time_elapsed | 65 |\n", + "| total_timesteps | 6000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1199 |\n", + "| policy_loss | -121 |\n", + "| reward | -5.2913017 |\n", + "| std | 0.998 |\n", + "| value_loss | 24 |\n", + "--------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 91 |\n", + "| iterations | 1300 |\n", + "| time_elapsed | 70 |\n", + "| total_timesteps | 6500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0.139 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1299 |\n", + "| policy_loss | 164 |\n", + "| reward | -0.32371435 |\n", + "| std | 1 |\n", + "| value_loss | 16.9 |\n", + "---------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 1400 |\n", + "| time_elapsed | 75 |\n", + "| total_timesteps | 7000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.0498 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1399 |\n", + "| policy_loss | -12 |\n", + "| reward | 0.8689141 |\n", + "| std | 1 |\n", + "| value_loss | 2.3 |\n", + "-------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 1500 |\n", + "| time_elapsed | 80 |\n", + "| total_timesteps | 7500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1499 |\n", + "| policy_loss | -72.2 |\n", + "| reward | -0.54522103 |\n", + "| std | 1 |\n", + "| value_loss | 3.61 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 1600 |\n", + "| time_elapsed | 86 |\n", + "| total_timesteps | 8000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -2.38e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1599 |\n", + "| policy_loss | -13.1 |\n", + "| reward | -1.0812243 |\n", + "| std | 1 |\n", + "| value_loss | 0.389 |\n", + "--------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 93 |\n", + "| iterations | 1700 |\n", + "| time_elapsed | 91 |\n", + "| total_timesteps | 8500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1699 |\n", + "| policy_loss | -86.9 |\n", + "| reward | -0.64294523 |\n", + "| std | 1 |\n", + "| value_loss | 5.99 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 1800 |\n", + "| time_elapsed | 97 |\n", + "| total_timesteps | 9000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1799 |\n", + "| policy_loss | 413 |\n", + "| reward | 0.50728357 |\n", + "| std | 1 |\n", + "| value_loss | 127 |\n", + "--------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 93 |\n", + "| iterations | 1900 |\n", + "| time_elapsed | 102 |\n", + "| total_timesteps | 9500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1899 |\n", + "| policy_loss | -55.7 |\n", + "| reward | -0.07039916 |\n", + "| std | 1 |\n", + "| value_loss | 2.31 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 92 |\n", + "| iterations | 2000 |\n", + "| time_elapsed | 107 |\n", + "| total_timesteps | 10000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1999 |\n", + "| policy_loss | -22.2 |\n", + "| reward | -0.5126278 |\n", + "| std | 1 |\n", + "| value_loss | 0.961 |\n", + "--------------------------------------\n", + "======a2c Validation from: 2022-04-04 to 2022-07-06\n", + "a2c Sharpe Ratio: -0.25366636627181594\n", + "======ddpg Training========\n", + "{'buffer_size': 10000, 'learning_rate': 0.0005, 'batch_size': 64}\n", + "Using cuda device\n", + "Logging to tensorboard_log/ddpg/ddpg_252_1\n", + "day: 3083, episode: 5\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 5721518.02\n", + "total_reward: 4721518.02\n", + "total_cost: 6164.84\n", + "total_trades: 44663\n", + "Sharpe: 0.868\n", + "=================================\n", + "======ddpg Validation from: 2022-04-04 to 2022-07-06\n", + "ddpg Sharpe Ratio: -0.22747056221011977\n", + "======td3 Training========\n", + "{'batch_size': 100, 'buffer_size': 1000000, 'learning_rate': 0.0001}\n", + "Using cuda device\n", + "Logging to tensorboard_log/td3/td3_252_1\n", + "day: 3083, episode: 10\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 4419882.67\n", + "total_reward: 3419882.67\n", + "total_cost: 1787.44\n", + "total_trades: 46447\n", + "Sharpe: 0.822\n", + "=================================\n", + "======td3 Validation from: 2022-04-04 to 2022-07-06\n", + "td3 Sharpe Ratio: -0.2839424978995499\n", + "======sac Training========\n", + "{'batch_size': 64, 'buffer_size': 100000, 'learning_rate': 0.0001, 'learning_starts': 100, 'ent_coef': 'auto_0.1'}\n", + "Using cuda device\n", + "Logging to tensorboard_log/sac/sac_252_1\n", + "day: 3083, episode: 15\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 4927709.27\n", + "total_reward: 3927709.27\n", + "total_cost: 85026.93\n", + "total_trades: 55788\n", + "Sharpe: 0.808\n", + "=================================\n", + "======sac Validation from: 2022-04-04 to 2022-07-06\n", + "sac Sharpe Ratio: -0.16022717745791382\n", + "======ppo Training========\n", + "{'ent_coef': 0.01, 'n_steps': 2048, 'learning_rate': 0.00025, 'batch_size': 128}\n", + "Using cuda device\n", + "Logging to tensorboard_log/ppo/ppo_252_1\n", + "-----------------------------------\n", + "| time/ | |\n", + "| fps | 105 |\n", + "| iterations | 1 |\n", + "| time_elapsed | 19 |\n", + "| total_timesteps | 2048 |\n", + "| train/ | |\n", + "| reward | 0.54891366 |\n", + "-----------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 103 |\n", + "| iterations | 2 |\n", + "| time_elapsed | 39 |\n", + "| total_timesteps | 4096 |\n", + "| train/ | |\n", + "| approx_kl | 0.016892547 |\n", + "| clip_fraction | 0.209 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -0.0182 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 5.17 |\n", + "| n_updates | 10 |\n", + "| policy_gradient_loss | -0.0246 |\n", + "| reward | -0.46093306 |\n", + "| std | 1 |\n", + "| value_loss | 10.4 |\n", + "-----------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 104 |\n", + "| iterations | 3 |\n", + "| time_elapsed | 58 |\n", + "| total_timesteps | 6144 |\n", + "| train/ | |\n", + "| approx_kl | 0.013119971 |\n", + "| clip_fraction | 0.109 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -0.000288 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 28.6 |\n", + "| n_updates | 20 |\n", + "| policy_gradient_loss | -0.0202 |\n", + "| reward | -9.113171 |\n", + "| std | 1 |\n", + "| value_loss | 57.9 |\n", + "-----------------------------------------\n", + "------------------------------------------\n", + "| time/ | |\n", + "| fps | 102 |\n", + "| iterations | 4 |\n", + "| time_elapsed | 79 |\n", + "| total_timesteps | 8192 |\n", + "| train/ | |\n", + "| approx_kl | 0.0148056755 |\n", + "| clip_fraction | 0.147 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | -0.0199 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 47.2 |\n", + "| n_updates | 30 |\n", + "| policy_gradient_loss | -0.0206 |\n", + "| reward | -0.5656307 |\n", + "| std | 1.01 |\n", + "| value_loss | 78.6 |\n", + "------------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 102 |\n", + "| iterations | 5 |\n", + "| time_elapsed | 99 |\n", + "| total_timesteps | 10240 |\n", + "| train/ | |\n", + "| approx_kl | 0.027241705 |\n", + "| clip_fraction | 0.268 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | -0.00487 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 8.49 |\n", + "| n_updates | 40 |\n", + "| policy_gradient_loss | -0.0307 |\n", + "| reward | -0.5270617 |\n", + "| std | 1.01 |\n", + "| value_loss | 17.2 |\n", + "-----------------------------------------\n", + "======ppo Validation from: 2022-04-04 to 2022-07-06\n", + "ppo Sharpe Ratio: -0.23906732813732043\n", + "======Best Model Retraining from: 2010-01-01 to 2022-07-06\n", + "======Trading from: 2022-07-06 to 2022-10-04\n", + "============================================\n", + "turbulence_threshold: 201.74162030011615\n", + "======Model training from: 2010-01-01 to 2022-07-06\n", + "======a2c Training========\n", + "{'n_steps': 5, 'ent_coef': 0.005, 'learning_rate': 0.0007}\n", + "Using cuda device\n", + "Logging to tensorboard_log/a2c/a2c_315_1\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 102 |\n", + "| iterations | 100 |\n", + "| time_elapsed | 4 |\n", + "| total_timesteps | 500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0.0353 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 99 |\n", + "| policy_loss | -80 |\n", + "| reward | 0.24549441 |\n", + "| std | 1 |\n", + "| value_loss | 4.92 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 200 |\n", + "| time_elapsed | 10 |\n", + "| total_timesteps | 1000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.1 |\n", + "| explained_variance | -0.126 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 199 |\n", + "| policy_loss | -17.6 |\n", + "| reward | 1.3894979 |\n", + "| std | 1 |\n", + "| value_loss | 3.75 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 96 |\n", + "| iterations | 300 |\n", + "| time_elapsed | 15 |\n", + "| total_timesteps | 1500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -0.012 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 299 |\n", + "| policy_loss | -91.5 |\n", + "| reward | -2.606353 |\n", + "| std | 1 |\n", + "| value_loss | 8.84 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 97 |\n", + "| iterations | 400 |\n", + "| time_elapsed | 20 |\n", + "| total_timesteps | 2000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -0.183 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 399 |\n", + "| policy_loss | -10.2 |\n", + "| reward | 1.6483078 |\n", + "| std | 1 |\n", + "| value_loss | 4.13 |\n", + "-------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 500 |\n", + "| time_elapsed | 26 |\n", + "| total_timesteps | 2500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0.0521 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 499 |\n", + "| policy_loss | -51.2 |\n", + "| reward | -0.46745828 |\n", + "| std | 1 |\n", + "| value_loss | 2.93 |\n", + "---------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 96 |\n", + "| iterations | 600 |\n", + "| time_elapsed | 31 |\n", + "| total_timesteps | 3000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0.0325 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 599 |\n", + "| policy_loss | -2.87 |\n", + "| reward | 10.919484 |\n", + "| std | 1 |\n", + "| value_loss | 8.18 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 94 |\n", + "| iterations | 700 |\n", + "| time_elapsed | 36 |\n", + "| total_timesteps | 3500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | 0.0171 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 699 |\n", + "| policy_loss | -27.7 |\n", + "| reward | 0.8419629 |\n", + "| std | 1.01 |\n", + "| value_loss | 0.606 |\n", + "-------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 800 |\n", + "| time_elapsed | 41 |\n", + "| total_timesteps | 4000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | -1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 799 |\n", + "| policy_loss | -27.5 |\n", + "| reward | -0.18779811 |\n", + "| std | 1.01 |\n", + "| value_loss | 0.786 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 93 |\n", + "| iterations | 900 |\n", + "| time_elapsed | 47 |\n", + "| total_timesteps | 4500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | 1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 899 |\n", + "| policy_loss | -23.3 |\n", + "| reward | 0.21865338 |\n", + "| std | 1.01 |\n", + "| value_loss | 1.68 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 94 |\n", + "| iterations | 1000 |\n", + "| time_elapsed | 52 |\n", + "| total_timesteps | 5000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | 1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 999 |\n", + "| policy_loss | 30.7 |\n", + "| reward | -0.8657269 |\n", + "| std | 1.01 |\n", + "| value_loss | 0.856 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 1100 |\n", + "| time_elapsed | 57 |\n", + "| total_timesteps | 5500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | 5.96e-08 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1099 |\n", + "| policy_loss | 75.6 |\n", + "| reward | 3.6971135 |\n", + "| std | 1.01 |\n", + "| value_loss | 7.44 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 94 |\n", + "| iterations | 1200 |\n", + "| time_elapsed | 63 |\n", + "| total_timesteps | 6000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1199 |\n", + "| policy_loss | -237 |\n", + "| reward | 0.9042094 |\n", + "| std | 1.01 |\n", + "| value_loss | 34.5 |\n", + "-------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 1300 |\n", + "| time_elapsed | 68 |\n", + "| total_timesteps | 6500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | -0.503 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1299 |\n", + "| policy_loss | 58.3 |\n", + "| reward | 0.20865634 |\n", + "| std | 1.01 |\n", + "| value_loss | 2.1 |\n", + "--------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 94 |\n", + "| iterations | 1400 |\n", + "| time_elapsed | 74 |\n", + "| total_timesteps | 7000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | -1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1399 |\n", + "| policy_loss | -72.9 |\n", + "| reward | -1.3368342 |\n", + "| std | 1.01 |\n", + "| value_loss | 4.41 |\n", + "--------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 1500 |\n", + "| time_elapsed | 78 |\n", + "| total_timesteps | 7500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1499 |\n", + "| policy_loss | -144 |\n", + "| reward | 3.5003781 |\n", + "| std | 1.01 |\n", + "| value_loss | 14.4 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 94 |\n", + "| iterations | 1600 |\n", + "| time_elapsed | 84 |\n", + "| total_timesteps | 8000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | 1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1599 |\n", + "| policy_loss | -38.2 |\n", + "| reward | 1.3683945 |\n", + "| std | 1.01 |\n", + "| value_loss | 1.89 |\n", + "-------------------------------------\n", + "-------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 1700 |\n", + "| time_elapsed | 89 |\n", + "| total_timesteps | 8500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1699 |\n", + "| policy_loss | 48.4 |\n", + "| reward | 1.4903697 |\n", + "| std | 1.01 |\n", + "| value_loss | 4.15 |\n", + "-------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 1800 |\n", + "| time_elapsed | 94 |\n", + "| total_timesteps | 9000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | -1.19e-07 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1799 |\n", + "| policy_loss | -31.4 |\n", + "| reward | -1.6481568 |\n", + "| std | 1.01 |\n", + "| value_loss | 17.5 |\n", + "--------------------------------------\n", + "---------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 1900 |\n", + "| time_elapsed | 99 |\n", + "| total_timesteps | 9500 |\n", + "| train/ | |\n", + "| entropy_loss | -41.4 |\n", + "| explained_variance | 0 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1899 |\n", + "| policy_loss | 27.9 |\n", + "| reward | -0.39915258 |\n", + "| std | 1.01 |\n", + "| value_loss | 0.507 |\n", + "---------------------------------------\n", + "--------------------------------------\n", + "| time/ | |\n", + "| fps | 95 |\n", + "| iterations | 2000 |\n", + "| time_elapsed | 104 |\n", + "| total_timesteps | 10000 |\n", + "| train/ | |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | 0.159 |\n", + "| learning_rate | 0.0007 |\n", + "| n_updates | 1999 |\n", + "| policy_loss | 58.6 |\n", + "| reward | -1.4694927 |\n", + "| std | 1.01 |\n", + "| value_loss | 2.85 |\n", + "--------------------------------------\n", + "======a2c Validation from: 2022-07-06 to 2022-10-04\n", + "a2c Sharpe Ratio: -0.10266785475978492\n", + "======ddpg Training========\n", + "{'buffer_size': 10000, 'learning_rate': 0.0005, 'batch_size': 64}\n", + "Using cuda device\n", + "Logging to tensorboard_log/ddpg/ddpg_315_1\n", + "day: 3146, episode: 5\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 8621242.15\n", + "total_reward: 7621242.15\n", + "total_cost: 7912.99\n", + "total_trades: 39562\n", + "Sharpe: 1.023\n", + "=================================\n", + "======ddpg Validation from: 2022-07-06 to 2022-10-04\n", + "ddpg Sharpe Ratio: -0.06187703782204383\n", + "======td3 Training========\n", + "{'batch_size': 100, 'buffer_size': 1000000, 'learning_rate': 0.0001}\n", + "Using cuda device\n", + "Logging to tensorboard_log/td3/td3_315_1\n", + "day: 3146, episode: 10\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 4437212.38\n", + "total_reward: 3437212.38\n", + "total_cost: 2996.04\n", + "total_trades: 31813\n", + "Sharpe: 0.776\n", + "=================================\n", + "======td3 Validation from: 2022-07-06 to 2022-10-04\n", + "td3 Sharpe Ratio: -0.12530693561038414\n", + "======sac Training========\n", + "{'batch_size': 64, 'buffer_size': 100000, 'learning_rate': 0.0001, 'learning_starts': 100, 'ent_coef': 'auto_0.1'}\n", + "Using cuda device\n", + "Logging to tensorboard_log/sac/sac_315_1\n", + "day: 3146, episode: 15\n", + "begin_total_asset: 1000000.00\n", + "end_total_asset: 3601294.13\n", + "total_reward: 2601294.13\n", + "total_cost: 234860.64\n", + "total_trades: 64468\n", + "Sharpe: 0.695\n", + "=================================\n", + "======sac Validation from: 2022-07-06 to 2022-10-04\n", + "sac Sharpe Ratio: -0.16088947893289524\n", + "======ppo Training========\n", + "{'ent_coef': 0.01, 'n_steps': 2048, 'learning_rate': 0.00025, 'batch_size': 128}\n", + "Using cuda device\n", + "Logging to tensorboard_log/ppo/ppo_315_1\n", + "----------------------------------\n", + "| time/ | |\n", + "| fps | 105 |\n", + "| iterations | 1 |\n", + "| time_elapsed | 19 |\n", + "| total_timesteps | 2048 |\n", + "| train/ | |\n", + "| reward | 1.6173023 |\n", + "----------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 103 |\n", + "| iterations | 2 |\n", + "| time_elapsed | 39 |\n", + "| total_timesteps | 4096 |\n", + "| train/ | |\n", + "| approx_kl | 0.015555255 |\n", + "| clip_fraction | 0.228 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | -0.0101 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 6.3 |\n", + "| n_updates | 10 |\n", + "| policy_gradient_loss | -0.0255 |\n", + "| reward | 3.5431957 |\n", + "| std | 1 |\n", + "| value_loss | 13.2 |\n", + "-----------------------------------------\n", + "-----------------------------------------\n", + "| time/ | |\n", + "| fps | 104 |\n", + "| iterations | 3 |\n", + "| time_elapsed | 58 |\n", + "| total_timesteps | 6144 |\n", + "| train/ | |\n", + "| approx_kl | 0.015205141 |\n", + "| clip_fraction | 0.167 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.2 |\n", + "| explained_variance | 0.00121 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 24.5 |\n", + "| n_updates | 20 |\n", + "| policy_gradient_loss | -0.0202 |\n", + "| reward | 5.9619627 |\n", + "| std | 1 |\n", + "| value_loss | 81.8 |\n", + "-----------------------------------------\n", + "----------------------------------------\n", + "| time/ | |\n", + "| fps | 103 |\n", + "| iterations | 4 |\n", + "| time_elapsed | 78 |\n", + "| total_timesteps | 8192 |\n", + "| train/ | |\n", + "| approx_kl | 0.01795656 |\n", + "| clip_fraction | 0.154 |\n", + "| clip_range | 0.2 |\n", + "| entropy_loss | -41.3 |\n", + "| explained_variance | -0.00243 |\n", + "| learning_rate | 0.00025 |\n", + "| loss | 31.6 |\n", + "| n_updates | 30 |\n", + "| policy_gradient_loss | -0.0196 |\n", + "| reward | 1.3367934 |\n", + "| std | 1.01 |\n", + "| value_loss | 49.2 |\n", + "----------------------------------------\n" + ] + } + ], + "source": [ + "df_summary = ensemble_agent.run_ensemble_strategy(A2C_model_kwargs,\n", + " PPO_model_kwargs,\n", + " DDPG_model_kwargs,\n", + " SAC_model_kwargs,\n", + " TD3_model_kwargs,\n", + " timesteps_dict)" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "-0qd8acMtj1f", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 89 + }, + "outputId": "ef19ff5d-9173-4268-e50b-6128cf9278f5" + }, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + "Empty DataFrame\n", + "Columns: [Iter, Val Start, Val End, Model Used, A2C Sharpe, PPO Sharpe, DDPG Sharpe, SAC Sharpe, TD3 Sharpe]\n", + "Index: []" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
IterVal StartVal EndModel UsedA2C SharpePPO SharpeDDPG SharpeSAC SharpeTD3 Sharpe
\n", + "
\n", + "
\n", + "\n", + "
\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "
\n", + "\n", + "\n", + "
\n", + " \n", + " \n", + " \n", + "
\n", + "\n", + "
\n", + "
\n" + ], + "application/vnd.google.colaboratory.intrinsic+json": { + "type": "dataframe", + "variable_name": "df_summary", + "summary": "{\n \"name\": \"df_summary\",\n \"rows\": 0,\n \"fields\": [\n {\n \"column\": \"Iter\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Val Start\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Val End\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Model Used\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"A2C Sharpe\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"PPO Sharpe\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"DDPG Sharpe\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"SAC Sharpe\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"TD3 Sharpe\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": null,\n \"min\": null,\n \"max\": null,\n \"num_unique_values\": 0,\n \"samples\": [],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}" + } + }, + "metadata": {}, + "execution_count": 15 + } + ], + "source": [ + "df_summary" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "W6vvNSC6h1jZ" + }, + "source": [ + "\n", + "# Part 7: Backtest Our Strategy\n", + "Backtesting plays a key role in evaluating the performance of a trading strategy. Automated backtesting tool is preferred because it reduces the human error. We usually use the Quantopian pyfolio package to backtest our trading strategies. It is easy to use and consists of various individual plots that provide a comprehensive image of the performance of a trading strategy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "X4JKB--8tj1g" + }, + "outputs": [], + "source": [ + "unique_trade_date = processed[(processed.date > TEST_START_DATE)&(processed.date <= TEST_END_DATE)].date.unique()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "q9mKF7GGtj1g", + "scrolled": true + }, + "outputs": [], + "source": [ + "df_trade_date = pd.DataFrame({'datadate':unique_trade_date})\n", + "\n", + "df_account_value=pd.DataFrame()\n", + "for i in range(rebalance_window+validation_window, len(unique_trade_date)+1,rebalance_window):\n", + " temp = pd.read_csv('results/account_value_trade_{}_{}.csv'.format('ensemble',i))\n", + " df_account_value = df_account_value.append(temp,ignore_index=True)\n", + "sharpe=(252**0.5)*df_account_value.account_value.pct_change(1).mean()/df_account_value.account_value.pct_change(1).std()\n", + "print('Sharpe Ratio: ',sharpe)\n", + "df_account_value=df_account_value.join(df_trade_date[validation_window:].reset_index(drop=True))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "oyosyW7_tj1g" + }, + "outputs": [], + "source": [ + "df_account_value.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "wLsRdw2Ctj1h" + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "df_account_value.account_value.plot()" + ] }, - "id": "HggausPRoCem", - "outputId": "615e8d79-f3d7-47e9-c886-3cd18e4535f2" - }, - "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "df_result_ensemble.columns: Index(['ensemble'], dtype='object')\n", - "df_trade_date: datadate\n", - "0 2021-10-04\n", - "1 2021-10-05\n", - "2 2021-10-06\n", - "3 2021-10-07\n", - "4 2021-10-08\n", - ".. ...\n", - "348 2023-02-22\n", - "349 2023-02-23\n", - "350 2023-02-24\n", - "351 2023-02-27\n", - "352 2023-02-28\n", - "\n", - "[353 rows x 1 columns]\n", - "df_result_ensemble: ensemble\n", - "date \n", - "2022-01-03 1000000.000000\n", - "2022-01-04 999006.177890\n", - "2022-01-05 992190.375143\n", - "2022-01-06 986549.918776\n", - "2022-01-07 984951.522695\n", - "... ...\n", - "2022-12-27 966931.603579\n", - "2022-12-28 956294.904131\n", - "2022-12-29 964607.097342\n", - "2022-12-30 960687.624327\n", - "2023-01-03 960610.826884\n", - "\n", - "[252 rows x 1 columns]\n", - "==============Compare to DJIA===========\n", - "result: ensemble dji\n", - "date \n", - "2022-01-03 1000000.000000 1.000000e+06\n", - "2022-01-04 999006.177890 1.005866e+06\n", - "2022-01-05 992190.375143 9.951360e+05\n", - "2022-01-06 986549.918776 9.904718e+05\n", - "2022-01-07 984951.522695 9.903404e+05\n", - "... ... ...\n", - "2022-12-27 966931.603579 9.086102e+05\n", - "2022-12-28 956294.904131 8.986103e+05\n", - "2022-12-29 964607.097342 9.080428e+05\n", - "2022-12-30 960687.624327 9.060324e+05\n", - "2023-01-03 960610.826884 NaN\n", - "\n", - "[252 rows x 2 columns]\n" - ] + "cell_type": "markdown", + "metadata": { + "id": "Lr2zX7ZxNyFQ" + }, + "source": [ + "\n", + "## 7.1 BackTestStats\n", + "pass in df_account_value, this information is stored in env class\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "Nzkr9yv-AdV_", + "scrolled": true + }, + "outputs": [], + "source": [ + "print(\"==============Get Backtest Results===========\")\n", + "now = datetime.datetime.now().strftime('%Y%m%d-%Hh%M')\n", + "\n", + "perf_stats_all = backtest_stats(account_value=df_account_value)\n", + "perf_stats_all = pd.DataFrame(perf_stats_all)" + ] }, { - "data": { - "text/plain": [ - "
" + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "DiHhM1YkoCel" + }, + "outputs": [], + "source": [ + "#baseline stats\n", + "print(\"==============Get Baseline Stats===========\")\n", + "df_dji_ = get_baseline(\n", + " ticker=\"^DJI\",\n", + " start = df_account_value.loc[0,'date'],\n", + " end = df_account_value.loc[len(df_account_value)-1,'date'])\n", + "\n", + "stats = backtest_stats(df_dji_, value_col_name = 'close')" ] - }, - "metadata": {}, - "output_type": "display_data" }, { - "data": { - "image/png": "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yHd3WQvgwIc2W6Xj9L+It4iEnAI4ERERkZEiKx9am+DwDlv/rbmufyUERCTkAlVGQERERETCXXa+XZZthjFN9rmGUIoMKwrgREREREaKtKk262T5FlsAHDSEUmSYUQAnIiIiMlJERMC4+TaRSXKWXZeaG9ImiUj/KIAboNtvv53ExERqa2tZsWIF55xzDjfeeCM333wzs2fPDnXzRERERLzLzocNv4eMGRCfAbGJoW6RiPSDArhBuuOOO9qf33fffSFsiYiIiIgfsvKhpQF2v6QEJiLDkLJQ9sOaNWuYPn06p512Gjt37gTguuuu4/HHHwfgzDPPpHsRchEREZGw4klkcuyA5r+JDEPDrwfuuVvhwAeBPee4eXD+D3rdZePGjTzyyCNs3ryZlpYWFi1axEknnRTYdoiIiIgEW/o0iE5QCQGRYUo9cH564403+MhHPkJ8fDzJyclccskloW6SiIiISP9FRNovr0E9cCLD0PDrgeujp0xERERE+pCdD8XvqAacyDCkHjg/rVixgn/84x80NDRw9OhRnnrqqVA3SURERGRgJi6HiGjInBHqlohIPw2/HrgQWbRoEf/xH//BggULGDNmDEuWLGnfZowJYctERERE+mnWxXDzdkjMDHVLRKSfFMD1w2233cZtt93WZd3FF19MWloaAGvXrg1Bq0RERET6yRgFbyLDlIZQDsL1119PfX09p512WqibIiIiIiIiI4B64AbhgQceCHUTRERERERkBFEPnIiIiIiIyDAxbAI4x3FC3YQTht5LEREREZHhaVgEcHFxcVRWVirwCADHcaisrCQuLi7UTRERERERkX4aFnPgcnJyKCkp4fDhw6FuygkhLi6OnJycUDdDRERERET6aVgEcNHR0UyePDnUzRAREREREQmpYTGEUkRERERERBTAiYiIiIiIDBsK4ERERERERIYJE26ZHY0xh4HCULfDiwygItSNkBOW7i8JJt1fEiy6tySYdH9JsAyHe2ui4ziZ3jaEXQAXrowxGxzHWRzqdsiJSfeXBJPuLwkW3VsSTLq/JFiG+72lIZQiIiIiIiLDhAI4ERERERGRYUIBnP9+F+oGyAlN95cEk+4vCRbdWxJMur8kWIb1vaU5cCIiIiIiIsOEeuBERERERESGiWEbwBljJhhjXjXGbDPGbDXGfMVdn2aMedEYU+AuR7vrrzHG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", - "text/plain": [ - "
" + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "RhJ9whD75WTs" + }, + "outputs": [], + "source": [ + "df_dji = pd.DataFrame()\n", + "df_dji['date'] = df_account_value['date']\n", + "df_dji['dji'] = df_dji_['close'] / df_dji_['close'][0] * env_kwargs[\"initial_amount\"]\n", + "print(\"df_dji: \", df_dji)\n", + "df_dji.to_csv(\"df_dji.csv\")\n", + "df_dji = df_dji.set_index(df_dji.columns[0])\n", + "print(\"df_dji: \", df_dji)\n", + "df_dji.to_csv(\"df_dji+.csv\")\n", + "\n", + "df_account_value.to_csv('df_account_value.csv')\n" ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" + }, + { + "cell_type": "markdown", + "metadata": { + "id": "9U6Suru3h1jc" + }, + "source": [ + "\n", + "## 7.2 BackTestPlot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HggausPRoCem" + }, + "outputs": [], + "source": [ + "\n", + "\n", + "# print(\"==============Compare to DJIA===========\")\n", + "# %matplotlib inline\n", + "# # S&P 500: ^GSPC\n", + "# # Dow Jones Index: ^DJI\n", + "# # NASDAQ 100: ^NDX\n", + "# backtest_plot(df_account_value,\n", + "# baseline_ticker = '^DJI',\n", + "# baseline_start = df_account_value.loc[0,'date'],\n", + "# baseline_end = df_account_value.loc[len(df_account_value)-1,'date'])\n", + "df.to_csv(\"df.csv\")\n", + "df_result_ensemble = pd.DataFrame({'date': df_account_value['date'], 'ensemble': df_account_value['account_value']})\n", + "df_result_ensemble = df_result_ensemble.set_index('date')\n", + "\n", + "print(\"df_result_ensemble.columns: \", df_result_ensemble.columns)\n", + "\n", + "# df_result_ensemble.drop(df_result_ensemble.columns[0], axis = 1)\n", + "print(\"df_trade_date: \", df_trade_date)\n", + "# df_result_ensemble['date'] = df_trade_date['datadate']\n", + "# df_result_ensemble['account_value'] = df_account_value['account_value']\n", + "df_result_ensemble.to_csv(\"df_result_ensemble.csv\")\n", + "print(\"df_result_ensemble: \", df_result_ensemble)\n", + "print(\"==============Compare to DJIA===========\")\n", + "result = pd.DataFrame()\n", + "# result = pd.merge(result, df_result_ensemble, left_index=True, right_index=True)\n", + "# result = pd.merge(result, df_dji, left_index=True, right_index=True)\n", + "result = pd.merge(df_result_ensemble, df_dji, left_index=True, right_index=True)\n", + "print(\"result: \", result)\n", + "result.to_csv(\"result.csv\")\n", + "result.columns = ['ensemble', 'dji']\n", + "\n", + "%matplotlib inline\n", + "plt.rcParams[\"figure.figsize\"] = (15,5)\n", + "plt.figure();\n", + "result.plot();" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "oBQx4bVQFi-a" + }, + "source": [] } - ], - "source": [ - "\n", - "\n", - "# print(\"==============Compare to DJIA===========\")\n", - "# %matplotlib inline\n", - "# # S&P 500: ^GSPC\n", - "# # Dow Jones Index: ^DJI\n", - "# # NASDAQ 100: ^NDX\n", - "# backtest_plot(df_account_value, \n", - "# baseline_ticker = '^DJI', \n", - "# baseline_start = df_account_value.loc[0,'date'],\n", - "# baseline_end = df_account_value.loc[len(df_account_value)-1,'date'])\n", - "df.to_csv(\"df.csv\")\n", - "df_result_ensemble = pd.DataFrame({'date': df_account_value['date'], 'ensemble': df_account_value['account_value']})\n", - "df_result_ensemble = df_result_ensemble.set_index('date')\n", - "\n", - "print(\"df_result_ensemble.columns: \", df_result_ensemble.columns)\n", - "\n", - "# df_result_ensemble.drop(df_result_ensemble.columns[0], axis = 1)\n", - "print(\"df_trade_date: \", df_trade_date)\n", - "# df_result_ensemble['date'] = df_trade_date['datadate']\n", - "# df_result_ensemble['account_value'] = df_account_value['account_value']\n", - "df_result_ensemble.to_csv(\"df_result_ensemble.csv\")\n", - "print(\"df_result_ensemble: \", df_result_ensemble)\n", - "print(\"==============Compare to DJIA===========\")\n", - "result = pd.DataFrame()\n", - "# result = pd.merge(result, df_result_ensemble, left_index=True, right_index=True)\n", - "# result = pd.merge(result, df_dji, left_index=True, right_index=True)\n", - "result = pd.merge(df_result_ensemble, df_dji, left_index=True, right_index=True)\n", - "print(\"result: \", result)\n", - "result.to_csv(\"result.csv\")\n", - "result.columns = ['ensemble', 'dji']\n", - "\n", - "%matplotlib inline\n", - "plt.rcParams[\"figure.figsize\"] = (15,5)\n", - "plt.figure();\n", - "result.plot();" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "oBQx4bVQFi-a" - }, - "source": [] - } - ], - "metadata": { - "accelerator": "GPU", - "colab": { - "name": "FinRL_Ensemble_StockTrading_ICAIF_2020.ipynb", - "provenance": [] - }, - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.10" - }, - "pycharm": { - "stem_cell": { - "cell_type": "raw", - "metadata": { - "collapsed": false + ], + "metadata": { + "accelerator": "GPU", + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.10" }, - "source": [] - } - } - }, - "nbformat": 4, - "nbformat_minor": 0 + "pycharm": { + "stem_cell": { + "cell_type": "raw", + "metadata": { + "collapsed": false + }, + "source": [] + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 } From d06a71e11a62683c0aa28f63c8cceb2c206713cf Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 14:52:38 +0800 Subject: [PATCH 11/11] [pre-commit.ci] pre-commit autoupdate (#1204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [pre-commit.ci] pre-commit autoupdate updates: - [github.com/pre-commit/pre-commit-hooks: v4.5.0 → v4.6.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.5.0...v4.6.0) * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- requirements.txt | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 1f4adba88..e9b3726b5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -3,7 +3,7 @@ ci: skip: [flake8] # remove this eventually repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-docstring-first - id: check-yaml diff --git a/requirements.txt b/requirements.txt index 2c62a4345..22e919a47 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,6 @@ pytest ray[default] ray[tune] recommonmark -recommonmark # Model Building Requirements scikit-learn>=0.21.0