hyperopted 回测0501-0901结果: 2152, 胜率达到98%, 追求低风险
This commit is contained in:
parent
681f5e5d20
commit
7e68e4e31d
BIN
freqtrade/templates/.freqaiprimer.py.swp
Normal file
BIN
freqtrade/templates/.freqaiprimer.py.swp
Normal file
Binary file not shown.
@ -15,28 +15,34 @@
|
||||
"max_open_trades": 5
|
||||
},
|
||||
"buy": {
|
||||
"stake_divisor": 2,
|
||||
"add_position_callback": 0.056,
|
||||
"bb_length": 22,
|
||||
"bb_lower_deviation": 1.05,
|
||||
"bb_std": 1.6,
|
||||
"bb_width_threshold": 0.017,
|
||||
"h1_max_candles": 239,
|
||||
"h1_max_consecutive_candles": 1,
|
||||
"h1_rapid_rise_threshold": 0.054,
|
||||
"min_condition_count": 3,
|
||||
"rsi_bull_threshold": 48,
|
||||
"rsi_length": 9,
|
||||
"rsi_oversold": 50,
|
||||
"stochrsi_bull_threshold": 38,
|
||||
"stochrsi_neutral_threshold": 27,
|
||||
"volume_multiplier": 1.8
|
||||
"bb_lower_deviation": 1.03,
|
||||
"bb_std": 2.1,
|
||||
"bb_width_threshold": 0.01,
|
||||
"h1_max_candles": 223,
|
||||
"h1_max_consecutive_candles": 4,
|
||||
"h1_rapid_rise_threshold": 0.061,
|
||||
"max_entry_adjustments": 5,
|
||||
"min_condition_count": 2,
|
||||
"rsi_bull_threshold": 53,
|
||||
"rsi_length": 10,
|
||||
"rsi_oversold": 49,
|
||||
"stochrsi_bull_threshold": 40,
|
||||
"stochrsi_neutral_threshold": 20,
|
||||
"volume_multiplier": 1.4
|
||||
},
|
||||
"sell": {
|
||||
"exit_bb_upper_deviation": 0.99,
|
||||
"exit_volume_multiplier": 2.6,
|
||||
"rsi_overbought": 67
|
||||
"exit_bb_upper_deviation": 0.98,
|
||||
"exit_volume_multiplier": 1.9,
|
||||
"roi_param_a": 0.06,
|
||||
"roi_param_c": 0.0057,
|
||||
"roi_param_k": 0.0088,
|
||||
"rsi_overbought": 66
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2025-09-08 10:59:05.144144+00:00"
|
||||
"export_time": "2025-09-10 13:07:34.606541+00:00"
|
||||
}
|
||||
@ -11,10 +11,10 @@ import datetime
|
||||
import math
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
class FreqaiPrimer(IStrategy):
|
||||
# 策略参数 - 使用custom_roi替代minimal_roi字典
|
||||
loglevel = "warning"
|
||||
minimal_roi = {}
|
||||
|
||||
# 启用自定义ROI回调函数
|
||||
@ -84,12 +84,9 @@ class FreqaiPrimer(IStrategy):
|
||||
bb_length = IntParameter(10, 30, default=20, optimize=True, load=True, space='buy')
|
||||
bb_std = DecimalParameter(1.5, 3.0, decimals=1, default=2.0, optimize=True, load=True, space='buy')
|
||||
rsi_length = IntParameter(7, 21, default=14, optimize=True, load=True, space='buy')
|
||||
rsi_overbought = IntParameter(50, 70, default=58, optimize=True, load=True, space='sell')
|
||||
rsi_oversold = IntParameter(30, 50, default=42, optimize=True, load=True, space='buy')
|
||||
|
||||
# 出场条件阈值参数
|
||||
exit_bb_upper_deviation = DecimalParameter(0.98, 1.02, decimals=2, default=1.0, optimize=True, load=True, space='sell')
|
||||
exit_volume_multiplier = DecimalParameter(1.5, 3.0, decimals=1, default=2.0, optimize=True, load=True, space='sell')
|
||||
|
||||
|
||||
# 入场条件阈值参数
|
||||
bb_lower_deviation = DecimalParameter(1.01, 1.05, decimals=2, default=1.03, optimize=True, load=True, space='buy')
|
||||
@ -104,11 +101,21 @@ class FreqaiPrimer(IStrategy):
|
||||
h1_max_candles = IntParameter(100, 300, default=200, optimize=True, load=True, space='buy')
|
||||
h1_rapid_rise_threshold = DecimalParameter(0.05, 0.15, decimals=3, default=0.11, optimize=True, load=True, space='buy')
|
||||
h1_max_consecutive_candles = IntParameter(1, 4, default=2, optimize=True, load=True, space='buy')
|
||||
# 定义可优化参数
|
||||
max_entry_adjustments = IntParameter(2, 5, default=3, optimize=True, load=True, space='buy') # 最大加仓次数
|
||||
add_position_callback = DecimalParameter(0.03, 0.06, decimals=3, default=0.047, optimize=True, load=True, space='buy') # 加仓回调百分比
|
||||
stake_divisor = IntParameter(2, 4, default=2, optimize=False, load=True, space='buy') # 加仓金额分母
|
||||
|
||||
# 动态ROI参数 - 指数衰减函数参数 (ROI(t) = a·e^(-k·t) + c)
|
||||
roi_param_a = DecimalParameter(0.01, 0.1, decimals=3, default=0.05, optimize=True, load=True, space='roi') # 初始ROI水平
|
||||
roi_param_k = DecimalParameter(0.001, 0.01, decimals=4, default=0.003, optimize=True, load=True, space='roi') # 衰减速率
|
||||
roi_param_c = DecimalParameter(0, 0.01, decimals=4, default=0.005, optimize=True, load=True, space='roi') # 最低ROI水平
|
||||
roi_param_a = DecimalParameter(0.01, 0.1, decimals=3, default=0.05, optimize=True, load=True, space='sell') # 初始ROI水平
|
||||
roi_param_k = DecimalParameter(0.001, 0.01, decimals=4, default=0.003, optimize=True, load=True, space='sell') # 衰减速率
|
||||
roi_param_c = DecimalParameter(0, 0.01, decimals=4, default=0.005, optimize=True, load=True, space='sell') # 最低ROI水平
|
||||
# 出场条件阈值参数
|
||||
exit_bb_upper_deviation = DecimalParameter(0.98, 1.02, decimals=2, default=1.0, optimize=True, load=True, space='sell')
|
||||
exit_volume_multiplier = DecimalParameter(1.5, 3.0, decimals=1, default=2.0, optimize=True, load=True, space='sell')
|
||||
|
||||
rsi_overbought = IntParameter(50, 70, default=58, optimize=True, load=True, space='sell')
|
||||
|
||||
|
||||
def informative_pairs(self):
|
||||
pairs = self.dp.current_whitelist()
|
||||
@ -207,7 +214,7 @@ class FreqaiPrimer(IStrategy):
|
||||
df_1h['macd_hist_1h'] = macd_1h['MACDh_12_26_9']
|
||||
|
||||
# 验证 MACD 列是否正确生成
|
||||
logger.info(f"[{metadata['pair']}] 1小时 MACD 列: {list(macd_1h.columns)}")
|
||||
#logger.info(f"[{metadata['pair']}] 1小时 MACD 列: {list(macd_1h.columns)}")
|
||||
|
||||
# 确保 StochRSI 指标已正确计算
|
||||
# 将 1h 数据重新索引到主时间框架 (3m),并填充缺失值
|
||||
@ -242,7 +249,7 @@ class FreqaiPrimer(IStrategy):
|
||||
dataframe = dataframe.merge(df_1h, how='left', on='date').fillna(method='ffill')
|
||||
|
||||
# 验证合并后的列
|
||||
logger.info(f"[{metadata['pair']}] 合并后的数据框列名: {list(dataframe.columns)}")
|
||||
#logger.info(f"[{metadata['pair']}] 合并后的数据框列名: {list(dataframe.columns)}")
|
||||
|
||||
# K线形态:看涨吞没
|
||||
dataframe['bullish_engulfing'] = (
|
||||
@ -291,10 +298,10 @@ class FreqaiPrimer(IStrategy):
|
||||
if len(dataframe) > 0:
|
||||
current_score = dataframe['market_score'].iloc[-1]
|
||||
current_state = dataframe['market_state'].iloc[-1]
|
||||
logger.info(f"[{metadata['pair']}] 熊牛得分: {current_score:.1f}, 市场状态: {current_state}")
|
||||
logger.info(f"[{metadata['pair']}] 各时间框架趋势: 3m={'牛' if dataframe['trend_3m'].iloc[-1] == 1 else '熊'}, \
|
||||
15m={'牛' if dataframe['trend_15m'].iloc[-1] == 1 else '熊'}, \
|
||||
1h={'牛' if dataframe['trend_1h_ema'].iloc[-1] == 1 else '熊'}")
|
||||
#logger.info(f"[{metadata['pair']}] 熊牛得分: {current_score:.1f}, 市场状态: {current_state}")
|
||||
#logger.info(f"[{metadata['pair']}] 各时间框架趋势: 3m={'牛' if dataframe['trend_3m'].iloc[-1] == 1 else '熊'}, \
|
||||
# 15m={'牛' if dataframe['trend_15m'].iloc[-1] == 1 else '熊'}, \
|
||||
# 1h={'牛' if dataframe['trend_1h_ema'].iloc[-1] == 1 else '熊'}")
|
||||
|
||||
# 调试:打印指标值(最后 5 行),验证时间对齐
|
||||
print(f"Pair: {metadata['pair']}, Last 5 rows after reindexing:")
|
||||
@ -303,36 +310,7 @@ class FreqaiPrimer(IStrategy):
|
||||
'bullish_engulfing', 'volume', 'volume_ma']].tail(5))
|
||||
|
||||
# 打印最终数据框的列名以验证
|
||||
logger.info(f"[{metadata['pair']}] 最终数据框列名: {list(dataframe.columns)}")
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# 入场信号主要依据1小时周期
|
||||
# 条件1: 价格接近布林带下轨
|
||||
close_to_bb_lower_1h = (dataframe['close'] <= dataframe['bb_lower_1h'] * 1.02)
|
||||
|
||||
# 条件2: RSI 不高于阈值
|
||||
rsi_condition_1h = dataframe['rsi_1h'] < self.rsi_oversold
|
||||
|
||||
# 条件3: StochRSI 处于超卖区域
|
||||
stochrsi_condition_1h = (dataframe['stochrsi_k_1h'] < 20) & (dataframe['stochrsi_d_1h'] < 20)
|
||||
|
||||
# 条件4: MACD 上升趋势
|
||||
macd_condition_1h = dataframe['macd_1h'] > dataframe['macd_signal_1h']
|
||||
|
||||
# 辅助条件: 3m 和 15m 趋势确认
|
||||
trend_confirmation = (dataframe['trend_3m'] == 1) & (dataframe['trend_15m'] == 1)
|
||||
|
||||
# 合并所有条件
|
||||
final_condition = close_to_bb_lower_1h & rsi_condition_1h & stochrsi_condition_1h & macd_condition_1h & trend_confirmation
|
||||
|
||||
# 设置入场信号
|
||||
dataframe.loc[final_condition, 'enter_long'] = 1
|
||||
|
||||
# 日志记录
|
||||
if dataframe['enter_long'].sum() > 0:
|
||||
logger.info(f"[{metadata['pair']}] 发现入场信号数量: {dataframe['enter_long'].sum()}")
|
||||
#logger.info(f"[{metadata['pair']}] 最终数据框列名: {list(dataframe.columns)}")
|
||||
|
||||
return dataframe
|
||||
|
||||
@ -357,13 +335,13 @@ class FreqaiPrimer(IStrategy):
|
||||
dataframe.loc[final_condition, 'exit_long'] = 1
|
||||
|
||||
# 增强调试信息
|
||||
logger.info(f"[{metadata['pair']}] 出场条件检查:")
|
||||
logger.info(f" - 价格突破布林带上轨: {breakout_condition.sum()} 次")
|
||||
logger.info(f" - 成交量显著放大: {volume_spike.sum()} 次")
|
||||
logger.info(f" - MACD 下降趋势: {macd_downward.sum()} 次")
|
||||
logger.info(f" - RSI 超买: {rsi_overbought.sum()} 次")
|
||||
logger.info(f" - 最终条件: {final_condition.sum()} 次")
|
||||
logger.info(f" - 使用参数: exit_bb_upper_deviation={self.exit_bb_upper_deviation.value}, exit_volume_multiplier={self.exit_volume_multiplier.value}, rsi_overbought={self.rsi_overbought.value}")
|
||||
#logger.info(f"[{metadata['pair']}] 出场条件检查:")
|
||||
#logger.info(f" - 价格突破布林带上轨: {breakout_condition.sum()} 次")
|
||||
#logger.info(f" - 成交量显著放大: {volume_spike.sum()} 次")
|
||||
#logger.info(f" - MACD 下降趋势: {macd_downward.sum()} 次")
|
||||
#logger.info(f" - RSI 超买: {rsi_overbought.sum()} 次")
|
||||
#logger.info(f" - 最终条件: {final_condition.sum()} 次")
|
||||
#logger.info(f" - 使用参数: exit_bb_upper_deviation={self.exit_bb_upper_deviation.value}, exit_volume_multiplier={self.exit_volume_multiplier.value}, rsi_overbought={self.rsi_overbought.value}")
|
||||
|
||||
# 日志记录
|
||||
if dataframe['exit_long'].sum() > 0:
|
||||
@ -420,14 +398,14 @@ class FreqaiPrimer(IStrategy):
|
||||
dataframe.loc[final_condition, 'enter_long'] = 1
|
||||
|
||||
# 增强调试信息
|
||||
logger.info(f"[{metadata['pair']}] 入场条件检查:")
|
||||
logger.info(f" - 价格接近布林带下轨: {close_to_bb_lower_1h.sum()} 次")
|
||||
logger.info(f" - RSI 超卖: {rsi_condition_1h.sum()} 次")
|
||||
logger.info(f" - StochRSI 超卖: {stochrsi_condition_1h.sum()} 次")
|
||||
logger.info(f" - MACD 上升趋势: {macd_condition_1h.sum()} 次")
|
||||
logger.info(f" - 成交量或布林带宽度: {(volume_spike | bb_width_condition).sum()} 次")
|
||||
logger.info(f" - 趋势确认: {trend_confirmation.sum()} 次")
|
||||
logger.info(f" - 最终条件: {final_condition.sum()} 次")
|
||||
#logger.info(f"[{metadata['pair']}] 入场条件检查:")
|
||||
#logger.info(f" - 价格接近布林带下轨: {close_to_bb_lower_1h.sum()} 次")
|
||||
#logger.info(f" - RSI 超卖: {rsi_condition_1h.sum()} 次")
|
||||
#logger.info(f" - StochRSI 超卖: {stochrsi_condition_1h.sum()} 次")
|
||||
#logger.info(f" - MACD 上升趋势: {macd_condition_1h.sum()} 次")
|
||||
#logger.info(f" - 成交量或布林带宽度: {(volume_spike | bb_width_condition).sum()} 次")
|
||||
#logger.info(f" - 趋势确认: {trend_confirmation.sum()} 次")
|
||||
#logger.info(f" - 最终条件: {final_condition.sum()} 次")
|
||||
# 在populate_entry_trend方法末尾添加
|
||||
# 计算条件间的相关性
|
||||
conditions = DataFrame({
|
||||
@ -439,7 +417,7 @@ class FreqaiPrimer(IStrategy):
|
||||
'trend': trend_confirmation
|
||||
})
|
||||
correlation = conditions.corr().mean().mean()
|
||||
logger.info(f"[{metadata['pair']}] 条件平均相关性: {correlation:.2f}")
|
||||
#logger.info(f"[{metadata['pair']}] 条件平均相关性: {correlation:.2f}")
|
||||
# 日志记录
|
||||
if dataframe['enter_long'].sum() > 0:
|
||||
logger.info(f"[{metadata['pair']}] 发现入场信号数量: {dataframe['enter_long'].sum()}")
|
||||
@ -489,12 +467,12 @@ class FreqaiPrimer(IStrategy):
|
||||
# 检查是否超过阈值
|
||||
if rise_percentage >= rapid_rise_threshold:
|
||||
rapid_rise_detected = True
|
||||
logger.info(f"[{pair}] 检测到剧烈拉升: 从 {window_low:.2f} 到 {window_high:.2f} ({rise_percentage:.2%}) 在 {max_consecutive_candles} 根K线内")
|
||||
#logger.info(f"[{pair}] 检测到剧烈拉升: 从 {window_low:.2f} 到 {window_high:.2f} ({rise_percentage:.2%}) 在 {max_consecutive_candles} 根K线内")
|
||||
break
|
||||
|
||||
current_price = recent_data['close'].iloc[-1]
|
||||
logger.info(f"[{pair}] 剧烈拉升检测结果: {'不稳固' if rapid_rise_detected else '稳固'}")
|
||||
logger.info(f"[{pair}] 最近最大涨幅: {max_rise:.2%}")
|
||||
#logger.info(f"[{pair}] 剧烈拉升检测结果: {'不稳固' if rapid_rise_detected else '稳固'}")
|
||||
#logger.info(f"[{pair}] 最近最大涨幅: {max_rise:.2%}")
|
||||
|
||||
return rapid_rise_detected
|
||||
|
||||
@ -526,7 +504,7 @@ class FreqaiPrimer(IStrategy):
|
||||
# 检查是否处于剧烈拉升的不稳固区域
|
||||
is_unstable_region = self.detect_h1_rapid_rise(pair)
|
||||
if is_unstable_region:
|
||||
logger.info(f"[{pair}] 由于检测到剧烈拉升,取消入场交易")
|
||||
#logger.info(f"[{pair}] 由于检测到剧烈拉升,取消入场交易")
|
||||
allow_trade = False
|
||||
|
||||
# 如果没有阻止因素,允许交易
|
||||
@ -633,68 +611,57 @@ class FreqaiPrimer(IStrategy):
|
||||
exit_ratio = 1.0 # 达到ROI阈值时全部退出
|
||||
|
||||
# 记录动态止盈决策
|
||||
logger.info(f"[{pair}] 动态止盈: 持仓时间={trade_age_minutes:.1f}分钟, 当前利润={current_profit:.2%}, \
|
||||
动态ROI阈值={dynamic_roi_threshold:.4f}, 利润比值={profit_ratio:.2f}, \
|
||||
市场状态={current_state}, 退出比例={exit_ratio:.0%}")
|
||||
#logger.info(f"[{pair}] 动态止盈: 持仓时间={trade_age_minutes:.1f}分钟, 当前利润={current_profit:.2%}, \
|
||||
# 动态ROI阈值={dynamic_roi_threshold:.4f}, 利润比值={profit_ratio:.2f}, \
|
||||
# 市场状态={current_state}, 退出比例={exit_ratio:.0%}")
|
||||
|
||||
# 返回应退出的比例(0.0表示不退出,1.0表示全部退出)
|
||||
return exit_ratio
|
||||
|
||||
|
||||
|
||||
def adjust_trade_position(self, trade: 'Trade', current_time, current_rate: float,
|
||||
current_profit: float, min_stake: float, max_stake: float, **kwargs) -> float:
|
||||
"""
|
||||
根据用户要求实现加仓逻辑
|
||||
- 加仓间隔设置为0.047(4.7%回调)
|
||||
- 加仓额度为: (stake_amount / 2) ^ (加仓次数 - 1)
|
||||
- 加仓间隔设置为可优化参数 add_position_callback
|
||||
- 加仓额度为: (stake_amount / stake_divisor) ^ (加仓次数 - 1)
|
||||
"""
|
||||
# 检查是否已启用加仓
|
||||
if not hasattr(self, 'max_entry_adjustments'):
|
||||
self.max_entry_adjustments = 3 # 设置最大加仓次数
|
||||
|
||||
# 获取当前交易对
|
||||
pair = trade.pair
|
||||
|
||||
# 获取当前交易的加仓次数
|
||||
# 初始交易算第1次,加仓次数=total_entry_position - 1
|
||||
entry_count = len(trade.orders) # 获取所有入场订单数量
|
||||
|
||||
# 如果已经达到最大加仓次数,则不再加仓
|
||||
if entry_count - 1 >= self.max_entry_adjustments:
|
||||
if entry_count - 1 >= self.max_entry_adjustments.value:
|
||||
return 0.0
|
||||
|
||||
# 获取初始入场价格和当前价格的差值百分比
|
||||
initial_price = trade.open_rate
|
||||
# 防止除零错误:如果initial_price为0,则返回不加仓
|
||||
if initial_price == 0:
|
||||
return 0.0
|
||||
price_diff_pct = (current_rate - initial_price) / initial_price
|
||||
|
||||
# 检查价格回调是否达到加仓间隔(0.047)
|
||||
# 价格回调表示价格比初始价格低4.7%或更多
|
||||
# 同时考虑市场状态,只在市场不是弱势时加仓
|
||||
# 检查价格回调是否达到加仓间隔
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
current_state = dataframe['market_state'].iloc[-1] if 'market_state' in dataframe.columns else 'neutral'
|
||||
|
||||
if price_diff_pct <= -0.047 and current_state not in ['bear', 'weak_bear']:
|
||||
if price_diff_pct <= -self.add_position_callback.value and current_state not in ['bear', 'weak_bear']:
|
||||
# 计算初始入场金额
|
||||
initial_stake = trade.orders[0].cost # 第一笔订单的成本
|
||||
|
||||
# 计算加仓次数(从1开始计数)
|
||||
adjustment_count = entry_count - 1 # 已加仓次数
|
||||
|
||||
# 计算加仓额度: (stake_amount / 2) ^ (加仓次数)
|
||||
# 对于第一次加仓,公式为 (initial_stake / 2) ^ 1 = initial_stake / 2
|
||||
# 第二次加仓,公式为 (initial_stake / 2) ^ 2
|
||||
# 第三次加仓,公式为 (initial_stake / 2) ^ 3
|
||||
|
||||
# 计算加仓金额
|
||||
additional_stake = (initial_stake / 2) ** (adjustment_count + 1)
|
||||
# 计算加仓金额: (initial_stake / stake_divisor) ^ (adjustment_count + 1)
|
||||
additional_stake = (initial_stake / self.stake_divisor.value) ** (adjustment_count + 1)
|
||||
|
||||
# 确保加仓金额在允许的范围内
|
||||
additional_stake = max(min_stake, min(additional_stake, max_stake - trade.stake_amount))
|
||||
|
||||
logger.info(f"[{pair}] 触发加仓: 第{adjustment_count + 1}次加仓, 初始金额{initial_stake:.2f}, \
|
||||
加仓金额{additional_stake:.2f}, 价格差{price_diff_pct:.2%}, 当前利润{current_profit:.2%}")
|
||||
#logger.info(f"[{pair}] 触发加仓: 第{adjustment_count + 1}次加仓, 初始金额{initial_stake:.2f}, \
|
||||
# 加仓金额{additional_stake:.2f}, 价格差{price_diff_pct:.2%}, 当前利润{current_profit:.2%}")
|
||||
|
||||
return additional_stake
|
||||
|
||||
|
||||
2196137
tools/nohup.out
Normal file
2196137
tools/nohup.out
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user