Changelog

Model updates, new sports, and API changes.

v10.0 April 8–10, 2026

Billing Overhaul, Crypto Payments, Model Accuracy Leap, Google Ads Attribution

  • NBA Model Retrained with Team Stats: Brier improved 0.131 → 0.127 (3.2%). Added ORtg/DRtg/pace features that were trained but never fed real data at inference — the cache was empty for NBA and NHL. Fixed, rebuilt, retrained as Split-Phase model with 16 features including momentum.
  • NHL Model Retrained: Brier improved 0.205 → 0.157 (23.6%). Biggest single-model accuracy jump ever. Same root cause: team stats cache was NCAAMB-only. NHL now has ortg/drtg/pace/pp_pct/pk_pct/save_pct/faceoff_pct flowing at inference.
  • NHL Injury System: New nhl_injuries.py with 44 tracked skaters (McDavid 12%, Draisaitl 10%, Makar 9%, etc). Live ESPN API, goalie-excluded (handled by separate GOALIE_QUALITY overlay), ±12% cap. First real data: Carolina 7 skaters out → NYR +12% adjustment.
  • NBA STAR_IMPACT Expanded: 37 → 58 players. Added 2025-26 breakouts (Amen Thompson, Zach Edey, Reed Sheppard, Stephon Castle, Zaccharie Risacher) and key starters (Jalen Williams, Evan Mobley, Domantas Sabonis, OG Anunoby, Derrick White).
  • Live Recalibration System: New live_recalibrator.py — rolling isotonic regression on last 500 resolved predictions per sport. Auto-refits every 25 new samples. Persists to JSONL. Activates after 50 resolved trades. Catches calibration drift without full retraining.
  • MLB Bullpen Quality Overlay: New mlb_bullpen.py with 30-team bullpen ERA rankings. Time-scaled: 0% impact in innings 1-4, scales to 100% in 8th-9th. ATL/LAD/HOU elite (3.10-3.20 ERA) vs COL/CWS weak (4.40-4.45). Capped ±5%.
  • Momentum Ablation Test: Confirmed momentum features (run_diff_120s/300s) improve NBA Brier by 1.1% (0.12655 with vs 0.12794 without). Keeping them.
  • Crypto Payments (NowPayments): Bitcoin, Ethereum, USDC, USDT, and 350+ coins now accepted. 10% crypto discount on all products. "Pay with crypto" CTA on every pricing card and checkout interstitial. Email validation prevents empty-email invoices. Full billing event tracking + admin dashboard integration.
  • Abandoned Cart Recovery: Stripe after_expiration.recovery enabled on every session. 60-minute session expiry (was 24 hours). Webhook handler sends "Your trial is waiting" recovery email with Stripe's recovery URL. 212 recovery emails sent on first day.
  • Google Ads Attribution Fix: Conversion events were reporting $0 value (Stripe trial = $0 charge). Now passes plan sticker price ($49) as expected LTV. Added Enhanced Conversions (email hashing for cross-device attribution). Added begin_checkout GA4 event on every interstitial page load (150/day top-of-funnel signal). New GCLIDMiddleware captures gclid/gbraid/wbraid as first-party cookies (90-day TTL).
  • Real MRR Dashboard: New /admin/revenue page with honest numbers — Real MRR (status=active only), At-Risk MRR (no-card trials), Projected MRR, Cash Collected. 30-day Stripe vs Crypto rail-split stacked bar chart (inline SVG, no JS library). Daily Discord MRR ping at 09:03 UTC.
  • Admin Support Tool: New /admin/support/mint-link — paste a customer email + pick a product → generates a fresh Stripe hosted checkout URL pre-filled with their email. For customers who can't get through the normal checkout (IAB browsers, etc).
  • Middleware Security Overhaul: Converted 5 BaseHTTPMiddleware classes to pure ASGI (eliminated LocalProtocolError: Too much data for declared Content-Length — 200 crashes/day → 0). GZipMiddleware moved to outermost position. CSP tightened with explicit form-action allowlist for Stripe + NowPayments + Coinbase Commerce hosts.
  • IAB Interstitial Improvements: Added "Continue in this browser anyway" escape hatch (tracked via inapp_browser_override event). Trimmed IAB fragments list (removed Messenger/LinkedIn/Reddit/Pinterest — they work fine with Stripe). Added STRIPE_CHECKOUT_IAB_MODE env var (block/warn/allow).
  • Stripe Key Rotation: Migrated from standard sk_live_ to restricted rk_live_ key (smaller blast radius). Consolidated secrets into single /opt/fairprob/.env (was split across two files). Scrubbed old key from 4 backup/staging locations.
  • Cron Observability: New cron_heartbeat.py — every cron writes start/ok/error to an append-only JSONL ledger. Fixed retention_emails cron (ModuleNotFoundError for 7+ days). Fixed run_campaigns.sh strict mode. Logrotate split: copytruncate for api.log, create for cron logs.
  • Campaign Drip Fix: run_campaigns.sh was silently broken (SyntaxError in heredoc). Manual recovery sent 98 backlogged Day 2/Day 5 emails. Backfilled campaign_state.jsonl to prevent duplicate sends.
  • Billing Events Ledger: New event types: crypto_charge_created, crypto_charge_confirmed, inapp_browser_override, checkout_recovery_sent, support_mint_link. Test-traffic filter (localhost/curl-smoke IPs excluded). Crypto conversion stats in health_snapshot().
  • Card-Required Experiment: Flipped STRIPE_API_STARTER_NO_CARD_TRIAL_PCT from 50% → 0% (all signups require card). Discovered 5 of 7 trialing customers had no card on file. Conversion dropped from 3.4% to 0% — root cause was audience/pricing mismatch, not the card requirement itself.
  • File Ownership Sweep: 4,742 files on VPS were owned by macOS uid 501/staff (rsync artifact). Chowned to root:root. Deploy scripts now exclude *.jsonl to prevent state-file clobber.
  • Test Coverage: 200+ new tests across 7 test files (ads attribution, billing health, stripe MRR, admin mint-link, IAB interstitial, Dodo billing, checkout dedup). Full regression: 174+ passing.
