hyperopt & change freqai params

This commit is contained in:
zhangkun9038@dingtalk.com 2025-06-03 23:27:35 +00:00
parent c167bf5df0
commit 998ac0a7b1
5 changed files with 253 additions and 51 deletions

128
chat/hyperopt.md Normal file
View File

@ -0,0 +1,128 @@
- Datetime: 2025-06-03 17:30:28
- Model: _qwen3/qwen-plus-latest
- Selected files:
- freqtrade/templates/freqaiprimer.py
> https://www.freqtrade.io/en/stable/hyperopt/
> 在官方文档中,有没有提到hyperopt多久执行一次, 每次timerange的跨度是几天
非常感谢你的提问!
你提供的链接是 Freqtrade 的官方 Hyperopt 文档:
🔗 [https://www.freqtrade.io/en/stable/hyperopt/](https://www.freqtrade.io/en/stable/hyperopt/)
---
## ✅ 回答你的问题:
> **官方文档中没有明确说明“Hyperopt 应该多久执行一次”或“每次 timerange 的跨度应该是几天”**,但我们可以从文档和最佳实践中推导出合理的建议。
---
## 📚 官方文档相关提示
在文档的以下部分提到了一些关键信息:
### 1. **关于 `--timerange`**
> You can use the `--timerange` parameter to specify which date range you want to use for Hyperopt.
示例:
```bash
freqtrade hyperopt --timerange 20200101-20210101 ...
```
这意味着你可以自由指定训练数据的时间范围。
---
### 2. **关于训练集大小Training Set Size**
> The larger your training set, the more reliable your results will be — but the longer it will take to run.
也就是说:
- 更大的训练集 → 更可靠的结果
- 更小的训练集 → 更快完成,但可能过拟合
---
### 3. **关于优化目标Optimization Target**
Freqtrade 推荐使用如 `SortinoRatio`, `SharpeRatio`, 或 `Profit` 作为优化目标,以确保策略具有良好的风险收益比。
---
## ✅ 实战经验总结Hyperopt 执行频率 & Timerange 设置建议
| 问题 | 建议 |
|------|------|
| ❓ Hyperopt 多久执行一次? | ✅ 每次策略逻辑、参数空间或市场环境发生重大变化时运行一次 |
| ❓ 每次 Hyperopt 使用多少历史数据? | ✅ 至少 **30天以上**,推荐 **90~180天** |
| ❓ Hyperopt 需要定期重新运行吗? | ✅ 是的,建议每 **1~3个月** 重新运行一次,适应市场变化 |
---
## 🧠 推荐配置(基于实战经验)
### ✅ Hyperopt 运行频率建议:
| 场景 | 推荐频率 |
|------|-----------|
| 策略首次开发 | ✅ 必须运行一次 |
| 策略小幅调整(如指标、阈值) | ✅ 每次修改后运行 |
| 市场风格切换(如牛市→熊市) | ✅ 每季度运行一次 |
| 策略部署到实盘前 | ✅ 必须运行并验证 |
---
### ✅ `--timerange` 时间跨度建议:
| 目标 | 推荐时间跨度 |
|------|----------------|
| 快速测试 | ✅ 7~14天 |
| 中期趋势策略 | ✅ 30~60天 |
| 长期趋势策略 | ✅ 90~180天 |
| 多币种轮动策略 | ✅ 至少覆盖一个完整周期(如牛熊交替) |
---
### ✅ 示例命令:
```bash
# 快速测试用7天
freqtrade hyperopt --strategy MyStrategy --timerange 20250501-20250507 --timeframe 5m --hyperopt-loss SharpeHyperOptLossDaily
# 正式优化用30天
freqtrade hyperopt --strategy MyStrategy --timerange 20250401-20250501 --timeframe 5m --hyperopt-loss SortinoHyperOptLoss
# 多币种轮动策略90天+
freqtrade hyperopt --strategy MyStrategy --timerange 20250101-20250401 --timeframe 15m --hyperopt-loss ProfitHyperOptLoss --spaces all
```
---
## 🛠️ 补充建议Hyperopt 的最佳实践
| 建议 | 描述 |
|------|------|
| 🔁 分阶段运行 | 先跑短期7天快速验证逻辑再跑长期30天优化参数 |
| 📊 使用合适的时间粒度 | 如果你是做日内交易,使用 `1m``5m`;如果是波段交易,使用 `15m``1h` |
| 🧪 多币种回测 | 使用多个币种进行 Hyperopt避免单币过拟合 |
| 📦 保存结果 | 使用 `--export-filename` 导出最优参数,便于复用 |
---
## ✅ 总结
| 问题 | 推荐做法 |
|------|-----------|
| Hyperopt 多久执行一次? | ✅ 每次策略更新或市场环境变化时运行 |
| 每次 Hyperopt 使用多少数据? | ✅ 最少 7~14天推荐 30~90天 |
| 是否需要定期重新运行? | ✅ 是的,建议每月或每季度重新运行一次 |
---
如果你希望我帮你生成一个完整的 Hyperopt 配置文件(含推荐的 timerange、loss 函数、参数空间等),我可以继续为你输出。是否需要?

View File

@ -107,11 +107,11 @@
"shuffle": false
},
"model_training_parameters": {
"n_estimators": 120,
"learning_rate": 0.05,
"n_estimators": 60,
"learning_rate": 0.1,
"num_leaves": 31,
"verbose": -1,
"max_depth": 8
"verbose": 1,
"max_depth": 4
}
},
"api_server": {

View File

@ -2,29 +2,35 @@
"strategy_name": "FreqaiPrimer",
"params": {
"max_open_trades": {
"max_open_trades": 2
"max_open_trades": 4
},
"buy": {},
"sell": {},
"protection": {
"cooldown_period": 5
"buy": {
"BUY_THRESHOLD_MAX": -0.005,
"BUY_THRESHOLD_MIN": -0.05
},
"sell": {
"SELL_THRESHOLD_MAX": 0.05,
"SELL_THRESHOLD_MIN": 0.005,
"TRAILING_STOP_DISTANCE": 0.01,
"TRAILING_STOP_START": 0.03
},
"protection": {},
"roi": {
"0": 0.03,
"15": 0.02,
"30": 0.015,
"45": 0.01,
"60": 0.002
"0": 0.135,
"21": 0.033,
"41": 0.007,
"110": 0
},
"stoploss": {
"stoploss": -0.015
"stoploss": -0.036
},
"trailing": {
"trailing_stop": true,
"trailing_stop_positive": 0.005,
"trailing_stop_positive_offset": 0.01
"trailing_stop_positive": 0.151,
"trailing_stop_positive_offset": 0.237,
"trailing_only_offset_is_reached": true
}
},
"ft_stratparam_v": 1,
"export_time": "2025-05-31 23:03:00.000000+09:00"
}
"export_time": "2025-06-03 22:51:36.760022+00:00"
}

