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.corefor low-level PyO3 smoke and runtime objectsshadow_backtest.futuresfor futures business-facing objects and next-bar replayshadow_backtest.stocksfor 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_rqdatashadow-ingest- a future
shadow-dataprovider - 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/