1. 模块定位与关键思想
自动挂单 V2 将“固定价差阈值触发开仓”的方式升级为“两段式触发”:
- StartSpread只作为启动门槛:价差达到后进入观察追踪(ARM),并不立即开仓。
- 行为确认作为真正开仓触发:基于价差的峰值、回撤、速度、确认窗口等行为条件执行开仓。
把“开仓点”从单点条件(>=500)升级为行为条件(出现更高峰值 + 回撤确认/突破确认),提升开仓质量,减少“开进去才发现开低了”。
2. 变量与参数定义(研发统一口径)
| 变量/参数 | 说明 | 推荐默认/范围 | 工程备注 |
|---|---|---|---|
| spread(t) | 实时价差(例如:国内金期货 - 国外金期货折算后) | 单位必须统一(USD 或 点) | 建议统一用“可交易口径价差”,并固化汇率/合约乘数换算规则 |
| StartSpread | 启动门槛:达到后进入 ARM(观察/追踪阶段) | 如 500(仅门槛) | 不再等价于进场点 |
| maxSpread | ARM 后记录的历史最大价差(峰值) | 实时更新 | maxSpread = max(maxSpread, spread) |
| MinPeakDelta(可选) | 峰值最小抬升:要求 maxSpread 至少比 StartSpread 高出 X 才允许触发 | 150(示例) | 用于防止刚过门槛就触发追踪进场 |
| EntryPullbackPct | 追踪回撤比例:从 maxSpread 回撤该比例后触发开仓 | 10%~25% | 越小越“追高”越快进;越大越“等回撤”越稳健 |
| entryLine | 追踪开仓线:entryLine = maxSpread × (1 - EntryPullbackPct) | 动态更新 | 与动态止盈的 StopProfit 对称 |
| ConfirmWindow | 确认窗口:需连续 N 个采样满足条件才触发 | 3~5 | 过滤跳点/噪声 |
| drawdownSpeed | 回撤速度:从 maxSpread 回落到当前 spread 的速度 | 窗口 2~5 秒计算 | 用于区分“慢回撤(震荡)/快回撤(峰值确认)” |
| speedThreshold | 回撤速度阈值:超过才认为回撤“可信” | 需用历史数据标定 | 第一版可先给经验值,后续用统计分位数自适应 |
| ARMTimeout | ARM 超时:ARM 后若长时间不触发则撤销追踪,重新等待 | 60~180 秒 | 防止“挂住不动”占用风控状态 |
| ExecutionMode | 开仓执行方式:市价双腿 / 限价 / 条件单 | 按交易通道确定 | 影响滑点与确认窗口策略,建议写入日志 |
3. 状态机设计(工程实现主骨架)
建议将自动挂单分为四个明确状态,便于研发实现与日志追踪:
| 状态 | 含义 | 进入条件 | 退出条件 |
|---|---|---|---|
| WAIT | 等待触发门槛 | 默认状态 | spread ≥ StartSpread → ARM |
| ARM | 观察追踪:记录 maxSpread,计算 entryLine | spread ≥ StartSpread | 满足 TRIGGER 条件 → TRIGGER;超时 → WAIT |
| TRIGGER | 触发开仓:准备下单/校验两腿/下单 | 回撤确认/突破确认通过 | 下单成功 → ENTERED;失败/风控拒绝 → WAIT/ARM |
| ENTERED | 已开仓:进入持仓管理(止盈/止损/风控) | 下单成功 | 平仓后返回 WAIT |
4. 核心算法:追踪开仓(Trailing Entry)
追踪开仓的核心是:进入 ARM 后不断记录峰值 maxSpread,并根据峰值计算动态“追踪开仓线 entryLine”。
当价差从峰值回撤到 entryLine,并通过确认过滤后,触发开仓。
4.1 entryLine 的计算公式(动态)
// ARM 阶段每次采样更新峰值:
maxSpread = max(maxSpread, spread)
// 追踪开仓线(动态随峰值上移):
entryLine = maxSpread * (1 - EntryPullbackPct)
4.2 MinPeakDelta(峰值最小抬升)的作用(可选但推荐)
如果没有 MinPeakDelta,当 spread 刚达到 StartSpread 附近,maxSpread 也很接近 StartSpread,
entryLine 会很靠近门槛,可能导致“刚进入 ARM 就很快触发”。
因此可加入一条约束:必须先出现更高峰值,再允许追踪进场。
// 只有当峰值足够抬升,才允许进入“回撤触发”的判定
if (maxSpread < StartSpread + MinPeakDelta) {
// 还没有出现“更高价差”,继续观察,不触发
continue
}
5. 三类过滤器(防误触发,让触发更科学)
5.1 过滤器 A:确认窗口 ConfirmWindow(N 连续采样)
目的:过滤“瞬时穿越 entryLine”的噪声。
只有当 spread 连续 N 次采样都 ≤ entryLine,才认为回撤真正发生。
// belowCount:连续低于 entryLine 的计数器
if (spread <= entryLine) {
belowCount += 1
} else {
// 只要价差重新回到 entryLine 上方,就认为这次回撤未确认
belowCount = 0
}
passConfirm = (belowCount >= ConfirmWindow)
5.2 过滤器 B:回撤速度 drawdownSpeed(斜率过滤)
目的:区分“慢震荡”与“快回撤”。
只有当回撤速度足够快,才更像“峰值确认 + 回撤”,触发开仓更可靠。
// 回撤幅度(从峰值回落多少)
drawdown = maxSpread - spread
// 推荐:用固定窗口 K 秒计算速度,抗噪声更强
// drawdownSpeed = (spread(t-K) - spread(t)) / K
drawdownSpeed = computeDrawdownSpeed(windowSeconds = K)
// 判定:速度达到阈值才算通过
passSpeed = (drawdownSpeed >= speedThreshold)
速度阈值 speedThreshold 不要拍脑袋,建议用历史数据统计:取 drawdownSpeed 的 P70/P80 作为阈值起点,再迭代。
5.3 过滤器 C:ARM 超时 ARMTimeout(防“挂住不动”)
目的:如果价差到达 StartSpread 后长期在一个区间震荡, 既不出峰值也不回撤触发,系统不应一直处于 ARM 占用状态。
if (now - armStartTime >= ARMTimeout) {
// 撤销本次追踪,回到 WAIT,重新等待下一次机会
resetArmState()
STATE = WAIT
}
5.4 TRIGGER 条件(把过滤器组合起来)
// ARM 阶段:只有当满足“峰值抬升”后,才允许触发
if (maxSpread >= StartSpread + MinPeakDelta) {
entryLine = maxSpread * (1 - EntryPullbackPct)
if (spread <= entryLine) {
// 过滤器 A:确认窗口
if (!passConfirmWindow()) return
// 过滤器 B:回撤速度
if (!passSpeedFilter()) return
// 过滤器 C:未超时
if (isArmTimeout()) return
// 通过全部过滤器,触发开仓
STATE = TRIGGER
placeOrders()
}
}
6. 强势补偿:突破确认进场(可选,避免“等回撤等不到”)
在某些行情中,价差可能持续扩张且回撤很浅,Trailing Entry 可能一直等不到 entryLine。
此时可提供一个可选分支:突破确认进场(Breakout Confirm)。
| 模式 | 触发逻辑 | 适用 | 风险 |
|---|---|---|---|
| Trailing Entry | 峰值出现后回撤到 entryLine 触发 | 高波动、尖峰多 | 可能错过“一去不回头”的扩张 |
| Breakout Confirm | 突破 StartSpread+BreakoutDelta 并持续 T 秒 | 强势持续扩张 | 更偏追涨,需要更严格风控 |
// BreakoutDelta:突破幅度(例如 2 * MinPeakDelta)
// HoldTime:持续时间(例如 8~15 秒)
if (spread >= StartSpread + BreakoutDelta) {
if (spread stays above for HoldTime) {
STATE = TRIGGER
placeOrders()
}
}
7. 分批开仓(Scale-in)建议(提升入场均价与收益结构)
即便采用动态追踪开仓,仍可能出现“进场后继续扩张”的情况。
因此建议支持分批开仓:把一次性全仓开仓升级为多段触发加仓,提升整体入场均价与收益稳定性。
| 分批策略 | 示例 | 好处 | 工程注意 |
|---|---|---|---|
| 阶梯触发 | 550 开 30% / 700 开 30% / 900 开 40% | 减少“一枪打满开低” | 必须有仓位上限与对冲完整性校验 |
| 峰值回撤 + 二次确认加仓 | 第一笔触发后,若再创新高并回撤再次满足条件加仓 | 顺势扩张时能提升总体收益 | 避免无限加仓:设置 MaxAddCount / MaxPosition |
8. 阈值自适应:用分位数启动门槛(P80/P90 替代拍脑袋)
StartSpread 若长期固定(如 500),会在不同市场环境下显得过低或过高。
建议引入基于历史分布的启动门槛:
// 在过去 N 天/过去 M 小时的 spread 序列上计算分位数
StartSpread_auto = Quantile(spread_history, q) // q = 0.8 或 0.9
// 最终使用值取“用户底线”和“自适应建议”的最大值
StartSpread_used = max(StartSpread_user_min, StartSpread_auto)
不再死等某个数值,而是等价差进入最近一段时间的“高位区域”(如前 20%)才进入追踪阶段。
9. 日志埋点与开仓质量评分(为 AI 参数建议铺路)
9.1 必备日志字段(每次挂单与开仓)
[AutoEntryV2]
timestamp
state_from -> state_to
spread
StartSpread_used
maxSpread
entryLine
EntryPullbackPct
MinPeakDelta
ConfirmWindow
drawdownSpeed
speedThreshold
ARMTimeout
armDuration
ExecutionMode (market/limit/conditional)
orderResult (success/fail + reason)
latency_ms
9.2 开仓质量评分(建议)
用于复盘“是否开低了”,并为后续 AI 给参数建议提供监督信号。
| 指标 | 定义(示例) | 解释 |
|---|---|---|
| PostEntryMaxSpread | 开仓后 X 分钟内最大 spread | 如果显著高于 entrySpread,说明开得偏低 |
| AdverseMove | 开仓后最大不利波动(价差回落幅度) | 衡量被套风险 |
| EntryEfficiency | entrySpread / PostEntryMaxSpread | 越接近 1 越好(更接近高位入场) |
没有这些“后验质量指标”,AI 就只能拍脑袋建议参数;有了这些数据,AI 才能学会“什么叫开得好”。
10. 默认参数建议(第一版可直接上线)
| 参数 | 建议默认 | 说明 |
|---|---|---|
| StartSpread | 500(仅门槛) | 进入 ARM 的启动门槛,不再等价于进场点 |
| MinPeakDelta | 150 | 至少先出现更高峰值(≥650)再允许触发追踪进场 |
| EntryPullbackPct | 15% | 峰值回撤 15% 触发开仓(可后续自适应) |
| ConfirmWindow | 3 | 连续 3 次采样满足条件才触发 |
| drawdownSpeedWindow | 3 秒 | 速度采用固定窗口计算,抗噪声更强 |
| ARMTimeout | 120 秒 | 两分钟不触发则撤销 ARM,回到 WAIT |
| Breakout Confirm | 默认关闭(可选) | 强势扩张场景用作补偿 |
11. 测试用例清单(关键边界)
- 刚过 StartSpread:spread=505 后快速回落,不应立即触发(需峰值抬升/确认窗口)。
- 峰值抬升后回撤触发:500→650→回撤至 entryLine 且连续 N 次满足,应触发开仓。
- 瞬时穿越 entryLine:单次采样跌破后立刻恢复,不应触发(ConfirmWindow 生效)。
- 慢回撤:持续在 entryLine 附近震荡但回撤速度低,应不触发或延后触发(速度过滤)。
- ARM 超时:进入 ARM 后 120 秒无触发,应回到 WAIT。
- Breakout Confirm(可选):持续突破条件达到时应触发;否则不触发。
- 下单失败回退:TRIGGER 下单失败应记录原因并回到 WAIT/ARM(按策略)。