This commit is contained in:
薇薇安 2026-01-17 11:52:40 +08:00
parent 2e23d66af1
commit bbae52c15f
3 changed files with 24 additions and 18 deletions

View File

@ -357,7 +357,7 @@ const StatsDashboard = () => {
</div> </div>
<div className="trade-info"> <div className="trade-info">
<div>数量: {parseFloat(trade.quantity || 0).toFixed(4)}</div> <div>数量: {parseFloat(trade.quantity || 0).toFixed(4)}</div>
<div>保证金: {margin.toFixed(2)} USDT</div> <div>保证金: {margin >= 0.01 ? margin.toFixed(2) : margin.toFixed(4)} USDT</div>
<div>入场价: {entryPrice.toFixed(4)}</div> <div>入场价: {entryPrice.toFixed(4)}</div>
{trade.mark_price && ( {trade.mark_price && (
@ -384,13 +384,13 @@ const StatsDashboard = () => {
止损: <span className="negative">-{stopLossPercent.toFixed(2)}%</span> 止损: <span className="negative">-{stopLossPercent.toFixed(2)}%</span>
<span className="stop-note">(of margin)</span> <span className="stop-note">(of margin)</span>
<span className="stop-price">(: {stopLossPrice.toFixed(4)})</span> <span className="stop-price">(: {stopLossPrice.toFixed(4)})</span>
<span className="stop-amount">(金额: -{stopLossAmount.toFixed(2)} USDT)</span> <span className="stop-amount">(金额: -{stopLossAmount >= 0.01 ? stopLossAmount.toFixed(2) : stopLossAmount.toFixed(4)} USDT)</span>
</div> </div>
<div className="take-profit-info"> <div className="take-profit-info">
止盈: <span className="positive">+{takeProfitPercent.toFixed(2)}%</span> 止盈: <span className="positive">+{takeProfitPercent.toFixed(2)}%</span>
<span className="take-note">(of margin)</span> <span className="take-note">(of margin)</span>
<span className="take-price">(: {takeProfitPrice.toFixed(4)})</span> <span className="take-price">(: {takeProfitPrice.toFixed(4)})</span>
<span className="take-amount">(金额: +{takeProfitAmount.toFixed(2)} USDT)</span> <span className="take-amount">(金额: +{takeProfitAmount >= 0.01 ? takeProfitAmount.toFixed(2) : takeProfitAmount.toFixed(4)} USDT)</span>
</div> </div>
</div> </div>
<div className="trade-actions"> <div className="trade-actions">

View File

@ -309,7 +309,7 @@ const TradeList = () => {
<td>{trade.symbol}</td> <td>{trade.symbol}</td>
<td className={trade.side === 'BUY' ? 'buy' : 'sell'}>{trade.side}</td> <td className={trade.side === 'BUY' ? 'buy' : 'sell'}>{trade.side}</td>
<td>{parseFloat(trade.quantity).toFixed(4)}</td> <td>{parseFloat(trade.quantity).toFixed(4)}</td>
<td>{margin.toFixed(2)} USDT</td> <td>{margin >= 0.01 ? margin.toFixed(2) : margin.toFixed(4)} USDT</td>
<td>{parseFloat(trade.entry_price).toFixed(4)}</td> <td>{parseFloat(trade.entry_price).toFixed(4)}</td>
<td>{trade.exit_price ? parseFloat(trade.exit_price).toFixed(4) : '-'}</td> <td>{trade.exit_price ? parseFloat(trade.exit_price).toFixed(4) : '-'}</td>
<td className={pnl >= 0 ? 'positive' : 'negative'}> <td className={pnl >= 0 ? 'positive' : 'negative'}>
@ -377,7 +377,7 @@ const TradeList = () => {
</div> </div>
<div className="trade-card-field"> <div className="trade-card-field">
<span className="trade-card-label">保证金</span> <span className="trade-card-label">保证金</span>
<span className="trade-card-value">{margin.toFixed(2)} USDT</span> <span className="trade-card-value">{margin >= 0.01 ? margin.toFixed(2) : margin.toFixed(4)} USDT</span>
</div> </div>
<div className="trade-card-field"> <div className="trade-card-field">
<span className="trade-card-label">入场价</span> <span className="trade-card-label">入场价</span>

View File

@ -6,6 +6,7 @@ import logging
import json import json
import aiohttp import aiohttp
from typing import Dict, List, Optional from typing import Dict, List, Optional
from datetime import datetime
try: try:
from .binance_client import BinanceClient from .binance_client import BinanceClient
from .risk_manager import RiskManager from .risk_manager import RiskManager
@ -20,6 +21,7 @@ logger = logging.getLogger(__name__)
# 尝试导入数据库模型(如果可用) # 尝试导入数据库模型(如果可用)
DB_AVAILABLE = False DB_AVAILABLE = False
Trade = None Trade = None
get_beijing_time = None
try: try:
import sys import sys
from pathlib import Path from pathlib import Path
@ -27,7 +29,7 @@ try:
backend_path = project_root / 'backend' backend_path = project_root / 'backend'
if backend_path.exists(): if backend_path.exists():
sys.path.insert(0, str(backend_path)) sys.path.insert(0, str(backend_path))
from database.models import Trade from database.models import Trade, get_beijing_time
DB_AVAILABLE = True DB_AVAILABLE = True
logger.info("✓ 数据库模型导入成功,交易记录将保存到数据库") logger.info("✓ 数据库模型导入成功,交易记录将保存到数据库")
else: else:
@ -42,6 +44,14 @@ except Exception as e:
logger.warning(" 交易记录将不会保存到数据库") logger.warning(" 交易记录将不会保存到数据库")
DB_AVAILABLE = False DB_AVAILABLE = False
# 如果没有导入get_beijing_time创建一个本地版本
if get_beijing_time is None:
from datetime import datetime, timezone, timedelta
BEIJING_TZ = timezone(timedelta(hours=8))
def get_beijing_time():
"""获取当前北京时间UTC+8"""
return datetime.now(BEIJING_TZ).replace(tzinfo=None)
class PositionManager: class PositionManager:
"""仓位管理类""" """仓位管理类"""
@ -334,7 +344,7 @@ class PositionManager:
'initialStopLoss': stop_loss_price, # 初始止损(用于移动止损) 'initialStopLoss': stop_loss_price, # 初始止损(用于移动止损)
'leverage': leverage, 'leverage': leverage,
'entryReason': entry_reason, 'entryReason': entry_reason,
'entryTime': datetime.now(), # 记录入场时间(用于计算持仓持续时间) 'entryTime': get_beijing_time(), # 记录入场时间(使用北京时间,用于计算持仓持续时间)
'strategyType': 'trend_following', # 策略类型(简化后只有趋势跟踪) 'strategyType': 'trend_following', # 策略类型(简化后只有趋势跟踪)
'atr': atr, 'atr': atr,
'maxProfit': 0.0, # 记录最大盈利(用于移动止损) 'maxProfit': 0.0, # 记录最大盈利(用于移动止损)
@ -446,12 +456,11 @@ class PositionManager:
duration_minutes = None duration_minutes = None
if entry_time: if entry_time:
try: try:
from datetime import datetime
if isinstance(entry_time, str): if isinstance(entry_time, str):
entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S') entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S')
else: else:
entry_dt = entry_time entry_dt = entry_time
exit_dt = datetime.now() exit_dt = get_beijing_time() # 使用北京时间计算持续时间
duration = exit_dt - entry_dt duration = exit_dt - entry_dt
duration_minutes = int(duration.total_seconds() / 60) duration_minutes = int(duration.total_seconds() / 60)
except Exception as e: except Exception as e:
@ -590,12 +599,11 @@ class PositionManager:
duration_minutes = None duration_minutes = None
if entry_time: if entry_time:
try: try:
from datetime import datetime
if isinstance(entry_time, str): if isinstance(entry_time, str):
entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S') entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S')
else: else:
entry_dt = entry_time entry_dt = entry_time
exit_dt = datetime.now() exit_dt = get_beijing_time() # 使用北京时间计算持续时间
duration = exit_dt - entry_dt duration = exit_dt - entry_dt
duration_minutes = int(duration.total_seconds() / 60) duration_minutes = int(duration.total_seconds() / 60)
except Exception as e: except Exception as e:
@ -848,12 +856,11 @@ class PositionManager:
duration_minutes = None duration_minutes = None
if entry_time: if entry_time:
try: try:
from datetime import datetime
if isinstance(entry_time, str): if isinstance(entry_time, str):
entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S') entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S')
else: else:
entry_dt = entry_time entry_dt = entry_time
exit_dt = datetime.now() exit_dt = get_beijing_time() # 使用北京时间计算持续时间
duration = exit_dt - entry_dt duration = exit_dt - entry_dt
duration_minutes = int(duration.total_seconds() / 60) duration_minutes = int(duration.total_seconds() / 60)
except Exception as e: except Exception as e:
@ -964,12 +971,11 @@ class PositionManager:
duration_minutes = None duration_minutes = None
if entry_time: if entry_time:
try: try:
from datetime import datetime
if isinstance(entry_time, str): if isinstance(entry_time, str):
entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S') entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S')
else: else:
entry_dt = entry_time entry_dt = entry_time
exit_dt = datetime.now() exit_dt = get_beijing_time() # 使用北京时间计算持续时间
duration = exit_dt - entry_dt duration = exit_dt - entry_dt
duration_minutes = int(duration.total_seconds() / 60) duration_minutes = int(duration.total_seconds() / 60)
except Exception as e: except Exception as e:
@ -1026,7 +1032,7 @@ class PositionManager:
entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S') entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S')
else: else:
entry_dt = entry_time entry_dt = entry_time
exit_dt = datetime.now() exit_dt = get_beijing_time() # 使用北京时间计算持续时间
duration = exit_dt - entry_dt duration = exit_dt - entry_dt
duration_minutes = int(duration.total_seconds() / 60) duration_minutes = int(duration.total_seconds() / 60)
except Exception as e: except Exception as e:
@ -1313,7 +1319,7 @@ class PositionManager:
entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S') entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S')
else: else:
entry_dt = entry_time entry_dt = entry_time
exit_dt = datetime.now() exit_dt = get_beijing_time() # 使用北京时间计算持续时间
duration = exit_dt - entry_dt duration = exit_dt - entry_dt
duration_minutes = int(duration.total_seconds() / 60) duration_minutes = int(duration.total_seconds() / 60)
except Exception as e: except Exception as e:
@ -1909,7 +1915,7 @@ class PositionManager:
entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S') entry_dt = datetime.strptime(entry_time, '%Y-%m-%d %H:%M:%S')
else: else:
entry_dt = entry_time entry_dt = entry_time
exit_dt = datetime.now() exit_dt = get_beijing_time() # 使用北京时间计算持续时间
duration = exit_dt - entry_dt duration = exit_dt - entry_dt
duration_minutes = int(duration.total_seconds() / 60) duration_minutes = int(duration.total_seconds() / 60)
except Exception as e: except Exception as e: