Systematic Trading Backtester
A backtesting engine built with NumPy: momentum, mean-reversion, and pairs/cointegration strategies, with transaction-cost modeling, walk-forward validation, and an overfitting-detection parameter sweep. This includes from-scratch cointegration testing for pairs trading, along with explicit gauges of lookahead bias, transaction costs, and overfitting for realistic strategy assessment. Data comes from Yahoo Finance.
Strategy & parameters
Transaction costs
Cointegration test (Engle-Granger)
Pick any two series. We fit an OLS hedge ratio and test whether the residual spread is stationary with an Augmented Dickey-Fuller test, which indicates whether the pair is cointegrated.
Walk-forward validation
Finds optimized parameters for each in-sample window, then judged on the out-of-sample window that follows. Use the gap between in-sample and out-of-sample Sharpe to assess how much the strategy was overfit.
Parameter sweep
Each cell is the Sharpe ratio for one parameter combination. A sharp peak in-sample that flattens or vanishes out-of-sample is a sign of overfitting.
Limitations
This backtester makes a number of simplifying assumptions, partially due to design decisions made to keep it fast and runnable entirely in-browser.
Signal Timing
The engine processes one trading day at a time and only ever looks at information available up through that day's close (it can't peek ahead). Because a day's closing price isn't known until the day is over, any order a signal generates at close[i] is filled at the next day's open (open[i+1]) rather than at that same close, so the backtest can never trade at a price it couldn't actually have gotten in real time.
Other Limitations
Daily bars. Every decision is made once per day at the close and executed once per day at the next open, so any strategy that depends on intraday timing can't be represented here.
Simplified cost and fill model. I aimed to approximate trading frictions with commission and half-spread. None of this models order-book depth, queue position, or adverse selection from other participants, so costs here are just an estimate.
Small universe. The panel is 18 series and 3 notable pairs (SPY, sector ETFs, and cointegration candidates like EWA/EWC). This is of course a narrower scope than the entire market.
Adjusted-price accounting only. Prices are split/dividend-adjusted via yfinance, which is standard for return calculations but means the backtest doesn't model things a live account actually pays or earns (dividend cash flows, financing/borrow costs for short positions, taxes, etc.).
Only 2018-26 real data. All results are only computed over the history of the series from 2018-26. This is partially just the nature of backtesting, but a different time interval could yield different results. Also, for simplicity and speed, the walk-forward and sweep analyses are coarse and aren't an exhaustive optimization.