docs: add V5.4 execution state machine design (maker/taker combo)

This commit is contained in:
root 2026-03-06 07:08:20 +00:00
parent 6fbf3566f9
commit 2d64a5524e

View 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 入场挂单相对盘口的偏移(通常为 12 个 tick
- `entry_timeout_ms`:入场 maker 挂单最大等待时间(如 30005000ms
- `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