7. Backtest and replay from the command line¶
Backtest¶
"$BIN"/tutorial-backtest --config configs/backtest-example.toml --data synthetic \
--strategy first_mm --param edge_bps=0.002 --seed 7 --duration 60 \
--out runs/tutorial/backtest --journal-out runs/tutorial/backtest.fmj
--config configs/backtest-example.tomlsupplies the synthetic market, fees, risk limits and the fill model. Its strategy isbasic_mm;--strategy first_mmreplaces it and ignores its[strategy.params].--param edge_bps=0.002sets a parameter; repeat--paramfor more. An unknown name is an error (exit codes).--seed 7 --duration 60seeds the synthetic market and the simulated venue and runs 60 s of simulated time. The engine's random generator keeps[engine] rng_seed(1 in this file).
tutorial-backtest: note: ignoring [strategy.params] of 'basic_mm' for --strategy first_mm
backtest first_mm seed=7 md_events=15148 steps=16808 wall=0.03s
net pnl -25.7849
fills (maker / taker) 471 (471 / 0)
...
outbound messages / sha256 1189 / 6ccab4815434470ef46161a79f32f6bf18ef422229d26be328adacc73df80812
where the PnL came from (quote currency, 25791.74 traded notional)
gross spread capture 0.0068 +0.003 bps of 25791.74, mid at the fill
fees paid -25.7917
= net -25.7849
...
results written to runs/tutorial/backtest/{equity,fills,orders}.csv and summary.json
session journal: runs/tutorial/backtest.fmj
| File | Content |
|---|---|
summary.json |
the metrics of the summary table |
equity.csv |
one row per 1 s bar: realised and unrealised PnL, fees, position, mid, which sides were quoted |
fills.csv |
one row per fill: time, side, price, quantity, fee, liquidity, the mid and the touch at the fill, the queue position, and the mid at each markout horizon |
orders.csv |
one row per order message sent: new, cancel or replace |
Prices, quantities, fees and PnL in the CSV files are decimals in quote currency or base units; ts_ns columns are nanoseconds since the epoch. An empty markout column means the run ended before that horizon, so the fill is left out of it (Backtesting).
Report¶
One self-contained page from those four files: the equity curve and the inventory on one time axis, the PnL split into spread capture, mid drift and fees, the markout at each horizon, the fill quality, the counts and the configuration (Run report). --config is optional; it names the instrument's currencies. With the Python package installed, fastmm report runs/tutorial/backtest is the same command.
Replay¶
journal runs/tutorial/backtest.fmj: format v3, 18067 messages (15148 market data, 1189 outbound), rng_seed 1, strategy 'first_mm'
session epoch 1, quoting enabled, cancel-replace venues 0, engine clock recorded
config embedded in the journal (hash 4b67f35b82760ab2)
replay strategy=first_mm events=16814
recorded outbound 1189 msgs sha256 6ccab4815434470ef46161a79f32f6bf18ef422229d26be328adacc73df80812
replayed outbound 1189 msgs sha256 6ccab4815434470ef46161a79f32f6bf18ef422229d26be328adacc73df80812
replay MATCH
The journal holds the events the engine consumed and the configuration after the command-line overrides, so the replay needs no configuration file. --verify compares each order message the replayed engine sends with the recorded copy and exits with code 1 on the first difference, which it prints. A mismatch with the same binary means the strategy used something that is not an engine input (Determinism). rng_seed in the first line is the recorded [engine] rng_seed. The replayed strategy's logs go to stderr.