趋势获取采用了新的方式

This commit is contained in:
zhangkun9038@dingtalk.com 2025-08-13 18:34:13 +08:00
parent ad73d9a4ed
commit c45e223692
2 changed files with 205 additions and 69 deletions

View File

View File

@ -34,6 +34,10 @@ class FreqaiPrimer(IStrategy):
EXIT_POSITION_RATIO = 0.472
COOLDOWN_PERIOD_MINUTES = 9
MAX_ENTRY_POSITION_ADJUSTMENT = 3
# 趋势判定阈值参数
TREND_BULLISH_THRESHOLD = 85
TREND_BEARISH_THRESHOLD = 60
# --- 🛠️ 固定配置参数 ---
stoploss = -0.15
@ -422,23 +426,45 @@ class FreqaiPrimer(IStrategy):
stochrsi_overbought = self.is_stochrsi_overbought(dataframe, period=10, threshold=85)
stochrsi_overbought_aligned = stochrsi_overbought.reindex(dataframe.index, method='ffill').fillna(True)
# 买入条件
# 检测趋势状态
trend_status = self.detect_trend_status(dataframe, metadata)
# 根据趋势状态调整入场策略
if "&-price_value_divergence" in dataframe.columns:
cond1 = (dataframe["&-price_value_divergence"] < self.buy_threshold)
cond2 = (dataframe["volume_z_score"] > volume_z_score_threshold)
cond3 = (dataframe["rsi"] < rsi_threshold)
cond4 = (dataframe["close"] <= dataframe["bb_lowerband"])
cond5 = (dataframe["stochrsi_k"] < stochrsi_threshold)
cond6 = ~bearish_signal_aligned
cond7 = ~stochrsi_overbought_aligned
if trend_status == "bullish":
# 上涨趋势:放宽入场条件,允许追高
cond1 = (dataframe["&-price_value_divergence"] < self.buy_threshold * 1.5) # 放宽到1.5倍
cond2 = (dataframe["volume_z_score"] > volume_z_score_threshold * 0.7) # 降低成交量要求
cond3 = (dataframe["rsi"] < rsi_threshold * 1.2) # 放宽RSI要求
cond4 = (dataframe["close"] <= dataframe["bb_upperband"]) # 可以在上轨附近入场
cond5 = (dataframe["stochrsi_k"] < stochrsi_threshold * 1.2) # 放宽STOCHRSI要求
cond6 = True # 取消熊市过滤
cond7 = True # 取消超买过滤
logger.info(f"[{pair}] 🚀 上涨趋势策略:放宽入场条件")
elif trend_status == "bearish":
# 下跌趋势:严格入场条件,只抄底
cond1 = (dataframe["&-price_value_divergence"] < self.buy_threshold * 0.7) # 严格到0.7倍
cond2 = (dataframe["volume_z_score"] > volume_z_score_threshold * 1.3) # 提高成交量要求
cond3 = (dataframe["rsi"] < rsi_threshold * 0.8) # 严格RSI要求
cond4 = (dataframe["close"] <= dataframe["bb_lowerband"] * 0.95) # 必须跌破下轨
cond5 = (dataframe["stochrsi_k"] < stochrsi_threshold * 0.8) # 严格STOCHRSI要求
cond6 = ~bearish_signal_aligned # 保持熊市过滤
cond7 = ~stochrsi_overbought_aligned # 保持超买过滤
logger.info(f"[{pair}] 📉 下跌趋势策略:严格入场条件")
else: # ranging
# 震荡趋势:使用原策略
cond1 = (dataframe["&-price_value_divergence"] < self.buy_threshold)
cond2 = (dataframe["volume_z_score"] > volume_z_score_threshold)
cond3 = (dataframe["rsi"] < rsi_threshold)
cond4 = (dataframe["close"] <= dataframe["bb_lowerband"])
cond5 = (dataframe["stochrsi_k"] < stochrsi_threshold)
cond6 = ~bearish_signal_aligned
cond7 = ~stochrsi_overbought_aligned
logger.info(f"[{pair}] ⚖️ 震荡趋势策略:标准入场条件")
# 记录 cond6 和 cond7 的触发情况
logger.info(f"[{pair}] cond6 (非熊市) 触发率: {(~bearish_signal_aligned).mean():.2%}, "
f"熊市信号 K 线数: {bearish_signal_aligned.sum()}")
logger.info(f"[{pair}] cond7 (STOCHRSI 非超买) 触发率: {(~stochrsi_overbought_aligned).mean():.2%}, "
f"STOCHRSI 超买 K 线数: {stochrsi_overbought_aligned.sum()}")
buy_condition = cond1 & cond2 & cond3 & cond4 & cond5 & cond6 & cond7 & (trend_score > 60)
buy_condition = cond1 & cond2 & cond3 & cond4 & cond5 & cond6 & cond7
conditions.append(buy_condition)
# 调试日志
@ -561,19 +587,47 @@ class FreqaiPrimer(IStrategy):
(dataframe["volume_z_score"] > 1.0)
)
# 综合卖出条件:根据 trend_score 调整逻辑
#如果趋势得分为100拒绝退出
if trend_score > 92:
logger.info(f"[{pair}] 趋势得分为100拒绝退出")
return dataframe
# 检测趋势状态
trend_status = self.detect_trend_status(dataframe, metadata)
trend_sell_threshold = 85
if trend_score > trend_sell_threshold:
sell_condition = (cond1 & cond2) | (cond1 & cond3) | (cond2 & cond3) # 中等趋势,至少两个条件满足
logger.info(f"[{pair}] 趋势得分 {trend_score:.2f} > 55需满足至少两个条件")
else:
sell_condition = cond1 | cond2 | cond3 # 弱势趋势,任一条件满足
logger.info(f"[{pair}] 趋势得分 {trend_score:.2f} <= 趋势得分卖出条件:{trend_sell_threshold},任一条件满足")
# 根据趋势状态调整出场策略
if trend_status == "bullish":
# 上涨趋势:严格出场条件,让利润奔跑
if trend_score > 95:
logger.info(f"[{pair}] 🚀 强劲上涨趋势,拒绝卖出")
return dataframe
# 上涨趋势下需要更强的卖出信号
bullish_sell_threshold = 90
cond1_bullish = (dataframe["&-price_value_divergence"] > self.sell_threshold * 1.15) # 更严格的阈值
cond2_bullish = (dataframe["rsi"] > 75) & (dataframe["stochrsi_k"] > 85) & (dataframe["adx"] > 30)
cond3_bullish = (dataframe["short_term_return"] > 5.0) & (dataframe["stochrsi_k"] > 85) # 更高的涨幅要求
sell_condition = (cond1_bullish & cond2_bullish) | (cond1_bullish & cond3_bullish) | (cond2_bullish & cond3_bullish)
logger.info(f"[{pair}] 🚀 上涨趋势策略:严格出场条件")
elif trend_status == "bearish":
# 下跌趋势:宽松出场条件,快速止盈止损
cond1_bearish = (dataframe["&-price_value_divergence"] > self.sell_threshold * 0.9) # 更宽松的阈值
cond2_bearish = (dataframe["rsi"] > 60) & (dataframe["stochrsi_k"] > 70) & (dataframe["adx"] > 20)
cond3_bearish = (dataframe["short_term_return"] > 1.5) & (dataframe["stochrsi_k"] > 75) # 较低的涨幅要求
sell_condition = cond1_bearish | cond2_bearish | cond3_bearish # 任一条件即可卖出
logger.info(f"[{pair}] 📉 下跌趋势策略:宽松出场条件")
else: # ranging
# 震荡趋势:使用原策略
if trend_score > 92:
logger.info(f"[{pair}] ⚖️ 震荡趋势但得分较高,拒绝卖出")
return dataframe
trend_sell_threshold = 85
if trend_score > trend_sell_threshold:
sell_condition = (cond1 & cond2) | (cond1 & cond3) | (cond2 & cond3) # 中等趋势,至少两个条件满足
logger.info(f"[{pair}] ⚖️ 震荡趋势策略:标准出场条件")
else:
sell_condition = cond1 | cond2 | cond3 # 弱势趋势,任一条件满足
logger.info(f"[{pair}] ⚖️ 弱势震荡,任一条件满足")
conditions.append(sell_condition)
@ -645,73 +699,101 @@ class FreqaiPrimer(IStrategy):
initial_stake_amount = trade.stake_amount / 3
logger.info(f"{pair} 首次入场金额: {initial_stake_amount:.2f}, 当前持仓金额: {trade.stake_amount:.2f}, "
f"加仓次数: {trade.nr_of_successful_entries - 1}")
f"加仓次数: {trade.nr_of_successful_entries - 1}, 趋势得分: {trend_score:.2f}")
# 检测趋势状态
trend_status = self.detect_trend_status(dataframe, {'pair': pair})
logger.info(f"{pair} 当前趋势状态: {trend_status}")
# 根据趋势状态调整仓位管理参数
if trend_status == "bullish":
# 上涨趋势:积极加仓,放宽止盈
max_entry_adjustments = min(self.MAX_ENTRY_POSITION_ADJUSTMENT + 1, 5) # 允许更多加仓
add_position_threshold = self.ADD_POSITION_THRESHOLD * 1.3 # 更宽松的加仓条件
exit_position_ratio = self.EXIT_POSITION_RATIO * 1.4 # 更高的止盈目标
trailing_stop_start = self.TRAILING_STOP_START * 1.2 # 更高的启动阈值
trailing_stop_distance = self.TRAILING_STOP_DISTANCE * 1.5 # 更大的回撤容忍
logger.info(f"{pair} 🚀 上涨趋势仓位管理参数: max_entries={max_entry_adjustments}, add_thresh={add_position_threshold:.4f}, exit_ratio={exit_position_ratio:.2%}")
elif trend_status == "bearish":
# 下跌趋势:谨慎加仓,严格止盈
max_entry_adjustments = max(self.MAX_ENTRY_POSITION_ADJUSTMENT - 1, 1) # 减少加仓次数
add_position_threshold = self.ADD_POSITION_THRESHOLD * 0.7 # 更严格的加仓条件
exit_position_ratio = self.EXIT_POSITION_RATIO * 0.8 # 更低的止盈目标
trailing_stop_start = self.TRAILING_STOP_START * 0.8 # 更低的启动阈值
trailing_stop_distance = self.TRAILING_STOP_DISTANCE * 0.7 # 更严格的止损
logger.info(f"{pair} 📉 下跌趋势仓位管理参数: max_entries={max_entry_adjustments}, add_thresh={add_position_threshold:.4f}, exit_ratio={exit_position_ratio:.2%}")
else: # ranging
# 震荡趋势:使用标准参数
max_entry_adjustments = self.MAX_ENTRY_POSITION_ADJUSTMENT
add_position_threshold = self.ADD_POSITION_THRESHOLD
exit_position_ratio = self.EXIT_POSITION_RATIO
trailing_stop_start = self.TRAILING_STOP_START
trailing_stop_distance = self.TRAILING_STOP_DISTANCE
logger.info(f"{pair} ⚖️ 震荡趋势仓位管理参数: max_entries={max_entry_adjustments}, add_thresh={add_position_threshold:.4f}, exit_ratio={exit_position_ratio:.2%}")
# 加仓逻辑
max_entry_adjustments = self.MAX_ENTRY_POSITION_ADJUSTMENT
if trade.nr_of_successful_entries <= max_entry_adjustments + 1:
add_position_threshold = self.ADD_POSITION_THRESHOLD
# 线性映射加仓阈值,趋势值越高,加仓越严格
add_threshold = 80 - 30 * (trend_score / 100) # 趋势值 100 -> 50, 0 -> 80
# 动态调整加仓阈值
if trend_status == "bullish":
add_threshold = 90 - 20 * (trend_score / 100) # 上涨趋势下更宽松
elif trend_status == "bearish":
add_threshold = 70 - 30 * (trend_score / 100) # 下跌趋势下更谨慎
else:
add_threshold = 80 - 30 * (trend_score / 100) # 震荡趋势标准
if profit_ratio <= add_position_threshold and hold_time > 5 and trend_score <= add_threshold:
logger.info(f"{pair} 初始下注金额: {initial_stake_amount:.2f}, trend_score: {trend_score:.2f}, add_threshold: {add_threshold} ")
# 计算加仓金额
add_count = trade.nr_of_successful_entries - 1
multipliers = [2, 4, 8]
# 根据趋势状态调整加仓倍数
if trend_status == "bullish":
multipliers = [1.5, 3, 6] # 上涨趋势下更保守的加仓
elif trend_status == "bearish":
multipliers = [1, 2, 4] # 下跌趋势下更激进的加仓(抄底)
else:
multipliers = [2, 4, 8] # 震荡趋势标准加仓
if add_count < len(multipliers):
multiplier = multipliers[add_count]
add_amount = initial_stake_amount * multiplier
logger.info(f"{pair}{add_count + 1} 次加仓,倍数={multiplier}, "
f"金额 = {initial_stake_amount:.2f} * {multiplier} = {add_amount:.2f}")
logger.info(f"{pair} 加仓计算: 第 {add_count + 1} 次加仓,倍数={multiplier}, "
f"金额 = {initial_stake_amount:.2f} * {multiplier} = {add_amount:.2f}")
if min_stake is not None and add_amount < min_stake:
logger.warning(f"{pair} 加仓金额 {add_amount:.2f} 低于最小下注金额 {min_stake:.2f},取消加仓")
logger.warning(f"{pair} 加仓金额 {add_amount:.2f} 低于最小下注金额 {min_stake:.2f}")
return (None, f"Add amount {add_amount:.2f} below min_stake {min_stake:.2f}")
if add_amount > max_stake:
logger.warning(f"{pair} 加仓金额 {add_amount:.2f} 超出最大可用金额 {max_stake:.2f},调整为 {max_stake:.2f}")
add_amount = max_stake
logger.info(f"{pair} 价格下跌 {profit_ratio*100:.2f}%,触发第 {add_count + 1} 次加仓 {add_amount:.2f}")
return (add_amount, f"Price dropped {profit_ratio*100:.2f}%, add {add_amount:.2f}")
logger.info(f"{pair} 趋势状态: {trend_status}, 价格下跌 {profit_ratio*100:.2f}%,触发第 {add_count + 1} 次加仓 {add_amount:.2f}")
return (add_amount, f"Trend: {trend_status}, Price dropped {profit_ratio*100:.2f}%, add {add_amount:.2f}")
# 减仓逻辑
exit_position_ratio = self.EXIT_POSITION_RATIO
if profit_ratio >= 0.03:
# 趋势值越高,减仓比例越低
reduce_factor = 0.6 + 0.4 * (1 - trend_score / 100) # 牛市(100) -> 0.6, 熊市(0) -> 1.0
reduce_amount = -exit_position_ratio * reduce_factor * trade.stake_amount
logger.info(f"{pair} 趋势值 {trend_score:.2f},利润 {profit_ratio*100:.2f}%,减仓 {abs(reduce_amount):.2f}")
return (reduce_amount, f"Profit {profit_ratio*100:.2f}%")
elif profit_ratio >= 0.05:
reduce_factor = 1.4 - 0.4 * (trend_score / 100) # 牛市(100) -> 1.0, 熊市(0) -> 1.4
reduce_amount = -exit_position_ratio * reduce_factor * trade.stake_amount
logger.info(f"{pair} 趋势{trend_score:.2f}利润 {profit_ratio*100:.2f}%,减仓 {abs(reduce_amount):.2f}")
return (reduce_amount, f"Profit {profit_ratio*100:.2f}%")
if profit_ratio >= exit_position_ratio:
# 根据趋势状态调整减仓比例
if trend_status == "bullish":
reduce_factor = 0.5 # 上涨趋势下只减仓50%
elif trend_status == "bearish":
reduce_factor = 1.0 # 下跌趋势下全部减仓
else:
reduce_factor = 0.8 # 震荡趋势下减仓80%
reduce_amount = -trade.stake_amount * reduce_factor
logger.info(f"{pair} 趋势状态: {trend_status}, 利润 {profit_ratio*100:.2f}%,减仓 {abs(reduce_amount):.2f} ({reduce_factor*100:.0f}%)")
return (reduce_amount, f"Trend: {trend_status}, Profit {profit_ratio*100:.2f}%, reduce {abs(reduce_amount):.2f}")
# 追踪止损逻辑
trailing_stop_start = self.TRAILING_STOP_START
trailing_stop_distance = self.TRAILING_STOP_DISTANCE
# 使用 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
distance_factor = 0.7 + (1.5 - 0.7) * sigmoid # 牛市(100) -> 1.5, 熊市(0) -> 0.7
trailing_stop_start *= trailing_factor
trailing_stop_distance *= distance_factor
if profit_ratio >= trailing_stop_start and not self.trailing_stop_enabled:
self.trailing_stop_enabled = True
trade.adjust_min_max_rates(current_rate, current_rate)
logger.info(f"{pair} 价格上涨超过 {trailing_stop_start*100:.1f}%,启动追踪止损")
logger.info(f"{pair} 趋势状态: {trend_status}, 价格上涨超过 {trailing_stop_start*100:.1f}%,启动追踪止损")
return None
if self.trailing_stop_enabled:
max_rate = trade.max_rate or current_rate
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"Trailing stop at {trailing_stop_price:.6f}")
logger.info(f"{pair} 趋势状态: {trend_status}, 价格回落至 {trailing_stop_price:.6f},触发全部卖出")
return (-trade.stake_amount, f"Trend: {trend_status}, Trailing stop at {trailing_stop_price:.6f}")
trade.adjust_min_max_rates(current_rate, trade.min_rate)
return None
@ -948,3 +1030,57 @@ class FreqaiPrimer(IStrategy):
except Exception as e:
logger.error(f"[{pair}] 获取市场趋势失败:{e}", exc_info=True)
return 50
def detect_trend_status(self, dataframe: DataFrame, metadata: dict) -> str:
"""
基于最近20个周期的trend_score判断趋势状态
规则
- 最近20个周期中75%以上得分TREND_BULLISH_THRESHOLD且最近10个周期中90%以上得分TREND_BULLISH_THRESHOLD 上涨趋势
- 最近20个周期中75%以上得分TREND_BEARISH_THRESHOLD且最近10个周期中90%以上得分TREND_BEARISH_THRESHOLD 下跌趋势
- 其他情况 震荡趋势
"""
pair = metadata.get('pair', 'Unknown')
try:
# 获取最近20个周期的trend_score历史
if len(dataframe) < 20:
logger.warning(f"[{pair}] 数据不足20个周期返回震荡趋势")
return "ranging"
# 计算最近20个周期的trend_score
trend_scores_20 = []
for i in range(-20, 0):
# 获取历史数据片段
hist_df = dataframe.iloc[:i+1] if i != -1 else dataframe
if len(hist_df) > 0:
score = self.get_market_trend(hist_df, metadata)
trend_scores_20.append(score)
else:
trend_scores_20.append(50) # 默认值
# 最近10个周期
trend_scores_10 = trend_scores_20[-10:]
# 计算满足条件的比例
strong_bull_20 = sum(1 for score in trend_scores_20 if score >= self.TREND_BULLISH_THRESHOLD) / len(trend_scores_20)
strong_bull_10 = sum(1 for score in trend_scores_10 if score >= self.TREND_BULLISH_THRESHOLD) / len(trend_scores_10)
strong_bear_20 = sum(1 for score in trend_scores_20 if score <= self.TREND_BEARISH_THRESHOLD) / len(trend_scores_20)
strong_bear_10 = sum(1 for score in trend_scores_10 if score <= self.TREND_BEARISH_THRESHOLD) / len(trend_scores_10)
# 判定趋势
if strong_bull_20 >= 0.75 and strong_bull_10 >= 0.9:
trend_status = "bullish"
logger.info(f"[{pair}] 🚀 检测到上涨趋势: 20周期强势比例={strong_bull_20:.1%}, 10周期强势比例={strong_bull_10:.1%}, 阈值={self.TREND_BULLISH_THRESHOLD}")
elif strong_bear_20 >= 0.75 and strong_bear_10 >= 0.9:
trend_status = "bearish"
logger.info(f"[{pair}] 📉 检测到下跌趋势: 20周期弱势比例={strong_bear_20:.1%}, 10周期弱势比例={strong_bear_10:.1%}, 阈值={self.TREND_BEARISH_THRESHOLD}")
else:
trend_status = "ranging"
logger.info(f"[{pair}] ⚖️ 检测到震荡趋势: 20周期强势比例={strong_bull_20:.1%}, 弱势比例={strong_bear_20:.1%}, 阈值={self.TREND_BULLISH_THRESHOLD}/{self.TREND_BEARISH_THRESHOLD}")
return trend_status
except Exception as e:
logger.error(f"[{pair}] 趋势状态检测失败: {e}")
return "ranging"