Install
openclaw skills install kalshalystContrarian prediction market scanner that finds mispricings on Kalshi using Claude Sonnet analysis, Brier score calibration, and Kelly Criterion position siz...
openclaw skills install kalshalystKalshalyst is a complete intelligence system for finding and trading prediction market opportunities. It combines:
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.
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.
Kalshi API Key (free at kalshi.com)
Anthropic API Key (for Claude Sonnet)
Polygon.io API Key (optional, free tier available)
Python 3.10 or higher
Required packages:
pip install kalshi-python requests anthropic pyyaml
Optional (for local fallback estimation):
ollama pull qwen3:latestCreate or update your config.yaml file with:
kalshi:
enabled: true
api_key_id: "your-key-id-here"
private_key_file: "path/to/private.key"
ticker_names: {} # Optional: custom display names for tickers
anthropic:
api_key: "sk-ant-..."
polygon:
api_key: "pk_..." # Optional
kalshalyst:
enabled: true
check_interval_minutes: 60
min_volume: 50
min_days_to_close: 7
max_days_to_close: 365
max_pages: 10
max_markets_to_analyze: 50
min_edge_pct: 3.0
min_qwen_confidence: 0.4
alert_edge_pct: 6.0
max_alerts: 5
max_fetch_seconds: 30
page_timeout_seconds: 8
Fetches all open markets from Kalshi and applies pre-filters:
Blocklist Filtering:
Timeframe Gates:
Volume Floor:
Price Availability:
Output: List of ~100-500 pre-filtered markets ready for analysis
Status: Disabled (Qwen unreliable) — Markets pass through with defaults.
When re-enabled, would use local Qwen to classify each market by:
For now, all markets receive default classification values and proceed to Phase 3.
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>"
}
Context Enrichment:
Fallback to Qwen:
Output: Estimated probability, confidence, reasoning, key factors
For each estimate, calculates the edge (profit potential):
Raw Edge = |estimated_prob - market_price| * 100%
Direction = "underpriced" if estimate > market else "overpriced" else "fair"
Effective Edge = Raw Edge - 0.0% (limit orders assumption — no spread penalty)
Why limit orders? You're a sophisticated trader who can post limit orders at midpoint or better, avoiding spread costs.
Filtering:
Output: Ranked list of edges, highest first
Cache Writing:
.kalshi_research_cache.json (used by related commands)state/kalshalyst_results.json for analysisAlerting:
Brier Tracking:
Ticker Prefixes (High-Volume Garbage):
KXHIGH, KXLOW, KXRAIN, KXSNOW, KXTEMP, KXWIND, KXWEATH — Weather markets
INX, NASDAQ — Intraday index ranges
FED-MR — Fed meeting minute-range bets
KXCELEB, KXMOVIE, KXTIKTOK, KXYT, KXTWIT — Celebrity/entertainment
KXSTREAM — Streaming metrics
Category Slugs (API-Level Blocking):
weather, climate, entertainment, sports, social-media, streaming, celebrities
Micro-Timeframe Patterns (Coin Flips):
"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):
Blind mode (not showing Claude the market price):
Why? Claude doesn't know what the market thinks, so it defaults to high uncertainty.
Contrarian mode (showing Claude the price):
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 = (1/n) * Σ(forecast - outcome)²
Log Phase: Every edge scanner run logs all estimates to SQLite
Resolve Phase: When markets close on Kalshi, log the outcome
check_and_resolve_markets() polls Kalshi API dailyresolve_market(ticker="POTUS-2028", outcome=1)Report Phase: get_brier_report() computes calibration
CREATE TABLE estimates (
id INTEGER PRIMARY KEY,
ticker TEXT NOT NULL,
title TEXT,
estimated_prob REAL NOT NULL,
market_price_cents INTEGER,
confidence REAL,
estimator TEXT, -- 'claude' or 'qwen'
edge_pct REAL,
direction TEXT, -- 'underpriced', 'overpriced', 'fair'
category TEXT, -- 'politics', 'crypto', etc.
info_density REAL, -- 0.0-1.0 richness of context
created_at TEXT,
created_ts REAL
);
CREATE TABLE resolutions (
id INTEGER PRIMARY KEY,
ticker TEXT NOT NULL UNIQUE,
outcome INTEGER, -- 1 = YES, 0 = NO
resolved_at TEXT,
resolved_ts REAL
);
Measures how much context was available at estimation time (0.0-1.0):
Higher density estimates should be better calibrated (more informed).
Weekly check: get_calibration_alert()
For binary prediction markets, Kelly fraction tells you what % of bankroll to risk:
f* = (p * b - q) / b
where:
p = estimated true probability of winning
q = 1 - p (probability of losing)
b = decimal odds - 1 = (payout / cost) - 1
Example: Estimate YES at 65%, market prices at 50¢
p = 0.65, q = 0.35
Cost = 50¢, Profit = 50¢ → b = 50/50 = 1.0
f* = (0.65 * 1.0 - 0.35) / 1.0 = 0.30 (30% of bankroll)
With $200 bankroll → $60 bet = 120 contracts at 50¢
Full Kelly is risky with noisy estimates. Kalshalyst uses fractional Kelly (α = 0.25 default):
fractional_f = f* * α * (confidence^2)
where:
α = 0.25 (quarter-Kelly, conservative)
confidence^2 penalizes low-confidence estimates aggressively
Same example, confidence = 0.7:
fractional_f = 0.30 * 0.25 * (0.7^2) = 0.00735 (0.735% of bankroll)
Position: $1.47 bet = 3 contracts at 50¢
# In kalshalyst config:
kelly:
alpha: 0.25 # Fractional Kelly multiplier
min_edge_for_sizing: 0.03 # 3% minimum edge
max_contracts_per_trade: 100
max_cost_per_trade_usd: 25.0
max_portfolio_exposure_usd: 100.0
confidence_exponent: 2.0 # penalize low confidence aggressively
KellyResult {
contracts: 3,
cost_usd: 1.50,
kelly_fraction: 0.30,
fractional_kelly: 0.00735,
edge_pct: 15.0,
reason: "Kelly=0.30 | frac=0.00735 (α=0.25, conf=0.70) | 3x @ 50¢ = $1.50 (0.75% of bankroll)",
capped: False,
bankroll_fraction: 0.75
}
# 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
# Add to crontab -e:
0 * * * * cd /path/to/kalshalyst && python -m kalshalyst.kalshalyst >> /tmp/kalshalyst.log 2>&1
# Add to openclaw config:
skills:
kalshalyst:
enabled: true
schedule: "*/60 * * * *" # Every 60 minutes
timeout_seconds: 300
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"]
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.
{
"insights": [
{
"ticker": "POTUS-2028-DEM",
"title": "Will a Democrat win 2028?",
"side": "NO",
"confidence": "high",
"yes_bid": 45,
"yes_ask": 51,
"volume": 2500,
"open_interest": 8000,
"days_to_close": 672,
"edge_type": "claude_contrarian",
"spread_capture_cents": 6,
"spread_pct": 6.6,
"market_prob": 0.48,
"estimated_prob": 0.62,
"edge_pct": 14.0,
"effective_edge_pct": 14.0,
"direction": "overpriced",
"reasoning": "Market overweighting base rate without pricing recent policy momentum...",
"estimator": "claude",
"is_sports": false
}
],
"macro_count": 3,
"sports_count": 0,
"total_scanned": 342,
"scanner_version": "1.0.0",
"estimator": "claude+qwen_fallback",
"cached_at": "2026-03-08T15:32:18+00:00"
}
# Run the full pipeline
from kalshalyst import check_kalshalyst
check_kalshalyst(state={}, dry_run=False, force=False)
# Or run individual phases
from kalshalyst.kalshalyst import (
fetch_kalshi_markets,
classify_markets,
calculate_edges,
)
markets = fetch_kalshi_markets(cfg)
markets = classify_markets(markets, cfg)
edges = calculate_edges(markets, cfg)
# Position sizing
from kalshalyst.kelly_size import kelly_size, kelly_from_edge_result
result = kelly_size(
estimated_prob=0.65,
market_price_cents=50,
confidence=0.7,
bankroll_usd=200.0,
side="yes",
)
print(result.contracts, result.reason)
# Brier tracking
from kalshalyst.brier_tracker import (
log_estimate,
resolve_market,
get_brier_report,
)
log_estimate(ticker="POTUS-2028", estimated_prob=0.62, ...)
resolve_market(ticker="POTUS-2028", outcome=1)
print(get_brier_report())
Kalshalyst automatically falls back to Qwen after 3 consecutive Claude failures. Check:
To force Qwen fallback immediately:
CLAUDE_DISABLED=1 python -m kalshalyst.kalshalyst
If "no markets passed filters":
To debug:
DEBUG=1 python scripts/kalshalyst.py
Brier score requires market resolutions. If none available:
resolve_market("TICKER", 1)sqlite3 state/brier_tracker.db "SELECT COUNT(*) FROM resolutions;"Possible causes:
min_edge_for_sizing)Verify with:
result = kelly_size(..., bankroll_usd=100.0)
print(result.reason) # Explains why contracts = 0
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.
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 |
Install the complete stack:
clawhub install kalshalyst kalshi-command-center polymarket-command-center prediction-market-arbiter xpulse portfolio-drift-monitor market-morning-brief personality-engine
Battle-tested in production trading environments. Key design decisions:
references/contrarian-prompt.md for the full Claude system prompt with explanationreferences/blocklist.md for complete blocklist documentationreferences/brier-schema.md for database schema and methodologyreferences/kelly-math.md for Kelly Criterion math derivationKalshalyst is actively maintained. Common iteration paths:
See the GitHub issues (if published) or contact the maintainer for feature requests.
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:
.py file on disk (e.g., ~/skills/kalshalyst/scripts/*.py)~/.openclaw/skills/kalshalyst/scripts/*.py~/skills/Never say "fixed" if you only demonstrated the fix in conversation output.
Found a bug? Have a feature request? Want to share results?
Part of the OpenClaw Prediction Stack — the first prediction market skill suite on ClawHub.