An automated trading bot for Kalshi daily temperature prediction markets. It ingests real-time NWP model output (HRRR), live METAR airport observations, and GEFS ensemble forecasts to estimate same-day temperature outcomes and trade where its probability estimate diverges from the market price.
Status: Demo (paper) mode by default. Set
EXECUTION_MODE: "demo"in config to paper-trade, or"prod"to trade real money. Use at your own risk.
The bot runs two async loops continuously:
- Discovery loop — scans Kalshi for new weather markets and populates a local database
- Signal loop (every 30s) — for each watched market, computes a probability estimate and executes if the edge exceeds the threshold
NWS gridpoint hourly anchor
+ city prior bias correction (seasonal, auto-updated weekly)
+ rolling short-term bias (exponential decay, auto-updated daily)
+ METAR live correction ((METAR_now - HRRR_now) × diurnal_weight)
+ GEFS ensemble blend (30-member, dynamic alpha)
→ Gaussian bracket probability
→ ML calibration layer (LightGBM, 7 cities, 28 intraday features)
→ edge vs. market price → trade if edge ≥ 15%
NYC, Chicago, Miami, Austin, LA, Denver, Philadelphia (ML models trained for all 7; active set configurable via ML_ENABLED_CITIES).
Kalshi weather markets settle against NWS Daily Climate Reports (official government observations). The bot uses METAR data from the same stations (KNYC, KMDW, KMIA, KAUS, KLAX, KDEN, KPHL) as its real-time signal.
# 1. Clone and install
git clone https://github.com/fsevkli/ProjectKM.git
cd ProjectKM
pip install -r requirements.txt
# 2. Configure credentials
cp config/local.json.example config/local.json
# Edit config/local.json — fill in KALSHI_ACCESS_KEY and KALSHI_PRIVATE_KEY_PATH
# 3. Verify Kalshi auth
python scripts/kalshi_smoke.py
# 4. Train ML models (optional but recommended)
python scripts/ml_train_intraday.py --temp both
# 5. Run
python scripts/run_loops.py| Key | Where to get |
|---|---|
KALSHI_ACCESS_KEY |
Kalshi account → API settings |
KALSHI_PRIVATE_KEY_PATH |
Path to your RSA private key (see AUTH.md) |
NCEI_TOKEN |
NOAA NCEI token — used for ML training data |
OPENAI_API_KEY |
Optional — only used if USE_LLM_FOR_EXITS: true (disabled by default) |
All credentials go in config/local.json (gitignored). See AUTH.md for RSA key setup.
All runtime behaviour is controlled by config/local.json. Key flags:
| Flag | Default | Description |
|---|---|---|
EXECUTION_MODE |
"demo" |
"demo" = paper trading, "prod" = real money |
KALSHI_ENV |
"demo" |
API environment ("demo" or "prod") |
ML_ENABLED_CITIES |
["AUS","CHI","MIA"] |
Cities with active ML models |
EDGE_BASE_THRESHOLD |
0.15 |
Minimum edge (15%) required to enter a trade |
SIGNAL_YES_ENABLED |
false |
Enable/disable YES-side trades |
NO_BRACKET_HOLD_TO_EXPIRY |
true |
Hold all NO positions to settlement |
BANKROLL |
1000 |
Paper bankroll in dollars |
DAILY_LOSS_LIMIT |
-0.20 |
Halt trading if daily loss exceeds 20% of bankroll |
GEFS_ENSEMBLE_ENABLED |
true |
Blend GEFS 30-member ensemble into probability |
OBSERVATION_ONLY_MODE |
true |
Use HRRR+METAR only (skip external forecast APIs) |
See CLAUDE.md for the full config reference.
# Live status
python scripts/live_positions.py # Open positions + unrealized P&L
python scripts/why_not_trading.py # Diagnose why no signals are firing
python scripts/check_status.py # Quick status snapshot
# P&L and history
python scripts/weekly_check.py # Weekly P&L report
python scripts/show_trade_history.py # Full trade log
python scripts/daily_report.py # Daily summary
python scripts/fetch_outcomes.py # Settle closed markets
# Bias calibration (run regularly)
python scripts/rolling_bias_update.py # Daily rolling correction
python scripts/auto_bias_update.py --start-date YYYY-MM-DD # Weekly residual update
python scripts/build_seasonal_corrections.py --years 3 --apply # Quarterly seasonal rebuild
# ML
python scripts/ml_train_intraday.py --temp both # Retrain all city models
python scripts/ml_analyze.py # Model health check (Brier scores, freshness)
# Analysis
python scripts/analyze_edge_buckets.py # Win rate by edge bucket
python scripts/retroactive_calibration.py --days 14 --print-only # Forecast residualssrc/kmbot/
├── loops.py Main async loops (discovery + signal)
├── loops_realtime.py Real-time observation loop (NWS + METAR)
├── config.py BotConfig dataclass
├── models.py Shared dataclasses
│
├── ingestion/
│ ├── kalshi.py Kalshi REST client (RSA-PSS auth)
│ ├── kalshi_ws.py WebSocket live orderbook
│ ├── hourly_coordinator.py HRRR + METAR + NWS ingestion
│ ├── gefs_ensemble.py GEFS 30-member ensemble (Open-Meteo)
│ ├── metar.py Live METAR observations
│ └── coordinator.py Forecast aggregation
│
├── processing/
│ ├── hourly_projector.py HRRR+METAR → model probability
│ └── aggregator.py Multi-source weighted aggregation
│
├── decision/
│ ├── signals.py Signal generation + all trade guardrails
│ ├── edge.py Edge calculation (model prob vs. market)
│ ├── probability.py Gaussian bracket probability
│ ├── risk.py Risk manager (loss limits, drawdown)
│ └── sizing.py Kelly position sizing
│
├── execution/
│ └── engine.py Order placement via Kalshi REST
│
├── tracking/
│ └── store.py Prediction + trade logging (SQLite)
│
└── ml/
├── training/trainer.py LightGBM trainer (28 intraday features)
├── features/builder.py Feature engineering
└── integration/probability_adapter.py ML ↔ base model blend
| File | Contents |
|---|---|
data/kalshi.db |
Market data, orderbooks, forecasts, watchlist |
data/kalshi_tracking.db |
Predictions, trades, settlement outcomes |
data/ml_cache.db |
ML feature cache, historical observations |
LightGBM models trained on 14 years of historical ASOS + NCEI data (2010–2023). One model per city per market type (HIGH/LOW), plus global fallbacks.
28 features include:
- Static: city, day-of-year, historical mean/std, threshold distance
- Intraday snapshot: current temp, peak so far, hours elapsed, trend, window progress
- Atmospheric: dewpoint, humidity, wind speed, cloud cover
Retrain with:
python scripts/ml_train_intraday.py --temp bothTraining data is downloaded automatically from IEM (ASOS) and NOAA NCEI.
Three layers of temperature bias correction:
- Seasonal baseline (
data/city_prior_biases.json) — quarterly rebuild from 3yr HRRR vs. NCEI actuals - Rolling short-term (
data/rolling_bias.json) — daily exponential-decay correction - Live METAR correction — real-time
(METAR_now - HRRR_now) × diurnal_weight
This software is provided for educational and research purposes. Trading prediction markets involves financial risk. Always start with EXECUTION_MODE: "demo" and paper-trade before using real funds. The authors accept no responsibility for financial losses.
MIT — see LICENSE.