From 7cdb24bf47dbf5837ee946c288ea28e0d035d68d Mon Sep 17 00:00:00 2001 From: aaron <> Date: Wed, 25 Feb 2026 21:29:39 +0800 Subject: [PATCH] update --- backend/app/api/paper_trading.py | 29 +++++++++++ backend/app/services/paper_trading_service.py | 49 +++++++++++++++++++ frontend/paper-trading.html | 28 +++++++++++ 3 files changed, 106 insertions(+) diff --git a/backend/app/api/paper_trading.py b/backend/app/api/paper_trading.py index 242f95c..b93f45d 100644 --- a/backend/app/api/paper_trading.py +++ b/backend/app/api/paper_trading.py @@ -129,6 +129,35 @@ async def close_order(order_id: str, request: CloseOrderRequest): raise HTTPException(status_code=500, detail=str(e)) +@router.delete("/orders/{order_id}") +async def delete_order(order_id: str): + """ + 删除订单(不产生盈亏,仅删除记录) + + 注意:此操作会直接删除订单记录,不会产生任何盈亏计算, + 也不会影响收益率等统计指标。主要用于删除错误订单或测试数据。 + + - order_id: 订单ID + """ + try: + service = get_paper_trading_service() + result = service.delete_order(order_id) + + if not result: + raise HTTPException(status_code=404, detail="订单不存在") + + return { + "success": True, + "message": "订单已删除", + "result": result + } + except HTTPException: + raise + except Exception as e: + logger.error(f"删除订单失败: {e}") + raise HTTPException(status_code=500, detail=str(e)) + + @router.get("/statistics") async def get_statistics( symbol: Optional[str] = Query(None, description="交易对筛选"), diff --git a/backend/app/services/paper_trading_service.py b/backend/app/services/paper_trading_service.py index 2b72ae3..86b60f8 100644 --- a/backend/app/services/paper_trading_service.py +++ b/backend/app/services/paper_trading_service.py @@ -880,6 +880,55 @@ class PaperTradingService: return self._close_order(order, OrderStatus.CLOSED_MANUAL, exit_price) + def delete_order(self, order_id: str) -> Optional[Dict[str, Any]]: + """ + 删除订单(不产生盈亏,仅删除记录) + + 注意:此操作会直接从数据库中删除订单记录,不会产生任何盈亏计算, + 也不会影响收益率等统计指标。主要用于删除错误订单或测试数据。 + + Args: + order_id: 订单ID + + Returns: + 删除结果字典 + """ + if order_id not in self.active_orders: + logger.warning(f"订单不存在或已删除: {order_id}") + return None + + order = self.active_orders[order_id] + symbol = order.symbol + side = order.side.value + status = order.status.value + + db = db_service.get_session() + try: + # 从数据库中彻底删除订单 + db_order = db.query(PaperOrder).filter(PaperOrder.order_id == order_id).first() + if db_order: + db.delete(db_order) + db.commit() + logger.info(f"订单已从数据库删除: {order_id} | {symbol} {side} | 原状态: {status}") + + # 从活跃订单缓存中移除 + if order_id in self.active_orders: + del self.active_orders[order_id] + + return { + 'order_id': order_id, + 'symbol': symbol, + 'side': side, + 'status': status, + 'message': '订单已删除(不影响收益率)' + } + except Exception as e: + logger.error(f"删除订单失败: {e}") + db.rollback() + return None + finally: + db.close() + def _cancel_pending_order(self, order: PaperOrder) -> Dict[str, Any]: """取消挂单""" db = db_service.get_session() diff --git a/frontend/paper-trading.html b/frontend/paper-trading.html index 773ae74..5ea5fdd 100644 --- a/frontend/paper-trading.html +++ b/frontend/paper-trading.html @@ -592,6 +592,10 @@ color: #ff4444; } + .action-btn + .action-btn { + margin-left: 6px; + } + /* 持仓汇总 */ .position-summary { display: flex; @@ -1319,6 +1323,9 @@ + 分享 @@ -1958,6 +1965,27 @@ } }, + async deleteOrder(order) { + if (!confirm(`确定要删除订单 ${order.order_id.slice(-12)} 吗?\n\n此操作会直接删除订单记录,不会产生任何盈亏计算,也不会影响收益率等统计指标。`)) { + return; + } + + try { + const response = await fetch(`/api/paper-trading/orders/${order.order_id}`, { + method: 'DELETE' + }); + const data = await response.json(); + if (data.success) { + alert('订单已删除'); + this.refreshData(); + } else { + alert('删除失败: ' + (data.detail || '未知错误')); + } + } catch (e) { + alert('删除失败: ' + e.message); + } + }, + formatTime(timeStr) { if (!timeStr) return '-'; const date = new Date(timeStr);