btoptionbtoption
Feedback

How our backtesting works.
Including what it doesn't do.

Any backtester can show you an equity curve. Whether you should trust it depends entirely on how the trades underneath were simulated. This page describes exactly what the btoption engine does — data, fills, management, settlement — and lists the things it deliberately does not model. We'd rather you find the limitations here than in your account.

The data

Backtests run on end-of-day historical options chains from ORATS, going back to 2007, topped up nightly with fresh end-of-day data for supported tickers. For every trading day, every expiration and every strike we store the actual closing bid and ask— not just a mid price — plus delta, implied volatility, and the underlying's close.

One row per strike per day. That means the engine sees the market once a day, at the close. It does not have intraday data, and it won't pretend to: there is no tick-level simulation here, and strategies that depend on intraday behavior (0 DTE in particular) are rejected rather than approximated.

Fills: how a trade gets its price

Most backtesters fill you at mid. Real fills are worse than mid, so the results are flattered before you've even looked at them. Our fill model crosses 75% of the bid-ask spread: when you buy, you pay bid + 0.75 × spread; when you sell, you receive ask − 0.75 × spread.

Example: an option quoted 1.00 × 1.20.
Mid would fill you at 1.10.
btoption buys at 1.15 and sells at 1.05.

That's deliberately pessimistic for liquid chains and roughly honest for wider ones. Open positions are marked at mid for P&L and rule evaluation; only actual entries and exits pay the spread. Entries fill at the close of the same day the entry condition is met.

Strike selection

When your strategy says “sell the 16-delta put, 45 DTE”, the engine looks at expirations within ±10 days of your DTE target and picks the strike whose delta is closest to 16 — the same imperfect match you'd get trading a real chain, where the exact 16-delta strike rarely exists.

If a leg can't be filled — no quote, no bid, nothing in the DTE window — the position simply doesn't open that day. Multi-leg positions are all-or-nothing: either every leg fills or no trade happens. The engine never invents a quote to keep a backtest going.

Management: how rules are evaluated

Every open position is checked once per trading day, against that day's closing quotes, in a fixed order: profit target first, then time- and roll-based management rules, then stop loss, then expiration handling. First rule that triggers wins, and the exit fills at that day's actual quoted price through the same 75%-spread model — never at your theoretical trigger level.

Two consequences worth understanding. If the underlying gaps through your stop, you exit at the real (worse) end-of-day price, just like a stop-market order. But a stop level that's breached intraday and recovers by the close is never seen at all — daily data can't catch it, so we don't pretend it can.

Rolls close every leg at the quoted price and re-enter the new position the same day, with the same strike-selection rules. A roll that can't fill doesn't happen.

Expiration

Positions held to expiration are cash-settled at intrinsic value against the underlying's closing price: an option that expires in the money is worth exactly its intrinsic value, one that expires out of the money is worth zero.

The engine does not simulate share assignment. A covered call or cash-secured put that finishes in the money settles in cash rather than delivering a stock position — economically close at expiry, but it means post-assignment share P&L (and wheel-style continuation on the assigned shares) isn't part of the simulation. Early assignment isn't modeled either.

A worked example

Say your strategy is: sell a 16-delta SPY iron condor at 45 DTE, close at 50% of max profit, stop at 2× the credit. On each trading day with no open position, the engine:

  1. Finds the expiration nearest 45 DTE (within ±10 days) in that day's actual chain.
  2. Picks the put and call closest to 16 delta, and the wings per your width — each leg needs a live quote or nothing opens.
  3. Fills all four legs at 75% of each leg's real closing spread, and books the net credit.
  4. Every following close, marks the condor at mid and checks: 50% profit hit? Roll or time rule due? 2× stop breached?
  5. Exits at that day's quoted prices when a rule fires, or cash-settles at intrinsic if it reaches expiration.

Every trade in your results table went through exactly this process. Same strategy, same window, same data — same result, every run. There is no randomness in the simulation.

What we don't model (yet)

Commissions and fees.

Results are gross P&L. At a typical $0.65 per contract per side, a high-frequency strategy loses a meaningful slice of its edge to fees — check your trade count and do that math before trusting a thin edge.

Intraday price action.

Everything happens at the close. Intraday stop breaches, morning gaps that recover, same-day entry-and-exit — invisible by construction.

Share assignment and early assignment.

ITM expirations settle in cash at intrinsic value. No stock positions, no dividend-driven early exercise.

Dividends and corporate actions.

Prices are as recorded historically; splits and dividends aren’t separately adjusted for.

Liquidity beyond the quote.

A strike needs a live bid to be selected, and the fill model charges you most of the spread — but there’s no volume or open-interest filter. On illiquid underlyings, real fills could be worse than simulated ones.

Position sizing and margin.

You trade a fixed number of contracts per position. The engine doesn’t compound, model buying power, or block trades a broker would reject. The equity curve is cumulative dollar P&L; return figures use a $10,000 reference capital.

Near-worthless exits.

Options quoted below $0.05 at exit are treated as closing for zero — a small simplification that slightly flatters short-premium exits.

These are real limitations and we'd rather state them than have you discover them. The practical read: btoption is built to tell you whether a strategy's logic held up historically — not to predict your fills to the cent. If an edge only survives with zero commissions and perfect mid fills, it isn't an edge, and this engine is designed to expose that rather than hide it.

Judge the engine yourself.

Run a backtest and open the trade list — every fill, every roll, every exit is there to inspect. Free, no account.

Run a backtest →

New to backtesting? Start with the options backtesting guide.