# weatherbot — Polymarket 每日温度市场纸面交易验证 (Phase 1)

用多模型气象 ensemble 预报计算 Polymarket 每日最高/最低温市场各 bucket 的真实概率，
与盘口价格对比，**只做纸面交易**（不下真单、不涉及私钥），用于验证扣除点差后是否存在真实 edge。

策略的理论依据（ensemble 概率、Kelly、favorite-longshot bias、以及已知薄弱环节）
见 [docs/STRATEGY.md](docs/STRATEGY.md)；给 AI 协作会话的项目上下文见 [CLAUDE.md](CLAUDE.md)；
按日期汇总的上线内容与验证边界见 [CHANGELOG.md](CHANGELOG.md)。

## 项目进度

| 阶段 | 状态 | 说明 |
|---|---|---|
| Phase 1 开发 | ✅ 完成（2026-07-06） | 扫描/概率/edge/纸面闭环/看板/备份全链路实测通过 |
| Phase 1 部署 | ✅ 运行中 | AWS 7×24（见 docs/OPS.md），2026-07-06 起持续纸面交易 |
| **Phase 1 验证** | ⏳ **进行中** | 截至 2026-07-20 C3 上线前生产快照：761 单 settled、402 胜、历史 gross P&L +$253.20；allocation v2 前瞻 82 单 / -7.0%。旧订单未保存协议费，不能再作为过门槛口径；从 `fee_accounting_v1_start` 起只看扣动态 taker fee 的净收益。主动前瞻对照仅保留原策略 Hold 与双向趋势 Shadow C |
| Phase 2 偏差校正 | ⏳ corr_gate_v1 前瞻中 | `calibrate` 用 Previous Runs + IEM 实测按站点×D+1/D+2/D+3 拟合，持久化 walk-forward MAE。2026-07-28 起 `model_prob_corr` **已参与开仓门槛与 Kelly 定仓**（`corr_gate_v1_start`），叠加在 raw band 之上；前瞻对照进行中，下一步才是风向等条件化维度 |
| Phase 3 执行研究 | ⏳ maker 只读观测 | 公共 WebSocket L2/成交落库 + 保守队列回放已实现，**无认证、签名或真实下单代码**；真实交易仍未开始 |

## 核心逻辑

1. **市场扫描**：Gamma API 拉取活跃天气事件，按流动性过滤僵尸市场
2. **站点对齐**：从市场 description 解析结算站点码（Wunderground / NOAA / 香港天文台），
   `stations.toml` 提供站点坐标和时区 —— 预报必须对准结算站，这是成败关键
3. **概率计算**：Open-Meteo ensemble API（ECMWF/GEFS/ICON，~120 个成员），按城市本地日
   算每个成员的日极值 → 换算市场单位取整（与结算源一致）→ 落入 bucket 的成员比例即模型概率
4. **Edge 判断**：Gamma 发现市场后，用 CLOB top-of-book 作为可成交价（YES 吃 ask，NO 吃 1−bid），
   再从 CLOB market info 动态读取该 condition 的协议费曲线；扣入场 taker fee 后的
   net edge ≥ 阈值（默认 8%）才开仓，费率查询或曲线不受支持时拒绝下单。
   **corr_gate_v1（2026-07-28 起）**：raw ensemble 概率必须先落在 `[edge_threshold,
   edge_cap)` 的老 band 内，站点去偏后的 `model_prob_corr` 还要再次清过同一阈值——
   两道门是「与」关系，校正只收窄不放宽候选流。无新鲜 bias 行时退化为老规则
5. **仓位**：用含入场费的有效价格重算 fractional Kelly（默认 0.25×），受单笔上限和
   CLOB top-of-book 深度约束；corr_gate_v1 起 Kelly 按去偏概率定仓，这是该改动一半的
   收益来源——raw 的过度自信会被 Kelly 直接放大成最大的仓位；
   每轮先收齐候选，在总敞口竞争时优先前瞻较稳的 raw edge 8-20% NO 组合，再在各层
   内按 edge 排序；同一事件最多 2 个持仓，避免 Gamma 扫描顺序和单事件集中占用额度
6. **结算闭环**：市场 resolve 后自动结算纸面持仓，记录 P&L；每次新预报同时落库，
   为 Phase 2 偏差校正积累 forecast-vs-actual 样本
7. **Shadow C（独立实验）**：只用同源 Gamma YES 中价的 30/60/180 分钟变化判断趋势，
   YES/NO 完全对称；CLOB 只用于价差、深度、费用和真实买卖价门禁。每事件只取最强一档，
   固定含费成本 $5，不占原策略敞口；30/60 分钟同时反转才全平

## 使用

```bash
cargo run --release -- scan          # 列出活跃温度市场
cargo run --release -- edge          # 全市场 edge 报告（只读，不落库）
cargo run --release -- edge --city Shanghai
cargo run --release -- paper         # 常驻纸面交易循环（每 10 分钟一轮）
cargo run --release -- calibrate     # 刷新站点偏差表（Phase 2 影子校正，生产上每日 timer 自动跑）
cargo run --release -- maker-observe --minutes 60 # 公共 L2 + maker 队列纸面回放；0=常驻
cargo run --release -- settle        # 手动结算已 resolve 的市场
cargo run --release -- report        # 查看纸面交易战绩
cargo run --release -- web           # 只读实验控制台（默认 :8080）
python3 tools/replay_exits.py weatherbot.db --sample shadow-b-proxy # 10 分钟快照止盈回放
```

**生产部署**：AWS 上以 systemd 运行交易循环、只读看板、每日固定 lead 校准和
maker 公共行情观测，并每 6 小时把策略主库备份到本仓库 `data` 分支。运维命令、
部署流程、备份恢复见
[docs/OPS.md](docs/OPS.md)。

