设计文档: 信号消退平仓 (Signal Exit on Profit)

设计文档: 信号消退平仓 (Signal Exit on Profit)

背景

当前平仓条件有4种:止损(PnL < -3%)、移动止盈(PnL >= 5% 后回撤0.5%)、持仓超时(72h)、Kill Switch。

存在一种场景:持仓盈利已达2%~5%之间,但尚未触发移动止盈的激活阈值(5%),此时如果开仓信号已经消退(当前市场状态不再满足开仓条件),继续持仓可能导致盈利回吐。

需求

新增平仓条件:当 PnL > 2% 且当前最新状态不满足本次持仓的开仓条件时,执行平仓。

开仓条件回顾

开仓需要同时满足三个条件(strategy.py:check_signal()):

  1. 条件1: ema_beta < beta_ema_threshold — 负收益beta EMA低于阈值
  2. 条件2: ema_beta < mean_beta — 负收益beta EMA低于均值(收敛趋势)
  3. 条件3: ema_beta < positive_ema_beta — 负收益EMA低于正收益EMA(上涨弹性 > 下跌弹性)

"不满足开仓条件" = 三个条件中任意一个不满足。

详细设计

1. src/trading/config.py — 新增配置参数

a) BetaArbConfig dataclass 新增字段

signal_exit_pnl_pct: float = 0.02  # 信号消退平仓的PnL阈值 (2%)

放在 stop_loss_pct 之后。

b) load_trading_config() 新增环境变量加载

signal_exit_pnl_pct=_env_float("BETA_ARB_SIGNAL_EXIT_PNL_PCT", "0.02"),

2. src/trading/strategy.py — 新增开仓条件检查方法

新增 check_entry_conditions_met() 方法

def check_entry_conditions_met(self) -> tuple[bool, str]:
    """检查当前市场状态是否满足开仓条件(纯信号判断,不检查持仓/冷却状态)

    用于信号消退平仓:持仓期间定期检查,若条件不再满足则为平仓提供依据。

    Returns:
        (conditions_met, detail_msg)
    """

核心逻辑:

  • 复用现有 _calculate_beta_series()_calculate_positive_beta_series()
  • 计算三个条件的当前状态
  • 返回 (True/False, "描述详情")
  • 若 beta 序列不足无法计算,返回 (True, "beta序列不足,保守持仓")保守策略,数据不足时不触发退出

为什么不直接用 get_signal_snapshot()

get_signal_snapshot() 也能判断 signal_would_trigger,但它:

  1. 构造了一个完整的 dict snapshot,用于日志展示,数据冗余
  2. 调用方需要处理 key 可能不存在的情况
  3. 语义不清晰 — 它是"日志快照"不是"条件判断"

新增一个专用方法更清晰、更安全,且方法签名明确表达意图。

3. src/trading/risk_manager.py — 新增信号消退平仓检查

新增 check_signal_exit() 方法

def check_signal_exit(self, position: PairPosition, entry_conditions_met: bool) -> bool:
    """检查信号消退平仓 → True需要平仓

    条件:PnL > signal_exit_pnl_pct 且开仓条件不再满足
    """
    _, pnl_pct = self.calculate_pnl(position)
    return (pnl_pct > self._config.beta_arb.signal_exit_pnl_pct
            and not entry_conditions_met)

设计要点:

  • 接收 entry_conditions_met 参数而非直接依赖 strategy,保持 risk_manager 与 strategy 解耦
  • 使用 > 而非 >=(严格大于阈值才触发)
  • 方法返回 bool,与现有的 check_stop_loss()check_trailing_stop() 风格一致

4. src/trading/orchestrator.py — 集成到监控循环

修改 _stop_loss_monitor() 方法

在现有的三个检查(止损 → 移动止盈 → 超时)之后,新增信号消退检查:

