开仓动量过滤器设计方案

开仓动量过滤器设计方案

版本:v1.0
日期:2026-03-06
适用系统:Hyperliquid 量化交易系统(Adaptive Bollinger Z-Score 配对策略)


目录

  1. 背景与问题定义
  2. 算法选择与理由
  3. 算法具体实现
  4. 融入当前交易体系的方案
  5. 与当前交易风格的契合度分析
  6. 与四项开单约束的对应关系
  7. 参数配置指南
  8. 风险与局限性

1. 背景与问题定义

1.1 交易系统现状

当前系统基于 Adaptive Bollinger Z-Score 配对策略,核心逻辑是协整对的 spread 均值回归:

  • adaptive_z 突破 adaptive_threshold 时产生入场信号
  • adaptive_z 回归至 entry_adaptive_z * reversion_factor 时平仓
  • 使用 1-5 分钟 K 线,最大持仓时间控制在 30 分钟以内

1.2 待解决的问题

均值回归策略在以下场景存在明显风险:

场景 问题 后果
单边持续上涨 N 根 K 线后 追涨做多(跟趋势入场) 趋势已过度延伸,极易被反转砸穿
单边持续下跌 N 根 K 线后 追跌做空(跟趋势入场) 跌幅充分释放,反弹风险极高
短时间内迅速暴涨 做空对抗强动量 被轧空,止损代价极大
短时间内迅速暴跌 做多接飞刀 继续下杀,止损代价极大

1.3 四项约束目标

约束 1:连续下跌 → 不追跌(不做空)
约束 2:连续上涨 → 不追涨(不做多)
约束 3:迅速暴涨 → 不做空
约束 4:迅速暴跌 → 不做多

2. 算法选择与理由

2.1 约束 1&2:持续单边行情过滤

候选算法对比

算法 适合周期 优点 缺点 1-5min 适用性
连续 K 线计数 中长周期 直观 1-5min 噪音大,交替涨跌频繁,容易漏判 不适合
ADX + DMI 中周期 学术验证充分 需要完整 OHLCV,计算量较大,参数较多 一般
N 根 K 线净位移 短周期 捕捉净方向,对噪音免疫 最适合
EMA 方向 短周期 平滑 滞后较大 一般

选择:N 根 K 线净位移(Net Displacement)

核心公式:

N = max_hold_minutes / candle_period_minutes
  = 30 / 1  = 30 根(1分钟K线)
  = 30 / 5  = 6  根(5分钟K线)

net_return = (close[-1] - close[-N]) / close[-N]

约束1 触发:direction == 'short' AND net_return <= -sustained_threshold
约束2 触发:direction == 'long'  AND net_return >= +sustained_threshold

选择原因:

  1. 对 1-5min 噪音免疫:1 分钟 K 线经常出现 +1/-1/+1/-1 交替,纯计数无法准确判断趋势。净位移只看"起点到终点",中间震荡不影响结果。

  2. 时间窗口与持仓时间对齐:N = max_hold_minutes / candle_period,过滤的时间范围恰好等于最大持仓周期,语义一致:「过去 30 分钟内」单边幅度是否过大。

  3. 无需预热:不依赖历史统计分布,只需 N 根 K 线历史即可工作,系统启动后很快就能生效。

  4. 参数直接可解释sustained_threshold = 0.8% 意味着「过去 30 分钟内净涨/跌幅超过 0.8% 则判定为持续单边」,可以直接对照行情校准。

2.2 约束 3&4:急涨急跌过滤

候选算法对比

算法 核心思路 优点 缺点 1-5min 适用性
固定百分比阈值 单根 K 线涨幅 > X% 最简单 加密货币波动率变化大,高波动期误杀太多 一般
Z-Score of Returns 滚动分布标准化 自适应 需要 50+ 根历史才稳定(50 分钟预热) 一般
ATR 倍数 单根 K 线涨幅 vs 近期 ATR 自适应波动率,无需大量历史 需 high/low 数据(可降级用 close) 最适合

