stock-ai-agent/backend/check_abnormal_orders.py
2026-02-21 19:41:08 +08:00

202 lines
6.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
检查数据库中的异常订单
用于调试莫名奇妙出现的平仓消息问题
"""
import sys
import os
# 添加项目路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from app.services.db_service import db_service
from app.models.paper_trading import PaperOrder, OrderStatus
from sqlalchemy import text
from datetime import datetime, timedelta
def check_abnormal_orders():
"""检查所有异常订单"""
db = db_service.get_session()
print("=" * 80)
print("异常订单检查报告")
print("=" * 80)
print(f"检查时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print()
# 1. 检查 OPEN 状态但 filled_price 为 0 或 None 的订单
print("【1】OPEN 状态但成交价无效的订单(可能导致错误平仓):")
print("-" * 80)
invalid_filled_orders = db.query(PaperOrder).filter(
PaperOrder.status == OrderStatus.OPEN,
(PaperOrder.filled_price == None) | (PaperOrder.filled_price == 0)
).all()
if invalid_filled_orders:
for order in invalid_filled_orders:
print(f" ⚠️ 订单ID: {order.order_id}")
print(f" 交易对: {order.symbol}")
print(f" 方向: {order.side.value}")
print(f" 状态: {order.status.value}")
print(f" 入场价: {order.entry_price}")
print(f" 成交价: {order.filled_price} ❌ 无效")
print(f" 创建时间: {order.created_at}")
print()
else:
print(" ✅ 无异常订单")
print()
# 2. 检查 PENDING 状态但已有成交价的订单
print("【2】PENDING 状态但有成交价的订单(状态不一致):")
print("-" * 80)
pending_with_filled = db.query(PaperOrder).filter(
PaperOrder.status == OrderStatus.PENDING,
PaperOrder.filled_price != None,
PaperOrder.filled_price > 0
).all()
if pending_with_filled:
for order in pending_with_filled:
print(f" ⚠️ 订单ID: {order.order_id}")
print(f" 交易对: {order.symbol}")
print(f" 成交价: {order.filled_price}")
print(f" 状态: PENDING应该是 OPEN")
print()
else:
print(" ✅ 无异常订单")
print()
# 3. 检查最近1小时内平仓的订单入场价或出场价为0
print("【3】最近平仓订单中价格异常的记录:")
print("-" * 80)
one_hour_ago = datetime.now() - timedelta(hours=1)
closed_abnormal = db.query(PaperOrder).filter(
PaperOrder.status.in_([
OrderStatus.CLOSED_TP,
OrderStatus.CLOSED_SL,
OrderStatus.CLOSED_BE,
OrderStatus.CLOSED_MANUAL
]),
PaperOrder.closed_at >= one_hour_ago,
(
(PaperOrder.filled_price == None) | (PaperOrder.filled_price == 0) |
(PaperOrder.exit_price == None) | (PaperOrder.exit_price == 0)
)
).all()
if closed_abnormal:
for order in closed_abnormal:
print(f" ⚠️ 订单ID: {order.order_id}")
print(f" 交易对: {order.symbol}")
print(f" 成交价: {order.filled_price}")
print(f" 出场价: {order.exit_price}")
print(f" 平仓时间: {order.closed_at}")
print(f" 平仓原因: {order.status.value}")
print()
else:
print(" ✅ 无异常记录")
print()
# 4. 检查所有活跃订单的状态统计
print("【4】活跃订单状态统计:")
print("-" * 80)
active_stats = db.execute(text("""
SELECT
status,
COUNT(*) as count,
SUM(CASE WHEN filled_price IS NULL OR filled_price = 0 THEN 1 ELSE 0 END) as invalid_count
FROM paper_orders
WHERE status IN ('PENDING', 'OPEN')
GROUP BY status
"""))
for row in active_stats:
status_name = row[0]
count = row[1]
invalid = row[2]
print(f" {status_name}: {count} 个(异常: {invalid} 个)")
print()
# 5. 检查重复订单
print("【5】可能重复的订单同一交易对、同一方向、相近创建时间:")
print("-" * 80)
duplicates = db.execute(text("""
SELECT symbol, side, created_at, order_id, entry_price
FROM paper_orders
WHERE status IN ('PENDING', 'OPEN')
AND created_at >= datetime('now', '-1 hour')
ORDER BY symbol, side, created_at DESC
""")).fetchall()
# 简单的重复检测:同一交易对+方向在1分钟内创建
seen = {}
duplicate_found = False
for row in duplicates:
key = (row[0], row[1]) # symbol + side
if key in seen:
prev_time = seen[key]
if abs((row[2] - prev_time).total_seconds()) < 60:
print(f" ⚠️ 可能重复: {row[0]} {row[1]}")
print(f" 订单ID: {row[3]}")
print(f" 时间: {row[2]}")
duplicate_found = True
seen[key] = row[2]
if not duplicate_found:
print(" ✅ 无明显重复")
print()
# 6. 最近的活动日志
print("【6】最近10条订单变更记录按时间倒序:")
print("-" * 80)
# 使用 COALESCE 来优先显示 closed_at其次 opened_at最后 created_at
recent_orders = db.execute(text("""
SELECT
COALESCE(closed_at, opened_at, created_at) as last_time,
symbol,
side,
status,
entry_price,
filled_price
FROM paper_orders
ORDER BY last_time DESC
LIMIT 10
""")).fetchall()
for order in recent_orders:
last_time = order[0]
symbol = order[1]
side = order[2]
status = order[3]
entry_price = order[4]
filled_price = order[5]
time_str = last_time.strftime('%H:%M:%S') if last_time else 'N/A'
filled_str = f"{filled_price:.2f}" if filled_price else "NULL"
print(f" {time_str} | {symbol} | {side:4s} | {status:15s} | "
f"入场:{entry_price:.2f} 成交:{filled_str}")
print()
print("=" * 80)
print("检查完成")
print("=" * 80)
# 输出清理建议
if invalid_filled_orders:
print()
print("🔧 发现异常订单!建议执行以下操作:")
print()
print("1. 删除 OPEN 状态但成交价无效的订单:")
for order in invalid_filled_orders:
print(f" DELETE FROM paper_orders WHERE order_id = '{order.order_id}';")
print()
print("2. 或者运行 python fix_abnormal_orders.py 自动修复")
db.close()
if __name__ == "__main__":
check_abnormal_orders()