View File

@ -9,21 +9,42 @@ from freqtrade.persistence import Trade
import talib.abstract as ta
from pandas import DataFrame
from typing import Dict
from freqtrade.strategy import IStrategy
from freqtrade.strategy import (DecimalParameter, IStrategy, IntParameter)
logger = logging.getLogger(__name__)
class FreqaiPrimer(IStrategy):
"""
基于 FreqAI 的动态阈值交易策略
"""
# --- 🧪 Hyperopt Parameters ---
# ROI 参数(用于收益目标)
ROI_T0 = DecimalParameter(0.01, 0.05, default=0.02, space='roi', optimize=True)
ROI_T1 = DecimalParameter(0.005, 0.02, default=0.01, space='roi', optimize=True)
ROI_T2 = DecimalParameter(0.0, 0.01, default=0.0, space='roi', optimize=True)
# Trailing Stop 参数(追踪止损)
TRAILING_STOP_START = DecimalParameter(0.01, 0.05, default=0.03, space='sell', optimize=True)
TRAILING_STOP_DISTANCE = DecimalParameter(0.005, 0.02, default=0.01, space='sell', optimize=True)
# 买卖阈值边界(你要优化的目标)
BUY_THRESHOLD_MIN = DecimalParameter(-0.1, -0.01, default=-0.05, space='buy', optimize=True)
BUY_THRESHOLD_MAX = DecimalParameter(-0.02, -0.001, default=-0.005, space='buy', optimize=True)
SELL_THRESHOLD_MIN = DecimalParameter(0.001, 0.02, default=0.005, space='sell', optimize=True)
SELL_THRESHOLD_MAX = DecimalParameter(0.02, 0.1, default=0.05, space='sell', optimize=True)
# --- 🛠️ 固定配置参数 ---
minimal_roi = {
"0": 0.02,
"30": 0.01,
"60": 0
"0": ROI_T0.value,
"30": ROI_T1.value,
"60": ROI_T2.value
}
stoploss = -0.015
timeframe = "3m"
use_custom_stoploss = False
plot_config = {
@ -82,6 +103,7 @@ class FreqaiPrimer(IStrategy):
self.pair_stats = {}
self.stats_logged = False
self.fit_live_predictions_candles = self.freqai_info.get("fit_live_predictions_candles", 100)
self.last_entry_time = {} # 记录每个币种的最后入场时间
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period)
@ -215,7 +237,26 @@ class FreqaiPrimer(IStrategy):
labels_std = 0.01
logger.warning(f"[{pair}] labels_std 计算异常,使用默认值 0.01")
self.pair_stats[pair] = {"labels_mean": labels_mean, "labels_std": labels_std}
# 根据 labels_std 调整 k 值
if labels_std > 0.015:
k_buy = 1.2
k_sell = 1.5
elif labels_std < 0.010:
k_buy = 0.8
k_sell = 1.0
else:
k_buy = 1.0
k_sell = 1.2
if labels_mean > 0.015:
k_sell += 0.5
self.buy_threshold = labels_mean - k_buy * labels_std
self.sell_threshold = labels_mean + k_sell * labels_std
else:
self.buy_threshold = -0.02
self.sell_threshold = 0.03
self.pair_stats[pair] = {"labels_mean": labels_mean, "labels_std": labels_std}
if labels_std > 0.015:
k_buy = 1.2
@ -234,15 +275,17 @@ class FreqaiPrimer(IStrategy):
self.buy_threshold = labels_mean - k_buy * labels_std
self.sell_threshold = labels_mean + k_sell * labels_std
# self.buy_threshold = max(self.buy_threshold, -0.05)
# self.buy_threshold = min(self.buy_threshold, -0.005)
# self.sell_threshold = min(self.sell_threshold, 0.05)
# self.sell_threshold = max(self.sell_threshold, 0.005)
# 使用 Hyperopt 参数动态限制阈值
self.buy_threshold = max(self.buy_threshold, self.BUY_THRESHOLD_MIN.value)
self.buy_threshold = min(self.buy_threshold, self.BUY_THRESHOLD_MAX.value)
self.sell_threshold = min(self.sell_threshold, self.SELL_THRESHOLD_MAX.value)
self.sell_threshold = max(self.sell_threshold, self.SELL_THRESHOLD_MIN.value)
logger.info(f"[{pair}] labels_mean{labels_mean:.4f}, labels_std{labels_std:.4f}")
logger.info(f"[{pair}] k_buy{k_buy:.2f}, k_sell{k_sell:.2f}")
logger.info(f"[{pair}] 动态买入阈值:{self.buy_threshold:.4f}")
logger.info(f"[{pair}] 动态卖出阈值:{self.sell_threshold:.4f}")
logger.info(f"[{pair}] 当前买入阈值:{self.buy_threshold:.6f},卖出阈值:{self.sell_threshold:.6f}")
if not self.stats_logged:
logger.info("===== 所有币对的 labels_mean 和 labels_std 汇总 =====")
@ -253,6 +296,27 @@ class FreqaiPrimer(IStrategy):
return dataframe
def generate_roi_table(self, params: Dict) -> Dict[int, float]:
roi_table = {
"0": params.get("roi_t0", 0.02),
"30": params.get("roi_t1", 0.01),
"60": params.get("roi_t2", 0.0),
}
return roi_table
def roi_space(self):
return [
DecimalParameter(0.01, 0.05, name="roi_t0"),
DecimalParameter(0.005, 0.02, name="roi_t1"),
DecimalParameter(0.0, 0.01, name="roi_t2")
]
def trailing_space(self):
return [
DecimalParameter(0.01, 0.05, name="trailing_stop_start"),
DecimalParameter(0.005, 0.02, name="trailing_stop_distance")
]
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
pair = metadata.get('pair', 'Unknown')
conditions = []
@ -345,20 +409,24 @@ class FreqaiPrimer(IStrategy):
return None
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time: datetime, **kwargs) -> bool:
# 添加调试日志:检查是否允许买入
recent_trades = Trade.query.filter(
and_(
Trade.pair == pair,
Trade.is_open == False, # noqa: E712
Trade.close_date > current_time - datetime.timedelta(minutes=5)
)
).all()
if len(recent_trades) > 0:
logger.info(f"[{pair}] 5分钟内有近期交易{len(recent_trades)} 笔),跳过本次入场")
return False
time_in_force: str, current_time: datetime, **kwargs) -> bool:
# """
# 使用内存变量代替数据库查询,防止 Hyperopt 报错
# """
#
cooldown_period_minutes = 5 # 可以改为 DecimalParameter 进行 Hyperopt
if pair in self.last_entry_time:
last_time = self.last_entry_time[pair]
if (current_time - last_time).total_seconds() < cooldown_period_minutes * 60:
logger.info(f"[{pair}] 冷却期内,跳过本次入场")
return False
# 更新最后入场时间
self.last_entry_time[pair] = current_time
self.trailing_stop_enabled = False
# 如果我猜的没错的话, 用了这个方法上述被注释的内容, 反到降低了本策略盈利, 需要更多测试,所以暂时禁用并不删除
return True
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,

