错误用法:trade.current_profit() - 这可能返回不准确的值

This commit is contained in:
zhangkun9038@dingtalk.com 2026-02-10 12:49:17 +08:00
parent e474414d52
commit cf436211ea

View File

@ -1523,185 +1523,7 @@ class FreqaiPrimer(IStrategy):
self.strategy_log(f"[{pair}] 入场被拒绝,原因列表: {', '.join(rejected_conditions)}")
return False
def confirm_trade_exit(
self,
pair: str,
trade: 'Trade',
order_type: str,
amount: float,
rate: float,
time_in_force: str,
exit_reason: str,
current_time: datetime,
**kwargs,
) -> bool:
"""
交易卖出前的确认函数用于最终决定是否执行出场
此处使用 ML 审核官exit_signal 置信度过滤出场
"""
self.strategy_log(f"[{pair}] confirm_trade_exit 被调用 - 价格: {rate:.8f}, 出场原因: {exit_reason}, 时间: {current_time}")
# 风险控制类退出原因:不经过 ML 审核官,直接允许出场
if exit_reason in ['stop_loss', 'trailing_stop_loss', 'emergency_exit', 'force_exit']:
self.strategy_log(f"[{pair}] 风险控制退出,不走 ML 审核官: exit_reason={exit_reason}")
return True
# 默认允许出场
allow_exit = True
try:
df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
if len(df) > 0:
last_row = df.iloc[-1]
exit_prob = None
# 优先使用 FreqAI 的 exit_signal 预测列
if '&s-exit_signal' in df.columns:
exit_prob = float(last_row['&s-exit_signal'])
elif '&-exit_signal_prob' in df.columns:
exit_prob = float(last_row['&-exit_signal_prob'])
elif '&-s-exit_signal_prob' in df.columns:
exit_prob = float(last_row['&-s-exit_signal_prob'])
elif '&-exit_signal' in df.columns:
val = last_row['&-exit_signal']
if isinstance(val, (int, float)):
exit_prob = float(val)
else:
# 文本标签时,简单映射为 0/1
exit_prob = 1.0 if str(val).lower() in ['exit', 'sell', '1'] else 0.0
if exit_prob is not None:
# 确保概率在 [0, 1] 范围内(分类器输出可能有浮点误差)
exit_prob = max(0.0, min(1.0, exit_prob))
# 从 kwargs 获取当前利润freqtrade 会传入 current_profit
current_profit = float(kwargs.get('current_profit', 0.0))
# 获取出场一字基础阈值
base_threshold = self.ml_exit_signal_threshold.value
# 计算持仓时长(分钟)
try:
trade_age_minutes = max(0.0, (current_time - trade.open_date_utc).total_seconds() / 60.0)
except Exception:
trade_age_minutes = 0.0
# 基于持仓时长的阈值衰减:持仓越久,阈值越低,越容易出场
age_factor = min(trade_age_minutes / (24 * 60.0), 1.0) # 0~1对应 0~24 小时+
dynamic_threshold = base_threshold * (1.0 - 0.3 * age_factor)
# 小利润单(<=2%)再额外放宽 20%
if current_profit <= 0.02:
dynamic_threshold *= 0.8
# 新增:读取 AI 预测的未来波动率信号(极端化方案)
future_vol_signal = None
if '&s-future_volatility' in df.columns:
future_vol_signal = float(last_row['&s-future_volatility'])
elif '&-future_volatility' in df.columns:
future_vol_signal = float(last_row['&-future_volatility'])
# 极端化逻辑:根据 AI 预测的未来波动率直接接管部分出场决策
if future_vol_signal is not None and exit_reason == 'exit_signal':
# 情况AAI 预测强趋势(高波动),且当前不亏损 → 忽略本次 exit_signal继续持有
if future_vol_signal > 0.65 and current_profit >= 0:
self.strategy_log(
f"[波动率 AI] [{pair}] AI 预测强趋势(高波动 {future_vol_signal:.2f}),忽略本次 exit_signal继续持有 | "
f"持仓: {trade_age_minutes:.1f}min, 利润: {current_profit:.4f}"
)
allow_exit = False
return allow_exit
# 情况BAI 预测震荡市(低波动) → 强制接受 exit_signal立即出场
elif future_vol_signal < 0.35:
self.strategy_log(
f"[波动率 AI] [{pair}] AI 预测震荡市(低波动 {future_vol_signal:.2f}),强制接受 exit_signal 出场 | "
f"持仓: {trade_age_minutes:.1f}min, 利润: {current_profit:.4f}"
)
return True
# 介于 0.35-0.65 之间:中性区间,不做强制处理,继续走原有 ML 审核官逻辑
# 设定下限,避免阈值过低
dynamic_threshold = max(0.05, dynamic_threshold)
if exit_prob < dynamic_threshold:
self.strategy_log(
f"[{pair}] ML 审核官拒绝出场: exit_signal 概率 {exit_prob:.2f} < 动态阈值 {dynamic_threshold:.2f}"
f" | 原应出场原因: {exit_reason} | 持仓: {trade_age_minutes:.1f}min, 利润: {current_profit:.4f}"
f" | 波动率AI: {future_vol_signal if future_vol_signal is not None else 'N/A'}"
)
allow_exit = False
else:
if future_vol_signal is not None:
future_vol_str = f"{future_vol_signal:.2f}"
else:
future_vol_str = "N/A"
# 格式化数字限制有效位数不超过5位
def format_number(value, max_digits=5):
"""格式化数字,限制有效位数"""
if value == 0:
return "0"
# 转换为字符串并去掉末尾的0
s = f"{value:.10f}".rstrip('0').rstrip('.')
# 如果小数点前的数字超过max_digits使用科学计数法
if len(s.split('.')[0]) > max_digits:
return f"{value:.2e}"
# 如果总长度超过max_digits截断
if len(s) > max_digits:
# 保留小数点前的数字
if '.' in s:
integer_part, decimal_part = s.split('.')
if len(integer_part) > max_digits:
return f"{value:.2e}"
else:
# 截断小数部分
max_decimal = max_digits - len(integer_part) - 1
if max_decimal > 0:
s = integer_part + '.' + decimal_part[:max_decimal]
else:
s = integer_part
else:
# 整数部分超过限制
if len(s) > max_digits:
return f"{value:.2e}"
return s
# 格式化价格限制有效位数不超过5位
def format_number(value, max_digits=5):
"""格式化数字,限制有效位数"""
if value == 0:
return "0"
# 转换为字符串并去掉末尾的0
s = f"{value:.10f}".rstrip('0').rstrip('.')
# 如果小数点前的数字超过max_digits使用科学计数法
if len(s.split('.')[0]) > max_digits:
return f"{value:.2e}"
# 如果总长度超过max_digits截断
if len(s) > max_digits:
# 保留小数点前的数字
if '.' in s:
integer_part, decimal_part = s.split('.')
if len(integer_part) > max_digits:
return f"{value:.2e}"
else:
# 截断小数部分
max_decimal = max_digits - len(integer_part) - 1
if max_decimal > 0:
s = integer_part + '.' + decimal_part[:max_decimal]
else:
s = integer_part
else:
# 整数部分超过限制
if len(s) > max_digits:
return f"{value:.2e}"
return s
self.strategy_log(
f"[{pair}] ML 审核官允许出场: exit_signal 概率 {exit_prob:.2f} >= 动态阈值 {dynamic_threshold:.2f}"
f" | 出场原因: {exit_reason} | 持仓: {format_number(trade_age_minutes)}min, 利润: {format_number(current_profit)}"
f" | 波动率AI: {future_vol_str}"
)
except Exception as e:
logger.warning(f"[{pair}] ML 审核官出场检查失败,允许出场: {e}")
return allow_exit
def custom_stoploss(self, pair: str, trade: 'Trade', current_time, current_rate: float,
current_profit: float, **kwargs) -> float:
@ -1731,10 +1553,19 @@ class FreqaiPrimer(IStrategy):
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
rate: float, time_in_force: str, exit_reason: str,
current_time: datetime, **kwargs) -> bool:
current_time: datetime, current_profit: float, **kwargs) -> bool:
"""
智能出场确认结合ML预测信号来决定是否出场
"""
# 计算持仓时长(分钟)
trade_age_minutes = (current_time - trade.open_date_utc).total_seconds() / 60
# 设置最小持仓时间保护,避免交易刚开仓就立刻被平仓
min_hold_minutes = 3 # 至少持有3分钟
if trade_age_minutes < min_hold_minutes:
self.strategy_log(f"[{pair}] 交易开仓时间仅{trade_age_minutes:.1f}分钟,小于最小持仓时间{min_hold_minutes}分钟,阻止出场")
return False
try:
# 获取当前的ML预测数据
df, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
@ -1763,7 +1594,7 @@ class FreqaiPrimer(IStrategy):
# 基于ML预测的智能决策
if current_entry_prob is not None and predicted_volatility is not None:
# 如果当前入场信号概率很高,说明市场条件仍然良好,可以继续持有
if current_entry_prob > 0.6 and trade.current_profit() < 0.05:
if current_entry_prob > 0.6 and current_profit < 0.05:
# 高入场概率 + 低利润,建议继续持有(除非已有相当利润)
self.strategy_log(f"[{pair}] 当前入场信号概率高({current_entry_prob:.2f}),建议继续持有")
return False # 阻止出场