freqtrade list-hyperoptloss 命令实战:发现并选择超参优化损失函数的完整指南
【免费下载链接】freqtradeFree, open source crypto trading bot项目地址: https://gitcode.com/GitHub_Trending/fr/freqtrade
list-hyperoptloss是 Freqtrade 用于列出所有可用超参优化(Hyperopt)损失函数的命令。本篇基于 list-hyperoptloss 命令参考,完整讲解该命令的用法与全部参数,并结合仓库源码说明其背后的类发现机制(HyperOptLossResolver)、内置损失函数清单及其各自优化目标,以及如何在hyperopt中通过--hyperopt-loss指定这些损失函数。读完本文,你可以快速确认当前环境中有哪些损失函数可用、自定义损失函数放在哪里才会被发现,并为优化任务选择更合适的优化目标。
命令概览与完整参数
list-hyperoptloss的输出即命令的 help 信息,完整用法如下(源自 docs/commands/list-hyperoptloss.md):
usage: freqtrade list-hyperoptloss [-h] [-v] [--no-color] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [--hyperopt-path PATH] [-1] options: -h, --help show this help message and exit --hyperopt-path PATH Specify additional lookup path for Hyperopt Loss functions. -1, --one-column Print output in one column. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). --no-color Disable colorization of hyperopt results. May be useful if you are redirecting output to a file. --logfile, --log-file FILE Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. -V, --version show program's version number and exit -c, --config PATH Specify configuration file (default: `userdir/config.json` or `config.json` whichever exists). Multiple --config options may be used. Can be set to `-` to read config from stdin. -d, --datadir, --data-dir PATH Path to the base directory of the exchange with historical backtesting data. To see futures data, use trading-mode additionally. --userdir, --user-data-dir PATH Path to userdata directory.该命令属于 Freqtrade 的一组 "list" 类只读工具命令,命令注册位于 freqtrade/commands/arguments.py:
list_hyperopt_loss_cmd = subparsers.add_parser( "list-hyperoptloss", help="Print available hyperopt loss functions.", parents=[_common_parser], ) list_hyperopt_loss_cmd.set_defaults(func=start_list_hyperopt_loss_functions) self._build_args(optionlist=ARGS_LIST_HYPEROPTS, parser=list_hyperopt_loss_cmd)参数逐项说明:
| 参数 | 作用 |
|---|---|
--hyperopt-path PATH | 指定 Hyperopt Loss 函数的额外查找路径。默认情况下命令只会扫描user_data/hyperopts/与内置目录;如果你把自定义损失函数放在其他目录,需要用它把该目录加入搜索范围 |
-1/--one-column | 以单列纯文本输出(每行一个类名),便于脚本处理或重定向到文件 |
-c/--config PATH | 指定配置文件;可重复使用以合并多份配置,也可设为-从 stdin 读取 |
-d/--datadir PATH | 历史数据目录(对纯列表命令影响有限,但与hyperopt共用同一套公共参数) |
--userdir/--user-data-dir PATH | 指定 userdata 目录。损失函数搜索路径中的user_data/hyperopts/正是相对此目录解析的 |
-v/--verbose | 开启详细日志,-vv、-vvv逐级增加 |
--no-color | 关闭彩色输出,输出重定向到文件时很有用 |
--logfile FILE | 写日志到文件,支持syslog、journald特殊值 |
-V/--version | 输出版本号后退出 |
由于该命令运行在RunMode.UTIL_NO_EXCHANGE模式下(见下文源码分析),它不需要连接交易所,是一个纯粹的本地扫描工具,可以放心在 CI 或脚本中频繁调用。
源码实现:命令如何发现损失函数
命令入口函数start_list_hyperopt_loss_functions位于 freqtrade/commands/list_commands.py:
def start_list_hyperopt_loss_functions(args: dict[str, Any]) -> None: """ Print files with FreqAI models custom classes available in the directory """ from freqtrade.configuration import setup_utils_configuration from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE) model_objs = HyperOptLossResolver.search_all_objects(config, not args["print_one_column"]) # Sort alphabetically model_objs = sorted(model_objs, key=lambda x: x["name"]) if args["print_one_column"]: print("\n".join([s["name"] for s in model_objs])) else: _print_objs_tabular(model_objs, config.get("print_colorized", False))从源码结构看,其执行链路为:
setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)构建工具类配置(不初始化交易所连接);- 调用
HyperOptLossResolver.search_all_objects(...)扫描所有候选目录,收集继承自IHyperOptLoss的类; - 结果按类名字母排序后输出:
--one-column时打印纯文本列表,否则通过_print_objs_tabular()渲染为 Rich 表格,表中还会标注每个类的location(来源文件相对路径)与加载状态(OK / LOAD FAILED / DUPLICATE NAME,状态列逻辑见 freqtrade/commands/list_commands.py)。
搜索路径的构成
真正决定"能列出哪些损失函数"的是HyperOptLossResolver的类属性,位于 freqtrade/resolvers/hyperopt_resolver.py:
class HyperOptLossResolver(IResolver): """ This class contains all the logic to load custom hyperopt loss class """ object_type = IHyperOptLoss object_type_str = "HyperoptLoss" user_subdir = USERPATH_HYPEROPTS # 即 "hyperopts" initial_search_path = Path(__file__).parent.parent.joinpath("optimize/hyperopt_loss").resolve()结合基类IResolver.build_search_paths()的实现(见 freqtrade/resolvers/iresolver.py),最终搜索顺序为(越靠前优先级越高):
--hyperopt-path指定的额外目录(extra_dirs插入到最前);<user_data_dir>/hyperopts/(USERPATH_HYPEROPTS = "hyperopts",定义于 freqtrade/constants.py);- 内置目录
freqtrade/optimize/hyperopt_loss/。
也就是说:自定义损失函数放进user_data/hyperopts/即可被发现,无需--hyperopt-path;放在仓库之外时才需要显式传入。扫描时基类会用importlib逐个加载.py文件,只收集本模块中定义(obj.__module__ == module_name)且继承自IHyperOptLoss的非接口类;导入失败的模块会被跳过并记录 warning(若开启enum_failed则会显示为 LOAD FAILED)。
损失函数接口:IHyperOptLoss
所有被列出的对象都必须实现IHyperOptLoss抽象接口,定义于 freqtrade/optimize/hyperopt_loss/hyperopt_loss_interface.py:
class IHyperOptLoss(ABC): """ Interface for freqtrade hyperopt Loss functions. Defines the custom loss function (`hyperopt_loss_function()` which is evaluated every epoch.) """ timeframe: str @staticmethod @abstractmethod def hyperopt_loss_function( *, results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, config: Config, processed: dict[str, DataFrame], backtest_stats: dict[str, Any], starting_balance: float, **kwargs, ) -> float: """ Objective function, returns smaller number for better results """要点:
hyperopt_loss_function必须是@staticmethod,每个 epoch 都会被调用一次;- 返回值是越小越好的目标值——Hyperopt 的整个搜索过程就是在最小化这个数;
- 函数签名提供了回测结果 DataFrame(
results)、交易数量(trade_count)、时间范围、完整配置、按对处理的 DataFrame(processed)与回测统计(backtest_stats),足以计算任意基于回测结果的指标; - 加载时 resolver 会把配置中的
timeframe赋值给损失函数类(hyperoptloss.__class__.timeframe = str(config["timeframe"]),见 freqtrade/resolvers/hyperopt_resolver.py),供损失函数感知当前优化粒度。
仓库自带的 freqtrade/templates/sample_hyperopt_loss.py 是一个可直接复制到user_data/hyperopts/改造的示例实现(包含TARGET_TRADES、EXPECTED_MAX_PROFIT、MAX_ACCEPTED_TRADE_DURATION等可调常量)。
内置的 12 种损失函数
内置损失函数集中定义在 freqtrade/optimize/hyperopt_loss/ 目录下,其名称清单在 freqtrade/constants.py 中以HYPEROPT_LOSS_BUILTIN维护:
HYPEROPT_LOSS_BUILTIN = [ "ShortTradeDurHyperOptLoss", "OnlyProfitHyperOptLoss", "SharpeHyperOptLoss", "SharpeHyperOptLossDaily", "SortinoHyperOptLoss", "SortinoHyperOptLossDaily", "CalmarHyperOptLoss", "MaxDrawDownHyperOptLoss", "MaxDrawDownRelativeHyperOptLoss", "MaxDrawDownPerPairHyperOptLoss", "ProfitDrawDownHyperOptLoss", "MultiMetricHyperOptLoss", ]list-hyperoptloss默认输出中就会包含上述全部 12 个内置类。它们在 超参优化文档 中的定义与优化目标如下:
| 类名 | 对应文件 | 优化目标 |
|---|---|---|
ShortTradeDurHyperOptLoss | hyperopt_loss_short_trade_dur.py | 传统(legacy)默认损失函数:侧重缩短平均交易时长并规避亏损 |
OnlyProfitHyperOptLoss | hyperopt_loss_onlyprofit.py | 只考虑盈利额(profit only) |
SharpeHyperOptLoss | hyperopt_loss_sharpe.py | 优化基于逐笔交易收益与其标准差计算的 Sharpe 比率 |
SharpeHyperOptLossDaily | hyperopt_loss_sharpe_daily.py | 优化基于每日收益的 Sharpe 比率 |
SortinoHyperOptLoss | hyperopt_loss_sortino.py | 优化基于逐笔收益与下行标准差的 Sortino 比率 |
SortinoHyperOptLossDaily | hyperopt_loss_sortino_daily.py | 优化基于每日收益与下行标准差的 Sortino 比率 |
CalmarHyperOptLoss | hyperopt_loss_calmar.py | 优化交易收益相对最大回撤的 Calmar 比率 |
MaxDrawDownHyperOptLoss | hyperopt_loss_max_drawdown.py | 优化最大绝对回撤 |
MaxDrawDownRelativeHyperOptLoss | hyperopt_loss_max_drawdown_relative.py | 同时优化最大绝对回撤,并按最大相对回撤调整 |
MaxDrawDownPerPairHyperOptLoss | hyperopt_loss_max_drawdown_per_pair.py | 按交易对计算收益/回撤比,以最差的一对为目标值,防止个别交易对的好结果"拉高"整体指标 |
ProfitDrawDownHyperOptLoss | hyperopt_loss_profit_drawdown.py | 以最大收益 + 最小回撤为联合目标;文件内DRAWDOWN_MULT常量可调松/调紧对回撤的惩罚 |
MultiMetricHyperOptLoss | hyperopt_loss_multi_metric.py | 综合收益、回撤、Profit Factor、Expectancy、胜率等多指标;并对交易数量过少的 epoch 施加惩罚,鼓励足够的交易频率 |
选择损失函数的经验(对应 docs/hyperopt.md 的 "Loss-functions" 一节):
- 追求资金曲线稳健性:优先考虑
SharpeHyperOptLossDaily/SortinoHyperOptLossDaily(按日归一,减少交易次数差异带来的偏差); - 控制回撤风险:
MaxDrawDownHyperOptLoss及其 Relative/PerPair 变体;PerPair变体特别适合多交易对组合,避免"一星带多尘"; - 平衡收益与回撤:
ProfitDrawDownHyperOptLoss、MultiMetricHyperOptLoss; ShortTradeDurHyperOptLoss是历史默认值,适合快速复现早期结果,但对现代组合目标通常不如比率型损失函数精细。
在 hyperopt 中使用损失函数
list-hyperoptloss列出的类名,正是运行超参优化时--hyperopt-loss参数的取值。该参数定义于 freqtrade/commands/cli_options.py,help 文本本身就提示了全部内置函数:
"hyperopt_loss": Arg( "--hyperopt-loss", "--hyperoptloss", help="Specify the class name of the hyperopt loss function class (IHyperOptLoss). " "Different functions can generate completely different results, " "since the target for optimization is different. Built-in Hyperopt-loss-functions are: " f"{', '.join(HYPEROPT_LOSS_BUILTIN)}", metavar="NAME", ),典型工作流是"先列后用":
# 1. 确认当前可用的损失函数(含 user_data/hyperopts/ 下的自定义类) freqtrade list-hyperoptloss # 2. 用单列格式写入脚本变量,方便程序化处理 freqtrade list-hyperoptloss --one-column > available_losses.txt # 3. 运行超参优化并指定损失函数 freqtrade hyperopt --config config.json --hyperopt-loss SharpeHyperOptLossDaily \ --strategy MyWorkingStrategy --spaces roi stoploss trailing -e 1000除命令行外,也可以在配置文件的"hyperopt_loss"键中指定(配置 schema 的校验同样引用HYPEROPT_LOSS_BUILTIN名单,见 freqtrade/config_schema/config_schema.py)。若在运行时两者都未指定,resolver 会抛出异常并列出全部内置函数名作为提示:
No Hyperopt loss set. Please use `--hyperopt-loss` to specify the Hyperopt-Loss class to use. Built-in Hyperopt-loss-functions are: ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss, ...(见 freqtrade/resolvers/hyperopt_resolver.py。)
自定义损失函数:让新类出现在列表中
要让自定义损失函数出现在list-hyperoptloss的输出里,需要满足三个条件,均与上文源码证据对应:
- 位置正确:文件放在
<user_data>/hyperopts/下(默认即被扫描),或使用--hyperopt-path /path/to/dir加入额外查找路径; - 类定义在本文件且直接继承
IHyperOptLoss(resolver 要求obj.__module__ == module_name,从其他模块 import 进来再转述的类不会被收录); - 实现静态方法
hyperopt_loss_function(...),返回"越小越好"的 float。
骨架示例(基于仓库模板 freqtrade/templates/sample_hyperopt_loss.py):
from datetime import datetime from pandas import DataFrame from freqtrade.constants import Config from freqtrade.optimize.hyperopt_loss import IHyperOptLoss class MyCustomLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function( *, results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, config: Config, processed: dict[str, DataFrame], backtest_stats: dict[str, Any], starting_balance: float, **kwargs, ) -> float: # 基于 results / backtest_stats 计算你自己的目标值,越小越好 return 0.0保存后执行freqtrade list-hyperoptloss,应能看到MyCustomLoss及其来源位置;之后即可用freqtrade hyperopt --hyperopt-loss MyCustomLoss ...运行。若加载失败(语法错误、缺依赖等),该条会显示为LOAD FAILED并打印失败原因,便于快速定位。更多自定义损失函数的完整写法参见 Advanced Hyperopt 文档。
常见问题小结
- 输出为空或找不到我的自定义类?检查
--userdir指向的目录下是否存在hyperopts/子目录,以及类是否直接定义在该目录的.py文件中而非被 import 转述;非默认位置请用--hyperopt-path。 - 输出重定向到文件乱码/带颜色码?加
--no-color;需要机器可读格式时用--one-column。 - 为什么
list-hyperoptloss不要求--config?该命令运行于UTIL_NO_EXCHANGE模式,只依赖本地文件系统;传入-c主要是为了让user_data等路径解析符合你的项目布局。 - 内置函数会随版本变化吗?以 freqtrade/constants.py 中
HYPEROPT_LOSS_BUILTIN的当前内容为准;命令 help 与--hyperopt-loss的帮助文本都直接引用该清单,二者始终一致。
小结
list-hyperoptloss虽是一条轻量的只读命令,却揭示了 Freqtrade 超参优化体系中"目标函数可插拔"的设计:HyperOptLossResolver按"额外路径 →user_data/hyperopts/→ 内置目录"的顺序扫描所有实现IHyperOptLoss的类,list-hyperoptloss负责把它们全部展示出来,hyperopt --hyperopt-loss则负责在优化时按名字加载。理解了这条链路,你就能自如地在 12 个内置损失函数与自研目标函数之间切换,为不同策略挑选最匹配的优化方向。
【免费下载链接】freqtradeFree, open source crypto trading bot项目地址: https://gitcode.com/GitHub_Trending/fr/freqtrade
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考