diff --git a/frontend/src/components/TradeList.jsx b/frontend/src/components/TradeList.jsx
index 8f669f7..378fb67 100644
--- a/frontend/src/components/TradeList.jsx
+++ b/frontend/src/components/TradeList.jsx
@@ -271,7 +271,7 @@ const TradeList = () => {
平均持仓时长(分钟)
{Number(stats.avg_duration_minutes || 0).toFixed(0)}
- (仅统计“有意义交易”,且需要 duration_minutes 字段)
+ (仅统计“有意义交易”;优先使用 duration_minutes,缺失时用 exit_time-entry_time 计算)
)}
diff --git a/trading_system/atr_strategy.py b/trading_system/atr_strategy.py
index b2e1b89..bdbf085 100644
--- a/trading_system/atr_strategy.py
+++ b/trading_system/atr_strategy.py
@@ -28,6 +28,25 @@ class ATRStrategy:
self.use_dynamic_atr_multiplier = config.TRADING_CONFIG.get('USE_DYNAMIC_ATR_MULTIPLIER', False)
self.atr_multiplier_min = config.TRADING_CONFIG.get('ATR_MULTIPLIER_MIN', 1.5)
self.atr_multiplier_max = config.TRADING_CONFIG.get('ATR_MULTIPLIER_MAX', 2.5)
+
+ def _refresh_from_config(self) -> None:
+ """
+ 动态刷新配置(重要:配置页修改后希望立即生效)。
+ 之前这些参数只在 __init__ 时读取,会导致“改了配置但策略仍按旧值运行”。
+ """
+ try:
+ cfg = getattr(config, "TRADING_CONFIG", {}) or {}
+ self.use_atr = bool(cfg.get('USE_ATR_STOP_LOSS', True))
+ self.atr_sl_multiplier = float(cfg.get('ATR_STOP_LOSS_MULTIPLIER', 1.8))
+ self.atr_tp_multiplier = float(cfg.get('ATR_TAKE_PROFIT_MULTIPLIER', 3.0))
+ self.risk_reward_ratio = float(cfg.get('RISK_REWARD_RATIO', 3.0))
+ self.atr_period = int(cfg.get('ATR_PERIOD', 14))
+ self.use_dynamic_atr_multiplier = bool(cfg.get('USE_DYNAMIC_ATR_MULTIPLIER', False))
+ self.atr_multiplier_min = float(cfg.get('ATR_MULTIPLIER_MIN', 1.5))
+ self.atr_multiplier_max = float(cfg.get('ATR_MULTIPLIER_MAX', 2.5))
+ except Exception:
+ # 刷新失败则继续使用旧值(不影响下单流程)
+ return
def calculate_stop_loss(
self,
@@ -50,6 +69,7 @@ class ATRStrategy:
Returns:
(止损价格, 止损距离, 详细信息字典)
"""
+ self._refresh_from_config()
if not self.use_atr:
return None, None, {}
@@ -137,6 +157,7 @@ class ATRStrategy:
Returns:
(止盈价格, 止盈距离, 详细信息字典)
"""
+ self._refresh_from_config()
if not self.use_atr:
return None, None, {}
diff --git a/trading_system/market_scanner.py b/trading_system/market_scanner.py
index 2bab2c2..68f110f 100644
--- a/trading_system/market_scanner.py
+++ b/trading_system/market_scanner.py
@@ -236,7 +236,8 @@ class MarketScanner:
rsi = TechnicalIndicators.calculate_rsi(close_prices, period=14)
macd = TechnicalIndicators.calculate_macd(close_prices)
bollinger = TechnicalIndicators.calculate_bollinger_bands(close_prices, period=20)
- atr = TechnicalIndicators.calculate_atr(high_prices, low_prices, close_prices, period=14)
+ atr_period = int(config.TRADING_CONFIG.get('ATR_PERIOD', 14) or 14)
+ atr = TechnicalIndicators.calculate_atr(high_prices, low_prices, close_prices, period=atr_period)
ema20 = TechnicalIndicators.calculate_ema(close_prices, period=20)
ema50 = TechnicalIndicators.calculate_ema(close_prices, period=50)
diff --git a/trading_system/strategy.py b/trading_system/strategy.py
index 4fb389f..2e9ccfe 100644
--- a/trading_system/strategy.py
+++ b/trading_system/strategy.py
@@ -138,6 +138,12 @@ class TradingStrategy:
logger.debug(f"✓ {symbol} 自动生成推荐成功 (信号强度: {trade_signal.get('strength', 0)}/10)")
except Exception as e:
logger.warning(f"自动生成推荐失败 {symbol}: {e}")
+
+ # 提升胜率:震荡/未知市场状态不做自动交易(只保留推荐/观察)
+ # 你当前统计里“止损远多于止盈 + 平均持仓很短”高度符合震荡来回扫损特征。
+ if market_regime != 'trending':
+ logger.info(f"{symbol} 市场状态={market_regime},跳过自动交易(仅生成推荐)")
+ continue
# 检查是否应该自动交易(已有持仓则跳过自动交易,但推荐已生成)
if not await self.risk_manager.should_trade(symbol, change_percent):