"""Signal-driven market maker with 5 signals + custom."""
import horizon as hz
from horizon.context import FeedData
def expiry_pressure(ctx: hz.Context) -> float:
"""Custom signal: markets approaching expiry tend to converge."""
days = ctx.params.get("days_to_expiry", 30)
if days < 7:
return 0.8 # strong convergence pressure
elif days < 14:
return 0.3
return 0.0
# Combine 5 built-in signals + custom
combiner = hz.signal_combiner(
signals=[
hz.price_signal(feed_name="polymarket"),
hz.imbalance_signal(feed_name="polymarket"),
hz.spread_signal(feed_name="polymarket"),
hz.momentum_signal(feed_name="polymarket", lookback=20),
hz.flow_signal(feed_name="polymarket"),
hz.Signal(name="expiry", fn=expiry_pressure, weight=0.10),
],
method="weighted_avg",
)
def quoter(ctx: hz.Context, fair: float) -> list[hz.Quote]:
"""Adaptive spread based on signal confidence."""
# Signal confidence is stored by the combiner
confidence = ctx.params.get("signal_confidence", 0.5)
# High confidence -> tight spread, low confidence -> wide spread
base_spread = 0.02
spread = base_spread + (1.0 - confidence) * 0.06
# Kelly sizing from the combined signal
book = ctx.feeds.get("polymarket", FeedData())
market_price = book.price if book.price > 0 else 0.50
size = hz.kelly_size(
prob=fair,
market_price=market_price,
bankroll=5000.0,
fraction=0.25,
max_size=30.0,
)
if size <= 0:
return []
return hz.quotes(fair, spread, size=size)
hz.run(
name="signal_driven_mm",
markets=["election-winner"],
feeds={
"polymarket": hz.PolymarketBook("election-winner"),
},
pipeline=[combiner, quoter],
risk=hz.Risk(max_position=100, max_drawdown_pct=5),
params={"days_to_expiry": 21},
interval=1.0,
mode="paper",
)