This commit is contained in:
薇薇安 2026-01-17 09:58:35 +08:00
parent b2411fe745
commit be44cd02a7
2 changed files with 105 additions and 8 deletions

View File

@ -0,0 +1,50 @@
-- 修复 exit_order_id 唯一约束问题
-- 问题exit_order_id 有 UNIQUE 约束,但在状态同步时,同一个订单可能被多次更新,导致重复键错误
-- 解决方案:移除 UNIQUE 约束,保留索引以便快速查询
USE `auto_trade_sys`;
-- 1. 删除唯一约束(如果存在)
-- 注意MySQL 中,如果字段有 UNIQUE 约束,删除索引会同时删除唯一约束
-- 先检查是否存在唯一索引
SET @index_exists = (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = 'auto_trade_sys'
AND table_name = 'trades'
AND index_name = 'exit_order_id'
AND non_unique = 0
);
-- 如果存在唯一索引,删除它
SET @sql = IF(@index_exists > 0,
'ALTER TABLE `trades` DROP INDEX `exit_order_id`',
'SELECT "exit_order_id 唯一索引不存在,跳过删除" as message'
);
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- 2. 重新添加普通索引(非唯一)
-- 先检查是否已存在普通索引
SET @normal_index_exists = (
SELECT COUNT(*)
FROM information_schema.statistics
WHERE table_schema = 'auto_trade_sys'
AND table_name = 'trades'
AND index_name = 'idx_exit_order_id'
);
-- 如果不存在普通索引,添加它
SET @sql2 = IF(@normal_index_exists = 0,
'ALTER TABLE `trades` ADD INDEX `idx_exit_order_id` (`exit_order_id`)',
'SELECT "idx_exit_order_id 索引已存在,跳过添加" as message'
);
PREPARE stmt2 FROM @sql2;
EXECUTE stmt2;
DEALLOCATE PREPARE stmt2;
-- 验证:检查表结构
-- SHOW CREATE TABLE `trades`;
-- 或者
-- SHOW INDEX FROM `trades` WHERE Column_name = 'exit_order_id';

View File

@ -120,8 +120,36 @@ class Trade:
pnl: 盈亏 pnl: 盈亏
pnl_percent: 盈亏百分比 pnl_percent: 盈亏百分比
exit_order_id: 币安平仓订单号可选用于对账 exit_order_id: 币安平仓订单号可选用于对账
注意如果 exit_order_id 已存在且属于其他交易记录会跳过更新 exit_order_id 以避免唯一约束冲突
""" """
exit_time = get_beijing_time() exit_time = get_beijing_time()
# 如果提供了 exit_order_id先检查是否已被其他交易记录使用
if exit_order_id is not None:
try:
existing_trade = Trade.get_by_exit_order_id(exit_order_id)
if existing_trade and existing_trade['id'] != trade_id:
# 如果 exit_order_id 已被其他交易记录使用,记录警告但不更新 exit_order_id
logger.warning(
f"交易记录 {trade_id} 的 exit_order_id {exit_order_id} 已被交易记录 {existing_trade['id']} 使用,"
f"跳过更新 exit_order_id只更新其他字段"
)
# 只更新其他字段,不更新 exit_order_id
db.execute_update(
"""UPDATE trades
SET exit_price = %s, exit_time = %s,
exit_reason = %s, pnl = %s, pnl_percent = %s, status = 'closed'
WHERE id = %s""",
(exit_price, exit_time, exit_reason, pnl, pnl_percent, trade_id)
)
return
except Exception as e:
# 如果查询失败,记录警告但继续正常更新
logger.warning(f"检查 exit_order_id {exit_order_id} 时出错: {e},继续正常更新")
# 正常更新(包括 exit_order_id
try:
db.execute_update( db.execute_update(
"""UPDATE trades """UPDATE trades
SET exit_price = %s, exit_time = %s, SET exit_price = %s, exit_time = %s,
@ -130,6 +158,25 @@ class Trade:
WHERE id = %s""", WHERE id = %s""",
(exit_price, exit_time, exit_reason, pnl, pnl_percent, exit_order_id, trade_id) (exit_price, exit_time, exit_reason, pnl, pnl_percent, exit_order_id, trade_id)
) )
except Exception as e:
# 如果更新失败(可能是唯一约束冲突),尝试不更新 exit_order_id
error_str = str(e)
if "Duplicate entry" in error_str and "exit_order_id" in error_str:
logger.warning(
f"更新交易记录 {trade_id} 时 exit_order_id {exit_order_id} 唯一约束冲突,"
f"尝试不更新 exit_order_id"
)
# 只更新其他字段,不更新 exit_order_id
db.execute_update(
"""UPDATE trades
SET exit_price = %s, exit_time = %s,
exit_reason = %s, pnl = %s, pnl_percent = %s, status = 'closed'
WHERE id = %s""",
(exit_price, exit_time, exit_reason, pnl, pnl_percent, trade_id)
)
else:
# 其他错误,重新抛出
raise
@staticmethod @staticmethod
def get_by_entry_order_id(entry_order_id): def get_by_entry_order_id(entry_order_id):