From b2dd758977aa3a4fa8b6c9534f9e12b9d18ef16f Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Sat, 23 May 2026 22:59:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=A9=E5=B1=95=E6=A8=A1=E5=9E=8B=E5=8C=BA?= =?UTF-8?q?=E9=97=B4=E7=AB=AF=E7=82=B9=E8=87=B3=E9=A6=96=E5=B0=94=E5=92=8C?= =?UTF-8?q?=E9=87=9C=E5=B1=B1=EF=BC=8C=E5=B9=B6=E5=81=9A=E5=89=8D=E7=AB=AF?= =?UTF-8?q?=E5=B0=8F=E5=B9=85=E6=B8=85=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - GET /api/cities/model-range 新增 seoul/busan,总计 9 城 - 移除未使用的 react-leaflet 依赖 - 提取 chart Tooltip contentStyle 为共享常量 CHART_TOOLTIP_STYLE,消除 6 个文件中 15 处重复内联样式 Tested: npx tsc --noEmit pass Confidence: high --- docs/deep-research-report.md | 40 ++++++++++--------- .../ops/analytics/AnalyticsPageClient.tsx | 3 +- .../ops/health/HealthPageClient.tsx | 3 +- .../ops/memberships/MembershipsPageClient.tsx | 5 ++- .../ops/overview/OverviewPageClient.tsx | 13 +++--- .../ops/payments/PaymentsPageClient.tsx | 3 +- .../ops/training/TrainingPageClient.tsx | 9 +++-- frontend/lib/chart-utils.ts | 8 ++++ frontend/package-lock.json | 26 +----------- frontend/package.json | 1 - web/routers/city.py | 6 ++- 11 files changed, 58 insertions(+), 59 deletions(-) diff --git a/docs/deep-research-report.md b/docs/deep-research-report.md index 5a93d51a..0f4bbc37 100644 --- a/docs/deep-research-report.md +++ b/docs/deep-research-report.md @@ -2,7 +2,9 @@ ## 执行摘要 -PolyWeather(仓库:`yangyuan-zhen/PolyWeather`)定位为**面向温度类结算预测市场(如 Polymarket 的温度结算合约)**的“生产级气象情报系统”,核心在于把多源天气观测/预报转化为**结算导向的概率桶(μ + bucket distribution)**,并进一步映射到市场报价完成**错价扫描**;同时提供 Web 仪表盘与 Telegram Bot 两套交互入口,并包含 Polygon 链上 USDC/USDC.e 支付、自动补单与订阅/积分体系。项目 README 现明确仓库代码采用 `AGPL-3.0-only`,同时将品牌、商标、生产私有数据与运营阈值保留在代码许可证之外。 +PolyWeather(仓库:`yangyuan-zhen/PolyWeather`)定位为**面向温度类结算预测市场(如 Polymarket 的温度结算合约)**的”生产级气象情报系统”,核心在于把多源天气观测/预报转化为**结算导向的概率桶(μ + bucket distribution)**;同时提供 Web 仪表盘与 Telegram Bot 两套交互入口,并包含 Polygon 链上 USDC/USDC.e 支付、自动补单与订阅/积分体系。项目 README 现明确仓库代码采用 `AGPL-3.0-only`,同时将品牌、商标、生产私有数据与运营阈值保留在代码许可证之外。 + +> **2026-05-23 更新(v1.7.0)**:Polymarket 价格拉取与 UI 层(MarketDecisionLine)已删除,`market_scan` 当前返回空;LGBM 已完全移除,概率引擎仅保留 legacy 高斯 + EMOS/CRPS;Groq、Meteoblue、NMC、pogodaiklimat 数据源和 prewarm 预热系统已移除。 ## 项目概览 PolyWeather 的目标与范围在 README/README_ZH 中定义得较清楚:为温度结算市场提供气象情报(多源采集→融合→概率→对照市场报价),并提供“官方看板(Vercel 前端)+ VPS 后端 + Telegram Bot”。 @@ -12,7 +14,7 @@ PolyWeather 的目标与范围在 README/README_ZH 中定义得较清楚:为 DEB(Dynamic Error Balancing)基于过去 N 天模型误差(MAE)倒数加权,输出融合预报;运行态仍维护近 14 天 `daily_records` 缓存做当前对账,但长期监督真值与训练特征已经迁到 SQLite 永久表中,并支持基于 WU(Weather Underground 口径)四舍五入的结算命中评估。 趋势/概率引擎在 `trend_engine.py` 中实现:综合“集合预报区间→σ/μ→高温窗口→死盘判定→温度桶概率分布→边界提示”等,用于 bot 展示与 web 结构化数据输出。 **城市决策层(Scan Terminal / AI 机场报文解读)**:地图点击城市后加入城市决策卡,前端拉取 full detail、多模型区间、最新 METAR,并通过 `/api/scan/terminal/ai-city/stream` 生成城市级 AI 解读。该解读由 `final_judgment`、`metar_read`、`reasoning`、`model_cluster_note`、`risks` 与原始 METAR 证据组成;最高温中枢优先使用 AI `predicted_max`,再回退到 DEB、多模型中心、日内 pace 或当前实测。 -**市场层(Polymarket 行情对照)**:只读模式从 Gamma API 发现市场、从 CLOB(`py-clob-client` 或 REST 回退)读取价格/盘口,并用完整 `all_buckets` 对目标温度桶做 exact/range/“or higher”/“or lower” 严格匹配,计算“模型-市场差”(模型概率 − 市场隐含概率)生成信号标签。 +**市场层(Polymarket 行情对照)**:*[v1.7.0 已移除]* 原先从 Gamma API 发现市场、从 CLOB 读取价格/盘口并计算”模型-市场差”,已于 2026-05-23 随 Polymarket 价格拉取层一并删除。当前 `market_scan` 返回空。 **商业化与支付**:订阅(`Pro Monthly 10 USDC`)、积分抵扣、Polygon 链上收款合约(USDC/USDC.e),并提供“事件监听 + 周期确认”的自动补单机制。 **支持的数据集/数据源**:项目不是传统“训练数据集+模型训练”的机器学习仓库;其“数据集”本质是外部实时/预报 API 与站点观测数据。对外部数据的使用需要遵守来源方的访问与速率限制,例如 AviationWeather Data API 明确限制请求频率(含每分钟请求上限/建议降低频率与使用缓存文件)。 **许可证**:仓库根目录 `LICENSE` 当前为 `AGPL-3.0-only`。同时 README 与策略文档明确:品牌、商标、生产私有数据与运营策略不随代码许可证一并授权。 @@ -29,7 +31,7 @@ DEB(Dynamic Error Balancing)基于过去 N 天模型误差(MAE)倒数加 | 运行时组件 | `frontend/` | Next.js 前端(Vercel) | 前端重构报告提到 App Router、Route Handlers(BFF)、缓存策略、支付与账户中心等;Scan Terminal 已新增城市决策卡、AI 机场报文解读、页面内存/localStorage 双层缓存、AI stream 小并发队列与完整市场桶映射。 | | 运行时组件 | `web/app.py` + `web/core.py` + `web/routes.py` + `web/analysis_service.py` + `web/scan_terminal_service.py` | FastAPI 后端 API | 已从单文件入口拆为启动入口、核心上下文、路由层、分析服务层;Scan Terminal 侧提供 `/api/scan/terminal/ai-city/stream`,城市 AI 默认 30s 超时并支持 stream parse failure 的非流式重试。 | | 运行时组件 | `bot_listener.py` + `src/bot/*` | Telegram Bot | 入口 `bot_listener.py` 调 `start_bot()`,并由 `StartupCoordinator` 启动多个后台 loop。 | -| Python 域模块 | `src/data_collection/*` | 天气采集 + 城市注册 + 市场读取 | 采集层已拆为 `weather_sources.py` 编排层 + `open_meteo_cache.py`、`settlement_sources.py`、`metar_sources.py`、`mgm_sources.py`、`amos_station_sources.py`、`jma_amedas_sources.py`、`nws_open_meteo_sources.py`。 | +| Python 域模块 | `src/data_collection/*` | 天气采集 + 城市注册 | 采集层已拆为 `weather_sources.py` 编排层 + `open_meteo_cache.py`、`settlement_sources.py`、`metar_sources.py`、`mgm_sources.py`、`amos_station_sources.py`、`jma_amedas_sources.py`、`nws_open_meteo_sources.py`、`country_networks.py` 等。v1.7.0 已移除 NMC、pogodaiklimat、Meteoblue 数据源。 | | Python 域模块 | `src/analysis/*` | DEB/趋势/概率/结算口径 | `deb_algorithm.py`、`trend_engine.py`、`settlement_rounding.py`。 | | Python 域模块 | `src/payments/*` + `contracts/*` | 支付合约 + 事件监听/补单 | Solidity 合约 + Python 侧事件扫描/确认循环 + SQLite 审计事件 + RPC 多节点容灾 + 合约静态检查。 | | Python 域模块 | `src/auth/*`、`docs/SUPABASE_SETUP_ZH.md`、`scripts/supabase/schema.sql` | Supabase 鉴权/订阅/积分 | 使用 `/auth/v1/user` 校验 JWT、`/rest/v1/subscriptions` 查订阅(服务端角色 key 必须保密)。 | @@ -68,8 +70,6 @@ JSON[Legacy JSON files
migration/export/explicit fallback only] NWS[api.weather.gov] HKO[data.weather.gov.hk] CWA[opendata.cwa.gov.tw] - PM_G[Polymarket Gamma API] - PM_C[Polymarket CLOB API] SB[Supabase Auth/REST] RPC[Polygon RPC] end @@ -96,8 +96,6 @@ JSON[Legacy JSON files
migration/export/explicit fallback only] WX --> HKO WX --> CWA - FAST --> PM_G - FAST --> PM_C FAST --> LLM FAST --> SB @@ -161,13 +159,15 @@ Web/Telegram 请求 → FastAPI 调用采集器抓取/复用缓存 → 分析引 **CI 已建立,但组织级质量门禁未必完全收口**:CI 现已覆盖 Python、前端与 Docker build。当前问题不再是“缺 CI”,而是是否把这些 status check 绑定到 `main` 保护策略,以及是否逐步引入更严格的 pre-merge 审查。 **运行态状态/缓存与核心离线链路的 SQLite 收口已完成**:`daily_records`、`telegram_alert_state`、`probability_training_snapshots`、`open_meteo` 缓存已经支持并在生产中主读 SQLite,迁移/校验脚本可用;进一步地,在临时移除 `data/*.json` / `data/*.jsonl` 后,训练集导出、概率拟合、评估报告、shadow report 和关键 backfill 脚本已验证仍可运行。当前 legacy 文件路径主要是显式回退入口,而不再是默认主输入。 **第三方服务合规与稳定性风险**: -项目强依赖外部 API(Open-Meteo、AviationWeather、global.amo.go.kr AMOS、NWS、HKO、CWA、Polymarket、Supabase)以及城市 AI provider(OpenAI-compatible stream,当前临时 MiMo)。其中 AviationWeather Data API 有明确速率限制;Polymarket 官方说明 Gamma/Data/CLOB 三套 API 分属不同域,CLOB 交易端点需鉴权且策略可能变化;Supabase 明确强调 `service_role`/secret keys 绝不可暴露。若缺乏集中治理(重试/退避/熔断/降级/配额监控/密钥轮换),稳定性与合规不可控。城市 AI 解读已经通过前端 2 并发队列、30s timeout、stream parse retry 与缓存 key 稳定化降低第三/第四城市失败概率,但仍需持续记录 stream duration、cache hit、retry、degraded 与 queue depth。 +项目强依赖外部 API(Open-Meteo、AviationWeather、global.amo.go.kr AMOS、NWS、HKO、CWA、Supabase)以及城市 AI provider(OpenAI-compatible stream,当前使用 MiMo)。其中 AviationWeather Data API 有明确速率限制;Supabase 明确强调 `service_role`/secret keys 绝不可暴露。若缺乏集中治理(重试/退避/熔断/降级/配额监控/密钥轮换),稳定性与合规不可控。城市 AI 解读已经通过前端 2 并发队列、30s timeout、stream parse retry 与缓存 key 稳定化降低第三/第四城市失败概率,但仍需持续记录 stream duration、cache hit、retry、degraded 与 queue depth。 + +> **v1.7.0 更新**:Polymarket(Gamma/CLOB)API 依赖已随市场价格拉取层一并移除。 **许可证/商业使用的潜在冲突点**:仓库自身现为 `AGPL-3.0-only`,但如果未来尝试引入外部神经天气模型,仍需单独核验第三方代码与权重的商用条件:GraphCast 仓库代码 Apache-2.0,但权重使用 CC BY-NC-SA 4.0(非商业),Pangu-Weather 权重同样 BY-NC-SA 且明确禁止商业用途;不加区分地把这些模型用于付费产品会留下法律风险。 ## 对标分析 为满足“至少 3 个相似开源项目或近期论文”对标,本报告选择三类代表: 1)**AI 气象预报模型**(GraphCast / FourCastNet / Pangu-Weather):用于评估“若 PolyWeather 未来扩展到更强预测能力”的技术与许可边界; -3)**预测市场 API 客户端生态**(Polymarket/py-clob-client、aiopolymarket):用于评估市场层的工程选型。 +3)**预测市场 API 客户端生态**(Polymarket/py-clob-client、aiopolymarket):*[v1.7.0 后已不适用]* 市场价格拉取层已移除,此对标仅作历史参考。 ### 关键对比表 | 项目/论文 | 解决的问题 | 输出形态 | 性能/效果(公开描述) | 易用性与依赖 | 许可证要点 | @@ -175,18 +175,18 @@ Web/Telegram 请求 → FastAPI 调用采集器抓取/复用缓存 → 分析引 | **GraphCast**(google-deepmind/graphcast) | 10 天全球中期预报(ML 替代/增强 NWP) | 模型代码+权重+notebooks | 论文与介绍提到在大量指标上优于主流确定性系统;仓库提供预训练权重与示例数据入口,并提示 ERA5/HRES 数据条款需另行遵守。 | 完整训练需 ERA5 等;更适合科研/平台级推理,不是产品级 BFF。 | 代码 Apache-2.0;权重 CC BY-NC-SA 4.0(商业限制)。 | | **FourCastNet**(NVlabs/FourCastNet) | 高分辨率 data-driven 全球预报(AFNO/ViT) | 模型训练/推理代码+数据/权重链接 | README 描述:0.25° 分辨率、周尺度推理非常快,并可做大规模集合;适合平台型预报。 | 训练/数据依赖大(ERA5 子集 TB 级);工程集成成本高。 | BSD 3-Clause(代码)。 | | **Pangu-Weather**(198808xc/Pangu-Weather + Nature 论文) | 3D Transformer 架构的中期全球预报 | ONNX 推理代码+预训练模型 | Nature 论文称在 reanalysis 上对比 IFS 有更强确定性预报表现,并强调速度优势;仓库提供 ONNX 推理与 lite 版训练说明。 | 模型文件大(多份 ~GB 级),训练资源需求高;更适合科研推理或内部平台。 | 权重 BY-NC-SA 4.0、明确禁止商业用途。 | -| **Polymarket/py-clob-client** | Polymarket CLOB 读写 SDK | Python SDK | 官方 SDK,支持 read-only 与交易接口;协议与端点在官方文档中给出。 | 易用,适合增强 PolyWeather 市场层。 | MIT。 | -| **aiopolymarket** | Polymarket APIs 的 async 客户端 | Python async 客户端 | 强调类型安全(Pydantic)、自动分页、重试与 backoff,适合高并发与健壮性诉求。 | 适合替换/补强当前同步 requests 与自定义缓存。 | 以仓库许可为准(此处建议上线前核验)。 | +| **Polymarket/py-clob-client** | Polymarket CLOB 读写 SDK | Python SDK | *[2026-05 起不再使用]* 官方 SDK,支持 read-only 与交易接口。 | 曾用作 PolyWeather 市场层参考。 | MIT。 | +| **aiopolymarket** | Polymarket APIs 的 async 客户端 | Python async 客户端 | *[2026-05 起不再使用]* 类型安全(Pydantic)、自动分页、重试与 backoff。 | 曾用作市场层升级候选。 | 以仓库许可为准。 | **对标结论**:PolyWeather 与这类“全球神经天气模型”不在同一层级:PolyWeather 是“面向结算市场的产品化情报系统”,其价值核心是**将预测转成可交易/可结算的决策信息**。短中期内更高 ROI 的方向不是“自训大模型”,而是把现有“采集+后处理+市场映射”的链路做成**可复现、可观测、可评测、可扩展**的工程平台;在许可合规前提下,再评估引入外部模型推理作为额外信号源。 ## 优先级改进建议 -下表按截至 `2026-05-11` 的真实状态重排优先级。已完成项不再继续列为“待做”,只保留当前仍需推进的事项。 +下表按截至 `2026-05-23` 的真实状态重排优先级。已完成项不再继续列为”待做”,只保留当前仍需推进的事项。 | 优先级 | 改进项 | 预估工作量 | 主要收益 | 主要风险 | 可执行步骤(建议顺序) | | ------ | --------------------------------------------------------------------------------------------------------------------------------- | -------------------: | ------------------------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 中 | **把最小外部监控继续补深**:从“可告警”提升到“可运营” | 3–7 天 | 不再只知道服务坏没坏,还能看资源趋势、来源 SLA 和支付波动 | 指标过多会带来维护噪音 | 1) 增加节点 CPU/内存/磁盘 → 2) 增加 SQLite/支付体积与事件趋势 → 3) 把 HTTP/来源指标细分到城市/来源维度 → 4) 增加日报或异常摘要 | | 中 | **城市决策卡 AI 解读可观测性与回放测试** | 3–5 天 | 降低第三/第四/第五城市 AI 解读失败,验证缓存与队列是否真正生效 | 外部 AI stream 仍可能超时或输出截断,若无指标很难复盘 | 1) 记录 city-ai stream status/duration/retry/degraded/cache-hit/queue-depth → 2) 增加固定 METAR + detail + all_buckets fixture → 3) 回归断言 bucket 匹配、模型-市场差、温度单位与缓存 key → 4) 将生产 env 建议同步进部署文档 | -| 中 | **市场层升级为 async + 类型安全**:引入 `aiopolymarket` 或在现有层加重试/backoff/连接池 | 4–7 天 | 行情层更稳,减少短时网络抖动;更易扩展更多市场/分页 | 依赖升级带来的行为差异 | 1) 把 requests.Session 替换为 aiohttp/httpx → 2) 在 Gamma/CLOB 调用侧实现指数退避 → 3) 引入 typed models,减少解析失败 | +| - | ~~市场层升级为 async + 类型安全~~ | N/A | *[v1.7.0 已移除]* 市场价格拉取层已删除,此改进项不再适用 | - | - | | 中 | **支付合约从“最小可用”升级到“更强合约防护”** | 1–2 周 | 在已完成的链下审计与容灾之上,进一步收紧链上授权边界 | 合约升级需要重新部署、迁移配置并再次验证 | 1) 维持现有事件重放、SQLite 审计、多 RPC fallback → 2) 升级合约到 SafeERC20 + Pausable → 3) 评估链上 plan/amount/token 绑定或 EIP-712 签名校验 → 4) 迁移后更新 PolygonScan 验证与支付审计文档 | | 中 | **将 CI 与分支保护/发布流程真正绑定** | 1–3 天 | 让现有 CI 从“存在”变成“强制门禁” | 历史分支/热修流程可能受影响 | 1) GitHub `main` 开启 required checks → 2) 把 release/tag 流程绑定 CI → 3) 明确热修例外流程 | | 低 | **引入外部神经天气模型作为附加信号**(GraphCast/FourCastNet/Pangu-Weather 等) | 2–6 周(取决于范围) | 可能提升极端/中期预测能力与差异化 | **商业许可限制**(多为 CC BY-NC-SA/禁止商业)与算力成本 | 1) 先做合规评审(权重许可/数据条款)→ 2) 仅在研究/非商业环境评估 → 3) 若要商用,优先选择可商用权重或自研/购买授权 | @@ -194,7 +194,7 @@ Web/Telegram 请求 → FastAPI 调用采集器抓取/复用缓存 → 分析引 ### 文档、测试与贡献流程的具体补强建议(落到仓库层面) 1)**文档体系**:保留现有中文 API/TechDebt 文档的同时,增加三份“高价值”文档: -(a)《运行与配置手册》:按环境(本地/测试/VPS/生产)列必需变量、默认值、敏感等级,并明确城市 AI 推荐配置(`POLYWEATHER_SCAN_CITY_AI_TIMEOUT_SEC=30`、`POLYWEATHER_SCAN_CITY_AI_MAX_TOKENS=900`、`POLYWEATHER_SCAN_CITY_AI_RETRY_ON_STREAM_PARSE_ERROR=true`);(b)《数据源与合规说明》:列出 Open-Meteo、AviationWeather、NWS、HKO、CWA、Polymarket、Supabase 的使用条款要点、速率限制与降级策略(例如 AviationWeather 明确建议降低请求频率并提供 cache 文件)。 (c)《故障排查 Runbook》:429、支付 pending、市场扫描 miss、城市 AI stream timeout/JSON 截断、前端缓存异常、温度桶错配等典型故障处理。 +(a)《运行与配置手册》:按环境(本地/测试/VPS/生产)列必需变量、默认值、敏感等级,并明确城市 AI 推荐配置(`POLYWEATHER_SCAN_CITY_AI_TIMEOUT_SEC=30`、`POLYWEATHER_SCAN_CITY_AI_MAX_TOKENS=900`、`POLYWEATHER_SCAN_CITY_AI_RETRY_ON_STREAM_PARSE_ERROR=true`);(b)《数据源与合规说明》:列出 Open-Meteo、AviationWeather、NWS、HKO、CWA、Supabase 的使用条款要点、速率限制与降级策略(例如 AviationWeather 明确建议降低请求频率并提供 cache 文件)。 (c)《故障排查 Runbook》:429、支付 pending、城市 AI stream timeout/JSON 截断、前端缓存异常、温度桶错配等典型故障处理。 2)**测试金字塔**:在现有 `trend_engine` 单测基础上,补齐: (a)天气 provider 的“录制回放”测试(VCR 思路:固定响应→确保解析稳定);(b)市场层的契约测试(Gamma/CLOB schema 变更时提前失败);(c)城市决策卡 fixture 测试(固定 `detail/market_scan/all_buckets/METAR` → 断言 bucket mapping、模型-市场差、温度单位、AI 缓存 key 与排队提示);(d)支付链路的本地链集成测试(Hardhat/Anvil + 事件扫描回放)。这些测试能把“外部依赖漂移”尽量转成可控的回归失败。 3)**贡献工作流**:引入 `CONTRIBUTING.md`(分支策略、PR 模板、变更日志、版本号策略)、`CODEOWNERS`(核心模块审查人)、`SECURITY.md`(漏洞披露与密钥处理),并把静态检查(ruff/eslint)作为 pre-commit + CI 必过项。 @@ -219,21 +219,23 @@ PolyWeather 的评测应围绕“结算场景”而非传统数值天气预报 - 若历史样本足够,DEB 应在“系统性偏差明显”的城市提升 MAE; **算力**:以上评测全部可在 CPU 上完成;数据量按“51 城市 × 180 天”级别,pandas/duckdb 即可。若引入更复杂拟合(如分层贝叶斯/分位数回归),也通常不需要 GPU。 -### 错价信号与市场有效性基准 +### 错价信号与市场有效性基准 *[v1.7.0 已暂停]* + +> **2026-05-23 更新**:Polymarket 价格拉取层与市场扫描(`market_scan`)已于 v1.7.0 移除。本节基准评测方案暂不适用,留待未来若重新引入市场数据层时参考。 **数据集** -- 保存每次扫描输出:`date/city/bucket/bucket_label/bucket_direction/model_probability/market_implied/model_market_diff/yes_buy/quote_source/liquidity/matching_reason`,并加上未来 `settled_bucket` 作为标签;Polymarket 市场发现与报价来自 Gamma/CLOB(官方文档说明三套 API:Gamma/Data/CLOB)。 +- 若恢复:保存每次扫描输出:`date/city/bucket/bucket_label/bucket_direction/model_probability/market_implied/model_market_diff/yes_buy/quote_source/liquidity/matching_reason`,并加上未来 `settled_bucket` 作为标签。 **指标** - Signal 覆盖率:能否找到正确 market / bucket; - Edge 稳健性:不同流动性分位的 edge 分布; -- 交易模拟(如需):在考虑滑点/手续费/成交概率下的期望收益(即使项目当前只读,也可以离线评估“若执行”会怎样)。 +- 交易模拟(如需):在考虑滑点/手续费/成交概率下的期望收益。 **基线** - 简单策略:仅用市场中间价(不做模型)作为概率; - 当前策略:模型概率 vs 市场概率 edge 阈值; -- 改进策略:引入“流动性/盘口深度/波动”作为信号置信度(aiopolymarket/py-clob-client 提供更完整的盘口读取能力)。 +- 改进策略:引入”流动性/盘口深度/波动”作为信号置信度。 **算力**:CPU 即可;关键在于数据采样与回放。 ## 路线图与风险缓解 @@ -254,6 +256,8 @@ PolyWeather 的评测应围绕“结算场景”而非传统数值天气预报 **代码公开与生产私有资产边界导致的“公开仓库与生产行为不一致”**:README 明确品牌、商标、生产私有数据与运营阈值不在代码许可证授权范围内。缓解:把“公开核心”的可复现与评测做扎实(接口/数据 schema/测试/评测),私有策略只作为可插拔 policy layer 接入。 ## 参考链接 +> **v1.7.0 注**:以下 Polymarket 相关链接已不再被项目使用,保留作为历史参考。 + - PolyWeather 仓库(本次评估对象):https://github.com/yangyuan-zhen/PolyWeather - Polymarket API 文档(Gamma/Data/CLOB):https://docs.polymarket.com/api-reference - AviationWeather Data API(METAR 等):https://aviationweather.gov/data/api/ diff --git a/frontend/components/ops/analytics/AnalyticsPageClient.tsx b/frontend/components/ops/analytics/AnalyticsPageClient.tsx index 40df4e86..1cb07267 100644 --- a/frontend/components/ops/analytics/AnalyticsPageClient.tsx +++ b/frontend/components/ops/analytics/AnalyticsPageClient.tsx @@ -5,6 +5,7 @@ import { RefreshCcw } from "lucide-react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { opsApi } from "@/lib/ops-api"; +import { CHART_TOOLTIP_STYLE } from "@/lib/chart-utils"; import { BarChart, Bar, @@ -117,7 +118,7 @@ export function AnalyticsPageClient() { [`${value} 人`, "数量"]} /> diff --git a/frontend/components/ops/health/HealthPageClient.tsx b/frontend/components/ops/health/HealthPageClient.tsx index 87e9c664..52625961 100644 --- a/frontend/components/ops/health/HealthPageClient.tsx +++ b/frontend/components/ops/health/HealthPageClient.tsx @@ -4,6 +4,7 @@ import { useEffect, useState } from "react"; import { RefreshCcw, CheckCircle2, XCircle, AlertTriangle } from "lucide-react"; import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; +import { CHART_TOOLTIP_STYLE } from "@/lib/chart-utils"; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Cell, @@ -109,7 +110,7 @@ export function HealthPageClient() { [`${value} ms`, "延迟"]} /> diff --git a/frontend/components/ops/memberships/MembershipsPageClient.tsx b/frontend/components/ops/memberships/MembershipsPageClient.tsx index 299e8534..bc435993 100644 --- a/frontend/components/ops/memberships/MembershipsPageClient.tsx +++ b/frontend/components/ops/memberships/MembershipsPageClient.tsx @@ -6,6 +6,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { opsApi } from "@/lib/ops-api"; import type { MembershipEntry } from "@/types/ops"; +import { CHART_TOOLTIP_STYLE } from "@/lib/chart-utils"; import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, Legend, Area, AreaChart, @@ -170,7 +171,7 @@ export function MembershipsPageClient() { - + @@ -184,7 +185,7 @@ export function MembershipsPageClient() { - + diff --git a/frontend/components/ops/overview/OverviewPageClient.tsx b/frontend/components/ops/overview/OverviewPageClient.tsx index 391827d4..ea160679 100644 --- a/frontend/components/ops/overview/OverviewPageClient.tsx +++ b/frontend/components/ops/overview/OverviewPageClient.tsx @@ -8,6 +8,7 @@ import { Badge } from "@/components/ui/badge"; import { opsApi } from "@/lib/ops-api"; import Link from "next/link"; import type { SystemStatusPayload, MembershipsPayload, MembershipEntry } from "@/types/ops"; +import { CHART_TOOLTIP_STYLE } from "@/lib/chart-utils"; import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, BarChart, Bar, XAxis, YAxis, CartesianGrid, @@ -164,7 +165,7 @@ export function OverviewPageClient() { - + @@ -178,7 +179,7 @@ export function OverviewPageClient() { - + @@ -208,7 +209,7 @@ export function OverviewPageClient() { - + @@ -228,7 +229,7 @@ export function OverviewPageClient() { - + @@ -271,7 +272,7 @@ export function OverviewPageClient() { {memberPie.map((d, i) => ())} - + @@ -317,7 +318,7 @@ export function OverviewPageClient() { {cachePie.map((d, i) => ())} - + diff --git a/frontend/components/ops/payments/PaymentsPageClient.tsx b/frontend/components/ops/payments/PaymentsPageClient.tsx index 95ab9a08..d731abcb 100644 --- a/frontend/components/ops/payments/PaymentsPageClient.tsx +++ b/frontend/components/ops/payments/PaymentsPageClient.tsx @@ -6,6 +6,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { opsApi } from "@/lib/ops-api"; import type { PaymentRuntimePayload, PaymentIncident, PaymentRecord } from "@/types/ops"; +import { CHART_TOOLTIP_STYLE } from "@/lib/chart-utils"; import { PieChart, Pie, Cell, ResponsiveContainer, Tooltip, } from "recharts"; @@ -119,7 +120,7 @@ export function PaymentsPageClient() { ))} - + diff --git a/frontend/components/ops/training/TrainingPageClient.tsx b/frontend/components/ops/training/TrainingPageClient.tsx index 8771c03c..d8ad981b 100644 --- a/frontend/components/ops/training/TrainingPageClient.tsx +++ b/frontend/components/ops/training/TrainingPageClient.tsx @@ -7,6 +7,7 @@ import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { opsApi } from "@/lib/ops-api"; import type { SystemStatusPayload } from "@/types/ops"; +import { CHART_TOOLTIP_STYLE } from "@/lib/chart-utils"; import Link from "next/link"; import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, @@ -233,7 +234,7 @@ export function TrainingPageClient() { [`${Number(value).toFixed(1)}%`, "命中率"]} /> @@ -258,7 +259,7 @@ export function TrainingPageClient() { [`${Number(value).toFixed(1)}°`, "MAE"]} /> @@ -288,7 +289,7 @@ export function TrainingPageClient() { [Number(value).toFixed(4), "Brier Score"]} /> @@ -313,7 +314,7 @@ export function TrainingPageClient() { [`${Number(value).toFixed(1)}%`, "命中率"]} /> diff --git a/frontend/lib/chart-utils.ts b/frontend/lib/chart-utils.ts index 7af32310..5ca9a518 100644 --- a/frontend/lib/chart-utils.ts +++ b/frontend/lib/chart-utils.ts @@ -664,3 +664,11 @@ export function getTemperatureChartData( yTickStep, }; } + +export const CHART_TOOLTIP_STYLE: React.CSSProperties = { + background: "#1e293b", + border: "1px solid rgba(255,255,255,0.1)", + borderRadius: 8, + color: "#e2e8f0", + fontSize: 12, +}; diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b1e18365..ebec67b3 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "polyweather-frontend", - "version": "1.5.5", + "version": "1.7.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "polyweather-frontend", - "version": "1.5.5", + "version": "1.7.0", "dependencies": { "@radix-ui/react-slot": "^1.1.2", "@supabase/ssr": "^0.5.2", @@ -20,7 +20,6 @@ "next": "^15.3.2", "react": "^19.0.0", "react-dom": "^19.0.0", - "react-leaflet": "^5.0.0", "recharts": "^3.8.1", "tailwind-merge": "^3.3.0" }, @@ -362,15 +361,6 @@ } } }, - "node_modules/@react-leaflet/core": { - "version": "3.0.0", - "license": "Hippocratic-2.1", - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" - } - }, "node_modules/@reduxjs/toolkit": { "version": "2.12.0", "resolved": "https://registry.npmmirror.com/@reduxjs/toolkit/-/toolkit-2.12.0.tgz", @@ -3302,18 +3292,6 @@ "license": "MIT", "peer": true }, - "node_modules/react-leaflet": { - "version": "5.0.0", - "license": "Hippocratic-2.1", - "dependencies": { - "@react-leaflet/core": "^3.0.0" - }, - "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^19.0.0", - "react-dom": "^19.0.0" - } - }, "node_modules/react-redux": { "version": "9.3.0", "resolved": "https://registry.npmmirror.com/react-redux/-/react-redux-9.3.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index f6d79f44..411f1e52 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -23,7 +23,6 @@ "next": "^15.3.2", "react": "^19.0.0", "react-dom": "^19.0.0", - "react-leaflet": "^5.0.0", "recharts": "^3.8.1", "tailwind-merge": "^3.3.0" }, diff --git a/web/routers/city.py b/web/routers/city.py index d7d5115f..3104d3e9 100644 --- a/web/routers/city.py +++ b/web/routers/city.py @@ -22,6 +22,8 @@ _MODEL_RANGE_CITIES: List[str] = [ "chongqing", "qingdao", "wuhan", + "seoul", + "busan", ] _MODEL_RANGE_NAMES: Dict[str, str] = { @@ -32,6 +34,8 @@ _MODEL_RANGE_NAMES: Dict[str, str] = { "chongqing": "重庆 (ZUCK)", "qingdao": "青岛 (ZSQD)", "wuhan": "武汉 (ZHHH)", + "seoul": "首尔 (RKSI)", + "busan": "釜山 (RKPK)", } @@ -45,7 +49,7 @@ async def cities_model_range( request: Request, force_refresh: bool = Query(False), ): - """Return DEB prediction and model range for monitored Chinese cities.""" + """Return DEB prediction and model range for monitored cities (CN + KR).""" from web.app import _analyze rows: List[Dict[str, Any]] = []