View File

@ -4,10 +4,10 @@
if [ ! -f ".env" ]; then
echo "⚠️ 本地缺少 .env 文件,请创建并配置。示例内容如下:"
echo ""
echo "STRATEGY_NAME=TheForceV7"
echo "CONFIG_FILE=basic.json"
echo "TEST_BRANCH=theforce-noai-test"
echo "DRYRUN_BRANCH=theforce-noai-dryrun"
echo "STRATEGY_NAME=FreqaiPrimer"
echo "CONFIG_FILE=FreqaiPrimer.json"
echo "TEST_BRANCH=freqaiprimer-deviation-test"
echo "DRYRUN_BRANCH=freqaiprimer-deviation-dryrun"
echo ""
exit 1
fi
@ -15,8 +15,8 @@ fi
# 加载 .env 文件中的变量
export $(grep -v '^#' .env | xargs)
# 设置默认值
STRATEGY_NAME=${STRATEGY_NAME:-TheForceV7}
CONFIG_FILE=${CONFIG_FILE:-basic.json}
STRATEGY_NAME=${STRATEGY_NAME:-FreqaiPrimer}
CONFIG_FILE=${CONFIG_FILE:-FreqaiPrimer.json}
echo "Using strategy: $STRATEGY_NAME"
echo "Using config: $CONFIG_FILE"
@ -34,7 +34,7 @@ rm -fr ./user_data/dryrun_results/*
#docker-compose -f docker-compose_backtest.yml run --rm freqtrade >output.log 2>&1
echo "docker-compose run --rm freqtrade hyperopt \
--logfile /freqtrade/user_data/logs/freqtrade.log \
--freqaimodel LightGBMRegressor \
--freqaimodel XGBoostRegressorMultiTarget \
--strategy $STRATEGY_NAME \
--config /freqtrade/config_examples/$CONFIG_FILE \
--strategy-path /freqtrade/templates \
@ -45,12 +45,12 @@ echo "docker-compose run --rm freqtrade hyperopt \
--fee 0.0016"
docker-compose run --rm freqtrade hyperopt \
--logfile /freqtrade/user_data/logs/freqtrade.log \
--freqaimodel LightGBMRegressorMultiTarget \
--freqaimodel XGBoostRegressorMultiTarget \
--strategy $STRATEGY_NAME \
--config /freqtrade/config_examples/$CONFIG_FILE \
--strategy-path /freqtrade/templates \
--timerange ${START_DATE}-${END_DATE} \
-e 200 \
-e 100 \
--hyperopt-loss ShortTradeDurHyperOptLoss \
--spaces roi stoploss trailing \
--fee 0.0016