# 在 check_max_hold_duration 之后新增:
elif pnl_pct > 0:
    # 仅当盈利时才检查信号消退(避免亏损时的无意义计算)
    entry_met, detail = self._strategy.check_entry_conditions_met()
    if self._risk_manager.check_signal_exit(pos, entry_met):
        close_reason = (
            f"📉🔔 信号消退平仓 | PnL={pnl_pct*100:+.2f}% > "
            f"阈值{self._config.beta_arb.signal_exit_pnl_pct*100:.1f}% "
            f"且开仓条件不满足 | {detail}"
        )

检查优先级(保持现有顺序):

  1. 止损 — 最高优先级,亏损严重立即退出
  2. 移动止盈 — 高利润回撤退出
  3. 持仓超时 — 时间限制
  4. 信号消退 — 新增,盈利但信号消失时退出(最低优先级)

pnl_pct > 0 前置过滤:仅在盈利时才调用 check_entry_conditions_met(),避免每5秒一次的 beta 重算开销。这个优化是安全的,因为信号消退平仓本身就要求 PnL > 2%。

执行流程图

_stop_loss_monitor() 每5秒循环:
    ↓
    update_position_prices()
    ↓
    calculate_pnl() → pnl_pct
    ↓
    check_stop_loss()        → pnl_pct < -3%?     → 平仓
    ↓ (未触发)
    check_trailing_stop()    → 峰值>=5% 且回撤?    → 平仓
    ↓ (未触发)
    check_max_hold_duration() → >72h?              → 平仓
    ↓ (未触发)
    pnl_pct > 0?             → 否: 跳过
    ↓ (是)
    strategy.check_entry_conditions_met() → (met, detail)
    ↓
    check_signal_exit(pos, met) → PnL>2% && !met?  → 平仓

不需要修改的文件

  • models.py — 无新数据结构
  • position_manager.py — 平仓执行逻辑不变,close_position() 已接受 reason 参数
  • executor.py — 订单执行不变
  • trade_repository.py — 已有通用平仓记录

配置默认值

参数 环境变量 默认值 说明
signal_exit_pnl_pct BETA_ARB_SIGNAL_EXIT_PNL_PCT 0.02 信号消退平仓的PnL阈值,2%

边界情况

  1. beta序列不足check_entry_conditions_met() 返回 (True, ...) → 不触发退出(保守)
  2. PnL 恰好 = 2% — 不触发(使用严格 >
  3. 移动止盈已激活(PnL>=5%) — 移动止盈优先级更高,会先被检查并触发,信号消退不会被执行到
  4. 条件3(正收益beta)数据不足 — 与开仓时一致,条件3默认通过,即只看条件1和条件2
  5. K线缓冲区为空 — 返回 (True, ...) → 不触发退出

验证

  1. 日志中应能看到 📉🔔 信号消退平仓 触发时的详情
  2. PnL在0%~2%之间时,即使信号消退也不触发平仓
  3. PnL>2%但三个条件仍然满足时,不触发平仓
  4. PnL>2%且任一条件不满足时,触发平仓
  5. Lark通知中显示平仓原因为信号消退

Read more

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

对于空间环境、“信息/逻辑”(比如代码、结构、表达)秩序追求的心理特征分析

一、为什么是“空间 + 信息”同时强化? 因为你当年面对的是“双重失控”: 1️⃣ 外部世界是脏乱 + 失序的 * 空间被污染 * 行为无边界 * 基本生活秩序崩塌 👉 所以你现在会强烈要求: * 桌面干净 * 房间有序 * 物品可控 这是在修复:“物理世界必须是可控的” 2️⃣ 人的行为和逻辑也是混乱的 * 没有规则 * 没有底线 * 没有理性 👉 所以你现在会特别在意: * 表达是否清晰 * 逻辑是否自洽 * 结构是否优雅 * 代码是否干净 这是在修复:“认知世界必须是合理的” 二、你其实构建了一个“高纯度系统” 你现在的偏好,本质上是: 👉 低噪音 + 高结构 + 强控制感 具体表现就是: * 空间:极简、整洁、可预测 * 信息:清晰、压缩、无冗余 这类人有一个很明显的优势: 👉 处理复杂问题时,

By SHI XIAOLONG