backtest2live 0.2.0__tar.gz → 0.3.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 (50) hide show
  1. {backtest2live-0.2.0 → backtest2live-0.3.0}/.claude-plugin/marketplace.json +1 -1
  2. {backtest2live-0.2.0 → backtest2live-0.3.0}/CHANGELOG.md +12 -0
  3. {backtest2live-0.2.0 → backtest2live-0.3.0}/PKG-INFO +32 -4
  4. {backtest2live-0.2.0 → backtest2live-0.3.0}/README.md +29 -1
  5. {backtest2live-0.2.0 → backtest2live-0.3.0}/ROADMAP.md +4 -4
  6. backtest2live-0.3.0/examples/market_orders_btcusdt_2024-03-30.csv +1436 -0
  7. {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/.claude-plugin/plugin.json +2 -2
  8. {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/skills/convergence/SKILL.md +2 -2
  9. backtest2live-0.3.0/plugins/backtest2live/skills/cost-gap/SKILL.md +40 -0
  10. {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/skills/fill-gap/SKILL.md +2 -2
  11. {backtest2live-0.2.0 → backtest2live-0.3.0}/pyproject.toml +3 -3
  12. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/cli.py +10 -1
  13. backtest2live-0.3.0/src/backtest2live/costgap/__init__.py +57 -0
  14. backtest2live-0.3.0/src/backtest2live/costgap/engine.py +202 -0
  15. backtest2live-0.3.0/src/backtest2live/costgap/report.py +99 -0
  16. backtest2live-0.3.0/src/backtest2live/costgap/sim.py +84 -0
  17. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/engine.py +25 -7
  18. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/report.py +1 -1
  19. backtest2live-0.3.0/tests/conftest.py +34 -0
  20. backtest2live-0.3.0/tests/test_costgap.py +155 -0
  21. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/test_fillgap.py +46 -16
  22. backtest2live-0.2.0/tests/conftest.py +0 -20
  23. {backtest2live-0.2.0 → backtest2live-0.3.0}/.github/workflows/ci.yml +0 -0
  24. {backtest2live-0.2.0 → backtest2live-0.3.0}/.github/workflows/pr-title.yml +0 -0
  25. {backtest2live-0.2.0 → backtest2live-0.3.0}/.github/workflows/release.yml +0 -0
  26. {backtest2live-0.2.0 → backtest2live-0.3.0}/.github/workflows/testpypi.yml +0 -0
  27. {backtest2live-0.2.0 → backtest2live-0.3.0}/.gitignore +0 -0
  28. {backtest2live-0.2.0 → backtest2live-0.3.0}/.releaserc.json +0 -0
  29. {backtest2live-0.2.0 → backtest2live-0.3.0}/LICENSE +0 -0
  30. {backtest2live-0.2.0 → backtest2live-0.3.0}/RELEASING.md +0 -0
  31. {backtest2live-0.2.0 → backtest2live-0.3.0}/examples/orders_btcusdt_2024-03-30.csv +0 -0
  32. {backtest2live-0.2.0 → backtest2live-0.3.0}/examples/results_converged.csv +0 -0
  33. {backtest2live-0.2.0 → backtest2live-0.3.0}/examples/results_iterate.csv +0 -0
  34. {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/skills/convergence/examples/results_converged.csv +0 -0
  35. {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/skills/convergence/examples/results_iterate.csv +0 -0
  36. {backtest2live-0.2.0 → backtest2live-0.3.0}/scripts/release_version.py +0 -0
  37. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/__init__.py +0 -0
  38. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/__main__.py +0 -0
  39. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/convergence.py +0 -0
  40. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/__init__.py +0 -0
  41. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/data.py +0 -0
  42. {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/sim.py +0 -0
  43. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/fixtures/results_drawdown.csv +0 -0
  44. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/fixtures/results_kill.csv +0 -0
  45. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/golden/results_converged.md +0 -0
  46. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/golden/results_drawdown.md +0 -0
  47. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/golden/results_iterate.md +0 -0
  48. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/golden/results_kill.md +0 -0
  49. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/test_cli.py +0 -0
  50. {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/test_convergence.py +0 -0
@@ -9,7 +9,7 @@
9
9
  "plugins": [
10
10
  {
11
11
  "name": "backtest2live",
12
- "description": "Check a backtest against what live execution would do, run locally. Convergence across a variant sweep (CONVERGED / ITERATE / KILL) with the numbers behind the verdict; fill-gap and more evaluators follow. Wraps the backtest2live CLI.",
12
+ "description": "Check a backtest against what live execution would do, run locally. Three checks: convergence across a variant sweep (CONVERGED / ITERATE / KILL), fill-gap for resting orders against a queue proxy, cost-gap for taker orders against the real book. Wraps the backtest2live CLI.",
13
13
  "source": "./plugins/backtest2live",
14
14
  "category": "data",
15
15
  "homepage": "https://github.com/martianmobile/backtest2live"
@@ -1,3 +1,15 @@
1
+ # [0.3.0](https://github.com/martianmobile/backtest2live/compare/v0.2.0...v0.3.0) (2026-10-15)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **fill-gap:** off-grid price guard trips on the share, not a single row ([#22](https://github.com/martianmobile/backtest2live/issues/22)) ([3de66dc](https://github.com/martianmobile/backtest2live/commit/3de66dc3466f813c9055b82421bde05f6e255da5)), closes [#21](https://github.com/martianmobile/backtest2live/issues/21)
7
+
8
+
9
+ ### Features
10
+
11
+ * cost-gap evaluator — backtest taker orders re-priced on the real book ([#23](https://github.com/martianmobile/backtest2live/issues/23)) ([e5f9fb0](https://github.com/martianmobile/backtest2live/commit/e5f9fb05771ad35a9fe39ab7b5eea71906c191fb))
12
+
1
13
  # [0.2.0](https://github.com/martianmobile/backtest2live/compare/v0.1.0...v0.2.0) (2026-10-02)
2
14
 
3
15
 
@@ -1,14 +1,14 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: backtest2live
3
- Version: 0.2.0
4
- Summary: Check a backtest against what live execution would do: convergence, fill-gap, and more, run locally.
3
+ Version: 0.3.0
4
+ Summary: Check a backtest against what live execution would do: convergence, fill-gap and cost-gap, run locally.
5
5
  Project-URL: Homepage, https://martianmobile.com
6
6
  Project-URL: Source, https://github.com/martianmobile/backtest2live
7
7
  Project-URL: Issues, https://github.com/martianmobile/backtest2live/issues
8
8
  Author-email: Martian Mobile <martin@martianmobile.com>
9
9
  License-Expression: MIT
10
10
  License-File: LICENSE
11
- Keywords: backtest,execution,fill-rate,overfitting,quant,trading
11
+ Keywords: backtest,execution,fill-rate,overfitting,quant,slippage,trading
12
12
  Classifier: Development Status :: 3 - Alpha
13
13
  Classifier: Intended Audience :: Financial and Insurance Industry
14
14
  Classifier: Intended Audience :: Science/Research
@@ -41,6 +41,7 @@ This is the public, MIT-licensed version of checks used in live crypto trading r
41
41
  |---------|--------|--------------|
42
42
  | **`bt2live convergence`** | shipped | Read a variant parameter sweep → measure dispersion, IS/OOS rank stability, and parameter-plateau structure → verdict: **CONVERGED / ITERATE / KILL**. |
43
43
  | **`bt2live fill-gap`** | shipped | Re-run your backtest's resting orders under a queue proxy on top-of-book and trades → your fill rate vs the proxy's: **CONSISTENT / OVERSTATED**. |
44
+ | **`bt2live cost-gap`** | shipped | Re-price your backtest's taker orders (market, or limits that cross) on top-of-book at arrival, with latency → what they would have paid vs what the backtest booked: **CONSISTENT / OVERSTATED**. The check for bar-based backtests. |
44
45
 
45
46
  Roadmap: [ROADMAP.md](ROADMAP.md) and the [milestones](https://github.com/martianmobile/backtest2live/milestones).
46
47
 
@@ -104,7 +105,7 @@ CSV, one row per order. Column names are matched case-insensitively:
104
105
  | P&L | `pnl` | no |
105
106
  | id | `order_id` | no |
106
107
 
107
- Orders marketable at arrival are taker orders and are skipped. `--latency-ms` delays every order's arrival at the book.
108
+ Orders marketable at arrival are taker orders: `fill-gap` skips them and `cost-gap` prices them. `--latency-ms` delays every order's arrival at the book.
108
109
 
109
110
  ### Market data
110
111
 
@@ -117,6 +118,33 @@ The touch rule is an upper bound: a resting order fills only if something trades
117
118
 
118
119
  ---
119
120
 
121
+ ## `cost-gap`: what would your taker orders have paid?
122
+
123
+ A bar-based backtest fills every order at a bar price: the close, the open, or the mid. A real market order crosses the spread, eats whatever is displayed at the touch, and arrives some milliseconds after the book you saw. `cost-gap` re-prices each market order, and each limit that crosses the spread, against top-of-book at its arrival time and reports the cost against the price the backtest booked.
124
+
125
+ ```bash
126
+ bt2live cost-gap examples/market_orders_btcusdt_2024-03-30.csv --venue binance-um --pair BTCUSDT
127
+ ```
128
+
129
+ ```
130
+ ## Verdict: REPORTED
131
+
132
+ **Your backtest's 1,435 taker orders would have paid +0.01 bps on average
133
+ (+0.01 bps median) against the price it booked.**
134
+ ```
135
+
136
+ That example is a toy momentum strategy sending 0.1 BTC market orders every minute and booking the mid. On BTCUSDT perpetuals the half-spread is under 0.01 bps and the touch absorbs 0.1 BTC, so the mid-fill assumption holds there, and the report says so. The check bites on thinner pairs, larger sizes and slower paths: the latency table (0 / 5 / 20 / 100 ms) shows the slope, and the by-volatility table shows where it concentrates. With a `pnl` column the verdict is **OVERSTATED** when the cost removes more than `--tolerance` (default 25%) of the backtest's P&L; without one it is **REPORTED**. Exit code: `0` CONSISTENT or REPORTED, `1` OVERSTATED, `3` error.
137
+
138
+ ### Your order log
139
+
140
+ Same columns as `fill-gap`, with three additions: `type` (`market`/`limit`), `price` for limits (a limit that crosses the touch is priced as a taker and capped at its limit; one that rests is counted and left to `fill-gap`), and `fill_price`, the price the backtest booked (without it, the mid at arrival is the baseline). A log with no `price` column is all market orders. A log with a `price` column but no `type` and no `fill_price` is read as a bar backtest's export: the price is the booked fill, every order is a market order, and the run says so.
141
+
142
+ ### What the book can and cannot see
143
+
144
+ Top-of-book shows the touch and its displayed size, nothing behind it. Size beyond the touch is priced one tick worse per displayed-size slice, the least impact consistent with the feed, so the cost is a floor, not a measurement. Only your own live fills settle it.
145
+
146
+ ---
147
+
120
148
  ## `convergence`: has your variant sweep converged?
121
149
 
122
150
  Given one row per variant (parameters + metrics), it measures:
@@ -16,6 +16,7 @@ This is the public, MIT-licensed version of checks used in live crypto trading r
16
16
  |---------|--------|--------------|
17
17
  | **`bt2live convergence`** | shipped | Read a variant parameter sweep → measure dispersion, IS/OOS rank stability, and parameter-plateau structure → verdict: **CONVERGED / ITERATE / KILL**. |
18
18
  | **`bt2live fill-gap`** | shipped | Re-run your backtest's resting orders under a queue proxy on top-of-book and trades → your fill rate vs the proxy's: **CONSISTENT / OVERSTATED**. |
19
+ | **`bt2live cost-gap`** | shipped | Re-price your backtest's taker orders (market, or limits that cross) on top-of-book at arrival, with latency → what they would have paid vs what the backtest booked: **CONSISTENT / OVERSTATED**. The check for bar-based backtests. |
19
20
 
20
21
  Roadmap: [ROADMAP.md](ROADMAP.md) and the [milestones](https://github.com/martianmobile/backtest2live/milestones).
21
22
 
@@ -79,7 +80,7 @@ CSV, one row per order. Column names are matched case-insensitively:
79
80
  | P&L | `pnl` | no |
80
81
  | id | `order_id` | no |
81
82
 
82
- Orders marketable at arrival are taker orders and are skipped. `--latency-ms` delays every order's arrival at the book.
83
+ Orders marketable at arrival are taker orders: `fill-gap` skips them and `cost-gap` prices them. `--latency-ms` delays every order's arrival at the book.
83
84
 
84
85
  ### Market data
85
86
 
@@ -92,6 +93,33 @@ The touch rule is an upper bound: a resting order fills only if something trades
92
93
 
93
94
  ---
94
95
 
96
+ ## `cost-gap`: what would your taker orders have paid?
97
+
98
+ A bar-based backtest fills every order at a bar price: the close, the open, or the mid. A real market order crosses the spread, eats whatever is displayed at the touch, and arrives some milliseconds after the book you saw. `cost-gap` re-prices each market order, and each limit that crosses the spread, against top-of-book at its arrival time and reports the cost against the price the backtest booked.
99
+
100
+ ```bash
101
+ bt2live cost-gap examples/market_orders_btcusdt_2024-03-30.csv --venue binance-um --pair BTCUSDT
102
+ ```
103
+
104
+ ```
105
+ ## Verdict: REPORTED
106
+
107
+ **Your backtest's 1,435 taker orders would have paid +0.01 bps on average
108
+ (+0.01 bps median) against the price it booked.**
109
+ ```
110
+
111
+ That example is a toy momentum strategy sending 0.1 BTC market orders every minute and booking the mid. On BTCUSDT perpetuals the half-spread is under 0.01 bps and the touch absorbs 0.1 BTC, so the mid-fill assumption holds there, and the report says so. The check bites on thinner pairs, larger sizes and slower paths: the latency table (0 / 5 / 20 / 100 ms) shows the slope, and the by-volatility table shows where it concentrates. With a `pnl` column the verdict is **OVERSTATED** when the cost removes more than `--tolerance` (default 25%) of the backtest's P&L; without one it is **REPORTED**. Exit code: `0` CONSISTENT or REPORTED, `1` OVERSTATED, `3` error.
112
+
113
+ ### Your order log
114
+
115
+ Same columns as `fill-gap`, with three additions: `type` (`market`/`limit`), `price` for limits (a limit that crosses the touch is priced as a taker and capped at its limit; one that rests is counted and left to `fill-gap`), and `fill_price`, the price the backtest booked (without it, the mid at arrival is the baseline). A log with no `price` column is all market orders. A log with a `price` column but no `type` and no `fill_price` is read as a bar backtest's export: the price is the booked fill, every order is a market order, and the run says so.
116
+
117
+ ### What the book can and cannot see
118
+
119
+ Top-of-book shows the touch and its displayed size, nothing behind it. Size beyond the touch is priced one tick worse per displayed-size slice, the least impact consistent with the feed, so the cost is a floor, not a measurement. Only your own live fills settle it.
120
+
121
+ ---
122
+
95
123
  ## `convergence`: has your variant sweep converged?
96
124
 
97
125
  Given one row per variant (parameters + metrics), it measures:
@@ -11,12 +11,11 @@ Tracking: [milestones](https://github.com/martianmobile/backtest2live/milestones
11
11
  - **Tests + CI** — [#3](https://github.com/martianmobile/backtest2live/issues/3). pytest on Python 3.9–3.13; the core stays dependency-free.
12
12
  - **Release** — [#11](https://github.com/martianmobile/backtest2live/issues/11). Closing a milestone publishes the version to GitHub Releases and PyPI.
13
13
 
14
- ## v0.3 — run the contract, check any engine, share the output (target mid-October 2026)
14
+ ## v0.3 — any backtest, any engine, shareable output (target mid-October 2026)
15
15
 
16
- Two ways in. A strategy written to the published `StrategyProtocol` contract (the format Validate accepts) runs locally with `bt2live run`. A backtest from any other engine connects through the order-log schema and its adapters.
16
+ The toolkit checks artifacts a backtest already produces; the order-log schema is the connection to the strategy, whatever engine wrote it.
17
17
 
18
- - **`bt2live run`** — [#15](https://github.com/martianmobile/backtest2live/issues/15). Load a strategy package on the published contract, build its inputs from public data, simulate fills at both ends of the band (front of queue vs the `fill-gap` queue proxy) and taker fills through the published simulator. Emits order logs in the `fill-gap` schema and two equity curves.
19
- - **`cost-gap`** — [#16](https://github.com/martianmobile/backtest2live/issues/16). For bar-based backtests, which have no resting orders: each market order re-priced against the real book at its time, with latency. Spread, depth and latency cost vs the backtest's fill price.
18
+ - **`cost-gap`** — [#16](https://github.com/martianmobile/backtest2live/issues/16), merged; ships in 0.3.0. For bar-based backtests, which have no resting orders: each market order re-priced against the real book at its time, with latency. Spread, depth and latency cost vs the backtest's fill price.
20
19
  - **Schema + engine adapters** — [#7](https://github.com/martianmobile/backtest2live/issues/7). One order-log and results schema; importers for Nautilus, LEAN, backtrader, vectorbt, freqtrade, so the export is one command.
21
20
  - **Tear sheet** — [#10](https://github.com/martianmobile/backtest2live/issues/10). One shareable performance artifact with a provenance label.
22
21
  - **MCP server** — [#8](https://github.com/martianmobile/backtest2live/issues/8). The checks, exposed to any AI assistant.
@@ -26,6 +25,7 @@ Two ways in. A strategy written to the published `StrategyProtocol` contract (th
26
25
 
27
26
  ## Later (directional)
28
27
 
28
+ - **`bt2live run`** — [#15](https://github.com/martianmobile/backtest2live/issues/15), on demand. Run a strategy written to a published strategy contract locally, with fills at both ends of the band (front of queue vs the `fill-gap` queue proxy). Built when users ask for it.
29
29
  - **`robustness`** — outlier-trade drop test, bootstrap CIs on Sharpe, parameter-perturbation sensitivity.
30
30
  - **`walk-forward`** — multi-fold rolling/anchored stability of a chosen variant.
31
31
  - **`regime`** — performance by vol/trend regime; flags strategies that only work in one.