replaybt¶
Realistic backtesting engine for algo traders and AI agents.
The engine owns execution — your strategy only emits signals. No look-ahead bias by default. Gap protection, adverse slippage, and fees are built in, not bolted on.
Why replaybt?¶
Most backtesting frameworks let you fill orders at the close of the bar that generated the signal. That's not how real trading works. In production, you see the bar close, compute indicators, and fill at the next bar's open — at a worse price.
replaybt enforces this by design:
- Signals at T, fills at T+1 — the engine queues market orders and fills at the next bar's open
- Gap protection — if the open gaps past your stop, you get the open (not the stop level)
- Adverse slippage — entries fill worse, exits fill worse, always
- 1-minute resolution — check stops intra-bar, not just at bar boundaries
Features¶
| Category | What you get |
|---|---|
| Execution | 4-phase loop, gap protection, adverse slippage, maker/taker fees |
| Indicators | 11 built-in (EMA, SMA, RSI, ATR, CHOP, Bollinger, MACD, Stochastic, VWAP, OBV) + multi-timeframe resampler |
| Orders | Market, limit (with timeout), stop orders, scale-in via merge |
| Risk | Breakeven stops, trailing stops, partial take profit |
| Multi-asset | Time-synchronized multi-symbol loop with portfolio-level metrics |
| RL-ready | StepEngine with gym-like step(action) / reset() API |
| AI-friendly | DeclarativeStrategy from JSON config, no Python class needed |
| Validation | Static bias auditor (11 checks), delay test, out-of-sample split |
| Optimization | Parallel parameter sweep, walk-forward, Monte Carlo |
| Live-ready | Async data providers for Hyperliquid and Lighter exchanges |
Install¶
Optional extras:
pip install replaybt[live] # + aiohttp, websockets
pip install replaybt[plots] # + matplotlib
pip install replaybt[data] # + requests (exchange fetchers)
pip install replaybt[dev] # + pytest, pytest-cov
Quick Example¶
from replaybt import BacktestEngine, CSVProvider, Strategy, MarketOrder, Side
class EMACrossover(Strategy):
def configure(self, config):
self._prev_fast = self._prev_slow = None
def on_bar(self, bar, indicators, positions):
fast = indicators.get("ema_fast")
slow = indicators.get("ema_slow")
if fast is None or slow is None or self._prev_fast is None:
self._prev_fast, self._prev_slow = fast, slow
return None
crossed_up = fast > slow and self._prev_fast <= self._prev_slow
self._prev_fast, self._prev_slow = fast, slow
if not positions and crossed_up:
return MarketOrder(
side=Side.LONG,
take_profit_pct=0.05,
stop_loss_pct=0.03,
)
return None
engine = BacktestEngine(
strategy=EMACrossover(),
data=CSVProvider("ETH_1m.csv", symbol_name="ETH"),
config={
"initial_equity": 10_000,
"indicators": {
"ema_fast": {"type": "ema", "period": 15, "source": "close"},
"ema_slow": {"type": "ema", "period": 35, "source": "close"},
},
},
)
results = engine.run()
print(results.summary())
Next Steps¶
- Getting Started — install, run your first backtest, understand the output
- Concepts — how the execution loop, signal timing, and gap protection work
- Cookbook — working recipes for common patterns
- API Reference — every class, method, and parameter