防止hyperopt结果冲掉roi, protection, trailing设置; 退出阈值使用hyperopt优化

This commit is contained in:
zhangkun9038@dingtalk.com 2025-09-06 21:55:15 +08:00
parent 3edab44e32
commit 6414b7dbae
5 changed files with 152 additions and 98 deletions

View File

@ -102,6 +102,23 @@ class FreqaiPrimer(IStrategy):
volume_spike_multiplier = DecimalParameter(1.0, 3.0, default=1.5, decimals=1, space="buy", optimize=True, load=True)
bb_width_min = DecimalParameter(0.01, 0.05, default=0.02, decimals=3, space="buy", optimize=True, load=True)
# 出场条件hyperopt参数 (space="sell")
exit_volume_multiplier = DecimalParameter(1.5, 3.0, default=2.0, decimals=1, space="sell", optimize=True, load=True) # 成交量放大倍数
exit_rsi_threshold = IntParameter(60, 80, default=65, space="sell", optimize=True, load=True) # 出场RSI阈值
exit_max_hold_hours = IntParameter(8, 12, default=9, space="sell", optimize=True, load=True) # 最大持仓时间(小时)
# 渐进式止盈参数
strong_bull_take_profit_1 = DecimalParameter(0.02, 0.04, default=0.03, decimals=2, space="sell", optimize=True, load=True)
strong_bull_take_profit_2 = DecimalParameter(0.05, 0.07, default=0.06, decimals=2, space="sell", optimize=True, load=True)
strong_bull_take_profit_3 = DecimalParameter(0.08, 0.10, default=0.09, decimals=2, space="sell", optimize=True, load=True)
strong_bull_take_profit_4 = DecimalParameter(0.11, 0.13, default=0.12, decimals=2, space="sell", optimize=True, load=True)
strong_bull_take_profit_5 = DecimalParameter(0.14, 0.16, default=0.15, decimals=2, space="sell", optimize=True, load=True)
weak_bull_take_profit_1 = DecimalParameter(0.01, 0.03, default=0.02, decimals=2, space="sell", optimize=True, load=True)
weak_bull_take_profit_2 = DecimalParameter(0.03, 0.05, default=0.04, decimals=2, space="sell", optimize=True, load=True)
weak_bull_take_profit_3 = DecimalParameter(0.05, 0.07, default=0.06, decimals=2, space="sell", optimize=True, load=True)
weak_bull_take_profit_4 = DecimalParameter(0.07, 0.09, default=0.08, decimals=2, space="sell", optimize=True, load=True)
def informative_pairs(self):
pairs = self.dp.current_whitelist()
@ -486,14 +503,14 @@ class FreqaiPrimer(IStrategy):
# 条件1: 价格突破布林带上轨
breakout_condition = dataframe['close'] >= dataframe['bb_upper_1h']
# 条件2: 成交量显著放大
volume_spike = dataframe['volume'] > dataframe['volume_ma'] * 2
# 条件2: 成交量显著放大使用hyperopt优化参数
volume_spike = dataframe['volume'] > dataframe['volume_ma'] * self.exit_volume_multiplier.value
# 条件3: MACD 下降趋势
macd_downward = dataframe['macd_1h'] < dataframe['macd_signal_1h']
# 条件4: RSI 进入超买区域
rsi_overbought = dataframe['rsi_1h'] > self.rsi_overbought.value
# 条件4: RSI 进入超买区域使用hyperopt优化参数
rsi_overbought = dataframe['rsi_1h'] > self.exit_rsi_threshold.value
# 合并所有条件
final_condition = breakout_condition | volume_spike | macd_downward | rsi_overbought
@ -713,9 +730,9 @@ class FreqaiPrimer(IStrategy):
# 如果current_time没有时区信息直接计算
holding_time = (current_time - trade.open_date).total_seconds() / 3600
# 如果持仓时间超过9小时强制平仓
if holding_time >= 9:
logger.info(f"[{pair}] 持仓时间超过9小时,强制平仓")
# 如果持仓时间超过最大持仓时间强制平仓使用hyperopt优化参数
if holding_time >= self.exit_max_hold_hours.value:
logger.info(f"[{pair}] 持仓时间超过{self.exit_max_hold_hours.value}小时,强制平仓")
return 1.0 # 全部退出
"""渐进式止盈逻辑"""
@ -723,11 +740,22 @@ class FreqaiPrimer(IStrategy):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
current_state = dataframe['market_state'].iloc[-1] if 'market_state' in dataframe.columns else 'unknown'
# 定义更激进的渐进式止盈水平,提高收益上限
# 定义渐进式止盈水平使用hyperopt优化参数
profit_levels = {
# 状态: [(止盈触发利润, 止盈比例)]
'strong_bull': [(0.03, 0.2), (0.06, 0.4), (0.09, 0.6), (0.12, 0.8), (0.15, 1.0)], # 强劲牛市的渐进止盈,降低目标
'weak_bull': [(0.02, 0.3), (0.04, 0.5), (0.06, 0.7), (0.08, 0.9)], # 弱牛市的渐进止盈
'strong_bull': [
(self.strong_bull_take_profit_1.value, 0.2),
(self.strong_bull_take_profit_2.value, 0.4),
(self.strong_bull_take_profit_3.value, 0.6),
(self.strong_bull_take_profit_4.value, 0.8),
(self.strong_bull_take_profit_5.value, 1.0)
], # 强劲牛市的渐进止盈
'weak_bull': [
(self.weak_bull_take_profit_1.value, 0.3),
(self.weak_bull_take_profit_2.value, 0.5),
(self.weak_bull_take_profit_3.value, 0.7),
(self.weak_bull_take_profit_4.value, 0.9)
], # 弱牛市的渐进止盈
'neutral': [(0.015, 0.4), (0.03, 0.6), (0.045, 0.8), (0.06, 1.0)], # 中性市场的渐进止盈
'bear': [(0.01, 0.6), (0.015, 0.8), (0.02, 1.0)] # 熊市的渐进止盈(更保守)
}

