移动止损(Trailing Stop)设计方案

移动止损(Trailing Stop)设计方案

1. 概述

移动止损是风控体系中的止盈保护机制。当仓位盈利达到激活阈值后,系统开始追踪盈利峰值;当价格从峰值回撤超过回调阈值时,自动平仓锁定利润。

适用场景:短周期配对交易(持仓 < 30 分钟),捕获瞬间定价错误的套利机会。

2. 核心参数

参数 环境变量 默认值 说明
trailing_stop_activation_pct TRADING_TRAILING_STOP_ACTIVATION_PCT 0.01 激活阈值,盈利达到 1% 后启用追踪
trailing_stop_callback_pct TRADING_TRAILING_STOP_CALLBACK_PCT 0.003 回调阈值,从峰值回撤 0.3% 触发平仓
stop_loss_check_interval TRADING_STOP_LOSS_CHECK_INTERVAL 3 监控轮询间隔(秒)

注意:PnL 百分比基于名义价值(非保证金)。例如 1% 在 3x 杠杆下相当于保证金的 3%。

参数支持按交易对覆盖,通过 TradingConfig.get_strategy_params(symbol, base_symbol) 获取。

3. 判定算法

触发平仓 = (peak_pnl_pct >= activation_pct) AND (current_pnl_pct < peak_pnl_pct - callback_pct)
  • peak_pnl_pct:仓位生命周期内记录的最高盈利百分比(只升不降)
  • current_pnl_pct:当前实时盈利百分比

两个条件缺一不可:

  1. 历史峰值盈利必须曾达到激活阈值(未达到则移动止损不生效,仅固定止损保护)
  2. 当前盈利必须从峰值回撤超过回调阈值

示例演示

配置:activation_pct=0.01, callback_pct=0.003

时间 当前盈利 峰值盈利 已激活 触发平仓 说明
T1 0.5% 0.5% - - 峰值未达 1%,不激活
T2 1.2% 1.2% Y - 达到激活阈值,开始追踪
T3 2.0% 2.0% Y - 峰值更新,2.0% >= 2.0%-0.3%
T4 1.8% 2.0% Y - 小幅回撤,1.8% >= 1.7%
T5 1.6% 2.0% Y 平仓 1.6% < 1.7%,触发

最终锁定约 1.6% 利润(名义价值维度)。

4. 架构与数据流

4.1 模块关系

orchestrator._stop_loss_monitor()    # 监控线程(每 3s 轮询)
    |
    +-- position_manager.update_position_prices()   # 从 WebSocket 缓存更新价格
    |
    +-- risk_manager.check_trailing_stop(pos)       # 判定逻辑
            |
            +-- _calculate_pnl_pct(pos)             # 计算当前 PnL%
            +-- position.update_peak_pnl(pnl)       # 更新峰值
            +-- 比较 peak vs current                 # 判定是否触发
    |
    +-- orchestrator._close_with_retry(pos, reason) # 触发时市价平仓

4.2 涉及文件

文件 职责
src/trading/config.py 参数定义、环境变量读取、按交易对覆盖
src/trading/models.py PairPosition.peak_pnl_pct 字段、update_peak_pnl() 线程安全更新
src/trading/risk_manager.py check_trailing_stop() 判定、_calculate_pnl_pct() PnL 计算
src/trading/orchestrator.py _stop_loss_monitor() 监控线程、平仓执行
src/trading/position_manager.py 价格更新、peak_pnl_pct 初始化与持久化
src/trading/trade_repository.py update_position_runtime() DB 持久化

5. PnL 计算逻辑

5.1 Single 模式

# buy 方向
pnl_pct = (current_price - entry_price) / entry_price

# sell 方向
pnl_pct = (entry_price - current_price) / entry_price

5.2 Pair 模式(两腿加权平均)

alt_pnl_pct = ...   # alt 腿 PnL%(同 single 逻辑)
base_pnl_pct = ...  # base 腿 PnL%(同 single 逻辑)

alt_notional = alt_size * alt_entry_price
base_notional = base_size * base_entry_price
total_notional = alt_notional + base_notional

combined_pnl_pct = (alt_pnl_pct * alt_notional + base_pnl_pct * base_notional) / total_notional

按名义价值加权,避免两腿仓位大小不等时简单平均产生偏差。

6. 峰值追踪机制

6.1 运行时更新

PairPosition.update_peak_pnl() 使用 threading.Lock 保证线程安全,只允许峰值单调递增:

def update_peak_pnl(self, current_pnl_pct: float):
    with self._pnl_lock:
        if current_pnl_pct > self.peak_pnl_pct:
            self.peak_pnl_pct = current_pnl_pct

6.2 持久化

  • 写入 DB:仓位同步时(position_sync_interval 周期),若 peak_pnl_pct > 0 则调用 trade_repository.update_position_runtime() 写入 pair_positions
  • 从 DB 恢复:服务重启时从 pair_positions.peak_pnl_pct 字段恢复,不会丢失历史峰值

6.3 孤儿仓位初始化

服务重启发现交易所有仓位但 DB 无记录时,按以下方式初始化 peak_pnl_pct

  • Pair 模式(alt_unrealizedPnl + base_unrealizedPnl) / (alt_notional + base_notional),与 _calculate_pnl_pct() 两腿加权口径一致
  • Single 模式unrealizedPnl / notional

