QuantWeather is a monorepo for a modular weather-market trading system targeting Polymarket-style markets.
- Root package: dependency-light weather-market screening, artifact generation, and local CLI/dashboard tooling.
quantweather-execution/: execution-system starter with SQLite persistence, paper-trading lifecycle, approval API, and Next.js dashboard.
See docs/MVP.md for the full MVP acceptance checklist.
The following capabilities are required for a working paper-trading product:
| Capability | Status | Notes |
|---|---|---|
| Live weather market discovery | Partial | Fixture-backed works; live Polymarket pending |
| Live forecast ingestion | Done | NOAA/NWS via points API |
| Model edge calculation | Done | Probability estimation + signal generation |
| Paper trade execution | Done | Artifacts from saved screening runs |
| Visible P/L and audit trail | Done | Execution API reports; manual signal ingest |
| Health and monitoring | Done | Screen + execution health checks |
| Local operator dashboard | Done | HTML dashboard with analytics |
Blocking issues for end-to-end live data:
- CHA-2902 — Venue configuration and runtime status
- CHA-2903 — Live Polymarket market data adapter
- CHA-2904 — Screening to execution signal handoff
The root package currently supports:
- structured market and forecast domain objects
- fixture-backed JSON normalization for markets and forecasts
- market discovery from exchange/catalog snapshots with liquidity, spread, rule, and location filters
- NOAA/NWS forecast normalization from fixture payloads, plus an explicit live fetch path through the NWS points API
- parsing threshold-style weather market rules
- generating probability estimates for temperature and precipitation events
- comparing model probabilities to market-implied prices
- sizing proposed positions under configurable risk limits
- paper execution artifacts for approved recommendations
- monitoring checks for screen and execution health
- analytics for latest runs and saved-run history
- producing auditable, reviewable opportunity summaries through a CLI entrypoint
- screening batches of markets against forecast snapshots into a ranked review feed
- exporting review feeds as stable JSON for future UI or persistence layers
- rendering a local HTML dashboard with summaries, analytics, monitoring alerts, comparisons, run history, and linked artifacts
The execution package currently supports:
- persisted signals, approvals, order intents, orders, fills, positions, and events
- paper-trading approval and auto-trading rules
- reconciliation and performance reporting
- stdlib HTTP API
- Next.js execution dashboard
The following remain deferred until the paper-trading loop is proven reliable:
- Live-money trading — exchange adapter, wallet/key management
- Live Polymarket discovery — REST client for Gamma/CLOB APIs (CHA-2903, GitHub #2)
- Automated signal handoff — screening to execution flow (CHA-2904, GitHub #3)
- Venue status visibility — dry-run vs live state reporting (CHA-2902, GitHub #1)
- Persisted analytics stores — beyond local JSON artifacts
- Authentication — multi-user access control
- Production monitoring transports — metrics, alerting, logging pipelines
Run the test suite:
env PYTHONPATH=src python3 -m unittest discover -s tests -p 'test_*.py'Run the demo pipeline:
env PYTHONPATH=src python3 -m quantweather.cliScreen the fixture-backed review feed:
env PYTHONPATH=src python3 -m quantweather.cli screen --format textDiscover supported markets from a catalog snapshot:
env PYTHONPATH=src python3 -m quantweather.cli discover --format json --min-liquidity 10000Normalize a NOAA/NWS fixture into QuantWeather forecast JSON:
env PYTHONPATH=src python3 -m quantweather.cli ingest-noaa --input ./tests/fixtures/noaa_forecast.jsonFetch a live NWS forecast by point and normalize it:
env PYTHONPATH=src python3 -m quantweather.cli ingest-noaa \
--lat 40.7128 \
--lon -74.0060 \
--location "New York City" \
--user-agent "QuantWeather/0.1 contact=you@example.com"Run a screen from a JSON profile:
env PYTHONPATH=src python3 -m quantweather.cli screen --config ./quantweather-profile.jsonPrint the mixed review feed as JSON:
env PYTHONPATH=src python3 -m quantweather.cli screen --format jsonWrite the mixed review feed to disk:
env PYTHONPATH=src python3 -c "from quantweather.cli import export_fixture_screen_json; print(export_fixture_screen_json())"Save the mixed review feed as a durable run with manifest metadata:
env PYTHONPATH=src python3 -m quantweather.cli save-run --run-dir ./artifacts/screen-runsSave a run from a profile with CLI overrides:
env PYTHONPATH=src python3 -m quantweather.cli save-run --config ./quantweather-profile.json --min-edge 0.07List saved runs from the manifest:
env PYTHONPATH=src python3 -m quantweather.cli list-runs --run-dir ./artifacts/screen-runsSummarize the latest saved run:
env PYTHONPATH=src python3 -m quantweather.cli summary --run-dir ./artifacts/screen-runsCompare the latest two saved runs:
env PYTHONPATH=src python3 -m quantweather.cli compare --run-dir ./artifacts/screen-runsRender the latest saved run as a Markdown report:
env PYTHONPATH=src python3 -m quantweather.cli report --run-dir ./artifacts/screen-runsRender the latest comparison as a Markdown report:
env PYTHONPATH=src python3 -m quantweather.cli comparison-report --run-dir ./artifacts/screen-runsWrite the latest run report to disk:
env PYTHONPATH=src python3 -m quantweather.cli report-save --run-dir ./artifacts/screen-runsWrite the latest comparison report to disk:
env PYTHONPATH=src python3 -m quantweather.cli comparison-report-save --run-dir ./artifacts/screen-runsWrite the latest local manual-review dashboard to disk:
env PYTHONPATH=src python3 -m quantweather.cli dashboard-save --run-dir ./artifacts/screen-runsPaper-execute the latest saved run and persist an execution artifact:
env PYTHONPATH=src python3 -m quantweather.cli execute --run-dir ./artifacts/screen-runsMonitor the latest saved run and any linked execution artifact:
env PYTHONPATH=src python3 -m quantweather.cli monitor --run-dir ./artifacts/screen-runsAnalyze the latest saved run plus saved-run history:
env PYTHONPATH=src python3 -m quantweather.cli analytics --run-dir ./artifacts/screen-runsBuild the local image:
docker build -t quantweather:local .Run the default demo command in a container:
docker run --rm quantweather:localRun a screen from mounted local files:
docker run --rm \
-v "$(pwd)/artifacts:/app/artifacts" \
-v "$(pwd)/tests/fixtures:/app/tests/fixtures:ro" \
quantweather:local \
screen --format jsonUse the included Compose setup:
docker compose run --rm quantweatherSave a run into the mounted local artifacts/ directory:
docker compose run --rm quantweather save-run --run-dir /app/artifacts/screen-runssrc/quantweather/domain.py: shared dataclasses and enumssrc/quantweather/discovery.py: market catalog discovery filterssrc/quantweather/noaa.py: NOAA/NWS forecast normalization and live fetch helpersrc/quantweather/ingest.py: fixture-backed payload normalization helperssrc/quantweather/market_rules.py: rule parsing for simple weather marketssrc/quantweather/modeling.py: probability estimation helperssrc/quantweather/signals.py: market edge and opportunity ranking logicsrc/quantweather/risk.py: sizing and guardrailssrc/quantweather/execution.py: paper execution order generationsrc/quantweather/monitoring.py: run and execution health checkssrc/quantweather/analytics.py: latest-run and history analyticssrc/quantweather/audit.py: recommendation record assemblysrc/quantweather/engine.py: end-to-end market evaluation orchestrationsrc/quantweather/serialize.py: JSON-safe recommendation export helperssrc/quantweather/storage.py: local run history and manifest helperssrc/quantweather/report.py: Markdown reporting for saved runs and comparisonssrc/quantweather/dashboard.py: HTML dashboard rendering for saved runssrc/quantweather/cli.py: sample runnable entrypointDockerfile/compose.yaml: local container packaging for the CLI workflowtests/: regression coverage for the initial decision pipeline
max_daily_risk is enforced in aggregate by screen_markets, the layer that
sizes positions and reports proposed_notional. Execution consumes those
values as-is, so the sum of approved proposed_notional in one screen never
exceeds max_daily_risk - daily_risk_used.
- Each market is first sized independently (per-trade, per-market and other static caps).
- Approved proposals then draw on the shared budget in descending edge order (ties keep input order), so scarce budget goes to the best opportunities rather than whichever market the feed listed first.
- The proposal that crosses the limit is cut to the remainder and carries
DAILY_RISK_AGGREGATE_REDUCED; later proposals are blocked withDAILY_RISK_AGGREGATE_EXHAUSTEDand a notional of 0.DAILY_RISK_EXHAUSTEDstill means the day's budget was already spent before the screen started. risk.apply_daily_risk_budgetandengine.budget_consumption_orderare the shared accumulator step; a backtest should use them so it and live screening report the same total exposure for the same inputs.
- The initial model treats weather inputs as already normalized forecast facts.
- Market prices are expressed as
0.0..1.0probabilities. - Unsupported market titles are normalized at ingest time and surfaced as review-feed errors during screening.
- Paper execution is supported; live exchange execution is intentionally blocked until a broker/exchange adapter is configured.
- Live NOAA ingestion uses the NWS
/points/{lat},{lon}lookup to discover the grid forecast URL, then normalizes the forecast periods into QuantWeather forecast snapshots.
The CLI accepts a stdlib-only JSON profile for reusable operator runs:
{
"version": 1,
"name": "baseline",
"run_dir": "./artifacts/screen-runs",
"screen": {
"markets": "./tests/fixtures/markets_mixed.json",
"forecasts": "./tests/fixtures/forecasts.json",
"account_balance": 5000.0,
"sizing_method": "proportional",
"format": "json",
"risk_limits": {
"max_trade_notional": 250.0,
"max_market_exposure": 400.0,
"max_daily_risk": 500.0,
"min_confidence": 0.45,
"min_edge": 0.05,
"max_spread": 0.05,
"min_liquidity": 5000.0
}
},
"save_run": {
"label": "screen"
}
}Override rules:
- CLI flags win over profile values.
- Profile values win over built-in defaults.
- Relative paths inside the profile are resolved relative to the profile file.