第 3 章 · 02 populateindicators 计算指标 本节摘要:策略三步走的第一步——把原始 OHLCV 数据加工成技术指标。本节讲透 的职责与套路:输入是什么、要做什么、返回什么;然后实打实地用 TA-Lib( )与 计算四类常用指标——趋势类(SMA/EMA/TEMA)、震荡类(RSI/MFI)、能量类(MACD)、统计类(布林带),并挂回 DataFrame 列。读完本节,你能给任意策略添加任意常用指标,并理解每一类指标在 DataFrame 上长什么样。 内容来源:原项目源码 、文档 ,汉化并套用体系化模板。 学习目标 阅读完本节,你应当能够: 说清 的输入、职责、输出与禁忌。 用 计算 SMA、EMA、TEMA、RSI、MFI、MACD、ADX、SAR。
本节摘要:策略三步走的第一步——把原始 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,汉化并套用体系化模板。
阅读完本节,你应当能够:
populate_indicators 的输入、职责、输出与禁忌。talib.abstract as ta 计算 SMA、EMA、TEMA、RSI、MFI、MACD、ADX、SAR。qtpylib.bollinger_bands 计算布林带(上下中三轨)。def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: ... return dataframe
dataframe:当前交易对的 OHLCV 数据,基础列为 date、open、high、low、close、volume,外加 buy/sell(旧版,新版不用)。metadata:字典,含 pair(交易对名,如 "ETH/USDT")。💡 核心心法:指标计算是纯函数——输入是 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
理由:
⚠️ 从 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)
用法:
震荡指标衡量「超买/超卖」,在 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 = 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 减小)预示大行情要来。
注意一个细节: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,实际建议设得更大(给信号留缓冲)。
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 就用这些列拼买入条件。
SMA(等权,滞后)、EMA(加权,灵敏)、TEMA(三重平滑,最灵敏)、SAR(反转点)。RSI 只看价格、MFI 加入成交量,经典区间 >70 超买、<30 超卖。macd 是快慢均线之差,与 macdsignal 的金叉/死叉是经典动量信号。qtpylib.bollinger_bands 输出上中下三轨,带子收口预示波动率放大。startup_candle_count 必须 ≥ 最长指标周期。下一节,我们用这些指标拼出入场与出场信号——
populate_entry_trend与populate_exit_trend的列约定与条件组合。