UPDATE 2026-06-22 — this gate runs in the
weather_aslane (own repo, pmv2 reorg)This is the convergence gate (
tradeable_10, threshold 0.68) the Asian-weather (weather_as) producer screens with: sourceweather_as, subjectpmv2.order.weather_as.entry, in the PRIVATE repopmv2-weather-as-algoat/coding/pmv2/as_weather_algo(committede9415dc) — loaded there viagate/predict.py+gate/gate_model.pkl. The research record stays in the renamed US repopmv2-weather-us-algoat/coding/pmv2/us_weather_algo, so theresearch/gate/...paths below resolve under/coding/pmv2/us_weather_algo/. Important downstream: the gate’s “convergence, not win” semantics was re-scored on a true WIN label in weather-gate-winlabel-2026-06-19 — the EV collapses ~+0.14/ and the gate loses to a per-city win-rate lookup, so treat its scores as a research artifact, not a calibrated live probability. Full reorg + current state: pmv2-reorg-and-weather-as-2026-06-22.
The implementable replacement for the non-implementable “observed-lag” gate flagged as an open item by weather-lag-distribution-2026-06-19. A calibrated binary classifier (logistic + GBT) predicts P(tradeable) from entry-time-only features — no look-ahead. Verdict: good enough to gate on now; METAR-physics phase-2 deferred until the live rehearsal proves the lean gate’s economics insufficient. Full report: research/reports/weather-exante-gate-2026-06-19.md.
This is the SELECTION layer only — the economics are still gated downstream
A positive gate verdict means an entry is worth routing into the pipeline; it does not assert the trade is profitable. Net-of-cost recovery (taker fee + slippage vs. the ~2c entry premium, see weather-lag-distribution-2026-06-19) and the live dry rehearsal still gate the economics. The gate narrows the funnel; it does not close it.
For Agents
Five load-bearing facts:
- What it is: a calibrated classifier for
tradeable_10=converged@180 AND reprice_lag_min > 10min, from 9 entry-time-only features. The ex-ante, implementable answer to the “gate must be ex-ante, never observed lag” requirement from weather-lag-distribution-2026-06-19.- Skill (verified, no leakage, strict temporal split): GBT OOS AUC 0.795 (logistic 0.743), train→OOS gap 0.067, Brier 0.161, well-calibrated to ~0.75. Beats a per-city base-rate baseline (0.795 vs 0.611) → genuinely more than a city-picker.
- The real signal is
local_hour(permutation AUC-drop 0.14, dominant): tradeable rate ~8% pre-dawn → ~56% at 13–15h local, because temperature extremes resolve in the afternoon. The model nearly formalizes “trade the local-afternoon window”; city + entry-gap are secondary.- Honest caveats: within-city skill is UNEVEN — weak (~0.64 AUC) in the high-volume cities NYC/London/Shanghai, strong (0.85–0.96) elsewhere (some thin-sample). Deployment threshold ~0.68–0.70 admits ~6–9% of candidates at ~0.59–0.65 precision (headline 0.6545 was picked on test = mildly optimistic). Base rate is non-stationary, declining (Q1 0.47→Q4 0.27) → needs rolling refit + live predicted-vs-realized monitoring.
- Verdict: ship the lean gate; defer METAR phase-2 (running-max / peak-passed / headroom) until the rehearsal shows net-of-cost is binding and misses cluster where a path signal would help.
What it is
A binary classifier for tradeable, defined per copy-trade entry as:
tradeable_10 = converged@180 AND reprice_lag_min > 10min
converged@180— the book reprices to ≥ 0.97 within 180 minutes of entry. (In this sample every non-null lag is ≤ 180, soconverged@180 == reprice_lag_min is not null.)reprice_lag_min > 10min— enough lag remains after entry to actually get filled before the move completes. Primary horizon L = 10 min (tradeable_10); L = 5 / 15 also computed.
It answers one ex-ante question: given only what is known at the instant of entry, is this entry likely to be a tradeable late-convergence opportunity? It is the implementable replacement for the “suppress entries where observed lag < p25” rule that weather-lag-distribution-2026-06-19 killed as look-ahead — observed lag is measured forward and cannot be a feature; this model predicts it from entry-time inputs instead.
Features (all entry-time-known, no post-entry information)
city, hi_lo (highest/lowest), unit (degF/degC, deterministic from city), session (night/morning/afternoon/evening), day_of_week, entry_price, book_at_entry (order-book mid at entry), entry_gap (entry_price − book_at_entry), local_hour (local clock hour from entry_ts + city tz).
local_hour is the dominant feature and physically grounded — daily temperature extremes, and thus convergence to 0.97, concentrate in the local afternoon. It is a legitimate entry-time signal, not a proxy for the outcome.
Skill (honest, no leakage)
Split: time-based on entry_ts, last 25% held out as OOS test. 28,291 modeled rows (21,218 train / 7,073 test); 548+ null-city / unmapped rows dropped upstream.
| Metric | Logistic | GBT (selected) |
|---|---|---|
| OOS AUC | 0.743 | 0.795 |
| Brier | 0.177 | 0.161 |
- Global OOS AUC 0.795 (GBT), train→OOS gap only ~0.067; expanding-window folds rise and stabilize (GBT: 0.659 / 0.705 / 0.781 / 0.779) → not materially overfit.
- Calibration is monotone and usable up to ~0.75, then runs slightly hot in the sparse high-confidence bins. Predicted → realized tradeable-rate: 0.04→0.03, 0.15→0.13, 0.25→0.18, 0.35→0.26, 0.45→0.35, 0.55→0.46, 0.65→0.53, 0.75→0.65, 0.83→0.69 (n=58). Above 0.8 the data is thin (0 obs above 0.9) → confidence reads optimistically there.
- Beats a per-city base-rate baseline decisively: a baseline predicting each city’s historical train tradeable-rate scores OOS AUC 0.611 vs. the model’s 0.795; at matched admit fraction it yields ~0.36 realized tradeable vs. the model’s ~0.59–0.65. Within-city OOS AUC averages 0.80 across 44 eligible cities and is > 0.60 for every one — which a per-city-base-rate model cannot achieve (it is 0.5 within-city by construction). The model is not a disguised city picker.
The real signal: local_hour (trade the local-afternoon window)
Permutation AUC-drop ranks local_hour far above everything else:
| feature | permutation AUC-drop |
|---|---|
local_hour | 0.141 |
entry_gap | 0.038 |
session | 0.037 |
city | 0.033 |
book_at_entry | 0.025 |
entry_price | 0.019 |
hi_lo | 0.010 |
day_of_week | 0.004 |
unit | 0.001 |
Tradeable rate climbs from ~8% pre-dawn to ~56% at 13–15h local — because daily temperature extremes (and thus convergence to 0.97) resolve in the afternoon. The model nearly formalizes an interpretable rule: “trade the local-afternoon window.” City and entry-gap are secondary refinements on top of the clock. (The logistic agrees: session_afternoon is the largest positive coefficient, session_night among the largest negative.) This is the same physics the weather-strategy-validated-plan edge rests on, now learned ex-ante.
Honest caveats
Within-city skill is UNEVEN — weakest exactly where volume is highest
The aggregate (44 cities, mean AUC 0.80, all > 0.60) is robust, but it is not uniform. The model is weak (~0.64 AUC) in the high-volume cities —
nyc(n=227, 0.636),shanghai(n=275, 0.636),london(n=207, 0.668) — and strong (0.85–0.96) elsewhere, some of it thin-sample. The cities where most candidate flow actually arrives are the ones the gate discriminates worst. Plan around that.
- Thin per-city AUCs are noise individually. The eye-catching highs sit on ~8–12 positives and are high-variance:
denver(n=56, 0.96),los-angeles(n=59, 0.95),toronto(n=64, 0.94),buenos-aires(n=54, 0.92),tel-aviv(n=94, 0.93). Treat n < 100 as indicative only. The well-powered cities carry the real signal:paris(n=299, 0.86),seoul(n=523, 0.80),hong-kong(n=552, 0.75),beijing(n=368, 0.72). - Operating threshold ~0.68–0.70, not the headline 0.6545. The saved model bundles threshold 0.68 (targets ~0.65 precision);
gate_metrics.jsonreports precision 0.6545 at 8.5% admit — but that threshold was picked on the test set, so it is mildly optimistic. Re-picking on a train-internal validation carve-out (~0.70–0.71) and applying to the untouched test gives realized precision ~0.59–0.65 at ~6–8% admit (2.2–2.4× over the 0.269 test base rate). Plan with the conservative ~0.59–0.65 precision number; report test precision only as held-out confirmation; pick deployment thresholds on a validation split going forward. - Non-stationary, declining base rate.
tradeable_10falls monotonically byentry_tsquartile: Q1 0.467 → Q2 0.403 → Q3 0.367 → Q4 0.269 (train base 0.412 vs. test base 0.269). Two consequences: (1) OOS skill is measured on the hardest, lowest-base-rate quartile, so the reported lift is conservative, not inflated; (2) any fixed threshold and the reliability table will drift in production → refit on a rolling window and monitor live predicted-vs-realized tradeable-rate for drift. - Lean features only. No weather-path features (running-max / peak-passed / headroom) — the gate decides on clock, city, and price/book at entry alone.
time_to_resolution_hrsomitted. Many slugs lack a parseable year (e.g.highest-temperature-in-london-on-january-29) and ~4k rows are monthlytemperature-increasemarkets with no daily resolution → a clean derivation was not feasible. The time split uses cleanentry_tsinstead of fragile slug-date parsing. A genuine entry-time time-to-resolution feature would likely add signal if the slug-date parse can be made reliable.- One historical regime. The temporal OOS split is honest, but the whole sample is one historical copy-trade regime. Overfit-to-regime risk is real → the live rehearsal is the real test, not the held-out AUC.
Leakage / split summary
No post-entry field (reprice_lag_min, converged, fair_gap, snap_dt_s) is used as a feature — all 9 features are entry-time-known. fair_gap (on the “forbidden” list) was verified mathematically identical to feature entry_gap (entry_price − book, to ≤ 5e-7 across all 28,291 rows) — it is mislabeled, not leakage, and enters the model only via the label. Split is temporal and clean (entry_ts-sorted, last 25% OOS). No code fix was required; the saved model and predict.py were verified consistent and left unchanged. The only substantive open risk is regime non-stationarity, handled by caveat + rolling-refit recommendation.
Verdict — ship the lean gate; defer METAR phase-2
Good enough to gate on now. Reasoning from measured skill:
- OOS AUC 0.795 with a 0.067 train→OOS gap and stable expanding folds is solid, well-generalizing discrimination — not marginal or overfit.
- It clears the two hard bars: beats the per-city base-rate baseline decisively (0.795 vs. 0.611; within-city 0.80, all 44 cities > 0.60), and does so on the lowest-base-rate (hardest) period, so the lift is conservative.
- At the operating point it admits ~6–9% of candidates at ~0.59–0.65 precision — a usable, materially enriched funnel for the downstream economic gate.
- The dominant signal (
local_hour) is physically grounded and cheaply available at entry, so the lean gate is robust and operationally simple.
Phase-2 METAR features (running-max, peak-passed, headroom-to-extreme) are NOT yet warranted. They are physically the right next signal and would most plausibly help the cases the lean gate misses (mid-session entries where the temperature path, not the clock, decides convergence). But they add data-dependency, latency, and failure modes. The disciplined sequence: ship the lean gate → run the live rehearsal → if net-of-cost recovery is the binding constraint AND the misses cluster where a peak-passed signal would resolve them, then build phase-2. Do not pay for METAR complexity before the rehearsal shows the lean gate’s precision/recall is the bottleneck.
How to call the gate
Use research/gate/predict.py (loads gate_model.pkl lazily; needs sklearn/pandas, which research/gate/.venv has):
p = predict.predict_proba(city, hi_lo, entry_ts, entry_price, book_at_entry)
# -> float in [0,1], P(tradeable_10)
ok, p = predict.is_tradeable(city, hi_lo, entry_ts, entry_price, book_at_entry)
# -> (bool, float); uses the bundled threshold (0.68) unless threshold=... is passedcity must be one of the 51 mapped cities (it carries the timezone used to derive local_hour/session/day_of_week); entry_ts is unix seconds; hi_lo is "highest"/"lowest" (None → "unknown"). Verified end-to-end on the saved artifact: GBT pipeline, target tradeable_10, threshold 0.68.
Repo pointers
Source files
- Full report:
research/reports/weather-exante-gate-2026-06-19.md- Artifacts:
research/gate/{gate_model.pkl, predict.py, gate_metrics.json}- Builder:
research/gate/build_gate.py
Related
- pmv2-reorg-and-weather-as-2026-06-22 — the pmv2 reorg + the
weather_aslane that screens with this gate - weather-gate-winlabel-2026-06-19 — the WIN-label re-score of this exact gate: convergence-selection inflated the EV; the model adds ~nothing over the market price
- weather-lag-distribution-2026-06-19 — the unbiased reprice-lag study whose “gate must be ex-ante, never observed lag” open item this model resolves; it sizes the payoff (realized hit ~34.4%, ~2-tick premium entry, net-of-cost the binding economic gate), this selects which entries to route
- weather-top50-decypher-2026-06-19 — the v2 copy-trade decypher that produced the entry population this gate is trained/evaluated on
- weather-bet-live-status — the live
wx-signalengine + dry rehearsal that is the real test of the gate’s economics (net-of-cost recovery), and where the rolling-refit / live-calibration monitoring lives - weather-strategy-validated-plan — the late-settlement / repricing-lag GO plan; the gate’s dominant
local_hoursignal is the ex-ante formalization of that plan’s afternoon-peak physics - weather-bet — project overview