engine.backtest¶
The deterministic event loop and the frozen BacktestResult it returns. One loop, strict time order, no look-ahead.
backtest
¶
The deterministic backtest engine: one loop, strict time order, no look-ahead.
Per bar (the three-phase settle):
1. session boundaries due before the bar are enforced (16:10 ET flatten,
17:00 ET session close -> MLL ratchet, day roll);
2. the SimBroker matches the bar (fills + intrabar rule breaches, in path
order) and queued user events (on_order/on_fill/on_position) dispatch;
3. the strategy sees the completed bar (on_bar) and may submit orders,
which are accepted at the bar's close timestamp — eligible from the NEXT
bar (the accepted_ts firewall).
Determinism: single-threaded, a single monotonic event order, all state transitions driven by feed timestamps through the TestClock. Two runs over the same inputs produce byte-identical results.
RoundTrip
¶
Bases: Struct
One flat-to-flat excursion in a single contract — a "trade" in the colloquial sense, as opposed to the half-turns the gateway reports.
Boundaries are unambiguous and need no new convention: a round trip opens when a contract goes from flat to positioned and closes when it returns to flat. A FLIP (long straight to short in one fill) closes one round trip and opens the next at that instant; the flip's single half-turn and its costs are attributed to the round trip being CLOSED, so no fill is counted twice.
This is a REPORTING grouping over the broker's own FIFO half-turns. It does
not re-derive P&L: gross_pnl is the sum of the profit_and_loss
figures the broker already computed, so the open question of how the live
gateway pairs fills (docs/topstep-rules.md §9) cannot change these numbers
without changing the half-turns first.
max_qty
instance-attribute
¶
Largest position size held during the excursion (scale-ins included).
gross_pnl
instance-attribute
¶
Sum of the closing half-turns' realized P&L. GROSS — no fees.
costs
instance-attribute
¶
Fees + commissions charged on every half-turn in the excursion.
net_pnl
instance-attribute
¶
gross_pnl - costs. This is what the excursion actually earned.
initial_risk
instance-attribute
¶
Dollars at risk when the position was opened, from the bracket stop
distance at entry (stop_loss_ticks x tick value x size, summed over
every opening fill).
None when ANY opening fill carried no bracket stop — a signal-exit
strategy has no defined risk, and guessing one would manufacture an
R-multiple out of nothing. Captured AT ENTRY: moving or trailing the stop
afterwards does not change it, which is the conventional meaning of R.
r_multiple
instance-attribute
¶
net_pnl / initial_risk — the excursion's return in units of what it
actually risked. NET basis deliberately: R answers "what did I make
against what I put up", and the fees were genuinely paid. None
whenever initial_risk is.
BarEquity
¶
Bases: Struct
One bar's equity envelope and the MLL floor in force during it.
high/low are realized + unrealized equity — the same figure the
rule kernel breach-checks — sampled over the modelled intrabar path, NOT
from real ticks (Tier-0 ships bars only). floor is the trailing MLL
floor as of this bar, so low - floor is how close the account came to
termination while the bar printed.
BacktestResult
¶
Bases: Struct
End-of-run outcome (msgspec-serializable -> golden-master friendly).
BacktestEngine
¶
BacktestEngine(*, feed: DataFeed, broker: SimBroker, strategy: Strategy, clock: TestClock, session: SessionTimes = TOPSTEP_SESSION, recorder: Recorder | None = None)
Drives feed -> broker -> strategy under a TestClock.
Source code in src/topstep_backtest/engine/backtest.py
run
async
¶
run() -> BacktestResult
Source code in src/topstep_backtest/engine/backtest.py
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 | |