优化退出条件

This commit is contained in:
zhangkun9038@dingtalk.com 2025-07-03 08:37:07 +00:00
parent 04ad9ee171
commit 429f247deb
3 changed files with 42 additions and 30 deletions

View File

@ -22,14 +22,8 @@
"TRAILING_STOP_DISTANCE": 0.015,
"TRAILING_STOP_START": 0.016
},
"protection": {},
"trailing": {
"trailing_stop": true,
"trailing_stop_positive": 0.106,
"trailing_stop_positive_offset": 0.196,
"trailing_only_offset_is_reached": false
}
"protection": {}
},
"ft_stratparam_v": 1,
"export_time": "2025-07-01 14:51:29.420394+00:00"
}
}

View File

@ -19,9 +19,6 @@ class FreqaiPrimer(IStrategy):
基于 FreqAI 的动态阈值交易策略集成动态加仓减仓和自定义 ROI 逻辑兼容最新 Freqtrade 版本
"""
# --- 🧪 Hyperopt Parameters ---
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.15, -0.03, default=-0.07, space='buy', optimize=True)
BUY_THRESHOLD_MAX = DecimalParameter(-0.04, -0.005, default=-0.01, space='buy', optimize=True)
@ -190,6 +187,11 @@ class FreqaiPrimer(IStrategy):
dataframe["volume_mean_20"] = dataframe["volume"].rolling(20).mean()
dataframe["volume_std_20"] = dataframe["volume"].rolling(20).std()
dataframe["volume_z_score"] = (dataframe["volume"] - dataframe["volume_mean_20"]) / dataframe["volume_std_20"]
dataframe_15m = self.dp.get_pair_dataframe(pair=pair, timeframe="15m")
dataframe_15m['atr15m'] = ta.ATR(dataframe_15m, timeperiod=14)
dataframe['atr15m'] = dataframe_15m['atr15m'].reindex(dataframe.index, method="ffill")
dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20)
# 数据清理
for col in ["ema200", "bb_upperband", "bb_middleband", "bb_lowerband", "rsi", "volume_z_score", "&-price_value_divergence", "price_value_divergence"]:
@ -349,25 +351,35 @@ class FreqaiPrimer(IStrategy):
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
pair = metadata.get('pair', 'Unknown')
conditions = []
# 初始化所有条件为 False
cond1 = cond2 = cond3 = False
if "&-price_value_divergence" in dataframe.columns:
cond1 = (dataframe["&-price_value_divergence"] > self.sell_threshold * 1.025)
cond2 = (dataframe["rsi"] > 75)
sell_condition = cond1 | cond2
conditions.append(sell_condition)
cond1 = (dataframe["&-price_value_divergence"] > self.sell_threshold * 1.05)
logger.debug(f"[{pair}] 卖出条件检查 - "
f"&-price_value_divergence > {self.sell_threshold:.6f}: {cond1.iloc[-1]}, "
f"rsi > 75: {cond2.iloc[-1]}")
else:
logger.warning(f"[{pair}] ⚠️ &-price_value_divergence 列缺失,跳过该条件")
if "rsi" in dataframe.columns:
cond2 = (dataframe["rsi"] > 70)
if len(conditions) > 0:
dataframe.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1
logger.debug(f"[{pair}] 出场信号触发,条件满足")
else:
logger.debug(f"[{pair}] 无有效卖出条件")
if "ema10" in dataframe.columns and "ema20" in dataframe.columns:
cond3 = (dataframe['ema10'] < dataframe['ema20'])
# 组合卖出信号
sell_condition = cond1 | cond2 | cond3
if sell_condition.any():
dataframe.loc[sell_condition, 'exit_long'] = 1
# 获取最后一根K线的实际指标值用于日志
price_divergence = dataframe["&-price_value_divergence"].iloc[-1] if "&-price_value_divergence" in dataframe.columns else np.nan
rsi_value = dataframe["rsi"].iloc[-1] if "rsi" in dataframe.columns else np.nan
ema10_value = dataframe["ema10"].iloc[-1] if "ema10" in dataframe.columns else np.nan
ema20_value = dataframe["ema20"].iloc[-1] if "ema20" in dataframe.columns else np.nan
# 构建详细日志信息
logger.debug(f"[{pair}] 卖出条件检查 - "
f"&-price_value_divergence={price_divergence:.6f} > {self.sell_threshold * 1.05:.6f}: {cond1}, "
f"rsi={rsi_value:.2f} > 70: {cond2}, "
f"ema10={ema10_value:.6f} < ema20={ema20_value:.6f}: {cond3}")
return dataframe
@ -463,8 +475,14 @@ class FreqaiPrimer(IStrategy):
return (reduce_amount, f"Profit {profit_ratio*100:.2f}%")
# 追踪止损逻辑
trailing_stop_start = self.TRAILING_STOP_START.value
trailing_stop_distance = self.TRAILING_STOP_DISTANCE.value
atr15m = dataframe['atr15m'].iloc[-1]
trailing_stop_distance = 2 * atr15m / current_rate # 2倍ATR转换为比例
trailing_stop_price = max_rate * (1 - trailing_stop_distance)
if current_rate < trailing_stop_price:
logger.info(f"{pair} 价格回落至 {trailing_stop_price:.6f},触发全部卖出")
return (-trade.stake_amount, f"ATR trailing stop at {trailing_stop_price:.6f}")
# 使用 Sigmoid 映射调整追踪止损参数
sigmoid = 1 / (1 + np.exp(-0.1 * (trend_score - 50)))
trailing_factor = 0.8 + (1.2 - 0.8) * sigmoid # 牛市(100) -> 1.2, 熊市(0) -> 0.8

View File

@ -65,7 +65,7 @@ echo "docker-compose run --rm freqtrade hyperopt \
--timerange ${START_DATE}-${END_DATE} \
-e 100 \
--hyperopt-loss ShortTradeDurHyperOptLoss \
--spaces buy sell trailing \
--spaces buy sell \
--fee 0.0016"
docker-compose run --rm freqtrade hyperopt \
--logfile /freqtrade/user_data/logs/freqtrade.log \
@ -77,7 +77,7 @@ docker-compose run --rm freqtrade hyperopt \
--timerange ${START_DATE}-${END_DATE} \
-e 100 \
--hyperopt-loss SharpeHyperOptLoss \
--spaces buy sell trailing \
--spaces buy sell \
--fee 0.0016
#>output.log 2>&1