""" 动量突破策略。 价格突破 N 日新高 → 买入 价格跌破 N 日均线 → 平仓 """ import pandas as pd from backtest.base import BaseStrategy from backtest.signal import factor_to_threshold_signal class MomentumBreakoutStrategy(BaseStrategy): """动量突破策略。""" category = "trend" def __init__(self, lookback: int = 20, exit_period: int = 10): self.lookback = lookback self.exit_period = exit_period self.name = f"mom_breakout_{lookback}" def generate_signals(self, factor_df: pd.DataFrame) -> pd.Series: if "close" not in factor_df.columns: raise ValueError("factor_df 缺少 'close' 列") close = factor_df["close"] # 买入信号:突破 N 日新高 rolling_high = close.rolling(window=self.lookback, min_periods=self.lookback).max() breakout = close >= rolling_high.shift(1) # 平仓信号:跌破 exit 日均线 exit_ma = close.rolling(window=self.exit_period, min_periods=self.exit_period).mean() signals = pd.Series(0, index=close.index) signals[breakout] = 1 signals[close < exit_ma] = 0 return self._dedup(signals) @staticmethod def _dedup(signals: pd.Series) -> pd.Series: """只保留第一个买入和第一个卖出信号。""" result = signals.copy() prev = -1 for i in range(len(result)): if result.iloc[i] == prev: result.iloc[i] = -1 else: prev = result.iloc[i] return result[result != -1].reindex(signals.index).fillna(-1)