This commit is contained in:
薇薇安 2026-01-15 16:51:31 +08:00
parent bb795604a3
commit db2bd6a3b2
3 changed files with 127 additions and 11 deletions

View File

@ -55,6 +55,54 @@ async def get_recommendations(
end_date=end_dt end_date=end_dt
) )
# 如果是获取有效推荐,尝试更新实时价格
if status == 'active' or (status is None and len(recommendations) > 0):
try:
import sys
from pathlib import Path
current_file = Path(__file__)
backend_path = current_file.parent.parent.parent
project_root = backend_path.parent
trading_system_path = project_root / 'trading_system'
if trading_system_path.exists():
sys.path.insert(0, str(trading_system_path))
from binance_client import BinanceClient
import config
# 创建客户端实例(不需要连接,只需要访问价格缓存)
client = BinanceClient(
api_key=config.BINANCE_API_KEY,
api_secret=config.BINANCE_API_SECRET,
testnet=config.USE_TESTNET
)
# 更新推荐中的实时价格和涨跌幅
for rec in recommendations:
symbol = rec.get('symbol')
if symbol:
# 尝试从WebSocket缓存获取实时价格
realtime_price = client.get_realtime_price(symbol)
if realtime_price is not None:
# 更新价格
old_price = rec.get('current_price', 0)
rec['current_price'] = realtime_price
# 计算新的涨跌幅
if old_price > 0:
change_percent = ((realtime_price - old_price) / old_price) * 100
rec['change_percent'] = round(change_percent, 4)
rec['price_updated'] = True # 标记价格已更新
else:
rec['price_updated'] = False
else:
rec['price_updated'] = False
else:
rec['price_updated'] = False
except Exception as price_update_error:
# 如果价格更新失败,不影响返回推荐列表
logger.debug(f"更新推荐实时价格失败(不影响返回): {price_update_error}")
return { return {
"success": True, "success": True,
"count": len(recommendations), "count": len(recommendations),
@ -69,9 +117,58 @@ async def get_recommendations(
async def get_active_recommendations(): async def get_active_recommendations():
""" """
获取当前有效的推荐未过期未执行未取消 获取当前有效的推荐未过期未执行未取消
使用WebSocket实时价格更新推荐中的价格信息
""" """
try: try:
recommendations = TradeRecommendation.get_active() recommendations = TradeRecommendation.get_active()
# 尝试从WebSocket缓存获取实时价格更新推荐中的价格
try:
import sys
from pathlib import Path
current_file = Path(__file__)
backend_path = current_file.parent.parent.parent
project_root = backend_path.parent
trading_system_path = project_root / 'trading_system'
if trading_system_path.exists():
sys.path.insert(0, str(trading_system_path))
from binance_client import BinanceClient
import config
# 创建客户端实例(不需要连接,只需要访问价格缓存)
client = BinanceClient(
api_key=config.BINANCE_API_KEY,
api_secret=config.BINANCE_API_SECRET,
testnet=config.USE_TESTNET
)
# 更新推荐中的实时价格和涨跌幅
for rec in recommendations:
symbol = rec.get('symbol')
if symbol:
# 尝试从WebSocket缓存获取实时价格
realtime_price = client.get_realtime_price(symbol)
if realtime_price is not None:
# 更新价格
old_price = rec.get('current_price', 0)
rec['current_price'] = realtime_price
# 计算新的涨跌幅
if old_price > 0:
change_percent = ((realtime_price - old_price) / old_price) * 100
rec['change_percent'] = round(change_percent, 4)
rec['price_updated'] = True # 标记价格已更新
else:
rec['price_updated'] = False
else:
rec['price_updated'] = False
else:
rec['price_updated'] = False
except Exception as price_update_error:
# 如果价格更新失败,不影响返回推荐列表
logger.debug(f"更新推荐实时价格失败(不影响返回): {price_update_error}")
return { return {
"success": True, "success": True,
"count": len(recommendations), "count": len(recommendations),

View File

@ -13,6 +13,18 @@ function Recommendations() {
useEffect(() => { useEffect(() => {
loadRecommendations() loadRecommendations()
// 10
let interval = null
if (statusFilter === 'active') {
interval = setInterval(loadRecommendations, 10000) // 10
}
return () => {
if (interval) {
clearInterval(interval)
}
}
}, [statusFilter, directionFilter]) }, [statusFilter, directionFilter])
const loadRecommendations = async () => { const loadRecommendations = async () => {
@ -208,9 +220,14 @@ function Recommendations() {
<div className="price-info"> <div className="price-info">
<div className="price-item"> <div className="price-item">
<label>当前价格:</label> <label>当前价格:</label>
<span>{parseFloat(rec.current_price || 0).toFixed(4)} USDT</span> <span>
{parseFloat(rec.current_price || 0).toFixed(4)} USDT
{rec.price_updated && (
<span className="price-updated-badge" title="价格已通过WebSocket实时更新">🟢</span>
)}
</span>
</div> </div>
{rec.change_percent && ( {rec.change_percent !== undefined && rec.change_percent !== null && (
<div className="price-item"> <div className="price-item">
<label>24h涨跌:</label> <label>24h涨跌:</label>
<span className={rec.change_percent >= 0 ? 'positive' : 'negative'}> <span className={rec.change_percent >= 0 ? 'positive' : 'negative'}>

View File

@ -533,8 +533,10 @@ class PositionManager:
) )
# 检查止损(使用更新后的止损价) # 检查止损(使用更新后的止损价)
stop_loss = position_info['stopLoss'] stop_loss = position_info.get('stopLoss')
if position_info['side'] == 'BUY' and current_price <= stop_loss: if stop_loss is None:
logger.warning(f"{symbol} 止损价未设置,跳过止损检查")
elif position_info['side'] == 'BUY' and current_price <= stop_loss:
logger.warning( logger.warning(
f"{symbol} 触发止损: {current_price:.4f} <= {stop_loss:.4f} " f"{symbol} 触发止损: {current_price:.4f} <= {stop_loss:.4f} "
f"(盈亏: {pnl_percent:.2f}%)" f"(盈亏: {pnl_percent:.2f}%)"
@ -559,7 +561,7 @@ class PositionManager:
closed_positions.append(symbol) closed_positions.append(symbol)
continue continue
if position_info['side'] == 'SELL' and current_price >= stop_loss: if stop_loss is not None and position_info['side'] == 'SELL' and current_price >= stop_loss:
logger.warning( logger.warning(
f"{symbol} 触发止损: {current_price:.4f} >= {stop_loss:.4f} " f"{symbol} 触发止损: {current_price:.4f} >= {stop_loss:.4f} "
f"(盈亏: {pnl_percent:.2f}%)" f"(盈亏: {pnl_percent:.2f}%)"
@ -591,7 +593,7 @@ class PositionManager:
remaining_quantity = position_info.get('remainingQuantity', quantity) remaining_quantity = position_info.get('remainingQuantity', quantity)
# 第一目标盈亏比1:1了结50%仓位 # 第一目标盈亏比1:1了结50%仓位
if not partial_profit_taken: if not partial_profit_taken and take_profit_1 is not None:
if position_info['side'] == 'BUY' and current_price >= take_profit_1: if position_info['side'] == 'BUY' and current_price >= take_profit_1:
logger.info( logger.info(
f"{symbol} 触发第一目标止盈盈亏比1:1: {current_price:.4f} >= {take_profit_1:.4f} " f"{symbol} 触发第一目标止盈盈亏比1:1: {current_price:.4f} >= {take_profit_1:.4f} "
@ -620,7 +622,7 @@ class PositionManager:
logger.info(f"{symbol} 剩余仓位止损移至成本价,配合移动止损博取更大利润") logger.info(f"{symbol} 剩余仓位止损移至成本价,配合移动止损博取更大利润")
except Exception as e: except Exception as e:
logger.error(f"{symbol} 部分止盈失败: {e}") logger.error(f"{symbol} 部分止盈失败: {e}")
elif position_info['side'] == 'SELL' and current_price <= take_profit_1: elif take_profit_1 is not None and position_info['side'] == 'SELL' and current_price <= take_profit_1:
logger.info( logger.info(
f"{symbol} 触发第一目标止盈盈亏比1:1: {current_price:.4f} <= {take_profit_1:.4f} " f"{symbol} 触发第一目标止盈盈亏比1:1: {current_price:.4f} <= {take_profit_1:.4f} "
f"(盈亏: {pnl_percent:.2f}%)" f"(盈亏: {pnl_percent:.2f}%)"
@ -649,7 +651,7 @@ class PositionManager:
logger.error(f"{symbol} 部分止盈失败: {e}") logger.error(f"{symbol} 部分止盈失败: {e}")
# 第二目标:原始止盈价,平掉剩余仓位 # 第二目标:原始止盈价,平掉剩余仓位
if partial_profit_taken: if partial_profit_taken and take_profit_2 is not None:
if position_info['side'] == 'BUY' and current_price >= take_profit_2: if position_info['side'] == 'BUY' and current_price >= take_profit_2:
logger.info( logger.info(
f"{symbol} 触发第二目标止盈: {current_price:.4f} >= {take_profit_2:.4f} " f"{symbol} 触发第二目标止盈: {current_price:.4f} >= {take_profit_2:.4f} "
@ -673,7 +675,7 @@ class PositionManager:
if await self.close_position(symbol, reason=exit_reason): if await self.close_position(symbol, reason=exit_reason):
closed_positions.append(symbol) closed_positions.append(symbol)
continue continue
elif position_info['side'] == 'SELL' and current_price <= take_profit_2: elif take_profit_2 is not None and position_info['side'] == 'SELL' and current_price <= take_profit_2:
logger.info( logger.info(
f"{symbol} 触发第二目标止盈: {current_price:.4f} <= {take_profit_2:.4f} " f"{symbol} 触发第二目标止盈: {current_price:.4f} <= {take_profit_2:.4f} "
f"(盈亏: {pnl_percent:.2f}%)" f"(盈亏: {pnl_percent:.2f}%)"
@ -699,7 +701,7 @@ class PositionManager:
else: else:
# 如果未部分止盈,但达到第二目标,直接全部平仓 # 如果未部分止盈,但达到第二目标,直接全部平仓
take_profit = position_info.get('takeProfit') take_profit = position_info.get('takeProfit')
if position_info['side'] == 'BUY' and current_price >= take_profit: if take_profit is not None and position_info['side'] == 'BUY' and current_price >= take_profit:
logger.info( logger.info(
f"{symbol} 触发止盈: {current_price:.4f} >= {take_profit:.4f} " f"{symbol} 触发止盈: {current_price:.4f} >= {take_profit:.4f} "
f"(盈亏: {pnl_percent:.2f}%)" f"(盈亏: {pnl_percent:.2f}%)"
@ -723,7 +725,7 @@ class PositionManager:
closed_positions.append(symbol) closed_positions.append(symbol)
continue continue
if position_info['side'] == 'SELL' and current_price <= take_profit: if take_profit is not None and position_info['side'] == 'SELL' and current_price <= take_profit:
logger.info( logger.info(
f"{symbol} 触发止盈: {current_price:.4f} <= {take_profit:.4f} " f"{symbol} 触发止盈: {current_price:.4f} <= {take_profit:.4f} "
f"(盈亏: {pnl_percent:.2f}%)" f"(盈亏: {pnl_percent:.2f}%)"