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.
- {backtest2live-0.2.0 → backtest2live-0.3.0}/.claude-plugin/marketplace.json +1 -1
- {backtest2live-0.2.0 → backtest2live-0.3.0}/CHANGELOG.md +12 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/PKG-INFO +32 -4
- {backtest2live-0.2.0 → backtest2live-0.3.0}/README.md +29 -1
- {backtest2live-0.2.0 → backtest2live-0.3.0}/ROADMAP.md +4 -4
- backtest2live-0.3.0/examples/market_orders_btcusdt_2024-03-30.csv +1436 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/.claude-plugin/plugin.json +2 -2
- {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/skills/convergence/SKILL.md +2 -2
- backtest2live-0.3.0/plugins/backtest2live/skills/cost-gap/SKILL.md +40 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/skills/fill-gap/SKILL.md +2 -2
- {backtest2live-0.2.0 → backtest2live-0.3.0}/pyproject.toml +3 -3
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/cli.py +10 -1
- backtest2live-0.3.0/src/backtest2live/costgap/__init__.py +57 -0
- backtest2live-0.3.0/src/backtest2live/costgap/engine.py +202 -0
- backtest2live-0.3.0/src/backtest2live/costgap/report.py +99 -0
- backtest2live-0.3.0/src/backtest2live/costgap/sim.py +84 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/engine.py +25 -7
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/report.py +1 -1
- backtest2live-0.3.0/tests/conftest.py +34 -0
- backtest2live-0.3.0/tests/test_costgap.py +155 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/test_fillgap.py +46 -16
- backtest2live-0.2.0/tests/conftest.py +0 -20
- {backtest2live-0.2.0 → backtest2live-0.3.0}/.github/workflows/ci.yml +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/.github/workflows/pr-title.yml +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/.github/workflows/release.yml +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/.github/workflows/testpypi.yml +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/.gitignore +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/.releaserc.json +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/LICENSE +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/RELEASING.md +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/examples/orders_btcusdt_2024-03-30.csv +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/examples/results_converged.csv +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/examples/results_iterate.csv +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/skills/convergence/examples/results_converged.csv +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/plugins/backtest2live/skills/convergence/examples/results_iterate.csv +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/scripts/release_version.py +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/__init__.py +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/__main__.py +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/convergence.py +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/__init__.py +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/data.py +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/src/backtest2live/fillgap/sim.py +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/fixtures/results_drawdown.csv +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/fixtures/results_kill.csv +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/golden/results_converged.md +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/golden/results_drawdown.md +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/golden/results_iterate.md +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/golden/results_kill.md +0 -0
- {backtest2live-0.2.0 → backtest2live-0.3.0}/tests/test_cli.py +0 -0
- {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.
|
|
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.
|
|
4
|
-
Summary: Check a backtest against what live execution would do: convergence, fill-gap
|
|
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
|
|
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
|
|
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 —
|
|
14
|
+
## v0.3 — any backtest, any engine, shareable output (target mid-October 2026)
|
|
15
15
|
|
|
16
|
-
|
|
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
|
-
- **`
|
|
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.
|