State as of 2026-06-22
The
wx-signalengine is deployed, live, and publishing real signals to NATS (unchanged from 2026-06-18). The big change since then: the pmv2 monolith is being split into independent service repos with NATS as the spine and a sharedpmv2-contractscrate as the seam, and weather has signed off on a v2 trade wire-contract (thelimitarm). Producer code to emit v2 is scoped but NOT yet built. The dry-rehearsal (capital gate) is still pending — it was blocked by a “too close to resolution” gate, now fixed on the consumer side (i64::MINexemption, PM @43023ba), needs a redeploy + a fresh US lock to complete. Supersedes the stale “code not started” status in weather-bet.
TL;DR — where everything is
| piece | state |
|---|---|
| Strategy | Validated GO on US fillable cohort (UNCHANGED) — 94% win / +29.9% mean / +17.4% 80%-LCB on the ~44% fillable (≤0.95) cohort. weather-strategy-validated-plan + honest re-backtest below |
| Repo | RENAMED + MOVED (2026-06-22) — github.com/wowjeeez/pmv2-weather-us-algo (PRIVATE), local /Users/levander/coding/pmv2/us_weather_algo/. Was wowjeeez/weather-bet @ /Users/levander/coding/weather_bet |
Engine (wx-signal) | Live in --loop on polymarket-infra (GCP), pin a2fa5ee, branch feat/wx-signal-engine. Validated lock logic unchanged |
| Publishing | Confirmed live — real acked signals (Atlanta, Chicago) on the old weather.signals stream. v2 not yet wired |
| Architecture | pmv2 monolith RETIRING → split into service repos (producers → executor → notify), NATS spine, shared pmv2-contracts. See pmv2-rearchitecture |
| Wire contract | v2 signed off (weather limit arm) — supersedes old docs/signal-schema.md v1 envelope. Producer code to emit it = PENDING |
| Executor (Position Manager) | pmv2-position-manager (@deploy / @positionmanager) — consumes NATS directly, gates, signs EIP-712, POSTs CLOB. Mode = OFF (not live-armed) |
| Capital gate (dry-test) | PENDING — was blocked by the “too close to resolution” liveness_gate; FIXED consumer-side (i64::MIN exemption, PM @ 43023ba). Needs redeploy + a FRESH US afternoon lock to fire the 🧪 DRY-RUN alert, then cross-check |
The strategy (obs-driven late-settlement) — UNCHANGED, still GO
Polymarket “highest temperature in {city} on {date}” markets resolve on the day’s actual high at a named ICAO airport (whole °F US), winning bucket → $1. The market is slow to reprice a high that’s already physically set: the daily high pins mid-afternoon, but the market takes time to mark the winning bucket up. The engine detects the high is in, from live METAR, before the market catches up.
Lock rule (the core, validated, unchanged): poll METAR per-minute → running whole-°F max → lock = first obs with station-local hour ≥ 15:00 (LOCK_HOUR) where the running max hasn’t risen for 90 min (NO_RISE_SECS=5400) → buy that bucket’s YES only if fillable ≤ 0.95 (else skip and retry) → hold to $1. Mirrors research/strategy/engine.py byte-for-byte (80 golden fixtures).
The strategy did not change
The pmv2 re-architecture changes how the signal is delivered and executed, NOT what the signal is. The lock logic, the ≤0.95 fillability gate, the US-only GO verdict, and the validated edge are all unchanged. The load-bearing unknown remains fills (what the dry rehearsal measures).
Honest re-backtest verdict (2026-06-16, unchanged)
A clean causal backtest (research/strategy/clean_backtest.py, report research/reports/strategy-revalidation-honest-2026-06-16.md) corrected the earlier inflated +10.7%:
- US cohort (NYC/Chicago/Miami/Atlanta), 151 locked days: reliability 96.7% all-locked. But ~53% of locked days are already > 0.95 at lock (locked out of the near-certain winners). On the ~44% fillable (entry ≤ 0.95) cohort: 94% win, +29.9% mean return, +17.4% 80%-LCB — a real, positive edge on a smaller day-count.
- Intl °C cohort (London/Seoul/Paris): NO-GO for the lock-and-hold entry — 60.8% tradeable reliability, return 80% CI (−13.3%, +31.1%). 1°C buckets too tight. (Asian markets are now a separate lane —
weather_as/ pmv2-weather-as-algo — not part of this repo’s GO.) - The load-bearing unknown is fills — the backtest prices at
prices-historymid + a small haircut; real fillability at ≤0.95 is what the dry-rehearsal measures.
Repo rename + move (2026-06-22)
Every old reference is stale
- GitHub:
github.com/wowjeeez/weather-bet→github.com/wowjeeez/pmv2-weather-us-algo(PRIVATE).- Local path:
/Users/levander/coding/weather_bet→/Users/levander/coding/pmv2/us_weather_algo/.
This repo is now one of a sibling set of pmv2 service repos under /Users/levander/coding/pmv2/: us_weather_algo (this), as_weather_algo, cohort_algo, crypto_algo, position_manager, telegram_connector. On GitHub: pmv2-weather-us-algo, pmv2-weather-as-algo, pmv2-cohort-algo, pmv2-crypto-algo, pmv2-position-manager, pmv2-telegram-connector, and the shared pmv2-contracts.
The engine (crates/wx-signal) — unchanged
Rust workspace crate. Polls aviationweather.gov METAR (live) / IEM ASOS (replay), computes the lock, maps to the Gamma bucket/token, prices it (CLOB /price→/midpoint→/book ladder, dust floor MIN_VALID_PRICE=0.02), and dual-writes: Supabase weather_signals (atomic INSERT + pg_notify, ON CONFLICT(market_slug) dedup) and a NATS JetStream publisher.
- Engine files (
lock.rs,price.rs,nats.rs,sink.rs,signal.rs,main.rs) and the validated lock logic are unchanged by the re-arch. --smokeflag: on-demand connect → publish one synthetic signal → ack, no Supabase/lock needed (the deploy-host e2e proof).- Skip-on-untradeable: when no confirmed ask ≤ 0.95, it emits nothing (logs
untradeable: ... skipping emit) — never defaults to a 0.95 cap. Verified live (Chicago skipped once its bucket drifted > 0.95). - Telemetry: OTLP → SigNoz,
service.name=wx-signal. Useful log bodies:lock_detected,no_lock,nats publish(withackedbool),untradeable: ... skipping emit,outside US afternoon window; sleeping.
Architecture (the pmv2 split) — NEW
The monolith (polymarket_fetch) is retiring, split into independent service repos with NATS JetStream as the spine and a shared pmv2-contracts crate as the seam. Dependencies are unidirectional: producers → executor → notify. Full design in pmv2-rearchitecture.
producers (weather=THIS / weather_as / cohort=first_mover_core / crypto=crypto_shortterm_latency_test)
→ PMV2_ORDERS / pmv2.order.<source>.<entry|exit>
→ Position Manager: ONE durable pull consumer on pmv2.order.> (explicit ack, Nats-Msg-Id dedup)
→ gate (off/dry/live + caps + breaker) → sign EIP-712 → POST clob.polymarket.com → record/settle
- Producers emit READY orders and own ALL gating — PM has no GammaClient. Weather does its lock + ≤0.95 fillability and emits only orders it has decided to take.
- Position Manager = the executor (@deploy / @positionmanager):
polymarket_fetch’s consume + exec moves here. Consumes NATS directly (no separate runner), gates, signs EIP-712, POSTsclob.polymarket.com, records/settles. Mode currently OFF (not live-armed). - Notification service: dedicated, centralizes the ~25–30 scattered Telegram send-sites behind a NATS notify subject. Owner TBD.
pmv2-contracts(PUBLISHED,github.com/wowjeeez/pmv2-contracts): serde + rust_decimal only; holds the envelope types, thePricingenum (limit|derived),Side,SCHEMA_VERSION = 2, and subject builders.sourceis a FREE String, not an enum — adding a lane = publish the source string + insert apmv2_autotrade_sourcesDB row. Producers + PM vendor it so the wire can’t drift.
Supersedes the old single-stream pipeline
The previous design (single stream
WEATHER_SIGNALS/ subjectweather.signals, a hand-trackeddocs/signal-schema.mdenvelope, cohort riding the same stream oncohort.signals) is being replaced by the one-PMV2_ORDERS-stream, source-routed-subjects, shared-contracts model above. The old envelope is documented in this repo’sdocs/signal-schema.md(still v1) and is now historical.
The wire contract (v2 — weather’s limit arm) — NEW, signed off
Signed off by weather (2026-06-22) — supersedes the v1 envelope
Weather emits a READY BUY entry-order to
pmv2.order.weather.entry. Full field table + PM placement semantics in [[pmv2-rearchitecture#trade-wire-contract-v2—weathers-limit-arm|Trade wire-contract v2 — weather’slimitarm]]. Summary:
- common:
id = uuid5("{source}|{market_slug}|{action}")(dedup key =Nats-Msg-Id),source="weather"(EXACTpmv2_autotrade_sourceskey — a wrong value silently routes toMode::Off),schema_version=2,produced_at,valid_until_ts(past → Term),market{condition_id, outcome_index, token_id, title, event_slug, slug, + neg_risk/tick/min as HINTS},origin_ref(= our Supabaseweather_signalsrow id),side="BUY". - pricing = “limit”:
limit_price(≤ 0.95, hard cap),size_shares(weather-sized). - PM placement: FAK marketable-limit at
floor_to_tick(min(limit_price, best_ask))— fills ≤ our cap; a near-certain bucket whose ask > 0.95 simply won’t fill (correct, we never overpay). PM re-resolves neg_risk/tick/min authoritatively; sized-out (shares < min) → Skip. - ENTRY-ONLY: weather holds to settlement → no exit-signal (exit = resolution → $1). The
...exitsubject is cohort/crypto only. - Weather context (
city,bucket_label,observed_high_f,lock_ts,reason) stays OFF the execution wire — it lives in the Supabaseweather_signalsrow, reachable viaorigin_ref(PM ignores unknown fields).
Sizing moved to producers (NEW)
Weather now sizes its own orders (sizing moved out of the executor):
size_shares = clamp(floor(notional / limit_price), min_size = 5, cap)
Default notional = $50 (configurable); PM’s global caps + breaker remain the hard backstop.
wx-signal producer adaptation — PENDING (not built yet)
The v2 producer code change is scoped but NOT done
It was blocked on
pmv2-contracts, which now exists (published), so it is unblocked. The change:
- rename
action→side,max_price→limit_price- fold the flat market fields into
market{}- add
pricing = "limit"+size_shares- bump
schema_version1 → 2- switch subject
weather.signals→pmv2.order.weather.entry- add a sizing module (notional → shares, default $50)
- vendor
pmv2-contractsThe existing engine (
crates/wx-signal:lock.rs,price.rs,nats.rs,sink.rs) and the validated lock logic are unchanged by this. Until this ships,docs/signal-schema.mdin the repo is still the v1 envelope.
The dry-test / “too close to resolution” gate saga — NEW
The dry rehearsal (the capital gate) was blocked by the PM consumer’s liveness_gate (“too close to resolution”). This is a structural collision with the strategy, now fixed consumer-side.
Root cause
The lock strategy signals NEAR resolution by design — it locks mid-afternoon and the market resolves end-of-local-day, so every signal lands ~6–9h out and trips a gate meant to reject signals too close to settlement. The gate skips when
secs_to_resolution < min. The first Directive exemption setmin = 0, which only exempts POSITIVE secs. But the re-fired STALE Jun-19 NYC market is now PAST resolution (negative secs), so it kept skipping. A FRESH signal (positive secs) already passes withmin = 0.
Fix —
i64::MINfull exemption for Directive sourcesLanded in Position Manager
main@43023ba(consumer side, NOT this repo). Usingi64::MINas the threshold for Directive sources fully exempts them — including stale replays with negative secs.
Two earlier theories were WRONG — recorded as ruled out
- (a) weather’s “ask > max_price” — ruled out: PM caps at
min(limit_price, best_ask)and still builds the order, so this would have alerted, not silently skipped.- (b) “best_ask = None / no liquidity” — ruled out. The real cause was the liveness gate’s negative-secs handling above.
Live evidence (from SigNoz, 2026-06-17) — historical
nats publish acked=trueforhighest-temperature-in-atlanta-on-june-17(16:56 EDT) andhighest-temperature-in-chicago-on-june-17(17:27 CDT) — first real signals, on the oldweather.signalsstream.- Pre-DNS-fix (6-17 AM) one publish timed out 3× (
NATS publish ack failed: timed out); clean since @deploy switchedNATS_URLtohost.docker.internal.
Two weather lanes
- US (
source = weather, THIS repopmv2-weather-us-algo) — NYC/Chicago/Miami/Atlanta, the validated-GO cohort. - AS / Asian (
source = weather_as, a SEPARATE repo/sessionpmv2-weather-as-algo, ~$10–30 notional) — see pmv2-reorg-and-weather-as-2026-06-22.
They are deliberately separate repos/lanes (not a shared engine). They share the contract (pmv2-contracts) and the executor (PM), nothing else.
Team / ownership
- @deploy / @positionmanager owns Position Manager (the executor) + provisioned NATS (on
polymarket-infra, loopback/tailnet, NKey, GH-secret seeds) + runs thewx-signaldaemon. Thei64::MINgate fix is on PM’s side (43023ba). - weather (this project) owns
pmv2-weather-us-algo: thewx-signalproducer (pure signal, no CLOB secrets), the v2 contract sign-off, and the strategy/backtest. - weather-AS owns
pmv2-weather-as-algo(separate session). - cohort / crypto own their producer repos.
Open items / next steps
Next steps (in order)
- Complete the dry rehearsal (capital gate). Needs: redeploy PM
43023ba+ a FRESH US afternoon lock (~16:00–18:00 ET) → the 🧪 DRY-RUN alert fires → cross-check market/bucket vs the lock → capital gate cleared. (The gate-skip blocker is fixed; this is the remaining step.)- Build the wx-signal v2 producer adaptation (unblocked now that
pmv2-contractsis published) — emit the v2 READY entry-order topmv2.order.weather.entry, add the sizing module, vendorpmv2-contracts. See the PENDING section above.- Then the live arm (operator flips
weathersource modeoff → dry → liveinpmv2_autotrade_sources).- Publish-retry gap (carried over) — publish is best-effort, gated on the Supabase insert; an ack-timeout leaves the signal in Supabase but not on the stream, no retry. Close via consumer-side Supabase reconciliation or publisher re-publish-until-acked. Low-risk since the DNS fix.
Key refs
- Architecture: pmv2-rearchitecture — the multi-service split + the trade wire-contract v2 (the
limitvsderivedarms, subjects,pmv2-contracts, producer/executor/notify) - Strategy: weather-strategy-validated-plan, copytrade-top-weather-traders, weather-lag-distribution-2026-06-19, intraday-drift-study-naive-no-go
- Market facts: polymarket-weather-market-structure, weather-bet-audit-findings
- Infra: wx-signal-nats-nkey-auth, weather-bet-supabase-migration
- Repo:
github.com/wowjeeez/pmv2-weather-us-algo(PRIVATE) · local/Users/levander/coding/pmv2/us_weather_algo/· branchfeat/wx-signal-engine@a2fa5ee· reports inresearch/reports/· v1 envelope (historical)docs/signal-schema.md - Related: polymarket-fetch, weather-bet