This commit is contained in:
薇薇安 2026-02-11 09:15:14 +08:00
parent 972156a702
commit 99c40c5752
2 changed files with 87 additions and 750 deletions

View File

@ -2021,20 +2021,52 @@ class PositionManager:
total_pnl = sum(p['unRealizedProfit'] for p in positions)
position_list = []
for p in positions:
symbol = p['symbol']
pos_data = {
'symbol': symbol,
'positionAmt': p['positionAmt'],
'entryPrice': p['entryPrice'],
'pnl': p['unRealizedProfit'],
'leverage': p.get('leverage', 10)
}
# 尝试从内存或数据库补充详细信息
active_pos = self.active_positions.get(symbol)
if active_pos:
pos_data.update({
'entry_time': active_pos.get('entryTime'),
'stop_loss_price': active_pos.get('stopLoss'),
'take_profit_price': active_pos.get('takeProfit'),
'atr': active_pos.get('atr'),
'entry_reason': active_pos.get('entryReason')
})
elif DB_AVAILABLE and Trade:
# 从数据库查询
try:
trades = Trade.get_by_symbol(symbol, status='open', account_id=self.account_id)
if trades:
# 取最新的一个
trade = trades[0]
pos_data.update({
'entry_time': trade.get('entry_time'),
'stop_loss_price': trade.get('stop_loss_price'),
'take_profit_price': trade.get('take_profit_price'),
'atr': trade.get('atr'),
'entry_reason': trade.get('entry_reason')
})
except Exception:
pass
position_list.append(pos_data)
return {
'totalPositions': len(positions),
'totalBalance': balance.get('total', 0),
'availableBalance': balance.get('available', 0),
'totalPnL': total_pnl,
'positions': [
{
'symbol': p['symbol'],
'positionAmt': p['positionAmt'],
'entryPrice': p['entryPrice'],
'pnl': p['unRealizedProfit']
}
for p in positions
]
'positions': position_list
}
except Exception as e:
logger.error(f"获取持仓摘要失败: {e}")
@ -2146,6 +2178,42 @@ class PositionManager:
end_time = int(time.time() * 1000) # 当前时间(毫秒)
start_time = end_time - (7 * 24 * 60 * 60 * 1000) # 最近7天
# 获取入场时间(毫秒)用于过滤
entry_ts_ms = 0
try:
et = trade.get('entry_time')
if et:
if isinstance(et, (int, float)):
# 如果小于 3000000000认为是秒转毫秒
entry_ts_ms = int(et * 1000) if et < 3000000000 else int(et)
elif hasattr(et, 'timestamp'): # datetime object
entry_ts_ms = int(et.timestamp() * 1000)
elif isinstance(et, str):
# 尝试解析字符串
try:
# 先尝试作为数字解析
et_float = float(et)
entry_ts_ms = int(et_float * 1000) if et_float < 3000000000 else int(et_float)
except ValueError:
# 尝试作为日期字符串解析
try:
from datetime import datetime
dt = datetime.strptime(et, "%Y-%m-%d %H:%M:%S")
entry_ts_ms = int(dt.timestamp() * 1000)
except:
pass
except Exception:
pass
# 优化:如果已知入场时间,则仅查询入场之后的订单
if entry_ts_ms > 0:
start_time = max(start_time, entry_ts_ms)
else:
# 如果没有入场时间(如手动录入且未填时间),缩小搜索范围以防止匹配到很久以前的订单
# 限制为最近1小时避免匹配到几天的订单导致"时间倒流"
start_time = end_time - (60 * 60 * 1000)
logger.warning(f"{symbol} [状态同步] ⚠️ 交易记录缺少入场时间将搜索范围限制为最近1小时")
logger.debug(
f"{symbol} [状态同步] 获取历史订单: "
f"symbol={symbol}, startTime={start_time}, endTime={end_time}"
@ -2174,9 +2242,18 @@ class PositionManager:
# 查找最近的平仓订单reduceOnly=True且已成交
close_orders = []
for o in orders:
try:
if isinstance(o, dict) and o.get('reduceOnly') == True and o.get('status') == 'FILLED':
# 再次过滤掉早于入场时间的订单(双重保险)
order_time = int(o.get('updateTime', 0))
if entry_ts_ms > 0 and order_time < entry_ts_ms:
continue
# 如果没有入场时间且订单时间早于1小时前虽然startTime已限制但双重检查则跳过
if entry_ts_ms == 0 and order_time < (end_time - 3600000):
continue
close_orders.append(o)
except (AttributeError, TypeError) as e:
logger.warning(
@ -2640,6 +2717,7 @@ class PositionManager:
'initialStopLoss': stop_loss_price,
'leverage': leverage,
'entryReason': 'manual_entry',
'entryTime': get_beijing_time(), # 补全入场时间
'atr': None,
'maxProfit': 0.0,
'trailingStopActivated': False

View File

@ -1,741 +0,0 @@
[
{
"symbol": "RVVUSDT",
"side": "SELL",
"quantity": 7637,
"entry_price": 0.000887,
"entry_value_usdt": 6.774019,
"notional_usdt": 7.024054380000001,
"margin_usdt": 2.3413514600000003,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.00091974,
"pnl": -0.25003538,
"pnl_percent": -10.679104964446472,
"leverage": 3,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000417435021,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.00125,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.00125 (NEW)",
"active_tp_orders": "",
"binance_open_orders_raw": [
{
"orderId": 2000000417435021,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.00125,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "VIRTUALUSDT",
"side": "SELL",
"quantity": 98.9,
"entry_price": 0.565,
"entry_value_usdt": 55.878499999999995,
"notional_usdt": 54.988400000000006,
"margin_usdt": 6.873550000000001,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.556,
"pnl": 0.8901,
"pnl_percent": 12.949640287769784,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000417274368,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.4822,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000417274350,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.5926,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.5926 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.4822 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000417274368,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.4822,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000417274350,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.5926,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "GIGGLEUSDT",
"side": "SELL",
"quantity": 3.3,
"entry_price": 30.41,
"entry_value_usdt": 100.353,
"notional_usdt": 100.57952256,
"margin_usdt": 12.57244032,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 30.4786432,
"pnl": -0.22652256,
"pnl_percent": -1.8017389960455983,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000416998896,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 25.42,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416998891,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 32.06,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 32.06 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 25.42 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000416998896,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 25.42,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416998891,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 32.06,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "TAOUSDT",
"side": "SELL",
"quantity": 0.409,
"entry_price": 157.94,
"entry_value_usdt": 64.59746,
"notional_usdt": 64.4603372694,
"margin_usdt": 8.057542158675,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 157.6047366,
"pnl": 0.13712273,
"pnl_percent": 1.701793515934253,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000416415747,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 153.21,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416415742,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 161.88,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 161.88 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 153.21 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000416415747,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 153.21,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416415742,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 161.88,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "PUMPUSDT",
"side": "SELL",
"quantity": 24758,
"entry_price": 0.001987,
"entry_value_usdt": 49.194146,
"notional_usdt": 48.78118256,
"margin_usdt": 6.09764782,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.00197032,
"pnl": 0.41296344,
"pnl_percent": 6.7725039587478175,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000416415778,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.001928,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416415771,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.002036,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.002036 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.001928 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000416415778,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.001928,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416415771,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.002036,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "ETHFIUSDT",
"side": "SELL",
"quantity": 129.1,
"entry_price": 0.4374,
"entry_value_usdt": 56.46834,
"notional_usdt": 55.511666397,
"margin_usdt": 6.938958299625,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.42998967,
"pnl": 0.9566736,
"pnl_percent": 13.786991630310002,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000417139079,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.3741,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000417139075,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.4585,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.4585 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.3741 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000417139079,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.3741,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000417139075,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.4585,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "BANANAS31USDT",
"side": "BUY",
"quantity": 3946,
"entry_price": 0.004487,
"entry_value_usdt": 17.705702,
"notional_usdt": 17.771126680000002,
"margin_usdt": 2.2213908350000002,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.00450358,
"pnl": 0.06542468,
"pnl_percent": 2.9452124754084523,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000416416751,
"type": "TAKE_PROFIT_MARKET",
"side": "SELL",
"stopPrice": 0.005503,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416416740,
"type": "STOP_MARKET",
"side": "SELL",
"stopPrice": 0.004149,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.004149 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.005503 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000416416751,
"type": "TAKE_PROFIT_MARKET",
"side": "SELL",
"stopPrice": 0.005503,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416416740,
"type": "STOP_MARKET",
"side": "SELL",
"stopPrice": 0.004149,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "ZILUSDT",
"side": "SELL",
"quantity": 4996,
"entry_price": 0.00424,
"entry_value_usdt": 21.18304,
"notional_usdt": 20.7334,
"margin_usdt": 2.591675,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.00415,
"pnl": 0.44964,
"pnl_percent": 17.349397590361445,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000417092136,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.00342,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000417092132,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.00451,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.00451 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.00342 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000417092136,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.00342,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000417092132,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.00451,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "NEIROUSDT",
"side": "SELL",
"quantity": 682371,
"entry_price": 0.0000752,
"entry_value_usdt": 51.3142992,
"notional_usdt": 50.68651788,
"margin_usdt": 6.335814735,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.00007428,
"pnl": 0.62778132,
"pnl_percent": 9.908454496499731,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000416415930,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.000073,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416415926,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.000077,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.000077 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.000073 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000416415930,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.000073,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416415926,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.000077,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "EIGENUSDT",
"side": "SELL",
"quantity": 265.8,
"entry_price": 0.2025,
"entry_value_usdt": 53.82450000000001,
"notional_usdt": 52.964349936000005,
"margin_usdt": 6.620543742000001,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.19926392,
"pnl": 0.86015006,
"pnl_percent": 12.992136197866994,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000416415985,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.1965,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416415975,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.2075,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.2075 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.1965 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000416415985,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.1965,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416415975,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.2075,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
},
{
"symbol": "ICXUSDT",
"side": "SELL",
"quantity": 704,
"entry_price": 0.0389,
"entry_value_usdt": 27.385599999999997,
"notional_usdt": 27.456,
"margin_usdt": 3.432,
"original_notional_usdt": null,
"original_margin_usdt": null,
"mark_price": 0.039,
"pnl": -0.0704,
"pnl_percent": -2.051282051282051,
"leverage": 8,
"entry_time": null,
"stop_loss_price": null,
"take_profit_price": null,
"take_profit_1": null,
"take_profit_2": null,
"atr": null,
"entry_order_id": null,
"entry_order_type": null,
"open_orders": [
{
"orderId": 2000000416942463,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.0272,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416942454,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.0428,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
],
"active_sl_orders": "STOP_MARKET @ 0.0428 (NEW)",
"active_tp_orders": "TAKE_PROFIT_MARKET @ 0.0272 (NEW)",
"binance_open_orders_raw": [
{
"orderId": 2000000416942463,
"type": "TAKE_PROFIT_MARKET",
"side": "BUY",
"stopPrice": 0.0272,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
},
{
"orderId": 2000000416942454,
"type": "STOP_MARKET",
"side": "BUY",
"stopPrice": 0.0428,
"price": 0,
"origType": "CONDITIONAL",
"reduceOnly": true,
"status": "NEW"
}
]
}
]