第 3 章 · 01 IStrategy 接口 本节摘要:本节是「策略开发基础」的第一块基石,讲透 freqtrade 策略的骨架——IStrategy 抽象基类。freqtrade 的一切买卖行为最终都由「策略」决定,而一个策略就是一个继承 的 Python 类。本节讲清三件事:策略类必须实现哪几个方法( 、 、 )、必须配置哪些类属性( 、 、 )、以及那些影响行为的可选约定( 、 、 )。读完本节,你能看懂任何一个 freqtrade 策略文件的结构,并搭出一个能跑的空策略骨架。 内容来源:原项目源码 、模板 、文档 ,汉化并套用体系化模板。 学习目标 阅读完本节,你应当能够: 说清一个 freqtrade 策略就是一个继承 的 Python 类。 列举必须实现的三个方法及其职责。
本节摘要:本节是「策略开发基础」的第一块基石,讲透 freqtrade 策略的骨架——IStrategy 抽象基类。freqtrade 的一切买卖行为最终都由「策略」决定,而一个策略就是一个继承
IStrategy的 Python 类。本节讲清三件事:策略类必须实现哪几个方法(populate_indicators、populate_entry_trend、populate_exit_trend)、必须配置哪些类属性(timeframe、minimal_roi、stoploss)、以及那些影响行为的可选约定(process_only_new_candles、startup_candle_count、order_types)。读完本节,你能看懂任何一个 freqtrade 策略文件的结构,并搭出一个能跑的空策略骨架。
内容来源:原项目源码
freqtrade/strategy/interface.py、模板freqtrade/templates/sample_strategy.py、文档docs/strategy-101.md,汉化并套用体系化模板。
阅读完本节,你应当能够:
IStrategy 的 Python 类。process_only_new_candles、startup_candle_count 等关键行为开关。在 freqtrade 里,策略 = 一个继承 IStrategy 的类。这个类的核心职责回答三个问题:
populate_indicators(算指标)populate_entry_trend(入场信号)populate_exit_trend(出场信号)💡 核心心法:freqtrade 把「策略」抽象成「数据流的三次变换」——原始 OHLCV → 加了指标的 DataFrame → 加了信号的 DataFrame。你写的代码就在做这三次变换,其余下单、记账、风控都由引擎接管。这就是「策略与引擎分离」。
一个最简策略骨架长这样:
import pandas as pd from pandas import DataFrame from freqtrade.strategy import IStrategy import talib.abstract as ta class MyStrategy(IStrategy): INTERFACE_VERSION = 3 # —— 必须配置的核心属性 —— timeframe = "1h" minimal_roi = {"0": 0.10 } # 任意时刻盈利 10% 平仓 stoploss = -0.10 # 亏损 10% 止损 # —— 必须实现的三个方法 —— def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe["rsi"] = ta.RSI(dataframe) return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ (dataframe["rsi"] < 30), "enter_long", ] = 1 return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ (dataframe["rsi"] > 70), "exit_long", ] = 1 return dataframe
这个策略的逻辑就是最经典的 RSI 超买超卖:RSI 跌破 30 买入(超卖反弹),涨破 70 卖出(超买回落)。下面逐块拆解。
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe 是当前交易对的 OHLCV 数据(含 open/high/low/close/volume/date 等列);metadata 含交易对名等信息。def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[条件, 列名] = 1 给特定行赋值。入场信号列名:
enter_long = 1:触发做多(买入)enter_short = 1:触发做空(需 can_short = True)&(与)组合,通常还加 & (dataframe["volume"] > 0) 排除零成交量的脏数据。def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
exit_long = 1:平多仓(卖出)exit_short = 1:平空仓💡 信号的本质:
enter_long/exit_long这些列,引擎只看它等于 1 的那一行(对应某根 K 线收盘时)。你在某根 K 线上把它设为 1,引擎就理解为「这根 K 线收盘后,进场/出场」。信号是布尔语义,设 1 表示触发,不设(或 0)表示不触发。
这些写在类体里作为类属性,但注意:它们可以被配置文件覆盖(配置 JSON 里同名字段优先级更高)。
| 属性 | 含义 | 示例 |
|---|---|---|
INTERFACE_VERSION |
策略接口版本,目前是 3 | 3 |
timeframe |
K 线周期,如 5m、1h、1d | "1h" |
minimal_roi |
最小投资回报率表,达到即平仓(见第四节) | {"0": 0.10} |
stoploss |
止损比例(负数),亏损到此比例自动平仓 | -0.10 |
can_short |
是否允许做空 | False(仅做多)/True |
minimal_roi 不是单一数字,而是一张时间-收益表,键是「进场后第 N 分钟」,值是「达到该收益率就平仓」:
minimal_roi = { "0": 0.04, # 进场后立即:盈利 4% 就平 "30": 0.02, # 进场 30 分钟后:盈利 2% 就平 "60": 0.01, # 进场 60 分钟后:盈利 1% 就平 }
含义是「持有越久,对收益的要求越低」——刚进场想多赚,久了就见好就收。时间键从大到小解读,任意时刻取适用的最高门槛。第 3 章第 04 节会详讲。
stoploss = -0.10 表示亏损 10% 自动平仓。这是「硬止损」,无论信号如何,触及即平。它和 minimal_roi、出场信号、追踪止损共同构成出场逻辑(详见第 04 章)。
这些类属性控制策略的执行细节,初学者最该知道几个:
| 属性 | 默认 | 说明 |
|---|---|---|
process_only_new_candles |
True |
只在新 K 线收盘时才跑策略,而非每秒跑。强烈保持 True,否则重复计算浪费资源 |
startup_candle_count |
如 200 | 策略产出有效信号前需要的 K 线根数(如 200 周期均线需 200 根)。前 N 根会被忽略,避免指标未热身产生假信号 |
use_exit_signal |
True |
是否使用 populate_exit_trend 的出场信号;False 则只靠 ROI/止损出场 |
exit_profit_only |
False |
仅在盈利时才用出场信号 |
order_types |
见下 | 订单类型映射(entry/exit 用 limit 还是 market) |
order_time_in_force |
GTC | 订单有效期(GTC/IOC/FOK/PO) |
典型 order_types:
order_types = { "entry": "limit", # 入场用限价单 "exit": "limit", # 出场用限价单 "stoploss": "market", # 止损用市价单(确保成交) "stoploss_on_exchange": False, # 是否把止损单挂在交易所 }
💡 startup_candle_count 的坑:如果你策略用了 200 周期的指标,但
startup_candle_count只设 50,那前 150 根的指标值是不准的(均线还没热身),可能产出错误信号。规则:startup_candle_count ≥ 你最长指标的周期数。回测时也要保证下载数据足够长。
IStrategy 还支持声明可优化参数,供第 7 章 Hyperopt 自动搜索:
from freqtrade.strategy import IntParameter class MyStrategy(IStrategy): buy_rsi = IntParameter(low=1, high=50, default=30, space="buy", optimize=True) def populate_entry_trend(self, dataframe, metadata): dataframe.loc[ (dataframe["rsi"] < self.buy_rsi.value), # 用 self.buy_rsi.value 引用 "enter_long", ] = 1 return dataframe
声明后,代码里用 self.buy_rsi.value 取当前值。Hyperopt 会在 low~high 区间搜索最优值。这是把「拍脑袋的魔法数字」变成「可优化的参数」的关键,第 7 章详讲。
如果你策略需要看其他交易对或周期的数据(比如用 BTC 1h 趋势辅助判断),用 informative_pairs 声明要预拉取的数据:
def informative_pairs(self): return [("BTC/USDT", "1h")] # 预拉 BTC/USDT 1 小时数据
引擎会缓存这些数据供策略使用。第 4 章的 @informative 装饰器是更优雅的写法。
plot_config 告诉 plot-dataframe 命令把哪些指标画在主图、哪些画在副图:
plot_config = { "main_plot": {"tema": {}, "sar": {"color": "white"}}, "subplots": {"RSI": {"rsi": {"color": "red"}}}, }
不影响交易,只影响可视化呈现。
写新策略不必从零敲,用脚手架:
freqtrade new-strategy --strategy MyStrategy --template minimal
会在 user_data/strategies/MyStrategy.py 生成一份骨架。--template minimal 是最简版,不写 --template 则生成带大量注释指标示例的完整版(就是官方的 SampleStrategy)。
⚠️ SampleStrategy 不是用来赚钱的:官方示例策略(SampleStrategy)展示的是「怎么写」,RSI + 布林带 + TEMA 那套逻辑直接实盘大概率亏钱。它是模板不是印钞机,务必回测 + Dry-Run 验证自己的逻辑。
IStrategy 的 Python 类,回答「数据怎么加工 / 何时买 / 何时卖」三个问题。populate_indicators(算指标加列)、populate_entry_trend(打 enter_long/short=1)、populate_exit_trend(打 exit_long/short=1)。==1 的行,理解为「那根 K 线收盘后触发」。timeframe(周期)、minimal_roi(收益阶梯表)、stoploss(止损比例)、can_short(能否做空);可被配置文件覆盖。process_only_new_candles=True(只在新 K 线跑)、startup_candle_count(指标热身根数,≥ 最长指标周期)。order_types 映射入场/出场/止损分别用 limit 还是 market。IntParameter 等声明后用 .value 引用,供 Hyperopt 优化;new-strategy 命令生成骨架。下一节,我们深入
populate_indicators,用 pandas 和 TA-Lib 实打实地算几类常用技术指标。