第 3 章 · 05 第一个示例策略


文档摘要

第 3 章 · 05 第一个示例策略 本节摘要:前三节我们把指标、信号、风控拆开学了,现在把它们拼起来,逐段精读 freqtrade 官方模板 ——它就是 不加 时生成的完整骨架。这套策略的逻辑是教科书级的「RSI 超卖反弹 + 布林带 + TEMA」:用 RSI 上穿 30 捕捉超卖反转事件,用 TEMA 与布林中轨的相对位置做守卫,用 minimalroi 阶梯表与 10% 止损做风控。读完本节,你能完整理解这份模板每一行的作用,并知道如何在其上改成自己的策略——同时牢记:它是「怎么写」的范例,不是「赚钱」的印钞机。 内容来源:原项目源码 、文档 ,汉化并套用体系化模板。 ⚠️ 风险提示:官方明说 SampleStrategy 不是用来赚钱的。直接拿它上实盘大概率亏损。

第 3 章 · 05 第一个示例策略

本节摘要:前三节我们把指标、信号、风控拆开学了,现在把它们拼起来,逐段精读 freqtrade 官方模板 freqtrade/templates/sample_strategy.py——它就是 freqtrade new-strategy 不加 --template minimal 时生成的完整骨架。这套策略的逻辑是教科书级的「RSI 超卖反弹 + 布林带 + TEMA」:用 RSI 上穿 30 捕捉超卖反转事件,用 TEMA 与布林中轨的相对位置做守卫,用 minimal_roi 阶梯表与 10% 止损做风控。读完本节,你能完整理解这份模板每一行的作用,并知道如何在其上改成自己的策略——同时牢记:它是「怎么写」的范例,不是「赚钱」的印钞机。

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

⚠️ 风险提示:官方明说 SampleStrategy 不是用来赚钱的。直接拿它上实盘大概率亏损。它是结构范例,真正实盘前必须回测 + Dry-Run + 自己理解每一行逻辑。

学习目标

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

  1. 把 sample_strategy 的类配置块、指标块、入场块、出场块对应到前三节学的概念。
  2. 说清「RSI + BB + TEMA」入场逻辑的每行作用。
  3. 理解示例里的 Hyperopt 参数(IntParameter)如何让 RSI 阈值可调。
  4. 知道哪些块必须保留、哪些可以删改
  5. 在 sample 基础上派生自己的策略
  6. freqtrade new-strategy 生成模板并跑起来。

一、整体结构:四块拼图

打开 sample_strategy.py,去掉注释后骨架是这样:

import talib.abstract as ta from technical import qtpylib from freqtrade.strategy import IStrategy, IntParameter, informative from pandas import DataFrame class SampleStrategy(IStrategy): # —— 第一块:类配置 —— INTERFACE_VERSION = 3 timeframe = "5m" can_short = False minimal_roi = {"60": 0.01, "30": 0.02, "0": 0.04} stoploss = -0.10 trailing_stop = False process_only_new_candles = True startup_candle_count = 200 order_types = {...} use_exit_signal = True # —— 第二块:Hyperopt 参数 —— buy_rsi = IntParameter(1, 50, default=30, space="buy") sell_rsi = IntParameter(50, 100, default=70, space="sell") # —— 第三块:三个必须方法 —— def populate_indicators(self, dataframe, metadata): ... def populate_entry_trend(self, dataframe, metadata): ... def populate_exit_trend(self, dataframe, metadata): ... # —— 第四块:可视化配置(可选) —— plot_config = {...}

二、第一块:类配置详解

INTERFACE_VERSION = 3 # 接口版本,目前固定 3 timeframe = "5m" # 5 分钟 K 线 can_short: bool = False # 仅做多 minimal_roi = { # 阶梯 ROI(第 04 节) "60": 0.01, # 1 小时后 1% 就平 "30": 0.02, # 30 分钟后 2% "0": 0.04, # 立即要 4% } stoploss = -0.10 # 亏损 10% 止损 trailing_stop = False # 不开启追踪止损(第 4 章详讲) process_only_new_candles = True # 只在新 K 线收盘跑 startup_candle_count: int = 200 # 前 200 根忽略 order_types = { "entry": "limit", # 入场用限价单 "exit": "limit", # 出场用限价单 "stoploss": "market", # 止损用市价单(确保成交) "stoploss_on_exchange": False, } use_exit_signal = True # 启用 populate_exit_trend exit_profit_only = False # 任何盈亏都可用信号出场 ignore_roi_if_entry_signal = False # 达 ROI 就平,不等信号

