限价单信号价格约束优化设计方案

限价单信号价格约束优化设计方案

1. 背景与问题

当前系统的限价单价格完全基于下单时刻的 L2 订单簿计算(_calculate_limit_price()),未参考信号生成时的价格。在信号生成到实际下单的间隔内,市场价格可能不利移动:

  • 买入场景:信号价 $100,下单时 bid 涨到 $102 → 限价 ~$102,比信号多付 2%
  • 卖出场景:信号价 $100,下单时 ask 跌到 $98 → 限价 ~$98,比信号少收 2%

目标:挂单价格不能比信号价格更差,确保开仓成本不劣于信号时刻的市场价。

2. 当前限价定价流程

信号生成 (orchestrator.on_entry_signal)
  │ latest_alt_price = 信号时刻的市场价
  │ l2_snapshot = 信号时刻的 L2 订单簿快照
  ↓
开仓决策 (position_manager.open_position)
  ↓
限价开仓 (executor.limit_open)
  ├─ Leg B 预检查: _calculate_limit_price(coin, is_buy, l2_snapshot)
  └─ Leg A 下单:   _place_limit_order(coin, is_buy, size, l2_snapshot)
                      └─ _calculate_limit_price(coin, is_buy, l2_snapshot)
                           └─ 买入: best_bid * (1 + offset)
                           └─ 卖出: best_ask * (1 - offset)

_calculate_limit_price() 当前逻辑 (executor.py:466-514):

def _calculate_limit_price(self, coin, is_buy, l2_snapshot=None):
    # 1. 从 L2 获取 best_bid, best_ask
    # 2. effective_offset = min(spread_pct, limit_price_offset_pct)
    # 3. 买入: price = best_bid * (1 + effective_offset)
    #    卖出: price = best_ask * (1 - effective_offset)
    return self.round_price(coin, price)

问题在于:L2 快照虽然是信号时刻缓存的,但如果快照无效会降级到 API 实时查询,且即便使用快照,价格也可能在极短时间内变化。更关键的是,当前没有任何机制保证最终挂单价格不劣于信号价格

3. 设计方案

3.1 核心思路

_calculate_limit_price() 中新增信号价格约束(Signal Price Clamp):

  • 买入price = min(l2_price, signal_price) — 不比信号时更贵
  • 卖出price = max(l2_price, signal_price) — 不比信号时更便宜

3.2 适用范围

场景 是否约束 原因
开仓 (limit_open) 信号价格 latest_alt_price 可用,保护开仓成本
平仓 (limit_close) 平仓优先成交速度,已有超时转市价兜底
市价单 (market_open/close) 市价单由 SDK slippage 参数控制

3.3 新增配置项

配置字段 环境变量 默认值 说明
signal_price_clamp_enabled TRADING_SIGNAL_PRICE_CLAMP_ENABLED true 是否启用信号价格约束
signal_price_max_deviation_pct TRADING_SIGNAL_PRICE_MAX_DEVIATION_PCT 0.03 L2 价格与信号价格偏差超过此阈值时输出 WARNING

4. 修改文件清单

4.1 src/trading/config.py — 新增配置字段

在限价单配置区域(limit_order_timeout 之后)新增:

# 信号价格约束
signal_price_clamp_enabled: bool = True        # 开仓限价不劣于信号价格
signal_price_max_deviation_pct: float = 0.03   # 偏差超过 3% 输出告警

load_trading_config() 中新增环境变量加载:

signal_price_clamp_enabled=os.getenv("TRADING_SIGNAL_PRICE_CLAMP_ENABLED", "true").lower() == "true",
signal_price_max_deviation_pct=_env_float("TRADING_SIGNAL_PRICE_MAX_DEVIATION_PCT", "0.03"),

4.2 src/trading/executor.py — 3 处修改

(a) _calculate_limit_price() — 新增 signal_price 参数 + clamp 逻辑

方法签名变更:

def _calculate_limit_price(
    self,
    coin: str,
    is_buy: bool,
    l2_snapshot: dict | None = None,
    signal_price: float | None = None,    # 新增:信号价格约束
) -> float:

return self.round_price(coin, price) 前插入约束逻辑:

