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-framework.md directly for raw markdown (easy copy/paste into an LLM).

Backtesting Framework

This knowledge base explains how to design a realistic options backtesting framework. It is written for engineers who want to build or audit a simulator, not for readers looking for a trading recommendation.

The public reference implementation is cutebacktests. It packages an intraday/options runtime, opening-range profile helpers, provider adapters, persistence, and robustness utilities. cute-intraday-option-strats is a narrower strategy package on top of that runtime.

Architecture spine

A credible framework keeps five responsibilities separate:

LayerJob
Data modelStore point-in-time underlyings, contracts, quotes, trades, bars, and coverage metadata.
Replay engineWalk the market forward using only information available at each simulated timestamp.
Strategy layerTurn historical state into a setup, signal timestamp, direction, and exit policy.
Instrument expressionConvert an underlying setup into an option contract or structure.
Research layerRun folds, holdouts, diagnostics, and portfolio aggregation without changing simulator rules.

This separation is the main design rule. A strategy should not know how the option provider paginates. A contract selector should not compute signal features. A research sweep should not rewrite fill semantics mid-run. When those boundaries blur, it becomes hard to tell whether a result came from edge, leakage, or a convenient simulator shortcut.

Minimum viable framework

The smallest useful options framework needs:

  • Historical contract discovery by simulated date, not today's chain.
  • Underlying bars for signal generation and option quotes or bars for execution.
  • A replay loop that makes signal decisions before entry decisions.
  • A contract selector with explicit DTE, moneyness, spread, open-interest, and volume rules.
  • A fill model that records the side of the market used and rejects untradable conditions.
  • A trade log with enough metadata to explain skipped trades and filled trades.
  • Walk-forward or holdout tests that run the same engine rules outside the selection window.

In cutebacktests, the public shape is intentionally explicit:

bash
from datetime import datetime

from cutebacktests import (
    IntradayOptionsBacktestConfig,
    IntradayOptionsBacktester,
    get_opening_range_profile,
)

profile = get_opening_range_profile("c4_long_only_rr15")
config = IntradayOptionsBacktestConfig(
    ticker="SPY",
    start=datetime(2025, 1, 1),
    end=datetime(2025, 1, 31),
    return_trade_log=True,
    **profile.to_intraday_strategy_kwargs(),
)

The concrete profile can change. The framework standards should not.

Private-to-public naming

Some early internal research code used legacy names tied to its original project history. The public extraction uses behavior-based names instead: IntradayOptionsBacktester, IntradayOptionsBacktestConfig, IntradayStrategyConfig, cutebacktests.backtest.intraday_options, and cutebacktests.strategies.intraday. Public docs should use the public names.

Read next

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.