第 3 章 · 02 populate_indicators 计算指标


文档摘要

第 3 章 · 02 populateindicators 计算指标 本节摘要:策略三步走的第一步——把原始 OHLCV 数据加工成技术指标。本节讲透 的职责与套路:输入是什么、要做什么、返回什么;然后实打实地用 TA-Lib( )与 计算四类常用指标——趋势类(SMA/EMA/TEMA)、震荡类(RSI/MFI)、能量类(MACD)、统计类(布林带),并挂回 DataFrame 列。读完本节,你能给任意策略添加任意常用指标,并理解每一类指标在 DataFrame 上长什么样。 内容来源:原项目源码 、文档 ,汉化并套用体系化模板。 学习目标 阅读完本节,你应当能够: 说清 的输入、职责、输出与禁忌。 用 计算 SMA、EMA、TEMA、RSI、MFI、MACD、ADX、SAR。

第 3 章 · 02 populate_indicators 计算指标

本节摘要:策略三步走的第一步——把原始 OHLCV 数据加工成技术指标。本节讲透 populate_indicators 的职责与套路:输入是什么、要做什么、返回什么;然后实打实地用 TA-Lib(talib.abstract as ta)与 technical.util.qtpylib 计算四类常用指标——趋势类(SMA/EMA/TEMA)、震荡类(RSI/MFI)、能量类(MACD)、统计类(布林带),并挂回 DataFrame 列。读完本节,你能给任意策略添加任意常用指标,并理解每一类指标在 DataFrame 上长什么样。

内容来源:原项目源码 freqtrade/templates/sample_strategy.py、文档 docs/strategy-101.md,汉化并套用体系化模板。

学习目标

阅读完本节,你应当能够:

  1. 说清 populate_indicators输入、职责、输出禁忌
  2. talib.abstract as ta 计算 SMA、EMA、TEMA、RSI、MFI、MACD、ADX、SAR
  3. qtpylib.bollinger_bands 计算布林带(上下中三轨)。
  4. 理解 DataFrame 列式语义:每一行就是一根 K 线,指标列是该根 K 线时刻的指标值。
  5. 遵守 「只算策略用到的」性能铁律
  6. 处理 NaN 与 startup_candle_count 的关系。

一、方法的输入输出

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: ... return dataframe
  • 输入 dataframe:当前交易对的 OHLCV 数据,基础列为 dateopenhighlowclosevolume,外加 buy/sell(旧版,新版不用)。
  • 输入 metadata:字典,含 pair(交易对名,如 "ETH/USDT")。
  • 职责:在这个 DataFrame 上新增列,把各类技术指标算出来挂上去。
  • 输出:返回加了指标列的 DataFrame。

💡 核心心法:指标计算是纯函数——输入是 OHLCV,输出是加了列的 DataFrame,不要在这里读写外部状态(数据库、文件、网络)。每个对、每根 K 线都会调用它,性能极敏感。

二、性能铁律:只算你用到的

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # ❌ 错误:把 sample_strategy 里的几十个指标全部算上 # ✅ 正确:只算你 populate_entry_trend / populate_exit_trend 真正引用的列 dataframe["rsi"] = ta.RSI(dataframe) return dataframe

理由:

  • 每个对、每次 K 线刷新都会算一遍;几十个无用指标会让回测慢 10 倍、实盘 CPU 飙满。
  • sample_strategy.py 里注释掉那么多指标,正是这个原因——它们是「目录」不是「清单」。

⚠️ 从 sample_strategy 复制的常见坑:新手把所有注释的指标都打开「以防万一」,结果回测一晚没跑完。打开 populate_indicators 前,先决定 populate_entry_trend 里要哪些列,只算那些。

三、趋势类:均线家族

均线是最基础的指标——把过去 N 根 K 线的 close 求平均,得到平滑的趋势线。

import talib.abstract as ta # 简单移动平均(等权) dataframe["sma50"] = ta.SMA(dataframe, timeperiod=50) # 指数移动平均(近期权重更大,反应更快) dataframe["ema21"] = ta.EMA(dataframe, timeperiod=21) # 三重指数移动平均(进一步去噪,趋势更平滑) dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9) # 抛物线 SAR(趋势反转点提示) dataframe["sar"] = ta.SAR(dataframe)

用法:

  • 趋势识别:close 在 SMA50 之上视为多头,之下视为空头。
  • 金叉/死叉:短期均线上穿/下穿长期均线(如 EMA9 × EMA21)。
  • TEMA 比 EMA 更平滑、比 SMA 更灵敏,常被用来替代 close 做信号判断。

四、震荡类:RSI 与 MFI

震荡指标衡量「超买/超卖」,在 0~100 之间波动。

