KoPepCointegrationPairsReversionLS
Hypotheses
KO/PEP Cointegration Pairs Reversion — Dollar-Neutral Long-Short Stat-Arb on Commission-Free US Equities: Trade the Mean-Reverting Spread Between Two Cointegrated Consumer-Staples Large Caps, Z-Score Entry, Convergence Exit, Divergence Stop (KO.USEQ + PEP.USEQ, Daily Bars, 3-Parameter)
Hypotheses
A DOLLAR-NEUTRAL, LONG-SHORT PAIRS stat-arb on two structurally cointegrated US large caps — Coca-Cola (KO.USEQ) long/short vs PepsiCo (PEP.USEQ) — on the USEQ venue. This is a materially different family from everything in the crypto book and from the single-name equity mean-reversion already in the pipeline: the tradeable object is the SPREAD between two fundamentally-linked companies, not either price. KO and PEP are the textbook cointegrated pair — same consumer-staples demand drivers, same macro sensitivity, decades of co-movement — so their relative valuation oscillates around a stable long-run relationship and reverts when it stretches. Why this belongs on USEQ and not crypto: pairs/market-neutral is 0/125 in the crypto book (L68) primarily because two-leg round-trip FEES (0.20-0.40%) exceed the thin spread-reversion capture, AND cross-venue legs can't be injected into the sandbox (L69). BOTH problems vanish here — USEQ is commission-free (~0.02-0.05% RT per leg, spread+impact only) so the same spread edge that is fee-dead on crypto clears costs with room to spare, and BOTH legs are the SAME venue (USEQ), so the second instrument injects into the Layer-3 sandbox exactly like the 372 same-venue crypto pairs that already run. Decades of daily history (KO and PEP both trade since the 1980s) give a genuinely robust multi-window walk-forward and a real 15-day holdout, avoiding the empty-OOS problem that sank short-history strategies. Only 3 free parameters (z_entry, lookback, hard_stop_z) with a fixed z-exit at 0 to resist overfitting. FEE ARITHMETIC: the KO/PEP spread z-score swings ~2-4% peak-to-mean between |z|=2 extremes and convergence; capturing ~0.8-1.2% of spread convergence per completed trade against a ~0.16% two-leg round-trip cost (4 fills × ~0.04%) is ~5-7x the cost floor and well above the 0.15% viability bar. The market-neutral construction cancels broad market beta, so the return is the mean-reversion of the RELATIVE valuation, not a directional bet.
Hypotheses
Iteration 2 fixes ONLY the Layer-2 failure and changes nothing else. Cause: the Layer-2 proxy copies inherited methods onto a plain wrapper with types.MethodType, which turns the base class staticmethod FactoryStrategy._bar_ts into a BOUND method — so self._bar_ts(bar) arrived as two positional args and raised TypeError on every scenario. Fix: a module-level _bar_timestamp(bar) helper (reads ts_event, falls back to ts_init) replaces the three self._bar_ts(...) call sites in on_extra_bar, _sessions_since and calculate_signal. No imports were added or removed (Layer 1 stays green), and the signal math, entry/exit thresholds, sizing, hedge-leg submission and config are byte-identical to the previous iteration. Everything else is unchanged from iteration 1: the continuous spread z-score is returned every bar and thresholded in should_enter; exactly 3 free parameters (z_entry, lookback, hard_stop_z) with their clamps declared in _param_bounds; both legs are the same commission-free USEQ venue at equal dollar notional (beta-scaled hedge leg, beta clamped to [0.6, 1.6]) with gross capped at 50% of equity and leverage 1.0, so the book stays market-neutral without the unequal-notional/naked-leg failure mode; SyncedBuffer keeps KO and PEP samples timestamp-aligned; and holding time is anchored on the engine position ts_opened so it survives restarts.
Hypotheses
No significant edge and a decayed mechanism — not worth optimizing. Full-sample Sharpe is 0.106 with a bootstrap CI [-0.163, 0.380] that straddles zero, information_ratio is negative (-0.385), and total_return is ~1%/yr over 54 years. Critically, the KO/PEP spread edge has decayed: every year from 2023 through 2026 is negative and rolling Sharpe has fallen to -4.26, so the walk-forward's recent OOS window and the last-20% holdout both sit in the losing regime and would fail. This is not fee-limited (avg_trade_return_pct 0.476% clears the USEQ floor) — it is the known USEQ market-neutral / KO-PEP-pairs zero-survivor pattern (already iterated to death twice). Optimizing a barely-positive, statistically-insignificant, actively-decaying cointegration spread would only curve-fit the historical windows and die at holdout.
Implementation
Dollar-neutral long-short pairs stat-arb on the KO/PEP cointegrated spread, USEQ daily bars. Each session it fits a rolling OLS hedge ratio of log(KO) on log(PEP) over a 45-session window, forms spread = log(KO) - beta*log(PEP), and returns the z-score of that spread as the signal. z <= -1.8 goes LONG KO / SHORT PEP, z >= +1.8 goes SHORT KO / LONG PEP; both legs open together at equal dollar notional (25% of equity each, beta-scaled on the hedge leg, whole shares). Positions close on convergence (z back through 0), a divergence hard stop at |z| >= 3.5 against the position, or a 40-session time stop, and both legs are always closed together. The PEP leg is only submitted after the KO leg is confirmed working, and any orphaned hedge leg found while the primary is flat is closed immediately, so the book never carries a naked directional position.
Verification Results
CLEAN RESTART 2026-09-04 — this run's verdict history and learning records were removed and it was restarted from verification. Its previous abandonment came from the pipeline, not from the market: the Layer-2 harness mis-bound @staticmethod helpers (fixed), QA issued terminal performance verdicts on an unoptimized smoke test (removed — QA now judges correctness only), and sandbox timeouts came from backtest-slot starvation (fixed). The hypothesis and the strategy code are unchanged. Verify the code on its merits; performance is decided later by the full backtest and the optimizer.
Verification Results
No code change; ensure full-history window is used so each WF window and the holdout carry enough completed round trips.
Verification Results
Modest sandbox trade count (42 over ~4.5yr, ~9/yr) — inherent to pairs cadence, NOT a measurability blocker since the full backtest runs on decades of KO/PEP daily history (hundreds of trades). Flagged so the analyst checks per-window walk-forward/holdout counts.
Backtest Review
Correctly dollar-neutral: beta 0.029, benchmark_correlation 0.14, benchmark_meaningful false — the market-neutral construction works as designed
Backtest Review
avg_trade_return_pct 0.476% clears the USEQ cost floor (not a fee failure)
Backtest Review
Well-controlled risk: max_drawdown 13.6%, both legs same-venue so no injection problem
Backtest Review
445 trades over a very long history — adequate sample count
Backtest Review
Sharpe 0.106 with CI [-0.163, 0.380] straddling zero — no statistically significant edge even in-sample
Backtest Review
total_return only 53.9% over 54 years (~1%/yr) with information_ratio -0.385 and profit_factor 1.18
Backtest Review
Edge is decayed: every year 2023–2026 is negative and rolling Sharpe has collapsed to -4.26 — the KO/PEP spread has stopped reverting profitably
Backtest Review
The holdout (last ~11 years) and most recent walk-forward OOS window fall inside the negative recent regime, so optimization would fail OOS/holdout
Backtest Review
Matches the known USEQ market-neutral / KO-PEP-pairs zero-survivor failure pattern (already died twice)
Iteration History
Verification failed (Layer 2 — synthetic scenarios):
Parameters used: ['z_exit', 'z_entry', 'beta_max', 'beta_min', 'lookback', 'hard_stop_z', 'per_leg_pct', 'min_notional', '_param_bounds', 'max_hold_bars']
Check that __init__ sets all attributes from self.parameters.get().
- steady_uptrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000)
- steady_downtrend: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000)
- flat_ranging: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000)
- volatility_spike: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000)
- zero_volume: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000)
- price_gap: TypeError: FactoryStrategy._bar_ts() takes 1 positional argument but 2 were given (bar timestamp: 1735689600000)
Backtest and paper results are hypothetical. Trading involves risk of loss.