v9.0 April 6, 2026

Model Intelligence Upgrade — All 5 Bots Improved

  • NBA Model Retrained: Calibration improved 44% (ECE 0.103 → 0.057). Switched from XGB+Isotonic to tuned XGBoost. Dynamic edge thresholds enabled — early-game requires higher edges (model uncertainty 18.7c), late-game accepts smaller edges (4c).
  • NBA Injury Integration: Real-time ESPN injury API + 35-player star impact table. Jokic out = -16% WP, LeBron = -12%. Applied after model prediction, before edge calculation. Capped at ±15%.
  • CS2 Combined Model: Map-specific CT win rates (Nuke 57%, Dust2 51%, 9 maps). 4-tier economy system (>15K gap = +20% round advantage). Conditional dampening: 0.75 for combined model, 0.70 for Elo-only. Team rank confidence modulates Elo trust.
  • CS2 Filters Optimized: min_edge 10→8c (5-10c bucket has 71.4% WR), max_edge added at 25c (20c+ edges have 36% WR — model overconfident), entry range 30-65c (sweet spot from backtest).
  • LoL ML Model Trained: Was running Elo-only despite full ML pipeline existing. Trained XGBoost on gold diff (39% importance), kills, towers, dragons, barons. Brier improved 47.8% (0.256→0.134), AUC from 0.575→0.890. +5K gold at 20min now correctly predicts 82% WP instead of ~55%.
  • Tennis WTA Calibration: Split serve rates for ATP vs WTA (WTA hard: 58% vs ATP 64%). Set dominance momentum: 6-0 win → +4% WP boost, tiebreak → no adjustment, comeback → +2% bonus.
  • MLB Model Hash Fixed: MLB model was SKIPPED due to stale SHA256 hash file. Regenerated — all 7 sports now loading correctly.
  • Homepage Visual Mockups: Added code-based product screenshots: scanner preview (hero), Jupyter notebook cell (curriculum), mini results widget (proof section).
  • Homepage 4-Phase Improvement: Clearer positioning ("ML-powered sports prediction models"), 2 CTAs only above fold, canonical proof block on pricing/results/course, "What can go wrong" risk disclosure.
  • CS2 Backtest: New backtest_cs2_combined.py using bo3.gg historical data + bookmaker odds. 121 trades, +8.4c/trade net. Economy snapshot trades: 97.1% WR (late-game bias noted).
  • Google Ads Campaign: New API trial campaign with 15 headlines + 5 long headlines + 4 descriptions. Separate from course campaign.
  • Bing Webmaster: BingSiteAuth.xml deployed for Bing verification.
v8.0 April 4, 2026

