Hyperopt¶
本页解释了如何通过寻找最佳参数来调整您的策略,这个过程称为超参数优化。机器人使用 optuna
包中包含的算法来完成这项工作。
搜索将消耗所有 CPU 核心,让您的笔记本电脑听起来像战斗机,并且仍然需要很长时间。
一般来说,最佳参数的搜索从几个随机组合开始(详见下文),然后使用 optuna 的采样器算法之一(目前是 NSGAIIISampler)来快速找到搜索超空间中最小化损失函数值的参数组合。
Hyperopt 需要历史数据,就像回测一样(hyperopt 使用不同参数多次运行回测)。 要了解如何获取您感兴趣的交易对和交易所的数据,请查看文档的数据下载部分。
安装 hyperopt 依赖¶
由于 Hyperopt 依赖项不是运行机器人本身所必需的,它们很重,在某些平台(如树莓派)上不容易构建,因此默认不安装。
在运行 Hyperopt 之前,您需要安装相应的依赖项,如下所述。
Docker 安装¶
docker 镜像包含 hyperopt 依赖项,无需进一步操作。
简易安装脚本 (setup.sh) / 手动安装¶
source .venv/bin/activate
pip install -r requirements-hyperopt.txt
Hyperopt 命令参考¶
用法: freqtrade hyperopt [-h] [-v] [--no-color] [--logfile FILE] [-V]
[-c PATH] [-d PATH] [--userdir PATH] [-s NAME]
[--strategy-path PATH] [--recursive-strategy-search]
[--freqaimodel NAME] [--freqaimodel-path PATH]
[-i TIMEFRAME] [--timerange TIMERANGE]
[--data-format-ohlcv {json,jsongz,feather,parquet}]
[--max-open-trades INT]
[--stake-amount STAKE_AMOUNT] [--fee FLOAT]
[-p PAIRS [PAIRS ...]] [--hyperopt-path PATH]
[--eps] [--enable-protections]
[--dry-run-wallet DRY_RUN_WALLET]
[--timeframe-detail TIMEFRAME_DETAIL] [-e INT]
[--spaces {all,buy,sell,roi,stoploss,trailing,protection,trades,default} [{all,buy,sell,roi,stoploss,trailing,protection,trades,default} ...]]
[--print-all] [--print-json] [-j JOBS]
[--random-state INT] [--min-trades INT]
[--hyperopt-loss NAME] [--disable-param-export]
[--ignore-missing-spaces] [--analyze-per-epoch]
选项:
-h, --help 显示帮助信息并退出
-i TIMEFRAME, --timeframe TIMEFRAME
指定时间框架 (`1m`, `5m`, `30m`, `1h`, `1d`)。
--timerange TIMERANGE
指定要使用的数据时间范围。
--data-format-ohlcv {json,jsongz,feather,parquet}
下载的K线(OHLCV)数据的存储格式。
(默认:`feather`)。
--max-open-trades INT
覆盖配置设置中的 `max_open_trades` 值。
--stake-amount STAKE_AMOUNT
覆盖配置设置中的 `stake_amount` 值。
--fee FLOAT 指定手续费比率。将应用两次(在交易进入和退出时)。
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
限制命令仅用于这些交易对。交易对之间用空格分隔。
--hyperopt-path PATH 指定超参数损失函数的额外查找路径。
--eps, --enable-position-stacking
允许多次购买同一交易对(仓位叠加)。
--enable-protections, --enableprotections
为回测启用保护机制。这将显著降低回测速度,但会包含已配置的保护机制。
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
起始余额,用于回测/超参数优化和模拟运行。
--timeframe-detail TIMEFRAME_DETAIL
为回测指定详细时间框架 (`1m`, `5m`, `30m`, `1h`, `1d`)。
-e INT, --epochs INT 指定 epoch 数量(默认:100)。
--spaces {all,buy,sell,roi,stoploss,trailing,protection,trades,default} [{all,buy,sell,roi,stoploss,trailing,protection,trades,default} ...]
指定要超参数优化的参数空间。空格分隔的列表。
--print-all 打印所有结果,而不仅仅是最佳结果。
--print-json 以 JSON 格式输出结果。
-j JOBS, --job-workers JOBS
超参数优化的并发作业数(worker 进程数)。如果为 -1(默认),则使用所有 CPU;为 -2 时,使用所有 CPU 但保留一个,依此类推。如果为 1,则不使用并行计算。
--random-state INT 设置随机种子,以便复现超参数优化结果。
--min-trades INT 设置超参数优化路径中评估的最小交易次数(默认:1)。
--hyperopt-loss NAME, --hyperoptloss NAME
指定超参数损失函数类(IHyperOptLoss)的类名。不同的损失函数会产生完全不同的结果,因为优化目标不同。内置损失函数包括:
ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss,
SharpeHyperOptLoss, SharpeHyperOptLossDaily,
SortinoHyperOptLoss, SortinoHyperOptLossDaily,
CalmarHyperOptLoss, MaxDrawDownHyperOptLoss,
MaxDrawDownRelativeHyperOptLoss,
MaxDrawDownPerPairHyperOptLoss,
ProfitDrawDownHyperOptLoss, MultiMetricHyperOptLoss
--disable-param-export
禁用自动导出超参数。
--ignore-missing-spaces, --ignore-unparameterized-spaces
对于未包含任何参数的超参数空间,抑制错误。
--analyze-per-epoch 每个 epoch 执行一次 populate_indicators。
通用参数:
-v, --verbose 详细模式(-vv 获取更多信息,-vvv 获取所有消息)。
--no-color 禁用超参数优化结果的着色。在将输出重定向到文件时可能有用。
--logfile FILE, --log-file FILE
记录到指定的文件。特殊值包括:
'syslog', 'journald'。有关更多详细信息,请参阅文档。
-V, --version 显示程序版本号并退出
-c PATH, --config PATH
指定配置文件(默认:`userdir/config.json` 或 `config.json`,以存在的为准)。
可以使用多个 --config 选项。可以设置为 `-` 以从标准输入读取配置。
-d PATH, --datadir PATH, --data-dir PATH
交易所历史回测数据的基本目录路径。要查看期货数据,需要额外使用 trading-mode。
--userdir PATH, --user-data-dir PATH
用户数据目录的路径。
策略参数:
-s NAME, --strategy NAME
指定机器人要使用的策略类名。
--strategy-path PATH 指定额外的策略查找路径。
--recursive-strategy-search
在策略文件夹中递归搜索策略。
--freqaimodel NAME 指定自定义的 freqaimodels。
--freqaimodel-path PATH
为 freqaimodels 指定额外的查找路径。
Hyperopt 清单¶
Hyperopt 中所有任务/可能性的清单
根据您想要优化的空间,只需要以下部分:
- 使用
space='buy'
定义参数 - 用于入场信号优化 - 使用
space='sell'
定义参数 - 用于出场信号优化
很少情况下,您可能还需要创建一个名为 HyperOpt
的嵌套类并实现:
roi_space
- 用于自定义 ROI 优化(如果您需要优化超空间中 ROI 参数的范围与默认值不同)generate_roi_table
- 用于自定义 ROI 优化(如果您需要 ROI 表中值的范围与默认值不同,或者 ROI 表中的条目数(步骤)与默认的 4 个步骤不同)stoploss_space
- 用于自定义止损优化(如果您需要优化超空间中止损参数的范围与默认值不同)trailing_space
- 用于自定义追踪止损优化(如果您需要优化超空间中追踪止损参数的范围与默认值不同)max_open_trades_space
- 用于自定义 max_open_trades 优化(如果您需要优化超空间中 max_open_trades 参数的范围与默认值不同)
Hyperopt 执行逻辑¶
Hyperopt 将首先将您的数据加载到内存中,然后为每个交易对运行一次 populate_indicators()
以生成所有指标,除非指定了 --analyze-per-epoch
。
然后,Hyperopt 将分叉到不同的进程(处理器数量或 -j <n>
),并反复运行回测,更改属于定义的 --spaces
的参数。
对于每组新参数,freqtrade 将首先运行 populate_entry_trend()
,然后运行 populate_exit_trend()
,然后运行常规回测过程来模拟交易。
回测后,结果将传递给损失函数,该函数将评估这个结果是否比之前的结果更好或更差。
基于损失函数结果,hyperopt 将确定下一轮回测中要尝试的下一组参数。
配置您的守卫和触发器¶
您需要在策略文件中更改两个地方来添加新的买入 hyperopt 进行测试:
- 在类级别定义 hyperopt 将要优化的参数。
- 在
populate_entry_trend()
中 - 使用定义的参数值而不是原始常量。
在那里您有两种不同类型的指标:1. guards
(守卫)和 2. triggers
(触发器)。
- 守卫是类似"当 ADX < 10 时永不买入"或"当当前价格超过 EMA10 时永不买入"的条件。
- 触发器是在特定时刻实际触发买入的指标,如"当 EMA5 上穿 EMA10 时买入"或"当收盘价触及布林带下轨时买入"。
超参优化将在每个 epoch 轮次中选择一个触发器和可能的多个守卫。
出场信号优化¶
与上述入场信号类似,出场信号也可以优化。 将相应的设置放入以下方法中:
- 在类级别定义 hyperopt 将要优化的参数,可以通过将它们命名为
sell_*
,或通过显式定义space='sell'
。 - 在
populate_exit_trend()
中 - 使用定义的参数值而不是原始常量。
配置和规则与买入信号相同。
解决一个谜题¶
假设您很好奇:是否应该使用 MACD 交叉或布林带下轨来触发您的做多入场。您还想知道是否应该使用 RSI 或 ADX 来帮助做出这些决定。如果您决定使用 RSI 或 ADX,应该为它们使用哪些值?
让我们使用超参数优化来解决这个谜题。
定义要使用的指标¶
我们首先计算策略将要使用的指标。
class MyAwesomeStrategy(IStrategy):
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
生成策略使用的所有指标
"""
dataframe['adx'] = ta.ADX(dataframe)
dataframe['rsi'] = ta.RSI(dataframe)
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
bollinger = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
dataframe['bb_lowerband'] = bollinger['lowerband']
dataframe['bb_middleband'] = bollinger['middleband']
dataframe['bb_upperband'] = bollinger['upperband']
return dataframe
超参数优化参数¶
我们继续定义超参数优化参数:
class MyAwesomeStrategy(IStrategy):
buy_adx = DecimalParameter(20, 40, decimals=1, default=30.1, space="buy")
buy_rsi = IntParameter(20, 40, default=30, space="buy")
buy_adx_enabled = BooleanParameter(default=True, space="buy")
buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy")
buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy")
上述定义表示:我有五个参数想要随机组合来找到最佳组合。buy_rsi
是一个整数参数,将在 20 到 40 之间进行测试。这个空间的大小为 20。buy_adx
是一个小数参数,将在 20 到 40 之间进行评估,保留 1 位小数(所以值是 20.1, 20.2, ...)。这个空间的大小为 200。
然后我们有三个分类变量。前两个是 True
或 False
。
我们使用这些来启用或禁用 ADX 和 RSI 保护。
最后一个我们称为 trigger
,用它来决定我们想要使用哪个买入触发条件。
所以让我们使用这些值编写买入策略:
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
# 保护和趋势
if self.buy_adx_enabled.value:
conditions.append(dataframe['adx'] > self.buy_adx.value)
if self.buy_rsi_enabled.value:
conditions.append(dataframe['rsi'] < self.buy_rsi.value)
# 触发条件
if self.buy_trigger.value == 'bb_lower':
conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
if self.buy_trigger.value == 'macd_cross_signal':
conditions.append(qtpylib.crossed_above(
dataframe['macd'], dataframe['macdsignal']
))
# 检查成交量不为 0
conditions.append(dataframe['volume'] > 0)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'enter_long'] = 1
return dataframe
超参数优化现在将使用不同的值组合多次调用 populate_entry_trend()
(epochs
次)。
它将使用给定的历史数据,并基于上述函数生成的买入信号模拟买入。
基于结果,超参数优化将告诉你哪个参数组合产生了最佳结果(基于配置的损失函数)。
参数类型¶
有四种参数类型,每种都适用于不同的目的。
IntParameter
- 定义具有搜索空间上下边界的整数参数。DecimalParameter
- 定义具有有限小数位数的浮点参数(默认 3 位)。在大多数情况下应该优先于RealParameter
。RealParameter
- 定义具有上下边界且无精度限制的浮点参数。很少使用,因为它创建了一个具有近乎无限可能性的空间。CategoricalParameter
- 定义具有预定数量选择的参数。BooleanParameter
-CategoricalParameter([True, False])
的简写 - 非常适合"启用"参数。
参数选项¶
有两个参数选项可以帮助你快速测试各种想法:
optimize
- 当设置为False
时,参数将不会包含在优化过程中。(默认值:True)load
- 当设置为False
时,之前超参数优化运行的结果(在你的策略或 JSON 输出文件中的buy_params
和sell_params
)将不会用作后续超参数优化的起始值。将使用参数中指定的默认值。(默认值:True)
优化指标参数¶
假设您有一个简单的策略 - EMA 交叉策略(2 个移动平均线交叉)- 并且您想找到这个策略的理想参数。
默认情况下,我们假设止损为 5% - 止盈(minimal_roi
)为 10% - 这意味着 freqtrade 将在达到 10% 利润时卖出交易。
from pandas import DataFrame
from functools import reduce
import talib.abstract as ta
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
IStrategy, IntParameter)
import freqtrade.vendor.qtpylib.indicators as qtpylib
class MyAwesomeStrategy(IStrategy):
stoploss = -0.05
timeframe = '15m'
minimal_roi = {
"0": 0.10
}
# 定义参数空间
buy_ema_short = IntParameter(3, 50, default=5)
buy_ema_long = IntParameter(15, 200, default=50)
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""生成策略使用的所有指标"""
# 计算所有 ema_short 值
for val in self.buy_ema_short.range:
dataframe[f'ema_short_{val}'] = ta.EMA(dataframe, timeperiod=val)
# 计算所有 ema_long 值
for val in self.buy_ema_long.range:
dataframe[f'ema_long_{val}'] = ta.EMA(dataframe, timeperiod=val)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
conditions.append(qtpylib.crossed_above(
dataframe[f'ema_short_{self.buy_ema_short.value}'], dataframe[f'ema_long_{self.buy_ema_long.value}']
))
# 检查交易量不为 0
conditions.append(dataframe['volume'] > 0)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'enter_long'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
conditions.append(qtpylib.crossed_above(
dataframe[f'ema_long_{self.buy_ema_long.value}'], dataframe[f'ema_short_{self.buy_ema_short.value}']
))
# 检查交易量不为 0
conditions.append(dataframe['volume'] > 0)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'exit_long'] = 1
return dataframe
分解说明:
使用 self.buy_ema_short.range
将返回一个包含参数低值和高值之间所有条目的范围对象。
在这种情况下(IntParameter(3, 50, default=5)
),循环将为 3 到 50 之间的所有数字运行([3, 4, 5, ... 49, 50]
)。
通过在循环中使用这个,hyperopt 将生成 48 个新列(['buy_ema_3', 'buy_ema_4', ... , 'buy_ema_50']
)。
Hyperopt 本身将使用选定的值来创建买入和卖出信号。
虽然这个策略可能过于简单,无法提供稳定的利润,但它应该作为如何优化指标参数的示例。
优化保护措施¶
Freqtrade 也可以优化保护措施。如何优化保护措施取决于您,以下内容仅供参考。
策略只需要将"protections"条目定义为返回保护配置列表的属性。
from pandas import DataFrame
from functools import reduce
import talib.abstract as ta
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
IStrategy, IntParameter)
import freqtrade.vendor.qtpylib.indicators as qtpylib
class MyAwesomeStrategy(IStrategy):
stoploss = -0.05
timeframe = '15m'
# 定义参数空间
cooldown_lookback = IntParameter(2, 48, default=5, space="protection", optimize=True)
stop_duration = IntParameter(12, 200, default=5, space="protection", optimize=True)
use_stop_protection = BooleanParameter(default=True, space="protection", optimize=True)
@property
def protections(self):
prot = []
prot.append({
"method": "CooldownPeriod",
"stop_duration_candles": self.cooldown_lookback.value
})
if self.use_stop_protection.value:
prot.append({
"method": "StoplossGuard",
"lookback_period_candles": 24 * 3,
"trade_limit": 4,
"stop_duration_candles": self.stop_duration.value,
"only_per_pair": False
})
return prot
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# ...
然后您可以按如下方式运行 hyperopt:
freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --strategy MyAwesomeStrategy --spaces protection
从以前的属性设置迁移¶
从以前的设置迁移非常简单,可以通过将保护措施条目转换为属性来完成。 简单来说,以下配置将转换为下面的内容。
class MyAwesomeStrategy(IStrategy):
protections = [
{
"method": "CooldownPeriod",
"stop_duration_candles": 4
}
]
结果
class MyAwesomeStrategy(IStrategy):
@property
def protections(self):
return [
{
"method": "CooldownPeriod",
"stop_duration_candles": 4
}
]
然后您显然也会将潜在有趣的条目更改为参数,以允许超参优化。
优化 max_entry_position_adjustment
¶
虽然 max_entry_position_adjustment
不是一个单独的空间,但它仍然可以通过使用上面显示的属性方法在 hyperopt 中使用。
from pandas import DataFrame
from functools import reduce
import talib.abstract as ta
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
IStrategy, IntParameter)
import freqtrade.vendor.qtpylib.indicators as qtpylib
class MyAwesomeStrategy(IStrategy):
stoploss = -0.05
timeframe = '15m'
# 定义参数空间
max_epa = CategoricalParameter([-1, 0, 1, 3, 5, 10], default=1, space="buy", optimize=True)
@property
def max_entry_position_adjustment(self):
return self.max_epa.value
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# ...
损失函数¶
每个超参数调优都需要一个目标。这通常被定义为损失函数(有时也称为目标函数),对于更理想的结果应该减小,对于不好的结果应该增加。
损失函数必须通过 --hyperopt-loss <Class-name>
参数指定(或可选地通过配置中的 "hyperopt_loss"
键)。
这个类应该位于 user_data/hyperopts/
目录中的自己的文件中。
目前,以下损失函数是内置的:
ShortTradeDurHyperOptLoss
- (默认的旧版 Freqtrade 超参优化损失函数)- 主要用于短交易持续时间和避免损失。OnlyProfitHyperOptLoss
- 只考虑利润金额。SharpeHyperOptLoss
- 优化相对于标准差的交易回报的夏普比率。SharpeHyperOptLossDaily
- 优化相对于标准差的每日交易回报的夏普比率。SortinoHyperOptLoss
- 优化相对于下行标准差的交易回报的索提诺比率。SortinoHyperOptLossDaily
- 优化相对于下行标准差的每日交易回报的索提诺比率。MaxDrawDownHyperOptLoss
- 优化最大绝对回撤。MaxDrawDownRelativeHyperOptLoss
- 优化最大绝对回撤,同时调整最大相对回撤。MaxDrawDownPerPairHyperOptLoss
- 计算每对交易对的利润/回撤比率,并返回最差结果作为目标,强制 hyperopt 优化交易对列表中所有交易对的参数。这样,我们防止一个或多个具有良好结果的交易对夸大指标,而表现不佳的交易对不被表示,因此不被优化。CalmarHyperOptLoss
- 优化相对于最大回撤的交易回报的卡玛比率。ProfitDrawDownHyperOptLoss
- 通过最大利润和最小回撤目标进行优化。可以在 hyperoptloss 文件中调整DRAWDOWN_MULT
变量,以在回撤目的上更严格或更灵活。MultiMetricHyperOptLoss
- 通过几个关键指标进行优化,以实现平衡的性能。主要重点是最大化利润和最小化回撤,同时还考虑其他指标,如利润因子、期望比率和胜率。此外,它对交易次数少的 epoch 应用惩罚,鼓励具有足够交易频率的策略。
创建自定义损失函数在文档的高级 Hyperopt 部分中介绍。
执行 Hyperopt¶
一旦您更新了 hyperopt 配置,您就可以运行它。 因为 hyperopt 尝试很多组合来找到最佳参数,所以需要时间才能获得好的结果。
我们强烈建议使用 screen
或 tmux
来防止任何连接丢失。
freqtrade hyperopt --config config.json --hyperopt-loss <hyperoptlossname> --strategy <strategyname> -e 500 --spaces all
-e
选项将设置 hyperopt 将进行多少次评估。由于 hyperopt 使用贝叶斯搜索,一次运行太多 epoch 可能不会产生更好的结果。经验表明,最佳结果通常在 500-1000 epoch 后不会有太大改善。
使用不同的随机状态进行多次运行(执行),每次运行几百个 epoch,很可能会产生不同的结果。
--spaces all
选项确定应该优化所有可能的参数。可能性如下所示。
使用不同的历史数据源执行 Hyperopt¶
如果您想使用磁盘上的替代历史数据集来超参优化参数,
请使用 --datadir PATH
选项。默认情况下,hyperopt 使用 user_data/data
目录中的数据。
使用较小的测试集运行 Hyperopt¶
使用 --timerange
参数来更改您想要使用的测试集数量。
例如,要使用一个月的数据,将 --timerange 20210101-20210201
(从 2021 年 1 月到 2021 年 2 月)传递给 hyperopt 调用。
完整命令:
freqtrade hyperopt --strategy <strategyname> --timerange 20210101-20210201
使用较小的搜索空间运行 Hyperopt¶
使用 --spaces
选项来限制 hyperopt 使用的搜索空间。
让 Hyperopt 优化所有内容是一个巨大的搜索空间。
通常,从只搜索初始买入算法开始可能更有意义。
或者,也许您只想为您拥有的那个很棒的新买入策略优化止损或 roi 表。
合法值是:
all
:优化所有内容buy
:只搜索新的买入策略sell
:只搜索新的卖出策略roi
:只为您的策略优化最小利润表stoploss
:搜索最佳止损值trailing
:搜索最佳追踪止损值trades
:搜索最佳最大开放交易值protection
:搜索最佳保护参数(阅读保护部分了解如何正确定义这些)default
:all
除了trailing
和protection
- 任何上述值的空格分隔列表,例如
--spaces roi stoploss
当未指定 --space
命令行选项时使用的默认 Hyperopt 搜索空间不包括 trailing
超空间。我们建议您在找到、验证并将其他超空间的最佳参数粘贴到您的自定义策略中后,单独运行 trailing
超空间的优化。
理解 Hyperopt 结果¶
一旦 Hyperopt 完成,您可以使用结果来更新您的策略。 给定以下结果来自 hyperopt:
Best result:
44/100: 135 trades. Avg profit 0.57%. Total profit 0.03871918 BTC (0.7722%). Avg duration 180:34 min. Objective: 1.94367
Buy hyperspace params:
{
'buy_adx': 44,
'buy_adx_enabled': False,
'buy_rsi': 29,
'buy_rsi_enabled': True,
'buy_trigger': 'bb_lower'
}
您应该理解这个结果如下:
- 最好的买入触发器是
bb_lower
。 - 您不应该使用 ADX,因为
'buy_adx_enabled': False
。 - 您应该考虑使用 RSI 指标 (
'buy_rsi_enabled': True
) 并且最好的值是29.0
('buy_rsi': 29.0
)
自动参数应用到策略¶
当使用 Hyperoptable 参数时,您的 hyperopt-run 结果将写入策略旁边的 json 文件(所以对于 MyAwesomeStrategy.py
,文件将是 MyAwesomeStrategy.json
)。
如果使用 hyperopt-show
子命令,除非 --disable-param-export
提供给两个命令中的任何一个,否则也会更新此文件。
您的策略类也可以包含这些结果明确。只需复制 hyperopt 结果块并将其粘贴到类级别,替换旧参数(如果有)。新参数将自动在下一次策略执行时加载。
将整个 hyperopt 结果传输到您的策略将如下所示:
class MyAwesomeStrategy(IStrategy):
# 最佳参数
buy_rsi = IntParameter(20, 40, default=30, space="buy", optimize=True)
buy_rsi_enabled = CategoricalParameter([True, False], default=True, space="buy", optimize=True)
buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal", "sar_reversal"], default="bb_lower", space="buy", optimize=True)
buy_adx = IntParameter(20, 50, default=30, space="buy", optimize=True)
buy_adx_enabled = CategoricalParameter([True, False], default=True, space="buy", optimize=True)
# 最佳结果
# 买入参数
buy_params = {
'buy_adx': 44,
'buy_adx_enabled': False,
'buy_rsi': 29,
'buy_rsi_enabled': True,
'buy_trigger': 'bb_lower'
}
理解 Hyperopt ROI 结果¶
如果您正在优化 ROI(即如果优化搜索空间包含 ‘all’、‘default’ 或 ‘roi’),您的结果将如下所示并包括 ROI 表:
Best result:
44/100: 135 trades. Avg profit 0.57%. Total profit 0.03871918 BTC (0.7722%). Avg duration 180:34 min. Objective: 1.94367
ROI table:
{
0: 0.106,
10: 0.079,
20: 0.053,
30: 0.027
}
为了在回测和实时交易/干运行中使用这个最佳 ROI 表,复制并粘贴它作为自定义策略的 minimal_roi
属性值:
# 最佳 ROI 表
minimal_roi = {
"0": 0.106,
"10": 0.079,
"20": 0.053,
"30": 0.027
}
如评论中所述,您也可以将其用作配置文件中的 minimal_roi
设置值。
默认 ROI 搜索空间¶
如果您正在优化 ROI,Freqtrade 为您创建了 ‘roi’ 优化超空间——它是 ROI 表组件的超空间。默认情况下,每个由 Freqtrade 生成的 ROI 表包含 4 行(步骤)。Hyperopt 实现了自适应范围,用于 ROI 表中的值,这些值取决于使用的时间框架。默认情况下,值在以下范围内变化(对于一些最常用的时间框架,值四舍五入到小数点后三位):
# step | 1m | 5m | 1h | 1d | ||||
---|---|---|---|---|---|---|---|---|
1 | 2...12 | 0.02...0.15 | 10...60 | 0.02...0.15 | 120...720 | 0.02...0.15 | 2880...17280 | 0.02...0.15 |
2 | 3...18 | 0.01...0.10 | 15...90 | 0.01...0.10 | 180...1080 | 0.01...0.10 | 4320...25920 | 0.01...0.10 |
3 | 4...24 | 0.01...0.07 | 20...120 | 0.01...0.07 | 240...1440 | 0.01...0.07 | 5760...34560 | 0.01...0.07 |
4 | 6...44 | 0.0 | 30...220 | 0.0 | 360...2640 | 0.0 | 8640...63360 | 0.0 |
这些范围应该足以满足大多数情况。步骤中的分钟(ROI dict 键)按比例缩放,取决于使用的时间框架。步骤中的 ROI 值按比例缩放,取决于使用的时间框架。
如果您有 generate_roi_table()
和 roi_space()
方法,请删除它们,以利用这些自适应 ROI 表和 Freqtrade 生成的 ROI 超参优化空间。
覆盖 roi_space()
方法,如果您需要 ROI 表组件在其他范围内变化。覆盖 generate_roi_table()
和 roi_space()
方法并实现您自己的自定义方法,以在 hyperoptimization 期间生成 ROI 表。
这些方法的示例可以在 overriding pre-defined spaces section 中找到。
理解 Hyperopt Stoploss 结果¶
如果您正在优化止损值(即如果优化搜索空间包含 ‘all’、‘default’ 或 ‘stoploss’),您的结果将如下所示并包括止损:
Best result:
44/100: 135 trades. Avg profit 0.57%. Total profit 0.03871918 BTC (0.7722%). Avg duration 180:34 min. Objective: 1.94367
Stoploss: -0.0699
为了在回测和实时交易/干运行中使用这个最佳止损值,复制并粘贴它作为自定义策略的 stoploss
属性值:
# 最佳止损值
stoploss = -0.0699
如评论中所述,您也可以将其用作配置文件中的 stoploss
设置值。
默认止损搜索空间¶
如果您正在优化止损值,Freqtrade 为您创建了 ‘stoploss’ 优化超空间。默认情况下,该超空间中的止损值范围为 -0.35...-0.02,足以满足大多数情况。
如果您有 stoploss_space()
方法,请删除它以利用 Freqtrade 生成的 Stoploss 超参优化空间。
覆盖 stoploss_space()
方法并定义您需要的范围,如果您需要止损值在 hyperoptimization 期间在其他范围内变化。这个方法的示例可以在 overriding pre-defined spaces section 中找到。
理解 Hyperopt Trailing Stop 结果¶
如果您正在优化追踪止损值(即如果优化搜索空间包含 ‘all’ 或 ‘trailing’),您的结果将如下所示并包括追踪止损参数:
Best result:
44/100: 135 trades. Avg profit 0.57%. Total profit 0.03871918 BTC (0.7722%). Avg duration 180:34 min. Objective: 1.94367
Trailing stop:
{
'trailing_stop': True,
'trailing_stop_positive': 0.0201,
'trailing_stop_positive_offset': 0.0547,
'trailing_only_offset_is_reached': True
}
为了在回测和实时交易/干运行中使用这些最佳追踪止损参数,复制并粘贴它们作为自定义策略的相应属性值:
# 追踪止损
# 如果配置文件包含相应的值,这些属性将被覆盖。
trailing_stop = True
trailing_stop_positive = 0.0201
trailing_stop_positive_offset = 0.0547
trailing_only_offset_is_reached = True
如评论中所述,您也可以将其用作配置文件中的相应设置值。
默认追踪止损搜索空间¶
如果您正在优化追踪止损值,Freqtrade 为您创建了 ‘trailing’ 优化超空间。默认情况下,trailing_stop
参数在该超空间中始终设置为 True,trailing_only_offset_is_reached
值在 True 和 False 之间变化,trailing_stop_positive
和 trailing_stop_positive_offset
参数在 0.02...0.35 和 0.01...0.1 范围内变化,足以满足大多数情况。
覆盖 trailing_space()
方法并定义您需要的范围,如果您需要值在 hyperoptimization 期间在其他范围内变化。这个方法的示例可以在 overriding pre-defined spaces section 中找到。
可重复的结果¶
最佳参数搜索从参数空间中的几个(目前是 30)随机组合开始,随机 Hyperopt 轮次。这些随机轮次在 Hyperopt 输出中的第一列中用星号字符 (*
) 标记。
这些随机值的初始状态(随机状态)由 --random-state
命令行选项的值控制。您可以将其设置为任意值,以获得可重复的结果。
如果您没有在命令行选项中明确设置此值,Hyperopt 会为您提供一些随机值。每个 Hyperopt 运行的随机状态值显示在日志中,因此您可以复制并粘贴它到 --random-state
命令行选项中,以重复使用初始随机轮次集。
如果您没有更改命令行选项、配置、时间范围、策略和 Hyperopt 类、历史数据和损失函数,您应该获得相同的超参优化结果,使用相同的随机状态值。
输出格式化¶
默认情况下,hyperopt 打印彩色结果——利润为正的 epoch 以绿色打印。此高亮帮助您找到可以稍后分析的有趣 epoch。利润为零或利润为负(损失)的 epoch 以正常颜色打印。如果您不需要结果的颜色化(例如,当您将 hyperopt 输出重定向到文件时),您可以通过在命令行中指定 --no-color
选项来切换颜色化。
您可以使用 --print-all
命令行选项,如果您想在 hyperopt 输出中看到所有结果,而不仅仅是最佳结果。当 --print-all
被使用时,当前最佳结果也默认高亮显示——它们以粗体(亮)样式打印。此功能也可以通过 --no-color
命令行选项关闭。
位置堆叠和禁用最大市场位置¶
在某些情况下,您可能需要运行 Hyperopt(和回测)与 --eps
/--enable-position-staking
参数,或者您可能需要将 max_open_trades
设置为非常高的数字以禁用对打开交易的限制。
默认情况下,hyperopt 模仿 Freqtrade Live Run/Dry Run 的行为,其中仅允许每对一个打开交易。所有对的交易总数也受 max_open_trades
设置的限制。在 Hyperopt/Backtesting 期间,这可能导致潜在的交易被已打开的交易隐藏(或屏蔽)。
--eps
/--enable-position-stacking
参数允许模拟多次购买同一对。使用 --max-open-trades
与非常高的数字将禁用对打开交易的限制。
您还可以在配置文件中通过明确设置 "position_stacking"=true
来启用位置堆叠。
内存错误¶
由于 hyperopt 消耗大量内存(每次并行回测过程需要一次将完整数据加载到内存中),您可能会遇到 “内存不足” 错误。 为了应对这些,您有多种选择:
- 减少对数。
- 减少使用的时间范围(
--timerange <timerange>
)。 - 避免使用
--timeframe-detail
(这会加载大量额外数据到内存中)。 - 减少并行进程的数量(
-j <n>
)。 - 增加机器的内存。
- 如果您使用大量具有
.range
功能的参数,请使用--analyze-per-epoch
。
目标已经在此点之前评估过¶
如果您看到 The objective has been evaluated at this point before.
- 那么这是一个信号,您的空间已经耗尽,或者接近耗尽。
基本上空间中的所有点都已被击中(或局部最小值已被击中) - 并且 hyperopt 不再在多维空间中尝试尚未尝试的点。
Freqtrade 尝试通过使用新的、随机化的点来解决 “局部最小值” 问题。
示例:
buy_ema_short = IntParameter(5, 20, default=10, space="buy", optimize=True)
# 这是买入空间中唯一的参数
买入空间有 15 个可能的值(5, 6, ... 19, 20
)。如果您现在运行买入空间的超参优化,hyperopt 将只有 15 个值可以尝试,然后运行完选项。
因此,您的 epoch 应该与可能的值对齐 - 或者您应该准备好中断运行,如果您注意到很多 The objective has been evaluated at this point before.
警告。
显示 Hyperopt 结果的详细信息¶
在您运行 Hyperopt 以获得所需的 epoch 数量后,您可以稍后列出所有结果进行分析,仅选择最佳或盈利一次,并显示以前评估的任何 epoch 的详细信息。这可以通过 hyperopt-list
和 hyperopt-show
子命令完成。这些子命令的使用在 实用工具子集相关 章节中描述。
输出来自策略的调试消息¶
如果您想输出策略的调试消息,您可以使用 logging
模块。默认情况下,Freqtrade 将输出所有级别为 INFO
或更高的消息。
import logging
class MyAwesomeStrategy(IStrategy):
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# 这将输出到日志文件
logging.info("计算指标")
# 这将输出到日志文件
logging.debug("计算指标 - 调试级别")
# 这将输出到日志文件
logging.warning("计算指标 - 警告级别")
# 这将输出到日志文件
logging.error("计算指标 - 错误级别")
# 这将输出到日志文件
logging.critical("计算指标 - 严重级别")
return dataframe
验证回测结果¶
一旦优化策略实现到您的策略中,您应该回测此策略,以确保一切按预期工作。
为了获得与 Hyperopt 期间相同的相同结果(交易次数、持续时间、利润等),请使用与 Hyperopt 相同的配置和参数(时间范围、时间框架、...)进行回测。
为什么我的回测结果与我的 Hyperopt 结果不匹配?¶
如果结果不匹配,请检查以下因素:
- 您可能已在
populate_indicators()
中添加了参数,这些参数仅在 所有 epoch 中计算一次。如果您是,例如,尝试优化多个 SMA 时间周期值,hyperoptable 时间周期参数应放置在populate_entry_trend()
中,该参数在每个 epoch 中计算。请参阅 Optimizing an indicator parameter。 - 如果您已禁用自动将 hyperopt 参数导出到 JSON 参数文件中,请双检查以确保您已将所有 hyperopted 值传输到策略中。
- 检查日志以验证设置了哪些参数以及使用了哪些值。
- 特别注意止损、max_open_trades 和追踪止损参数,因为这些参数通常在配置文件中设置,这些参数会覆盖对策略的更改。检查您的回测日志以确保没有参数无意中由配置设置(如
stoploss
、max_open_trades
或trailing_stop
)。 - 验证您是否没有意外的参数 JSON 文件覆盖策略参数或策略中的默认 hyperopt 设置。
- 验证如果您在回测中启用的任何保护措施在 hyperopting 时也已启用,反之亦然。当使用
--space protection
时,保护措施自动为 hyperopting 启用。