7. 监控线程执行流程

orchestrator._stop_loss_monitor() 每 3 秒执行一轮:

1. KillSwitch 检查 → 激活则平仓所有仓位并跳过后续
2. 更新所有仓位当前价格(WebSocket L2Book 缓存,<10ms)
3. 遍历所有 OPEN 仓位,依次检查:
   a. 固定止损(check_stop_loss)
   b. 移动止损(check_trailing_stop)
   c. 持仓超时(check_max_hold_duration)
4. 收集所有需平仓的仓位和原因
5. 逐个执行平仓(带重试机制)
   - 止损/移动止损 → 市价单(紧急退场)
   - 持仓超时 → 限价单(遵循 close_order_type 配置)

检查顺序有优先级:固定止损 > 移动止损 > 持仓超时。命中前者后不再检查后者(elif 链)。

8. 与其他退场机制的关系

退场机制 触发条件 优先级 订单类型
KillSwitch 外部文件信号 最高 市价
固定止损 pnl < -stop_loss_pct 市价
移动止损 峰值激活 + 回撤超阈值 市价
均值回归退场 z-score 回归到阈值 限价/市价
持仓超时 持仓时间 > max_hold_hours 限价

移动止损与固定止损互斥:亏损时固定止损保护,盈利时移动止损锁利。

9. 配置示例

# .env
TRADING_TRAILING_STOP_ACTIVATION_PCT=0.01    # 盈利 1% 后激活
TRADING_TRAILING_STOP_CALLBACK_PCT=0.003     # 从峰值回撤 0.3% 触发
TRADING_STOP_LOSS_CHECK_INTERVAL=3           # 3 秒轮询

Read more

跑步的技巧(滚动落地)

“滚动落地(rolling contact / rolling foot strike)”不是一种教条式的“脚法”,而是一种 让冲击沿着整只脚、整条后链逐级传递的落地机制。 它的核心不是“你先用哪儿着地”,而是: 你的脚落地之后,冲击是不是像轮子一样滚过去,而不是像锤子一样砸下去。 这就是滚动落地的本质。 一、什么叫“滚动落地”? 你可以把它理解成两种完全不同的落地方式: 1. 砸地(撞击式) 脚像锤子一样拍到地上: * 要么后跟先砸 * 要么前掌先戳 * 冲击集中在一个点 * 一个结构瞬间吃掉大部分载荷 结果就是: * 后跟砸 → 膝盖难受 * 前掌戳 → 前脚掌磨烂 * 都不是长跑友好模式 这叫 撞击式着地(impact strike)。 2. 滚地(滚动式) 脚像轮胎一样“滚”过地面: * 不是某一点硬砸 * 而是外侧中足先轻触 * 再向前滚到前掌 * 最后从大脚趾蹬离

By SHI XIAOLONG

AMI的优越性

世界模型(World Models)的具体例子 如下,我按类型分类,便于理解。每类都附带实际实现、演示效果和应用场景。 1. Yann LeCun / Meta 的 JEPA 系列(最直接对应“世界模型”概念) 这些是 LeCun 主张的非生成式抽象预测世界模型代表。 * I-JEPA(Image JEPA,2023) 输入一张图像,模型把不同区域(context 和 target)编码成抽象表示,然后预测 target 的表示(不在像素级别重建)。 例子:给定一张遮挡了部分物体的图片,模型能预测“被遮挡物体的大致位置和属性”,构建对物体持久性和空间关系的理解。 这是一个“原始世界模型”,能学习物理常识(如物体不会凭空消失)。 * V-JEPA / V-JEPA 2(Video JEPA,

By SHI XIAOLONG

什么是:“世界模型(World Models)”

世界模型(World Models) 是人工智能领域的一个核心概念,尤其在 Yann LeCun 等研究者推动的下一代 AI 架构中占据中心位置。它指的是 AI 系统在内部构建的对现实世界的抽象模拟或内部表示,让机器能够像人类或动物一样“理解”物理世界、预测未来、规划行动。 简单比喻 想象你闭上眼睛也能“看到”房间里的物体会如何移动、碰撞或掉落——这就是你大脑里的世界模型。AI 的世界模型就是类似的“数字孪生”(digital twin)或“内部模拟器”:它不是简单记住数据,而是学习世界的动态、因果关系和物理直觉(如重力、物体持久性、遮挡、因果等)。 为什么需要世界模型? 当前主流的大型语言模型(LLM) 擅长处理文本(统计模式预测),但存在根本局限: * 缺乏对物理世界的真正理解 → 容易“幻觉”、无法可靠规划。 * 样本效率低 → 人类/

By SHI XIAOLONG

K线周期可配置化设计方案

K线周期可配置化设计方案 1. 背景与目标 当前 Beta 套利策略的 K 线周期硬编码为 "1h",分散在多个文件中。需要: 1. 将 K 线周期从 1h 改为 2h 2. 提取为环境变量 BETA_ARB_KLINE_INTERVAL,使其可在 .env 中配置 2. 影响范围分析 2.1 需要修改的文件(共 6 个) 文件 硬编码位置 修改内容 src/trading/config.py BetaArbConfig dataclass 新增 kline_interval 字段,

By SHI XIAOLONG