Major Platform Overhaul — Infrastructure, Marketing, Security, CS2 Model

  • Unified Trading Bot: All 5 sport bots (Moneyline, CS2, LoL, Soccer, Tennis) consolidated into single process with shared WS connection, global circuit breaker, and portfolio-level risk management
  • CS2 bo3.gg Integration: Replaced HLTV (Cloudflare-blocked) with bo3.gg as primary data source. New combined series + map model uses live economy data (equipment values, buy phases). Backtest: 121 trades, +8.4c/trade net
  • Circuit Breakers on All Bots: Added $20 daily loss limit, 5-loss streak cooldown, 30% rolling WR gate to CS2, LoL, Soccer, Tennis. Fixed cents→dollars bug that was tripping breakers too early
  • Feed Quality System: New feed_quality.py scores every signal (price freshness, match confidence, spread). warm_start.py blocks trading until 30% of tokens have fresh prices for 15s. execution_queue.py prevents duplicate trades on restart
  • Email Drip Campaign: 6-step automated funnel (Day 2 calculator → Day 5 feedback → Day 8 results → Day 12 course → Day 20 API → Day 30 winback). 42+ emails sent to 54+ subscribers. Behavior-based triggers for activation reminders
  • Activation Flow: Dedicated /activate page for passwordless accounts. Full funnel tracking: activated_at, first_dashboard_at, first_progress_at, first_rating_at. Reactivation campaign sent to 23 unactivated users
  • Course Rating Pipeline: Star ratings with Discord notifications, action buckets (1-2★ → admin alert, 3★ → "what's missing?" email, 4-5★ → testimonial request), purchase-gated submissions
  • Security Audit + Fixes: 6 critical fixes — authenticated unsubscribe (HMAC tokens), SSRF webhook validation, XSS escaping, CSP updates (Chart.js + Alpine.js CDN allowed), session cookie hardening, logout CSRF
  • Backtest Integrity: All 14 backtests graded (production/semi-realistic/research-only). LoL backtest rebuilt with real Polymarket prices. NFL training split fixed (2020-21 season ordering). Honest numbers on all public pages (+2.4c net, not +10.9c)
  • State-Aware Site: Every page personalized by user state (free/paid/course owner/activated). Recovery actions shown automatically. Pricing CTAs change by tier. Course tab shows personalized next steps
  • Dashboard UX: Game detail drawer (click any row), mobile card layout, sticky filter bar, min-edge filter, human clock format, signal flash animation, freshness indicator, sport filters on games tab
  • Results Page: Ledger status bar (freshness, quality), sport filters, expandable trade rows, clear Live/Open/Backtest sections with "Simulated" badge
  • Research Paper: Published white paper at /research — 4 revision cycles, statistical significance tests, baseline comparisons, threats to validity. Email-gated PDF download
  • 5 Monitoring Agents: Reconciliation, strategy allocator, claim integrity, entitlement QA, deployment drift — all running daily via cron with Discord alerts
  • Cache Pipeline: Stale pruning (-1/+14 days), sport normalization, active cache (48h tradable tokens), sport shards, publish quality gate, health summary
  • 12 Blog Posts: 5 new technical posts (Polymarket API, calibration, Elo ratings, WebSocket data, backtesting pitfalls)
  • Purchase Flow: Every purchase path sends confirmation email. Webhook creates accounts. Bundle buyers get both API + course emails. Re-download section on account page
  • Growth Automation: Twitter agent posting wins, Discord fill notifications, daily/weekly summaries, metrics agent tracking MRR/users/email analytics — all on autopilot via watchdog.sh
v7.0 April 4, 2026