# 相对强弱指数(只看价格) dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14) # 资金流量指数(看价格 + 成交量,更"真实") dataframe["mfi"] = ta.MFI(dataframe, timeperiod=14)

经典解读:

区间 RSI 含义 MFI 含义
> 70 超买,可能回落 资金疯狂涌入
30~70 中性 正常
< 30 超卖,可能反弹 资金撤离

💡 为什么常用 RSI 而非 MFI:RSI 简单、广泛出现在所有教程里;MFI 加入了成交量维度,理论上更可靠,但实战中两者信号高度相关。新人从 RSI 开始。

五、MACD:趋势 + 动量

macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9) dataframe["macd"] = macd["macd"] # MACD 线 dataframe["macdsignal"] = macd["macdsignal"] # 信号线 dataframe["macdhist"] = macd["macdhist"] # 柱状图(MACD - 信号)

含义:

  • macd = 12 日 EMA − 26 日 EMA(快慢均线之差)。
  • macdsignal = macd 的 9 日 EMA。
  • macdhist = macd − macdsignal(柱状图)。

经典用法:macd 上穿 macdsignal(柱状图由负转正)为金叉做多;下穿为死叉做空。

六、布林带:统计波动率

布林带需要先算「典型价格」((high+low+close)/3),再用 qtpylib 算三轨:

from technical import qtpylib # 典型价格 tp = qtpylib.typical_price(dataframe) # 20 周期、2 倍标准差 bollinger = qtpylib.bollinger_bands(tp, window=20, stds=2) dataframe["bb_lowerband"] = bollinger["lower"] dataframe["bb_middleband"] = bollinger["mid"] dataframe["bb_upperband"] = bollinger["upper"]

含义:

  • bb_middleband = 20 周期 SMA(中轨)。
  • bb_upperband = 中轨 + 2σ(上轨)。
  • bb_lowerband = 中轨 − 2σ(下轨)。

经典用法:价格触及下轨视为超卖(可能反弹),触及上轨视为超买(可能回落);带子收口(bb_width 减小)预示大行情要来。

七、NaN 与 startup_candle_count

注意一个细节:200 周期的 SMA,前 199 行都是 NaN(数据不够)。如果策略在这些 NaN 行上做判断,会得到错误信号。这就是 IStrategy 类属性 startup_candle_count 的作用(第 01 节已讲):

class MyStrategy(IStrategy): startup_candle_count: int = 200 # ← 我最长指标是 SMA200,设 200

引擎会忽略每段数据前 startup_candle_count 根 K 线,确保指标热身完成。

⚠️ 规则:startup_candle_count 必须 ≥ 你用到的最长指标的周期数。用了 SMA200 就设 200,用了 RSI14 至少设 14,实际建议设得更大(给信号留缓冲)。

八、一段完整的 populate_indicators

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # 动量 dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14) dataframe["mfi"] = ta.MFI(dataframe) dataframe["adx"] = ta.ADX(dataframe) # 趋势 dataframe["ema21"] = ta.EMA(dataframe, timeperiod=21) dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9) dataframe["sar"] = ta.SAR(dataframe) # MACD macd = ta.MACD(dataframe) dataframe["macd"] = macd["macd"] dataframe["macdsignal"] = macd["macdsignal"] # 布林带 bb = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) dataframe["bb_lowerband"] = bb["lower"] dataframe["bb_middleband"] = bb["mid"] dataframe["bb_upperband"] = bb["upper"] return dataframe

这段计算了 5 类指标,挂了 10+ 个列。后续 populate_entry_trend 就用这些列拼买入条件。

本节要点回顾

  1. 方法签名:输入 OHLCV DataFrame + metadata,输出加指标列的 DataFrame;只算指标、不加信号。
  2. 性能铁律:只算策略真正引用的列;sample_strategy 的注释指标是「目录」不是「清单」。
  3. 趋势类:SMA(等权,滞后)、EMA(加权,灵敏)、TEMA(三重平滑,最灵敏)、SAR(反转点)。
  4. 震荡类:RSI 只看价格、MFI 加入成交量,经典区间 >70 超买、<30 超卖。
  5. MACD:macd 是快慢均线之差,与 macdsignal 的金叉/死叉是经典动量信号。
  6. 布林带:qtpylib.bollinger_bands 输出上中下三轨,带子收口预示波动率放大。
  7. NaN 处理:长周期指标前 N 行是 NaN,startup_candle_count 必须 ≥ 最长指标周期。

下一节,我们用这些指标拼出入场与出场信号——populate_entry_trendpopulate_exit_trend 的列约定与条件组合。


发布者: 作者: 灏天文库 转发
评论区 (0)
U