CuteMarkets Docs

Backtesting Framework

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

Tip: open /docs/options-contract-selection.md directly for raw markdown (easy copy/paste into an LLM).

Options Contract Selection

Options contract selection is where many backtests become unrealistic. The signal may be generated on the underlying, but the traded instrument is an option contract with its own listing history, liquidity, spread, expiration, and strike geometry.

Selection inputs

A contract selector should receive:

  • underlying ticker
  • trade date
  • signal direction
  • selection timestamp
  • underlying price at entry decision time
  • DTE window and target DTE
  • option type or structure mode
  • moneyness, delta, or strike ranking rules
  • spread, volume, open-interest, and quote-quality limits
  • provider status and data coverage metadata

It should return either a selected contract or a structured rejection payload. Silent failure is not acceptable because the rejection mix is part of the research evidence.

Historical availability first

Selection must start from contracts that existed on the simulated date. A safe sequence is:

  1. Fetch listed contracts by underlying and as_of.
  2. Restrict to the DTE and expiration window.
  3. Restrict to the side needed by the strategy.
  4. Rank contracts using only fields available at the selection timestamp.
  5. Validate quote, spread, volume, and open-interest rules.
  6. Store the final selected symbol and every rejection reason.

When a framework supports both single-leg and vertical structures, select the primary leg first, then select the paired leg from the same causal universe. Do not backfill a cleaner structure from a later chain.

Ranking rules

Common ranking criteria:

CriterionWhy it matters
DTEControls decay, gamma exposure, and historical availability.
MoneynessKeeps strike choice tied to the underlying price at entry.
DeltaUseful when greeks are available point-in-time.
SpreadPrevents fills in contracts that are too expensive to cross.
Open interestScreens out structurally inactive contracts.
Entry volumeConfirms activity around the trade window.
Intrinsic/extrinsic mixAvoids selecting contracts with poor payoff geometry for the setup.

The selector should prefer deterministic ranking. If two contracts tie, use a stable tie-breaker such as expiration, strike distance, symbol, and provider order.

Cache keys

Contract selection caches are useful but dangerous. Include every value that can affect the result:

  • ticker and trade date
  • direction and option type
  • contract status
  • min, target, and max DTE
  • entry underlying price or moneyness bucket
  • spread and liquidity thresholds
  • quote-ranking mode
  • selection timestamp when quote-aware ranking is used
  • structure mode and paired-leg settings

If the entry underlying price changes, the best strike can change. If the selection timestamp changes, the quote-aware rank can change. Both belong in the cache key.

Rejection payloads

Good rejection reasons are specific:

  • no_contract_provider
  • no_contracts_in_dte_window
  • open_interest_below_min
  • quote_missing_near_entry
  • spread_above_max
  • entry_volume_below_min
  • vertical_pair_missing
  • debit_to_width_ratio_too_high

Specific rejections make research debuggable. They also let a later tool explain whether a strategy failed because the signal was weak or because the market was not tradable.

Read next: Backtesting Data Model, Backtesting Execution Realism, and Contracts.

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.