From 96676e7097e7e504c3decf5c10b54615c2dd88aa Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Thu, 14 May 2026 16:00:55 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=B8=82=E5=9C=BA=E7=9B=91?= =?UTF-8?q?=E6=8E=A7=E6=B8=A9=E5=BA=A6=E6=95=B0=E6=8D=AE=E6=BA=90=EF=BC=9A?= =?UTF-8?q?=E6=8E=A5=E5=85=A5=20NOAA=20MADIS=205=E5=88=86=E9=92=9F?= =?UTF-8?q?=E9=AB=98=E9=A2=91=E6=95=B0=E6=8D=AE=E5=B9=B6=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 首尔/釜山:隐藏大号跑道温度值,改为"跑道温度"标签(跑道表面温度 ≠ 空气温度) - US 城市:MADIS HFMETAR 5分钟小数温度接入 airport_primary,前端优先读取 - 其他城市:整数值不再强制 toFixed(1) 追加虚假 .0 精度 - 后端:weather_sources.py 注入 madis_hfmetar_current 到 results - 后端:country_networks.py 的 _airport_primary_from_raw 新增 MADIS 优先分支 - 文档:更新 AIRPORT_REALTIME_SOURCES.md 新增 11 个 US 城市 - 文档:更新 CLAUDE.md 补充市场监控、高频数据管道、Country Network Provider 架构 Tested: npx tsc --noEmit ✓ ruff check . ✓ --- CLAUDE.md | 12 ++++--- docs/AIRPORT_REALTIME_SOURCES.md | 17 ++++++++++ .../monitoring/MonitorPanel.module.css | 9 ++++++ .../dashboard/monitoring/MonitorPanel.tsx | 17 +++++++--- .../monitoring/monitor-temperature.ts | 4 +++ src/data_collection/country_networks.py | 31 +++++++++++++++++++ src/data_collection/weather_sources.py | 2 ++ 7 files changed, 83 insertions(+), 9 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 6cc63a62..671034a8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -44,6 +44,9 @@ Users (Web / Telegram) → Next.js Frontend (Vercel) → FastAPI /web/app.py - **Shared analysis core** in `src/` is used by both web API and bot - **Scan Terminal**: Real-time city opportunity scanning (`web/scan_terminal_service.py` and `frontend/components/dashboard/scan-terminal/`) - **Dashboard**: Main dashboard with interactive map, city sidebar, detail panels, and probability views +- **Market Monitor** (`MonitorPanel`): Real-time temperature monitoring board for 22 trading cities. Uses a temperature resolution chain (AMOS runway → AMOS → `airport_primary` → `airport_current` → `current`) defined in `frontend/components/dashboard/monitoring/monitor-temperature.ts`. Per-city refresh decisions driven by source-aware freshness (`source-freshness.ts`) instead of uniform `obs_age_min`. Seoul/Busan display runway surface temperature from AMOS; US cities get 5-min MADIS HFMETAR via `airport_primary`; others fall back to METAR. +- **High-Freq Airport Pipeline**: 19 of 22 monitor cities have dedicated realtime sources (AMOS, MADIS, JMA, MGM, FMI, KNMI, AROME). Data flows: `weather_sources.py` (fetch) → `country_networks.py` (`_airport_primary_from_raw`, per-country providers) → API `airport_primary` field. Plain METAR stays in `airport_current`. Documented in `docs/AIRPORT_REALTIME_SOURCES.md`. +- **Country Network Providers**: `country_networks.py` routes per-city to the right provider (Turkey→MGM, Korea→KMA, Japan→JMA, etc.) via `get_country_network_provider()`. Each provider controls `airport_primary_current`, `official_nearby_current`, and `official_network_status`. US cities use the default `GlobalMetarNetworkProvider` but get MADIS overrides injected via `results["madis_hfmetar_current"]`. ## Commands @@ -98,7 +101,7 @@ curl http://127.0.0.1:8000/metrics | Directory | Purpose | |-----------|---------| -| `src/data_collection/` | Weather sources (METAR, TAF, Open-Meteo, JMA, KMA, MGM, NMC, Russia stations, settlement sources), city registry (52 cities), Polymarket readonly layer | +| `src/data_collection/` | Weather sources (METAR, TAF, Open-Meteo, JMA, KMA, MGM, NMC, Russia stations, settlement sources), city registry (52 cities), Polymarket readonly layer. Also: `madis_sources.py` (NOAA 5-min NetCDF), `amos_station_sources.py` (Korean runway sensors), `country_networks.py` (per-country provider routing + `_airport_primary_from_raw`) | | `src/analysis/` | DEB algorithm, trend engine, probability calibration (EMOS/LGBM), market alert engine, settlement rounding | | `src/models/` | LightGBM daily-high model training and feature engineering | | `src/payments/` | Onchain checkout, event listener, confirm loop, contract audit | @@ -106,8 +109,8 @@ curl http://127.0.0.1:8000/metrics | `src/database/` | SQLite-based runtime state, DB manager, daily/truth/training feature repositories | | `web/` | FastAPI app, routes (~65K), analysis service (~130K), scan terminal service (~56K), AI scan modules | | `frontend/app/` | Next.js App Router pages (dashboard, account, auth, docs, ops, probabilities, scan) | -| `frontend/components/dashboard/` | Dashboard UI components (map, sidebar, detail panel, modals, charts, scan terminal). `scan-root-styles.ts` is the CSS Module barrel, combining 22 module roots into one pre-composed className | -| `frontend/lib/` | Shared client logic: types, API client, chart utils, i18n, dashboard utils | +| `frontend/components/dashboard/` | Dashboard UI components (map, sidebar, detail panel, modals, charts, scan terminal). `scan-root-styles.ts` is the CSS Module barrel, combining 22 module roots into one pre-composed className. `monitoring/` subdirectory: `MonitorPanel`, `monitor-temperature.ts` (temp resolution chain), `monitor-refresh-policy.ts`. | +| `frontend/lib/` | Shared client logic: types (`dashboard-types.ts`, including `AirportCurrentConditions`, `CityDetail`), API client, chart utils, i18n, `source-freshness.ts` (per-source freshness with `expected_next_update_at`), dashboard utils | | `frontend/hooks/` | React hooks: dashboard store (global state), Leaflet map, chart helper | | `scripts/` | Operational scripts: probability calibration training, backfills, payment reconciliation, prewarm worker | | `config/` | YAML config (city list, weather settings, logging) | @@ -138,6 +141,7 @@ This repo uses the **Lore Commit Protocol** — structured decision records with - When modifying UI components, update both **dark-mode and light-mode CSS files** in the same edit batch. - **CSS Variables First**: Prefer `var(--color-*)` / `var(--color-signal-*)` tokens over hardcoded hex values. The token system is defined in `globals.css` with light-theme overrides under `html.light`. - **Avoid `!important`**: Only use it for Leaflet map overrides (inline style conflict) and chart canvas sizing. For light-theme overrides, use `html.light .root` prefix for higher specificity. +- **Monitoring CSS note**: `MonitorPanel.module.css` scopes its light-theme overrides to `.scan-terminal.light` (the terminal's built-in toggle), NOT `html.light`. When adding light styles for monitoring components, match this scoping. - **New CSS Modules**: Add the module root class to `scan-root-styles.ts` barrel file instead of importing it separately in `ScanTerminalDashboard.tsx`. ## Quality Gates (MANDATORY) @@ -146,7 +150,7 @@ Before marking any task as complete, you MUST: 1. **Type check** — Run `npx tsc --noEmit` (frontend) or `python -m ruff check .` (backend) on modified files 2. **No Unicode escapes** — Verify that NO `\uXXXX` sequences were introduced; if found, revert and fix -3. **Dual-theme CSS** — For any UI change, confirm BOTH the dark CSS module AND `ScanTerminalLightTheme.module.css` were updated +3. **Dual-theme CSS** — For any UI change, confirm BOTH dark and light styles. Most components need `ScanTerminalLightTheme.module.css` updated; monitoring components (`MonitorPanel.module.css`) contain their own `.scan-terminal.light` blocks inline. 4. **No new hardcoded palette colors** — Use `var(--color-*)` token references instead of `#4DA3FF` / `#E6EDF3` / `#9FB2C7` / `#6B7A90` hex values 5. **Show the diff** — Output `git diff --stat` and test results before declaring success diff --git a/docs/AIRPORT_REALTIME_SOURCES.md b/docs/AIRPORT_REALTIME_SOURCES.md index b21a6340..b23c7c72 100644 --- a/docs/AIRPORT_REALTIME_SOURCES.md +++ b/docs/AIRPORT_REALTIME_SOURCES.md @@ -12,6 +12,23 @@ | 赫尔辛基 | Vantaa | EFHK | FMI (`opendata.fmi.fi`) | 10 分钟 | 机场站点实时温度 | 免费 | | 阿姆斯特丹 | Schiphol | EHAM | KNMI (`dataplatform.knmi.nl`) | 10 分钟 | 机场站点实时温度 | 免费(需注册) | | 巴黎 | Le Bourget | LFPB | AROME HD (`api.open-meteo.com`) | 15 分钟 | 模型预报(非实测) | 免费 | +| 纽约 | LaGuardia | KLGA | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 洛杉矶 | LAX | KLAX | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 芝加哥 | O'Hare | KORD | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 丹佛 | Buckley | KBKF | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 亚特兰大 | Hartsfield | KATL | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 迈阿密 | MIA | KMIA | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 旧金山 | SFO | KSFO | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 休斯顿 | Hobby | KHOU | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 达拉斯 | Love Field | KDAL | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 奥斯汀 | Bergstrom | KAUS | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | +| 西雅图 | SeaTac | KSEA | NOAA MADIS HFMETAR | 5 分钟 | 机场站点实时温度 | 免费 | + +> **NOAA MADIS HFMETAR**: 美国 11 个城市的机场高频实时数据通过 NOAA MADIS 公共档案获取。 +> 数据源为 NetCDF 格式(`madis-data.ncep.noaa.gov/madisPublic1/data/LDAD/hfmetar/`), +> 每 5 分钟全量更新一次,温度保留一位小数。匿名公开访问,无需 API 密钥。 +> 后端通过 `weather_sources.py` 拉取并注入 `airport_primary`,前端市场监控通过 +> `resolveMonitorTemperature` 优先读取 `airport_primary.temp` 获得小数精度温度。 ## 推送机制 diff --git a/frontend/components/dashboard/monitoring/MonitorPanel.module.css b/frontend/components/dashboard/monitoring/MonitorPanel.module.css index 888c6d15..ae5b5d81 100644 --- a/frontend/components/dashboard/monitoring/MonitorPanel.module.css +++ b/frontend/components/dashboard/monitoring/MonitorPanel.module.css @@ -215,6 +215,13 @@ color: var(--color-border-default); } +.root :global(.monitor-temp-runway) { + font-size: 18px; + font-weight: 600; + color: var(--color-text-muted); + letter-spacing: 0.02em; +} + /* ── Stats row ── */ .root :global(.monitor-stats) { font-size: 14px; @@ -421,6 +428,7 @@ .root :global(.scan-terminal.light .monitor-temp-unit), .root :global(.scan-terminal.light .monitor-temp-missing), +.root :global(.scan-terminal.light .monitor-temp-runway), .root :global(.scan-terminal.light .monitor-stat-missing) { color: #94A3B8; } @@ -553,6 +561,7 @@ .root :global(.scan-terminal.light .monitor-temp-unit), .root :global(.scan-terminal.light .monitor-temp-missing), +.root :global(.scan-terminal.light .monitor-temp-runway), .root :global(.scan-terminal.light .monitor-stat-missing) { color: #94A3B8; } diff --git a/frontend/components/dashboard/monitoring/MonitorPanel.tsx b/frontend/components/dashboard/monitoring/MonitorPanel.tsx index d38935b5..22996051 100644 --- a/frontend/components/dashboard/monitoring/MonitorPanel.tsx +++ b/frontend/components/dashboard/monitoring/MonitorPanel.tsx @@ -476,7 +476,10 @@ export default function MonitorPanel({ } const ac = detail.airport_current; - const cur = resolveMonitorTemperature(detail).value; + const tempInfo = resolveMonitorTemperature(detail); + const cur = tempInfo.value; + const curSource = tempInfo.source; + const isRunwayTemp = curSource === "amos_runway_median" || curSource === "amos_runway"; const max = resolveMaxSoFar(detail, key); // HKO cities fall back to current.max_so_far const mtt = ac?.max_temp_time ?? detail.current?.max_temp_time ?? null; const freshnessInfo = getObservationFreshness(detail); @@ -533,12 +536,16 @@ export default function MonitorPanel({ {obs} - {/* Temperature */} + {/* Temperature — runway cities skip the large value (runway surface ≠ air temp) */}