Przeglądaj źródła

docs: update CLAUDE.md and README with undocumented features; fix markets loading skeleton

Horace Zhang 7 miesięcy temu
rodzic
commit
e3535b9728
3 zmienionych plików z 96 dodań i 23 usunięć
  1. 41 8
      CLAUDE.md
  2. 39 3
      README.md
  3. 16 12
      packages/dashboard/src/app/markets/loading.tsx

+ 41 - 8
CLAUDE.md

@@ -4,11 +4,13 @@
 
 Automated weather prediction market trading bot that exploits pricing inefficiencies in Polymarket's daily temperature markets. Compares professional weather forecast model probabilities (GFS/ECMWF/ICON ensembles) against market-implied probabilities and trades the delta.
 
-### Three Strategies
+### Five Strategies
 
 - **TAIL_NO** — Buy NO on overpriced tail buckets (e.g. "56°F or higher") where model prob < 5% but market prices YES > 3¢
 - **LATENCY_ARB** — Trade when new weather model data shifts probabilities >5% but market hasn't repriced yet
 - **PARITY_ARB** — Exploit when sum of all YES prices in an event deviates from 100¢ (pure arbitrage)
+- **OBSERVED_YES** — Buy YES on observed temperature bucket during peak hours (11:00–14:00 local) when market hasn't priced in the known high
+- **OBSERVED_NO** — Buy NO on the bucket below observed daily high (valid all day, highest confidence since temp can only go up)
 
 ## Architecture
 
@@ -17,9 +19,9 @@ TypeScript monorepo using Turborepo + pnpm workspaces.
 ```
 packages/
   core/             — Shared types, utils, Prisma schema, constants
-  weather-engine/   — GFS/ECMWF/ICON forecast fetching via Open-Meteo, ensemble probability calculation
+  weather-engine/   — GFS/ECMWF/ICON forecast fetching via Open-Meteo, HKO forecast for Hong Kong, ensemble probability calculation
   market-engine/    — Polymarket Gamma API scanning, CLOB orderbook reads, authenticated order placement
-  strategy/         — Signal generation (Tail NO, Latency Arb, Parity Arb), risk management, Kelly sizing
+  strategy/         — Signal generation (Tail NO, Latency Arb, Parity Arb, Observed YES/NO), risk management, Kelly sizing, portfolio tracking
   trading-engine/   — Main bot loop, pipeline orchestration, health-check server
   dashboard/        — Next.js App Router dashboard with live market data, signals, manual order placement
 ```
@@ -44,7 +46,7 @@ dashboard (depends on core, reads DB directly)
 - **Database**: PostgreSQL 16 (Prisma ORM) + Redis 7
 - **Dashboard**: Next.js 14 (App Router), Tailwind CSS, next-themes (light/dark), Radix UI primitives
 - **Market APIs**: Polymarket Gamma API (market discovery), CLOB API (orderbook + trading)
-- **Weather APIs**: Open-Meteo (GFS, ECMWF, ICON models)
+- **Weather APIs**: Open-Meteo (GFS, ECMWF, ICON models), Hong Kong Observatory (HKO) API, wttr.in (live temps)
 - **Trading**: @polymarket/clob-client, ethers (wallet signing)
 
 ## Key Commands
@@ -82,13 +84,17 @@ src/app/
   markets/            — Live market data from Polymarket Gamma API + orderbook viewer
   pnl/                — PnL charts and performance metrics
   api/
-    dashboard/        — GET summary stats
-    signals/          — GET signal history
-    markets/          — GET DB market snapshots
+    dashboard/        — GET summary stats (bot status, uptime, PnL, win rate)
+    signals/          — GET signal history with pagination/filtering
+    markets/          — GET DB market snapshots with bucket details
     live-markets/     — GET live Polymarket data via Gamma API
     orderbook/        — GET merged YES/NO orderbook from CLOB
     prices/           — POST fetch latest prices for selected signals
     orders/           — POST place orders (dry run or live)
+    bot-control/      — GET/POST bot status + auto-execute toggle
+    current-temps/    — POST fetch live temps via wttr.in (5-min cache)
+    trade-sync/       — POST sync pending CLOB orders for settlement
+    pnl/              — GET historical P&L data + performance metrics
 ```
 
 ### Dashboard Features
@@ -97,11 +103,16 @@ src/app/
 - **Neg-risk orderbook merging**: YES bids = direct YES bids ∪ (1 − NO asks)
 - **Manual order placement**: Multi-select signals → fetch live prices → choose limit/market → confirm → execute (works in DRY_RUN)
 - **Polymarket deep links**: Direct links to specific market events using city slug mapping
+- **City clocks**: Live local time for all 24 cities with daytime/nighttime indicators + weather history links
+- **Compact market cards**: Per-city live temps, forecast highs, bucket price bars, responsive 6-column grid
+- **Bot control panel**: Real-time bot status (LIVE badge), auto-execute toggle in sidebar
+- **Order panel**: Multi-step workflow (review → pricing → confirm → result) with batch ordering support
 
 ## Important Conventions
 
 - **DRY_RUN=true by default** — All signal detection and DB recording works, but no real orders are placed
-- **Temperature units** — NYC/Chicago/Miami/Houston/Denver/LA/Phoenix/Seattle = °F, others = °C
+- **Temperature units** — US cities (NYC/Chicago/Miami/Dallas/Atlanta/Seattle) = °F, all others = °C
+- **24 cities across 3 tiers** — P0 (NYC/London/Chicago), P1 (Paris/Seoul/Tokyo/Miami), P2 (20+ global cities)
 - **Maker orders only** — Limit orders (GTC) on Polymarket to pay zero fees
 - **All timestamps UTC** — Local timezone only in dashboard display
 - **Error isolation** — One city/market failing must not block others
@@ -124,9 +135,31 @@ See `.env.example` for all required variables. Key ones:
 - `DRY_RUN` — `true` (default) to simulate, `false` for real orders
 - `SIGNATURE_TYPE` — `1` for POLY_PROXY (standard Polymarket exported wallets)
 
+## Ensemble Weights (4 models)
+
+```
+ecmwf: 30%, gfs: 25%, hko: 25%, icon: 20%
+```
+
+HKO is the official settlement source for Hong Kong markets. Updates 4x daily.
+
+## Risk Management
+
+- **Kelly criterion** position sizing with configurable fraction (default 25%)
+- **Position limits**: per-market ($50), per-city ($200), total exposure ($1000), daily loss cap ($100)
+- **Min liquidity**: $500 required in orderbook before placing orders
+- **Portfolio tracker**: In-memory position tracking, PnL calculation, daily metrics aggregation
+
+## Bot Health Check Server (port 3001)
+
+- `/health` — Basic status (running/stopped, uptime, dryRun mode)
+- `/metrics` — Detailed metrics (open positions, daily PnL, last cycle results)
+- `/auto-execute` — Toggle endpoint for enable/disable
+
 ## Polymarket Integration Notes
 
 - Gamma API (`gamma-api.polymarket.com`) — Market discovery, no auth needed
 - CLOB API (`clob.polymarket.com`) — Orderbook reads (no auth), order placement (requires wallet auth)
+- WebSocket feed (`wss://ws-subscriptions-clob.polymarket.com`) — Real-time price updates with auto-reconnect
 - Neg-risk markets have separate YES and NO token IDs; orderbooks must be merged for accurate pricing
 - Market URL pattern: `https://polymarket.com/event/highest-temperature-in-{city-slug}-on-{month}-{day}-{year}`

+ 39 - 3
README.md

