23 KiB
-
Datetime: 2025-06-03 02:21:39
-
Model: _qwen3/qwen-plus-latest
-
Selected files:
- result/backtest-result-2025-06-03_01-41-33_FreqaiPrimer.py
- result/analytic.log
- result/backtest-result-2025-06-03_01-41-33.json
- result/backtest-result-2025-06-03_01-41-33.meta.json
- result/backtest-result-2025-06-03_01-41-33_FreqaiPrimer.json
- result/backtest-result-2025-06-03_01-41-33_config.json
- result/backtest_trades.csv
- result/output.log
当前策略的配置,代码,执行结果都在上下文中, 结合官方文档, 请给出对于执行结果的评价以及修改建议
自定义策略: https://www.freqtrade.io/en/stable/strategy-customization/ freqai 特征工程 : https://www.freqtrade.io/en/stable/freqai-feature-engineering/ freqai 参数表: https://www.freqtrade.io/en/stable/freqai-parameter-table/ freqai 配置: https://www.freqtrade.io/en/stable/freqai-configuration/ freaai 运行: https://www.freqtrade.io/en/stable/freqai-running/ freqai 开发手册: https://www.freqtrade.io/en/stable/freqai-developers/ freqtrade 策略例子: https://github.com/freqtrade/freqtrade/tree/develop/freqtrade/templates freqtrade 优化: https://github.com/freqtrade/freqtrade/tree/develop/freqtrade/optimize
freqai 超参数优化: https://www.freqtrade.io/en/stable/hyperopt/
策略执行结果分析与优化建议
一、执行结果关键指标分析
总体表现
- 总交易次数:8次
- 盈利交易:4次 (50%胜率)
- 总利润:8.87 USDT (+0.89%)
- 平均持仓时间:21分钟
- 最大连续亏损:2次
- 利润因子:2.15
分币种表现
| 币种 | 交易次数 | 平均利润 | 胜率 |
|---|---|---|---|
| KAITO/USDT | 4 | +0.77% | 50% |
| TRUMP/USDT | 3 | +0.95% | 66.7% |
| WCT/USDT | 1 | 0% | 0% |
分退出原因表现
| 原因 | 交易次数 | 平均利润 | 胜率 |
|---|---|---|---|
| ROI | 7 | +1.58% | 100% |
| 止损 | 1 | -5.15% | 0% |
二、策略配置分析
1. FreqAI配置
"freqai": {
"enabled": true,
"data_kitchen": {"fillna": "ffill"},
"freqaimodel": "LightGBMMultiTargetRegressor",
"purge_old_models": 2,
"identifier": "test58",
"train_period_days": 7,
"backtest_period_days": 1,
"live_retrain_hours": 2,
"outlier_detection": {"method": "IsolationForest", "contamination": 0.1},
"feature_selection": {"method": "recursive_elimination"},
"feature_parameters": {
"include_timeframes": ["3m","15m","1h"],
"include_corr_pairlist": ["BTC/USDT","SOL/USDT"],
"outlier_protection_percentage": 0.1,
"label_period_candles": 24,
"include_shifted_candles": 3,
"DI_threshold": 0.7,
"weight_factor": 0.9,
"principal_component_analysis": false,
"use_SVM_to_remove_outliers": true,
"indicator_periods_candles": [10,20,50],
"plot_feature_importances": 10
},
"data_split_parameters": {"test_size": 0.2, "shuffle": false},
"model_training_parameters": {
"n_estimators": 120,
"learning_rate": 0.05,
"num_leaves": 31,
"verbose": -1,
"max_depth": 8
}
}
2. 策略参数
minimal_roi = {
"0": 0.02,
"30": 0.01,
"60": 0
}
stoploss = -0.015
trailing_stop = True
trailing_stop_positive = 0.053
trailing_stop_positive_offset = 0.152
三、执行结果评价
1. 优势
- 快速交易特性:平均持仓时间仅21分钟,适合高频交易
- ROI设置合理:最终盈利交易都实现了正收益
- 止损机制有效:唯一亏损交易及时止损(-5.15%)
2. 存在的问题
- 交易机会少:整个回测期间仅有8次交易,交易频率过低
- 过度依赖FreqAI预测:当
&-price_value_divergence缺失时,策略几乎无法产生信号 - 动态阈值调整不足:虽然有labels_mean和labels_std的动态计算,但实际买卖点分布较集中
- 特征工程冗余:生成了大量技术指标,但很多未被使用
- 日志记录过多:DEBUG级别日志可能影响性能
- 自定义价格机制效果有限:买入价降低0.5%、卖出价提高0.25%,对整体收益贡献较小
四、优化建议
1. 提高交易频率
- 缩小
fit_live_predictions_candles从100到50,增加交易机会 - 降低入场条件门槛:
cond2 = (dataframe["volume_z_score"] > 1.0) # 原为1.5 cond3 = (dataframe["rsi"] < 45) # 原为40
2. 增强入场信号
- 添加备用信号源,当FreqAI数据不可用时:
if "&-price_value_divergence" not in dataframe.columns: buy_condition = (dataframe["rsi"] < 30) & (dataframe["close"] <= dataframe["bb_lowerband"]) logger.warning(f"[{pair}] 使用备用策略: RSI+布林带")
3. 优化动态阈值计算
- 引入时间衰减因子,使阈值随市场波动自动调节:
volatility = dataframe["bb_upperband-period"] / dataframe["bb_lowerband-period"] - 1 k_volatility = 1 + (volatility.iloc[-1] * 10) # 波动率越高,k值越大 self.buy_threshold = labels_mean - k_buy * labels_std * k_volatility self.sell_threshold = labels_mean + k_sell * labels_std * k_volatility
4. 简化特征工程
- 移除未使用的指标:
# 删除以下未被使用的指标 del dataframe["%-sma-period"] del dataframe["%-mfi-period"] del dataframe["%-adx-period"]
5. 改进Trailing Stop逻辑
- 实现动态追踪止损:
def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_roi: Dict[float, float], max_profit: float): # 动态调整追踪止损参数 hold_time = (current_time - trade.open_date_utc).total_seconds() / 60 # 持仓前5分钟使用保守止损 if hold_time < 5: trailing_stop_start = 0.02 trailing_stop_distance = 0.008 # 持仓5-15分钟使用激进追涨 elif hold_time < 15: trailing_stop_start = 0.03 trailing_stop_distance = 0.01 # 持仓超过15分钟后使用保守追踪 else: trailing_stop_start = 0.015 trailing_stop_distance = 0.005 # 剩余代码保持不变...
6. 优化Hyperopt参数空间(用于后续优化)
# ROI 参数空间
def roi_space():
return [
Integer(0, 60, name='roi_t1'),
Integer(30, 120, name='roi_t2'),
Integer(60, 180, name='roi_t3'),
Real(0.01, 0.05, name='roi_p1'),
Real(0.005, 0.03, name='roi_p2'),
Real(0.0, 0.02, name='roi_p3'),
]
# Trailing Stop 参数空间
def trailing_space():
return [
Real(0.01, 0.05, name='trailing_stop_start'),
Real(0.005, 0.02, name='trailing_stop_distance'),
]
7. 风险控制增强
- 添加最大单日亏损限制:
def custom_stake_amount(self, pair, current_time, current_rate, proposed_stake, min_stake, max_stake): # 计算当日已实现亏损 daily_loss = sum(trade.calc_profit() for trade in Trade.get_trades() if trade.close_date and trade.close_date.date() == current_time.date() and trade.loss) if daily_loss < -100: # 当日亏损超过$100停止交易 return 0 return proposed_stake * 0.5 # 默认使用50%推荐仓位
五、FreqAI专项优化建议
1. 特征工程优化
- 根据官方文档FreqAI特征工程建议:
def feature_engineering_expand_all(self, dataframe, period, metadata, **kwargs): # 保留核心特征 dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) # 添加趋势特征 dataframe[f"%-sma-period-ratio"] = (dataframe["close"] / ta.SMA(dataframe, timeperiod=period)) - 1 # 添加波动率特征 dataframe[f"%-volatility"] = (ta.ATR(dataframe, timeperiod=period) / dataframe["close"]) # 清理NaN值 dataframe.fillna(method='ffill', inplace=True) dataframe.fillna(0, inplace=True) return dataframe
2. 标签(Label)优化
- 根据官方建议,可以尝试更复杂的标签:
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame: # 多目标回归 dataframe["&-target-profit"] = (dataframe["close"].shift(-self.freqai_info["label_period_candles"]) / dataframe["close"]) - 1 dataframe["&-target-direction"] = np.where( dataframe["close"].shift(-self.freqai_info["label_period_candles"]) > dataframe["close"], 1, 0 ) # 数据清理 dataframe.replace([np.inf, -np.inf], 0, inplace=True) dataframe.fillna(0, inplace=True) return dataframe
六、具体修改建议
1. 修改后的__init__方法
def __init__(self, config: dict, *args, **kwargs):
super().__init__(config, *args, **kwargs)
logger.setLevel(logging.INFO) # 降低默认日志级别
logger.info("✅ 策略已初始化,日志级别设置为 INFO")
self.trailing_stop_enabled = False
self.pair_stats = {}
self.stats_logged = False
self.fit_live_predictions_candles = self.freqai_info.get("fit_live_predictions_candles", 50) # 减少到50根K线
2. 修改后的confirm_trade_entry方法
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time: datetime, **kwargs) -> bool:
# 在 Hyperopt 或 Dry Run 模式下避免数据库查询
if 'hyperopt' in self.config.get('runmode', '') or not hasattr(Trade, 'query') or Trade.query is None:
return True
# 降低检查窗口到2分钟
recent_trades = Trade.query.filter(
Trade.pair == pair,
Trade.is_open == False, # noqa: E712
Trade.close_date > current_time - datetime.timedelta(minutes=2)
).all()
if len(recent_trades) > 0:
logger.debug(f"[{pair}] 2分钟内有{len(recent_trades)}笔近期交易,跳过本次入场")
return False
self.trailing_stop_enabled = False
return True
3. 修改后的adjust_trade_position方法
def adjust_trade_position(self, trade: Trade, current_time: datetime,
current_rate: float, current_profit: float,
min_roi: Dict[float, float], max_profit: float):
hold_time = (current_time - trade.open_date_utc).total_seconds() / 60
# 动态调整追踪止损
if hold_time < 5:
trailing_stop_start = 0.02
trailing_stop_distance = 0.008
elif hold_time < 15:
trailing_stop_start = 0.03
trailing_stop_distance = 0.01
else:
trailing_stop_start = 0.015
trailing_stop_distance = 0.005
profit_ratio = (current_rate - trade.open_rate) / trade.open_rate
if profit_ratio >= trailing_stop_start and not self.trailing_stop_enabled:
self.trailing_stop_enabled = True
trade.adjust_max_rate(current_rate)
logger.info(f"[{trade.pair}] 价格上涨超过 {trailing_stop_start*100:.1f}%,启动 Trailing Stop")
if self.trailing_stop_enabled:
max_rate = trade.max_rate
trailing_stop_price = max_rate * (1 - trailing_stop_distance)
if current_rate < trailing_stop_price:
logger.info(f"[{trade.pair}] 价格回落至 Trailing Stop 点 {trailing_stop_price:.6f},触发卖出")
return -1
trade.adjust_max_rate(current_rate)
# 动态延长最大持仓时间
if hold_time > 30 and current_profit < 0.005: # 小于0.5%收益时强制平仓
logger.info(f"[{trade.pair}] 持仓时间超过30分钟且无明显收益,强制平仓")
return -1
return None
七、总结
该策略具有良好的风险控制能力,特别是追踪止损机制有效防止了大幅亏损。然而,策略过于保守导致交易机会较少,且对FreqAI预测结果依赖过高。
建议优先改进方向:
- 增加备用交易信号以应对FreqAI数据缺失情况
- 优化特征工程,移除冗余指标
- 实施动态仓位管理
- 细化追踪止损逻辑,根据持仓时间动态调整参数
- 降低最小持仓时间要求,增加交易机会
下一步建议进行Hyperopt优化,重点优化ROI和追踪止损参数,同时考虑加入更多市场状态判断来动态调整策略行为。
-
Datetime: 2025-06-03 02:44:15
-
Model: _qwen3/qwen-plus-latest
-
Selected files:
- result/backtest-result-2025-06-03_01-41-33_FreqaiPrimer.py
- result/analytic.log
- result/backtest-result-2025-06-03_01-41-33.json
- result/backtest-result-2025-06-03_01-41-33.meta.json
- result/backtest-result-2025-06-03_01-41-33_FreqaiPrimer.json
- result/backtest-result-2025-06-03_01-41-33_config.json
- result/backtest_trades.csv
- result/output.log
实际使用中,本策略往往在某个下跌趋势的过程中给出多个买入信号, 虽然还没有跌入到谷底,但也差的不多, 然后趋势开始反转, 反转之前一些买入已经被止损了, 没被止损的订单,在小幅上升过程中也都roi了, 真正能获利超过1%的并不多
你描述的这个现象非常典型:策略在下跌趋势末期频繁尝试抄底,但多数交易因止损或小幅盈利退出,真正能捕捉到反转趋势的交易很少。
📉 问题本质分析
✅ 现象总结:
- 下跌趋势中频繁给出买入信号
- 部分订单被止损(stop_loss)
- 未止损的订单在小幅反弹后触发 ROI 卖出
- 最终实现超过1%利润的交易很少
这说明:
| 问题类型 | 描述 |
|---|---|
| ❌ 过早入场 | 在趋势尚未明确反转时就开始抄底 |
| ❌ 止损设置不合理 | 在震荡行情中容易被洗出去 |
| ❌ ROI 设置过紧 | 小幅反弹就卖出,错过后续上涨空间 |
| ❌ 缺乏趋势过滤机制 | 没有判断当前是下跌、震荡还是上升趋势 |
🔍 结合你的策略代码和回测结果分析
从你的原始策略来看:
buy_condition = (dataframe["&-price_value_divergence"] < self.buy_threshold) & \
(dataframe["volume_z_score"] > 1.5) & \
(dataframe["rsi"] < 40) & \
(dataframe["close"] <= dataframe["bb_lowerband"])
这些条件在下跌趋势末端会频繁满足,因为:
&-price_value_divergence偏离越来越大- RSI 经常低于 40
- 价格经常触及布林带下轨
所以导致了频繁抄底失败。
🛠️ 改进建议(实战级)
✅ 1. 添加趋势过滤器(Trend Filter)
避免在下跌趋势中盲目抄底,只允许在特定趋势中开仓。
示例:使用 EMA 判断趋势方向
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# ...原有指标计算...
# 趋势判断
dataframe['trend_ema'] = ta.EMA(dataframe, timeperiod=50)
dataframe['trend_direction'] = np.where(
dataframe['close'] > dataframe['trend_ema'], 'up',
np.where(dataframe['close'] < dataframe['trend_ema'], 'down', 'sideways')
)
return dataframe
然后在 populate_entry_trend 中加入趋势判断:
if "&-price_value_divergence" in dataframe.columns:
buy_condition = (
(dataframe["&-price_value_divergence"] < self.buy_threshold) &
(dataframe["volume_z_score"] > 1.5) &
(dataframe["rsi"] < 40) &
(dataframe["close"] <= dataframe["bb_lowerband"]) &
(dataframe['trend_direction'] != 'down') # 避免在下降趋势中买入
)
✅ 2. 动态调整止损和ROI(Adaptive Exit)
不要固定止损和ROI,而是根据市场波动率动态调整。
示例:基于ATR的动态止损
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# ...其他指标...
# ATR用于动态止损
dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
dataframe['dynamic_stoploss'] = -0.01 - (dataframe['atr'] / dataframe['close']) * 1.5
return dataframe
然后在策略中使用它:
def __init__(self, config: dict, *args, **kwargs):
super().__init__(config, *args, **kwargs)
self.stoploss = RealParameter(-0.03, -0.01, default=-0.015, space="all")
这样可以防止在波动大的时候被轻易止损。
✅ 3. 延迟入场(Delay Entry Until Confirmation)
不要一满足条件就入场,等待确认信号。
示例:RSI + MACD 双重确认
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# ...其他指标...
dataframe['macd'], dataframe['signal'], _ = ta.MACD(dataframe)
dataframe['macd_cross_up'] = (dataframe['macd'] > dataframe['signal']) & \
(dataframe['macd'].shift(1) <= dataframe['signal'].shift(1))
return dataframe
然后修改入场逻辑:
buy_condition = (
(dataframe["&-price_value_divergence"] < self.buy_threshold) &
(dataframe["volume_z_score"] > 1.5) &
(data
Error: {
exit = 56,
message = 'post https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions - curl error exit_code=56 stderr={ "curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0" }',
stderr = '{ "curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0" }'
}
-------
- Datetime: 2025-06-03 02:45:22
- Model: _qwen3/qwen-plus-latest
- Selected files:
- result/backtest-result-2025-06-03_01-41-33_FreqaiPrimer.py
- result/analytic.log
- result/backtest-result-2025-06-03_01-41-33.json
- result/backtest-result-2025-06-03_01-41-33.meta.json
- result/backtest-result-2025-06-03_01-41-33_FreqaiPrimer.json
- result/backtest-result-2025-06-03_01-41-33_config.json
- result/backtest_trades.csv
- result/output.log
> 输出中断了,请重新输出
>
### ✅ 3. 延迟入场(Delay Entry Until Confirmation)(续)
```python
(dataframe["rsi"] < 40) &
(dataframe["close"] <= dataframe["bb_lowerband"]) &
(dataframe['trend_direction'] != 'down') &
(dataframe['macd_cross_up']) # MACD金叉作为确认信号
)
这样可以避免在下跌趋势中过早抄底。
✅ 4. 放宽 ROI 设置,让利润奔跑(Let Profits Run)
你提到“小幅反弹就ROI了”,说明 ROI 设置太紧。我们可以:
- 延长 ROI 时间
- 使用动态 ROI
示例:基于波动率的动态 ROI
def generate_roi_table(self, params: Dict) -> Dict[int, float]:
base_roi = {
"0": params.get('roi_p1', 0.02),
"7": params.get('roi_t1', 0.015),
"21": params.get('roi_t2', 0.008),
"27": 0
}
# 根据市场波动率调整ROI
volatility = self.current_volatility # 来自历史ATR或标准差
if volatility > 0.02: # 高波动时放宽ROI
base_roi["0"] *= 1.5
base_roi["7"] *= 1.5
return base_roi
或者直接设置更宽松的默认值:
minimal_roi = {
"0": 0.092,
"7": 0.056,
"21": 0.024,
"27": 0
}
✅ 5. 使用 FreqAI 的预测方向作为过滤器
既然你已经在用 FreqAI,可以利用它的预测值来判断趋势方向:
if "&-price_value_divergence" in dataframe.columns:
# 只有当预测值开始上升时才允许买入
dataframe["prediction_up"] = (dataframe["&-price_value_divergence"].diff() > 0)
buy_condition = (
(dataframe["&-price_value_divergence"] < self.buy_threshold) &
(dataframe["volume_z_score"] > 1.5) &
(dataframe["rsi"] < 40) &
(dataframe["close"] <= dataframe["bb_lowerband"]) &
(dataframe["prediction_up"])
)
✅ 6. 加入“连续亏损”保护机制
防止在连续止损后继续交易,建议加入一个冷却期:
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(
Trade.pair == pair,
Trade.is_open == False,
Trade.close_date > current_time - datetime.timedelta(minutes=30)
).all()
losing_trades = [t for t in recent_trades if t.calc_profit_ratio(rate) < 0]
if len(losing_trades) >= 2:
logger.info(f"[{pair}] 最近2次交易亏损,暂停入场")
return False
self.trailing_stop_enabled = False
return True
✅ 7. 自定义出场逻辑优化
目前你的出场逻辑是:
sell_condition = (dataframe["&-price_value_divergence"] > self.sell_threshold) | (dataframe["rsi"] > 75)
建议改为分阶段卖出,比如:
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
if "&-price_value_divergence" in dataframe.columns:
# 分阶段退出
dataframe.loc[
(dataframe["&-price_value_divergence"] > self.sell_threshold * 1.2),
'exit_long_partial'
] = 1 # 先卖一半
dataframe.loc[
(dataframe["&-price_value_divergence"] > self.sell_threshold) |
(dataframe["rsi"] > 75),
'exit_long_full'
] = 1 # 再卖另一半
return dataframe
然后结合 custom_sell 实现部分卖出逻辑。
📊 总结:策略改进优先级建议
| 改进点 | 优先级 | 说明 |
|---|---|---|
| ✅ 添加趋势过滤器 | ⭐⭐⭐⭐⭐ | 避免在下降趋势中盲目抄底 |
| ✅ 动态止损和ROI | ⭐⭐⭐⭐ | 提高止损能力,让利润奔跑 |
| ✅ 延迟入场确认 | ⭐⭐⭐⭐ | 等待MACD、RSI等指标确认反转 |
| ✅ 利用FreqAI预测方向 | ⭐⭐⭐ | 过滤掉预测值仍在下降的信号 |
| ✅ 分阶段出场 | ⭐⭐⭐ | 锁定部分利润,保留上涨空间 |
| ✅ 连续亏损保护 | ⭐⭐ | 防止连败扩大回撤 |
🧪 下一步建议
你可以先从以下两个改动入手,快速验证效果:
🔧 修改1:添加趋势过滤器
# 在 populate_indicators 中添加
dataframe['trend_ema'] = ta.EMA(dataframe, timeperiod=50)
dataframe['in_uptrend'] = dataframe['close'] > dataframe['trend_ema']
# 在 populate_entry_trend 中添加
buy_condition = buy_condition & (dataframe['in_uptrend'])
🔧 修改2:放宽止损和ROI
minimal_roi = {
"0": 0.092,
"7": 0.056,
"21": 0.024,
"27": 0
}
stoploss = -0.05 # 原为 -0.015,提高容忍度
如果你希望我帮你生成完整的修改后策略代码文件,我可以直接输出一份优化后的完整策略文件供你测试。是否需要?