选择:短期 ATR 倍数(ATR Multiple)

核心公式:

ATR(period=10) = 近 10 根 K 线的平均真实波幅
True Range(i) = max(high-low, |high-close_prev|, |low-close_prev|)

candle_return = (close[-1] - close[-2]) / close[-2]
spike_threshold_pct = spike_k * ATR(10) / close[-1]

约束3 触发:direction == 'short' AND 近 spike_lookback 根K线内存在 candle_return >= +spike_threshold_pct
约束4 触发:direction == 'long'  AND 近 spike_lookback 根K线内存在 candle_return <= -spike_threshold_pct

选择原因:

  1. 自适应波动率:加密货币在不同时段(亚盘/美盘/重大事件)波动率差异 3-5 倍。固定百分比会在低波动期过于宽松、高波动期过于严格。ATR(10) 在 1-5 分钟周期约为 10-50 分钟的滚动波幅,响应足够灵敏。

  2. 预热时间短:只需 10 根 K 线即可计算(vs Z-score 需要 50+),系统启动后 10-50 分钟内生效。

  3. spike_lookback 设计:检查最近 1-2 根 K 线,确保捕捉"刚刚发生"的急动,而非几分钟前的历史。

  4. 有 high/low 时更精确:当系统提供完整 OHLCV 时自动使用 True Range;仅有 close 时降级为 close-to-close 差,保证向下兼容。

2.3 算法组合逻辑

两类过滤器相互独立、串联运行:

净位移过滤(约束1&2)→ ATR急动过滤(约束3&4)→ 均通过则允许入场

两个过滤器覆盖不同时间尺度的风险:

  • 净位移:过去 30 分钟的"趋势是否已过度延伸"(中时间尺度)
  • ATR急动:最近 1-2 根 K 线是否有"暴力冲击"(极短时间尺度)

3. 算法具体实现

3.1 模块位置

src/trading/
  momentum_filter.py    ← 新建(独立模块,不耦合策略逻辑)
  strategy.py           ← 修改 _check_entry(),注入并调用 filter
  config.py             ← 修改 StrategyParams,新增过滤器参数

3.2 MomentumFilter 完整代码

# src/trading/momentum_filter.py
"""
开仓动量过滤器

实现四项开单约束:
  约束1:连续下跌不追跌(不做空)  → 净位移 < -threshold
  约束2:连续上涨不追涨(不做多)  → 净位移 > +threshold
  约束3:迅速暴涨不做空            → 单根K线涨幅 > spike_k * ATR
  约束4:迅速暴跌不做多            → 单根K线跌幅 > spike_k * ATR

设计原则:
  - 按 symbol(单腿)维度过滤,与配对逻辑解耦
  - 无外部依赖,仅需 close/high/low 序列
  - 数据不足时默认放行(安全降级)
"""

from collections import deque


