Skip to article frontmatterSkip to article content
Freqtrade 超参数优化

Hyperopt 超参数优化指南

使用 Hyperopt 优化策略参数

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 中所有任务/可能性的清单

根据您想要优化的空间,只需要以下部分:

很少情况下,您可能还需要创建一个名为 HyperOpt嵌套类并实现:

Hyperopt 执行逻辑

Hyperopt 将首先将您的数据加载到内存中,然后为每个交易对运行一次 populate_indicators() 以生成所有指标,除非指定了 --analyze-per-epoch

然后,Hyperopt 将分叉到不同的进程(处理器数量或 -j <n>),并反复运行回测,更改属于定义的 --spaces 的参数。

对于每组新参数,freqtrade 将首先运行 populate_entry_trend(),然后运行 populate_exit_trend(),然后运行常规回测过程来模拟交易。

回测后,结果将传递给损失函数,该函数将评估这个结果是否比之前的结果更好或更差。
基于损失函数结果,hyperopt 将确定下一轮回测中要尝试的下一组参数。

配置您的守卫和触发器

您需要在策略文件中更改两个地方来添加新的买入 hyperopt 进行测试:

在那里您有两种不同类型的指标:1. guards(守卫)和 2. triggers(触发器)。

  1. 守卫是类似"当 ADX < 10 时永不买入"或"当当前价格超过 EMA10 时永不买入"的条件。
  2. 触发器是在特定时刻实际触发买入的指标,如"当 EMA5 上穿 EMA10 时买入"或"当收盘价触及布林带下轨时买入"。

超参优化将在每个 epoch 轮次中选择一个触发器和可能的多个守卫。

出场信号优化

与上述入场信号类似,出场信号也可以优化。 将相应的设置放入以下方法中:

配置和规则与买入信号相同。

解决一个谜题

假设您很好奇:是否应该使用 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。
然后我们有三个分类变量。前两个是 TrueFalse。 我们使用这些来启用或禁用 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 次)。
它将使用给定的历史数据,并基于上述函数生成的买入信号模拟买入。
基于结果,超参数优化将告诉你哪个参数组合产生了最佳结果(基于配置的损失函数)。

参数类型

有四种参数类型,每种都适用于不同的目的。

参数选项

有两个参数选项可以帮助你快速测试各种想法:

优化指标参数

假设您有一个简单的策略 - 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/ 目录中的自己的文件中。

目前,以下损失函数是内置的:

创建自定义损失函数在文档的高级 Hyperopt 部分中介绍。

执行 Hyperopt

一旦您更新了 hyperopt 配置,您就可以运行它。 因为 hyperopt 尝试很多组合来找到最佳参数,所以需要时间才能获得好的结果。

我们强烈建议使用 screentmux 来防止任何连接丢失。

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 表。

合法值是:

当未指定 --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'
}

您应该理解这个结果如下:

自动参数应用到策略

当使用 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 表中的值,这些值取决于使用的时间框架。默认情况下,值在以下范围内变化(对于一些最常用的时间框架,值四舍五入到小数点后三位):

# step1m5m1h1d
12...120.02...0.1510...600.02...0.15120...7200.02...0.152880...172800.02...0.15
23...180.01...0.1015...900.01...0.10180...10800.01...0.104320...259200.01...0.10
34...240.01...0.0720...1200.01...0.07240...14400.01...0.075760...345600.01...0.07
46...440.030...2200.0360...26400.08640...633600.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_positivetrailing_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 消耗大量内存(每次并行回测过程需要一次将完整数据加载到内存中),您可能会遇到 “内存不足” 错误。 为了应对这些,您有多种选择:

目标已经在此点之前评估过

如果您看到 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-listhyperopt-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 结果不匹配?

如果结果不匹配,请检查以下因素: