📊 天气做市 — 仓位管理策略
作者: Spark ⚡ | 2026-04-26 | 基于weather_quotes.py+weather_mm_runner.py实际代码
一、核心思路
做市系统不只是单向押注方向,而是在有持仓后自动变成双边做市——低买高卖,赚取预测 edge 对应的价差。
无持仓: 预测方向 → 单向挂单(积累仓位)
有持仓: 预测方向 + 反向挂单(吃价差)
二、仓位生命周期
阶段 1: 无持仓 → 信号触发
Edge = fair_price - market_price = 30%
→ mode = buy_biased
→ BUY @ best_bid + 1 tick(积极买入,tick 通过 CLOB API 获取)
→ SELL @ best_ask(被动,不指望成交)
目标: 在市场低估时积累仓位。
阶段 2: 买入成交 → 持有 YES
check_fill: BUY 限价 ≥ market_ask → 按 market_ask 成交
→ yes_tokens += size
→ total_cost += price × size
此时持仓变化:
yes_tokens: 0 → 20total_cost: $0 → $10.02avg_entry: $0.501阶段 3: 有持仓 + Edge 仍在 → 双边做市
Edge 仍 > 0, yes_tokens > 0
→ mode = buy_biased_holding
BUY @ best_bid + 1 tick(继续吸筹)
SELL @ market_ask - 1 tick(对价减最小单位,成为新卖一)
但不低于 avg_cost + 1¢(绝不亏本卖)
定价对比:
| 无持仓 (buy_biased) | 有持仓 (buy_biased_holding) | |
|---|---|---|
| BUY 价 | 0.501 | 0.501 (不变) |
| BUY 量 | 30 份 | 30 份 (不变) |
| SELL 价 | 0.550 (被动) | max(0.549, 0.56) = 0.56 |
| SELL 量 | 5 份 (象征性) | 10 份 (有意义) |
定价规则:
market_ask - 1 tick (对价减最小单位)avg_cost + 1¢ 更高 → 用 avg_cost + 1¢(不亏本卖)阶段 4: Edge 反转 → 平仓
Edge 翻负 (市场高估了)
→ mode = sell_biased
→ 检测到 yes_tokens > 0
→ close_size = min(ask_size, yes_tokens)
→ 只平仓,不开新空
阶段 5: 合约结算
午夜 HKO 发布 Absolute Daily Max
→ 28°C 命中 → YES = $1.00 → 利润
→ 29°C 未中 → YES = $0.00 → 亏损
三、模式决策矩阵
Edge > 20% Edge < -20% |Edge| < 20%
─────────────────────────────────────────────────────────────────────
无持仓 buy_biased sell_biased symmetric
BUY积极/SELL被动 SELL积极/BUY被动 双边对称
持有 YES buy_biased_ sell_biased symmetric
(之前买入的) holding (先平仓再卖) 双边对称
BUY+SELL都积极 只平仓不开新空
持有 NO buy_biased sell_biased_ symmetric
(之前卖出的) (先平仓再买) holding 双边对称
只平仓不开新空 BUY+SELL都积极
四、定价规则详解
4.1 有流动性市场 (orderbook spread < 50%)
TICK = 0.001
buy_biased (无持仓):
bid = min(best_bid + TICK, fair - TICK)
ask = best_ask
buy_biased_holding (持有 YES):
bid = min(best_bid + TICK, fair - TICK)
ask = market_ask - TICK ← 对价减最小单位,成为新卖一
cost_floor = avg_entry + 0.01
ask = max(ask, cost_floor) ← 绝不亏本卖(成本 + 1 分)
sell_biased (无持仓):
ask = max(best_ask - TICK, fair + TICK)
bid = best_bid
sell_biased_holding (持有 NO):
ask = max(best_ask - TICK, fair + TICK)
bid = market_bid + TICK ← 对价加最小单位,成为新买一
cost_ceiling = avg_entry - 0.01
bid = min(bid, cost_ceiling) ← 绝不亏本买回(成本 - 1 分)
4.2 无流动性市场 (spread ≥ 50%)
回退到 fair-price 中心定价:
buy_biased: bid = fair - spread×0.25, ask = fair + spread×0.75
buy_biased_holding: bid = fair - spread×0.30, ask = fair + spread×0.30
sell_biased: bid = fair - spread×0.75, ask = fair + spread×0.25
sell_biased_holding: bid = fair - spread×0.30, ask = fair + spread×0.30
五、仓位大小规则
5.1 基础参数
| 参数 | 值 |
|---|---|
| BASE_ORDER_SIZE | 10 份 |
| MIN_ORDER_SIZE | 5 份 |
| MAX_ORDER_SIZE | 100 份 |
| MIN_NOTIONAL | $1 (price × size ≥ $1) |
5.2 持仓模式下的双边大小
# buy_biased_holding (持有 YES)
bid_size = base × 1.8 × buy_bias # 继续买入
ask_size = max(base × 1.0, 计算值) # 卖单至少 base 份
# sell_biased_holding (持有 NO)
ask_size = base × 1.8 × sell_bias # 继续卖出
bid_size = max(base × 1.0, 计算值) # 买单至少 base 份
5.3 离散档位
所有 size 自动取整: 5 → 10 → 20 → 30 → 40 → 50...
六、风控集成
仓位管理受 WeatherRiskManager 约束:
| 限制 | 值 | 超限行为 |
|---|---|---|
| 单合约最大敞口 | $10 | 缩减 size |
| 总最大敞口 | $50 | 缩减 50% |
| 单方向最大 | $10 | 该侧设为 0 |
| 日亏损上限 | $20 | 全部停止 |
| 连续亏损 | 3 次 | 暂停 1 小时 |
七、Edge 消失 → 主动平仓 (closing 模式)
当 |edge| < 20% 且持有仓位时,不做双边做市,而是积极平仓退出:
closing_long (持有 YES, edge 消失):
SELL @ market_ask - 1 tick(成为新卖一, 主动出)
≥ avg_cost + 1¢(不亏本)
BUY @ market_bid(被动, 不吸筹)
SELL size = base × 1.5(加大平仓力度)
closing_short (持有 NO, edge 消失):
BUY @ market_bid + 1 tick(成为新买一, 主动平)
≤ avg_cost - 1¢(不亏本)
SELL @ market_ask(被动, 不加空)
BUY size = base × 1.5(加大平仓力度)
触发条件: |edge| < 20% + has_position(之前 edge 够强时建的仓,现在信号消失)
八、价格竞争(保持最优价)
每次扫描后检查已有挂单是否还在盘口最优位置:
BUY 挂单: our_price < best_bid → 被人超了
→ 建议撤单重挂 @ best_bid + 1 tick
SELL 挂单: our_price > best_ask → 被人压了
→ 建议撤单重挂 @ best_ask - 1 tick
检测结果写入 order_competition.json,Web UI 显示建议按钮。
九、测试阶段:人工审批流程
⚠️ 当前测试阶段,所有订单不自动执行,需人工在 Web UI 点击 Approve。
流程
1. Runner 扫描 → 生成报价
2. 强 edge (≥20%) 或 closing 模式的报价 → 保存到 pending_orders.json
3. Web UI 显示待审批卡片(含 BUY/SELL 双向按钮)
4. 人工点击 [Approve BUY] 或 [Approve SELL]
5. 后端调用 CLOB API 下单
6. 订单标记为 approved
相关 API
| 端点 | 功能 |
|---|---|
GET /api/mm/weather/pending-orders | 列出待审批 |
POST /api/mm/weather/approve-order | 审批下单 {key, side} |
POST /api/mm/weather/reject-order | 拒绝 {key} |
GET /api/mm/weather/order-competition | 价格竞争建议 |
POST /api/mm/weather/improve-order | 撤旧挂新 {order_id, new_price} |
十、完整流程示例
时间线: 某日 10:00 - 16:00, 预测 28°C (fair=0.96), 当前 market=0.50
10:00 扫描 #1 无持仓, edge=+46%
→ buy_biased: BUY 0.501 x30, SELL 0.550 x5
→ 保存到 pending_orders.json → Web UI 显示 [Approve BUY]
→ 人工点击 Approve → BUY 成交 @0.55
→ 持仓: YES=30, avg=0.55, cost=$16.50
10:05 扫描 #2 有持仓(30YES, avg=0.55), edge 仍 +46%
→ buy_biased_holding: BUY 0.501 x30, SELL 0.56 x10
→ SELL = max(0.549, 0.56) = 0.56 (成本+1分)
→ Web UI: [Approve BUY] [Approve SELL]
10:30 扫描 #N 价格竞争检查
→ 我们的 BUY @0.501 < best_bid @0.510
→ ⚠️ Web UI 显示: [撤单重挂 @0.511]
→ 人工点击 Improve → 撤旧挂新
11:00 扫描 #M 市场涨到 0.70, market_ask=0.72
→ buy_biased_holding: BUY 0.701 x20, SELL 0.719 x10
→ BUY 成交 @0.72
→ 持仓: YES=50, avg=0.618
13:00 扫描 #K 市场 0.62, edge 缩小到 +4% (< 20%!)
→ closing_long: SELL @0.639 x15 (积极平仓!)
→ 人工点击 [Approve SELL] → 成交 @0.64
→ 持仓: YES=35, 已实现 +$0.22
16:00 温度已达 28.5°C, edge ≈ 0
→ closing_long: 继续平仓剩余
→ 持仓: YES=0, 总利润约 $5
十一、关键设计决策
1. 不做止损单: 不预设固定止损价。靠每 5 分钟重新评估 edge 决定方向。
2. 不做止盈单: 不预设固定止盈。靠双边做市在市场回归 fair 时自然卖出。
3. Edge 是唯一信号: 所有决策围绕 fair - market 展开。
4. 双边做市只在持仓后触发: 无持仓时单向吸筹,有持仓后才是真正的 market maker。
5. 成本底线: SELL 价 ≥ avg_cost + 1¢,BUY 价 ≤ avg_cost - 1¢。宁可不成交也不亏本。
6. 对价优先: 卖单挂 market_ask - 1 tick,买单挂 market_bid + 1 tick。做市要成为盘口最优价。
7. Edge 消失主动平仓: |edge| < 20% + 有仓位 → closing 模式,加大平仓力度。
8. 价格竞争: 挂单不是最优价时,撤单往前挂,始终保持盘口第一。
9. 测试期人工审批: 所有订单显示在 Web UI,人工点击 Approve 后才执行。
本文档随代码同步更新。最后更新: 2026-04-26 19:51 CST