From bec62631cb7dcf075e6c025cae6c842571e06da0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Mon, 19 Jan 2026 00:12:29 +0800 Subject: [PATCH] a --- frontend/src/components/Recommendations.jsx | 20 ++++++-- trading_system/trade_recommender.py | 52 ++++++++++++--------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/frontend/src/components/Recommendations.jsx b/frontend/src/components/Recommendations.jsx index 25724c5..f2b2649 100644 --- a/frontend/src/components/Recommendations.jsx +++ b/frontend/src/components/Recommendations.jsx @@ -223,6 +223,16 @@ function Recommendations() { } } + const fmtPrice = (v) => { + const n = Number(v || 0) + if (!isFinite(n)) return '-' + // 低价币用更多小数位,避免“挂单价=止损价”只是显示精度导致的误解 + if (Math.abs(n) >= 100) return n.toFixed(2) + if (Math.abs(n) >= 1) return n.toFixed(4) + if (Math.abs(n) >= 0.01) return n.toFixed(6) + return n.toFixed(8) + } + const getStatusBadge = (status) => { const statusMap = { active: { text: '有效', class: 'status-active' }, @@ -356,7 +366,7 @@ function Recommendations() {
- {parseFloat(rec.current_price || 0).toFixed(4)} USDT + {fmtPrice(rec.current_price)} USDT {rec.current_price_source === 'mark_price' && ( - {parseFloat(rec.suggested_limit_price || 0).toFixed(4)} USDT + {fmtPrice(rec.suggested_limit_price)} USDT {rec.current_price && ( ({rec.direction === 'BUY' ? '低于' : '高于'}当前价 @@ -430,15 +440,15 @@ function Recommendations() { )}
- {parseFloat(rec.suggested_stop_loss || 0).toFixed(4)} + {fmtPrice(rec.suggested_stop_loss)}
- {parseFloat(rec.suggested_take_profit_1 || 0).toFixed(4)} + {fmtPrice(rec.suggested_take_profit_1)}
- {parseFloat(rec.suggested_take_profit_2 || 0).toFixed(4)} + {fmtPrice(rec.suggested_take_profit_2)}
diff --git a/trading_system/trade_recommender.py b/trading_system/trade_recommender.py index 278c047..e0242b1 100644 --- a/trading_system/trade_recommender.py +++ b/trading_system/trade_recommender.py @@ -331,18 +331,23 @@ class TradeRecommender: signal_strength += 2 reasons.append("4H周期共振确认") - # 判断是否应该交易(使用传入的参数,如果没有则使用config中的值) + # 推荐系统:默认不再输出“逆4H趋势”的推荐(用户反馈方向不对的主要来源) + # 如果未来需要放开,可做成配置项 ALLOW_COUNTER_TREND_RECOMMENDATIONS。 + if direction and trend_4h and trend_4h in ("up", "down"): + if (direction == 'BUY' and trend_4h == 'down') or (direction == 'SELL' and trend_4h == 'up'): + reasons.append("❌ 逆4H趋势,跳过推荐") + return { + 'should_trade': False, + 'direction': direction, + 'reason': ', '.join(reasons) if reasons else '逆趋势', + 'strength': max(0, signal_strength - 2), + 'trend_4h': trend_4h + } + + # 判断是否应该推荐(使用传入的参数,如果没有则使用config中的值) if min_signal_strength is None: min_signal_strength = config.TRADING_CONFIG.get('MIN_SIGNAL_STRENGTH', 7) - should_trade = signal_strength >= min_signal_strength - - # 对于推荐系统,允许逆4H趋势交易(但降低信号强度,标记为高风险) - if direction and trend_4h: - if (direction == 'BUY' and trend_4h == 'down') or (direction == 'SELL' and trend_4h == 'up'): - # 推荐系统允许逆趋势,但降低信号强度(减2分) - signal_strength = max(0, signal_strength - 2) - reasons.append("⚠️ 逆4H趋势(高风险)") - # 不禁止,但标记为高风险 + should_trade = (direction is not None) and (signal_strength >= min_signal_strength) return { 'should_trade': should_trade, @@ -395,10 +400,20 @@ class TradeRecommender: price_ts_ms = None direction = trade_signal['direction'] + if not direction: + return None - # 计算建议的止损止盈(基于保证金) - entry_price = current_price - + # 先计算建议挂单价(限价单),然后用“挂单价”作为止损/止盈的基准入场价 + # 否则会出现:止损按 current_price 算、但挂单按回调价算 → 止损/挂单价不匹配,甚至相等 + limit_price_offset_pct = config.TRADING_CONFIG.get('LIMIT_ORDER_OFFSET_PCT', 0.5) # 默认0.5% + if direction == 'BUY': + suggested_limit_price = current_price * (1 - limit_price_offset_pct / 100) + else: # SELL + suggested_limit_price = current_price * (1 + limit_price_offset_pct / 100) + + # 计算建议的止损止盈(基于保证金),以“计划入场价=挂单价”为基准 + entry_price = suggested_limit_price + # 估算仓位数量和杠杆(用于计算止损止盈) # 重要语义:suggested_position_pct 表示“保证金占用比例” account_balance = symbol_info.get('account_balance', 1000) @@ -453,15 +468,6 @@ class TradeRecommender: position_multiplier = min(1.0 + (signal_strength - 5) * 0.1, 1.5) suggested_position_pct = base_position_pct * position_multiplier - # 计算建议的挂单价(使用限价单,而不是市价单) - # 对于做多:建议价格略低于当前价格(当前价格的99.5%),以便在回调时买入 - # 对于做空:建议价格略高于当前价格(当前价格的100.5%),以便在反弹时卖出 - limit_price_offset_pct = config.TRADING_CONFIG.get('LIMIT_ORDER_OFFSET_PCT', 0.5) # 默认0.5% - if direction == 'BUY': - suggested_limit_price = current_price * (1 - limit_price_offset_pct / 100) - else: # SELL - suggested_limit_price = current_price * (1 + limit_price_offset_pct / 100) - # 添加时间戳 timestamp = time.time() recommendation_time = datetime.now().isoformat() @@ -533,6 +539,8 @@ class TradeRecommender: 'suggested_stop_loss': stop_loss_price, 'suggested_take_profit_1': take_profit_1, 'suggested_take_profit_2': take_profit_2, + # 计划入场价(限价挂单价)作为止损/止盈计算基准 + 'planned_entry_price': entry_price, 'suggested_position_percent': suggested_position_pct, 'suggested_leverage': config.TRADING_CONFIG.get('LEVERAGE', 10), 'volume_24h': symbol_info.get('volume24h'),