strategy-backtest-agent 1.1.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.
- strategy_backtest_agent-1.1.0/.env.example +2 -0
- strategy_backtest_agent-1.1.0/LICENSE +21 -0
- strategy_backtest_agent-1.1.0/PKG-INFO +525 -0
- strategy_backtest_agent-1.1.0/README.md +504 -0
- strategy_backtest_agent-1.1.0/pyproject.toml +53 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/__init__.py +1 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/ai/__init__.py +1 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/ai/models.py +271 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/ai/parser.py +290 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/ai/prompts.py +162 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/backtester.py +159 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/cli.py +347 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/__init__.py +9 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/cli.py +69 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/engine.py +203 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/formatter.py +71 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/models.py +148 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/__init__.py +1 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/cli.py +35 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/engine.py +103 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/formatter.py +39 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/models.py +81 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/demo.py +56 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/doctor.py +215 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/execution.py +86 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/execution_cli.py +34 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/indicators.py +137 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/init_cli.py +87 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/market_data.py +103 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/metrics.py +51 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/models.py +179 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/__init__.py +1 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/ai.py +212 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/cli.py +102 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/evidence.py +572 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/inputs.py +224 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/models.py +147 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/render.py +457 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/validation.py +712 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/__init__.py +5 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/evaluator.py +160 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/formatter.py +33 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/history.py +82 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/indicator_specs.py +97 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/models.py +105 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/__init__.py +1 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/analysis.py +131 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/cache.py +27 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/cli.py +49 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/engine.py +110 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/formatter.py +132 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/grid.py +245 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/models.py +180 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/strategy.py +39 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/__init__.py +1 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/cli.py +64 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/engine.py +125 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/formatter.py +63 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/models.py +76 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/__init__.py +1 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/cli.py +66 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/engine.py +188 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/formatter.py +78 -0
- strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/models.py +136 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 changelia
|
|
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,525 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: strategy-backtest-agent
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Deterministic cryptocurrency strategy backtesting
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Python: >=3.12,<4.0
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
14
|
+
Requires-Dist: httpx (>=0.28,<0.29)
|
|
15
|
+
Requires-Dist: openai (>=3.24.0,<4.0.0)
|
|
16
|
+
Requires-Dist: pandas (>=2.2,<3.0)
|
|
17
|
+
Requires-Dist: pydantic (>=2.10,<3.0)
|
|
18
|
+
Requires-Dist: python-dotenv (>=1.2.4,<2.0.0)
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
|
|
21
|
+
# Strategy Backtest Agent
|
|
22
|
+
|
|
23
|
+
**Research historical strategy rules with deterministic calculations and optional AI-assisted parsing.**
|
|
24
|
+
|
|
25
|
+
Strategy Backtest Agent evaluates single-symbol, long-only strategy rules. Python
|
|
26
|
+
calculates indicators, signals, trades, execution costs and metrics. Optional OpenAI
|
|
27
|
+
features parse natural-language strategies and explain validated research evidence.
|
|
28
|
+
|
|
29
|
+
Latest tagged release: **v1.0.0 — Evidence-Grounded AI Research Reports**.
|
|
30
|
+
The repository includes an unreleased **v1.1.0 release candidate**. It is not
|
|
31
|
+
published or tagged. See [CHANGELOG.md](CHANGELOG.md) and the [release candidate
|
|
32
|
+
procedure](RELEASE.md).
|
|
33
|
+
|
|
34
|
+
## Quick Start
|
|
35
|
+
|
|
36
|
+
Requires Python 3.12 or newer, pip, and a POSIX environment. Report and configuration
|
|
37
|
+
file creation uses POSIX filesystem operations; Windows file-output support is not
|
|
38
|
+
available. Source installation was verified on macOS with Python 3.12 and in Ubuntu
|
|
39
|
+
Python 3.12 CI. The commands below use deterministic synthetic data and need neither
|
|
40
|
+
OpenAI credentials nor application network access.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone https://github.com/changelia/strategy-backtest-agent.git
|
|
44
|
+
cd strategy-backtest-agent
|
|
45
|
+
|
|
46
|
+
REPO="$(pwd -P)"
|
|
47
|
+
TMP_ROOT="$(python3.12 -c 'from pathlib import Path; import tempfile; print(Path(tempfile.gettempdir()).resolve())')"
|
|
48
|
+
WORKDIR="$(mktemp -d "$TMP_ROOT/strategy-backtest.XXXXXX")"
|
|
49
|
+
python3.12 -m venv "$WORKDIR/venv"
|
|
50
|
+
"$WORKDIR/venv/bin/python" -m pip install "$REPO"
|
|
51
|
+
cd "$WORKDIR"
|
|
52
|
+
CLI="$WORKDIR/venv/bin/strategy-backtest"
|
|
53
|
+
export PYTHON_DOTENV_DISABLED=1 # Keep this tutorial run independent of local .env files.
|
|
54
|
+
set -C # Refuse to overwrite JSON files created by shell redirection.
|
|
55
|
+
|
|
56
|
+
env -u OPENAI_API_KEY -u OPENAI_MODEL PYTHON_DOTENV_DISABLED=1 "$CLI" doctor
|
|
57
|
+
"$CLI" init --type backtest --output backtest-config.json
|
|
58
|
+
"$CLI" --config backtest-config.json --days 180 --demo --json > backtest-result.json
|
|
59
|
+
"$CLI" report --input backtest-result.json --format json --output research-report.json
|
|
60
|
+
"$CLI" report --input backtest-result.json --format markdown --output research-report.md
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The generated files have different roles: `backtest-config.json` is the research
|
|
64
|
+
configuration; `backtest-result.json` is raw CLI output; `research-report.json` is
|
|
65
|
+
normalized, evidence-grounded report data; and `research-report.md` is its readable
|
|
66
|
+
rendering. Reports are deterministic for identical input bytes and generator version.
|
|
67
|
+
Both configuration and report files refuse to overwrite existing paths. Start a new
|
|
68
|
+
working directory for a rerun. The shell's `set -C` also prevents result redirection
|
|
69
|
+
from replacing an existing file.
|
|
70
|
+
|
|
71
|
+
See the [Quick Start and Research Tutorial](https://github.com/changelia/strategy-backtest-agent/blob/main/docs/QUICK_START.md) for comparison,
|
|
72
|
+
chronological validation, walk-forward, interpretation, and real-market-data notes.
|
|
73
|
+
For development, `poetry install` creates the project environment and
|
|
74
|
+
`poetry run strategy-backtest ...` runs commands there; the Quick Start above instead
|
|
75
|
+
installs the checkout into a separate virtual environment and runs its installed CLI.
|
|
76
|
+
The project is not confirmed published on PyPI. After publication, the intended
|
|
77
|
+
package install command will be `python -m pip install strategy-backtest-agent`;
|
|
78
|
+
that command is not a working installation route at present.
|
|
79
|
+
|
|
80
|
+
## Configuration
|
|
81
|
+
|
|
82
|
+
The CLI automatically loads `.env` from the current directory or nearest parent
|
|
83
|
+
once at startup, before dispatching any command. For example:
|
|
84
|
+
|
|
85
|
+
```dotenv
|
|
86
|
+
OPENAI_API_KEY=your_openai_api_key_here
|
|
87
|
+
OPENAI_MODEL=gpt-4.1-mini
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Existing shell variables always take precedence (`override=False`). You can still
|
|
91
|
+
configure both values with `export`; no `.env` is required. `.env` is already
|
|
92
|
+
ignored by Git—never commit credentials. Offline reports and demo need no API key.
|
|
93
|
+
|
|
94
|
+
## Compare Strategies
|
|
95
|
+
|
|
96
|
+
Compare 2–5 strategies on the same symbol, timeframe, historical window, initial
|
|
97
|
+
balance, and fee. Each strategy runs its own independent portfolio.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
poetry run strategy-backtest compare \
|
|
101
|
+
'Compare RSI 25/70, RSI 30/70 and SMA 20/50 on BTCUSDT over 90 days'
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or use a validated JSON config without an OpenAI key (Binance access required):
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
poetry run strategy-backtest compare --config examples/comparison.json
|
|
108
|
+
poetry run strategy-backtest compare --config examples/comparison.json --json
|
|
109
|
+
poetry run strategy-backtest compare --config examples/comparison.json --sort max_drawdown
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The [example config](examples/comparison.json) sets a fixed UTC end time. Data is
|
|
113
|
+
fetched once, and shared indicators are calculated once. All comparison strategies,
|
|
114
|
+
including legacy RSI configurations, use the same prior-history warm-up. This can
|
|
115
|
+
produce different results from single-strategy legacy RSI runs.
|
|
116
|
+
|
|
117
|
+
The table shows returns, excess return, drawdown, trades, win rate, and profit factor.
|
|
118
|
+
**Excess return** is strategy return minus buy-and-hold return, in percentage points.
|
|
119
|
+
Sort by `total_return` (default), `excess_return`, `max_drawdown`, or `profit_factor`.
|
|
120
|
+
Less negative drawdown ranks higher; undefined metrics rank last, with ties broken
|
|
121
|
+
by strategy ID. A null profit factor is not infinity. Rankings describe historical
|
|
122
|
+
results and do not predict which strategy will perform best in the future.
|
|
123
|
+
|
|
124
|
+
Comparison JSON contains `configuration`, `shared_data`, `buy_and_hold_return_percent`,
|
|
125
|
+
`results`, `ranking_criterion`, and ranked strategy IDs in `ranking`. It records the
|
|
126
|
+
resolved UTC window, warm-up policy, definitions, and a candle-history digest. A fixed
|
|
127
|
+
end makes the requested window repeatable; exact reproduction requires the same data.
|
|
128
|
+
Multi-symbol comparisons and per-strategy overrides of shared trading settings are rejected.
|
|
129
|
+
|
|
130
|
+
## Train/Test Validation
|
|
131
|
+
|
|
132
|
+
Validate 1–5 fixed strategies on chronological Train and Test segments:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
poetry run strategy-backtest validate \
|
|
136
|
+
'Validate RSI 30/70 and SMA 20/50 on BTCUSDT over 180 days using a 70/30 train/test split'
|
|
137
|
+
poetry run strategy-backtest validate --config examples/validation.json
|
|
138
|
+
poetry run strategy-backtest validate --config examples/validation.json --json
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Config mode needs no OpenAI credentials. The [example](examples/validation.json)
|
|
142
|
+
sets a fixed UTC end. One shared fetch includes the maximum indicator warm-up.
|
|
143
|
+
Train receives the first `floor(completed evaluation candles × train_ratio)` candles;
|
|
144
|
+
Test receives all remaining candles. Default ratio is 0.70, allowed range 0.50–0.90.
|
|
145
|
+
Each segment needs at least two candles; insufficient history is rejected.
|
|
146
|
+
|
|
147
|
+
Each segment starts flat with its own initial cash. Prior candles initialize causal
|
|
148
|
+
indicators only. The first signal uses the first completed segment candle and executes
|
|
149
|
+
at the next segment open. Final-candle signals never cross the split; open positions
|
|
150
|
+
liquidate at their own segment's final close. No trades or equity carry into Test.
|
|
151
|
+
Exact UTC boundaries, candle counts, warm-up and a full-history SHA256 are recorded.
|
|
152
|
+
|
|
153
|
+
**Test is Held-out evaluation.** Select and freeze strategies before examining Test;
|
|
154
|
+
repeated inspection or choosing strategies using Test contaminates the holdout.
|
|
155
|
+
The return gap is `Test return − Train return`, in percentage points. It is descriptive:
|
|
156
|
+
durations differ and total returns are not normalized. No winner or robustness score
|
|
157
|
+
is assigned. A single holdout cannot establish robustness or future profitability.
|
|
158
|
+
Parameter optimization is unsupported; use `walk-forward` for multiple fixed-strategy windows.
|
|
159
|
+
|
|
160
|
+
JSON contains `configuration`, `shared_data`, `split`, per-strategy `results` with
|
|
161
|
+
independent Train/Test metrics and trades, `return_gap_pp`, and `methodology_warnings`.
|
|
162
|
+
Undefined metrics are `null`; JSON stdout contains no progress messages.
|
|
163
|
+
Fixed boundaries make the window repeatable; exact replay requires unchanged candles,
|
|
164
|
+
including warm-up. See [ARCHITECTURE.md](ARCHITECTURE.md#chronological-out-of-sample-validation)
|
|
165
|
+
for boundary policy and initialization limitations.
|
|
166
|
+
|
|
167
|
+
## Walk-Forward Analysis
|
|
168
|
+
|
|
169
|
+
Evaluate 1–5 **fixed, predeclared** strategies on multiple chronological Train/Test
|
|
170
|
+
windows, with fresh capital in every segment:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
poetry run strategy-backtest walk-forward --config examples/walk-forward.json
|
|
174
|
+
poetry run strategy-backtest walk-forward --config examples/walk-forward.json --json
|
|
175
|
+
poetry run strategy-backtest walk-forward \
|
|
176
|
+
'Run rolling walk-forward analysis of RSI 30/70 and SMA 20/50 on BTCUSDT on 1h over 360 days with 120-day Train and 30-day Test windows'
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Config mode needs no OpenAI key. Rolling Train windows have fixed lengths; expanding
|
|
180
|
+
Train windows retain the first evaluation candle and grow each fold. Durations are
|
|
181
|
+
whole days converted to exact candle counts. Step defaults to Test length; smaller
|
|
182
|
+
steps are rejected to prevent overlapping Test windows. At least two complete folds
|
|
183
|
+
are required, with a configurable limit (default 50, hard maximum 100). Excess folds
|
|
184
|
+
are rejected; incomplete final windows are excluded and trailing candles reported.
|
|
185
|
+
|
|
186
|
+
Reports include per-fold results, costs and net Buy & Hold, plus Test-only medians,
|
|
187
|
+
ranges, trade counts and positive/outperforming fold counts. Optional `stitch_oos`
|
|
188
|
+
compounds normalized independent Test returns into a **fold-endpoint index** starting
|
|
189
|
+
at 100. It requires contiguous Test windows and represents no position continuity or
|
|
190
|
+
continuous portfolio drawdown. All segments use the same declared execution costs.
|
|
191
|
+
|
|
192
|
+
Multiple OOS periods reveal variation across historical windows, but do not guarantee
|
|
193
|
+
robustness or future profitability. Train is diagnostic: no parameter optimization,
|
|
194
|
+
adaptive selection or winner ranking occurs. Choosing strategies after inspecting
|
|
195
|
+
this history undermines independent held-out evidence. See
|
|
196
|
+
[ARCHITECTURE.md](ARCHITECTURE.md#fixed-strategy-walk-forward-analysis) for initialization,
|
|
197
|
+
boundaries and aggregate definitions.
|
|
198
|
+
|
|
199
|
+
## Parameter Sensitivity
|
|
200
|
+
|
|
201
|
+
Explore how fixed numerical choices change historical results on **Train only**:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
poetry run strategy-backtest sensitivity \
|
|
205
|
+
'Analyze nearby RSI 30/70 thresholds on BTCUSDT over 180 days'
|
|
206
|
+
poetry run strategy-backtest sensitivity --config examples/sensitivity.json
|
|
207
|
+
poetry run strategy-backtest sensitivity --config examples/sensitivity.json --json
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Config mode needs no OpenAI key. [RSI](examples/sensitivity.json),
|
|
211
|
+
[SMA](examples/sensitivity-sma.json), and [EMA](examples/sensitivity-ema.json)
|
|
212
|
+
examples use fixed UTC ends. The existing DSL is the base strategy. Specify exact
|
|
213
|
+
paths, including `entry.conditions.0.left.period` for nested rules:
|
|
214
|
+
|
|
215
|
+
```json
|
|
216
|
+
{"path": "entry.right.value", "values": [25, 30, 35]}
|
|
217
|
+
{"path": "entry.left.period", "coupled_paths": ["exit.left.period"],
|
|
218
|
+
"range": {"start": 10, "stop": 20, "step": 5}}
|
|
219
|
+
{"path": "exit.right.value", "nearby": {}}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Each line above is a separate parameter specification. Choose exactly one source:
|
|
223
|
+
explicit values, an inclusive stepped range, or nearby values. Nearby defaults are
|
|
224
|
+
base±5 for RSI thresholds and base±1 for indicator periods; other constants require
|
|
225
|
+
an explicit step. Periods must remain integers. Invalid combinations fail the entire
|
|
226
|
+
grid; values are never clipped or discarded. Limits: three dimensions, 25 variants,
|
|
227
|
+
and existing DSL complexity. Candidate order controls output and neighbor adjacency.
|
|
228
|
+
Repeated indicators stay independent unless their exact paths are explicitly coupled.
|
|
229
|
+
|
|
230
|
+
The default 70/30 chronological split reserves Test without evaluating it. All variants
|
|
231
|
+
use the same Train boundaries, one maximum-warm-up fetch, fresh cash, fees and
|
|
232
|
+
Train final-close liquidation. Each indicator uses its own fixed prior-history window
|
|
233
|
+
anchored to Train start, so adding longer grid periods cannot change existing seeds.
|
|
234
|
+
RSI/EMA initialization remains finite; JSON records each indicator's initialization
|
|
235
|
+
boundary. Test candles never reach indicators or backtests.
|
|
236
|
+
Output includes per-variant metrics, min/median/max return, range, positive-return and
|
|
237
|
+
buy-and-hold outperformance percentages, neighbor differences, and a 1D series or
|
|
238
|
+
2D return matrix. JSON records the complete grid, definitions, split and history SHA256.
|
|
239
|
+
|
|
240
|
+
These statistics describe the declared grid only. Similar neighboring returns or an
|
|
241
|
+
isolated spike are descriptive observations; configurations with fewer than five trades
|
|
242
|
+
are flagged, including zero trades. Repeated experimentation can overfit Train.
|
|
243
|
+
**No variant is ranked, selected or recommended.** Sensitivity is not optimization,
|
|
244
|
+
a robustness test or a profitability prediction. Freeze a preselected strategy before
|
|
245
|
+
separately running `validate`; the software cannot prove its Test data was unseen.
|
|
246
|
+
|
|
247
|
+
## Execution Costs
|
|
248
|
+
|
|
249
|
+
Added costs default to zero, preserving v0.6.0 numerical results. Fees remain 0.1% per executed side by default.
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
poetry run strategy-backtest --demo --spread-bps 20 --slippage-bps 10
|
|
253
|
+
poetry run strategy-backtest ai \
|
|
254
|
+
'Backtest BTCUSDT on 1h for 180 days using RSI 30/70, with 10 bps spread and 5 bps slippage.'
|
|
255
|
+
poetry run strategy-backtest validate --config examples/validation.json --spread-bps 10 --slippage-bps 5 --json
|
|
256
|
+
poetry run strategy-backtest costs --config examples/execution-scenarios.json --json
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
The same flags work for explicit backtests, AI, compare, validate and sensitivity.
|
|
260
|
+
JSON configs accept `{"execution": {"spread_bps": 10, "slippage_bps": 5}}`; omitted
|
|
261
|
+
`fee_rate` inherits legacy `fee` (`fee_rate` in AI configuration). Conflicting explicit
|
|
262
|
+
fee settings are rejected. Config-only workflows need no OpenAI key.
|
|
263
|
+
|
|
264
|
+
**Spread is the full bid/ask spread**, with half applied on each side. Slippage is
|
|
265
|
+
adverse per side. With 20 bps spread and 10 bps slippage, buy reference 100 fills
|
|
266
|
+
at 100.20; sell reference 110 fills at 109.78. Fees are charged separately.
|
|
267
|
+
OHLC prices are mid-price proxies, not measured quotes or actual historical fills.
|
|
268
|
+
|
|
269
|
+
Open positions retain reference-price equity valuation; costs apply only to fills.
|
|
270
|
+
Buy & Hold buys at the first evaluation open and sells at the final close using
|
|
271
|
+
the same costs. Reports separate charged fees from modeled spread/slippage amounts.
|
|
272
|
+
|
|
273
|
+
[Cost scenarios](examples/execution-scenarios.json) evaluate one frozen DSL strategy
|
|
274
|
+
on Train only, sharing data and indicators with fresh portfolios. Declare 2–8 ordered
|
|
275
|
+
scenarios; the first has zero spread/slippage and supplies the comparison baseline.
|
|
276
|
+
Fees inherit the shared rate unless explicitly varied. These illustrative assumptions
|
|
277
|
+
are neither Binance cost estimates nor an optimization or recommendation.
|
|
278
|
+
|
|
279
|
+
## Advanced Technical Indicators
|
|
280
|
+
|
|
281
|
+
MACD, Bollinger Bands and ATR work with the same nested rule DSL and all research
|
|
282
|
+
commands. Config mode needs no OpenAI key:
|
|
283
|
+
|
|
284
|
+
```bash
|
|
285
|
+
poetry run strategy-backtest compare --config examples/advanced-comparison.json --json
|
|
286
|
+
poetry run strategy-backtest validate --config examples/advanced-validation.json
|
|
287
|
+
poetry run strategy-backtest sensitivity --config examples/advanced-sensitivity.json
|
|
288
|
+
poetry run strategy-backtest costs --config examples/advanced-costs.json
|
|
289
|
+
poetry run strategy-backtest walk-forward --config examples/advanced-walk-forward.json
|
|
290
|
+
poetry run strategy-backtest ai \
|
|
291
|
+
'Backtest BTCUSDT on 1h for 90 days. Buy when MACD line is above signal line and RSI is below 35. Sell when MACD line is below signal line.'
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Operands keep `type: "indicator"`. MACD uses `name: "macd"`, `fast_period: 12`,
|
|
295
|
+
`slow_period: 26`, `signal_period: 9`, and `component: "macd"`, `"signal"` or
|
|
296
|
+
`"histogram"`. Bollinger uses `name: "bollinger"`, `period: 20`, `multiplier: 2.0`
|
|
297
|
+
and an explicit `component: "upper"`, `"middle"` or `"lower"`. ATR uses
|
|
298
|
+
`name: "atr"`, `period: 14`, and **high/low/previous close**, with no component.
|
|
299
|
+
Numerical defaults apply when omitted; explicit invalid parameters are rejected.
|
|
300
|
+
|
|
301
|
+
MACD price EMAs seed at the first historical close; its signal EMA seeds at the
|
|
302
|
+
first available MACD value. Bollinger uses **population standard deviation**
|
|
303
|
+
(`ddof=0`). ATR uses an SMA True Range seed followed by Wilder smoothing.
|
|
304
|
+
Warm-up is MACD `10 × (slow + signal)`, Bollinger `period`, ATR `20 × period`
|
|
305
|
+
prior candles. Each new indicator has its own recorded history anchor; finite
|
|
306
|
+
MACD/ATR seeds can still influence threshold-adjacent signals.
|
|
307
|
+
|
|
308
|
+
`MACD line > signal` is a state condition. **Crosses above/below and crossover
|
|
309
|
+
operators remain unsupported.** Sensitivity accepts MACD `.fast_period`,
|
|
310
|
+
`.slow_period`, `.signal_period`, Bollinger `.period`/`.multiplier`, and ATR
|
|
311
|
+
`.period` paths on operands; invalid combinations fail the whole grid. See
|
|
312
|
+
[ARCHITECTURE.md](ARCHITECTURE.md#advanced-indicator-conventions) for formulas,
|
|
313
|
+
initialization policies and compatibility details.
|
|
314
|
+
|
|
315
|
+
## Supported Strategies
|
|
316
|
+
|
|
317
|
+
- Wilder RSI, SMA, EMA, MACD, Bollinger Bands, ATR, completed candle close (`price`), and constants
|
|
318
|
+
- Level comparisons: `<`, `<=`, `>`, `>=`, including indicator-to-indicator comparisons
|
|
319
|
+
- AND/OR conditions and clearly specified nested groups
|
|
320
|
+
- One symbol, one long position at a time, full available cash allocation
|
|
321
|
+
- Next-candle-open execution, entry/exit fees, and final-close liquidation
|
|
322
|
+
- Return, buy-and-hold comparison, trade PnL, win rate, drawdown, and profit factor
|
|
323
|
+
- Paginated Binance historical data, terminal summaries, JSON, and an offline demo
|
|
324
|
+
- Single-symbol comparisons, chronological validation and bounded parameter sensitivity
|
|
325
|
+
|
|
326
|
+
DSL periods: RSI 2–500; SMA/EMA 2–1000. Rules are limited to 20 comparisons and depth 5.
|
|
327
|
+
RSI defaults to period 14 when omitted; specify SMA/EMA periods. Use an explicit
|
|
328
|
+
market symbol such as `BTCUSDT`. AI mode defaults to 1h, 30 days, $10,000 initial
|
|
329
|
+
cash, and a 0.1% fee per side. Simple RSI requests default to buy below 30 and sell
|
|
330
|
+
above 70. The explicit-options CLI retains its 180-day default.
|
|
331
|
+
|
|
332
|
+
A moving-average level strategy:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
poetry run strategy-backtest ai \
|
|
336
|
+
'Backtest ETHUSDT on 4h for 90 days. Buy when SMA 20 > SMA 50. Sell when SMA 20 < SMA 50.'
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`SMA 20 > SMA 50` is supported. `SMA 20 crosses above SMA 50` is a transition event
|
|
340
|
+
and is rejected. NOT, stop loss/take profit, short selling,
|
|
341
|
+
leverage, multiple symbols, live trading, and predictions are unsupported.
|
|
342
|
+
|
|
343
|
+
## AI Parsing and Deterministic Execution
|
|
344
|
+
|
|
345
|
+
```text
|
|
346
|
+
Plain English → OpenAI parser → Validated Strategy DSL
|
|
347
|
+
↓
|
|
348
|
+
Historical candles → Cached indicators → Rule Engine → Backtester → Results
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
AI extracts configuration only. It does not calculate prices, indicators, trading
|
|
352
|
+
signals, or financial results. Python validates the DSL and executes fixed rules;
|
|
353
|
+
no AI-generated code or arbitrary expressions are executed. Given the same validated
|
|
354
|
+
strategy and candles, the financial results are deterministic.
|
|
355
|
+
|
|
356
|
+
Rules use completed candle N and execute at **candle N+1 open**. Open positions
|
|
357
|
+
check exit rules; flat portfolios check entry rules. Unavailable indicator operands
|
|
358
|
+
make a comparison false. A final-candle signal cannot execute; any remaining
|
|
359
|
+
position is liquidated at the final close.
|
|
360
|
+
|
|
361
|
+
Rule strategies fetch prior candles for indicator warm-up: RSI `p+1`, SMA `p`, and
|
|
362
|
+
EMA `5p`, using the largest requirement. Warm-up candles are excluded from trading,
|
|
363
|
+
equity, and buy-and-hold results. Incomplete history or gaps cause an error rather
|
|
364
|
+
than a shortened evaluation period. EMA uses a finite approximation to historical
|
|
365
|
+
initialization; its seed can still affect signals near thresholds. Legacy RSI CLI,
|
|
366
|
+
demo, and simple AI RSI requests retain their original in-range initialization.
|
|
367
|
+
All boundaries use UTC and exclude unfinished candles.
|
|
368
|
+
|
|
369
|
+
See [ARCHITECTURE.md](ARCHITECTURE.md) for the DSL schema, validation limits,
|
|
370
|
+
indicator initialization, execution accounting, metric definitions, and parser defaults.
|
|
371
|
+
|
|
372
|
+
## CLI and JSON
|
|
373
|
+
|
|
374
|
+
Run an RSI backtest with explicit options and no OpenAI key (Binance access required):
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
poetry run strategy-backtest \
|
|
378
|
+
--symbol BTCUSDT --timeframe 1h --days 30 --balance 10000
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Export an AI-parsed rule strategy:
|
|
382
|
+
|
|
383
|
+
```bash
|
|
384
|
+
poetry run strategy-backtest ai \
|
|
385
|
+
'Backtest BTCUSDT. Buy when RSI < 30 and price > EMA 200. Sell when RSI > 70.' \
|
|
386
|
+
--json > backtest.json
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
AI JSON includes `input`, `parsed_strategy`, and `backtest_result`, with metrics,
|
|
390
|
+
trades, indicator configuration, and evaluation-period metadata for rule strategies.
|
|
391
|
+
Explicit CLI JSON contains results and configuration directly. JSON stdout contains
|
|
392
|
+
no progress messages; errors go to stderr with exit code 2. Undefined metrics are
|
|
393
|
+
`null`. Credentials, prompts, and raw OpenAI responses are excluded.
|
|
394
|
+
|
|
395
|
+
For all CLI options and a network-free JSON example:
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
poetry run strategy-backtest --help
|
|
399
|
+
poetry run strategy-backtest ai --help
|
|
400
|
+
poetry run strategy-backtest --demo --days 30 --json
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## Limitations
|
|
404
|
+
|
|
405
|
+
Backtests assume full fills, fractional quantities, and unlimited liquidity. They
|
|
406
|
+
model constant spread/slippage only when configured, and exclude funding, taxes,
|
|
407
|
+
and exchange lot-size constraints.
|
|
408
|
+
Drawdown samples candle opens and closes, not intrabar highs and lows. Binance data
|
|
409
|
+
availability depends on history, network access, rate limits, and regional restrictions.
|
|
410
|
+
Legacy/direct candle runs can span missing intervals; the rule-history fetch rejects gaps.
|
|
411
|
+
The application does not place orders or connect to private trading endpoints.
|
|
412
|
+
|
|
413
|
+
## Evidence-grounded research reports
|
|
414
|
+
|
|
415
|
+
Generate a report from one existing v0.8/v0.9-compatible CLI JSON result (also
|
|
416
|
+
emitted by v1.0.0) without fetching prices or rerunning a backtest. Supported inputs: standard backtest (including the AI
|
|
417
|
+
wrapper), comparison, validation, sensitivity, cost scenarios and walk-forward.
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
poetry run strategy-backtest report --input examples/report-source.json --format markdown
|
|
421
|
+
poetry run strategy-backtest report --input examples/report-source.json --format json
|
|
422
|
+
poetry run strategy-backtest report --input examples/report-source.json --format markdown --output reports/research.md
|
|
423
|
+
poetry run strategy-backtest report --input examples/report-source.json --ai --format markdown
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Deterministic mode needs no API key. See the [synthetic example report](examples/research-report.md).
|
|
427
|
+
Markdown shows unique readable rules, compact segment tables and short row references;
|
|
428
|
+
full evidence identifiers and source paths remain in JSON.
|
|
429
|
+
Output files must be new; existing files are never overwritten. JSON stdout is one
|
|
430
|
+
object. Exit 0 means a deterministic report was generated, including when optional
|
|
431
|
+
AI is unavailable or rejected; its status and stderr explain the fallback. Invalid
|
|
432
|
+
input or filesystem errors exit 2.
|
|
433
|
+
|
|
434
|
+
Optional AI uses the existing OpenAI configuration to select evidence-linked,
|
|
435
|
+
preapproved explanatory statements and research questions. It cannot supply new
|
|
436
|
+
financial prose or change metrics. This deliberately conservative mode does not
|
|
437
|
+
prove arbitrary language true. Interpretation status and model are recorded.
|
|
438
|
+
|
|
439
|
+
Identical input bytes and generator version produce identical deterministic
|
|
440
|
+
content, with no generated timestamp. Source/canonical-input/evidence hashes aid
|
|
441
|
+
reproducibility, but cannot authenticate market data or supplied results. Inputs
|
|
442
|
+
are bounded and validated; Markdown metadata is escaped. Safe output creation
|
|
443
|
+
requires POSIX filesystem support and rejects symlink directories and parent
|
|
444
|
+
traversal. Reports preserve Train/Test distinctions and historical limitations;
|
|
445
|
+
positive returns do not establish predictive value.
|
|
446
|
+
|
|
447
|
+
## Configuration templates
|
|
448
|
+
|
|
449
|
+
Create validated JSON without prompts, OpenAI credentials, or repository examples.
|
|
450
|
+
`--output` must name a new file; existing files/directories and symlink destinations
|
|
451
|
+
are rejected. Missing real parent directories are created. No overwrite flag exists.
|
|
452
|
+
|
|
453
|
+
```bash
|
|
454
|
+
strategy-backtest init --type backtest --output backtest-config.json
|
|
455
|
+
strategy-backtest --config backtest-config.json --days 180 --demo --json
|
|
456
|
+
strategy-backtest init --type compare --output comparison-config.json
|
|
457
|
+
strategy-backtest compare --config comparison-config.json --demo --json
|
|
458
|
+
strategy-backtest init --type validate --output validation-config.json
|
|
459
|
+
strategy-backtest validate --config validation-config.json --demo --json
|
|
460
|
+
strategy-backtest init --type walk-forward --output walk-forward-config.json
|
|
461
|
+
strategy-backtest walk-forward --config walk-forward-config.json --demo --json
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
In a Poetry checkout, prefix these commands with `poetry run`. All four examples
|
|
465
|
+
run offline on deterministic synthetic candles and do not imply profitability.
|
|
466
|
+
Backtest uses `BacktestConfig`; its duration remains the CLI `--days` option
|
|
467
|
+
(default 180), and legacy account/strategy flags cannot accompany `--config`.
|
|
468
|
+
Spread/slippage flags can override costs. Other templates use their existing
|
|
469
|
+
research models (30 days for compare/validate, 60 days for walk-forward).
|
|
470
|
+
They declare balance 10000, fee 0.001 per side, full spread 10 bps and slippage
|
|
471
|
+
5 bps per side. Walk-forward uses rolling 30-day Train/10-day Test windows,
|
|
472
|
+
10-day steps and independent portfolios. These are fixed examples, not optimization.
|
|
473
|
+
`--demo` uses the fixed 2024-07-01 UTC end with exact prior warm-up candles;
|
|
474
|
+
research configs must use that end or null. For real Binance history omit `--demo`
|
|
475
|
+
and choose an appropriate evaluation period; that requires network access.
|
|
476
|
+
Safe file publication requires POSIX directory operations, as report output does.
|
|
477
|
+
|
|
478
|
+
## Offline diagnostics
|
|
479
|
+
|
|
480
|
+
```bash
|
|
481
|
+
strategy-backtest doctor
|
|
482
|
+
strategy-backtest doctor --type compare --config comparison-config.json
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
In a Poetry checkout, prefix with `poetry run`. Config validation is optional and
|
|
486
|
+
requires both `--type` (the same four choices as `init`) and `--config`; no research
|
|
487
|
+
files are scanned or guessed. Doctor reports Python compatibility, installed and
|
|
488
|
+
checkout metadata separately, dotenv discovery/loading, key presence and optional
|
|
489
|
+
AI model state. Stale editable metadata is labeled rather than used as the source
|
|
490
|
+
version. It uses normal shell-over-dotenv precedence, including empty shell values,
|
|
491
|
+
and honors `PYTHON_DOTENV_DISABLED`. Key values and model overrides are never shown.
|
|
492
|
+
|
|
493
|
+
Exit **0** means the checked offline capabilities are available; missing `.env`,
|
|
494
|
+
missing/empty credentials or unavailable optional AI do not cause failure. Exit
|
|
495
|
+
**1** means a Python compatibility, dotenv parsing/loading, explicit configuration
|
|
496
|
+
or offline self-check error needs attention. Exit **2** means invalid arguments.
|
|
497
|
+
Diagnostics are read-only: the offline check imports code and generates a small
|
|
498
|
+
synthetic sample, without running research, checking market connectivity or making
|
|
499
|
+
requests. A key's presence does not prove validity, funding or authorization; a
|
|
500
|
+
model setting does not prove provider availability. Validation confirms only the
|
|
501
|
+
selected configuration schema, not data availability, execution or profitability.
|
|
502
|
+
|
|
503
|
+
## Development
|
|
504
|
+
|
|
505
|
+
```bash
|
|
506
|
+
poetry run pytest
|
|
507
|
+
poetry run ruff check .
|
|
508
|
+
poetry run ruff format --check .
|
|
509
|
+
poetry run mypy
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
Tests use mocked provider and OpenAI responses and require no API keys or network.
|
|
513
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for development guidance.
|
|
514
|
+
|
|
515
|
+
## Financial Disclaimer
|
|
516
|
+
|
|
517
|
+
This is educational/research software, not financial advice. Historical backtests do
|
|
518
|
+
not predict future profitability. Natural-language parsing does not make this a
|
|
519
|
+
trading recommendation system. Do not use simulated results as the sole basis for
|
|
520
|
+
investment decisions.
|
|
521
|
+
|
|
522
|
+
## License
|
|
523
|
+
|
|
524
|
+
[MIT](LICENSE).
|
|
525
|
+
|