每一行都在前三节讲过。注意 startup_candle_count = 200 是因为指标里最长的周期接近 200(虽然示例实际只用短周期,但留 200 是给后续扩展留余地)。

💡 改自己的策略从这里开始:timeframeminimal_roistoploss 是最先该调整的三个。但记住——JSON 配置会覆盖它们,所以实盘时检查 JSON。

三、第二块:Hyperopt 参数

buy_rsi = IntParameter(low=1, high=50, default=30, space="buy", optimize=True, load=True) sell_rsi = IntParameter(low=50, high=100, default=70, space="sell", optimize=True, load=True) short_rsi = IntParameter(low=51, high=100, default=70, space="sell", optimize=True, load=True) exit_short_rsi = IntParameter(low=1, high=50, default=30, space="exit", optimize=True, load=True)

IntParameter 声明一个可优化参数:

  • low/high:搜索范围。
  • default:不用 Hyperopt 时的默认值。
  • space:"buy"(买空间)、"sell"(卖空间)、"roi""stoploss""exit" 等,Hyperopt 可分空间优化。
  • optimize:是否参与优化。
  • load:是否从 Hyperopt 结果文件加载。

代码里用 self.buy_rsi.value 取当前值。第 7 章详讲。

四、第三块:populate_indicators 实算哪些

去掉所有注释行,sample 实际计算的指标就这几个(注意:不是注释里的全部):

def populate_indicators(self, dataframe, metadata): dataframe["adx"] = ta.ADX(dataframe) # 趋势强度 dataframe["rsi"] = ta.RSI(dataframe) # 动量 stoch_fast = ta.STOCHF(dataframe) # 快随机 dataframe["fastd"] = stoch_fast["fastd"] dataframe["fastk"] = stoch_fast["fastk"] macd = ta.MACD(dataframe) # MACD dataframe["macd"] = macd["macd"] dataframe["macdsignal"] = macd["macdsignal"] dataframe["macdhist"] = macd["macdhist"] dataframe["mfi"] = ta.MFI(dataframe) # 资金流量 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"] dataframe["sar"] = ta.SAR(dataframe) # 抛物线 dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9) # 三重 EMA hilbert = ta.HT_SINE(dataframe) # 希尔伯特正弦 dataframe["htsine"] = hilbert["sine"] dataframe["htleadsine"] = hilbert["leadsine"] return dataframe

⚠️ 观察:sample 里 populate_indicators 算了 ~15 个指标,但 populate_entry_trend 实际只用到 rsitemabb_middleband 三个。这正是反面教材——按第 02 节的性能铁律,实战应该删掉没用的。sample 保留它们是「目录」用途,让你看到 TA-Lib 怎么调。

五、第三块:populate_entry_trend 精读

def populate_entry_trend(self, dataframe, metadata): # 做多信号 dataframe.loc[ ( # 信号:RSI 上穿 buy_rsi(默认 30)——超卖反弹事件 (qtpylib.crossed_above(dataframe["rsi"], self.buy_rsi.value)) # 守卫 1:TEMA ≤ 布林中轨(确认还在低位区间) & (dataframe["tema"] <= dataframe["bb_middleband"]) # 守卫 2:TEMA 在抬升(反弹已启动) & (dataframe["tema"] > dataframe["tema"].shift(1)) # 守卫 3:成交量 > 0 & (dataframe["volume"] > 0) ), "enter_long", ] = 1 # 做空信号(can_short=False 时不会触发) dataframe.loc[ ( (qtpylib.crossed_above(dataframe["rsi"], self.short_rsi.value)) & (dataframe["tema"] > dataframe["bb_middleband"]) & (dataframe["tema"] < dataframe["tema"].shift(1)) & (dataframe["volume"] > 0) ), "enter_short", ] = 1 return dataframe

这套「RSI + BB + TEMA」逻辑的解读(第 03 节已铺垫):

