第 4 章 · 01 informative 装饰器与多周期数据 本节摘要:很多稳健策略需要「多周期共振」——用大周期(如 1h)判断趋势,用小周期(如 5m)寻找入场点。freqtrade 提供两种引入辅助数据的机制:基础的 + ,以及更优雅的 装饰器。本节讲透这三者:如何声明要预拉取的辅助对、如何把大周期 DataFrame 合并回小周期 DataFrame、合并后的列命名规则,以及 装饰器的几种用法。读完本节,你能在策略里融合「BTC/USDT 1h 趋势 + 当前对 5m 入场」这类多周期逻辑。 内容来源:原项目文档 ,汉化并套用体系化模板。 学习目标 阅读完本节,你应当能够: 区分辅助数据(informative)与白名单交易对的不同。 用 声明要预拉取的辅助对。
本节摘要:很多稳健策略需要「多周期共振」——用大周期(如 1h)判断趋势,用小周期(如 5m)寻找入场点。freqtrade 提供两种引入辅助数据的机制:基础的
informative_pairs()+merge_informative_pair(),以及更优雅的@informative装饰器。本节讲透这三者:如何声明要预拉取的辅助对、如何把大周期 DataFrame 合并回小周期 DataFrame、合并后的列命名规则,以及@informative装饰器的几种用法。读完本节,你能在策略里融合「BTC/USDT 1h 趋势 + 当前对 5m 入场」这类多周期逻辑。
内容来源:原项目文档
docs/strategy-customization.md,汉化并套用体系化模板。
阅读完本节,你应当能够:
informative_pairs() 声明要预拉取的辅助对。merge_informative_pair() 把大周期数据合并回小周期 DataFrame。column_timeframe 后缀)。@informative 装饰器优雅地生成辅助指标。@informative 同对多周期与辅助币种两种用法。单周期策略有个常见痛点:5m 上的 RSI 信号太频繁,假信号多。一个经典解法是「周期共振」——只在 1h 趋势向上时,才采纳 5m 的做多信号。这就需要在一个策略里同时拿到两个周期的数据。
freqtrade 把「辅助数据」(informative pairs)与「交易对」(whitelist)区分开:
最基础的方式——重写 informative_pairs 方法,返回一个 (pair, timeframe) 元组列表:
def informative_pairs(self): return [ ("BTC/USDT", "1h"), # BTC 1 小时,做大盘趋势参考 ("ETH/USDT", "15m"), # ETH 15 分钟,做板块强弱参考 ]
引擎看到这个声明后,会在主循环里额外为这些组合下载行情并缓存,供你在 populate_indicators 里通过 self.dp.get_pair_dataframe(pair, timeframe) 取用。
💡 声明 ≠ 使用:声明了不取用,只是浪费一点带宽;忘了声明却取用,会拿到空数据或报错。先想好用什么 → 写进
informative_pairs→ 在populate_indicators里取用,三步成环。
辅助数据拉来后,要把大周期的列合并到小周期 DataFrame 上。merge_informative_pair 处理这件麻烦事:
from freqtrade.strategy import merge_informative_pair def populate_indicators(self, dataframe, metadata): # 1. 算 5m 上的指标 dataframe["rsi"] = ta.RSI(dataframe) # 2. 取 BTC 1h 数据 informative = self.dp.get_pair_dataframe("BTC/USDT", "1h") informative["rsi_1h"] = ta.RSI(informative) # 3. 合并到 5m 主 DataFrame dataframe = merge_informative_pair( dataframe, informative, self.timeframe, "1h", ffill=True, ) return dataframe
合并后,DataFrame 会多出 rsi_1h、close_1h、open_1h、date_1h 等列。
合并后的列名 = 原列名 + _ + 时间周期:
| 原列 | 合并后(1h informative) |
|---|---|
close |
close_1h |
rsi_1h(已带后缀) |
rsi_1h_1h(注意双后缀) |
date |
date_1h |
⚠️ 命名冲突坑:如果你在 informative 上算的指标列名已经带
_1h后缀,合并后会变成rsi_1h_1h——可读性差。建议 informative 上的指标不要预先加后缀,让merge_informative_pair自动加。
ffill=True(默认)做「前向填充」——1h 一根 K 线对应 12 根 5m K 线,1h 那根的 RSI 值会被复制到对应区间的所有 5m 行上。没有 ffill 的话,5m 行上的 rsi_1h 大部分是 NaN。
💡 ffill 是关键:没有它,5m 行几乎拿不到 1h 指标(只有每小时对齐那一根有值)。多数场景保持
ffill=True。
手动 get_pair_dataframe + merge_informative_pair 三步走比较啰嗦。@informative 装饰器把这三步自动化——你写一个返回指标 DataFrame 的方法,装饰器自动处理声明、拉取、合并、命名。
from freqtrade.strategy import informative @informative("1h") def populate_indicators_1h(self, dataframe, metadata): dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14) dataframe["ema50"] = ta.EMA(dataframe, timeperiod=50) return dataframe
装饰器会:
("当前对", "1h") 加入 informative_pairs。_1h 后缀(rsi_1h、ema50_1h)。主 populate_indicators 里就可以直接用 dataframe["rsi_1h"] 了。
@informative("1h", "BTC/USDT") def populate_indicators_btc_1h(self, dataframe, metadata): dataframe["rsi"] = ta.RSI(dataframe) return dataframe
这样无论当前策略在跑哪个对,都会拉 BTC/USDT 1h 数据,合并出 rsi_1h_BTC/USDT 列(注意:辅助币的列名会带上币种标识)。
@informative( timeframe="1h", fmt="{base}_{column}_{timeframe}", # 列名格式 ffill=True, ) def populate_indicators_1h(self, dataframe, metadata): ...
fmt 控制列名格式,可用占位符 {base}、{column}、{timeframe}、{quote}、{base}_{quote}。
合并好后,populate_entry_trend 里就能用「共振」条件:
def populate_entry_trend(self, dataframe, metadata): dataframe.loc[ # 5m 信号:RSI 超卖 (qtpylib.crossed_above(dataframe["rsi"], 30)) # 1h 守卫:大周期趋势向上(EMA50 上方) & (dataframe["close_1h"] > dataframe["ema50_1h"]) & (dataframe["rsi_1h"] > 50) & (dataframe["volume"] > 0), "enter_long", ] = 1 return dataframe
含义:5m 出现 RSI 超卖反弹(信号),且 1h 处于多头趋势(close 在 EMA50 上方、RSI 大于 50)——小周期信号被大周期趋势确认。
💡 多周期的本质:不是让信号变多,而是让信号变精——大周期做「方向过滤」,小周期做「时机选择」。胜率通常会显著提升,代价是信号变少。
download-data 把这些周期也下下来。⚠️ 避免未来函数:merge_informative_pair 默认会对齐时间,确保 1h 的指标只用「已收盘」的 1h K 线值,不会偷看未来。但如果你手动用
dataframe["rsi_1h"].shift(-1)这类负 shift,就会引入未来函数——回测神准、实盘崩盘。第 6 章会专门讲。
informative_pairs 声明要预拉的辅助对。_<tf> 后缀,默认 ffill=True 前向填充。close → close_1h;若 informative 指标已带后缀会叠加成 _1h_1h,建议 informative 不预加后缀。fmt。下一节,我们看 freqtrade 把「机械规则」变灵活的关键——回调函数全解。