From d5ef5252246908ad590d5511c9112981c9db26fe 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 13:58:59 +0800 Subject: [PATCH] 1 --- frontend/src/components/GlobalConfig.jsx | 208 +++++++++++++++++++++-- 1 file changed, 194 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/GlobalConfig.jsx b/frontend/src/components/GlobalConfig.jsx index 3198c84..44b3050 100644 --- a/frontend/src/components/GlobalConfig.jsx +++ b/frontend/src/components/GlobalConfig.jsx @@ -1208,9 +1208,32 @@ const GlobalConfig = () => { }, ] + // 统计过滤可视化:解析全局 STATS_* 配置 + const rawStatsSymbolFilters = configs?.STATS_SYMBOL_FILTERS + const rawStatsHourFilters = configs?.STATS_HOUR_FILTERS + const statsSymbolFiltersValue = + rawStatsSymbolFilters && typeof rawStatsSymbolFilters === 'object' + ? (rawStatsSymbolFilters.value ?? rawStatsSymbolFilters) + : null - + const statsHourFiltersValue = + rawStatsHourFilters && typeof rawStatsHourFilters === 'object' + ? (rawStatsHourFilters.value ?? rawStatsHourFilters) + : null + + const statsBlacklist = Array.isArray(statsSymbolFiltersValue?.blacklist) + ? statsSymbolFiltersValue.blacklist + : [] + const statsWhitelist = Array.isArray(statsSymbolFiltersValue?.whitelist) + ? statsSymbolFiltersValue.whitelist + : [] + const statsHours = Array.isArray(statsHourFiltersValue?.hours) + ? statsHourFiltersValue.hours + : [] + + const statsGeneratedAt = statsSymbolFiltersValue?.generated_at || statsHourFiltersValue?.generated_at || null + const statsDays = statsSymbolFiltersValue?.days || statsHourFiltersValue?.days || null return (
@@ -1645,15 +1668,16 @@ const GlobalConfig = () => { )}
- {/* Tabs */} -
- {[ - { key: 'all', label: '全部' }, - { key: 'risk', label: '风险控制' }, - { key: 'strategy', label: '策略参数' }, - { key: 'scan', label: '市场扫描' }, - { key: 'position', label: '仓位控制' }, - ].map(tab => ( + {/* Tabs */} +
+ {[ + { key: 'all', label: '全部' }, + { key: 'risk', label: '风险控制' }, + { key: 'strategy', label: '策略参数' }, + { key: 'scan', label: '市场扫描' }, + { key: 'position', label: '仓位控制' }, + { key: 'stats', label: '统计过滤' }, + ].map(tab => (
+ {/* 统计过滤可视化(仅在“统计过滤” Tab 展示) */} + {activeTab === 'stats' && ( +
+
+
+

统计过滤总览

+
+ 基于最近 {statsDays || 7} 天的交易统计自动生成:差标的与差时段会被自动降权并提高信号门槛,仅影响自动交易,不会一刀切禁止。 +
+
+ {statsGeneratedAt && ( +
生成时间(UTC):{String(statsGeneratedAt).replace('T', ' ').slice(0, 19)}
+ )} +
+ +
+ {/* Symbol 白/黑名单 */} +
+
+ 交易对白名单 / 黑名单 + + 白名单 {statsWhitelist.length} · 黑名单 {statsBlacklist.length} + +
+ {(statsWhitelist.length === 0 && statsBlacklist.length === 0) ? ( +
暂无统计结果(需先定时跑 7 天聚合脚本)。
+ ) : ( +
+
+
白名单(近期表现较好)
+
+ + + + + + + + + + + {statsWhitelist.slice(0, 20).map((item) => ( + + + + + + + ))} + +
Symbol笔数净盈亏胜率%
{item.symbol}{item.trade_count}= 0 ? '#28a745' : '#dc3545' }}> + {Number(item.net_pnl) >= 0 ? '+' : ''}{Number(item.net_pnl).toFixed(2)} + {Number(item.win_rate_pct).toFixed(1)}
+
+
+
+
黑名单(软降权,考核期中)
+
+ + + + + + + + + + + {statsBlacklist.slice(0, 20).map((item) => ( + + + + + + + ))} + +
Symbol笔数净盈亏胜率%
{item.symbol}{item.trade_count} + {Number(item.net_pnl).toFixed(2)} + {Number(item.win_rate_pct).toFixed(1)}
+
+
+
+ )} +
+ + {/* 按小时时段过滤 */} +
+
+ 按小时过滤(北京时间) + bucket=bad → 降仓 & 提高信号门槛 +
+ {statsHours.length === 0 ? ( +
暂无时段统计结果。
+ ) : ( +
+ + + + + + + + + + + + + {statsHours + .slice() + .sort((a, b) => Number(a.hour) - Number(b.hour)) + .map((item) => { + const bucket = String(item.bucket || '').toLowerCase() + const rowBg = + bucket === 'bad' + ? '#fff5f5' + : bucket === 'good' + ? '#f0fff4' + : '#ffffff' + const badgeColor = + bucket === 'bad' + ? '#dc3545' + : bucket === 'good' + ? '#28a745' + : '#6c757d' + return ( + + + + + + + + + ) + })} + +
小时笔数净盈亏分组仓位系数信号+档数
{item.hour}:00{item.trade_count}= 0 ? '#28a745' : '#dc3545' }}> + {Number(item.net_pnl) >= 0 ? '+' : ''}{Number(item.net_pnl).toFixed(2)} + + + {bucket || 'unknown'} + + + {item.position_factor !== undefined ? Number(item.position_factor).toFixed(2) : '1.00'} + + {item.signal_boost || 0} +
+
+ )} +
+
+
+ )} + {Object.keys(configs).length > 0 ? ( (() => { const configCategories = { - 'risk': '风险控制', - 'strategy': '策略参数', - 'scan': '市场扫描', - 'position': '仓位控制', + risk: '风险控制', + strategy: '策略参数', + scan: '市场扫描', + position: '仓位控制', + stats: '统计过滤', } // 过滤逻辑