CS2 Bot Audit, Domain Migration, Performance, Claim Accuracy

  • CS2 Bot Overhaul: Deep analysis of 33 live trades revealed 45% WR vs 78% backtest. Root causes: slippage (avg 4.9c), underdog trap (0-40c entries 17% WR), thin edges (0-10c bucket 38% WR). Tightened filters turn -67c into +40c retroactively
  • CS2 Config Changes: min_edge 4c→10c, min_fair 50c→55c, max_entry 80c→70c, added max_slippage 8c gate. Entry price cap prevents high-entry asymmetric risk
  • CS2 Elo Rebuild: 311 teams from 4,350 matches (up from 258 teams). Fixes stale ratings that caused 0% WR in +100-200 Elo diff bucket
  • Domain Migration: Primary domain moved from api.zenhodl.net to zenhodl.net. All canonical URLs, sitemap, emails, CSP updated. api.zenhodl.net returns 301 permanent redirect
  • Performance (PageSpeed 55→79): GZip middleware (54KB→11KB), 1-year immutable cache headers, deferred Google Tag, CSS preload, dashboard mockup HTML→WebP image (90 DOM nodes→17KB image). FCP 3.6s→1.0s, TBT 420ms→120ms, CLS 0.286→0
  • Claim Audit: Backtest table updated from stale v2 data to v4 model results (1,171 trades, 70.9% WR). Numbers synced across course.html, pricing.html, email templates. Source of truth: model v4 + Elo improvements, Mar 2026
  • Results Page: Renamed to "Filtered Public Ledger" with explicit start date, reconciliation status (healthy/warning), excluded rows count, and clearer scope labels
  • Dashboard Course Tab: Backend-saved progress (replaces localStorage). Resume/next-step hero CTA. Expandable module workspaces with checklists, common failures, success criteria. Contextual support by module. Live proof panel with per-sport stats
  • Trade Resolution Cron: Auto-resolves pending trades every 15 minutes via Polymarket settlement API. No more manual PnL corrections
  • OddsAPI Fix: Retry backoff on 401/failure (was hammering API every 5s). Daily budget tracking. Key updated for 100K/mo plan
  • Tennis Bot: Added WTT tour support (ATP + WTA + WTT)
  • Blog: 4 new posts — execution quality deep dive, 5 bots P&L transparency, multi-venue edge guide, hold-to-settlement strategy
  • Wording: "Sign up" → "Create Account" across all user-facing pages
v6.0 March 30, 2026

Infrastructure Upgrade — CLV Tracking, Confidence Intervals, Webhooks, Email Campaigns

  • Model Quality API: /v1/model/performance — Brier score, ROC-AUC, ECE, accuracy, and full conformal calibration tables for all 7 sports
  • CLV Tracking: /v1/model/clv — live closing line value tracking. Measures how often our entry price beats the final market price
  • Confidence Intervals: All prediction endpoints now include calibrated prediction bands from conformal prediction tables. Width narrows as games progress
  • Venue Status: /v1/venues — real-time status of all connected data venues (Polymarket, Kalshi, DraftKings, FanDuel, etc.)
  • Venue Filter: ?venue=kalshi on /v1/games and /v1/edges to filter by specific venue
  • Intraday WP Snapshots: /v1/snapshots/{sport}/{date} — win probability archived every 30s during live games (Pro+ tier)
  • Batch Predictions: /v1/predictions/batch — bulk download predictions for up to 90 days (Pro+ tier)
  • Webhook Push: /v1/webhooks — register URLs to receive edge signals in real-time via signed POST requests (HMAC-SHA256)
  • Email Drip Campaigns: 6-step automated sequence for launch signups (Day 2 calculator, Day 5 feedback, Day 8 results, Day 12 course, Day 20 API, Day 30 win-back)
  • Course Rating System: Star ratings + written reviews at /course/rate with social proof widget on course page
  • 5 New Blog Posts: Polymarket API tutorial, model calibration guide, Elo ratings from scratch, WebSocket data guide, backtesting pitfalls
  • NFL Model Fix: Corrected season ordering bug where 2020-21 test set was older than training data (data leakage eliminated)
  • Bot Safety: Circuit breaker (daily loss limit + streak detection), bankroll depletion check, WS/ESPN staleness guards, performance dashboard every 10 min
  • Billing Fixes: Fixed free trial 402 error, added checkout.session.completed webhook handler, fixed 3 pricing page checkout links pointing to wrong tiers
  • Security Hardening: Timing-safe CSRF comparison, HTTPS-only session cookies, randomized download secrets, custom 404 page
v5.0 March 28, 2026

Multi-Venue Edge Detection + Prediction API

  • Multi-venue pricing: edges now computed across Polymarket, Kalshi, and 15+ sportsbooks (DraftKings, FanDuel, BetMGM, etc.) via the-odds-api.com
  • Cross-venue game matching: automatic team name normalization across ESPN, Polymarket, Kalshi, and sportsbook feeds (127 team mappings)
  • Best venue indicator: dashboard shows which venue has the best price per side for every game
  • Venue filter: Edge Scanner now filterable by venue (Polymarket, Kalshi, DraftKings, FanDuel)
  • Prediction API (B2B): /v1/predict/{sport}/live — live win probabilities + multi-venue edges for all active games
  • Pregame predictions: /v1/predict/{sport}/pregame — Elo-based pregame win probabilities for today's scheduled games
  • Single game detail: /v1/predict/{sport}/{game_id} — full model output for a specific game
  • Fair lines endpoint: /v1/fair-lines/{sport} — fair moneylines in American odds format
  • Usage metering: /v1/usage — monthly request tracking with per-endpoint breakdown
  • Monthly API caps enforced per tier: Free (100), Starter (10K), Pro (100K), Enterprise (unlimited)
  • American odds conversion: fair probabilities displayed as moneylines for sportsbook integration
  • Multiplicative vig removal for sportsbook odds — true implied probability from raw lines
  • Adaptive sportsbook polling: only fetches odds for sports with active ESPN games, respecting API budget
  • Graceful degradation: runs Polymarket-only when no ODDS_API_KEY configured
