Documentation Index
Fetch the complete documentation index at: https://mathematicalcompany.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Trade the spread between two cointegrated prediction markets. When the spread deviates from its mean, enter positions expecting reversion.
Full Code
"""Stat arb pairs trading: GOP Senate vs House markets."""
import horizon as hz
from horizon.context import FeedData
def fair_value(ctx: hz.Context) -> float:
"""Use the Senate feed as primary fair value."""
senate = ctx.feeds.get("gop_senate_feed", FeedData())
return senate.price if senate.price > 0 else 0.50
# Check cointegration first
coint = hz.cointegration_test(
series_a=[0.52, 0.53, 0.51, 0.54, 0.55, 0.53, 0.52, 0.54, 0.56, 0.55],
series_b=[0.48, 0.49, 0.47, 0.50, 0.51, 0.49, 0.48, 0.50, 0.52, 0.51],
)
print(f"Cointegrated: {coint.is_cointegrated}")
print(f"ADF stat: {coint.adf_statistic:.4f}, p-value: {coint.p_value:.4f}")
print(f"Hedge ratio: {coint.hedge_ratio:.4f}")
# Configure stat arb
config = hz.StatArbConfig(
market_a="gop-senate",
market_b="gop-house",
feed_a="gop_senate_feed",
feed_b="gop_house_feed",
hedge_ratio=coint.hedge_ratio,
entry_z=2.0, # enter at 2 standard deviations
exit_z=0.5, # exit at 0.5 standard deviations
lookback=50, # rolling window for z-score
max_size=20.0,
)
stat_arb_pipeline = hz.stat_arb(config, auto_execute=True)
hz.run(
name="stat_arb_pairs",
markets=["gop-senate", "gop-house"],
feeds={
"gop_senate_feed": hz.PolymarketBook("gop-senate"),
"gop_house_feed": hz.PolymarketBook("gop-house"),
},
pipeline=[fair_value, stat_arb_pipeline],
risk=hz.Risk(max_position=100, max_drawdown_pct=5),
interval=1.0,
mode="paper",
)
How It Works
cointegration_test() verifies the two price series share a long-run equilibrium
StatArbConfig sets entry/exit z-score thresholds and the hedge ratio
stat_arb() monitors the spread z-score each cycle:
- When z >
entry_z: short the spread (sell A, buy B)
- When z <
-entry_z: long the spread (buy A, sell B)
- When |z| <
exit_z: close the position
- The hedge ratio scales the B-side size to maintain dollar-neutrality
Spread Z-Score
You can also compute the z-score manually for custom logic:
z = hz.spread_zscore(
price_a=0.55,
price_b=0.51,
hedge_ratio=0.95,
mean=0.02,
std=0.015,
)
print(f"Spread z-score: {z:.2f}")
Run It
python examples/stat_arb_pairs.py
Simpler Alternative
For a lighter approach without cointegration testing, use spread_convergence():
spread_pipe = hz.spread_convergence(
market_a="gop-senate",
market_b="gop-house",
feed_a="gop_senate_feed",
feed_b="gop_house_feed",
threshold=0.03, # trade when spread exceeds 3 cents
target_spread=0.01, # expect convergence to 1 cent
size=10.0,
)
See Statistical Arbitrage for the full method reference.