docs: add V5.4 execution state machine design (maker/taker combo)
This commit is contained in:
parent
6fbf3566f9
commit
2d64a5524e
251
docs/arbitrage-engine/execution-state-machine.md
Normal file
251
docs/arbitrage-engine/execution-state-machine.md
Normal file
@ -0,0 +1,251 @@
|
||||
# V5.4 Execution State Machine
|
||||
|
||||
本文档描述 V5.4 策略的执行层状态机设计,重点是 maker/taker 组合策略,确保在不牺牲入场/出场时效性的前提下,最大程度降低手续费与滑点摩擦。
|
||||
|
||||
设计目标:
|
||||
- 将"信号质量"和"执行质量"解耦,执行层只负责:更便宜、更稳定地实现既定 TP/SL/flip/timeout 规则。
|
||||
- 入场阶段在不丢失大行情的前提下尽量使用 maker;
|
||||
- 出场阶段 TP 强制 maker 主路径,同时用 taker 做安全兜底;
|
||||
- SL 始终使用 taker,优先保证风控。
|
||||
|
||||
---
|
||||
|
||||
## 1. 入场状态机(Entry State Machine)
|
||||
|
||||
### 1.1 状态定义
|
||||
|
||||
- `IDLE`:无持仓、无挂单,等待信号。
|
||||
- `ENTRY_PENDING_MAKER`:已下入场限价挂单(post-only),等待成交或超时。
|
||||
- `ENTRY_FILL`:入场成交完成(全仓或部分)。
|
||||
- `ENTRY_FALLBACK_TAKER`:超时后使用 taker 市价单补齐未成交部分。
|
||||
|
||||
### 1.2 关键参数
|
||||
|
||||
- `entry_price_signal`:信号引擎给出的入场参考价(通常为最新价或中间价 mid)。
|
||||
- `tick_size`:交易所最小价格步长。
|
||||
- `entry_offset_ticks`:maker 入场挂单相对盘口的偏移(通常为 1–2 个 tick)。
|
||||
- `entry_timeout_ms`:入场 maker 挂单最大等待时间(如 3000–5000ms)。
|
||||
- `entry_fallback_slippage_bps`:fallback taker 允许的最大滑点(基础保护,超出则放弃补仓或缩小仓位)。
|
||||
|
||||
### 1.3 状态机伪代码
|
||||
|
||||
```pseudo
|
||||
state = IDLE
|
||||
|
||||
on_signal_open(signal):
|
||||
if state != IDLE:
|
||||
return // 避免重复入场
|
||||
|
||||
// 计算 maker 挂单价格
|
||||
side = signal.side // LONG or SHORT
|
||||
ref_price = best_bid_ask_mid()
|
||||
|
||||
if side == LONG:
|
||||
entry_price_maker = min(ref_price, best_bid() + entry_offset_ticks * tick_size)
|
||||
else: // SHORT
|
||||
entry_price_maker = max(ref_price, best_ask() - entry_offset_ticks * tick_size)
|
||||
|
||||
// 下 post-only 入场挂单
|
||||
order_id = place_limit_post_only(side, entry_price_maker, target_size)
|
||||
entry_start_ts = now()
|
||||
state = ENTRY_PENDING_MAKER
|
||||
|
||||
|
||||
on_timer():
|
||||
if state == ENTRY_PENDING_MAKER:
|
||||
if order_filled(order_id):
|
||||
filled_size = get_filled_size(order_id)
|
||||
if filled_size >= min_fill_ratio * target_size:
|
||||
state = ENTRY_FILL
|
||||
return
|
||||
|
||||
if now() - entry_start_ts >= entry_timeout_ms:
|
||||
// 超时,取消剩余挂单
|
||||
cancel_order(order_id)
|
||||
remaining_size = target_size - get_filled_size(order_id)
|
||||
|
||||
if remaining_size <= 0:
|
||||
state = ENTRY_FILL
|
||||
return
|
||||
|
||||
// 兜底:按容忍滑点发市价单
|
||||
mkt_price = best_bid_ask_mid()
|
||||
theoretical_price = ref_price_at_signal
|
||||
slippage_bps = abs(mkt_price - theoretical_price) / theoretical_price * 10000
|
||||
|
||||
if slippage_bps <= entry_fallback_slippage_bps:
|
||||
place_market_order(side, remaining_size)
|
||||
state = ENTRY_FILL
|
||||
else:
|
||||
// 滑点过大,放弃补仓或缩减仓位
|
||||
state = ENTRY_FILL // 仅保留已成交部分
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 出场状态机(TP/SL/Flip/Timeout)
|
||||
|
||||
出场分为四类:TP(止盈)、SL(止损)、flip(信号翻转)、timeout(超时退出)。
|
||||
|
||||
### 2.1 通用状态
|
||||
|
||||
- `POSITION_OPEN`:持仓打开,已根据策略下好 TP/SL 限价单。
|
||||
- `TP_PENDING_MAKER`:TP 限价挂单等待成交。
|
||||
- `TP_FALLBACK_TAKER`:TP 越价未成交时,撤单+市价平仓兜底。
|
||||
- `SL_PENDING`:止损触发,直接发送 taker 单。
|
||||
- `FLIP_PENDING`:翻转触发,先平仓再反向开仓(可复用入场状态机)。
|
||||
- `TIMEOUT_PENDING`:超时触发,按策略规则离场(可偏 maker)。
|
||||
|
||||
### 2.2 关键参数
|
||||
|
||||
- `tp1_r`, `tp2_r`:TP1/TP2 的目标 R 距离(如 1.0R / 2.0R)。
|
||||
- `sl_r`:止损距离(如 -1.0R)。
|
||||
- `tp_timeout_ms`:价格越过 TP 水平后,TP 限价未成交的允许时间窗口。
|
||||
- `flip_threshold`:翻转触发条件(score + OBI + VWAP 等综合判断)。
|
||||
- `timeout_seconds`:最大持仓时间,用于 timeout 出场。
|
||||
|
||||
### 2.3 TP 状态机(maker 主路径 + taker 兜底)
|
||||
|
||||
```pseudo
|
||||
on_position_open(pos):
|
||||
// 开仓后立即挂 TP1 限价单(maker)
|
||||
tp1_price = pos.entry_price + pos.side * tp1_r * pos.risk_distance
|
||||
tp2_price = pos.entry_price + pos.side * tp2_r * pos.risk_distance
|
||||
|
||||
// 半仓挂 TP1,半仓挂 TP2
|
||||
tp1_id = place_limit_post_only(exit_side(pos.side), tp1_price, pos.size * 0.5)
|
||||
tp2_id = place_limit_post_only(exit_side(pos.side), tp2_price, pos.size * 0.5)
|
||||
pos.state = POSITION_OPEN
|
||||
|
||||
|
||||
on_timer():
|
||||
if pos.state == POSITION_OPEN:
|
||||
current_price = best_bid_ask_mid()
|
||||
|
||||
// 检查 TP1 越价兜底
|
||||
tp1_crossed = (pos.side == LONG and current_price >= tp1_price) or
|
||||
(pos.side == SHORT and current_price <= tp1_price)
|
||||
if tp1_crossed and not pos.tp1_cross_ts:
|
||||
pos.tp1_cross_ts = now()
|
||||
|
||||
if pos.tp1_cross_ts:
|
||||
if order_filled(tp1_id):
|
||||
pos.tp1_cross_ts = None // 成交,清除计时
|
||||
elif now() - pos.tp1_cross_ts >= tp_timeout_ms:
|
||||
cancel_order(tp1_id)
|
||||
remaining = size_tp1 - get_filled_size(tp1_id)
|
||||
if remaining > 0:
|
||||
place_market_order(exit_side(pos.side), remaining)
|
||||
|
||||
// 检查 TP2 越价兜底
|
||||
tp2_crossed = (pos.side == LONG and current_price >= tp2_price) or
|
||||
(pos.side == SHORT and current_price <= tp2_price)
|
||||
if tp2_crossed and not pos.tp2_cross_ts:
|
||||
pos.tp2_cross_ts = now()
|
||||
|
||||
if pos.tp2_cross_ts:
|
||||
if order_filled(tp2_id):
|
||||
pos.tp2_cross_ts = None
|
||||
elif now() - pos.tp2_cross_ts >= tp_timeout_ms:
|
||||
cancel_order(tp2_id)
|
||||
remaining = size_tp2 - get_filled_size(tp2_id)
|
||||
if remaining > 0:
|
||||
place_market_order(exit_side(pos.side), remaining)
|
||||
|
||||
// 检查是否已全部平仓
|
||||
if pos_size(pos) <= 0:
|
||||
pos.state = CLOSED
|
||||
```
|
||||
|
||||
### 2.4 SL 状态机(纯 taker)
|
||||
|
||||
```pseudo
|
||||
on_sl_trigger(pos, sl_price):
|
||||
// 触发条件可以来自价格监控或止损订单触发
|
||||
// 这里策略层只关心:一旦触发,立即使用 taker
|
||||
close_size = pos_size(pos)
|
||||
if close_size > 0:
|
||||
place_market_order(exit_side(pos.side), close_size)
|
||||
pos.state = CLOSED
|
||||
```
|
||||
|
||||
SL 不做 maker 逻辑,避免在极端行情下挂单无法成交。
|
||||
|
||||
### 2.5 Flip 状态机(平旧仓 + 新开仓)
|
||||
|
||||
```pseudo
|
||||
on_flip_signal(pos, new_side, flip_context):
|
||||
if not flip_condition_met(flip_context):
|
||||
return
|
||||
|
||||
// flip 条件:score < 85 AND OBI 翻转 AND 价格跌破 VWAP(三条件同时满足)
|
||||
// flip_condition_met 由信号引擎判断
|
||||
|
||||
// 1) 先平旧仓(按 SL 逻辑,优先 taker)
|
||||
close_size = pos_size(pos)
|
||||
if close_size > 0:
|
||||
place_market_order(exit_side(pos.side), close_size)
|
||||
|
||||
pos.state = CLOSED
|
||||
|
||||
// 2) 再按入场状态机开新仓
|
||||
new_signal = build_signal_from_flip(new_side, flip_context)
|
||||
entry_state_machine.on_signal_open(new_signal)
|
||||
```
|
||||
|
||||
flip 的关键是:**门槛更高**(如 score < 85 且 OBI 翻转且价格跌破 VWAP),尽量减少在震荡行情中来回打脸。
|
||||
|
||||
### 2.6 Timeout 状态机(超时出场)
|
||||
|
||||
```pseudo
|
||||
on_timer():
|
||||
if pos.state == POSITION_OPEN and now() - pos.open_ts >= timeout_seconds:
|
||||
// 可以偏 maker:先挂限价平仓,超时再 taker
|
||||
timeout_price = best_bid_ask_mid()
|
||||
size = pos_size(pos)
|
||||
|
||||
oid = place_limit_post_only(exit_side(pos.side), timeout_price, size)
|
||||
pos.timeout_order_id = oid
|
||||
pos.timeout_start_ts = now()
|
||||
pos.state = TIMEOUT_PENDING
|
||||
|
||||
if pos.state == TIMEOUT_PENDING:
|
||||
if order_filled(pos.timeout_order_id):
|
||||
pos.state = CLOSED
|
||||
elif now() - pos.timeout_start_ts >= timeout_grace_ms:
|
||||
cancel_order(pos.timeout_order_id)
|
||||
remaining = pos_size(pos)
|
||||
if remaining > 0:
|
||||
place_market_order(exit_side(pos.side), remaining)
|
||||
pos.state = CLOSED
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 监控指标(执行层 KPI)
|
||||
|
||||
| 指标 | 说明 | 目标 |
|
||||
|------|------|------|
|
||||
| `maker_ratio_entry` | 入场成交中 maker 比例 | ≥ 50% |
|
||||
| `maker_ratio_tp` | TP 成交中 maker 比例 | ≥ 80% |
|
||||
| `avg_friction_cost_r` | 每笔平均摩擦成本(手续费+滑点,以 R 计) | ≤ 0.15R |
|
||||
| `entry_timeout_rate` | 入场超时触发 taker 兜底比例 | ≤ 30% |
|
||||
| `tp_overshoot_rate` | TP 越价后兜底比例 | ≤ 20% |
|
||||
| `flip_frequency` | 每笔持仓中 flip 次数 | ≤ 1次/持仓 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 设计原则汇总
|
||||
|
||||
| 场景 | 主路径 | 兜底 |
|
||||
|------|--------|------|
|
||||
| 入场 | limit post-only(盘口内侧 1-2 tick) | 超时 → taker(滑点容忍内) |
|
||||
| TP1 / TP2 | limit post-only(预挂) | 越价 X ms 未成交 → 撤单 + taker |
|
||||
| SL | — | 纯 taker,立即执行 |
|
||||
| Flip | 平仓用 taker,新开仓复用入场逻辑 | — |
|
||||
| Timeout | limit post-only | grace period 后 → taker |
|
||||
|
||||
> **标签**:`#EXECUTION-MAKER-TAKER`
|
||||
> **状态**:V5.4 设计文档,待 3/11 A/B test 结束后进入实现阶段
|
||||
> **作者**:小范(xiaofan)+ 露露(lulu)
|
||||
> **日期**:2026-03-06
|
||||
Loading…
Reference in New Issue
Block a user