CuteMarkets Docs

Backtesting Framework

Framework guides for engineers building realistic options backtests with causal data, quote-aware fills, and robust validation.

Tip: open /docs/backtesting-execution-realism.md directly for raw markdown (easy copy/paste into an LLM).

Backtesting Execution Realism

Execution realism is the difference between a signal backtest and a tradable options backtest. Options do not trade continuously across every strike. Last price can be stale, midpoint can be optimistic, and a few cents of spread can dominate a short-dated trade.

Bars, quotes, and trades

Use each data object for the job it answers:

DataBest use
Underlying barsSignal features and underlying stop/target logic.
Option barsOption price path and fallback valuation.
Option quotesExecutable bid/ask context and spread quality.
Option tradesActivity evidence and last-sale context.

A serious framework often uses bars for path and quotes for fills. For a long option, entry near the ask and exit near the bid is more conservative than assuming midpoint both ways. More advanced models can allow midpoint or price improvement only when quote freshness, spread width, and trade evidence support it.

Fill policy

Make the fill model explicit:

bash
def long_option_entry_fill(bid: float, ask: float, mode: str) -> float:
    if ask <= 0 or bid < 0 or ask < bid:
        raise ValueError("invalid_quote")
    if mode == "marketable_limit":
        return ask
    if mode == "mid_with_haircut":
        return (bid + ask) / 2 + 0.25 * (ask - bid)
    raise ValueError(f"unsupported_fill_mode: {mode}")

The important part is not this exact formula. It is that the simulator records what side of the market was used and rejects quotes that do not pass the policy.

Stops and exits

Stops and targets must be observable. If a premium stop uses option quotes, the framework should check quotes after entry and apply the stop only when a quote pair proves the stop level was reachable. If an underlying stop uses underlying bars, the option exit still needs a corresponding option quote or option bar at the exit time.

Common exit reasons:

  • profit target
  • premium stop
  • underlying stop
  • time stop
  • end-of-day exit
  • max-hold exit
  • invalid or missing quote
  • forced rejection because entry would occur after exit

Every exit should preserve the timestamp and price source.

Spread and slippage

Track cost in dollars, not only percentages. A 0.10 option spread is 10 dollars per contract before commissions. For short-dated options, that may be larger than the expected edge.

Useful execution metrics:

  • entry spread percentage
  • exit spread percentage
  • spread as a share of premium
  • expected move to spread ratio
  • entry quote age
  • exit quote age
  • rejected trade count by reason
  • fill source: quote, bar fallback, or proxy

Rejecting trades is success

A realistic simulator should reject trades when the market is not good enough. That can reduce trade count and make performance less exciting, but it improves the scientific value of the result.

Good rejection reasons include:

  • no quote near entry
  • quote crossed or invalid
  • spread too wide
  • ask below minimum premium
  • entry after effective exit
  • stop/target cannot be priced
  • quantity below one after risk caps

Read next: Quotes, Trades, Backtesting Robustness, and Options Backtest Realism Checker.

Next steps

Move from the docs into the product workflow

If you are evaluating the API rather than implementing a specific endpoint right now, the product pages map the live, historical, and chain workflows directly.