diff --git a/backend/api/routes/system.py b/backend/api/routes/system.py index a8e413a..765b777 100644 --- a/backend/api/routes/system.py +++ b/backend/api/routes/system.py @@ -1298,6 +1298,22 @@ async def market_overview(_admin: Dict[str, Any] = Depends(require_system_admin) "MARKET_SCHEME": market_scheme, } data["beta_filter_triggered"] = triggered + + # 策略执行概览:当前执行方案与配置项执行情况(易读文字) + try: + from market_overview import get_strategy_execution_overview + except ImportError: + try: + from backend.market_overview import get_strategy_execution_overview + except ImportError: + get_strategy_execution_overview = None + if get_strategy_execution_overview is not None: + try: + data["strategy_execution_overview"] = get_strategy_execution_overview() + except Exception as e: + data["strategy_execution_overview"] = {"sections": [{"title": "加载失败", "content": str(e)}]} + else: + data["strategy_execution_overview"] = {"sections": []} return data diff --git a/backend/market_overview.py b/backend/market_overview.py index e32f1b4..cb99750 100644 --- a/backend/market_overview.py +++ b/backend/market_overview.py @@ -180,3 +180,162 @@ def _simple_trend_4h(klines: list) -> str: if price < avg20 * 0.998: return "down" return "neutral" + + +def _g(key: str, default: Any, cfg: dict) -> Any: + """从配置字典取键,支持 bool/数字/字符串。""" + v = cfg.get(key, default) + if v is None: + return default + if isinstance(default, bool): + return str(v).lower() in ("true", "1", "yes") + return v + + +def get_strategy_execution_overview() -> Dict[str, Any]: + """ + 生成「策略执行概览」:当前执行方案、配置项执行情况,用易读文字描述整体策略执行标准与机制。 + 供全局配置页「策略执行概览」展示。 + 返回格式:{ "sections": [ { "title": "小节标题", "content": "正文" } ] } + """ + sections = [] + cfg = {} + try: + from config_manager import GlobalStrategyConfigManager + mgr = GlobalStrategyConfigManager() + mgr.reload_from_redis() + for key in ( + "AUTO_TRADE_ENABLED", "AUTO_TRADE_ONLY_TRENDING", "AUTO_TRADE_ALLOW_4H_NEUTRAL", + "MIN_SIGNAL_STRENGTH", "LOW_VOLATILITY_MIN_SIGNAL_STRENGTH", "MARKET_REGIME_AUTO", + "TOP_N_SYMBOLS", "SCAN_INTERVAL", "PRIMARY_INTERVAL", "CONFIRM_INTERVAL", + "MAX_OPEN_POSITIONS", "MAX_DAILY_ENTRIES", "FIXED_RISK_PERCENT", "USE_FIXED_RISK_SIZING", + "BETA_FILTER_ENABLED", "BETA_FILTER_THRESHOLD", "MARKET_SCHEME", + "USE_ATR_STOP_LOSS", "ATR_STOP_LOSS_MULTIPLIER", "STOP_LOSS_PERCENT", + "TAKE_PROFIT_1_PERCENT", "TAKE_PROFIT_PERCENT", "USE_TRAILING_STOP", + "TRAILING_STOP_ACTIVATION", "TRAILING_STOP_PROTECT", "PROFIT_PROTECTION_ENABLED", + "SMART_ENTRY_ENABLED", "USE_TREND_ENTRY_FILTER", "MAX_TREND_MOVE_BEFORE_ENTRY", + "MAX_RSI_FOR_LONG", "MIN_RSI_FOR_SHORT", "MAX_CHANGE_PERCENT_FOR_LONG", "MAX_CHANGE_PERCENT_FOR_SHORT", + "MIN_VOLUME_24H", "MIN_VOLATILITY", "MIN_HOLD_TIME_SEC", + ): + cfg[key] = mgr.get(key) + except Exception as e: + logger.debug("get_strategy_execution_overview 加载配置失败: %s", e) + + def pct(x): + if x is None: + return "—" + try: + f = float(x) + if abs(f) < 1 and abs(f) > 0: + return f"{f * 100:.2f}%" + return f"{f}%" + except (TypeError, ValueError): + return str(x) + + # ---------- 1. 总开关与自动交易条件 ---------- + auto_on = _g("AUTO_TRADE_ENABLED", True, cfg) + only_trending = _g("AUTO_TRADE_ONLY_TRENDING", True, cfg) + allow_4h_neutral = _g("AUTO_TRADE_ALLOW_4H_NEUTRAL", False, cfg) + min_strength = _g("MIN_SIGNAL_STRENGTH", 8, cfg) + low_vol_strength = _g("LOW_VOLATILITY_MIN_SIGNAL_STRENGTH", 9, cfg) + regime_auto = _g("MARKET_REGIME_AUTO", True, cfg) + + c1 = [] + c1.append("自动交易总开关:" + ("开启" if auto_on else "关闭")) + if not auto_on: + c1.append("关闭时仅生成推荐,不会自动下单。") + else: + c1.append("自动下单条件(需同时满足):") + c1.append("• 信号强度 ≥ " + str(min_strength) + "(技术指标综合评分);低波动期自动提高至 " + str(low_vol_strength) + "(" + ("已开启" if regime_auto else "未开启") + "市场节奏识别)。") + c1.append("• 市场状态:仅当「仅做趋势市」开启时,要求市场状态为 trending 才下单;ranging/unknown 只生成推荐、不自动下单。当前「仅做趋势市」=" + ("是" if only_trending else "否") + "。") + c1.append("• 4H 趋势:允许 4H 中性时自动交易 = " + ("是" if allow_4h_neutral else "否") + ";为否时 4H 为中性会跳过自动下单。") + sections.append({ + "title": "一、总开关与自动交易条件", + "content": "\n".join(c1), + }) + + # ---------- 2. 扫描与候选池 ---------- + top_n = _g("TOP_N_SYMBOLS", 30, cfg) + scan_interval = _g("SCAN_INTERVAL", 900, cfg) + primary = _g("PRIMARY_INTERVAL", "4h", cfg) + confirm = _g("CONFIRM_INTERVAL", "1d", cfg) + min_vol = _g("MIN_VOLUME_24H", 30000000, cfg) + min_vol_str = f"{min_vol / 1e6:.0f} 万 USDT" if isinstance(min_vol, (int, float)) and min_vol >= 1e6 else str(min_vol) + vol_pct = _g("MIN_VOLATILITY", 0.03, cfg) + vol_pct_str = f"{float(vol_pct) * 100:.1f}%" if isinstance(vol_pct, (int, float)) else str(vol_pct) + + c2 = [] + c2.append("每次扫描取涨跌幅最大的前 " + str(top_n) + " 个交易对进行详细分析;扫描间隔 " + str(scan_interval) + " 秒。") + c2.append("主周期 " + str(primary) + ",确认周期 " + str(confirm) + ";24h 成交额 ≥ " + min_vol_str + ",最小波动率 " + vol_pct_str + "。") + sections.append({ + "title": "二、扫描与候选池", + "content": "\n".join(c2), + }) + + # ---------- 3. 仓位与风控 ---------- + max_pos = _g("MAX_OPEN_POSITIONS", 4, cfg) + max_daily = _g("MAX_DAILY_ENTRIES", 15, cfg) + fixed_risk = _g("USE_FIXED_RISK_SIZING", True, cfg) + risk_pct = _g("FIXED_RISK_PERCENT", 0.01, cfg) + risk_pct_str = pct(risk_pct) if isinstance(risk_pct, (int, float)) and risk_pct <= 1 else f"{float(risk_pct)}%" + + c3 = [] + c3.append("同时持仓上限 " + str(max_pos) + " 个,每日最多开仓 " + str(max_daily) + " 笔。") + c3.append("固定风险 sizing:" + ("开启" if fixed_risk else "关闭") + ";每笔最大亏损 " + risk_pct_str + " 账户资金。") + sections.append({ + "title": "三、仓位与风控", + "content": "\n".join(c3), + }) + + # ---------- 4. 大盘与市场方案 ---------- + beta_on = _g("BETA_FILTER_ENABLED", True, cfg) + beta_th = _g("BETA_FILTER_THRESHOLD", -0.005, cfg) + scheme = str(_g("MARKET_SCHEME", "normal", cfg) or "normal") + + c4 = [] + c4.append("大盘共振过滤:" + ("开启" if beta_on else "关闭") + ";BTC/ETH 短周期跌逾 " + pct(beta_th) + " 时屏蔽多单。") + c4.append("当前市场方案:" + scheme + "(用于参数预设)。") + sections.append({ + "title": "四、大盘与市场方案", + "content": "\n".join(c4), + }) + + # ---------- 5. 止损止盈与保护 ---------- + use_atr = _g("USE_ATR_STOP_LOSS", True, cfg) + atr_mult = _g("ATR_STOP_LOSS_MULTIPLIER", 2.0, cfg) + sl_pct = _g("STOP_LOSS_PERCENT", 0.05, cfg) + tp1 = _g("TAKE_PROFIT_1_PERCENT", 0.12, cfg) + tp2 = _g("TAKE_PROFIT_PERCENT", 0.25, cfg) + trail = _g("USE_TRAILING_STOP", True, cfg) + trail_act = _g("TRAILING_STOP_ACTIVATION", 0.10, cfg) + trail_prot = _g("TRAILING_STOP_PROTECT", 0.02, cfg) + profit_prot = _g("PROFIT_PROTECTION_ENABLED", True, cfg) + + c5 = [] + c5.append("止损:ATR 动态止损 " + ("开启" if use_atr else "关闭") + (",倍数 " + str(atr_mult) if use_atr else "") + ";固定止损 " + pct(sl_pct) + "。") + c5.append("止盈:第一目标 " + pct(tp1) + ",第二目标 " + pct(tp2) + "。") + c5.append("盈利保护总开关:" + ("开启" if profit_prot else "关闭") + ";移动止损 " + ("开启" if trail else "关闭") + (",盈利 " + pct(trail_act) + " 激活、保护 " + pct(trail_prot) + " 利润" if trail else "") + "。") + sections.append({ + "title": "五、止损止盈与保护", + "content": "\n".join(c5), + }) + + # ---------- 6. 入场与过滤 ---------- + smart = _g("SMART_ENTRY_ENABLED", True, cfg) + trend_filter = _g("USE_TREND_ENTRY_FILTER", True, cfg) + max_trend = _g("MAX_TREND_MOVE_BEFORE_ENTRY", 0.04, cfg) + max_rsi_long = _g("MAX_RSI_FOR_LONG", 65, cfg) + min_rsi_short = _g("MIN_RSI_FOR_SHORT", 30, cfg) + max_ch_long = _g("MAX_CHANGE_PERCENT_FOR_LONG", 25, cfg) + max_ch_short = _g("MAX_CHANGE_PERCENT_FOR_SHORT", 10, cfg) + + c6 = [] + c6.append("智能入场(限价+追价+市价兜底):" + ("开启" if smart else "关闭") + "。") + c6.append("趋势入场过滤:" + ("开启" if trend_filter else "关闭") + ";信号方向已走超 " + pct(max_trend) + " 则不再入场。") + c6.append("做多:RSI ≤ " + str(max_rsi_long) + ",24h 涨跌幅 ≤ " + str(max_ch_long) + "%。做空:RSI ≥ " + str(min_rsi_short) + ",24h 涨跌幅 ≤ " + str(max_ch_short) + "%。") + sections.append({ + "title": "六、入场与过滤", + "content": "\n".join(c6), + }) + + return {"sections": sections} diff --git a/frontend/src/components/GlobalConfig.jsx b/frontend/src/components/GlobalConfig.jsx index 7570149..71c06d1 100644 --- a/frontend/src/components/GlobalConfig.jsx +++ b/frontend/src/components/GlobalConfig.jsx @@ -1254,53 +1254,71 @@ const GlobalConfig = () => { {marketOverview ? ( -
-
-
BTC 24h
-
= 0 ? '#4caf50' : '#f44336' }}> - {marketOverview.btc_24h_change_pct != null ? `${marketOverview.btc_24h_change_pct}%` : '—'} -
-
-
-
ETH 24h
-
= 0 ? '#4caf50' : '#f44336' }}> - {marketOverview.eth_24h_change_pct != null ? `${marketOverview.eth_24h_change_pct}%` : '—'} -
-
-
-
BTC 15m / 1h
-
- {marketOverview.btc_15m_change_pct != null ? marketOverview.btc_15m_change_pct : '—'}% / {marketOverview.btc_1h_change_pct != null ? marketOverview.btc_1h_change_pct : '—'}% -
-
-
-
ETH 15m / 1h
-
- {marketOverview.eth_15m_change_pct != null ? marketOverview.eth_15m_change_pct : '—'}% / {marketOverview.eth_1h_change_pct != null ? marketOverview.eth_1h_change_pct : '—'}% -
-
-
-
大盘共振过滤
-
- {marketOverview.beta_filter_triggered ? '已触发(屏蔽多单)' : '未触发'} -
- {marketOverview.config && ( -
- 阈值 {marketOverview.config.BETA_FILTER_THRESHOLD_PCT}% · {marketOverview.config.BETA_FILTER_ENABLED ? '已开启' : '已关闭'} + <> +
+
+
BTC 24h
+
= 0 ? '#4caf50' : '#f44336' }}> + {marketOverview.btc_24h_change_pct != null ? `${marketOverview.btc_24h_change_pct}%` : '—'}
- )} -
-
-
市场状态 / 4H
-
- {marketOverview.market_regime || '—'} / {marketOverview.btc_trend_4h || '—'} +
+
+
ETH 24h
+
= 0 ? '#4caf50' : '#f44336' }}> + {marketOverview.eth_24h_change_pct != null ? `${marketOverview.eth_24h_change_pct}%` : '—'} +
+
+
+
BTC 15m / 1h
+
+ {marketOverview.btc_15m_change_pct != null ? marketOverview.btc_15m_change_pct : '—'}% / {marketOverview.btc_1h_change_pct != null ? marketOverview.btc_1h_change_pct : '—'}% +
+
+
+
ETH 15m / 1h
+
+ {marketOverview.eth_15m_change_pct != null ? marketOverview.eth_15m_change_pct : '—'}% / {marketOverview.eth_1h_change_pct != null ? marketOverview.eth_1h_change_pct : '—'}% +
+
+
+
大盘共振过滤
+
+ {marketOverview.beta_filter_triggered ? '已触发(屏蔽多单)' : '未触发'} +
+ {marketOverview.config && ( +
+ 阈值 {marketOverview.config.BETA_FILTER_THRESHOLD_PCT}% · {marketOverview.config.BETA_FILTER_ENABLED ? '已开启' : '已关闭'} +
+ )} +
+
+
市场状态 / 4H
+
+ {marketOverview.market_regime || '—'} / {marketOverview.btc_trend_4h || '—'} +
+
+
+
当前方案
+
{marketOverview.config?.MARKET_SCHEME || '—'}
-
-
当前方案
-
{marketOverview.config?.MARKET_SCHEME || '—'}
-
-
+ + {/* 策略执行概览:当前执行方案与配置项执行情况(易读文字) */} + {marketOverview.strategy_execution_overview?.sections?.length > 0 && ( +
+

策略执行概览

+

+ 以下为当前生效的整体策略执行标准与机制说明(由数据库/Redis 配置生成,刷新市场行情时一并更新)。 +

+ {marketOverview.strategy_execution_overview.sections.map((sec, idx) => ( +
+
{sec.title}
+
{sec.content}
+
+ ))} +
+ )} + ) : (
加载中或拉取失败,请点击刷新
)}