a
This commit is contained in:
parent
bb795604a3
commit
db2bd6a3b2
|
|
@ -55,6 +55,54 @@ async def get_recommendations(
|
|||
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 {
|
||||
"success": True,
|
||||
"count": len(recommendations),
|
||||
|
|
@ -69,9 +117,58 @@ async def get_recommendations(
|
|||
async def get_active_recommendations():
|
||||
"""
|
||||
获取当前有效的推荐(未过期、未执行、未取消)
|
||||
使用WebSocket实时价格更新推荐中的价格信息
|
||||
"""
|
||||
try:
|
||||
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 {
|
||||
"success": True,
|
||||
"count": len(recommendations),
|
||||
|
|
|
|||
|
|
@ -13,6 +13,18 @@ function Recommendations() {
|
|||
|
||||
useEffect(() => {
|
||||
loadRecommendations()
|
||||
|
||||
// 如果是查看有效推荐,每10秒自动刷新一次(获取实时价格)
|
||||
let interval = null
|
||||
if (statusFilter === 'active') {
|
||||
interval = setInterval(loadRecommendations, 10000) // 每10秒刷新
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (interval) {
|
||||
clearInterval(interval)
|
||||
}
|
||||
}
|
||||
}, [statusFilter, directionFilter])
|
||||
|
||||
const loadRecommendations = async () => {
|
||||
|
|
@ -208,9 +220,14 @@ function Recommendations() {
|
|||
<div className="price-info">
|
||||
<div className="price-item">
|
||||
<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>
|
||||
{rec.change_percent && (
|
||||
{rec.change_percent !== undefined && rec.change_percent !== null && (
|
||||
<div className="price-item">
|
||||
<label>24h涨跌:</label>
|
||||
<span className={rec.change_percent >= 0 ? 'positive' : 'negative'}>
|
||||
|
|
|
|||
|
|
@ -533,8 +533,10 @@ class PositionManager:
|
|||
)
|
||||
|
||||
# 检查止损(使用更新后的止损价)
|
||||
stop_loss = position_info['stopLoss']
|
||||
if position_info['side'] == 'BUY' and current_price <= stop_loss:
|
||||
stop_loss = position_info.get('stopLoss')
|
||||
if stop_loss is None:
|
||||
logger.warning(f"{symbol} 止损价未设置,跳过止损检查")
|
||||
elif position_info['side'] == 'BUY' and current_price <= stop_loss:
|
||||
logger.warning(
|
||||
f"{symbol} 触发止损: {current_price:.4f} <= {stop_loss:.4f} "
|
||||
f"(盈亏: {pnl_percent:.2f}%)"
|
||||
|
|
@ -559,7 +561,7 @@ class PositionManager:
|
|||
closed_positions.append(symbol)
|
||||
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(
|
||||
f"{symbol} 触发止损: {current_price:.4f} >= {stop_loss:.4f} "
|
||||
f"(盈亏: {pnl_percent:.2f}%)"
|
||||
|
|
@ -591,7 +593,7 @@ class PositionManager:
|
|||
remaining_quantity = position_info.get('remainingQuantity', quantity)
|
||||
|
||||
# 第一目标:盈亏比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:
|
||||
logger.info(
|
||||
f"{symbol} 触发第一目标止盈(盈亏比1:1): {current_price:.4f} >= {take_profit_1:.4f} "
|
||||
|
|
@ -620,7 +622,7 @@ class PositionManager:
|
|||
logger.info(f"{symbol} 剩余仓位止损移至成本价,配合移动止损博取更大利润")
|
||||
except Exception as 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(
|
||||
f"{symbol} 触发第一目标止盈(盈亏比1:1): {current_price:.4f} <= {take_profit_1:.4f} "
|
||||
f"(盈亏: {pnl_percent:.2f}%)"
|
||||
|
|
@ -649,7 +651,7 @@ class PositionManager:
|
|||
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:
|
||||
logger.info(
|
||||
f"{symbol} 触发第二目标止盈: {current_price:.4f} >= {take_profit_2:.4f} "
|
||||
|
|
@ -673,7 +675,7 @@ class PositionManager:
|
|||
if await self.close_position(symbol, reason=exit_reason):
|
||||
closed_positions.append(symbol)
|
||||
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(
|
||||
f"{symbol} 触发第二目标止盈: {current_price:.4f} <= {take_profit_2:.4f} "
|
||||
f"(盈亏: {pnl_percent:.2f}%)"
|
||||
|
|
@ -699,7 +701,7 @@ class PositionManager:
|
|||
else:
|
||||
# 如果未部分止盈,但达到第二目标,直接全部平仓
|
||||
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(
|
||||
f"{symbol} 触发止盈: {current_price:.4f} >= {take_profit:.4f} "
|
||||
f"(盈亏: {pnl_percent:.2f}%)"
|
||||
|
|
@ -723,7 +725,7 @@ class PositionManager:
|
|||
closed_positions.append(symbol)
|
||||
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(
|
||||
f"{symbol} 触发止盈: {current_price:.4f} <= {take_profit:.4f} "
|
||||
f"(盈亏: {pnl_percent:.2f}%)"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user