diff --git a/backend/api/routes/account.py b/backend/api/routes/account.py index 2c210b5..636a866 100644 --- a/backend/api/routes/account.py +++ b/backend/api/routes/account.py @@ -785,6 +785,38 @@ async def fetch_realtime_positions(account_id: int): except Exception: entry_order_type = None + symbol_orders = open_orders_map.get(pos.get('symbol'), []) + # 若 DB 未提供止损/止盈,从交易所 open_orders 反填,避免持仓记录显示“无 SL/TP”而实际有挂单 + if symbol_orders and (stop_loss_price is None or take_profit_price is None or take_profit_1 is None): + is_long = position_amt > 0 + sl_prices = [] + tp_prices = [] + for o in symbol_orders: + if not o.get('reduceOnly'): + continue + t = o.get('type') + sp = o.get('stopPrice') + try: + sp = float(sp) if sp is not None else None + except (TypeError, ValueError): + sp = None + if sp is None: + continue + if t == 'STOP_MARKET': + sl_prices.append(sp) + elif t in ('TAKE_PROFIT_MARKET', 'TAKE_PROFIT'): + tp_prices.append(sp) + if sl_prices and stop_loss_price is None: + stop_loss_price = sl_prices[0] + if tp_prices: + tp_prices.sort(key=lambda p: abs(p - entry_price)) + if take_profit_1 is None: + take_profit_1 = tp_prices[0] + if len(tp_prices) > 1 and take_profit_2 is None: + take_profit_2 = tp_prices[1] + if take_profit_price is None: + take_profit_price = take_profit_1 + formatted_positions.append({ "id": id, "symbol": pos.get('symbol'), @@ -808,7 +840,7 @@ async def fetch_realtime_positions(account_id: int): "atr": atr_value, "entry_order_id": entry_order_id, "entry_order_type": entry_order_type, - "open_orders": open_orders_map.get(pos.get('symbol'), []), + "open_orders": symbol_orders, }) return formatted_positions except Exception as e: diff --git a/持仓记录_2026-02-19T09-39-29.json b/持仓记录_2026-02-19T09-39-29.json new file mode 100644 index 0000000..b6f3541 --- /dev/null +++ b/持仓记录_2026-02-19T09-39-29.json @@ -0,0 +1,702 @@ +[ + { + "id": null, + "symbol": "ZECUSDT", + "side": "SELL", + "quantity": 0.112, + "entry_price": 265.8, + "entry_value_usdt": 29.7696, + "notional_usdt": 29.12784, + "margin_usdt": 7.28196, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 260.07, + "pnl": 0.64176, + "pnl_percent": 8.813011881416543, + "leverage": 4, + "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": 2000000479271333, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 239.04, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000479271328, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 273.77, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 273.77 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 239.04 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000479271333, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 239.04, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000479271328, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 273.77, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "HYPEUSDT", + "side": "SELL", + "quantity": 0.96, + "entry_price": 28.503, + "entry_value_usdt": 27.36288, + "notional_usdt": 27.712493712, + "margin_usdt": 6.928123428, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 28.86718095, + "pnl": -0.34961371, + "pnl_percent": -5.046297365128294, + "leverage": 4, + "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": 2000000479340803, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 26.636, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000479340801, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 29.358, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 29.358 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 26.636 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000479340803, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 26.636, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000479340801, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 29.358, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "TAOUSDT", + "side": "SELL", + "quantity": 0.211, + "entry_price": 185.4614691943, + "entry_value_usdt": 39.1323699999973, + "notional_usdt": 38.51799427279, + "margin_usdt": 9.6294985681975, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 182.54973589, + "pnl": 0.61437572, + "pnl_percent": 6.38014238902371, + "leverage": 4, + "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": 2000000480794655, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 170.49, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480794649, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 189.07, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 189.07 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 170.49 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000480794655, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 170.49, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480794649, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 189.07, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "FILUSDT", + "side": "SELL", + "quantity": 60, + "entry_price": 0.933, + "entry_value_usdt": 55.980000000000004, + "notional_usdt": 55.552446, + "margin_usdt": 13.8881115, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 0.9258741, + "pnl": 0.427554, + "pnl_percent": 3.078561113222629, + "leverage": 4, + "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": 2000000479413824, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 0.875, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000479413817, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 0.96, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 0.96 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.875 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000479413824, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 0.875, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000479413817, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 0.96, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "TRUMPUSDT", + "side": "SELL", + "quantity": 7.2, + "entry_price": 3.436, + "entry_value_usdt": 24.7392, + "notional_usdt": 24.624, + "margin_usdt": 6.156, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 3.42, + "pnl": 0.1152, + "pnl_percent": 1.8713450292397662, + "leverage": 4, + "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": 2000000479508471, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 3.19, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000479508466, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 3.539, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 3.539 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 3.19 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000479508471, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 3.19, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000479508466, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 3.539, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "PUMPUSDT", + "side": "SELL", + "quantity": 9729, + "entry_price": 0.002039, + "entry_value_usdt": 19.837431, + "notional_usdt": 19.934721, + "margin_usdt": 4.98368025, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 0.002049, + "pnl": -0.09729, + "pnl_percent": -1.9521717911176184, + "leverage": 4, + "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": 2000000480154344, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 0.001851, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480154340, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 0.0021, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 0.0021 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.001851 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000480154344, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 0.001851, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480154340, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 0.0021, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "NAORISUSDT", + "side": "BUY", + "quantity": 335, + "entry_price": 0.0376422985075, + "entry_value_usdt": 12.610170000012499, + "notional_usdt": 13.52641225, + "margin_usdt": 13.52641225, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 0.04037735, + "pnl": 0.9162451, + "pnl_percent": 6.773748153358257, + "leverage": 1, + "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": 2000000480529814, + "type": "TAKE_PROFIT_MARKET", + "side": "SELL", + "stopPrice": 0.06148, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480529809, + "type": "STOP_MARKET", + "side": "SELL", + "stopPrice": 0.03643, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 0.03643 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.06148 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000480529814, + "type": "TAKE_PROFIT_MARKET", + "side": "SELL", + "stopPrice": 0.06148, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480529809, + "type": "STOP_MARKET", + "side": "SELL", + "stopPrice": 0.03643, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "KITEUSDT", + "side": "BUY", + "quantity": 617, + "entry_price": 0.2258499027553, + "entry_value_usdt": 139.3493900000201, + "notional_usdt": 141.32854537, + "margin_usdt": 35.3321363425, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 0.22905761, + "pnl": 1.97915707, + "pnl_percent": 5.601577699164852, + "leverage": 4, + "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": 2000000480845123, + "type": "TAKE_PROFIT_MARKET", + "side": "SELL", + "stopPrice": 0.26007, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480845117, + "type": "STOP_MARKET", + "side": "SELL", + "stopPrice": 0.22204, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 0.22204 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.26007 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000480845123, + "type": "TAKE_PROFIT_MARKET", + "side": "SELL", + "stopPrice": 0.26007, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480845117, + "type": "STOP_MARKET", + "side": "SELL", + "stopPrice": 0.22204, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "AAVEUSDT", + "side": "SELL", + "quantity": 0.5, + "entry_price": 123.936, + "entry_value_usdt": 61.968, + "notional_usdt": 61.495, + "margin_usdt": 15.37375, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 122.99, + "pnl": 0.473, + "pnl_percent": 3.0766729002357915, + "leverage": 4, + "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": 2000000480581320, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 115.95, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480581308, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 127.69, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 127.69 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 115.95 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000480581320, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 115.95, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480581308, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 127.69, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + }, + { + "id": null, + "symbol": "ASTERUSDT", + "side": "SELL", + "quantity": 84, + "entry_price": 0.69645, + "entry_value_usdt": 58.5018, + "notional_usdt": 58.576746480000004, + "margin_usdt": 14.644186620000001, + "original_notional_usdt": null, + "original_margin_usdt": null, + "mark_price": 0.69734222, + "pnl": -0.07494648, + "pnl_percent": -0.5117831528972961, + "leverage": 4, + "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": 2000000480743935, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 0.6525, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480743932, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 0.7168, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ], + "active_sl_orders": "STOP_MARKET @ 0.7168 (NEW)", + "active_tp_orders": "TAKE_PROFIT_MARKET @ 0.6525 (NEW)", + "binance_open_orders_raw": [ + { + "orderId": 2000000480743935, + "type": "TAKE_PROFIT_MARKET", + "side": "BUY", + "stopPrice": 0.6525, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + }, + { + "orderId": 2000000480743932, + "type": "STOP_MARKET", + "side": "BUY", + "stopPrice": 0.7168, + "price": 0, + "origType": "CONDITIONAL", + "reduceOnly": true, + "status": "NEW" + } + ] + } +] \ No newline at end of file