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);