跳转至

Shadow Backtest

shadow-backtest is the package-first execution core for China-market backtests.

它是当前 all-in-one backtest engine 的核心项目:Rust owns the strict execution runtime, Python remains the external control plane for factors, providers, strategies, ensembles, and reports.

Boundary

The core boundary is deliberately narrow.

Layer Owns
Rust shadow_backtest_core dense runtime catalogs, asset-specific ledgers/rules, deterministic strict loop
PyO3 facade shadow_backtest.core explicit bridge from Python objects into Rust profiles
Python package surfaces business-facing stock/futures/options objects, provider compilation, replay helpers
Downstream workspaces factor planning, universe construction, provider loading, report products, evidence archives

The Rust modules under common/, assets/, engines/, and profiles/ are internal implementation details. They are not a stable Rust SDK surface.

Development

uv sync --dev
uv run maturin develop
uv run pytest
cargo test --manifest-path shadow_backtest_core/Cargo.toml

Package-First Control Plane

shadow-backtest is a package, not a click-first app. CLI commands, when present, should be thin wrappers over package APIs.

Python callers should choose explicit package surfaces:

  • shadow_backtest.core for low-level PyO3 smoke and runtime objects
  • shadow_backtest.futures for futures business-facing objects and next-bar replay
  • shadow_backtest.stocks for stock rebalance and order execution workflows

Futures Surface

The futures package compiles business-facing specs into dense runtime data.

from shadow_backtest import futures

compiled = futures.compile_futures_run([
    futures.FuturesInstrumentSpec("rb2610", 1.0, 10.0, 0.08),
])

result = futures.run_single_market(
    compiled,
    futures.FuturesMarketSpec(1, "rb2610", 3000.0, 3000.0),
    [futures.FuturesOrderSpec(1, "rb2610", "buy", "open", 1, 3000.0)],
    initial_cash=100000.0,
)

Production-style scheduling uses run_next_bar(...): submitted orders are queued and can only fill on a later eligible market event. It supports day/GFD and IOC order life, forced liquidation, lifecycle windows, explicit contract rolls, warnings, and optional state_trace.v1 output for backend parity checks.

Stock Surface

The stock package accepts explicit market rows and rebalance intents.

from shadow_backtest import stocks

compiled = stocks.compile_stock_run([
    stocks.StockInstrumentSpec("000001.XSHE", 0.01, 100),
    stocks.StockInstrumentSpec("600000.XSHG", 0.01, 100),
])

result = stocks.run_rebalance_backtest(
    compiled,
    [
        stocks.StockMarketSpec(1, "000001.XSHE", 10.0, 10.0),
        stocks.StockMarketSpec(1, "600000.XSHG", 20.0, 20.0),
    ],
    [stocks.StockRebalanceIntent(1, ("000001.XSHE", "600000.XSHG"))],
    initial_cash=100000.0,
)

T+1, lot sizing, cash-limited buys, suspension, and one-way limit checks belong in the stock runtime path.

Factor And Market Data Boundaries

Strategies consume factor definitions and values through shadow_factor.api.

Market rows are explicit execution inputs. They may come from:

  • download_rqdata
  • shadow-ingest
  • a future shadow-data provider
  • a downstream research adapter

shadow-factor is the factor-definition/value boundary, not the trade tape or broker state boundary.

Guorn Replay Boundary

Guorn single-factor strategy definitions are packaged as JSONL config inside shadow-backtest.

Evidence, generated rebalance intents, replay outputs, and comparison artifacts remain in the sibling guoren_replications workspace. The replay path must not access the Guorn website.

Run the packaged registry through the stock execution layer:

uv run python scripts/run_guorn_registry_replay.py --max-strategies 3

By default, replay results are written under:

../guoren_replications/artifacts/shadow_backtest_registry_replays/