Contrarian prediction market scanner that finds mispricings on Kalshi using Claude Sonnet analysis, Brier score calibration, and Kelly Criterion position sizing. Five-phase pipeline: fetch markets, classify, estimate contrarian probabilities, calculate edge, and alert. Tracks estimate accuracy over time so you know when to trust the signal. Part of the OpenClaw Prediction Market Trading Stack — feeds edge data to Market Morning Brief and pairs with Kalshi Command Center for execution.
SKILL.md
Kalshalyst — Contrarian Prediction Market Scanner
Overview
Kalshalyst is a complete intelligence system for finding and trading prediction market opportunities. It combines:
Claude Sonnet contrarian estimation — sees market prices and finds reasons they're WRONG
Brier score tracking — measures how well your estimates calibrate against actual outcomes
Kelly Criterion position sizing — calculates optimal trade size for each opportunity
The key insight: blind estimation (not seeing prices) produces consensus-matching estimates with zero edge. Contrarian mode (showing Claude the price and asking it to disagree) produces opinionated, directional calls with real edge.
When to Use This Skill
You want to find mispricings on Kalshi prediction markets
You're looking for contrarian opportunities where the market is wrong
You need to track how accurate your probability estimates are over time
You want to size positions intelligently based on edge and confidence
You're building a systematic prediction market trading system
First run does not require Kalshi credentials. If they are missing, Kalshalyst prints a realistic demo scan and writes demo cache data so downstream tools like Market Morning Brief still have something useful to show.
Output: List of ~100-500 pre-filtered markets ready for analysis
Phase 2: CLASSIFY — Market Classification
Status: Disabled (Qwen unreliable) — Markets pass through with defaults.
When re-enabled, would use local Qwen to classify each market by:
Category: politics, economics, crypto, policy, technology, etc.
Tradability: 0.0-1.0 score (how analyzable with public info?)
News sensitivity: True if breaking news would materially shift the probability
For now, all markets receive default classification values and proceed to Phase 3.
Phase 3: ESTIMATE — Claude Contrarian Probability Estimation
The core IP. Claude sees the market price and is asked to find reasons it's WRONG.
System Prompt (Contrarian Mode):
You are a contrarian prediction market analyst. You look for reasons markets are WRONG.
Your job: given a prediction market and its current price, determine if there's a
directional opportunity. You are advising a sophisticated trader who uses limit orders.
CRITICAL RULES:
1. You WILL be shown the current market price. Your job is to DISAGREE with it when you have reason to.
2. Don't just confirm the market. That's worthless. Look for what the market is MISSING or LAGGING on.
3. Consider: breaking news the market hasn't priced, political dynamics shifting, timing mismatches,
crowd psychology errors, base rate neglect by the market.
4. Be opinionated. A 50% estimate on a 50% market is useless. Either find a reason it's wrong or
say confidence is low.
5. Weight recent developments HEAVILY — markets are often slow to react to news in the last 24-48 hours.
6. Think about asymmetric upside: where is the cost of being wrong low but the payoff of being right high?
You must respond with ONLY a JSON object:
{
"estimated_probability": <float 0.01-0.99>,
"confidence": <float 0.0-1.0>,
"reasoning": "<one sentence explaining WHY the market is wrong>",
"key_factors": ["<factor 1>", "<factor 2>", "<factor 3>"],
"conviction": "<strong|moderate|weak>"
}
"in next 15 min", "in next 30 min", "in next 1 hour", "in next 5 min",
"next 15 minutes", "next 30 minutes", "next hour", "price up in next",
"price down in next"
Sports Tokens (Blocked From The Production Stack):
Major leagues: NFL, NBA, MLB, NHL, MLS, NCAA, PGA, UFC, WWE
Soccer: Premier League, La Liga, Serie A, Bundesliga, Champions League, Copa
Esports: Valorant, League of Legends, CS:GO, Dota, Overwatch
Individual sports: ATP, WTA, Tennis, Boxing, MMA
Why These Filters?
Weather + Intraday: Near-pure noise — impossible to extract edge
Sports: Intentionally excluded. Recent evaluation did not show durable model edge, so sports are not part of the current production stack.
Entertainment: Celebrity/social media volatility — not analyzable with Claude
Micro-timeframe: Spreads dominate, zero informational edge
Blocklist philosophy: Cut the bottom 80% of opportunities (noise) to focus Claude on the top 20% (signal)
Contrarian Estimation — Why It Works
The Problem with Blind Estimation
Blind mode (not showing Claude the market price):
Claude produces "consensus" estimates
Usually close to 50% for uncertain markets
Results in zero edge (estimate ≈ market price)
Not actionable
Why? Claude doesn't know what the market thinks, so it defaults to high uncertainty.
The Solution: Contrarian Mode
Contrarian mode (showing Claude the price):
Claude sees the market price: "Market is priced at 35%"
Market: "Will Ukraine still be at war in 2026?"
Market Price: 72% (market implies YES very likely)
Recent Context: Leaked peace negotiations, US pushing settlement
Claude Contrarian Reasoning:
Estimated probability: 38%
Confidence: 0.65
Reasoning: Market overweighting base rate of ongoing war without pricing
in recent peace negotiation signals and US diplomatic pressure shift.
Timeline to 2026 (10 months) is insufficient for typical conflict duration,
but settlement momentum has real probability weight market ignores.
Key factors: [peace talks acceleration, US policy shift, timeline compression]
Edge: |38% - 72%| = 34% effective edge → BUY NO at 28¢ expected return
Brier Score Tracking
What It Measures
Brier Score = (1/n) * Σ(forecast - outcome)²
0.0 = perfect estimates
0.25 = random baseline (coin flip for 50/50 events)
Above 0.25 = worse than guessing (miscalibrated)
How It Works
Log Phase: Every edge scanner run logs all estimates to SQLite
Ticker, estimated probability, market price, confidence, estimator (Claude vs Qwen)
Category (politics, policy, crypto, etc.)
Edge percentage, info density (context richness score)
Resolve Phase: When markets close on Kalshi, log the outcome
Automatic: check_and_resolve_markets() polls Kalshi API daily
# Single run
python -m kalshalyst.kalshalyst
# With full logging
DEBUG=1 python -m kalshalyst.kalshalyst
# Dry run (no alerts sent)
python -m kalshalyst.kalshalyst --dry-run
# Fresh-market scan (new listings from last 48 hours; relaxed liquidity filters)
python -m kalshalyst.kalshalyst --fresh
# Fresh-market dry run
python -m kalshalyst.kalshalyst --fresh --dry-run
As a Cron Job (Every 60 Minutes)
# Add to crontab -e:
0 * * * * cd /path/to/kalshalyst && python -m kalshalyst.kalshalyst >> /tmp/kalshalyst.log 2>&1
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
RUN pip install kalshi-python anthropic pyyaml requests
ENTRYPOINT ["python", "-m", "kalshalyst.kalshalyst"]
Example Output
Alert Message
Found 3 opportunities. Top picks:
1. Will a Democrat win the 2028 presidential election?
NO @ 48% | 24% edge | 0.72 conf
Market overweighting base rate. Peace/tariff momentum underpriced.
2. Will inflation exceed 4% by Dec 2026?
YES @ 32% | 18% edge | 0.68 conf
Core CPI sticky; Fed unlikely to cut further. Market pricing full easing.
3. Ukraine war still ongoing in 12 months?
NO @ 28% | 20% edge | 0.65 conf
Peace talks at tipping point. Resolution probability underweighted by 2yr baseline.
+2 more. Say 'markets' for full list.
Say 'execute 1', 'execute 2', or 'execute 3' to trade.
Runtime: 2-4 minutes (50 markets, Claude estimation)
API calls:
Kalshi: 1-10 calls (market fetch, pagination)
Claude: 50-80 calls (estimate_batch)
Polygon: 2 calls (economic indicators, every 12 hours)
Cost per run:
Claude: variable by model and usage volume
Polygon: ~$0 (free tier)
Kalshi: $0 (read-only)
Scaling
For scheduled operation, Claude spend scales directly with your scan frequency and model selection. If you want a zero-API-cost fallback, keep Ollama/Qwen available and treat it as a lower-quality backup path rather than the primary estimator.
OpenClaw Ecosystem Integration
Kalshalyst is the intelligence engine of the Prediction Market Trading Stack. It feeds edge data to other skills:
Connected Skill
What It Gets From Kalshalyst
Market Morning Brief
Top edges appear in your daily morning digest
Kalshi Command Center
Execute trades directly on flagged opportunities
Portfolio Drift Monitor
Track positions opened on Kalshalyst recommendations
Battle-tested in production trading environments. Key design decisions:
Generic config loading — works with any OpenClaw config.yaml
Direct alerts — sends opportunities directly to you, no middleware
All thresholds, blocklists, and prompts refined through live trading
Scripts are standalone — zero external dependencies beyond listed packages
Further Reading
See references/contrarian-prompt.md for the full Claude system prompt with explanation
See references/blocklist.md for complete blocklist documentation
See references/brier-schema.md for database schema and methodology
See references/kelly-math.md for Kelly Criterion math derivation
Support & Iteration
Kalshalyst is actively maintained. Common iteration paths:
Contrarian Prompt Tuning: Refine system prompt to improve edge quality
Blocklist Refinement: Add new ticker prefixes or patterns as you encounter noise
Category Recalibration: Use Brier reports to identify systematically miscalibrated categories
Kelly Parameters: Adjust alpha, max contracts, exposure limits based on risk tolerance
Fallback Estimators: Replace Qwen with custom local models or other APIs
See the GitHub issues (if published) or contact the maintainer for feature requests.
Agent Bug-Fix Protocol
CRITICAL: When you (the agent) discover and fix a bug in any script during a conversation, you MUST write the fix to the source file on disk using file editing tools. Showing the fix in chat is NOT sufficient — the next scheduled run starts a fresh session and will not have your conversational fix.
Checklist after finding a bug:
Edit the actual .py file on disk (e.g., ~/skills/kalshalyst/scripts/*.py)
Also update the installed copy at ~/.openclaw/skills/kalshalyst/scripts/*.py
Confirm both files are written before telling the user the fix is done
If the fix is significant, stage a git commit in ~/skills/
Never say "fixed" if you only demonstrated the fix in conversation output.
Feedback & Issues
Found a bug? Have a feature request? Want to share results?