@@ -9,6 +9,8 @@ Polymarket 天气预测市场套利机器人。通过比较专业气象模型(
 | **TAIL_NO** | 在尾部区间买入 NO — 当模型概率 < 5% 但市场 YES 价格 > 3¢ 时 |
 | **LATENCY_ARB** | 新气象数据使概率偏移 > 5%,市场尚未重新定价时交易 |
 | **PARITY_ARB** | 当某事件所有 YES 价格之和偏离 100¢ 时的纯套利 |
+| **OBSERVED_YES** | 峰值时段(当地 11:00–14:00)在观测温度区间买入 YES,市场尚未反映已知高温 |
+| **OBSERVED_NO** | 在观测日最高温度以下的区间买入 NO(全天有效,最高置信度策略) |
 
 ## 架构
 
@@ -17,9 +19,9 @@ TypeScript monorepo,使用 Turborepo + pnpm workspaces。
 ```
 packages/
   core/             — 共享类型、工具函数、Prisma schema、常量
-  weather-engine/   — GFS/ECMWF/ICON 预报获取(Open-Meteo)、集合概率计算
+  weather-engine/   — GFS/ECMWF/ICON 预报获取(Open-Meteo)、HKO 香港天文台预报、集合概率计算
   market-engine/    — Polymarket Gamma API 扫描、CLOB 订单簿读取、认证下单
-  strategy/         — 信号生成(Tail NO / Latency Arb / Parity Arb)、风控、Kelly 仓位
+  strategy/         — 信号生成(Tail NO / Latency Arb / Parity Arb / Observed YES/NO)、风控、Kelly 仓位、组合追踪
   trading-engine/   — 机器人主循环、流水线编排、健康检查服务
   dashboard/        — Next.js App Router 仪表盘,实时市场数据、信号、手动下单
 ```
@@ -134,7 +136,7 @@ pnpm derive-keys          # 从 PRIVATE_KEY 派生 L2 API 密钥
 - **数据库**: PostgreSQL 16 (Prisma ORM) + Redis 7
 - **仪表盘**: Next.js 14 (App Router), Tailwind CSS, next-themes, Radix UI
 - **市场 API**: Polymarket Gamma API + CLOB API
-- **气象 API**: Open-Meteo (GFS, ECMWF, ICON)
+- **气象 API**: Open-Meteo (GFS, ECMWF, ICON), 香港天文台 (HKO), wttr.in (实时温度)
 - **交易**: @polymarket/clob-client, ethers
 
 ## 环境变量
@@ -151,12 +153,46 @@ pnpm derive-keys          # 从 PRIVATE_KEY 派生 L2 API 密钥
 | `DRY_RUN` | `true`(默认)模拟交易,`false` 真实下单 |
 | `AUTO_EXECUTE` | `false`(默认)仅检测信号,不自动下单 |
 
+## 覆盖城市
+
+24 个城市,分 3 个优先级:
+
+- **P0**(高流动性):纽约、伦敦、芝加哥
+- **P1**(中等流动性):巴黎、首尔、东京、迈阿密
+- **P2**(其他 Polymarket 城市):布宜诺斯艾利斯、香港、多伦多、西雅图、达拉斯、亚特兰大、慕尼黑、特拉维夫、圣保罗、上海、惠灵顿、米兰、勒克瑙、新加坡、安卡拉、华沙、马德里、台北
+
+## 集合模型权重
+
+| 模型 | 权重 |
+|------|------|
+| ECMWF | 30% |
+| GFS | 25% |
+| HKO | 25% |
+| ICON | 20% |
+
+HKO 为香港市场的官方结算数据源,每日更新 4 次。
+
+## 风控配置
+
+- **Kelly 仓位管理**:Kelly 分数默认 25%
+- **头寸限制**:单市场 $50、单城市 $200、总敞口 $1000、日亏损上限 $100
+- **最低流动性**:订单簿需有 $500 流动性
+
+## 健康检查服务(端口 3001)
+
+| 端点 | 说明 |
+|------|------|
+| `/health` | 基本状态(运行/停止、运行时长、DryRun 模式) |
+| `/metrics` | 详细指标(持仓、日 PnL、最近一轮结果) |
+| `/auto-execute` | 自动执行开关 |
+
 ## 注意事项
 
 - **DRY_RUN=true 为默认值** — 所有信号检测和数据库记录正常工作,但不会真正下单
 - **温度单位** — 美国城市使用 °F,其他城市使用 °C
 - **仅 Maker 订单** — 在 Polymarket 上使用限价单(GTC)以免手续费
 - **时间戳均为 UTC** — 本地时区仅在仪表盘显示中使用
+- **WebSocket 实时价格** — 通过 Polymarket WebSocket 获取实时价格更新,支持自动重连
 
 ## License
 

+ 16 - 12
packages/dashboard/src/app/markets/loading.tsx

@@ -13,24 +13,28 @@ export default function MarketsLoading() {
       <div className="h-11 bg-gray-200 dark:bg-slate-700 rounded-lg animate-pulse" />
 
       {/* Market card skeletons */}
-      <div className="grid grid-cols-1 xl:grid-cols-2 gap-4">
-        {[1, 2, 3, 4].map((i) => (
-          <div key={i} className="card animate-pulse">
-            <div className="flex items-start justify-between p-5 pb-3">
-              <div className="flex-1">
-                <div className="h-6 w-32 bg-gray-200 dark:bg-slate-700 rounded" />
-                <div className="h-4 w-48 bg-gray-200 dark:bg-slate-700 rounded mt-2" />
+      <div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 2xl:grid-cols-6 gap-3">
+        {[1, 2, 3, 4, 5, 6].map((i) => (
+          <div key={i} className="card animate-pulse overflow-hidden">
+            <div className="flex items-start justify-between px-3 pt-3 pb-1.5">
+              <div className="flex-1 min-w-0">
+                <div className="h-4 w-16 bg-gray-200 dark:bg-slate-700 rounded" />
+                <div className="h-3 w-12 bg-gray-200 dark:bg-slate-700 rounded mt-1" />
               </div>
-              <div className="text-right">
-                <div className="h-5 w-20 bg-gray-200 dark:bg-slate-700 rounded" />
-                <div className="h-3 w-16 bg-gray-200 dark:bg-slate-700 rounded mt-1" />
+              <div className="text-right shrink-0 ml-2">
+                <div className="h-5 w-10 bg-gray-200 dark:bg-slate-700 rounded" />
+                <div className="h-2.5 w-8 bg-gray-200 dark:bg-slate-700 rounded mt-1" />
               </div>
             </div>
-            <div className="space-y-2 px-5 pb-4">
+            <div className="px-2 pb-2 space-y-0.5">
               {[1, 2, 3, 4, 5].map((j) => (
-                <div key={j} className="h-8 bg-gray-200 dark:bg-slate-700 rounded" />
+                <div key={j} className="h-5 bg-gray-200 dark:bg-slate-700 rounded" />
               ))}
             </div>
+            <div className="flex items-center justify-between px-3 py-1.5 border-t border-gray-100 dark:border-slate-700/30">
+              <div className="h-2.5 w-20 bg-gray-200 dark:bg-slate-700 rounded" />
+              <div className="h-2.5 w-6 bg-gray-200 dark:bg-slate-700 rounded" />
+            </div>
           </div>
         ))}
       </div>