← All projects

02 · Python · Backtest research

ETFArbitrage

A research-only backtest of a Chinese A-share 期现套利 (spot-futures) basis arbitrage strategy: hold a high-liquidity ETF, short the matching CFFEX index future, and harvest the basis as it converges at delivery.

U-Shine Fund Management · Hedge Fund Summer Analyst, Jul–Aug 2026
Equity curve from a synthetic smoke run
Real output of the kernel, plotted from its own decision log — but run on seeded synthetic prices (a random walk), the tool's built-in "smoke test" mode. This is not a backtest result and shouldn't be read as one; it shows the engine runs end to end.

Built during a summer analyst stint on an event-driven cash-and-carry backtesting platform covering four Chinese A-share index futures and their ETFs, modeling margin, T+1 settlement, contract expiry, commissions, slippage, dividends, and intraday execution. This project is a from-scratch rebuild of that engine, with the leak-proofing pushed further.

The strategy trades four matched pairs, always same-index — an ETF is only ever hedged with a future on its own underlying index, because convergence at cash settlement is the whole basis of the trade: IH (上证50), IF (沪深300), IC (中证500), and IM (中证1000). The entry signal is an ETF premium/discount-adjusted, dividend-stripped annualized basis rate, computed on every listed contract of every pair, with the dividend term estimated from the ETF's NAV drift against its index by default. Entry requires the signal to exceed the pair's funding-cost hurdle — calibrated from a 2023 sell-side report — on a contract with more than 30 trading days to expiry.

Why the engine comes first

The signal is inherently forward-looking, since it depends on dividends between now and expiry — so a lookahead leak wouldn't produce an obviously broken result, it would produce a plausible and wrong one. The kernel is built to make that leak inexpressible rather than merely discouraged: the history view's methods take a lookback and no end/as_of parameter, and orders submitted on session t can only match against the frame for t+1, which doesn't exist in the process yet. This is verified by a future-perturbation test — two datasets identical up to day T and randomly different after it must produce byte-identical decision logs up to T — and a deliberately cheating strategy is kept in the test suite as a positive control, so the leak detector is itself tested.

Reproducibility and honesty about assumptions

The evaluation step re-executes the run recorded in its manifest and refuses to render a report if the digest no longer reproduces, so a report can never describe a run that has stopped being reproducible. Every run is also stamped with the assumptions that bias its result — several of them large relative to the edge itself — rather than presenting a single clean number.

This system does not trade. It has no broker adapter and isn't intended to get one; it exists to test whether the strategy's edge survives a rigorous, leak-proof accounting of costs and timing.