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.
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.