Intra-bar-fidelity crypto backtester with overfit gates built in
Project description
honest-bt
Intra-bar-fidelity crypto backtester with overfit gates built in.
pip install honest-bt
Why this exists
In May 2026 I caught 9 separate bugs in my own backtester that were inflating reported Sharpe by up to +5.0. After fixing them, my mean-reversion strategy went from Sharpe -2.12 to Sharpe +1.04 on the same 14 entries — same data, no overfitting, just an honest fee + slippage + exit model.
The tools that caused those bugs (and the ones that caught them) are in this library.
If you've been backtesting against close-to-close prices with flat percentage fees, your Sharpe is wrong. This library fixes the four things that matter most:
- Intra-bar SL/TP fidelity — bar-path inference (bullish: low-then-high; bearish: high-then-low) so the simulator never uses a future extreme's information to tighten SL before checking the prior extreme.
- Realistic fee model — per-fill maker (limit) vs taker (market) distinction × leverage. Ladder TPs charged at maker (
0.02%); SL/trailing/market exits at taker (0.055%). - Funding accrual — 8-hour marks, sign-aware (longs pay positive funding, shorts receive). Plus a funding-drain exit that closes rotten longs.
- Overfit gates — CPCV (combinatorial purged cross-validation) + PBO (probability of backtest overfit) + Probabilistic / Deflated Sharpe per Bailey & López de Prado 2014.
No live trading. No exchange connectors. No strategy templates. This is a library, not a framework.
3-minute quickstart
from datetime import datetime, timedelta, timezone
from honest_bt import Position, simulate_exit
start = datetime(2026, 5, 1, tzinfo=timezone.utc)
position = Position(
symbol="BTCUSDT", side="long", entry_price=100.0, entry_ts=start,
qty=1.0, leverage=5,
stop_loss_pct=4.0, take_profit_pct=8.0,
vol_regime="medium",
)
# Each candle: dict with timestamp, open, high, low, close, (optional) volume.
# Must be ASCENDING by timestamp, AT or AFTER position.entry_ts.
candles = [
{"timestamp": start + timedelta(minutes=i), "open": 100, "high": 105,
"low": 99, "close": 103, "volume": 100.0}
for i in range(60)
]
outcome = simulate_exit(position, candles)
print(f"Exit reason: {outcome.final_reason}")
print(f"Net PnL: {outcome.realized_pnl_pct:+.2f}%")
print(f"Hold: {outcome.hold_minutes} min")
print(f"Fees: {outcome.fees_paid_pct:.4f}% Funding: {outcome.funding_paid_pct:.4f}%")
for fill in outcome.fills:
print(f" fill {fill.reason} @ {fill.price:.2f} (portion {fill.portion:.2f})")
What honest-bt does that Backtrader / VectorBT don't
| Feature | honest-bt | Backtrader | VectorBT |
|---|---|---|---|
| Intra-bar SL/TP path inference | ✓ | partial | ✗ |
| Per-fill maker/taker fees | ✓ | flat % | flat % |
| Funding accrual (crypto perps) | ✓ | ✗ | ✗ |
| Trailing SL two-phase (ease-out + linear) | ✓ | linear only | ✗ |
| Ladder TP (3 levels, vol-regime spacing) | ✓ | manual | manual |
| Funding-drain exit | ✓ | ✗ | ✗ |
| Reversal-detection exit (7 HTF signals) | ✓ | ✗ | ✗ |
| CPCV + PBO overfit gate | ✓ | ✗ | ✗ |
| Probabilistic / Deflated Sharpe (Bailey-LdP 2014) | ✓ | ✗ | ✗ |
| Slippage model (bps per fill side) | ✓ | manual | ✗ |
| Production-validated (caught 9 of its own bugs) | ✓ | ? | ? |
This is a crypto-first library. Spot / margin trading works fine, but the differentiator is in perpetual futures.
API surface
Core
from honest_bt import (
Position, # input dataclass
FundingPoint, # optional funding rate history
FillEvent, # output: each partial fill
ExitOutcome, # output: full per-position result
simulate_exit, # the main function
)
Metrics & validation
from honest_bt import (
BacktestMetrics, compute_metrics,
deflated_sharpe, expected_max_sharpe,
beats_baseline, beats_baseline_deflated,
walk_forward_gate,
split_outcomes_at, split_outcomes_into_folds,
)
CPCV
from honest_bt import (
CPCVSplit, cpcv_split,
compute_pbo, aggregate_cpcv_metrics,
)
The 9 bugs we caught (May 2026)
Long-form post coming. Short list:
- Sharpe double-flip bug — metrics aggregator was negating short-side returns twice (sign error). Variants ranked best on training Sharpe were actually the worst on test.
- DCA simulator MTM bug — accumulation strategy was reporting realized-only PnL, hiding mid-cycle drawdowns that hit -30%. Honest MTM Sharpe collapsed from inflated +16 → -0.13.
- Limit-timeout fee blend — maker entries were never charged taker fees on the ~7% of orders that timed out, systematically under-counting costs.
- HTF cursor per-timeframe bug — the higher-timeframe indicator cache was silently skipping 5-15% of evaluations when the cursor advanced across two timeframes simultaneously.
- MR clock-source mismatch — backtest cooldown gate used
time.monotonic()while live used wall-clock; cooldowns effectively disabled in backtest, fired in live. - Funding-arb paper-mode signal swallow — paper-mode emitted NOTIFICATION events instead of SignalEvents; "0 trades dormant" verdict was a harness bug, not a strategy result.
- Variant-yaml params no-op — evolution loop's
params:wrapper silently dropped overrides; "promising" variant results were just baseline noise. - Graveyard dead-code on live —
AssetGraveyard.refresh_for_asset()was never called in production; backtest enforced it strictly. Live looked better than it should have, backtest worse. - K8 magnitude scaling inverted — liquidation-cascade reversion strategy's signal size was inversely correlated with cascade magnitude. Smaller cascades → larger positions.
Lesson: a backtest that doesn't reproduce live behavior to within sub-1% PnL is lying. honest-bt is the de-couple-and-port of the harness that found these.
Roadmap
- v0.2 (Q2 2026): live data adapters for Binance / Bybit / Hyperliquid (CSV ingestion only in v0.1)
- v0.3 (Q3 2026): stocks / options examples (exit model is asset-agnostic once SL/TP/trailing semantics are defined)
- v0.4 (Q4 2026): hosted backtest API (paid tier — see
honest-bt-cloud)
Contributing
PRs welcome. Please include a regression test for any bug fix. Style: ruff check src/ tests/ must pass.
License
MIT. Use it freely, sell paid services around it, fork it. If it saves you from a Sharpe-inflation bug, open an issue and tell us — we'd love to add it to the case-studies list.
Related work
- López de Prado, M. (2018). Advances in Financial Machine Learning. Wiley. (CPCV chapter)
- Bailey, D. & López de Prado, M. (2014). The Deflated Sharpe Ratio: Correcting for Selection Bias, Backtest Overfitting, and Non-Normality. Journal of Portfolio Management.
- Stoic.ai / QuantPedia blog posts on slippage modeling for crypto perps.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file honest_bt-0.1.0.tar.gz.
File metadata
- Download URL: honest_bt-0.1.0.tar.gz
- Upload date:
- Size: 39.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25c8e5b822f78f845dd02ed60e4ac1f26fd7dc70bbf19d038b5893960e74c672
|
|
| MD5 |
0594979dad38ae681d03604aac62d85f
|
|
| BLAKE2b-256 |
77130a3f7ac12c7ff724c7920f2b65b6ec9a9b30da7cd726df1482a10ad284e6
|
File details
Details for the file honest_bt-0.1.0-py3-none-any.whl.
File metadata
- Download URL: honest_bt-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b13f32c0460cef762496c6621be33389c758f11671b45975c704fb94ba3c6bab
|
|
| MD5 |
048aefcd4bcc0e28f2e4f66b1e6a8334
|
|
| BLAKE2b-256 |
ed0173de7020f2a3ce8819a7c9042924323d7d700215ee9faa76168a816daa92
|