class MomentumFilter:

    def __init__(
        self,
        candle_period_minutes: int = 1,
        max_hold_minutes: int = 30,
        sustained_threshold: float = 0.008,
        spike_atr_multiple: float = 2.5,
        spike_atr_period: int = 10,
        spike_lookback: int = 2,
        enabled: bool = True,
    ):
        """
        Args:
            candle_period_minutes:  K线周期(分钟),用于计算净位移回望根数
            max_hold_minutes:       最大持仓时间(分钟),决定净位移窗口大小
            sustained_threshold:    净位移阈值(小数,0.008=0.8%)
            spike_atr_multiple:     急动检测:单根涨幅 > k * ATR(period)
            spike_atr_period:       ATR计算周期(根数)
            spike_lookback:         检查最近几根K线内是否有急动(1-3)
            enabled:                总开关,False时所有check直接放行
        """
        self._enabled = enabled
        self._sustained_n = max(3, max_hold_minutes // max(1, candle_period_minutes))
        self._sustained_thresh = sustained_threshold
        self._spike_k = spike_atr_multiple
        self._atr_period = spike_atr_period
        self._spike_lookback = spike_lookback

        buf_size = self._sustained_n + spike_atr_period + spike_lookback + 5
        # symbol → deque of (close, high, low)
        self._buffers: dict[str, deque] = {}
        self._buf_size = buf_size

    # ------------------------------------------------------------------
    # 公开接口
    # ------------------------------------------------------------------

    def update(self, symbol: str, close: float, high: float = 0.0, low: float = 0.0):
        """
        每根新K线收盘时调用。
        high/low 可选;有则 ATR 更精确,无则降级为 close-to-close。
        """
        if symbol not in self._buffers:
            self._buffers[symbol] = deque(maxlen=self._buf_size)
        self._buffers[symbol].append((close, high, low))

    def check(self, symbol: str, direction: str) -> tuple[bool, str]:
        """
        检查 direction 方向的入场是否被动量过滤器阻止。

        Args:
            symbol:    目标 coin(单腿,非配对)
            direction: 'long' 或 'short'

        Returns:
            (allowed: bool, reason: str)
            allowed=False 表示该方向被阻止,reason 为拒绝原因
        """
        if not self._enabled:
            return True, ""

        buf = self._buffers.get(symbol)
        min_required = max(self._sustained_n + 2, self._atr_period + self._spike_lookback + 2)
        if buf is None or len(buf) < min_required:
            return True, ""  # 数据不足,安全放行

        data = list(buf)
        closes = [d[0] for d in data]
        highs  = [d[1] for d in data]
        lows   = [d[2] for d in data]

        # 约束 1&2:净位移过滤
        ok, reason = self._check_sustained(closes, direction)
        if not ok:
            return False, reason

        # 约束 3&4:急动过滤
        ok, reason = self._check_spike(closes, highs, lows, direction)
        if not ok:
            return False, reason

        return True, ""

    def ready(self, symbol: str) -> bool:
        """该 symbol 是否已积累足够数据"""
        buf = self._buffers.get(symbol)
        if buf is None:
            return False
        min_required = max(self._sustained_n + 2, self._atr_period + self._spike_lookback + 2)
        return len(buf) >= min_required

    # ------------------------------------------------------------------
    # 内部实现
    # ------------------------------------------------------------------

    def _check_sustained(self, closes: list, direction: str) -> tuple[bool, str]:
        """
        约束1&2:过去 sustained_n 根K线的净位移过滤。

        逻辑:
          净位移 <= -threshold → 市场已持续下跌 → 拒绝 short(不追跌)
          净位移 >= +threshold → 市场已持续上涨 → 拒绝 long(不追涨)
        """
        n = self._sustained_n
        if len(closes) < n + 1:
            return True, ""

        ref = closes[-n - 1]
        if ref <= 0:
            return True, ""

        net_return = (closes[-1] - ref) / ref

        if direction == 'short' and net_return <= -self._sustained_thresh:
            return False, (
                f"约束1-不追跌: 过去{n}根净跌幅={net_return:.2%}"
                f" <= -{self._sustained_thresh:.2%}"
            )
        if direction == 'long' and net_return >= self._sustained_thresh:
            return False, (
                f"约束2-不追涨: 过去{n}根净涨幅={net_return:.2%}"
                f" >= +{self._sustained_thresh:.2%}"
            )
        return True, ""

    def _check_spike(
        self, closes: list, highs: list, lows: list, direction: str
    ) -> tuple[bool, str]:
        """
        约束3&4:最近 spike_lookback 根K线内是否发生急涨/急跌。

        逻辑:
          任意一根 candle_return >= +spike_k*ATR → 急涨 → 拒绝 short
          任意一根 candle_return <= -spike_k*ATR → 急跌 → 拒绝 long
        """
        atr = self._calc_atr(closes, highs, lows, self._atr_period)
        if atr <= 0 or closes[-1] <= 0:
            return True, ""

        spike_pct = self._spike_k * atr / closes[-1]

        for i in range(-1, -1 - self._spike_lookback, -1):
            idx = len(closes) + i
            if idx < 1:
                break
            prev = closes[idx - 1]
            if prev <= 0:
                continue
            candle_ret = (closes[idx] - prev) / prev

            if direction == 'short' and candle_ret >= spike_pct:
                return False, (
                    f"约束3-暴涨不做空: 第{abs(i)}根涨幅={candle_ret:.2%}"
                    f" >= {self._spike_k}×ATR={spike_pct:.2%}"
                )
            if direction == 'long' and candle_ret <= -spike_pct:
                return False, (
                    f"约束4-暴跌不做多: 第{abs(i)}根跌幅={candle_ret:.2%}"
                    f" <= -{self._spike_k}×ATR={spike_pct:.2%}"
                )

        return True, ""

    @staticmethod
    def _calc_atr(closes: list, highs: list, lows: list, period: int) -> float:
        """
        计算 ATR(period)。
        有 high/low 时使用 True Range,否则降级为 close-to-close 差。
        """
        trs = []
        start = max(1, len(closes) - period)
        for i in range(start, len(closes)):
            prev_c = closes[i - 1]
            h = highs[i]
            l = lows[i]
            if h > 0 and l > 0 and prev_c > 0:
                tr = max(h - l, abs(h - prev_c), abs(l - prev_c))
            elif prev_c > 0:
                tr = abs(closes[i] - prev_c)
            else:
                continue
            trs.append(tr)

        return sum(trs) / len(trs) if trs else 0.0

3.3 StrategyParams 新增字段

src/trading/config.pyStrategyParams 中新增:

@dataclass(frozen=True)
class StrategyParams:
    # ... 现有字段 ...

    # 动量过滤器参数
    momentum_filter_enabled: bool = True
    momentum_candle_period_minutes: int = 1       # K线周期(分钟)
    momentum_max_hold_minutes: int = 30            # 最大持仓时间(分钟),决定净位移窗口
    momentum_sustained_threshold: float = 0.008   # 净位移阈值(0.8%)
    momentum_spike_atr_multiple: float = 2.5       # 急动检测:N倍ATR
    momentum_spike_atr_period: int = 10            # ATR计算周期
    momentum_spike_lookback: int = 2               # 检查最近N根K线有无急动

3.4 strategy.py 集成改动

AdaptiveBollingerStrategy.__init__() 中初始化:

from src.trading.momentum_filter import MomentumFilter

class AdaptiveBollingerStrategy:
    def __init__(self, config: TradingConfig):
        # ... 现有初始化 ...

        # 动量过滤器(symbol 维度,非配对维度)
        default_p = self._params_for("")
        self._momentum_filter = MomentumFilter(
            candle_period_minutes=default_p.momentum_candle_period_minutes,
            max_hold_minutes=default_p.momentum_max_hold_minutes,
            sustained_threshold=default_p.momentum_sustained_threshold,
            spike_atr_multiple=default_p.momentum_spike_atr_multiple,
            spike_atr_period=default_p.momentum_spike_atr_period,
            spike_lookback=default_p.momentum_spike_lookback,
            enabled=default_p.momentum_filter_enabled,
        ) if default_p.momentum_filter_enabled else None

process_tick() 中新增 open_ / high / low 参数,并调用 update()

def process_tick(
    self,
    symbol: str,
    base_symbol: str,
    z4h: float,
    timestamp: datetime,
    kline_time: datetime | None = None,
    latest_price: float | None = None,
    kline_open: float | None = None,    # 新增
    kline_high: float | None = None,    # 新增
    kline_low: float | None = None,     # 新增
    kline_close: float | None = None,   # 新增(等同 latest_price,但语义更明确)
) -> tuple[EntrySignal | None, ExitSignal | None]:
    # 新K线时更新动量过滤器
    if is_new_candle and self._momentum_filter and kline_close:
        close = kline_close or latest_price or 0.0
        self._momentum_filter.update(
            symbol=symbol,
            close=close,
            high=kline_high or 0.0,
            low=kline_low or 0.0,
        )

_check_entry() 步骤 4(z4h 过滤)之后、步骤 5(方向判断)之前插入:

def _check_entry(self, key, z4h, adaptive_z, timestamp, current_above, params):
    # ... 步骤 1-4(冷却期、突破检测、持仓检查、z4h 过滤) ...

    # 步骤 4.5:动量过滤(四项开单约束)
    if self._momentum_filter and self._momentum_filter.ready(key[0]):
        # 提前确定方向(用于过滤器检查)
        threshold = params.adaptive_threshold
        if adaptive_z < -threshold:
            proposed_direction = 'long'
        elif adaptive_z > threshold:
            proposed_direction = 'short'
        else:
            return None  # 不在阈值范围,不产生信号

        allowed, reason = self._momentum_filter.check(key[0], proposed_direction)
        if not allowed:
            logger.info(f"🚫 动量过滤 | {pair_label} | {reason}")
            return None

    # 步骤 5:方向判断(原有逻辑)
    # ...

4. 融入当前交易体系的方案

4.1 数据流全景

WebSocket K线推送
      |
      v
realtime_kline_service(1min/5min 原始 OHLCV)
      |
      v  process_tick(z4h, close, high, low, open)
      |
AdaptiveBollingerStrategy
      |
      +-- [新K线] MomentumFilter.update(symbol, close, high, low)
      |
      +-- _check_exit()  → ExitSignal
      |
      +-- _check_entry()
              |
              步骤1: 冷却期
              步骤2: 突破检测(adaptive_z 首次穿越阈值)
              步骤3: 持仓检查
              步骤4: z4h 绝对值过滤
         [新增]
              步骤4.5: MomentumFilter.check(symbol, direction)
                        ├── 约束1&2: 净位移过滤
                        └── 约束3&4: ATR急动过滤
              步骤5: 产生 EntrySignal
      |
      v
TradingOrchestrator.on_entry_signal()
      |
      v
RiskManager.pre_trade_check()(现有9项风控)
      |
      v
HyperliquidExecutor.open_position()

4.2 改动范围最小化原则

改动文件 改动内容 改动量
src/trading/momentum_filter.py 新建,独立模块 ~130 行
src/trading/strategy.py __init__ 注入,process_tick 新增参数,_check_entry 插入步骤4.5 ~25 行
src/trading/config.py StrategyParams 新增 7 个字段(带默认值) ~10 行
src/services/realtime_kline_service_base.py process_tick 调用处透传 OHLCV ~5 行

不需要改动:

  • orchestrator.py(无感知)
  • risk_manager.py(过滤在上游完成)
  • executor.py(无感知)
  • models.py(无感知)
  • 数据库 schema(无需持久化过滤器状态)

4.3 配置层集成

StrategyParams 增加带默认值的字段,支持全局默认 + 按 symbol 覆盖 + 按 pair 覆盖,与现有参数覆盖体系完全一致。

环境变量示例:

# 全局动量过滤器配置
TRADING_MOMENTUM_FILTER_ENABLED=true
TRADING_MOMENTUM_CANDLE_PERIOD_MINUTES=1
TRADING_MOMENTUM_MAX_HOLD_MINUTES=30
TRADING_MOMENTUM_SUSTAINED_THRESHOLD=0.008
TRADING_MOMENTUM_SPIKE_ATR_MULTIPLE=2.5
TRADING_MOMENTUM_SPIKE_ATR_PERIOD=10
TRADING_MOMENTUM_SPIKE_LOOKBACK=2

# 针对特定高波动 symbol 放宽阈值(示例)
TRADING_STRATEGY_OVERRIDE_SYMBOLS=BTC,SOL
TRADING_STRATEGY_BTC_MOMENTUM_SUSTAINED_THRESHOLD=0.012
TRADING_STRATEGY_SOL_MOMENTUM_SPIKE_ATR_MULTIPLE=3.0

4.4 线程安全

MomentumFilter 不持有锁,由 AdaptiveBollingerStrategy_lock(已存在)统一保护。update()check() 均在 _lock 的持有范围内调用,无竞态风险。

4.5 日志集成

拒绝入场时使用 INFO 级别(与现有入场过滤日志一致):

🚫 动量过滤 | BTC|ETH | 约束1-不追跌: 过去30根净跌幅=-1.23% <= -0.80%
🚫 动量过滤 | SOL|BTC | 约束3-暴涨不做空: 第1根涨幅=1.85% >= 2.5×ATR=1.20%

5. 与当前交易风格的契合度分析

5.1 交易风格特征

维度 当前系统特征
策略类型 配对协整均值回归
K线周期 1-5 分钟
最大持仓时间 30 分钟
入场逻辑 adaptive_z 突破阈值(非连续信号,要求首次穿越)
出场逻辑 adaptive_z 回归至 entry_adaptive_z × reversion_factor
已有风控 止损、移动止损、最大回撤、每日亏损限额、冷却期、熔断器

5.2 契合度分析

高度契合之处:

  1. 时间窗口对齐:净位移窗口 N = max_hold_minutes / candle_period,与策略的最大持仓时间语义一致——过滤的是「持仓期间内」可能影响均值回归的单边趋势。

  2. 信号层级匹配:过滤器在 _check_entry() 内执行,与现有的 z4h 过滤、冷却期等并列,均属于「信号层」过滤,而非「风控层」拒绝。逻辑层次清晰。

  3. 均值回归哲学一致:均值回归策略本身就假设「偏离终将回归」。动量过滤器在此基础上增加一个判断:「确实是偏离,但偏离是否仍在单边趋势的惯性中?」——只有趋势动量已衰减,均值回归才更可靠。

  4. 独立模块不影响出场:过滤器只影响入场判断,对 _check_exit() 和止损逻辑完全不干预,已有持仓的管理不受影响。

  5. symbol 维度 vs 配对维度:过滤器在 symbol 单腿维度工作,与策略引擎的 PairKey 维度正交,不干扰多配对并发运行。

潜在张力(需注意):

  • 均值回归策略逻辑上倾向于在"趋势最强的时候入场"(z4h 偏离最大),而动量过滤器会在此时压制部分信号。这是有意为之的权衡:宁可少开几单,不要开在动量最猛的那一刻

5.3 综合评分

维度 评分 说明
时间尺度匹配 ★★★★★ 窗口大小与持仓时间严格对齐
代码侵入性 ★★★★★ 独立模块,改动集中,可独立关闭
运行效率 ★★★★★ O(N) 线性计算,无数据库依赖
参数可控性 ★★★★☆ 全部走环境变量,支持 symbol 级覆盖
策略哲学一致性 ★★★★☆ 与均值回归核心逻辑方向一致,有合理张力

6. 与四项开单约束的对应关系

6.1 逐项验证

约束 1:连续下跌不追跌

触发条件:net_return(过去N根) <= -sustained_threshold
被阻止:direction == 'short'
原因:市场已持续下跌,跌幅充分释放,继续做空空间有限且反弹风险高

示例(1min K线,N=30,threshold=0.8%):

  • 过去 30 分钟从 100 跌到 99(净跌 1%)→ 拒绝做空 ✓
  • 过去 30 分钟震荡,净位移 -0.3%(低于阈值)→ 允许做空 ✓

约束 2:连续上涨不追涨

触发条件:net_return(过去N根) >= +sustained_threshold
被阻止:direction == 'long'
原因:市场已持续上涨,涨幅过度延伸,继续做多风险极高

示例(1min K线,N=30,threshold=0.8%):

  • 过去 30 分钟从 100 涨到 101.2(净涨 1.2%)→ 拒绝做多 ✓
  • 过去 30 分钟震荡,净位移 +0.5% → 允许做多 ✓

约束 3:迅速暴涨不做空

触发条件:任意近spike_lookback根K线的 candle_return >= spike_k * ATR(10)
被阻止:direction == 'short'
原因:刚刚发生的急涨说明多方动量极强,做空极易被轧空

示例(spike_k=2.5,ATR≈0.5%,spike_threshold≈1.25%):

  • 最近一根K线涨了 1.8%(> 2.5 × 0.5%)→ 拒绝做空 ✓
  • 最近一根K线涨了 0.6%(< 2.5 × 0.5%)→ 允许做空 ✓

约束 4:迅速暴跌不做多

触发条件:任意近spike_lookback根K线的 candle_return <= -(spike_k * ATR(10))
被阻止:direction == 'long'
原因:刚刚发生的急跌说明空方动量极强,做多极易被继续砸穿

示例(spike_k=2.5,ATR≈0.5%,spike_threshold≈1.25%):

  • 最近一根K线跌了 2.1%(> 2.5 × 0.5%)→ 拒绝做多 ✓
  • 最近一根K线跌了 0.4% → 允许做多 ✓

6.2 约束覆盖矩阵

约束 过滤器 触发指标 被阻止方向 正确性
1. 连续下跌不追跌 净位移 net_return <= -T short
2. 连续上涨不追涨 净位移 net_return >= +T long
3. 迅速暴涨不做空 ATR急动 candle_ret >= +k*ATR short
4. 迅速暴跌不做多 ATR急动 candle_ret <= -k*ATR long

四项约束完全覆盖,无遗漏,无逻辑矛盾。


7. 参数配置指南

7.1 基础参数推荐值

参数 1分钟K线 5分钟K线 说明
candle_period_minutes 1 5 必须与实际K线周期匹配
max_hold_minutes 30 30 决定净位移窗口(N根)
sustained_n(自动计算) 30 根 6 根 = max_hold / period
sustained_threshold 0.8% 1.5% 5min波动更大,阈值应更高
spike_atr_period 10 10 10根K线ATR,响应灵敏
spike_atr_multiple 2.5 2.5 单根涨幅超 2.5×ATR = 急动
spike_lookback 2 1 检查最近N根,越短线越小

7.2 参数调优思路

sustained_threshold 调优:

  • 过低(< 0.5%):过于敏感,过多有效信号被过滤
  • 过高(> 2%):过于宽松,无法拦截真正的单边行情
  • 建议:用历史 30min 滚动净位移的 60th-70th 百分位作为初始值

spike_atr_multiple 调优:

  • 过低(< 2.0):高波动期频繁误杀
  • 过高(> 4.0):只拦截极端行情,日常急动漏过
  • 建议:从 2.5 开始,观察被拦截的信号与实际行情对应关系

回测验证建议:

对比两组回测结果:
  A 组:无动量过滤(当前)
  B 组:开启动量过滤(本方案)

对比指标:
  - Sharpe Ratio(风险调整收益)
  - 最大连续亏损次数
  - 平均单笔盈亏比(W/L Ratio)
  - 信号数量减少比例(过滤率)

8. 风险与局限性

8.1 已知局限

局限 说明 缓解措施
数据预热期 启动后需积累 N+ATR_period 根K线才生效(1min约40根=40分钟) 启动时使用历史K线预填充 buffer
单腿视角 只看 symbol 单腿价格,不考虑 spread 的方向性 可后续扩展为 spread 净位移过滤
参数静态 sustained_threshold 是固定值,不随波动率变化 可后续升级为 ATR 标准化的自适应阈值
约束 1&2 方向矛盾风险 理论上净位移过滤阻止的正是均值回归应该入场的时机 该矛盾是有意为之的风险减仓,通过回测验证阈值平衡

8.2 不适合的场景

  • 极低流动性资产:ATR 计算可能因价格跳空而失真,需配合黑名单
  • HIP-3 资产:若 K 线数据稀疏,buffer 积累时间更长,预热期更长

8.3 后续迭代方向

  1. spread 净位移:除单腿价格外,同时检查 z4h spread 的净位移方向
  2. 自适应阈值sustained_threshold = k * rolling_daily_vol,随波动率自动调整
  3. 分时段参数:亚盘 / 欧盘 / 美盘使用不同阈值(美盘波动显著更大)
  4. 预填充历史:启动时从 DB 的 klines 表回填近 N 根 K 线,消除预热等待

文档结束

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