diff --git a/backend/ABNORMAL_ORDERS_README.md b/backend/ABNORMAL_ORDERS_README.md deleted file mode 100644 index 72ab106..0000000 --- a/backend/ABNORMAL_ORDERS_README.md +++ /dev/null @@ -1,124 +0,0 @@ -# 异常订单检查工具 - -用于检查和修复数据库中导致错误平仓消息的异常订单。 - -## 问题原因 - -根据之前的分析,"莫名其妙出现的平仓消息"通常是由以下异常订单导致的: - -1. **OPEN 状态但成交价为 0 的订单**:这些订单被系统认为是"已成交"但价格无效,导致平仓计算时显示 `$0.00` -2. **PENDING 状态但有成交价的订单**:状态不一致,可能导致重复处理 - -## 使用方法 - -### 方法 1: Python 脚本(推荐) - -在服务器上执行: - -```bash -cd /path/to/Stock_Agent/backend - -# 检查异常订单(不会修改数据) -python3 check_abnormal_orders.py - -# 自动修复异常订单(会删除/修改数据,需要确认) -python3 fix_abnormal_orders.py -``` - -### 方法 2: SQL 查询 - -如果有 SQLite 命令行工具: - -```bash -cd /path/to/Stock_Agent/backend - -# 需要先确认数据库路径 -sqlite3 /path/to/your/database.db < check_abnormal_orders.sql -``` - -或者直接进入 SQLite: - -```bash -sqlite3 /path/to/your/database.db - -# 然后复制粘贴 check_abnormal_orders.sql 中的查询语句 -``` - -### 方法 3: Bash 脚本 - -```bash -cd /path/to/Stock_Agent/backend - -# 需要指定数据库路径 -./check_orders.sh /path/to/your/database.db -``` - -## 检查结果说明 - -脚本会检查以下问题: - -| 问题 | 说明 | 影响 | -|------|------|------| -| OPEN 状态但成交价无效 | 订单已成交但 `filled_price` 为 0 或 NULL | 可能导致 `$0.00` 平仓消息 | -| PENDING 状态但有成交价 | 状态应该是 OPEN 但实际是 PENDING | 状态不一致 | -| 平仓订单价格异常 | 出场价或成交价为 0 | 历史记录错误 | -| 重复订单 | 同一交易对短时间内创建多个订单 | 可能是重复信号 | - -## 修复操作 - -确认有异常订单后,可以: - -1. **手动删除异常订单**(最安全): - -```sql --- 删除 OPEN 状态但成交价无效的订单 -DELETE FROM paper_orders -WHERE status = 'OPEN' - AND (filled_price IS NULL OR filled_price = 0); -``` - -2. **使用 Python 自动修复**: - -```bash -python3 fix_abnormal_orders.py -# 脚本会要求确认,输入 yes 确认删除/修复 -``` - -3. **重启服务**(推荐): - -修复后重启服务,让系统重新加载正确的活跃订单: - -```bash -# 重启 FastAPI 服务 -systemctl restart stock-agent # 或你的服务名称 -``` - -## 防止再次出现 - -代码中已添加防御性检查(在 `paper_trading_service.py` 中): - -1. `_load_active_orders()` 会跳过异常订单 -2. `_check_order_trigger()` 会检查成交价有效性 -3. `_close_order()` 会防止无效订单平仓 - -但建议定期运行检查脚本,确保数据库状态正常。 - -## 紧急处理 - -如果正在出现大量错误消息,可以: - -1. **临时停止服务**: -```bash -systemctl stop stock-agent -``` - -2. **运行检查和修复**: -```bash -python3 check_abnormal_orders.py -python3 fix_abnormal_orders.py -``` - -3. **重启服务**: -```bash -systemctl start stock-agent -``` diff --git a/backend/check_abnormal_orders.py b/backend/check_abnormal_orders.py deleted file mode 100644 index a5f8f56..0000000 --- a/backend/check_abnormal_orders.py +++ /dev/null @@ -1,210 +0,0 @@ -#!/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] - - # last_time 是字符串,直接格式化 - if last_time: - if isinstance(last_time, str): - time_str = last_time[11:19] # 提取 HH:MM:SS 部分 - else: - time_str = last_time.strftime('%H:%M:%S') - else: - time_str = 'N/A' - - filled_str = f"{filled_price:.2f}" if filled_price else "NULL" - entry_str = f"{entry_price:.2f}" if entry_price else "NULL" - print(f" {time_str} | {symbol} | {side:4s} | {status:15s} | " - f"入场:{entry_str} 成交:{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() diff --git a/backend/check_abnormal_orders.sql b/backend/check_abnormal_orders.sql deleted file mode 100644 index da9aefe..0000000 --- a/backend/check_abnormal_orders.sql +++ /dev/null @@ -1,91 +0,0 @@ --- ============================================================ --- 异常订单检查 SQL --- 可以直接在 SQLite 命令行或数据库管理工具中执行 --- ============================================================ - --- 1. 检查 OPEN 状态但成交价无效的订单(最可能的问题来源) -SELECT - order_id, - symbol, - side, - status, - entry_price, - filled_price, - created_at, - 'OPEN状态但成交价无效' as issue -FROM paper_orders -WHERE status = 'OPEN' - AND (filled_price IS NULL OR filled_price = 0); - --- 2. 检查 PENDING 状态但有成交价的订单(状态不一致) -SELECT - order_id, - symbol, - side, - status, - entry_price, - filled_price, - created_at, - 'PENDING状态但有成交价' as issue -FROM paper_orders -WHERE status = 'PENDING' - AND filled_price IS NOT NULL - AND filled_price > 0; - --- 3. 检查最近平仓订单中价格异常的记录 -SELECT - order_id, - symbol, - side, - status, - entry_price, - filled_price, - exit_price, - closed_at, - '平仓订单价格异常' as issue -FROM paper_orders -WHERE status IN ('CLOSED_TP', 'CLOSED_SL', 'CLOSED_BE', 'CLOSED_MANUAL') - AND closed_at >= datetime('now', '-1 hour') - AND ( - filled_price IS NULL OR filled_price = 0 OR - exit_price IS NULL OR exit_price = 0 - ); - --- 4. 活跃订单状态统计 -SELECT - status, - COUNT(*) as total, - 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; - --- 5. 检查可能重复的订单(同一交易对+方向,最近创建) -SELECT - symbol, - side, - COUNT(*) as count, - MIN(created_at) as first_created, - MAX(created_at) as last_created -FROM paper_orders -WHERE status IN ('PENDING', 'OPEN') - AND created_at >= datetime('now', '-1 hour') -GROUP BY symbol, side -HAVING COUNT(*) > 1; - --- ============================================================ --- 清理异常订单的 SQL(谨慎执行!) --- ============================================================ - --- 删除 OPEN 状态但成交价无效的订单 --- WARNING: 执行前请先确认上面的查询结果! --- DELETE FROM paper_orders --- WHERE status = 'OPEN' --- AND (filled_price IS NULL OR filled_price = 0); - --- 修复 PENDING 状态但有成交价的订单 --- UPDATE paper_orders --- SET status = 'OPEN' --- WHERE status = 'PENDING' --- AND filled_price IS NOT NULL --- AND filled_price > 0; diff --git a/backend/check_orders.sh b/backend/check_orders.sh deleted file mode 100755 index bb423bb..0000000 --- a/backend/check_orders.sh +++ /dev/null @@ -1,88 +0,0 @@ -#!/bin/bash -# ============================================================ -# 异常订单快速检查脚本 -# 用法: ./check_orders.sh [database_path] -# ============================================================ - -DB_PATH="${1:-/path/to/your/database.db}" - -echo "==========================================" -echo "异常订单检查报告" -echo "==========================================" -echo "数据库: $DB_PATH" -echo "检查时间: $(date '+%Y-%m-%d %H:%M:%S')" -echo "" - -if [ ! -f "$DB_PATH" ]; then - echo "错误: 找不到数据库文件 $DB_PATH" - echo "请指定正确的数据库路径" - exit 1 -fi - -# 1. 检查 OPEN 状态但成交价无效的订单 -echo "【1】OPEN 状态但成交价无效的订单:" -echo "----------------------------------------" -sqlite3 "$DB_PATH" " -SELECT - ' ' || substr(order_id, 1, 8) || '...' || - ' | ' || symbol || - ' | ' || side || - ' | 成交价:' || COALESCE(CAST(filled_price AS TEXT), 'NULL') -FROM paper_orders -WHERE status = 'OPEN' - AND (filled_price IS NULL OR filled_price = 0) -LIMIT 10; -" || echo " ✅ 无异常订单" -echo "" - -# 2. 检查 PENDING 状态但有成交价的订单 -echo "【2】PENDING 状态但有成交价的订单:" -echo "----------------------------------------" -sqlite3 "$DB_PATH" " -SELECT - ' ' || substr(order_id, 1, 8) || '...' || - ' | ' || symbol || - ' | 状态应该是OPEN' -FROM paper_orders -WHERE status = 'PENDING' - AND filled_price IS NOT NULL - AND filled_price > 0 -LIMIT 10; -" || echo " ✅ 无异常订单" -echo "" - -# 3. 活跃订单统计 -echo "【3】活跃订单统计:" -echo "----------------------------------------" -sqlite3 "$DB_PATH" " -SELECT - ' ' || status || ': ' || COUNT(*) || ' 个' -FROM paper_orders -WHERE status IN ('PENDING', 'OPEN') -GROUP BY status; -" -echo "" - -# 4. 最近异常平仓记录 -echo "【4】最近1小时内价格异常的平仓记录:" -echo "----------------------------------------" -sqlite3 "$DB_PATH" " -SELECT - ' ' || substr(order_id, 1, 8) || '...' || - ' | ' || symbol || - ' | 成交:' || COALESCE(CAST(filled_price AS TEXT), 'NULL') || - ' | 出场:' || COALESCE(CAST(exit_price AS TEXT), 'NULL') -FROM paper_orders -WHERE status IN ('CLOSED_TP', 'CLOSED_SL', 'CLOSED_BE', 'CLOSED_MANUAL') - AND closed_at >= datetime('now', '-1 hour') - AND ( - filled_price IS NULL OR filled_price = 0 OR - exit_price IS NULL OR exit_price = 0 - ) -LIMIT 10; -" || echo " ✅ 无异常记录" -echo "" - -echo "==========================================" -echo "检查完成" -echo "==========================================" diff --git a/backend/fix_abnormal_orders.py b/backend/fix_abnormal_orders.py deleted file mode 100644 index 0eaf616..0000000 --- a/backend/fix_abnormal_orders.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/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 datetime import datetime - - -def fix_abnormal_orders(): - """修复异常订单""" - - db = db_service.get_session() - - print("=" * 80) - print("异常订单自动修复") - print("=" * 80) - print() - - fixed_count = 0 - - # 1. 删除 OPEN 状态但 filled_price 为 0 或 None 的订单 - print("【1】清理 OPEN 状态但成交价无效的订单...") - invalid_orders = db.query(PaperOrder).filter( - PaperOrder.status == OrderStatus.OPEN, - (PaperOrder.filled_price == None) | (PaperOrder.filled_price == 0) - ).all() - - if invalid_orders: - print(f" 发现 {len(invalid_orders)} 个异常订单:") - for order in invalid_orders: - print(f" - {order.order_id} | {order.symbol} | {order.side.value} | 成交价: {order.filled_price}") - - # 确认删除 - confirm = input("\n 确认删除这些订单? (yes/no): ") - if confirm.lower() == 'yes': - for order in invalid_orders: - db.delete(order) - fixed_count += 1 - db.commit() - print(f" ✅ 已删除 {len(invalid_orders)} 个异常订单") - else: - print(" ⏭️ 跳过删除") - else: - print(" ✅ 无异常订单") - print() - - # 2. 修复 PENDING 状态但有成交价的订单 - print("【2】修复 PENDING 状态但有成交价的订单...") - pending_orders = db.query(PaperOrder).filter( - PaperOrder.status == OrderStatus.PENDING, - PaperOrder.filled_price != None, - PaperOrder.filled_price > 0 - ).all() - - if pending_orders: - print(f" 发现 {len(pending_orders)} 个状态不一致的订单:") - for order in pending_orders: - print(f" - {order.order_id} | {order.symbol} | 状态: PENDING → OPEN") - - confirm = input("\n 确认修复这些订单? (yes/no): ") - if confirm.lower() == 'yes': - for order in pending_orders: - order.status = OrderStatus.OPEN - fixed_count += 1 - db.commit() - print(f" ✅ 已修复 {len(pending_orders)} 个订单") - else: - print(" ⏭️ 跳过修复") - else: - print(" ✅ 无异常订单") - print() - - # 3. 删除无用的测试数据(可选) - print("【3】检查是否有测试数据需要清理...") - test_orders = db.query(PaperOrder).filter( - PaperOrder.symbol.like('%TEST%') - ).count() - - if test_orders > 0: - print(f" 发现 {test_orders} 个测试订单") - confirm = input(" 是否删除测试数据? (yes/no): ") - if confirm.lower() == 'yes': - db.execute("DELETE FROM paper_orders WHERE symbol LIKE '%TEST%'") - db.commit() - print(f" ✅ 已删除测试数据") - else: - print(" ✅ 无测试数据") - print() - - print("=" * 80) - print(f"修复完成!共处理 {fixed_count} 个异常订单") - print("=" * 80) - - db.close() - - -if __name__ == "__main__": - fix_abnormal_orders()