0
test_adx.py Normal file
View File

View File

@ -183,7 +183,8 @@ rm -rf ./freqtrade/user_data/data/backtest_results/*
rm -fr ./user_data/dryrun_results/*
rm result/*
hyperopt_config="${STRATEGY_NAME%.py}.json"
# 将 STRATEGY_NAME 转换为小写并生成 hyperopt_config
hyperopt_config="$(echo "${STRATEGY_NAME%.py}" | tr '[:upper:]' '[:lower:]').json"
echo "docker-compose run --rm freqtrade backtesting $PAIRS_FLAG \
--logfile /freqtrade/user_data/logs/freqtrade.log \
@ -197,11 +198,19 @@ echo "docker-compose run --rm freqtrade backtesting $PAIRS_FLAG \
--breakdown day \
--cache none >output.log"
# 在此之前插入逻辑以编辑 JSON 文件
hyperopt_config_path="../freqtrade/templates/${STRATEGY_NAME}.json"
# 使用 sed 清理空的 roi, sell, protection 元素
sed -i '/"roi": {},/d' "$hyperopt_config_path"
sed -i '/"sell": {},/d' "$hyperopt_config_path"
sed -i '/"protection": {},/d' "$hyperopt_config_path"
docker-compose run --rm freqtrade backtesting $PAIRS_FLAG \
--logfile /freqtrade/user_data/logs/freqtrade.log \
--freqaimodel LightGBMRegressorMultiTarget \
--config /freqtrade/config_examples/$CONFIG_FILE \
--config /freqtrade/templates/freqaiprimer.json \
--config /freqtrade/templates/$hyperopt_config \
--strategy-path /freqtrade/templates \
--enable-protections \
--strategy $STRATEGY_NAME \
@ -236,4 +245,4 @@ cp output.log result/ -f
cd tools/
python tradestocsv.py
python analytic.py >../result/analytic.log
cd ../
cd ../

View File

@ -123,93 +123,104 @@ fi
# Format end_date for URL parameter (YYYY-MM-DD format)
END_DATE_FORMATTED=$(date -d "@$END_DATE" "+%Y-%m-%d")
# 处理交易对参数:优先级为 --pairRemoteList > --pairs > 默认值
if [ -n "$PAIR_REMOTE_LIST_URL" ]; then
# 从远程API获取交易对列表
echo "Fetching pairs from remote URL: $PAIR_REMOTE_LIST_URL"
pairs_json=$(curl -s "$PAIR_REMOTE_LIST_URL")
# # 处理交易对参数:优先级为 --pairRemoteList > --pairs > 默认值
# if [ -n "$PAIR_REMOTE_LIST_URL" ]; then
# # 从远程API获取交易对列表
# echo "Fetching pairs from remote URL: $PAIR_REMOTE_LIST_URL"
# pairs_json=$(curl -s "$PAIR_REMOTE_LIST_URL")
#
# # 检查API响应是否成功
# if [[ $? -ne 0 || -z "$pairs_json" ]]; then
# echo "Error: Failed to fetch pairs from remote URL, using --pairs parameter or default"
# if [ -n "$PAIRS_ARG" ]; then
# PAIRS_FLAG="--pairs $PAIRS_ARG"
# echo "Using pairs from --pairs parameter: $PAIRS_ARG"
# else
# # 使用默认的交易对列表
# DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
# PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
# echo "Using default pairs: $DEFAULT_PAIRS"
# fi
# else
# # 解析JSON并提取交易对将连字符替换为斜杠
# remote_pairs=$(echo "$pairs_json" | python3 -c "
# import sys, json
# data = json.load(sys.stdin)
# pairs = [pair.replace('-', '/') for pair in data.get('pairlist', [])]
# print(' '.join(pairs) if pairs else '')
# ")
#
# # 如果解析成功且有交易对
# if [[ -n "$remote_pairs" ]]; then
# PAIRS_FLAG="--pairs $remote_pairs"
# echo "Successfully fetched $(echo "$remote_pairs" | wc -w) pairs from remote URL"
# echo "Pairs: $remote_pairs"
# else
# echo "Error: Failed to parse or empty pairlist from remote URL, using --pairs parameter or default"
# if [ -n "$PAIRS_ARG" ]; then
# PAIRS_FLAG="--pairs $PAIRS_ARG"
# echo "Using pairs from --pairs parameter: $PAIRS_ARG"
# else
# # 使用默认的交易对列表
# DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
# PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
# echo "Using default pairs: $DEFAULT_PAIRS"
# fi
# fi
# fi
# elif [ -n "$PAIRS_ARG" ]; then
# # 使用 --pairs 参数提供的交易对
# PAIRS_FLAG="--pairs $PAIRS_ARG"
# echo "Using pairs from --pairs parameter: $PAIRS_ARG"
# echo "Number of pairs: $(echo "$PAIRS_ARG" | wc -w)"
# else
# # 优先从指定URL获取交易对列表
# echo "Fetching pairs from primary URL with date parameter..."
# PRIMARY_URL="http://pairlist.xl.home/api/pairlist?mute=true&count=30&date=${END_DATE_FORMATTED}"
# echo "Requesting: $PRIMARY_URL"
#
# pairs_json=$(curl -s "$PRIMARY_URL")
#
# # 检查API响应是否成功
# if [[ $? -ne 0 || -z "$pairs_json" ]]; then
# echo "Error: Failed to fetch pairs from primary URL, using default pairs"
# # 使用默认的交易对列表
# DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
# PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
# echo "Using default pairs: $DEFAULT_PAIRS"
# else
# # 解析JSON并提取交易对将连字符替换为斜杠
# remote_pairs=$(echo "$pairs_json" | python3 -c "
# import sys, json
# data = json.load(sys.stdin)
# pairs = [pair.replace('-', '/') for pair in data.get('pairlist', [])]
# print(' '.join(pairs) if pairs else '')
# ")
#
# # 如果解析成功且有交易对
# if [[ -n "$remote_pairs" ]]; then
# PAIRS_FLAG="--pairs $remote_pairs"
# echo "Successfully fetched $(echo "$remote_pairs" | wc -w) pairs from primary URL"
# echo "Pairs: $remote_pairs"
# else
# echo "Error: Failed to parse or empty pairlist from primary URL, using default pairs"
# # 使用默认的交易对列表
# DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
# PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
# echo "Using default pairs: $DEFAULT_PAIRS"
# fi
# fi
# fi
# 检查API响应是否成功
if [[ $? -ne 0 || -z "$pairs_json" ]]; then
echo "Error: Failed to fetch pairs from remote URL, using --pairs parameter or default"
if [ -n "$PAIRS_ARG" ]; then
PAIRS_FLAG="--pairs $PAIRS_ARG"
echo "Using pairs from --pairs parameter: $PAIRS_ARG"
else
# 使用默认的交易对列表
DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
echo "Using default pairs: $DEFAULT_PAIRS"
fi
else
# 解析JSON并提取交易对将连字符替换为斜杠
remote_pairs=$(echo "$pairs_json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
pairs = [pair.replace('-', '/') for pair in data.get('pairlist', [])]
print(' '.join(pairs) if pairs else '')
")
# 如果解析成功且有交易对
if [[ -n "$remote_pairs" ]]; then
PAIRS_FLAG="--pairs $remote_pairs"
echo "Successfully fetched $(echo "$remote_pairs" | wc -w) pairs from remote URL"
echo "Pairs: $remote_pairs"
else
echo "Error: Failed to parse or empty pairlist from remote URL, using --pairs parameter or default"
if [ -n "$PAIRS_ARG" ]; then
PAIRS_FLAG="--pairs $PAIRS_ARG"
echo "Using pairs from --pairs parameter: $PAIRS_ARG"
else
# 使用默认的交易对列表
DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
echo "Using default pairs: $DEFAULT_PAIRS"
fi
fi
fi
elif [ -n "$PAIRS_ARG" ]; then
# 使用 --pairs 参数提供的交易对
DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
# 如果提供了 --pairs 参数,则使用它;否则使用默认币对列表
if [ -n "$PAIRS_ARG" ]; then
PAIRS_FLAG="--pairs $PAIRS_ARG"
echo "Using pairs from --pairs parameter: $PAIRS_ARG"
echo "Number of pairs: $(echo "$PAIRS_ARG" | wc -w)"
else
# 优先从指定URL获取交易对列表
echo "Fetching pairs from primary URL with date parameter..."
PRIMARY_URL="http://pairlist.xl.home/api/pairlist?mute=true&count=30&date=${END_DATE_FORMATTED}"
echo "Requesting: $PRIMARY_URL"
pairs_json=$(curl -s "$PRIMARY_URL")
# 检查API响应是否成功
if [[ $? -ne 0 || -z "$pairs_json" ]]; then
echo "Error: Failed to fetch pairs from primary URL, using default pairs"
# 使用默认的交易对列表
DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
echo "Using default pairs: $DEFAULT_PAIRS"
else
# 解析JSON并提取交易对将连字符替换为斜杠
remote_pairs=$(echo "$pairs_json" | python3 -c "
import sys, json
data = json.load(sys.stdin)
pairs = [pair.replace('-', '/') for pair in data.get('pairlist', [])]
print(' '.join(pairs) if pairs else '')
")
# 如果解析成功且有交易对
if [[ -n "$remote_pairs" ]]; then
PAIRS_FLAG="--pairs $remote_pairs"
echo "Successfully fetched $(echo "$remote_pairs" | wc -w) pairs from primary URL"
echo "Pairs: $remote_pairs"
else
echo "Error: Failed to parse or empty pairlist from primary URL, using default pairs"
# 使用默认的交易对列表
DEFAULT_PAIRS="BTC/USDT TON/USDT DOT/USDT XRP/USDT OKB/USDT SOL/USDT DOGE/USDT WCT/USDT TRUMP/USDT SUI/USDT PEPE/USDT TRB/USDT MASK/USDT UNI/USDT KAITO/USDT"
PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
echo "Using default pairs: $DEFAULT_PAIRS"
fi
fi
PAIRS_FLAG="--pairs $DEFAULT_PAIRS"
echo "Using default pairs: $DEFAULT_PAIRS"
fi
cd ../
@ -243,8 +254,8 @@ docker-compose run --rm freqtrade hyperopt $PAIRS_FLAG \
--enable-protections \
--strategy-path /freqtrade/templates \
--timerange ${START_DATE}-${END_DATE} \
-e 100 \
-e 200 \
-j 4 \
--hyperopt-loss OnlyProfitHyperOptLoss \
--spaces buy \
--fee 0.0016
--fee 0.0016

View File

@ -254,6 +254,12 @@ rm -rf ./freqtrade/user_data/data/backtest_results/*
rm -fr ./user_data/dryrun_results/*
cd -
hyperopt_config_path="../freqtrade/templates/${PARAMS_NAME}.json"
# 使用 sed 清理空的 roi, sell, protection 元素
sed -i '/"roi": {},/d' "$hyperopt_config_path"
sed -i '/"sell": {},/d' "$hyperopt_config_path"
sed -i '/"protection": {},/d' "$hyperopt_config_path"
# 启动新容器
echo "启动容器: $CONTAINER_NAME" >&2
docker-compose run -d --rm \
@ -275,4 +281,4 @@ if [ $? -eq 0 ]; then
else
echo "❌ 容器启动失败" >&2
exit 1
fi
fi