v4.0 March 24, 2026

Advanced Elo engine — MOV, dynamic K, surface-specific ratings

  • Margin-of-Victory (MOV) multiplier for basketball & football Elo — blowouts update ratings more than narrow wins, with autocorrelation correction to prevent double-counting expected outcomes
  • Dynamic K-factor for basketball & football: new teams converge 1.5x faster, established teams stabilize at 0.8x K
  • MOV/dynamic K intentionally disabled for low-scoring sports (NHL, MLB) where margin is noise
  • Combined moneyline backtest: 1,171 trades, 70.9% WR, +11.0c/trade, +$128.88 total
  • NBA: +8.5c/trade (up from +0.6c pre-Elo) — biggest winner from MOV + dynamic K
  • NCAAMB: +13.8c/trade, 73.1% WR on 821 trades. Pregame-confirmed: 82.9% WR, +18.4c
  • Tennis: surface-specific Elo (Hard/Clay/Grass) — Sinner #1 Hard (2344), Swiatek #1 Clay (2157), Djokovic #1 Grass (2037). Blended 50/50 for match predictions
  • LoL: regional initialization — LCK/LPL teams start at 1300 Elo, major regions at 1250, minor at 1200
  • Soccer: elo_power optimized 800 → 600, MOV + dynamic K enabled, Brier 0.5683
  • All 5 WP sport models retrained — NBA AUC 0.890, NCAAMB 0.868, NHL 0.739
Data March 24, 2026

Exclusive market data store

  • Polymarket Orderbook Archive: 136M+ ticks, Dec 2025 – Jan 2026, 6 sports (Parquet)
  • Kalshi MLB 1-Minute Candles: 2,203 games, full 2025 season
  • Prediction Market Microstructure Pack: guardrail feed + spread analysis
  • Tennis ATP/WTA Match Data + Odds: 10 years, 60K+ matches
  • All datasets watermarked (per-buyer fingerprint), SHA-256 signed, with data provenance cards
  • Interactive sample previews at /samples
v3.0 March 23, 2026

Model v3 — football features + pregame WP prior

  • Added football-specific features: down, distance, yard_line, possession_home (CFB/NFL)
  • Added pregame_wp as a fixed prior from ESPN pre-game win probability
  • CFB: 87.0% WR, +27.2c/trade (up from +9.4c in v2)
  • NFL: 90.0% WR, +29.7c/trade (up from +24.2c in v2)
  • NCAAMB: 73.8% WR, +12.0c/trade
  • Added --select-by-trading flag to train_wp_model.py
New March 2026

CS2, LoL, Tennis models

  • CS2: Negative binomial model with HLTV Elo (311 teams, MOV + dynamic K)
  • LoL: Elo + binomial series model via lolesports API (255 teams, regional init)
  • Tennis: Hierarchical point-level model with surface-specific Elo (Hard/Clay/Grass)
  • All in shadow testing — live results pending
New March 2026

ZenHodl API + Dashboard launch

  • REST API: /v1/games, /v1/edges, /v1/sports, /v1/predictions
  • WebSocket real-time stream
  • Backtest-as-a-service (25M+ rows)
  • Auto-refreshing edge scanner dashboard
  • Stripe billing with 7-day free trial
  • Discord edge alerts
v2.0 February 2026

Spread/Total WP + Soccer WP models

  • Spread WP: regression + CDF model, time-bucketed residual std
  • SPREAD: 721 trades, 56.7% WR, +6.3c/trade
  • Soccer WP: Poisson model, 64 trades, 64.1% WR, +26.0c/trade
  • Added ESPN adaptive polling (5s fast / 15s slow)
v1.0 December 2025

Initial moneyline WP model

  • LR+Spline models for NBA, NCAAMB, NHL, MLB
  • XGBoost+Isotonic for NCAAMB
  • Elo ratings for 258+ teams per sport
  • 13-feature model: score_diff, seconds_remaining, period, time_fraction, elo_diff