配置见 `config.toml`（edge 阈值、Kelly 系数、城市白名单等）。日志级别用 `RUST_LOG=debug` 调整。

策略主库 `weatherbot.db`（SQLite）包含 `forecasts` / `snapshots` / `paper_orders` /
`settlements` / `station_bias` / `station_lead_bias` / `calibration_observations` /
`shadow_orders` / `maker_sim_orders` / `bot_meta`。其中 `station_lead_bias` 保存固定提前量拟合结果，
`calibration_observations` 保存逐站点、目标日和 lead 的可审计 forecast-vs-actual 输入。
snapshots 的 `model_prob_corr` 列优先使用同站点同 D+1/D+2/D+3 的偏差，样本不足时
回退站点级 D+1 偏差，再做散布 ×1.2。自 `corr_gate_v1_start`(2026-07-28) 起该列参与
开仓门槛与 Kelly 定仓；`paper_orders.model_prob` / `.edge` 和 `snapshots.edge` 仍存
raw ensemble 值，跨分界点语义不变，**但分界点前后的 ROI 不能合并统计**。
`best_bid_size` / `best_ask_size` 从 allocation v2 起记录 CLOB 顶档数量，供后续执行回放；
`reference_bid` / `reference_ask` 是 C3 专用的同源 Gamma 参考报价，禁止用旧 CLOB 列回填；
10 分钟快照不是完整 L2 队列，不能据此宣称 maker 一定成交。
独立 `weatherbot-maker.db` 的 `clob_l2_events` 保存候选 token 的 top-5 book/trade；高频
price_change 只在内存更新盘口，不逐条落盘，避免写入竞争阻塞主策略库；主库
`maker_sim_orders` 只对最新
策略候选在 token 最优 bid 建 30 分钟虚拟买单。回放不把撤单当作排队减少，只有同价
SELL 成交量吃完可见队列+本单，或成交穿过挂单价，才记整单成交，因此是保守下界。
原始 L2 仅保留 7 天且不进入灾备，`maker_sim_orders` 与策略必需的 `forecasts` 不自动删除。
`bot_meta.shadow_no_08_20_start` 固定影子组合 A 的生产前瞻起点；`report` 同时显示
全历史回放与部署后前瞻结果，防止把事后筛选误当成前瞻表现。
`bot_meta.allocation_v2_start` 同理固定新分配器的前瞻边界。
`bot_meta.fee_accounting_v1_start`、`shadow_b_start`、`prob_score_v1_start`、
`shadow_c_start` 和 `shadow_c4_start` 分别固定费用净收益、历史 Shadow B、概率评分、C3
与 C4 的前瞻边界，均不得事后回拨。Shadow B 已停止新增，仅保留历史行用于结算/审计。
C3 不回填边界前的参考价格，因此新库/生产升级后至少自然预热 180 分钟才可能开仓。
C4 首轮沿用 C3，平仓后连续 30 分钟无任何有效趋势才重新武装，每事件最多两轮；订单独立
存入通用 `experiment_orders`，不改变 C3 的一事件一单口径。

Web 实验控制台以可展开实验矩阵突出当前主动的 Hold、C3 与 C4：展示规则、样本成熟度、
YES/NO 归因、循环事件数、Phase 1 门槛及滚动 24 小时活动；当前持仓可按实验即时筛选。
已停用的 Shadow A/B 不占界面空间，但历史数据仍保留在数据库和 CLI 报告中供审计。

**当日盘规则**：只对次日及以后的市场开仓（当日结果由实时 METAR 主导，预报无优势）；
已持仓的市场进入测量日后仍每轮刷新 CLOB 报价（看板现价保持鲜活），但不再开新仓。
目标日过去仍未 resolve 时标记为 pending resolution，继续计入敞口但停止历史预报请求。

## 已知近似（Phase 1 接受，Phase 2 处理）

- **纸面成交按 taker 价**（吃 ask）模拟；新边界后的订单同时按 CLOB condition 动态费率
  计入 entry/exit fee。边界前历史 P&L 没有费率快照，只能视为 gross，不能用于费用后门槛
- maker observer 的“成交”仍是市场数据回放，不等于真实账户在交易所队列中的成交证明；
  Phase 3 还需 user channel 的真实 `size_matched` 小额校准
- **看板/报告里的 raw 概率与 raw edge 未做偏差校正**，只用于 Phase 1 纸面验证，不能当作已验证真实概率
- **小时级预报**取日极值会系统性低估真实极值 ~0.2-0.4°C —— 属系统偏差，Phase 2 偏差校正吸收
- **香港天文台**结算精度为 0.1°C，当前按整数度近似处理
- 固定 lead 去均值已在影子层运行，但尚未纳入风向/风速、站点状态或真实结算源异常；
  在 walk-forward 指标和 Brier 分数证明改善前不会驱动交易

## 验证 edge 的标准（决定是否进入 Phase 2/3）

跑满 2-4 周后看 `report`：
- `fee-aware forward realized` 结算/提前退出合计 ≥ 100 单，且扣双边实际 taker fee 后
  的净 P&L 显著为正（相对本金+入场费 ≥ 3%）
- 按城市分组看：edge 是否集中在特定城市/时段（如中国城市、模型更新窗口后）
- 若纸面亏损或持平 → 说明 taker 成本下无 edge，Phase 3 必须做 maker 或放弃

## 路线图

- **Phase 2**：继续验证已上线的（站点 × D+1/D+2/D+3）滚动校正，再加入风向等条件化维度
- **Phase 3**（仅当 edge 验证为正）：真实下单 —— maker 限价单管理、EIP-712 签名（用 alloy
  自实现或审计过的 SDK）、风控熔断，参考 Polypulse 的挂单/wind-down 设计
