Daily temperature high/low bracket and threshold contracts on Kalshi — contract structure, forecast→P(YES) map, settlement rules, cross-venue divergences, and weather-specific pitfalls
npx skills add https://github.com/agiprolabs/claude-trading-skills --skill kalshi-weather-markets
Kalshi lists daily high and low temperature options for ~20 US cities as binary contracts that settle YES ($1.00) or NO ($0.00). This skill covers the market structure, the forecast-to-probability map, exact settlement mechanics, and hard-won pitfalls. It builds on the exchange layer — for Kalshi API mechanics (host, auth, orders, order book, candlesticks) see the kalshi-api skill; for strategy, sizing, and backtesting see prediction-market-strategy.
B<center>A bracket ticker B<center> is a 2°F-wide, both-ends-inclusive window.
B74.5 covers the two integers {74, 75}°F.T<strike>A threshold ticker T<strike> is a one-sided binary.
greater → YES iff cli >= strike + 1less → YES iff cli <= strike - 1strike_type ("greater" / "less") is not inferable from the ticker. Read it from the API strike_type field every time.KXHIGH<CITY>-<YYMONDD>-B<center> # bracket high
KXLOW<CITY>-<YYMONDD>-T<strike> # threshold low
The date is encoded in the ticker, not derivable from close_time.
KXHIGHNY-26JUN21 settles 2026-06-21 LST. close_time is next-day UTC (~00:59 ET). Joining on close_time off-by-ones every label — use the ticker date.
Given a forecast distribution N(μ, σ) for the day's extreme, apply the half-integer continuity correction (mandatory — settlement is on integers, not a continuous scale):
# Bracket B<center>, covering integers {floor, cap}
P(YES) = Φ((cap + 0.5 − μ) / σ) − Φ((floor − 0.5 − μ) / σ)
# Threshold "greater":
P(YES) = 1 − Φ((T + 0.5 − μ) / σ)
# Threshold "less":
P(YES) = Φ((T − 0.5 − μ) / σ)
Φ(x) = 0.5 · (1 + erf(x / √2)) # stdlib only, no scipy needed
The ±0.5 shift is not optional. Dropping it biases every bracket. Treating 2°F brackets as 1°F half-open windows produced a +1640% phantom backtest in one project.
See scripts/weather_brackets.py for runnable implementations of all four functions.
sigma_raw = max((p90 − p10) / 2.56, 0.5) · sigma_scale · sigma_mult
mu = p50 # or nowcast-blended (see forecasting.md)
sigma = max(sigma_raw, 0.1) # hard floor against degeneracy
The 2.56 divisor is the 10th–90th percentile span of a standard normal (2 × 1.28σ).
The settlement value (NWS CLI integer °F, LST day) is not the same as raw ASOS/METAR hourly max/min — CLI applies QC, backup-station fallback, and LST aggregation. Shift μ before computing P(YES):
mu_cli = mu_metar + bias_city_season # bias = oracle_extreme − asos_extreme, fit per city + season
Fit bias_max / bias_min as seasonal (circular) curves per city. Skipping this systematically misprices every bracket for cities with a structural CLI/METAR gap.
cli ∈ {floor, cap} (both ends inclusive).cli >= strike + 1.cli <= strike - 1.> Read each market's own rulebook before scoring or trading. Settlement source, station, and day-window are per-market contract terms that can change.
| Resource | URL |
|----------|-----|
| Kalshi market rules / Rulebook | <https://docs.kalshi.com> (per-market "Rulebook") |
| NWS Climatological Report (CLI) | <https://www.weather.gov/wrh/Climate> |
| IEM ASOS daily download | <https://mesonet.agron.iastate.edu/request/daily.phtml> |
| Polymarket resolution (WU) | <https://www.wunderground.com> |
| Polymarket disputes (UMA) | <https://docs.uma.xyz> |
The same metro on the same date can settle to different values across venues — both because of the station and the DST window in spring/fall.
| Axis | Kalshi | Polymarket |
|------|--------|------------|
| Source | NWS CLI / IEM ASOS | Weather Underground |
| Day window | LST (no DST) | Local clock (with DST) |
| NYC station | KNYC (Central Park) | KLGA (LaGuardia) |
| Rounding | Integer °F, t ∈ {floor, cap} | Per WU history |
Any cross-venue analysis must settle each leg on its own source.
Once an intraday observation is available, pull μ toward reality and shrink σ:
[obs, obs + drift · hours_remaining][obs − drift · hours_remaining, obs]sigma_raw · sqrt(hours_remaining / 24), floored at sigma_floor (≈ 0.5)drift ≈ 3.0°F/hr defaultOptional NWP prior blend: new_p50 = w · hrrr + (1−w) · p50 (w ≈ 0.5), then rebuild symmetric quantiles using a calibrated σ.
Per-city OOS Brier scores across 22 highs + 22 lows (v1.5, 2026-06-17 baseline):
| Metric | Range |
|--------|-------|
| Per-city OOS Brier | 0.07 – 0.14 (lower = better; 0.25 = climatology) |
| Per-city accuracy | 65–85% (bracket classification) |
Forecast skill ≠ trading edge. A calibrated model that beats climatology by 0.05 Brier does not guarantee positive EV at market prices — the market already incorporates NWP. The practical edge is maker-side fading of mispriced longshot brackets (favorite–longshot bias), not raw directional forecasting.
result.{floor, cap} as 1°F half-open [floor, cap) manufactures a large phantom backtest edge. The bracket is both-ends-inclusive.T74 on a low market might be greater or less. Always read strike_type from the API. Never guess.close_time. Use the date embedded in the ticker string for settlement-date joins, not close_time (which is next-day UTC).10. Overround as a diagnostic. Sum the YES prices across an event's full bracket set. overround > 1.0 is normal (house edge); overround >> 1.1 signals a mispriced event (or data error).
references/brackets-and-settlement.md — Bracket/threshold structure, P(YES) formulas, settlement rules, cross-venue divergence table, overroundreferences/forecasting.md — Ensemble quantiles → (μ, σ), nowcast blending, CLI-space bias correction, model skill numbers, forecast ≠ edgescripts/weather_brackets.py — Gaussian bracket/threshold P(YES), settlement resolution, and quantile→(μ,σ) functions (pure stdlib, runs offline)Integration with protocols.io API for managing scientific protocols. This skill should be used when working with protocols.io to search, create, update, or publish protocols; manage protocol steps and materials; handle discussions and comments; organize workspaces; upload and manage files; or integrate protocols.io functionality into workflows. Applicable for protocol discovery, collaborative protocol development, experiment tracking, lab protocol management, and scientific documentation.
Analyzes job descriptions and generates tailored resumes that highlight relevant experience, skills, and achievements to maximize interview chances
Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw.
Build and distribute Expo development clients locally or via TestFlight
Use when you have a written implementation plan to execute in a separate session with review checkpoints
Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.
Benchling R&D platform integration. Access registry (DNA, proteins), inventory, ELN entries, workflows via API, build Benchling Apps, query Data Warehouse, for lab data management automation.
Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.
Take agiprolabs/kalshi-weather-markets from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.