From 78007040f183f2b56276293ec5c52b75cd88d442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Fri, 27 Feb 2026 20:08:07 +0800 Subject: [PATCH] feat(blacklist): Enhance blacklist logic and UI representation Updated the trading system to differentiate between soft and hard blacklists based on recent performance metrics. The frontend now displays the blacklist status with clear visual indicators. This change aims to improve risk management and user awareness of trading conditions. --- frontend/src/components/GlobalConfig.jsx | 14 +++++++++++++- scripts/aggregate_trade_stats.py | 18 ++++++++++++++---- trading_system/strategy.py | 22 +++++++++++++++++----- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/GlobalConfig.jsx b/frontend/src/components/GlobalConfig.jsx index 44b3050..5cc4605 100644 --- a/frontend/src/components/GlobalConfig.jsx +++ b/frontend/src/components/GlobalConfig.jsx @@ -1756,7 +1756,7 @@ const GlobalConfig = () => {
-
黑名单(软降权,考核期中)
+
黑名单(软/硬,考察期动态调整)
@@ -1765,6 +1765,7 @@ const GlobalConfig = () => { + @@ -1776,6 +1777,17 @@ const GlobalConfig = () => { {Number(item.net_pnl).toFixed(2)} + ))} diff --git a/scripts/aggregate_trade_stats.py b/scripts/aggregate_trade_stats.py index 5e341b9..7d504cb 100644 --- a/scripts/aggregate_trade_stats.py +++ b/scripts/aggregate_trade_stats.py @@ -42,8 +42,11 @@ def main(): # 规则参数(后续可改成全局配置,这里先写死一版直观规则): min_trades_for_symbol = 5 # 至少 N 笔才纳入评估,避免样本太少 min_trades_for_hour = 10 # 小时至少 N 笔才纳入评估 - blacklist_pnl_threshold = 0.0 # 净盈亏 < 0 视为表现不佳 - good_hour_pnl_threshold = 0.0 # 净盈亏 > 0 视为表现较好 + blacklist_pnl_threshold = 0.0 # 净盈亏 < 0 视为表现不佳(软黑名单) + hard_blacklist_pnl_threshold = -3.0 # 净亏绝对值较大时考虑升级为硬黑名单 + hard_blacklist_min_trades = 10 # 硬黑名单至少需要的样本数 + hard_blacklist_max_win_rate = 10.0 # 胜率≤10% 且净亏较大时视为严重拖累 + good_hour_pnl_threshold = 0.0 # 净盈亏 > 0 视为表现较好 symbol_blacklist = [] symbol_whitelist = [] @@ -61,15 +64,22 @@ def main(): total = max(1, win + loss) win_rate = 100.0 * win / total - # 软黑名单:近期净亏 + 有一定笔数 -> 降权(不一刀切禁止) + # 黑名单:近期净亏 + 有一定笔数 -> 降权或升级为硬黑名单 if net_pnl < blacklist_pnl_threshold: + mode = "reduced" + if ( + net_pnl <= hard_blacklist_pnl_threshold + and tc >= hard_blacklist_min_trades + and win_rate <= hard_blacklist_max_win_rate + ): + mode = "hard" symbol_blacklist.append( { "symbol": sym, "trade_count": tc, "net_pnl": round(net_pnl, 4), "win_rate_pct": round(win_rate, 1), - "mode": "reduced", # 软黑名单:仅降权+提门槛 + "mode": mode, # reduced=软黑名单(降权+提门槛);hard=硬黑名单(自动不再开仓) } ) # 白名单:近期净盈且胜率尚可 diff --git a/trading_system/strategy.py b/trading_system/strategy.py index 2bf14c3..eea4670 100644 --- a/trading_system/strategy.py +++ b/trading_system/strategy.py @@ -690,8 +690,11 @@ class TradingStrategy: # 判断是否应该交易(信号强度 >= 有效 MIN_SIGNAL_STRENGTH 才交易;低波动期自动提高门槛) base_min_signal_strength = config.get_effective_config('MIN_SIGNAL_STRENGTH', 7) - # 基于全局 7 天统计的 symbol / 小时过滤:差标的、差时段提高信号门槛 + # 基于全局 7 天统计的 symbol / 小时过滤: + # - 硬黑名单:直接禁止自动交易(仅允许平仓) + # - 软黑名单 & 差时段:提高信号门槛 extra_signal_boost = 0 + blocked_by_hard_blacklist = False try: from datetime import datetime, timezone, timedelta from config_manager import GlobalStrategyConfigManager @@ -700,11 +703,17 @@ class TradingStrategy: stats_symbol = mgr.get("STATS_SYMBOL_FILTERS", {}) or {} stats_hour = mgr.get("STATS_HOUR_FILTERS", {}) or {} - # symbol 软黑名单:命中则在基础门槛上 +1 + # symbol 黑名单:硬黑名单直接拒绝;软黑名单在基础门槛上 +1 bl = stats_symbol.get("blacklist") or [] if symbol and isinstance(bl, list): - if any((item.get("symbol") or "").upper() == symbol.upper() for item in bl): - extra_signal_boost += 1 + for item in bl: + if (item.get("symbol") or "").upper() == symbol.upper(): + mode = (item.get("mode") or "reduced").lower() + if mode == "hard": + blocked_by_hard_blacklist = True + else: + extra_signal_boost += 1 + break # 按小时过滤:bad 小时再 +1 try: @@ -721,6 +730,7 @@ class TradingStrategy: except Exception: base_min_signal_strength = config.get_effective_config('MIN_SIGNAL_STRENGTH', 7) extra_signal_boost = 0 + blocked_by_hard_blacklist = False min_signal_strength = max(0, min(10, int(base_min_signal_strength) + int(extra_signal_boost))) # 强度上限归一到 0-10,避免出现 12/10 这种误导显示 @@ -740,7 +750,9 @@ class TradingStrategy: signal_strength = min(scan_strength, 5) direction = scan_dir reasons.append("采用扫描器综合信号(弱)") - should_trade = signal_strength >= min_signal_strength and direction is not None + should_trade = (not blocked_by_hard_blacklist) and signal_strength >= min_signal_strength and direction is not None + if blocked_by_hard_blacklist: + reasons.append("❌ 命中硬黑名单(7天持续净亏),自动交易禁用,仅允许手动/解封后再交易") # ===== RSI / 24h 涨跌幅过滤:做多不追高、做空不杀跌;可选 RSI 极端反向(超买反空/超卖反多)===== # 反向属于“逆短期超买超卖”的均值回归,在强趋势里逆势风险大;可选“仅4H中性时反向”以降低风险。
笔数 净盈亏 胜率%模式
{Number(item.win_rate_pct).toFixed(1)} + {String(item.mode || 'reduced') === 'hard' ? ( + + 硬 + + ) : ( + + 软 + + )} +