条件 角色 解读
crossed_above(rsi, 30) 信号 RSI 从超卖区上穿 30,反弹事件
tema <= bb_middleband 守卫 TEMA 还在布林下半区,确认低位
tema > tema.shift(1) 守卫 TEMA 在抬升,反弹已启动而非刚开始
volume > 0 守卫 排除零成交量脏数据

💡 为什么用 crossed_above 而非 <:RSI 跌到 25 然后反弹到 28,这一路上 < 30 都为真——会重复触发;而 crossed_above(rsi, 30) 只在「从下方穿越到上方」那一根 K 线触发,信号干净。

六、第三块:populate_exit_trend

出场逻辑与入场镜像对称——只是把阈值和方向反过来:

def populate_exit_trend(self, dataframe, metadata): # 平多:RSI 上穿 70(超买回落)+ TEMA 在高位 + TEMA 在下降 dataframe.loc[ ( (qtpylib.crossed_above(dataframe["rsi"], self.sell_rsi.value)) & (dataframe["tema"] > dataframe["bb_middleband"]) & (dataframe["tema"] < dataframe["tema"].shift(1)) & (dataframe["volume"] > 0) ), "exit_long", ] = 1 # 平空:略,逻辑对称 return dataframe

注意出场还会叠加 minimal_roi(4%/2%/1% 阶梯)和 stoploss(-10%),三者「或」关系。

七、第四块:plot_config 可视化

plot_config = { "main_plot": {"tema": {}, "sar": {"color": "white"}}, "subplots": { "MACD": {"macd": {"color": "blue"}, "macdsignal": {"color": "orange"}}, "RSI": {"rsi": {"color": "red"}}, }, }
  • main_plot:画在主图(K 线图)上的指标,通常是价格类(均线、SAR)。
  • subplots:画在副图上的指标,通常是震荡类(RSI、MACD)。

不影响交易,只影响 freqtrade plot-dataframe 的输出。

八、在 sample 上派生你的策略

实战路径:

  1. 复制改名:cp sample_strategy.py MyStrategy.py,把类名 SampleStrategy 改成 MyStrategy
  2. 精简指标:删掉 populate_indicators 里入场/出场没用到的列。
  3. 改阈值:buy_rsisell_rsidefault 改成你回测最优的值。
  4. 改 timeframe/ROI/stoploss:配合你的交易风格。
  5. 删做空逻辑:can_short=False 时,enter_short/exit_short 块可删。
  6. 回测验证:freqtrade backtesting -c config.json -s MyStrategy

⚠️ 必须保留:INTERFACE_VERSIONpopulate_indicatorspopulate_entry_trendpopulate_exit_trendtimeframeminimal_roistoploss——这些是引擎的硬性约定。其余(plot_config、Hyperopt 参数、informative_pairs)可选。

九、生成与运行

# 生成完整版(就是 sample_strategy) freqtrade new-strategy --strategy MyFirst # 生成最小骨架 freqtrade new-strategy --strategy MyFirst --template minimal # 回测 freqtrade backtesting -c user_data/config.json -s MyFirst # Dry-Run freqtrade trade -c user_data/config.json -s MyFirst --strategy-path user_data/strategies/

本节要点回顾

  1. 四块结构:类配置、Hyperopt 参数、三个必须方法、plot_config——前三块必留,第四块可选。
  2. 指标块反面教材:sample 算了 15 个指标但只用到 3 个,实战要按性能铁律删冗余。
  3. 入场精读:RSI 上穿 30(信号)+ TEMA 在布林下半区(守卫)+ TEMA 抬升(守卫)+ volume>0(守卫)。
  4. 用 crossed_above 而非 <:事件信号只在穿越那根触发,避免重复进场。
  5. 出场镜像对称:逻辑与入场同型,只是方向和阈值反过来;叠加 ROI + 止损是「或」关系。
  6. 派生路径:复制改名 → 精简指标 → 改阈值 → 改 timeframe/ROI/stoploss → 删做空 → 回测。
  7. SampleStrategy 是范例不是印钞机:直接上实盘大概率亏钱,必须理解每一行 + 回测 + Dry-Run。

下一章进入「策略深度定制」——先看 @informative 装饰器,如何在一个策略里融合多周期(如 1h 趋势 + 5m 入场)的数据。


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