StratVerra
METHODOLOGY

How a backtest fills an order

A backtest is worth exactly what its fill assumptions are worth. A model that fills every order at the midpoint will make almost any premium-selling strategy look profitable, and most published backtests never say which one they used.

Here is ours, in full — the rules the engine actually applies, and the things it deliberately does not pretend to know.

The short version

An order submitted during one minute can fill no earlier than the next one. By default it crosses the spread — you buy at the ask and sell at the bid. It fills completely or not at all. If any leg is missing the quote it needs, nothing fills and the order waits. Commission is charged per contract on every leg, both ways.

When an order can fill

The engine walks the session one slice at a time. Within a slice it does three things in a fixed order, and the order is the point:

  1. Step 01

    Cancellations are applied. An order cancelled during the previous slice is gone before anything is matched, so it cannot fill on its way out.

  2. Step 02

    Resting orders are matched, in the order they were submitted, against this slice's prices.

  3. Step 03

    Your strategy sees the slice and may submit new orders. Those orders are not matched until the next slice comes round.

That last point is the no-look-ahead guarantee: a strategy can never act on a price and be filled at that same price. It is not a setting. The engine has an optimistic same-slice mode in its configuration type, and nothing in the product ever selects it — every backtest you run uses next-slice fills.

Day orders that never filled expire at the close without a final matching pass, so an order placed in the last minute of the session cannot fill that day.

The three fill models

You choose one per run. All three price every leg of the combo, sum the legs into a net, and fill only if that net is at or better than the order's limit — and all three are all-or-none.

MarketableLimit

Default · conservative

buy legs fill at the ask · sell legs fill at the bid

You pay the spread, every time, in both directions. This is the default because it is the assumption least likely to flatter a result: if a strategy survives crossing the spread on every entry and every exit, the spread is not what was holding it up.

Midpoint

Optimistic

every leg fills at the midpoint of its quote

Assumes you are always filled halfway across. Real fills on a liquid SPX spread often land near the mid, and just as often do not. Useful as an upper bound rather than an estimate — the gap between this and the default is the spread's share of your edge.

Slippage

Tunable

midpoint, moved against you by a fixed amount per contract

Buys fill above the mid and sells below it, by whatever you set. Sits between the other two, and is the honest choice when you know roughly what your own fills look like: set it from your broker statements rather than from what makes the equity curve look best.

The default is the conservative one. Midpoint is there because it is the assumption most published backtests make silently — running the same strategy both ways tells you how much of its edge is really just the spread.

What happens when the data is thin

Nothing is invented. If a leg has no quote on the side that leg needs — no ask for something you are buying, no bid for something you are selling — the combo does not fill. It rests and tries again next slice.

The two mid-based models are stricter still: a midpoint only exists when both sides of the quote do, so a one-sided market produces no fill rather than a price derived from half a quote.

This is why a backtest over an illiquid stretch shows fewer trades rather than suspiciously good ones. An engine that fabricates a price where the market had none does not produce a more complete result — it produces a more confident wrong one.

Commissions

A flat rate per contract, summed across every leg of the order, charged on the fill. It is applied at run time rather than baked into the strategy, so the same strategy can be re-run at a different rate without being edited.

Worked example

A one-lot iron condor is four legs, so it is four contracts. At $0.65 per contract it costs $2.60 to open, and — because closing it is another four-leg order — $2.60 to close.

4 contracts × $0.65 × 2 sides = $5.20 round trip

On a condor collecting $2.05 of credit, that is a meaningful share of the trade. It is also the number most spreadsheet backtests leave out.

Stops

A stop arms on the combo's midpoint net reaching your trigger — not on a single leg, and not on the underlying. Once armed, a stop takes liquidity: it crosses the spread and is not held back by a limit price, which is what a stop is for.

A stop-limit arms the same way and then rests as an ordinary limit order at your price. Arming latches: if the midpoint later recovers past the trigger, the order stays working rather than quietly un-arming.

Margin

Every backtest works out what the open book requires under Reg-T, the margin rules a US broker applies to an ordinary account, and checks each order against the account's equity before accepting it. An order that would push the requirement past what the account holds is refused outright. It never enters the book, and it comes back to the strategy as a rejected order rather than as a silent skip.

That means a run can trade less than the strategy asked for. The run page reports how many orders were refused for exactly this reason, next to the peak and average requirement, so a thinner trade count than you expected has somewhere to be explained.

How the requirement is worked out

Positions are grouped by underlying and expiry, and each group is charged the lesser of two numbers: what a broker charges for a short option with nothing protecting it, and the worst the group could lose at expiry. A spread with a long behind every short is charged its real worst case. A naked short has no worst case, so it pays the percentage instead. One rule, and no separate treatment for a condor, a butterfly or a single short.

The requirement is measured at every point in the session, and each day contributes its highest reading. Measuring at the close would report nothing at all for a same-day strategy, which is flat every night by construction, while it had tied up capital in every session.

Three things follow that are worth knowing before you read a number off a run:

  • Reg-T only, so a large account sees refusals it would not see live

    An account on portfolio margin gets requirements well below Reg-T's. This model does not, so for such an account it is stricter than reality: a strategy that would trade fine live can be refused here. It errs towards refusing, never towards allowing.

  • A long in one expiry never protects a short in another

    Grouping is by underlying and expiry, so a calendar or diagonal spread is charged as though the short leg stood alone. On the cash-settled indices that is close to how brokers treat them; on the ETFs it overstates what a real diagonal costs.

  • Live trading is advisory, and your broker decides

    A live run works out the same figure and logs a warning, then submits the order anyway. Your broker is the authority on what your account can carry, and a model that is stricter than the broker must not refuse a trade the broker would have taken.

What this deliberately does not model

Every simulation is wrong somewhere. These are the places ours is, so you can judge a result rather than trust it.

  • Partial fills

    An order fills completely or not at all. A real broker can give you two of your four contracts and leave the rest working, and the simulator never will — it is incapable of reporting a partial fill, and a test pins that so strategy logic cannot come to depend on a signal it will never receive.

  • Your own size

    The price you get does not depend on how much you trade. A one-lot and a hundred-lot fill at the same quote, which is roughly true at one lot and steadily less true above it.

  • Queue position

    Resting orders are matched in the order you submitted them, which is not the order an exchange would fill them in. There is no model of who else is waiting at your price.

  • Quote size

    A midpoint is the plain average of bid and ask. It is not weighted by how much is available on each side, so a quote with a hundred contracts bid and one offered is treated as balanced when it is not.

None of this makes a backtest useless. It makes it a floor rather than a forecast — and it is the reason the same engine, unchanged, is what places your live orders. Whatever is wrong in the simulation is at least wrong in a way you can go and measure, because the code path is the same one.