QQ 301, 3 min read
What the tool does not model
Each line is a statement about the code as written.
Fills and the market
- No intrabar path. Fills happen at a bar's open (or a price the script supplies). The engine never looks inside a bar. It does not know whether the high or the low came first.
- No order types. There are no limit, stop or take-profit orders in the
engine. A script can compute a stop level and write an explicit
exitprice, and the engine will accept it without checking that the bar's range contained that price or that it was reachable before another level. - No gap handling for stops. Because stops are not modelled, a stop that would have been jumped by a gap is filled at whatever price the script wrote.
- No partial fills, no rejections, no queue. Every trade fills in full.
- Liquidity is not a constraint unless you turn it on. Size is unlimited
by default. Only
slippage_model: "sqrt_impact"makes size cost something, and it needs a real volume column. - Spread is a constant or a per-bar average. It does not widen at the
open, around news or at rollover, unless your data's
bid/askcolumns carry that. - Latency is in whole bars. There is no sub-bar latency.
The account
- No margin model. There is no margin requirement, margin call or
stop-out level. The only liquidation is equity reaching zero. An explicit
qtycan be any size. - One currency. P&L is
price difference × qty, in the quote currency of the instrument, added straight to the account. There is no conversion to a different account currency, no contract multiplier, no pip-value table and no lot-size rounding or minimum size. - Financing is a flat annual rate. No broker swap table, no triple-swap day, no dividends, no borrow fees or locate availability for shorts.
- Commission is a percentage of notional only. No per-lot or per-trade fixed fee, no minimum ticket, no tiered schedule.
- No taxes, no funding costs, no interest on idle cash.
- One instrument's bars per run.
dfis one dataset. A script can read others throughdata[...], but trades are filled and marked ondf's prices only. There is no shared-balance portfolio backtest in this build.
Data
- No corporate actions. Splits, dividends and symbol changes are not adjusted for. The engine uses the prices in the file as they are.
- No survivorship handling. If your dataset contains only instruments that still exist, the engine cannot know.
- No session calendar. The engine does not know exchange hours or holidays. Annualisation in the results tiles assumes bars around the clock (3.4).
- Provenance is recorded, not verified, for your own files. A file you
import is labelled
user-import. Nothing checks it against any source.
Statistics and validation
- The Sharpe in the tiles and the Sharpe in the checks are different
numbers (per-bar with a 365.25-day year, versus daily with
sqrt(252)). - No risk-free rate anywhere in the Sharpe, Sortino or alpha calculations.
- Monte Carlo resamples trades independently. Clustered losses are broken up.
- SPA and Romano–Wolf over-reject, and the bootstrap interval under-covers on autocorrelated returns (4.6, with the measured numbers).
- The trial registry and the holdout counter are local files keyed on the code hash. They count what the terminal saw. They cannot count variants you tried elsewhere, by hand, or under edited code, and they can be deleted.
- No live comparison.
live_trackingis a placeholder that always skips. - A passing verdict is not a forecast. Every check asks whether the backtest is evidence. None of them predicts next year.
Source. Fill prices backtest/runner.py:693-713; no range check on
explicit prices (the only price checks are finite and > 0,
backtest/runner.py:709-713, and positive after costs,
backtest/runner.py:468-486). Sizing and P&L backtest/runner.py:1167-1212.
Ruin backtest/runner.py:434-466. Sharpe backtest/runner.py:1605-1616
versus backtest/stats.py:537-555. Tool default bars
engine/server.py:4343; plain backtest limit: 0
engine/server.py:4272. Live tracking
backtest/institutional.py:238-239.