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.
Files changed (64) hide show
  1. strategy_backtest_agent-1.1.0/.env.example +2 -0
  2. strategy_backtest_agent-1.1.0/LICENSE +21 -0
  3. strategy_backtest_agent-1.1.0/PKG-INFO +525 -0
  4. strategy_backtest_agent-1.1.0/README.md +504 -0
  5. strategy_backtest_agent-1.1.0/pyproject.toml +53 -0
  6. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/__init__.py +1 -0
  7. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/ai/__init__.py +1 -0
  8. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/ai/models.py +271 -0
  9. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/ai/parser.py +290 -0
  10. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/ai/prompts.py +162 -0
  11. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/backtester.py +159 -0
  12. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/cli.py +347 -0
  13. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/__init__.py +9 -0
  14. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/cli.py +69 -0
  15. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/engine.py +203 -0
  16. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/formatter.py +71 -0
  17. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/comparison/models.py +148 -0
  18. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/__init__.py +1 -0
  19. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/cli.py +35 -0
  20. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/engine.py +103 -0
  21. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/formatter.py +39 -0
  22. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/costs/models.py +81 -0
  23. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/demo.py +56 -0
  24. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/doctor.py +215 -0
  25. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/execution.py +86 -0
  26. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/execution_cli.py +34 -0
  27. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/indicators.py +137 -0
  28. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/init_cli.py +87 -0
  29. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/market_data.py +103 -0
  30. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/metrics.py +51 -0
  31. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/models.py +179 -0
  32. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/__init__.py +1 -0
  33. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/ai.py +212 -0
  34. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/cli.py +102 -0
  35. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/evidence.py +572 -0
  36. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/inputs.py +224 -0
  37. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/models.py +147 -0
  38. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/render.py +457 -0
  39. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/reports/validation.py +712 -0
  40. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/__init__.py +5 -0
  41. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/evaluator.py +160 -0
  42. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/formatter.py +33 -0
  43. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/history.py +82 -0
  44. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/indicator_specs.py +97 -0
  45. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/rules/models.py +105 -0
  46. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/__init__.py +1 -0
  47. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/analysis.py +131 -0
  48. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/cache.py +27 -0
  49. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/cli.py +49 -0
  50. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/engine.py +110 -0
  51. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/formatter.py +132 -0
  52. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/grid.py +245 -0
  53. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/sensitivity/models.py +180 -0
  54. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/strategy.py +39 -0
  55. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/__init__.py +1 -0
  56. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/cli.py +64 -0
  57. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/engine.py +125 -0
  58. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/formatter.py +63 -0
  59. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/validation/models.py +76 -0
  60. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/__init__.py +1 -0
  61. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/cli.py +66 -0
  62. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/engine.py +188 -0
  63. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/formatter.py +78 -0
  64. strategy_backtest_agent-1.1.0/src/strategy_backtest_agent/walk_forward/models.py +136 -0
@@ -0,0 +1,2 @@
1
+ OPENAI_API_KEY=your_openai_api_key_here
2
+ OPENAI_MODEL=gpt-4.1-mini
@@ -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
+