""" MACD 趋势跟踪策略 策略逻辑: - 当 MACD 线上穿信号线时 (金叉),且价格 > EMA 时,买入 - 当 MACD 线下穿信号线时 (死叉),或价格 < EMA 时,卖出 指标计算: - MACD(10, 20, 9): 快线 10 日,慢线 20 日,信号线 9 日 - EMA: 200 日指数移动平均线(趋势确认) 参数选择理由: - 快线 10: 比标准 12 更敏感,适应 A 股较高波动性 - 慢线 20: 比标准 26 更快响应,同时保持趋势跟踪稳定性 - 信号线 9: 保持标准,避免信号过于频繁 - EMA: 被广泛认可为牛熊分界线,避免逆势交易 趋势过滤: - EMA 上方: 确认为上升趋势,允许开多仓 - EMA 下方: 确认为下降趋势,不开多仓,强制平仓 Author: Sisyphus Date: 2025-01-27 """ from backtesting import Strategy from backtesting.lib import crossover def calculate_indicators(data): """ 计算策略所需的技术指标 使用 ta-lib 库计算 MACD 和 EMA 指标 参数: data: DataFrame, 包含 [Open, High, Low, Close, Volume, factor] 返回: DataFrame, 添加了指标列: - macd: MACD 线 (macd) - signal: MACD 信号线 (DEA) - hist: MACD 柱状图 (Histogram) - ema: 日指数移动平均线 """ data = data.copy() # 计算 MACD 指标 (10, 20, 9) # talib.MACD 返回三个值: (macd, macdsignal, macdhist) macd, macdsignal, macdhist = talib.MACD(data["Close"], fastperiod=10, slowperiod=20, signalperiod=9) data["macd"] = macd data["signal"] = macdsignal data["hist"] = macdhist # 计算 EMA 趋势线 data["ema"] = talib.SMA(data["Close"], timeperiod=120) return data def get_strategy(): """ 返回策略类 返回: MacdTrendStrategy 类 """ return MacdTrendStrategy class MacdTrendStrategy(Strategy): """ MACD 趋势跟踪策略 结合 MACD 金叉/死叉信号和 EMA 趋势过滤 参数: fast_period: MACD 快线周期 (默认: 10) slow_period: MACD 慢线周期 (默认: 20) signal_period: MACD 信号线周期 (默认: 9) """ # 可配置参数 fast_period = 10 slow_period = 20 signal_period = 9 def init(self): """ 初始化策略 注册指标到 backtesting 框架 """ # 注册 MACD 线 self.macd = self.I(lambda x: x, self.data.macd) # 注册 MACD 信号线 self.signal = self.I(lambda x: x, self.data.signal) # 注册 EMA 趋势线 self.ema = self.I(lambda x: x, self.data.ema) def next(self): """ 每个时间步的决策逻辑 买入条件: - MACD 金叉 (MACD 线上穿信号线) - 价格 > EMA (确认上升趋势) 卖出条件: - MACD 死叉 (MACD 线下穿信号线) - 或价格 < EMA (趋势转向,强制平仓) """ # 买入条件: MACD 金叉 AND 价格 > EMA if crossover(self.macd, self.signal) and self.data.Close[-1] > self.ema[-1]: self.buy() # 开多仓 # 卖出条件: MACD 死叉 OR 价格 < EMA elif self.position.size > 0 and (crossover(self.signal, self.macd) or self.data.Close[-1] < self.ema[-1]): self.position.close() # 平掉多仓 # 导入 talib (必须在文件末尾,因为 calculate_indicators 函数中使用了 talib) import talib