rl-pricing 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rl_pricing-0.5.0/LICENSE +21 -0
- rl_pricing-0.5.0/MANIFEST.in +6 -0
- rl_pricing-0.5.0/PKG-INFO +86 -0
- rl_pricing-0.5.0/README.md +344 -0
- rl_pricing-0.5.0/main.py +6 -0
- rl_pricing-0.5.0/pyproject.toml +4 -0
- rl_pricing-0.5.0/pytest.ini +3 -0
- rl_pricing-0.5.0/requirements.in +15 -0
- rl_pricing-0.5.0/requirements.txt +14 -0
- rl_pricing-0.5.0/rl/__init__.py +0 -0
- rl_pricing-0.5.0/rl/autotrain/__init__.py +0 -0
- rl_pricing-0.5.0/rl/autotrain/r1.py +124 -0
- rl_pricing-0.5.0/rl/autotrain/training.py +933 -0
- rl_pricing-0.5.0/rl/bench/__init__.py +5 -0
- rl_pricing-0.5.0/rl/bench/cli.py +272 -0
- rl_pricing-0.5.0/rl/bench/data.py +383 -0
- rl_pricing-0.5.0/rl/bench/engine.py +173 -0
- rl_pricing-0.5.0/rl/bench/features.py +114 -0
- rl_pricing-0.5.0/rl/bench/figures.py +104 -0
- rl_pricing-0.5.0/rl/bench/gym_env.py +125 -0
- rl_pricing-0.5.0/rl/bench/leaderboard.py +424 -0
- rl_pricing-0.5.0/rl/bench/ledger.py +607 -0
- rl_pricing-0.5.0/rl/bench/market.py +178 -0
- rl_pricing-0.5.0/rl/bench/monthly.py +387 -0
- rl_pricing-0.5.0/rl/bench/policies/__init__.py +1 -0
- rl_pricing-0.5.0/rl/bench/policies/baselines.py +290 -0
- rl_pricing-0.5.0/rl/bench/policies/forecast.py +212 -0
- rl_pricing-0.5.0/rl/bench/policies/sb3.py +337 -0
- rl_pricing-0.5.0/rl/bench/policies/tradingagents.py +364 -0
- rl_pricing-0.5.0/rl/bench/policy.py +53 -0
- rl_pricing-0.5.0/rl/bench/runner.py +408 -0
- rl_pricing-0.5.0/rl/bench/scoring.py +279 -0
- rl_pricing-0.5.0/rl/bench/submission.py +124 -0
- rl_pricing-0.5.0/rl/bench/sweep.py +561 -0
- rl_pricing-0.5.0/rl/bench/tasks.py +206 -0
- rl_pricing-0.5.0/rl/bench/verdicts.py +265 -0
- rl_pricing-0.5.0/rl/cli.py +299 -0
- rl_pricing-0.5.0/rl/config/__init__.py +0 -0
- rl_pricing-0.5.0/rl/config/config.py +91 -0
- rl_pricing-0.5.0/rl/env/__init__.py +0 -0
- rl_pricing-0.5.0/rl/env/env_portfolio.py +261 -0
- rl_pricing-0.5.0/rl/env/env_stocktrading.py +406 -0
- rl_pricing-0.5.0/rl/forecast/__init__.py +0 -0
- rl_pricing-0.5.0/rl/forecast/lstm.py +238 -0
- rl_pricing-0.5.0/rl/marketdata/__init__.py +0 -0
- rl_pricing-0.5.0/rl/marketdata/sharadar.py +204 -0
- rl_pricing-0.5.0/rl/marketdata/synthetic.py +77 -0
- rl_pricing-0.5.0/rl/marketdata/yahoodownloader.py +130 -0
- rl_pricing-0.5.0/rl/model/__init__.py +0 -0
- rl_pricing-0.5.0/rl/model/models.py +584 -0
- rl_pricing-0.5.0/rl/preprocessing/__init__.py +0 -0
- rl_pricing-0.5.0/rl/preprocessing/data.py +26 -0
- rl_pricing-0.5.0/rl/preprocessing/preprocessors.py +248 -0
- rl_pricing-0.5.0/rl/trade/__init__.py +0 -0
- rl_pricing-0.5.0/rl/trade/backtest.py +93 -0
- rl_pricing-0.5.0/rl/trade/baselines.py +229 -0
- rl_pricing-0.5.0/rl/trade/execution.py +48 -0
- rl_pricing-0.5.0/rl/trade/metrics.py +154 -0
- rl_pricing-0.5.0/rl_pricing.egg-info/PKG-INFO +86 -0
- rl_pricing-0.5.0/rl_pricing.egg-info/SOURCES.txt +93 -0
- rl_pricing-0.5.0/rl_pricing.egg-info/dependency_links.txt +1 -0
- rl_pricing-0.5.0/rl_pricing.egg-info/entry_points.txt +2 -0
- rl_pricing-0.5.0/rl_pricing.egg-info/requires.txt +14 -0
- rl_pricing-0.5.0/rl_pricing.egg-info/top_level.txt +1 -0
- rl_pricing-0.5.0/ruff.toml +7 -0
- rl_pricing-0.5.0/setup.cfg +4 -0
- rl_pricing-0.5.0/setup.py +93 -0
- rl_pricing-0.5.0/tests/conftest.py +40 -0
- rl_pricing-0.5.0/tests/test_backtest_fees.py +87 -0
- rl_pricing-0.5.0/tests/test_bench_baselines.py +293 -0
- rl_pricing-0.5.0/tests/test_bench_core.py +133 -0
- rl_pricing-0.5.0/tests/test_bench_data.py +265 -0
- rl_pricing-0.5.0/tests/test_bench_forecast.py +148 -0
- rl_pricing-0.5.0/tests/test_bench_ledger.py +507 -0
- rl_pricing-0.5.0/tests/test_bench_monthly.py +204 -0
- rl_pricing-0.5.0/tests/test_bench_rl.py +224 -0
- rl_pricing-0.5.0/tests/test_bench_runner.py +320 -0
- rl_pricing-0.5.0/tests/test_bench_scoring.py +233 -0
- rl_pricing-0.5.0/tests/test_bench_sweep.py +232 -0
- rl_pricing-0.5.0/tests/test_bench_tradingagents.py +332 -0
- rl_pricing-0.5.0/tests/test_bench_verdicts.py +232 -0
- rl_pricing-0.5.0/tests/test_cli.py +86 -0
- rl_pricing-0.5.0/tests/test_data_eligibility.py +193 -0
- rl_pricing-0.5.0/tests/test_ensemble_options.py +306 -0
- rl_pricing-0.5.0/tests/test_env_stocktrading.py +227 -0
- rl_pricing-0.5.0/tests/test_evaluation.py +40 -0
- rl_pricing-0.5.0/tests/test_forecast.py +163 -0
- rl_pricing-0.5.0/tests/test_metrics_and_baselines.py +127 -0
- rl_pricing-0.5.0/tests/test_min_variance.py +167 -0
- rl_pricing-0.5.0/tests/test_other_envs.py +185 -0
- rl_pricing-0.5.0/tests/test_pipeline.py +350 -0
- rl_pricing-0.5.0/tests/test_preprocessors.py +151 -0
- rl_pricing-0.5.0/tests/test_sharadar.py +134 -0
- rl_pricing-0.5.0/tests/test_validation.py +92 -0
- rl_pricing-0.5.0/tests/test_yahoodownloader.py +152 -0
rl_pricing-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021-2026 Bicheng Wang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rl-pricing
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: A reproducibility lab for trading AI: causal backtests, a live forward-test track and a pre-open decision ledger for RL, LLM and forecasting policies.
|
|
5
|
+
Home-page: https://github.com/BichengWang/RL-pricing
|
|
6
|
+
Author: Bicheng Wang
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Project-URL: Source, https://github.com/BichengWang/RL-pricing
|
|
9
|
+
Project-URL: Issues, https://github.com/BichengWang/RL-pricing/issues
|
|
10
|
+
Project-URL: Leaderboard, https://github.com/BichengWang/RL-pricing/blob/main/leaderboard/LEADERBOARD.md
|
|
11
|
+
Project-URL: Paper, https://arxiv.org/abs/2609.31870
|
|
12
|
+
Keywords: reinforcement learning,portfolio management,backtesting,benchmark,leaderboard
|
|
13
|
+
Platform: any
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
23
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: numpy>=1.24
|
|
29
|
+
Requires-Dist: pandas>=2.0
|
|
30
|
+
Requires-Dist: stockstats>=0.6.2
|
|
31
|
+
Requires-Dist: yfinance>=0.2.40
|
|
32
|
+
Requires-Dist: matplotlib>=3.7
|
|
33
|
+
Requires-Dist: gymnasium>=0.29.1
|
|
34
|
+
Requires-Dist: stable-baselines3>=2.3.2
|
|
35
|
+
Requires-Dist: torch>=2.0
|
|
36
|
+
Provides-Extra: test
|
|
37
|
+
Requires-Dist: pytest>=7.0; extra == "test"
|
|
38
|
+
Provides-Extra: lint
|
|
39
|
+
Requires-Dist: ruff>=0.5; extra == "lint"
|
|
40
|
+
Dynamic: author
|
|
41
|
+
Dynamic: classifier
|
|
42
|
+
Dynamic: description
|
|
43
|
+
Dynamic: description-content-type
|
|
44
|
+
Dynamic: home-page
|
|
45
|
+
Dynamic: keywords
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
Dynamic: license-expression
|
|
48
|
+
Dynamic: platform
|
|
49
|
+
Dynamic: project-url
|
|
50
|
+
Dynamic: provides-extra
|
|
51
|
+
Dynamic: requires-dist
|
|
52
|
+
Dynamic: requires-python
|
|
53
|
+
Dynamic: summary
|
|
54
|
+
|
|
55
|
+
# RL-pricing
|
|
56
|
+
|
|
57
|
+
A reproducibility lab for trading AI. RL-pricing re-tests published claims
|
|
58
|
+
about deep RL agents, LLM trading agents and forecasters under one
|
|
59
|
+
pre-registered protocol. This package holds the lab's instruments:
|
|
60
|
+
|
|
61
|
+
- `rl-pricing bench`: a causal backtesting benchmark. Policies decide at the
|
|
62
|
+
close and fill at the next open with fees; learned policies run over
|
|
63
|
+
several seeds; frozen policies are scored on a live forward-test track; and
|
|
64
|
+
a decision ledger records LLM agents' trades before each US market open.
|
|
65
|
+
- `rl-pricing --mode train|backtest|ensemble|lstm`: the share-trading toolkit
|
|
66
|
+
that trains and backtests Stable-Baselines3 agents (A2C, PPO, DDPG, TD3,
|
|
67
|
+
SAC), a rolling ensemble and an LSTM forecaster on daily equity data.
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install rl-pricing
|
|
71
|
+
rl-pricing bench tasks # list the benchmark tasks
|
|
72
|
+
rl-pricing bench data us-sectors # download a task's data and print its hash
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The import package is `rl`, so this distribution can't share an environment
|
|
76
|
+
with the unrelated `rl` (GNU Readline bindings) distribution. Leaderboard
|
|
77
|
+
submissions, results and reports live in the
|
|
78
|
+
[repository](https://github.com/BichengWang/RL-pricing): clone it to run the
|
|
79
|
+
submissions, or pass `--submissions-root` to use your own.
|
|
80
|
+
|
|
81
|
+
- [Verdicts, findings and leaderboard](https://github.com/BichengWang/RL-pricing#readme)
|
|
82
|
+
- [Paper: Wang & Zhang, arXiv:2609.31870](https://arxiv.org/abs/2609.31870)
|
|
83
|
+
|
|
84
|
+
The training toolkit's environment, preprocessing and training code are
|
|
85
|
+
adapted from [FinRL](https://github.com/AI4Finance-Foundation/FinRL), which is
|
|
86
|
+
MIT-licensed.
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# RL-pricing: a reproducibility lab for trading AI
|
|
2
|
+
|
|
3
|
+
[](https://github.com/BichengWang/RL-pricing/actions/workflows/tests.yml)
|
|
4
|
+
[](https://github.com/BichengWang/RL-pricing/actions/workflows/bench.yml)
|
|
5
|
+
[](https://arxiv.org/abs/2609.31870)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
8
|
+
We re-test published trading-AI claims (deep RL, LLM agents, forecasters)
|
|
9
|
+
under one pre-registered protocol, and publish every verdict next to the
|
|
10
|
+
authors' reply. That includes the verdicts against our own paper. The instruments are public:
|
|
11
|
+
a causal backtesting benchmark, a live track scored only on market data that
|
|
12
|
+
did not exist when a policy was published, and a ledger of decisions
|
|
13
|
+
committed before each US market open.
|
|
14
|
+
|
|
15
|
+
## Verdicts
|
|
16
|
+
|
|
17
|
+
<!-- reports:start -->
|
|
18
|
+
| Report | Claim | Level | Claimed | Ours (95% interval) | Verdict |
|
|
19
|
+
| --- | --- | --- | --- | --- | --- |
|
|
20
|
+
| [r0-wang-zhang-2026](reports/r0-wang-zhang-2026/report.md) | `ddpg-annual-return` (annual_return) | L2 | 55.5% | 24.6% [17.3%, 31.9%] | ✗ does not hold |
|
|
21
|
+
| [r0-wang-zhang-2026](reports/r0-wang-zhang-2026/report.md) | `ddpg-sharpe` (sharpe) | L2 | 1.38 | 1.16 [0.93, 1.39] | ◐ partly holds |
|
|
22
|
+
| [r0-wang-zhang-2026](reports/r0-wang-zhang-2026/report.md) | `td3-sharpe` (sharpe) | L2 | 1.37 | 1.10 [0.69, 1.52] | ◐ partly holds |
|
|
23
|
+
| [r0-wang-zhang-2026](reports/r0-wang-zhang-2026/report.md) | `sac-sharpe` (sharpe) | L2 | 1.33 | 1.23 [1.07, 1.39] | ◐ partly holds |
|
|
24
|
+
| [r0-wang-zhang-2026](reports/r0-wang-zhang-2026/report.md) | `ppo-sharpe` (sharpe) | L2 | 1.09 | 1.17 [0.90, 1.44] | ◐ partly holds |
|
|
25
|
+
| [r0-wang-zhang-2026](reports/r0-wang-zhang-2026/report.md) | `a2c-sharpe` (sharpe) | L2 | 0.82 | 1.09 [0.91, 1.27] | ◐ partly holds |
|
|
26
|
+
| [r0-wang-zhang-2026](reports/r0-wang-zhang-2026/report.md) | `lstm-max-drawdown` (max_drawdown) | L2 | -9.6% | -26.5% [-29.4%, -23.7%] | ? inconclusive |
|
|
27
|
+
| [r0-wang-zhang-2026](reports/r0-wang-zhang-2026/report.md) | `lstm-sharpe` (sharpe) | L2 | 1.19 | 0.75 [0.39, 1.12] | ? inconclusive |
|
|
28
|
+
|
|
29
|
+
Verdicts: ✅ holds, ◐ partly holds, ✗ does not hold, ? inconclusive. [How a verdict is decided](reports/README.md#how-a-verdict-is-decided).
|
|
30
|
+
<!-- reports:end -->
|
|
31
|
+
|
|
32
|
+
| Next | Claim under test | Due |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| R1 | FinRL ensemble ([Yang et al., ICAIF 2020](https://arxiv.org/abs/2511.12120)): Sharpe 1.30 vs the DJIA's 0.47, 2016–2020 | 2026-12-01 |
|
|
35
|
+
| R2 | [TradingAgents](https://arxiv.org/abs/2412.20138) backtest: Sharpe 5.6–8.2 on AAPL, GOOGL, AMZN in 2024 Q1, replicated with a check for whether the models remember that period | 2027-01-05 |
|
|
36
|
+
| R3 | TradingAgents run live on the same three stocks for three months, each decision committed before the open ([pre-registration](reports/r3-tradingagents-live/preregistration.md)) | 2027-02-15 |
|
|
37
|
+
|
|
38
|
+
Authors get each draft seven days before publication. To nominate a claim,
|
|
39
|
+
open an issue titled `Nominate: <paper>` with the quoted claim and a link to
|
|
40
|
+
the code.
|
|
41
|
+
|
|
42
|
+
## How the lab works
|
|
43
|
+
|
|
44
|
+
- **Pre-registered.** Each report's test plan is committed before anything
|
|
45
|
+
runs; the commit time is the evidence that the plan came first.
|
|
46
|
+
- **Three levels.** L1 replicates with the authors' code and setup. L2
|
|
47
|
+
re-tests under this repository's protocol: next-open fills, fees, at least
|
|
48
|
+
five seeds, survivorship-free data. L3 tries new windows and, for anything
|
|
49
|
+
that can run daily, the live ledger.
|
|
50
|
+
- **Verdicts by rule:** holds, partly holds, does not hold, or inconclusive,
|
|
51
|
+
decided by thresholds fixed in the pre-registration
|
|
52
|
+
([rules and template](reports/README.md)).
|
|
53
|
+
- **LLM agents only count live.** Their historical backtests can be
|
|
54
|
+
contaminated by training data. The ledger commits each decision before the
|
|
55
|
+
open, and scoring checks the commit against GitHub's own run records.
|
|
56
|
+
- **Evidence is committed.** Each report ships its per-seed results, input
|
|
57
|
+
hashes and one command that reproduces them.
|
|
58
|
+
|
|
59
|
+
## R0: our own paper
|
|
60
|
+
|
|
61
|
+
Full report: [`reports/r0-wang-zhang-2026/report.md`](reports/r0-wang-zhang-2026/report.md).
|
|
62
|
+
|
|
63
|
+
Our preprint ([Wang & Zhang, arXiv:2609.31870](https://arxiv.org/abs/2609.31870))
|
|
64
|
+
reported DDPG with a 55.5% annual return and Sharpe 1.38 on 20 large-cap
|
|
65
|
+
stocks in 2019–2020, with TD3 and SAC close behind. Those are single runs on a
|
|
66
|
+
universe picked in 2021 from the largest companies, which the paper itself
|
|
67
|
+
lists as limitations.
|
|
68
|
+
|
|
69
|
+
We re-ran it three ways, 5 seeds per agent, same 20 stocks, same 2019–2020
|
|
70
|
+
window, 0.1% fees:
|
|
71
|
+
|
|
72
|
+
- **Share env + crash rule**: the paper's own share-trading environment
|
|
73
|
+
(`python main.py --mode train`, now with next-open fills), including its
|
|
74
|
+
default rule that sells everything when a market-turbulence index spikes.
|
|
75
|
+
- **Share env, no rule**: the same with `--no-turbulence`.
|
|
76
|
+
- **Benchmark**: this repository's `paper-2021` task (portfolio weights, no
|
|
77
|
+
hand-coded exits).
|
|
78
|
+
|
|
79
|
+
Sharpe ratio, mean ± sd over 5 seeds [best seed]:
|
|
80
|
+
|
|
81
|
+
| Agent | Reported (1 run) | Share env + crash rule | Share env, no rule | Benchmark |
|
|
82
|
+
| --- | --- | --- | --- | --- |
|
|
83
|
+
| DDPG | 1.38 | 1.16 ± 0.19 [1.43] | 1.06 ± 0.18 [1.24] | 0.70 ± 0.17 [0.97] |
|
|
84
|
+
| TD3 | 1.37 | 1.10 ± 0.34 [1.37] | 1.00 ± 0.30 [1.37] | 0.70 ± 0.21 [1.01] |
|
|
85
|
+
| SAC | 1.33 | 1.23 ± 0.13 [1.42] | 1.23 ± 0.18 [1.49] | 0.66 ± 0.26 [0.82] |
|
|
86
|
+
| PPO | 1.09 | 1.17 ± 0.21 [1.32] | 0.95 ± 0.21 [1.21] | 0.98 ± 0.04 [1.02] |
|
|
87
|
+
| A2C | 0.82 | 1.09 ± 0.15 [1.27] | 0.97 ± 0.15 [1.16] | 1.03 ± 0.01 [1.05] |
|
|
88
|
+
| LSTM forecast | 1.19 | – | – | 0.75 ± 0.29 [1.08] |
|
|
89
|
+
| *1/N buy and hold* | – | *1.10* | *1.10* | *1.11* |
|
|
90
|
+
|
|
91
|
+
What holds up and what doesn't:
|
|
92
|
+
|
|
93
|
+
- **The 55.5% return does not.** The best of the 50 share-environment runs
|
|
94
|
+
earned 46% a year and the median 26%. Holding the 20 stocks in equal
|
|
95
|
+
weight earned 29.7%, so the hindsight-chosen universe and the 2019–2020
|
|
96
|
+
bull market account for most of the headline.
|
|
97
|
+
- **The Sharpe ratios are best-of-five, not typical.** Values like the
|
|
98
|
+
reported 1.33–1.38 show up as the best seed for most agents.
|
|
99
|
+
- **The crash rule is not learning.** With it on, all 25 runs were moved to
|
|
100
|
+
cash on the same five sessions of March 2020 by the environment, not the agent.
|
|
101
|
+
Switching it off drops every agent's mean Sharpe except SAC's below 1/N.
|
|
102
|
+
- **SAC is the one survivor, but not a significant one.** Without the rule
|
|
103
|
+
its seed-averaged Sharpe is 1.32 against 1/N's 1.10, alpha 7.5% a year. Over
|
|
104
|
+
a two-year window that is not significant (bootstrap p = 0.13, alpha
|
|
105
|
+
*t* = 1.6).
|
|
106
|
+
- **The benchmark environment flips the picture.** There the same agents
|
|
107
|
+
trail 1/N. Which difference drives that is open: share counts versus
|
|
108
|
+
weights, the features, or the share environment's per-trade limits.
|
|
109
|
+
|
|
110
|
+
Per-seed results, equity curves, commands and the input-data hash are in
|
|
111
|
+
[`reports/r0-wang-zhang-2026/evidence/`](reports/r0-wang-zhang-2026/evidence/).
|
|
112
|
+
|
|
113
|
+
## Benchmark findings
|
|
114
|
+
|
|
115
|
+

|
|
116
|
+
|
|
117
|
+
Historical track, test windows 2018–2025 (US ETFs) and 2023–2025 (crypto),
|
|
118
|
+
Stable-Baselines3 agents with default and tuned hyperparameters, 5 seeds each:
|
|
119
|
+
|
|
120
|
+
- **No learned policy beats 1/N buy-and-hold here.** All 30 RL and LSTM entries
|
|
121
|
+
across the four tasks have a lower seed-averaged Sharpe ratio than holding
|
|
122
|
+
every asset in equal weight. Only 5 of their 150 individual seeds do better,
|
|
123
|
+
so cherry-picking one would make a publishable-looking result.
|
|
124
|
+
- **Tuning doesn't close the gap.** A declared sweep of 8 configurations each
|
|
125
|
+
for PPO and SAC, selected on validation data only, picks configurations that
|
|
126
|
+
still trail 1/N on every task. SAC's choice helps on the US tasks and
|
|
127
|
+
collapses on crypto (Sharpe 0.07 ± 0.49). The deflated Sharpe column
|
|
128
|
+
accounts for the 8 trials.
|
|
129
|
+
- **The off-policy agents churn themselves to death.** SAC, TD3 and DDPG
|
|
130
|
+
turn over 46–326× their equity per year. On the US tasks their alpha
|
|
131
|
+
against 1/N is negative, with *t*-statistics down to −2.8.
|
|
132
|
+
- **A2C rediscovers 1/N.** Its five seeds on US sectors land at Sharpe
|
|
133
|
+
0.67 ± 0.01 against 1/N's 0.68: the softmax policy learns to stay close to
|
|
134
|
+
equal weights.
|
|
135
|
+
- **The one significant win is not RL.** In crypto, long-only minimum
|
|
136
|
+
variance beats 1/N (ΔSharpe +0.86, bootstrap p < 0.001), mostly by holding
|
|
137
|
+
the two least volatile coins, BTC (50% on average) and BNB (36%).
|
|
138
|
+
|
|
139
|
+
Better configurations are what the leaderboard is for: submit one, and state
|
|
140
|
+
how many you tried.
|
|
141
|
+
|
|
142
|
+
## Leaderboard
|
|
143
|
+
|
|
144
|
+
<!-- leaderboard:start -->
|
|
145
|
+
| Track | Task | # | Strategy | Sharpe | CAGR | Max DD | ΔSharpe vs 1/N | DSR |
|
|
146
|
+
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
|
147
|
+
| historical | `crypto-majors` | 1 | Minimum variance | 1.64 | 90.9% | -33.3% | +0.86 (p<0.001) | 1.00 |
|
|
148
|
+
| historical | `crypto-majors` | 2 | Inverse volatility | 0.88 | 40.7% | -46.8% | +0.10 (p=0.089) | 0.94 |
|
|
149
|
+
| historical | `crypto-majors` | 3 | Momentum (top 3) | 0.84 | 37.8% | -47.9% | +0.06 (p=0.401) | 0.93 |
|
|
150
|
+
| historical | `crypto-majors` | 4 | **1/N buy and hold** ◆ | 0.78 | 32.7% | -44.5% | – | 0.91 |
|
|
151
|
+
| historical | `crypto-majors` | 6 | PPO (tuned) | 0.71 ± 0.22 | 26.9% | -49.3% | -0.04 (p=0.621) | 0.43 |
|
|
152
|
+
| historical | `us-multi-asset` | 1 | **1/N buy and hold** ◆ | 0.73 | 8.9% | -26.6% | – | 0.98 |
|
|
153
|
+
| historical | `us-multi-asset` | 2 | Momentum (top 3) | 0.72 | 9.9% | -23.7% | -0.01 (p=0.506) | 0.98 |
|
|
154
|
+
| historical | `us-multi-asset` | 3 | 1/N monthly rebalance | 0.69 | 8.0% | -25.8% | -0.04 (p=0.827) | 0.97 |
|
|
155
|
+
| historical | `us-multi-asset` | 4 | A2C | 0.66 ± 0.02 | 7.1% | -23.8% | -0.06 (p=0.940) | 0.97 |
|
|
156
|
+
| historical | `us-sectors` | 1 | 1/N monthly rebalance | 0.69 | 11.6% | -36.7% | +0.01 (p=0.449) | 0.97 |
|
|
157
|
+
| historical | `us-sectors` | 2 | **1/N buy and hold** ◆ | 0.68 | 11.5% | -35.5% | – | 0.97 |
|
|
158
|
+
| historical | `us-sectors` | 3 | A2C | 0.67 ± 0.01 | 10.3% | -34.3% | -0.01 (p=0.650) | 0.97 |
|
|
159
|
+
| historical | `paper-2021` (re-evaluation) | – | Momentum (top 3) | 1.31 | 48.6% | -30.4% | +0.20 (p=0.240) | 0.96 |
|
|
160
|
+
| historical | `paper-2021` (re-evaluation) | – | **1/N buy and hold** ◆ | 1.11 | 29.9% | -29.4% | – | 0.94 |
|
|
161
|
+
| historical | `paper-2021` (re-evaluation) | – | 1/N monthly rebalance | 1.04 | 26.7% | -29.5% | -0.07 (p=0.777) | 0.93 |
|
|
162
|
+
| historical | `paper-2021` (re-evaluation) | – | A2C | 1.03 ± 0.01 | 25.1% | -28.2% | -0.08 (p=0.825) | 0.92 |
|
|
163
|
+
|
|
164
|
+
Full tables: [leaderboard/LEADERBOARD.md](leaderboard/LEADERBOARD.md).
|
|
165
|
+
<!-- leaderboard:end -->
|
|
166
|
+
|
|
167
|
+
## Why trust these numbers
|
|
168
|
+
|
|
169
|
+
| | This benchmark | Common in RL-trading papers |
|
|
170
|
+
| --- | --- | --- |
|
|
171
|
+
| Execution | Decide at the close, fill at the next open, proportional fees | Fill at the same close used to decide; often no fees |
|
|
172
|
+
| Universe | Fixed ETFs; crypto top-10 by volume *before* the data starts, delistings included | Today's index members, back-tested into the past |
|
|
173
|
+
| Randomness | 5 seeds per learned policy, mean ± sd, every seed plotted | One run |
|
|
174
|
+
| Model selection | Validation window before the test; declared `trials` deflate the Sharpe | Tuned on the test period |
|
|
175
|
+
| Out-of-sample | Live track: frozen policy, scored only on sessions after its public freeze | One fixed historical window |
|
|
176
|
+
| Metrics | One implementation for everyone; beta and alpha against 1/N | Per-paper definitions |
|
|
177
|
+
|
|
178
|
+
The live track is the part nobody can overfit. A policy is fitted on all
|
|
179
|
+
data available today and its artifacts are committed with SHA-256 hashes. A
|
|
180
|
+
CI job on `main` then stamps the time the freeze became public
|
|
181
|
+
(`leaderboard/publications.json`, which pull requests may not edit), and
|
|
182
|
+
from then on it is scored monthly on sessions that start after that stamp.
|
|
183
|
+
The first live scores appear after the next monthly run.
|
|
184
|
+
|
|
185
|
+
## Quick start
|
|
186
|
+
|
|
187
|
+
Python 3.10 or newer:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
git clone https://github.com/BichengWang/RL-pricing.git
|
|
191
|
+
cd RL-pricing
|
|
192
|
+
python -m venv .venv && source .venv/bin/activate
|
|
193
|
+
python -m pip install -e .
|
|
194
|
+
|
|
195
|
+
rl-pricing bench tasks # list tasks
|
|
196
|
+
rl-pricing bench run --task synthetic --submission momentum --out-root /tmp/board
|
|
197
|
+
rl-pricing bench run --task synthetic --submission ppo --seeds 2 --out-root /tmp/board
|
|
198
|
+
rl-pricing bench leaderboard --out-root /tmp/board --no-readme
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
The `synthetic` task is offline random walks with no edge by construction.
|
|
202
|
+
Real tasks download data on first use (`rl-pricing bench data us-sectors`)
|
|
203
|
+
into `datasets/bench/`. PPO takes one to two minutes per seed on a laptop CPU.
|
|
204
|
+
|
|
205
|
+
## Submit a policy
|
|
206
|
+
|
|
207
|
+
A policy maps the history up to today's close to long-only target weights,
|
|
208
|
+
which fill at the next open. Here is a complete one:
|
|
209
|
+
|
|
210
|
+
```python
|
|
211
|
+
# submissions/low-vol-half/policy.py
|
|
212
|
+
import numpy as np
|
|
213
|
+
|
|
214
|
+
from rl.bench.policy import Policy
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class LowVolHalf(Policy):
|
|
218
|
+
"""Equal-weight the calmer half of the listed assets."""
|
|
219
|
+
|
|
220
|
+
def act(self, view):
|
|
221
|
+
closes = view.history.window(64).close
|
|
222
|
+
vol = np.nanstd(np.diff(np.log(closes), axis=0), axis=0)
|
|
223
|
+
vol = np.where(view.listed & np.isfinite(vol), vol, np.inf)
|
|
224
|
+
keep = np.argsort(vol)[: max(1, view.listed.sum() // 2)]
|
|
225
|
+
weights = np.zeros(len(view.tickers))
|
|
226
|
+
weights[keep] = 1 / len(keep)
|
|
227
|
+
return weights
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```json
|
|
231
|
+
{
|
|
232
|
+
"name": "Low-vol half",
|
|
233
|
+
"kind": "other",
|
|
234
|
+
"policy": "policy.py:LowVolHalf",
|
|
235
|
+
"trials": 3,
|
|
236
|
+
"authors": ["Your Name"],
|
|
237
|
+
"description": "Equal-weight the half of the assets with the lowest 63-day volatility."
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Learning policies implement `fit(history, validation_start, seed)` as well:
|
|
242
|
+
train on sessions before `validation_start`, select on the rest, and set
|
|
243
|
+
`stochastic = True` to be evaluated over several seeds. They also implement
|
|
244
|
+
`save`/`load` so the frozen live version can be restored. See
|
|
245
|
+
[`rl/bench/policies/sb3.py`](rl/bench/policies/sb3.py) for a full example.
|
|
246
|
+
Set `trials` honestly to the number of configurations you tried.
|
|
247
|
+
|
|
248
|
+
Then:
|
|
249
|
+
|
|
250
|
+
1. `rl-pricing bench validate` and `rl-pricing bench run --task <task> --submission <id>` locally.
|
|
251
|
+
2. Open a pull request with `submissions/<id>/` and your `leaderboard/historical/` records.
|
|
252
|
+
CI checks that the submission builds and the baselines reproduce.
|
|
253
|
+
3. On merge, CI freezes the policy on today's data (or publishes your
|
|
254
|
+
committed freeze from `rl-pricing bench freeze`) and the monthly job scores
|
|
255
|
+
it live from then on.
|
|
256
|
+
|
|
257
|
+
## Tasks
|
|
258
|
+
|
|
259
|
+
| Task | Universe | Test window | Fee per side | Why it is survivorship-free |
|
|
260
|
+
| --- | --- | --- | --- | --- |
|
|
261
|
+
| `us-sectors` | 9 SPDR sector ETFs | 2018–2025 | 5 bps | all listed since 1998 |
|
|
262
|
+
| `us-multi-asset` | SPY, QQQ, IWM, EFA, EEM, TLT, IEF, LQD, GLD, VNQ | 2018–2025 | 5 bps | all listed since 2004 |
|
|
263
|
+
| `crypto-majors` | top 10 Binance USDT pairs by Q2-2018 volume | 2023–2025 | 10 bps | chosen before the data starts; BCC and EOS delist mid-sample |
|
|
264
|
+
| `paper-2021` | the 2021 paper's 20 large caps | 2019–2020 | 10 bps | *it is not*: shown as a re-evaluation, not ranked |
|
|
265
|
+
| `synthetic` | 5 random walks | 2018–2019 | 10 bps | offline demo |
|
|
266
|
+
|
|
267
|
+
Each task trains before its validation window, selects on validation, and
|
|
268
|
+
reports the test window. Definitions live in [`rl/bench/tasks.py`](rl/bench/tasks.py).
|
|
269
|
+
|
|
270
|
+
## How scoring works
|
|
271
|
+
|
|
272
|
+
- **Execution** ([`rl/bench/engine.py`](rl/bench/engine.py)): targets set at
|
|
273
|
+
close *t* fill at open *t+1* with fees solved exactly on traded notional.
|
|
274
|
+
Weights are long-only and sum to at most one; the rest is cash at 0%. A
|
|
275
|
+
delisted holding is sold at its last close. RL agents train in a gym
|
|
276
|
+
environment that uses the same `Account`, so training and evaluation
|
|
277
|
+
accounting are identical.
|
|
278
|
+
- **Metrics** ([`rl/bench/scoring.py`](rl/bench/scoring.py)): Sharpe, CAGR,
|
|
279
|
+
max drawdown, annual turnover, and beta/alpha against 1/N (Newey-West *t*).
|
|
280
|
+
ΔSharpe against 1/N comes with a paired stationary-bootstrap p-value. The
|
|
281
|
+
deflated Sharpe ratio (Bailey & López de Prado) accounts for declared
|
|
282
|
+
`trials`. Full definitions are in [`leaderboard/LEADERBOARD.md`](leaderboard/LEADERBOARD.md).
|
|
283
|
+
- **Records**: every run stores its daily equity curve per seed, data
|
|
284
|
+
SHA-256, software versions and commit under `leaderboard/`, so all
|
|
285
|
+
metrics can be recomputed.
|
|
286
|
+
|
|
287
|
+
## Data
|
|
288
|
+
|
|
289
|
+
US tasks use Yahoo Finance prices and dividends, downloaded to a local cache.
|
|
290
|
+
Yahoo's terms prohibit redistribution, so the repository ships no prices,
|
|
291
|
+
only derived results. Prices are adjusted for dividends forward from each
|
|
292
|
+
task's first session rather than taken from Yahoo's adjusted close, whose
|
|
293
|
+
last digits change between identical requests. A past session therefore
|
|
294
|
+
keeps its prices as new sessions arrive, and replaying the same window
|
|
295
|
+
reproduces its data hash; a changed hash means Yahoo revised its
|
|
296
|
+
history. Crypto uses
|
|
297
|
+
[Binance Vision](https://data.binance.vision) daily klines, each archive
|
|
298
|
+
verified against Binance's SHA-256 checksum. Binance Vision data is licensed
|
|
299
|
+
CC BY-NC-SA 4.0; the crypto results here derive from it, with attribution,
|
|
300
|
+
for non-commercial research.
|
|
301
|
+
|
|
302
|
+
## Limitations
|
|
303
|
+
|
|
304
|
+
- Fees are proportional; spread, market impact and borrowing costs are not
|
|
305
|
+
modeled, and cash earns nothing.
|
|
306
|
+
- Daily bars only; adjusted prices model reinvested distributions rather
|
|
307
|
+
than exact exchange fills.
|
|
308
|
+
- Eight-year and three-year test windows are a few market regimes, which is
|
|
309
|
+
why the live track exists.
|
|
310
|
+
- Reference RL agents are untuned and use one feature set
|
|
311
|
+
([`rl/bench/features.py`](rl/bench/features.py)); they are a floor, not
|
|
312
|
+
the best RL can do.
|
|
313
|
+
|
|
314
|
+
## Training toolkit
|
|
315
|
+
|
|
316
|
+
The original FinRL-style training pipeline (share trading, portfolio
|
|
317
|
+
allocation, LSTM forecaster, rolling ensemble via `python main.py --mode ...`)
|
|
318
|
+
is still available and documented in [`docs/toolkit.md`](docs/toolkit.md).
|
|
319
|
+
|
|
320
|
+
## Development
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
pip install -e ".[test,lint]"
|
|
324
|
+
python -m pytest # offline: synthetic data and fixtures
|
|
325
|
+
ruff check .
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Use `type(scope): title` for pull request titles. The
|
|
329
|
+
[PR template](.github/pull_request_template.md) asks for a short summary and
|
|
330
|
+
verification results.
|
|
331
|
+
|
|
332
|
+
## Citing
|
|
333
|
+
|
|
334
|
+
GitHub's "Cite this repository" uses [`CITATION.cff`](CITATION.cff). The
|
|
335
|
+
original study is Wang & Zhang, *Deep Reinforcement Learning for Equity
|
|
336
|
+
Trading: Benchmarking Actor-Critic Methods with Forward Retraining*,
|
|
337
|
+
[arXiv:2609.31870](https://arxiv.org/abs/2609.31870)
|
|
338
|
+
([local PDF](docs/Wang_Zhang_2021_Deep_Learning_Stock_Trading_arxiv.pdf)).
|
|
339
|
+
|
|
340
|
+
## License
|
|
341
|
+
|
|
342
|
+
MIT; see [LICENSE](LICENSE). The training toolkit's environment,
|
|
343
|
+
preprocessing and training code are adapted from the MIT-licensed
|
|
344
|
+
[FinRL](https://github.com/AI4Finance-Foundation/FinRL) library.
|
rl_pricing-0.5.0/main.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# data handling
|
|
2
|
+
numpy>=1.24
|
|
3
|
+
pandas>=2.0
|
|
4
|
+
stockstats>=0.6.2
|
|
5
|
+
yfinance>=0.2.40
|
|
6
|
+
|
|
7
|
+
# plot
|
|
8
|
+
matplotlib>=3.7
|
|
9
|
+
|
|
10
|
+
# Model Building Requirements
|
|
11
|
+
gymnasium>=0.29.1
|
|
12
|
+
stable-baselines3>=2.3.2
|
|
13
|
+
torch>=2.0
|
|
14
|
+
|
|
15
|
+
# Test and lint tools are extras in setup.py: pip install -e ".[test]"
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Versions the test suite was last run with (Python 3.13).
|
|
2
|
+
# requirements.in lists the supported ranges; setup.py installs from it.
|
|
3
|
+
#
|
|
4
|
+
# For a CPU-only PyTorch (much smaller download), install it first:
|
|
5
|
+
# pip install torch --index-url https://download.pytorch.org/whl/cpu
|
|
6
|
+
gymnasium==1.4.0
|
|
7
|
+
matplotlib==3.11.2
|
|
8
|
+
numpy==2.5.3
|
|
9
|
+
pandas==3.0.5
|
|
10
|
+
pytest==9.1.1
|
|
11
|
+
stable-baselines3==2.9.0
|
|
12
|
+
stockstats==0.6.9
|
|
13
|
+
torch==2.14.1
|
|
14
|
+
yfinance==1.7.0
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Driver for the R1 runs: the toolkit's ensemble with the FinRL authors' recipe.
|
|
2
|
+
|
|
3
|
+
Sets what the toolkit lets us match from Yang, Liu, Zhong and Walid (ICAIF
|
|
4
|
+
2020): the four indicators (``macd``, ``rsi_30``, ``cci_30``, ``dx_30``), the
|
|
5
|
+
training steps per algorithm (A2C 30,000, PPO 100,000, DDPG 10,000), PPO with
|
|
6
|
+
``ent_coef`` 0.005 and 128-step rollouts in minibatches of 16 (the authors'
|
|
7
|
+
``nminibatches=8``), and DDPG with Ornstein-Uhlenbeck action noise of sigma
|
|
8
|
+
0.5. A2C and the rest of DDPG keep the toolkit defaults, as does everything
|
|
9
|
+
else (0.1% fees per side, $1,000,000, ``hmax`` 100, reward scaling 1e-4,
|
|
10
|
+
63-session rebalance and validation windows, next-open fills, observation
|
|
11
|
+
normalisation, refit of the winner). Each algorithm also trades its own
|
|
12
|
+
account (``standalone_accounts``).
|
|
13
|
+
|
|
14
|
+
Prices come from a CSV in the toolkit format (``date,tic,open,high,low,close,
|
|
15
|
+
volume``), e.g. from :mod:`rl.marketdata.sharadar`::
|
|
16
|
+
|
|
17
|
+
python -m rl.autotrain.r1 --data-file prices.csv --seed 0 --run-name r1_a_s0
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import argparse
|
|
21
|
+
import copy
|
|
22
|
+
import logging
|
|
23
|
+
|
|
24
|
+
from rl.autotrain.training import TrainConfig, run_ensemble
|
|
25
|
+
from rl.config import config
|
|
26
|
+
|
|
27
|
+
AUTHORS_INDICATORS = ("macd", "rsi_30", "cci_30", "dx_30")
|
|
28
|
+
AUTHORS_TIMESTEPS = {"a2c": 30_000, "ppo": 100_000, "ddpg": 10_000}
|
|
29
|
+
AUTHORS_DDPG_NOISE_SIGMA = 0.5
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def authors_model_kwargs(ddpg_noise_sigma=AUTHORS_DDPG_NOISE_SIGMA):
|
|
33
|
+
"""Per-algorithm model settings (each replaces the config.py default)."""
|
|
34
|
+
return {
|
|
35
|
+
"a2c": copy.deepcopy(config.A2C_PARAMS),
|
|
36
|
+
# 128 steps in 8 minibatches; every other PPO setting is stable-baselines3's default.
|
|
37
|
+
"ppo": {"n_steps": 128, "batch_size": 16, "ent_coef": 0.005},
|
|
38
|
+
"ddpg": {
|
|
39
|
+
**copy.deepcopy(config.DDPG_PARAMS),
|
|
40
|
+
"action_noise": {"type": "ornstein_uhlenbeck", "sigma": ddpg_noise_sigma},
|
|
41
|
+
},
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def r1_config(
|
|
46
|
+
data_file,
|
|
47
|
+
*,
|
|
48
|
+
seed,
|
|
49
|
+
use_turbulence=True,
|
|
50
|
+
ticker_list=None,
|
|
51
|
+
start_date="2009-01-02",
|
|
52
|
+
start_trade_date="2016-01-04",
|
|
53
|
+
end_date="2026-01-01",
|
|
54
|
+
ddpg_noise_sigma=AUTHORS_DDPG_NOISE_SIGMA,
|
|
55
|
+
ensemble_timesteps=None,
|
|
56
|
+
standalone_accounts=True,
|
|
57
|
+
run_name=None,
|
|
58
|
+
results_dir=config.RESULTS_DIR,
|
|
59
|
+
**overrides,
|
|
60
|
+
):
|
|
61
|
+
"""The :class:`TrainConfig` of one R1 ensemble run.
|
|
62
|
+
|
|
63
|
+
``end_date`` is exclusive (the default includes 2025-12-31). ``overrides``
|
|
64
|
+
set any other :class:`TrainConfig` field.
|
|
65
|
+
"""
|
|
66
|
+
settings = dict(
|
|
67
|
+
agent="ensemble",
|
|
68
|
+
task="trading",
|
|
69
|
+
data_source="csv",
|
|
70
|
+
data_file=data_file,
|
|
71
|
+
ticker_list=ticker_list,
|
|
72
|
+
start_date=start_date,
|
|
73
|
+
start_trade_date=start_trade_date,
|
|
74
|
+
end_date=end_date,
|
|
75
|
+
tech_indicator_list=list(AUTHORS_INDICATORS),
|
|
76
|
+
use_turbulence=use_turbulence,
|
|
77
|
+
ensemble_timesteps=dict(AUTHORS_TIMESTEPS if ensemble_timesteps is None else ensemble_timesteps),
|
|
78
|
+
ensemble_model_kwargs=authors_model_kwargs(ddpg_noise_sigma),
|
|
79
|
+
standalone_accounts=standalone_accounts,
|
|
80
|
+
seed=seed,
|
|
81
|
+
run_name=run_name,
|
|
82
|
+
results_dir=results_dir,
|
|
83
|
+
)
|
|
84
|
+
settings.update(overrides)
|
|
85
|
+
return TrainConfig(**settings).validate()
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def run_r1(data_file, *, seed, **options):
|
|
89
|
+
"""Run the ensemble for ``seed`` (see :func:`r1_config`); returns :func:`run_ensemble`'s dict."""
|
|
90
|
+
return run_ensemble(r1_config(data_file, seed=seed, **options))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def main(argv=None):
|
|
94
|
+
parser = argparse.ArgumentParser(description=__doc__.split("\n\n")[0])
|
|
95
|
+
parser.add_argument("--data-file", required=True, help="CSV of date,tic,open,high,low,close,volume")
|
|
96
|
+
parser.add_argument("--seed", type=int, required=True)
|
|
97
|
+
parser.add_argument("--tickers", nargs="+", help="default: every ticker in the file")
|
|
98
|
+
parser.add_argument("--no-turbulence", action="store_true", help="arm B: no liquidation rule")
|
|
99
|
+
parser.add_argument("--start-date", default="2009-01-02")
|
|
100
|
+
parser.add_argument("--start-trade-date", default="2016-01-04")
|
|
101
|
+
parser.add_argument("--end-date", default="2026-01-01", help="exclusive")
|
|
102
|
+
parser.add_argument("--ddpg-noise-sigma", type=float, default=AUTHORS_DDPG_NOISE_SIGMA)
|
|
103
|
+
parser.add_argument("--run-name")
|
|
104
|
+
parser.add_argument("--results-dir", default=config.RESULTS_DIR)
|
|
105
|
+
options = parser.parse_args(argv)
|
|
106
|
+
logging.basicConfig(
|
|
107
|
+
level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s"
|
|
108
|
+
)
|
|
109
|
+
return run_r1(
|
|
110
|
+
options.data_file,
|
|
111
|
+
seed=options.seed,
|
|
112
|
+
use_turbulence=not options.no_turbulence,
|
|
113
|
+
ticker_list=options.tickers,
|
|
114
|
+
start_date=options.start_date,
|
|
115
|
+
start_trade_date=options.start_trade_date,
|
|
116
|
+
end_date=options.end_date,
|
|
117
|
+
ddpg_noise_sigma=options.ddpg_noise_sigma,
|
|
118
|
+
run_name=options.run_name,
|
|
119
|
+
results_dir=options.results_dir,
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
if __name__ == "__main__":
|
|
124
|
+
main()
|