# 信号价格约束: 限价不能比信号生成时的价格更差
if (signal_price is not None and signal_price > 0
        and self._config.signal_price_clamp_enabled):
    original_price = price
    if is_buy:
        price = min(price, signal_price)   # 买入不超过信号价
    else:
        price = max(price, signal_price)   # 卖出不低于信号价

    if price != original_price:
        deviation_pct = abs(original_price - signal_price) / signal_price
        logger.info(
            f"信号价格约束生效: {coin} {'买入' if is_buy else '卖出'} | "
            f"L2=${original_price:.6f} → 约束后=${price:.6f} | "
            f"信号价=${signal_price:.6f} | 偏差={deviation_pct:.2%}"
        )
        if deviation_pct > self._config.signal_price_max_deviation_pct:
            logger.warning(
                f"信号价格偏差过大: {coin} | 偏差={deviation_pct:.2%} > "
                f"阈值={self._config.signal_price_max_deviation_pct:.2%}"
            )

(b) _place_limit_order() — 透传 signal_price

方法签名新增 signal_price: float | None = None,并传递给 _calculate_limit_price()

def _place_limit_order(
    self, coin: str, is_buy: bool, size: float, reduce_only: bool = False,
    l2_snapshot: dict | None = None,
    signal_price: float | None = None,    # 新增
) -> OrderResult:
    ...
    price = self._calculate_limit_price(coin, is_buy, l2_snapshot, signal_price)
    ...

(c) limit_open() — 传入 signal.latest_alt_price

两处调用传入 signal_price:

# Leg B 预检查估价
alt_limit_price = self._calculate_limit_price(
    alt_coin, alt_is_buy, l2_snapshot,
    signal_price=signal.latest_alt_price,
)

# Leg A 下单
result.leg_a = self._place_limit_order(
    alt_coin, alt_is_buy, alt_size, l2_snapshot=l2_snapshot,
    signal_price=signal.latest_alt_price,
)

5. 优化后的调用链

limit_open(signal)
  ├─ _calculate_limit_price(coin, is_buy, l2, signal_price=latest_alt_price)  # Leg B 预检
  │    └─ clamp: min(l2_price, signal_price) 或 max(l2_price, signal_price)
  └─ _place_limit_order(coin, is_buy, size, l2, signal_price=latest_alt_price)  # Leg A
       └─ _calculate_limit_price(coin, is_buy, l2, signal_price)
            └─ clamp 生效 → round_price()

limit_close(position)   ← 不受影响,signal_price 默认 None,跳过 clamp

6. 边界情况处理

场景 行为
latest_alt_priceNone0 跳过 clamp,纯 L2 定价(完全向后兼容)
L2 价格已优于信号价格 min/max 自动保留 L2 价格,无额外日志
L2 价格与信号价格相同 price != original_price 为 False,无日志输出
偏差 > 3%(默认阈值) 仍然 clamp,但输出 WARNING 日志供人工关注
配置关闭 clamp_enabled=false 完全跳过 clamp 逻辑,恢复原有行为
clamp 后 round_price() 精度 Python round() 四舍五入,对买/卖方向的影响 ≤0.01%,可忽略
L2 返回 0.0(无订单簿) 在 clamp 之前已 return 0.0,不会触达 clamp 代码

7. 风险评估

风险低

  • 所有新增参数都有默认值 None,完全向后兼容
  • limit_close()market_open()market_close() 不受影响
  • 可通过环境变量 TRADING_SIGNAL_PRICE_CLAMP_ENABLED=false 随时关闭

潜在影响

  • 如果市场在信号后不利移动较大,clamp 后的限价会远离当前市场(如:信号价 $100,当前 bid $105 → 限价 $100),导致限价单更难成交。但这正是期望行为 — 宁可不成交也不用更差的价格开仓。已有的 10 分钟超时 → 撤单机制会处理未成交情况。
  • round_price() 在 clamp 之后调用,存在极小的精度偏差(<0.01%),实际无影响。

8. 验证方式

  1. 配置 TRADING_OPEN_ORDER_TYPE=limit,观察日志中 信号价格约束生效 输出
  2. 对比约束前后的限价:日志中显示 L2=$X → 约束后=$Y
  3. 检查 Leg B 预检查的估算值是否使用了 clamped 价格(通过估算值日志确认)
  4. 通过 TRADING_SIGNAL_PRICE_CLAMP_ENABLED=false 确认可关闭,恢复纯 L2 定价
  5. 制造高偏差场景,确认 WARNING 日志 信号价格偏差过大 正常输出

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