"""Step 6: Full production deployment."""
import os
import time
import math
import horizon as hz
from horizon import Side, OrderSide, OrderRequest
from horizon import (
MetricsCollector,
MetricsServer,
AlertManager,
AlertType,
AlertLevel,
TelegramChannel,
LogChannel,
update_engine_metrics,
)
from horizon.calibration import CalibrationTracker
from horizon.algos import TWAP
# ============================================================
# Configuration
# ============================================================
POLY_MARKET = "will-btc-hit-100k-by-end-of-2025"
KALSHI_MARKET = "KXBTC-25DEC31"
STRIKE = 100_000
BANKROLL = 50_000.0
KELLY_FRACTION = 0.25
BASE_SPREAD = 0.02
GAMMA = 0.15
MIN_EDGE = 0.02
DAYS_TO_EXPIRY = 30
# ============================================================
# Monitoring setup
# ============================================================
# Prometheus metrics
collector = MetricsCollector()
server = MetricsServer(collector, port=9090)
server.start()
tick_counter = collector.counter("horizon_ticks_total")
edge_gauge = collector.gauge("horizon_current_edge")
vol_gauge = collector.gauge("horizon_implied_vol")
model_latency = collector.histogram("horizon_model_latency_seconds")
# Telegram alerts for the trading desk
alerts = AlertManager(channels=[
TelegramChannel(
bot_token=os.environ.get("TELEGRAM_BOT_TOKEN", ""),
chat_id=os.environ.get("TELEGRAM_CHAT_ID", ""),
),
LogChannel(),
])
# Calibration tracker (persistent across restarts)
calibration = CalibrationTracker("calibration_prod.db")
# ============================================================
# Pipeline functions (same model as backtest)
# ============================================================
_price_history: list[float] = []
_bracket_set: set[str] = set() # markets with active brackets
_twap_algo = None
def black_scholes_binary(spot, strike, vol, tte):
if tte <= 0:
return 1.0 if spot >= strike else 0.0
d2 = (math.log(spot / strike) - 0.5 * vol ** 2 * tte) / (vol * math.sqrt(tte))
return 0.5 * (1.0 + math.erf(d2 / math.sqrt(2)))
def estimate_vol(prices, window=20):
if len(prices) < window + 1:
return 0.60
returns = [math.log(prices[i] / prices[i - 1]) for i in range(-window, 0)]
variance = sum(r ** 2 for r in returns) / len(returns)
return math.sqrt(variance) * math.sqrt(365)
def fair_value(ctx: hz.Context) -> float:
"""Black-Scholes binary pricing with calibration adjustment."""
start = time.time()
btc = ctx.feeds.get("btc", hz.context.FeedData())
spot = btc.price if btc.price > 0 else 97_000
_price_history.append(spot)
if len(_price_history) > 500:
_price_history.pop(0)
vol = estimate_vol(_price_history)
vol_gauge.set(vol)
tte = ctx.params.get("days_to_expiry", DAYS_TO_EXPIRY) / 365.0
fair = black_scholes_binary(spot, STRIKE, vol, tte)
# Apply calibration adjustment from historical data
fair = calibration.suggest_adjustment(fair)
# Log prediction for future calibration analysis
if ctx.market:
calibration.log_prediction(ctx.market.id, fair)
model_latency.observe(time.time() - start)
return fair
def toxicity(ctx: hz.Context) -> float:
btc = ctx.feeds.get("btc", hz.context.FeedData())
if btc.bid <= 0 or btc.ask <= 0:
return 0.5
mid = (btc.bid + btc.ask) / 2.0
if mid <= 0:
return 0.5
return min(1.0, max(0.0, (btc.ask - btc.bid) / mid * 100.0))
def quoter(ctx: hz.Context, fair: float, tox: float) -> list[hz.Quote]:
"""GLFT spread + Kelly sizing. Reports edge to Prometheus."""
tick_counter.inc()
book = ctx.feeds.get("book", hz.context.FeedData())
market_mid = book.price if book.price > 0 else 0.50
edge = abs(fair - market_mid)
edge_gauge.set(edge)
if edge < MIN_EDGE:
return []
inv = ctx.inventory.net_for_market(ctx.market.id) if ctx.market else 0.0
spread = BASE_SPREAD + GAMMA * abs(inv) * 0.001 + tox * 0.04
size = hz.liquidity_adjusted_kelly(
prob=fair,
market_price=market_mid,
bankroll=BANKROLL,
fraction=KELLY_FRACTION,
available_liquidity=200.0,
max_size=50.0,
)
size = max(1.0, size)
return hz.quotes(fair, spread, size=size)
def risk_manager(ctx: hz.Context) -> None:
"""
Post-quote risk overlay:
- Update Prometheus engine metrics
- Send alerts on fills, kill switch, large positions
- Add bracket orders (SL/TP) after first fill
"""
engine = ctx.params.get("engine")
if engine is None:
return
update_engine_metrics(collector, engine)
status = engine.status()
# Kill switch alert
if status.kill_switch_active:
alerts.alert(
AlertType.RISK_TRIGGER,
f"Kill switch activated: {status.kill_switch_reason}",
)
return
# Large position alert
positions = engine.positions()
for pos in positions:
if pos.size > 150:
alerts.alert(
AlertType.RISK_TRIGGER,
f"Large position: {pos.market_id} {pos.side} {pos.size:.0f} contracts",
)
# Fill alerts
for fill in engine.recent_fills()[-5:]:
alerts.alert(
AlertType.FILL,
f"Fill: {fill.order_side} {fill.size:.0f} {fill.side} @ {fill.price:.4f} on {fill.market_id}",
)
# Bracket orders: add SL/TP after first fill on a market
if ctx.market and ctx.market.id not in _bracket_set:
market_pos = [p for p in positions if p.market_id == ctx.market.id]
if market_pos and market_pos[0].size >= 5:
pos = market_pos[0]
# Stop-loss 15 cents below entry
sl_price = max(0.05, pos.avg_entry_price - 0.15)
engine.add_stop_loss(
market_id=ctx.market.id,
side=pos.side,
order_side=OrderSide.Sell,
size=pos.size,
trigger_price=sl_price,
)
# Take-profit 20 cents above entry
tp_price = min(0.95, pos.avg_entry_price + 0.20)
engine.add_take_profit(
market_id=ctx.market.id,
side=pos.side,
order_side=OrderSide.Sell,
size=pos.size,
trigger_price=tp_price,
trigger_pnl=pos.size * 0.10, # or $0.10/contract profit
)
_bracket_set.add(ctx.market.id)
alerts.alert(
AlertType.CUSTOM,
f"Bracket set on {ctx.market.id}: SL@{sl_price:.2f}, TP@{tp_price:.2f}",
)
# ============================================================
# Launch
# ============================================================
try:
hz.run(
name="btc_binary_desk",
exchanges=[
hz.Polymarket(
private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
api_key=os.environ.get("POLYMARKET_API_KEY"),
api_secret=os.environ.get("POLYMARKET_API_SECRET"),
api_passphrase=os.environ.get("POLYMARKET_API_PASSPHRASE"),
),
hz.Kalshi(
api_key=os.environ["KALSHI_API_KEY"],
),
],
markets=[POLY_MARKET, KALSHI_MARKET],
feeds={
"btc": hz.BinanceWS("btcusdt"),
"book": hz.PolymarketBook(POLY_MARKET),
"kalshi_book": hz.KalshiBook(KALSHI_MARKET),
},
pipeline=[fair_value, toxicity, quoter, risk_manager],
risk=RISK,
params={
"days_to_expiry": DAYS_TO_EXPIRY,
},
interval=0.5,
mode="live",
dashboard=True,
netting_pairs=[
(POLY_MARKET, KALSHI_MARKET),
],
)
finally:
server.stop()
calibration.close()
alerts.alert(
AlertType.LIFECYCLE,
"Strategy shutdown complete.",
)