From 8dc0f0dbc328528d43e88744aea7501dfdee6a06 Mon Sep 17 00:00:00 2001 From: lz_db Date: Thu, 4 Dec 2025 19:44:22 +0800 Subject: [PATCH] 1 --- logs/sync_2025-12-04.log | 664 ++++++++++++++++++ sync/__pycache__/account_sync.cpython-311.pyc | Bin 16863 -> 9585 bytes sync/__pycache__/base_sync.cpython-311.pyc | Bin 6986 -> 6799 bytes sync/__pycache__/manager.cpython-311.pyc | Bin 19184 -> 8684 bytes .../__pycache__/position_sync.cpython-311.pyc | Bin 26592 -> 20222 bytes sync/account_sync.py | 191 +---- sync/base_sync.py | 5 - sync/manager.py | 238 +------ sync/position_sync.py | 98 +-- .../__pycache__/redis_client.cpython-311.pyc | Bin 3014 -> 23340 bytes utils/redis_client.py | 451 +++++++++++- 11 files changed, 1128 insertions(+), 519 deletions(-) diff --git a/logs/sync_2025-12-04.log b/logs/sync_2025-12-04.log index e17d4c2..2092eb0 100644 --- a/logs/sync_2025-12-04.log +++ b/logs/sync_2025-12-04.log @@ -2725,3 +2725,667 @@ KeyError: 'updated' 2025-12-04 15:32:23 | INFO | sync.manager:start:95 - 同步完成,总耗时 0.01 秒,等待 20 秒 2025-12-04 15:32:31 | INFO | sync.manager:signal_handler:382 - 接收到信号 2,正在关闭... 2025-12-04 15:32:43 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 16:20:34 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 16:20:34 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 16:20:34 | INFO | sync.manager:_get_computer_names:143 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 16:20:34 | INFO | sync.manager:__init__:39 - 启用持仓批量同步 +2025-12-04 16:20:34 | INFO | sync.manager:__init__:44 - 启用订单批量同步 +2025-12-04 16:20:34 | INFO | sync.manager:__init__:49 - 启用账户信息批量同步 +2025-12-04 16:20:34 | INFO | sync.manager:start:67 - 同步服务启动,间隔 20 秒 +2025-12-04 16:20:34 | INFO | utils.redis_client:_init_connection_pool:48 - Redis连接池初始化成功 +2025-12-04 16:20:34 | INFO | sync.manager:_get_accounts_by_computer_name:161 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 16:20:34 | INFO | sync.manager:_get_accounts_by_computer_name:186 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 16:20:34 | INFO | sync.manager:get_accounts_from_redis:131 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 16:20:34 | INFO | sync.manager:start:84 - 第1次同步开始,共 22 个账号 +2025-12-04 16:20:34 | INFO | sync.position_sync:sync_batch:18 - 开始批量同步持仓数据,共 22 个账号 +2025-12-04 16:20:34 | ERROR | sync.position_sync:sync_batch:42 - 持仓批量同步失败: 'PositionSyncBatch' object has no attribute '_collect_all_positions' +2025-12-04 16:20:34 | ERROR | sync.position_sync:sync_batch:49 - 完整堆栈跟踪: +Traceback (most recent call last): + File "/root/project/exchange_monitor_sync/sync/position_sync.py", line 23, in sync_batch + all_positions = await self._collect_all_positions(accounts) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +AttributeError: 'PositionSyncBatch' object has no attribute '_collect_all_positions' + +2025-12-04 16:20:34 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 16:20:34 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 16:20:34 | ERROR | sync.account_sync:_collect_all_account_data:59 - 收集账户信息数据失败: name 'asyncio' is not defined +2025-12-04 16:20:34 | INFO | sync.account_sync:sync_batch:21 - 无账户信息数据需要同步 +2025-12-04 16:20:34 | INFO | sync.manager:_update_stats:378 - === 第1次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 16:20:34 | INFO | sync.manager:start:95 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 16:20:53 | INFO | sync.manager:signal_handler:382 - 接收到信号 2,正在关闭... +2025-12-04 16:20:54 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 16:40:35 | ERROR | __main__::49 - 程序异常: name 'Optional' is not defined +2025-12-04 16:40:35 | ERROR | __main__::51 - Traceback (most recent call last): + File "/root/project/exchange_monitor_sync/main.py", line 45, in + asyncio.run(main()) + File "/root/.pyenv/versions/3.11.10/lib/python3.11/asyncio/runners.py", line 190, in run + return runner.run(main) + ^^^^^^^^^^^^^^^^ + File "/root/.pyenv/versions/3.11.10/lib/python3.11/asyncio/runners.py", line 118, in run + return self._loop.run_until_complete(task) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/root/.pyenv/versions/3.11.10/lib/python3.11/asyncio/base_events.py", line 654, in run_until_complete + return future.result() + ^^^^^^^^^^^^^^^ + File "/root/project/exchange_monitor_sync/main.py", line 25, in main + from sync.manager import SyncManager + File "/root/project/exchange_monitor_sync/sync/manager.py", line 10, in + from utils.redis_client import RedisClient + File "/root/project/exchange_monitor_sync/utils/redis_client.py", line 10, in + class RedisClient: + File "/root/project/exchange_monitor_sync/utils/redis_client.py", line 215, in RedisClient + def parse_account(self, exchange_id: str, account_id: str, account_info: str) -> Optional[Dict]: + ^^^^^^^^ +NameError: name 'Optional' is not defined + +2025-12-04 16:41:14 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 16:41:14 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 16:41:14 | INFO | utils.redis_client:_get_computer_names:87 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 16:41:15 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 16:41:15 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 16:41:15 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 16:41:15 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 16:41:15 | ERROR | utils.redis_client:_get_accounts_by_computer_name:133 - 获取计算机名 lz_c01 的账号失败: 'RedisClient' object has no attribute 'redis_client' +2025-12-04 16:41:15 | ERROR | utils.redis_client:_get_accounts_by_computer_name:133 - 获取计算机名 lz_c02 的账号失败: 'RedisClient' object has no attribute 'redis_client' +2025-12-04 16:41:15 | WARNING | utils.redis_client:get_accounts_from_redis:71 - 配置的计算机名未找到数据,尝试自动发现... +2025-12-04 16:41:15 | ERROR | utils.redis_client:_discover_all_accounts:174 - 自动发现账号失败: 'RedisClient' object has no attribute 'redis_client' +2025-12-04 16:41:15 | INFO | utils.redis_client:get_accounts_from_redis:74 - 从 2 个计算机名获取到 0 个账号 +2025-12-04 16:41:15 | WARNING | sync.manager:start:73 - 未获取到任何账号,等待下次同步 +2025-12-04 16:41:17 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 16:41:35 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 16:43:07 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 16:43:07 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 16:43:07 | INFO | utils.redis_client:_get_computer_names:87 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 16:43:07 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 16:43:07 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 16:43:07 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 16:43:07 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 16:43:07 | INFO | utils.redis_client:_init_connection_pool:51 - Redis连接池初始化成功 +2025-12-04 16:43:07 | INFO | utils.redis_client:_get_accounts_by_computer_name:105 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 16:43:07 | INFO | utils.redis_client:_get_accounts_by_computer_name:130 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 16:43:07 | INFO | utils.redis_client:get_accounts_from_redis:74 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 16:43:07 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 16:43:07 | INFO | sync.position_sync:sync_batch:20 - 开始批量同步持仓数据,共 22 个账号 +2025-12-04 16:43:07 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 16:43:07 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 16:43:07 | ERROR | sync.account_sync:_collect_all_account_data:59 - 收集账户信息数据失败: name 'asyncio' is not defined +2025-12-04 16:43:07 | INFO | sync.account_sync:sync_batch:21 - 无账户信息数据需要同步 +2025-12-04 16:43:07 | INFO | sync.position_sync:sync_batch:32 - 收集到 92 条持仓数据 +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 999999, 'st_id': 5549, 'side': 'sell', 'qty': 0.936, 'symbol': 'BTCUSDT', 'price': 93533.49297627, 'leverage': 20.0, 'uptime': 1764828465, 'liquidation_price': 264730.8837374, 'profit_price': None, 'stop_price': None, 'asset_profit': 571.1406258, 'asset': 'USDT', 'asset_num': 87547.3494258, 'exchange_id': 'bybit'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 999999, 'st_id': 5549, 'side': 'buy', 'qty': 1.87, 'symbol': 'BTC-4DEC25-93000-C-USDT', 'price': 965.0, 'leverage': None, 'uptime': 1764828465, 'liquidation_price': None, 'profit_price': None, 'stop_price': None, 'asset_profit': -1414.87970189, 'asset': 'USDT', 'asset_num': 389.6702981, 'exchange_id': 'bybit'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4219.78, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4430.769, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 35.29, 'asset': 'USDT', 'asset_num': 4219.78, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.65, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4451.6325, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.16, 'asset': 'USDT', 'asset_num': 4239.65, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4239.65, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4451.6325, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.16, 'asset': 'USDT', 'asset_num': 4239.65, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4239.78, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4451.769, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.29, 'asset': 'USDT', 'asset_num': 4239.78, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_4', 'price': 4239.76, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4451.7480000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.27, 'asset': 'USDT', 'asset_num': 4239.76, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_5', 'price': 4238.89, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4450.834500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.4, 'asset': 'USDT', 'asset_num': 4238.89, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_6', 'price': 4237.57, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4449.4484999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.08, 'asset': 'USDT', 'asset_num': 4237.57, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_7', 'price': 4237.55, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4449.427500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.06, 'asset': 'USDT', 'asset_num': 4237.55, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_8', 'price': 4237.6, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4449.4800000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.11, 'asset': 'USDT', 'asset_num': 4237.6, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_9', 'price': 4229.85, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4441.342500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.36, 'asset': 'USDT', 'asset_num': 4229.85, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_10', 'price': 4233.12, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.776, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.63, 'asset': 'USDT', 'asset_num': 4233.12, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_11', 'price': 4233.46, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4445.133, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.97, 'asset': 'USDT', 'asset_num': 4233.46, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_12', 'price': 4232.42, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.041, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.93, 'asset': 'USDT', 'asset_num': 4232.42, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_13', 'price': 4232.72, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.356000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.23, 'asset': 'USDT', 'asset_num': 4232.72, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_14', 'price': 4232.93, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.5765, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.44, 'asset': 'USDT', 'asset_num': 4232.93, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_15', 'price': 4232.91, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.5555, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.42, 'asset': 'USDT', 'asset_num': 4232.91, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_16', 'price': 4232.86, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.503, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.37, 'asset': 'USDT', 'asset_num': 4232.86, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_17', 'price': 4232.24, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4443.852, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.75, 'asset': 'USDT', 'asset_num': 4232.24, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_18', 'price': 4231.4, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4442.97, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 46.91, 'asset': 'USDT', 'asset_num': 4231.4, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4220.02, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4431.021000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 35.57, 'asset': 'USDT', 'asset_num': 4220.02, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.06, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.013000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.61, 'asset': 'USDT', 'asset_num': 4239.06, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4239.6, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.580000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.15, 'asset': 'USDT', 'asset_num': 4239.6, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4239.8, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.79, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.35, 'asset': 'USDT', 'asset_num': 4239.8, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_4', 'price': 4239.76, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.7480000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.31, 'asset': 'USDT', 'asset_num': 4239.76, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_5', 'price': 4239.2, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.16, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.75, 'asset': 'USDT', 'asset_num': 4239.2, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_6', 'price': 4237.57, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4449.4484999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.12, 'asset': 'USDT', 'asset_num': 4237.57, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_7', 'price': 4237.57, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4449.4484999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.12, 'asset': 'USDT', 'asset_num': 4237.57, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_8', 'price': 4237.56, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4449.438000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.11, 'asset': 'USDT', 'asset_num': 4237.56, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_9', 'price': 4238.31, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4450.2255000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.86, 'asset': 'USDT', 'asset_num': 4238.31, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_10', 'price': 4229.55, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4441.0275, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.1, 'asset': 'USDT', 'asset_num': 4229.55, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_11', 'price': 4232.78, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.419, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.33, 'asset': 'USDT', 'asset_num': 4232.78, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_12', 'price': 4233.1, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.755000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.65, 'asset': 'USDT', 'asset_num': 4233.1, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_13', 'price': 4233.12, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.776, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.67, 'asset': 'USDT', 'asset_num': 4233.12, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_14', 'price': 4232.42, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.041, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.97, 'asset': 'USDT', 'asset_num': 4232.42, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_15', 'price': 4232.29, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4443.904500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.84, 'asset': 'USDT', 'asset_num': 4232.29, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_16', 'price': 4232.27, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4443.883500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.82, 'asset': 'USDT', 'asset_num': 4232.27, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_17', 'price': 4232.72, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.356000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.27, 'asset': 'USDT', 'asset_num': 4232.72, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10123, 'st_id': 5539, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4230.55, 'leverage': 100, 'uptime': 1764828448, 'liquidation_price': 4442.0775, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 46.5, 'asset': 'USDT', 'asset_num': 4230.55, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10123, 'st_id': 5539, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.04, 'leverage': 100, 'uptime': 1764828448, 'liquidation_price': 4450.992, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.99, 'asset': 'USDT', 'asset_num': 4239.04, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10123, 'st_id': 5539, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4239.64, 'leverage': 100, 'uptime': 1764828448, 'liquidation_price': 4451.622, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.59, 'asset': 'USDT', 'asset_num': 4239.64, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10123, 'st_id': 5539, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4229.75, 'leverage': 100, 'uptime': 1764828448, 'liquidation_price': 4441.2375, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.7, 'asset': 'USDT', 'asset_num': 4229.75, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10125, 'st_id': 5540, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4220.02, 'leverage': 100, 'uptime': 1764828451, 'liquidation_price': 4431.021000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 35.98, 'asset': 'USDT', 'asset_num': 4220.02, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10125, 'st_id': 5540, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.66, 'leverage': 100, 'uptime': 1764828451, 'liquidation_price': 4451.643, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.62, 'asset': 'USDT', 'asset_num': 4239.66, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10125, 'st_id': 5540, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4239.8, 'leverage': 100, 'uptime': 1764828451, 'liquidation_price': 4451.79, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.76, 'asset': 'USDT', 'asset_num': 4239.8, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10125, 'st_id': 5540, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4229.55, 'leverage': 100, 'uptime': 1764828451, 'liquidation_price': 4441.0275, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.51, 'asset': 'USDT', 'asset_num': 4229.55, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4252.18, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.789000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.81, 'asset': 'USDT', 'asset_num': 4252.18, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4251.59, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.1695, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.22, 'asset': 'USDT', 'asset_num': 4251.59, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4252.64, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4465.272000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.27, 'asset': 'USDT', 'asset_num': 4252.64, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4252.46, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4465.0830000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.09, 'asset': 'USDT', 'asset_num': 4252.46, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_4', 'price': 4252.4, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4465.0199999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.03, 'asset': 'USDT', 'asset_num': 4252.4, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_5', 'price': 4251.83, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.4215, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.46, 'asset': 'USDT', 'asset_num': 4251.83, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_6', 'price': 4252.31, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.9255, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.94, 'asset': 'USDT', 'asset_num': 4252.31, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_7', 'price': 4251.99, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.5895, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.62, 'asset': 'USDT', 'asset_num': 4251.99, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_8', 'price': 4252.46, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4465.0830000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.09, 'asset': 'USDT', 'asset_num': 4252.46, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_9', 'price': 4235.22, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4446.981000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 50.85, 'asset': 'USDT', 'asset_num': 4235.22, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_10', 'price': 4229.4, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4440.87, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.03, 'asset': 'USDT', 'asset_num': 4229.4, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_11', 'price': 4232.32, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4443.936, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.95, 'asset': 'USDT', 'asset_num': 4232.32, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_12', 'price': 4231.73, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4443.3165, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.36, 'asset': 'USDT', 'asset_num': 4231.73, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_13', 'price': 4232.38, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4443.999000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.01, 'asset': 'USDT', 'asset_num': 4232.38, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_14', 'price': 4232.95, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4444.5975, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.58, 'asset': 'USDT', 'asset_num': 4232.95, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4252.98, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.629, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 69.1, 'asset': 'USDT', 'asset_num': 4252.98, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4251.6, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4464.18, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.72, 'asset': 'USDT', 'asset_num': 4251.6, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4252.58, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.209, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.7, 'asset': 'USDT', 'asset_num': 4252.58, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4252.44, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.062, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.56, 'asset': 'USDT', 'asset_num': 4252.44, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_4', 'price': 4251.83, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4464.4215, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.95, 'asset': 'USDT', 'asset_num': 4251.83, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_5', 'price': 4251.99, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4464.5895, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.11, 'asset': 'USDT', 'asset_num': 4251.99, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_6', 'price': 4252.99, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.6395, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 69.11, 'asset': 'USDT', 'asset_num': 4252.99, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_7', 'price': 4252.46, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.0830000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.58, 'asset': 'USDT', 'asset_num': 4252.46, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_8', 'price': 4253.18, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.839000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 69.3, 'asset': 'USDT', 'asset_num': 4253.18, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_9', 'price': 4241.25, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4453.3125, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 57.37, 'asset': 'USDT', 'asset_num': 4241.25, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_10', 'price': 4241.24, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4453.302, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 57.36, 'asset': 'USDT', 'asset_num': 4241.24, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_11', 'price': 4238.61, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4450.5405, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.73, 'asset': 'USDT', 'asset_num': 4238.61, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_12', 'price': 4229.75, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4441.2375, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.87, 'asset': 'USDT', 'asset_num': 4229.75, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_13', 'price': 4232.45, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4444.0725, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.57, 'asset': 'USDT', 'asset_num': 4232.45, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_14', 'price': 4232.3, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.915, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.42, 'asset': 'USDT', 'asset_num': 4232.3, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_15', 'price': 4232.25, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.8625, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.37, 'asset': 'USDT', 'asset_num': 4232.25, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_16', 'price': 4232.38, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.999000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.5, 'asset': 'USDT', 'asset_num': 4232.38, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_17', 'price': 4232.38, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.999000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.5, 'asset': 'USDT', 'asset_num': 4232.38, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_18', 'price': 4232.72, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4444.356000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.84, 'asset': 'USDT', 'asset_num': 4232.72, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_19', 'price': 4232.93, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4444.5765, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 49.05, 'asset': 'USDT', 'asset_num': 4232.93, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_20', 'price': 4231.73, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.3165, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.85, 'asset': 'USDT', 'asset_num': 4231.73, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_21', 'price': 4227.03, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4438.3814999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 43.15, 'asset': 'USDT', 'asset_num': 4227.03, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_22', 'price': 4196.72, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4406.5560000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 12.84, 'asset': 'USDT', 'asset_num': 4196.72, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10140, 'st_id': 5548, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4219.79, 'leverage': 100, 'uptime': 1764828463, 'liquidation_price': 4430.779500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 36.3, 'asset': 'USDT', 'asset_num': 4219.79, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10140, 'st_id': 5548, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.06, 'leverage': 100, 'uptime': 1764828463, 'liquidation_price': 4451.013000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.57, 'asset': 'USDT', 'asset_num': 4239.06, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10142, 'st_id': 5549, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4219.79, 'leverage': 100, 'uptime': 1764828465, 'liquidation_price': 4430.779500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 36.47, 'asset': 'USDT', 'asset_num': 4219.79, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10144, 'st_id': 5550, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4230.53, 'leverage': 100, 'uptime': 1764828405, 'liquidation_price': 4442.0565, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.35, 'asset': 'USDT', 'asset_num': 4230.53, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 10144, 'st_id': 5550, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4238.96, 'leverage': 100, 'uptime': 1764828405, 'liquidation_price': 4450.908, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.78, 'asset': 'USDT', 'asset_num': 4238.96, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 88887, 'st_id': 88882, 'side': 'sell', 'qty': 0.08, 'symbol': 'XAUAUD+_0', 'price': 6326.33, 'leverage': 100, 'uptime': 1764828408, 'liquidation_price': 6642.6465, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 0.0, 'asset': 'USDT', 'asset_num': 50610.64, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:333 - 处理持仓数据失败: {'k_id': 88887, 'st_id': 88882, 'side': 'sell', 'qty': 0.08, 'symbol': 'XAUAUD+_1', 'price': 6325.7, 'leverage': 100, 'uptime': 1764828408, 'liquidation_price': 6641.985, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 0.0, 'asset': 'USDT', 'asset_num': 50605.6, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:43:07 | INFO | sync.position_sync:sync_batch:39 - 持仓批量同步完成: 处理 0 条,受影响 0 条,删除 0 条,耗时 0.02秒 +2025-12-04 16:43:07 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.02秒 | 平均耗时: 0.00秒 +2025-12-04 16:43:07 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.02 秒,等待 20 秒 +2025-12-04 16:43:10 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 16:43:27 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 16:53:12 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 16:53:12 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 16:53:12 | INFO | utils.redis_client:_get_computer_names:87 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 16:53:12 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 16:53:12 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 16:53:12 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 16:53:12 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 16:53:12 | INFO | utils.redis_client:_init_connection_pool:51 - Redis连接池初始化成功 +2025-12-04 16:53:12 | INFO | utils.redis_client:_get_accounts_by_computer_name:105 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 16:53:12 | INFO | utils.redis_client:_get_accounts_by_computer_name:130 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 16:53:12 | INFO | utils.redis_client:get_accounts_from_redis:74 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 16:53:12 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 16:53:12 | INFO | sync.position_sync:sync_batch:18 - 开始批量同步持仓数据,共 22 个账号 +2025-12-04 16:53:12 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 16:53:12 | INFO | sync.position_sync:sync_batch:30 - 收集到 92 条持仓数据 +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 999999, 'st_id': 5549, 'side': 'sell', 'qty': 0.936, 'symbol': 'BTCUSDT', 'price': 93533.49297627, 'leverage': 20.0, 'uptime': 1764828465, 'liquidation_price': 264730.8837374, 'profit_price': None, 'stop_price': None, 'asset_profit': 571.1406258, 'asset': 'USDT', 'asset_num': 87547.3494258, 'exchange_id': 'bybit'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 999999, 'st_id': 5549, 'side': 'buy', 'qty': 1.87, 'symbol': 'BTC-4DEC25-93000-C-USDT', 'price': 965.0, 'leverage': None, 'uptime': 1764828465, 'liquidation_price': None, 'profit_price': None, 'stop_price': None, 'asset_profit': -1414.87970189, 'asset': 'USDT', 'asset_num': 389.6702981, 'exchange_id': 'bybit'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4219.78, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4430.769, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 35.29, 'asset': 'USDT', 'asset_num': 4219.78, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.65, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4451.6325, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.16, 'asset': 'USDT', 'asset_num': 4239.65, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4239.65, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4451.6325, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.16, 'asset': 'USDT', 'asset_num': 4239.65, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4239.78, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4451.769, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.29, 'asset': 'USDT', 'asset_num': 4239.78, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_4', 'price': 4239.76, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4451.7480000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.27, 'asset': 'USDT', 'asset_num': 4239.76, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_5', 'price': 4238.89, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4450.834500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.4, 'asset': 'USDT', 'asset_num': 4238.89, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_6', 'price': 4237.57, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4449.4484999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.08, 'asset': 'USDT', 'asset_num': 4237.57, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_7', 'price': 4237.55, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4449.427500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.06, 'asset': 'USDT', 'asset_num': 4237.55, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_8', 'price': 4237.6, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4449.4800000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.11, 'asset': 'USDT', 'asset_num': 4237.6, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_9', 'price': 4229.85, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4441.342500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.36, 'asset': 'USDT', 'asset_num': 4229.85, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_10', 'price': 4233.12, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.776, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.63, 'asset': 'USDT', 'asset_num': 4233.12, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_11', 'price': 4233.46, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4445.133, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.97, 'asset': 'USDT', 'asset_num': 4233.46, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_12', 'price': 4232.42, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.041, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.93, 'asset': 'USDT', 'asset_num': 4232.42, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_13', 'price': 4232.72, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.356000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.23, 'asset': 'USDT', 'asset_num': 4232.72, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_14', 'price': 4232.93, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.5765, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.44, 'asset': 'USDT', 'asset_num': 4232.93, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_15', 'price': 4232.91, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.5555, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.42, 'asset': 'USDT', 'asset_num': 4232.91, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_16', 'price': 4232.86, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4444.503, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.37, 'asset': 'USDT', 'asset_num': 4232.86, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_17', 'price': 4232.24, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4443.852, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.75, 'asset': 'USDT', 'asset_num': 4232.24, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10107, 'st_id': 5531, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_18', 'price': 4231.4, 'leverage': 100, 'uptime': 1764828442, 'liquidation_price': 4442.97, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 46.91, 'asset': 'USDT', 'asset_num': 4231.4, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4220.02, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4431.021000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 35.57, 'asset': 'USDT', 'asset_num': 4220.02, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.06, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.013000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.61, 'asset': 'USDT', 'asset_num': 4239.06, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4239.6, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.580000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.15, 'asset': 'USDT', 'asset_num': 4239.6, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4239.8, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.79, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.35, 'asset': 'USDT', 'asset_num': 4239.8, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_4', 'price': 4239.76, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.7480000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.31, 'asset': 'USDT', 'asset_num': 4239.76, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_5', 'price': 4239.2, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4451.16, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.75, 'asset': 'USDT', 'asset_num': 4239.2, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_6', 'price': 4237.57, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4449.4484999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.12, 'asset': 'USDT', 'asset_num': 4237.57, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_7', 'price': 4237.57, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4449.4484999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.12, 'asset': 'USDT', 'asset_num': 4237.57, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_8', 'price': 4237.56, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4449.438000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.11, 'asset': 'USDT', 'asset_num': 4237.56, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_9', 'price': 4238.31, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4450.2255000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.86, 'asset': 'USDT', 'asset_num': 4238.31, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_10', 'price': 4229.55, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4441.0275, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.1, 'asset': 'USDT', 'asset_num': 4229.55, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_11', 'price': 4232.78, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.419, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.33, 'asset': 'USDT', 'asset_num': 4232.78, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_12', 'price': 4233.1, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.755000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.65, 'asset': 'USDT', 'asset_num': 4233.1, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_13', 'price': 4233.12, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.776, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.67, 'asset': 'USDT', 'asset_num': 4233.12, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_14', 'price': 4232.42, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.041, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.97, 'asset': 'USDT', 'asset_num': 4232.42, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_15', 'price': 4232.29, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4443.904500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.84, 'asset': 'USDT', 'asset_num': 4232.29, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_16', 'price': 4232.27, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4443.883500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.82, 'asset': 'USDT', 'asset_num': 4232.27, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10115, 'st_id': 5535, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_17', 'price': 4232.72, 'leverage': 100, 'uptime': 1764828445, 'liquidation_price': 4444.356000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.27, 'asset': 'USDT', 'asset_num': 4232.72, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10123, 'st_id': 5539, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4230.55, 'leverage': 100, 'uptime': 1764828448, 'liquidation_price': 4442.0775, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 46.5, 'asset': 'USDT', 'asset_num': 4230.55, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10123, 'st_id': 5539, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.04, 'leverage': 100, 'uptime': 1764828448, 'liquidation_price': 4450.992, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.99, 'asset': 'USDT', 'asset_num': 4239.04, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10123, 'st_id': 5539, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4239.64, 'leverage': 100, 'uptime': 1764828448, 'liquidation_price': 4451.622, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.59, 'asset': 'USDT', 'asset_num': 4239.64, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10123, 'st_id': 5539, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4229.75, 'leverage': 100, 'uptime': 1764828448, 'liquidation_price': 4441.2375, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.7, 'asset': 'USDT', 'asset_num': 4229.75, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10125, 'st_id': 5540, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4220.02, 'leverage': 100, 'uptime': 1764828451, 'liquidation_price': 4431.021000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 35.98, 'asset': 'USDT', 'asset_num': 4220.02, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10125, 'st_id': 5540, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.66, 'leverage': 100, 'uptime': 1764828451, 'liquidation_price': 4451.643, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.62, 'asset': 'USDT', 'asset_num': 4239.66, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10125, 'st_id': 5540, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4239.8, 'leverage': 100, 'uptime': 1764828451, 'liquidation_price': 4451.79, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.76, 'asset': 'USDT', 'asset_num': 4239.8, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10125, 'st_id': 5540, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4229.55, 'leverage': 100, 'uptime': 1764828451, 'liquidation_price': 4441.0275, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.51, 'asset': 'USDT', 'asset_num': 4229.55, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4252.18, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.789000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.81, 'asset': 'USDT', 'asset_num': 4252.18, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4251.59, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.1695, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.22, 'asset': 'USDT', 'asset_num': 4251.59, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4252.64, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4465.272000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.27, 'asset': 'USDT', 'asset_num': 4252.64, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4252.46, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4465.0830000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.09, 'asset': 'USDT', 'asset_num': 4252.46, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_4', 'price': 4252.4, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4465.0199999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.03, 'asset': 'USDT', 'asset_num': 4252.4, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_5', 'price': 4251.83, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.4215, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.46, 'asset': 'USDT', 'asset_num': 4251.83, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_6', 'price': 4252.31, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.9255, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.94, 'asset': 'USDT', 'asset_num': 4252.31, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_7', 'price': 4251.99, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4464.5895, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.62, 'asset': 'USDT', 'asset_num': 4251.99, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_8', 'price': 4252.46, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4465.0830000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.09, 'asset': 'USDT', 'asset_num': 4252.46, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_9', 'price': 4235.22, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4446.981000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 50.85, 'asset': 'USDT', 'asset_num': 4235.22, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_10', 'price': 4229.4, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4440.87, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.03, 'asset': 'USDT', 'asset_num': 4229.4, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_11', 'price': 4232.32, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4443.936, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.95, 'asset': 'USDT', 'asset_num': 4232.32, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_12', 'price': 4231.73, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4443.3165, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.36, 'asset': 'USDT', 'asset_num': 4231.73, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_13', 'price': 4232.38, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4443.999000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.01, 'asset': 'USDT', 'asset_num': 4232.38, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10131, 'st_id': 5543, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_14', 'price': 4232.95, 'leverage': 100, 'uptime': 1764828457, 'liquidation_price': 4444.5975, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.58, 'asset': 'USDT', 'asset_num': 4232.95, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4252.98, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.629, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 69.1, 'asset': 'USDT', 'asset_num': 4252.98, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4251.6, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4464.18, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.72, 'asset': 'USDT', 'asset_num': 4251.6, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_2', 'price': 4252.58, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.209, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.7, 'asset': 'USDT', 'asset_num': 4252.58, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_3', 'price': 4252.44, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.062, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.56, 'asset': 'USDT', 'asset_num': 4252.44, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_4', 'price': 4251.83, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4464.4215, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 67.95, 'asset': 'USDT', 'asset_num': 4251.83, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_5', 'price': 4251.99, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4464.5895, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.11, 'asset': 'USDT', 'asset_num': 4251.99, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_6', 'price': 4252.99, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.6395, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 69.11, 'asset': 'USDT', 'asset_num': 4252.99, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_7', 'price': 4252.46, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.0830000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 68.58, 'asset': 'USDT', 'asset_num': 4252.46, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_8', 'price': 4253.18, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4465.839000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 69.3, 'asset': 'USDT', 'asset_num': 4253.18, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_9', 'price': 4241.25, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4453.3125, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 57.37, 'asset': 'USDT', 'asset_num': 4241.25, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_10', 'price': 4241.24, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4453.302, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 57.36, 'asset': 'USDT', 'asset_num': 4241.24, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_11', 'price': 4238.61, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4450.5405, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 54.73, 'asset': 'USDT', 'asset_num': 4238.61, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_12', 'price': 4229.75, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4441.2375, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.87, 'asset': 'USDT', 'asset_num': 4229.75, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_13', 'price': 4232.45, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4444.0725, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.57, 'asset': 'USDT', 'asset_num': 4232.45, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_14', 'price': 4232.3, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.915, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.42, 'asset': 'USDT', 'asset_num': 4232.3, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_15', 'price': 4232.25, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.8625, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.37, 'asset': 'USDT', 'asset_num': 4232.25, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_16', 'price': 4232.38, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.999000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.5, 'asset': 'USDT', 'asset_num': 4232.38, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_17', 'price': 4232.38, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.999000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.5, 'asset': 'USDT', 'asset_num': 4232.38, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_18', 'price': 4232.72, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4444.356000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 48.84, 'asset': 'USDT', 'asset_num': 4232.72, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_19', 'price': 4232.93, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4444.5765, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 49.05, 'asset': 'USDT', 'asset_num': 4232.93, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_20', 'price': 4231.73, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4443.3165, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 47.85, 'asset': 'USDT', 'asset_num': 4231.73, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_21', 'price': 4227.03, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4438.3814999999995, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 43.15, 'asset': 'USDT', 'asset_num': 4227.03, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10138, 'st_id': 5547, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_22', 'price': 4196.72, 'leverage': 100, 'uptime': 1764828460, 'liquidation_price': 4406.5560000000005, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 12.84, 'asset': 'USDT', 'asset_num': 4196.72, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10140, 'st_id': 5548, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4219.79, 'leverage': 100, 'uptime': 1764828463, 'liquidation_price': 4430.779500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 36.3, 'asset': 'USDT', 'asset_num': 4219.79, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10140, 'st_id': 5548, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4239.06, 'leverage': 100, 'uptime': 1764828463, 'liquidation_price': 4451.013000000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 55.57, 'asset': 'USDT', 'asset_num': 4239.06, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10142, 'st_id': 5549, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4219.79, 'leverage': 100, 'uptime': 1764828465, 'liquidation_price': 4430.779500000001, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 36.47, 'asset': 'USDT', 'asset_num': 4219.79, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10144, 'st_id': 5550, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_0', 'price': 4230.53, 'leverage': 100, 'uptime': 1764828405, 'liquidation_price': 4442.0565, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 45.35, 'asset': 'USDT', 'asset_num': 4230.53, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 10144, 'st_id': 5550, 'side': 'sell', 'qty': 0.01, 'symbol': 'XAUUSD+_1', 'price': 4238.96, 'leverage': 100, 'uptime': 1764828405, 'liquidation_price': 4450.908, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 53.78, 'asset': 'USDT', 'asset_num': 4238.96, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 88887, 'st_id': 88882, 'side': 'sell', 'qty': 0.08, 'symbol': 'XAUAUD+_0', 'price': 6326.33, 'leverage': 100, 'uptime': 1764828408, 'liquidation_price': 6642.6465, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 0.0, 'asset': 'USDT', 'asset_num': 50610.64, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | ERROR | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:331 - 处理持仓数据失败: {'k_id': 88887, 'st_id': 88882, 'side': 'sell', 'qty': 0.08, 'symbol': 'XAUAUD+_1', 'price': 6325.7, 'leverage': 100, 'uptime': 1764828408, 'liquidation_price': 6641.985, 'profit_price': 0.0, 'stop_price': 0.0, 'asset_profit': 0.0, 'asset': 'USDT', 'asset_num': 50605.6, 'exchange_id': 'mt5'}, error='PositionSyncBatch' object has no attribute '_convert_position_data' +2025-12-04 16:53:12 | INFO | sync.position_sync:sync_batch:37 - 持仓批量同步完成: 处理 0 条,受影响 0 条,删除 0 条,耗时 0.01秒 +2025-12-04 16:53:12 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.01秒 | 平均耗时: 0.00秒 +2025-12-04 16:53:12 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.01 秒,等待 20 秒 +2025-12-04 16:53:14 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 16:53:32 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 16:55:45 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 16:55:45 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 16:55:45 | INFO | utils.redis_client:_get_computer_names:87 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 16:55:45 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 16:55:45 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 16:55:45 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 16:55:45 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 16:55:45 | INFO | utils.redis_client:_init_connection_pool:51 - Redis连接池初始化成功 +2025-12-04 16:55:45 | INFO | utils.redis_client:_get_accounts_by_computer_name:105 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 16:55:45 | INFO | utils.redis_client:_get_accounts_by_computer_name:130 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 16:55:45 | INFO | utils.redis_client:get_accounts_from_redis:74 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 16:55:45 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 16:55:45 | INFO | sync.position_sync:sync_batch:19 - 开始批量同步持仓数据,共 22 个账号 +2025-12-04 16:55:45 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 16:55:45 | INFO | sync.position_sync:sync_batch:31 - 收集到 92 条持仓数据 +2025-12-04 16:55:45 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:340 - 准备同步 92 条持仓数据,去重后 92 条唯一记录 +2025-12-04 16:55:45 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:370 - UPSERT完成: 总数 92 条, 受影响 92 条 +2025-12-04 16:55:45 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:403 - 删除 0 条过期持仓 +2025-12-04 16:55:45 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:407 - 批量同步V3完成: 总数=92, 受影响=92, 删除=0 +2025-12-04 16:55:45 | INFO | sync.position_sync:sync_batch:38 - 持仓批量同步完成: 处理 92 条,受影响 92 条,删除 0 条,耗时 0.01秒 +2025-12-04 16:55:45 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.01秒 | 平均耗时: 0.00秒 +2025-12-04 16:55:45 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.01 秒,等待 20 秒 +2025-12-04 16:55:49 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 16:56:05 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 16:57:13 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 16:57:13 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 16:57:13 | INFO | utils.redis_client:_get_computer_names:87 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 16:57:13 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 16:57:13 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 16:57:13 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 16:57:13 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 16:57:13 | INFO | utils.redis_client:_init_connection_pool:51 - Redis连接池初始化成功 +2025-12-04 16:57:13 | INFO | utils.redis_client:_get_accounts_by_computer_name:105 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 16:57:13 | INFO | utils.redis_client:_get_accounts_by_computer_name:130 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 16:57:13 | INFO | utils.redis_client:get_accounts_from_redis:74 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 16:57:13 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 16:57:13 | INFO | sync.position_sync:sync_batch:19 - 开始批量同步持仓数据,共 22 个账号 +2025-12-04 16:57:13 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 16:57:13 | INFO | sync.position_sync:sync_batch:31 - 收集到 92 条持仓数据 +2025-12-04 16:57:13 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:340 - 准备同步 92 条持仓数据,去重后 92 条唯一记录 +2025-12-04 16:57:13 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:370 - UPSERT完成: 总数 92 条, 受影响 92 条 +2025-12-04 16:57:13 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:403 - 删除 0 条过期持仓 +2025-12-04 16:57:13 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:407 - 批量同步V3完成: 总数=92, 受影响=92, 删除=0 +2025-12-04 16:57:13 | INFO | sync.position_sync:sync_batch:38 - 持仓批量同步完成: 处理 92 条,受影响 92 条,删除 0 条,耗时 0.01秒 +2025-12-04 16:57:13 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.02秒 | 平均耗时: 0.00秒 +2025-12-04 16:57:13 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.02 秒,等待 20 秒 +2025-12-04 16:57:18 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 16:57:33 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 17:04:25 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 17:04:25 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 17:04:25 | INFO | utils.redis_client:_get_computer_names:87 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 17:04:25 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 17:04:25 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 17:04:25 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 17:04:25 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 17:04:25 | INFO | utils.redis_client:_init_connection_pool:51 - Redis连接池初始化成功 +2025-12-04 17:04:25 | INFO | utils.redis_client:_get_accounts_by_computer_name:105 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 17:04:25 | INFO | utils.redis_client:_get_accounts_by_computer_name:130 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 17:04:25 | INFO | utils.redis_client:get_accounts_from_redis:74 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 17:04:25 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 17:04:25 | INFO | sync.position_sync:sync_batch:19 - 开始批量同步持仓数据,共 22 个账号 +2025-12-04 17:04:25 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 17:04:25 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10106, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10113, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10114, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10122, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10124, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10130, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10132, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10137, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10139, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10141, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=999999, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10107, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10115, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10123, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10125, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10129, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10131, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10138, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10140, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10142, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10144, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=88887, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:04:25 | INFO | utils.redis_client:_collect_all_account_data:346 - 收集到 0 条账户信息记录 +2025-12-04 17:04:25 | INFO | sync.position_sync:sync_batch:31 - 收集到 92 条持仓数据 +2025-12-04 17:04:25 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:340 - 准备同步 92 条持仓数据,去重后 92 条唯一记录 +2025-12-04 17:04:25 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:370 - UPSERT完成: 总数 92 条, 受影响 92 条 +2025-12-04 17:04:25 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:403 - 删除 0 条过期持仓 +2025-12-04 17:04:25 | INFO | sync.position_sync:_sync_positions_batch_to_db_optimized_v3:407 - 批量同步V3完成: 总数=92, 受影响=92, 删除=0 +2025-12-04 17:04:25 | INFO | sync.position_sync:sync_batch:38 - 持仓批量同步完成: 处理 92 条,受影响 92 条,删除 0 条,耗时 0.02秒 +2025-12-04 17:04:25 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.02秒 | 平均耗时: 0.00秒 +2025-12-04 17:04:25 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.02 秒,等待 20 秒 +2025-12-04 17:04:30 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 17:04:45 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 17:05:03 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 17:05:03 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 17:05:03 | INFO | utils.redis_client:_get_computer_names:87 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 17:05:03 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 17:05:03 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 17:05:03 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 17:05:03 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 17:05:03 | INFO | utils.redis_client:_init_connection_pool:51 - Redis连接池初始化成功 +2025-12-04 17:05:03 | INFO | utils.redis_client:_get_accounts_by_computer_name:105 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 17:05:03 | INFO | utils.redis_client:_get_accounts_by_computer_name:130 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 17:05:03 | INFO | utils.redis_client:get_accounts_from_redis:74 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 17:05:03 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 17:05:03 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 17:05:03 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10106, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10113, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10114, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10122, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10124, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10130, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10132, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10137, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10139, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10141, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=999999, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10107, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10115, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10123, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10125, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10129, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10131, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10138, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10140, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10142, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=10144, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | ERROR | utils.redis_client:_get_account_info_from_redis:469 - 获取Redis账户信息失败: k_id=88887, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:05:03 | INFO | utils.redis_client:_collect_all_account_data:346 - 收集到 0 条账户信息记录 +2025-12-04 17:05:03 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 17:05:03 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 17:05:05 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 17:05:23 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 17:06:09 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 17:06:09 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 17:06:09 | INFO | utils.redis_client:_get_computer_names:88 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 17:06:09 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 17:06:09 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 17:06:09 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 17:06:09 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 17:06:09 | INFO | utils.redis_client:_init_connection_pool:52 - Redis连接池初始化成功 +2025-12-04 17:06:09 | INFO | utils.redis_client:_get_accounts_by_computer_name:106 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 17:06:09 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 17:06:09 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 17:06:09 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 17:06:09 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 17:06:09 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10106, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10113, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10114, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10122, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10124, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10130, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10132, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10137, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10139, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10141, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=999999, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10107, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10115, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10123, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10125, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10129, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10131, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10138, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10140, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10142, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=10144, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | ERROR | utils.redis_client:_get_account_info_from_redis:470 - 获取Redis账户信息失败: k_id=88887, error='RedisClient' object has no attribute 'redis_client' +2025-12-04 17:06:09 | INFO | utils.redis_client:_collect_all_account_data:347 - 收集到 0 条账户信息记录 +2025-12-04 17:06:09 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 17:06:09 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 17:06:11 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 17:06:29 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 17:06:48 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 17:06:48 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 17:06:48 | INFO | utils.redis_client:_get_computer_names:88 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 17:06:48 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 17:06:48 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 17:06:48 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 17:06:48 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 17:06:48 | INFO | utils.redis_client:_init_connection_pool:52 - Redis连接池初始化成功 +2025-12-04 17:06:48 | INFO | utils.redis_client:_get_accounts_by_computer_name:106 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 17:06:48 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 17:06:48 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 17:06:48 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 17:06:48 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 17:06:48 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 17:06:48 | INFO | utils.redis_client:_collect_all_account_data:347 - 收集到 51 条账户信息记录 +2025-12-04 17:06:48 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.02秒 | 平均耗时: 0.00秒 +2025-12-04 17:06:48 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.02 秒,等待 20 秒 +2025-12-04 17:06:50 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 17:07:08 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 18:24:49 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 18:24:49 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 18:24:49 | INFO | utils.redis_client:_get_computer_names:88 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 18:24:49 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 18:24:49 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 18:24:49 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 18:24:49 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 18:24:49 | INFO | utils.redis_client:_init_connection_pool:52 - Redis连接池初始化成功 +2025-12-04 18:24:49 | INFO | utils.redis_client:_get_accounts_by_computer_name:106 - 从 lz_c01_strategy_api 获取到 2 个交易所配置 +2025-12-04 18:24:49 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 18:24:49 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 18:24:49 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 18:24:49 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 18:24:49 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 18:24:49 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 18:24:49 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 18:24:51 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 18:25:09 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 18:32:05 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 18:32:05 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 18:32:05 | INFO | utils.redis_client:_get_computer_names:88 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 18:32:05 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 18:32:05 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 18:32:05 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 18:32:05 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 18:32:05 | INFO | utils.redis_client:_init_connection_pool:52 - Redis连接池初始化成功 +2025-12-04 18:32:05 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 18:32:05 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 18:32:05 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 18:32:05 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 18:32:05 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 18:32:05 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 18:32:05 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 18:32:14 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 18:32:25 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 19:00:43 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 19:00:43 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 19:00:43 | INFO | utils.redis_client:_get_computer_names:88 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 19:00:43 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 19:00:43 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 19:00:43 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 19:00:43 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 19:00:43 | INFO | utils.redis_client:_init_connection_pool:52 - Redis连接池初始化成功 +2025-12-04 19:00:43 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:00:43 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:00:43 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 19:00:43 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:00:43 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:00:43 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 19:00:43 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 19:01:03 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:01:03 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:01:03 | INFO | sync.manager:start:81 - 第2次同步开始,共 22 个账号 +2025-12-04 19:01:03 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:01:03 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:01:03 | INFO | sync.manager:_update_stats:142 - === 第2次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 19:01:03 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 19:01:23 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:01:23 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:01:23 | INFO | sync.manager:start:81 - 第3次同步开始,共 22 个账号 +2025-12-04 19:01:23 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:01:23 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:01:23 | INFO | sync.manager:_update_stats:142 - === 第3次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 19:01:23 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 19:01:43 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:01:43 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:01:43 | INFO | sync.manager:start:81 - 第4次同步开始,共 22 个账号 +2025-12-04 19:01:43 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:01:43 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:01:43 | INFO | sync.manager:_update_stats:142 - === 第4次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 19:01:43 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 19:02:03 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:02:03 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:02:03 | INFO | sync.manager:start:81 - 第5次同步开始,共 22 个账号 +2025-12-04 19:02:03 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:02:03 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:02:03 | INFO | sync.manager:_update_stats:142 - === 第5次同步统计 === +总耗时: 0.00秒 | 平均耗时: 0.00秒 +2025-12-04 19:02:03 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.00 秒,等待 20 秒 +2025-12-04 19:02:20 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 19:02:23 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 19:29:34 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 19:29:34 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 19:29:34 | INFO | utils.redis_client:_get_computer_names:88 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 19:29:34 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 19:29:34 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 19:29:34 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 19:29:34 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 19:29:34 | INFO | utils.redis_client:_init_connection_pool:52 - Redis连接池初始化成功 +2025-12-04 19:29:34 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:29:34 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:29:34 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 19:29:34 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:29:34 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:29:34 | INFO | utils.redis_client:_collect_all_account_data:347 - 收集到 86 条账户信息记录 +2025-12-04 19:29:34 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.04秒 | 平均耗时: 0.00秒 +2025-12-04 19:29:34 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.04 秒,等待 20 秒 +2025-12-04 19:29:54 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:29:54 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:29:54 | INFO | sync.manager:start:81 - 第2次同步开始,共 22 个账号 +2025-12-04 19:29:54 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:29:54 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:29:54 | INFO | utils.redis_client:_collect_all_account_data:347 - 收集到 86 条账户信息记录 +2025-12-04 19:29:54 | INFO | sync.manager:_update_stats:142 - === 第2次同步统计 === +总耗时: 0.04秒 | 平均耗时: 0.01秒 +2025-12-04 19:29:54 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.04 秒,等待 20 秒 +2025-12-04 19:30:14 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:30:14 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:30:14 | INFO | sync.manager:start:81 - 第3次同步开始,共 22 个账号 +2025-12-04 19:30:14 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:30:14 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:30:14 | INFO | utils.redis_client:_collect_all_account_data:347 - 收集到 86 条账户信息记录 +2025-12-04 19:30:14 | INFO | sync.manager:_update_stats:142 - === 第3次同步统计 === +总耗时: 0.05秒 | 平均耗时: 0.01秒 +2025-12-04 19:30:14 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.05 秒,等待 20 秒 +2025-12-04 19:30:34 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:30:34 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:30:34 | INFO | sync.manager:start:81 - 第4次同步开始,共 22 个账号 +2025-12-04 19:30:34 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:30:34 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:30:34 | INFO | utils.redis_client:_collect_all_account_data:347 - 收集到 86 条账户信息记录 +2025-12-04 19:30:34 | INFO | sync.manager:_update_stats:142 - === 第4次同步统计 === +总耗时: 0.04秒 | 平均耗时: 0.01秒 +2025-12-04 19:30:34 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.04 秒,等待 20 秒 +2025-12-04 19:30:54 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:30:54 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:30:54 | INFO | sync.manager:start:81 - 第5次同步开始,共 22 个账号 +2025-12-04 19:30:54 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:30:54 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:30:54 | INFO | utils.redis_client:_collect_all_account_data:347 - 收集到 86 条账户信息记录 +2025-12-04 19:30:54 | INFO | sync.manager:_update_stats:142 - === 第5次同步统计 === +总耗时: 0.04秒 | 平均耗时: 0.02秒 +2025-12-04 19:30:54 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.04 秒,等待 20 秒 +2025-12-04 19:30:58 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 19:31:14 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === +2025-12-04 19:37:54 | INFO | __main__:main:27 - === 交易所数据同步服务启动 === +2025-12-04 19:37:54 | INFO | __main__:main:28 - 工作目录: /root/project/exchange_monitor_sync +2025-12-04 19:37:54 | INFO | utils.redis_client:_get_computer_names:88 - 使用配置的计算机名列表: ['lz_c01', 'lz_c02'] +2025-12-04 19:37:54 | INFO | sync.manager:__init__:36 - 启用持仓批量同步 +2025-12-04 19:37:54 | INFO | sync.manager:__init__:41 - 启用订单批量同步 +2025-12-04 19:37:54 | INFO | sync.manager:__init__:46 - 启用账户信息批量同步 +2025-12-04 19:37:54 | INFO | sync.manager:start:64 - 同步服务启动,间隔 20 秒 +2025-12-04 19:37:54 | INFO | utils.redis_client:_init_connection_pool:52 - Redis连接池初始化成功 +2025-12-04 19:37:54 | INFO | utils.redis_client:_get_accounts_by_computer_name:131 - 从 lz_c01_strategy_api 解析到 22 个账号 +2025-12-04 19:37:54 | INFO | utils.redis_client:get_accounts_from_redis:75 - 从 2 个计算机名获取到 22 个账号 +2025-12-04 19:37:54 | INFO | sync.manager:start:81 - 第1次同步开始,共 22 个账号 +2025-12-04 19:37:54 | INFO | sync.order_sync:sync_batch:22 - 开始批量同步订单数据,共 22 个账号 +2025-12-04 19:37:54 | INFO | sync.account_sync:sync_batch:16 - 开始批量同步账户信息,共 22 个账号 +2025-12-04 19:37:54 | INFO | utils.redis_client:_collect_all_account_data:347 - 收集到 86 条账户信息记录 +2025-12-04 19:37:54 | INFO | sync.account_sync:_batch_upsert_account_info:100 - 原生SQL批量更新账户信息: 86 条记录 +2025-12-04 19:37:54 | INFO | sync.account_sync:sync_batch:34 - 账户信息批量同步完成: 处理 86 条记录 +2025-12-04 19:37:54 | INFO | sync.manager:_update_stats:142 - === 第1次同步统计 === +总耗时: 0.05秒 | 平均耗时: 0.00秒 +2025-12-04 19:37:54 | INFO | sync.manager:start:92 - 同步完成,总耗时 0.05 秒,等待 20 秒 +2025-12-04 19:38:05 | INFO | sync.manager:signal_handler:146 - 接收到信号 2,正在关闭... +2025-12-04 19:38:14 | INFO | __main__:main:41 - === 交易所数据同步服务停止 === diff --git a/sync/__pycache__/account_sync.cpython-311.pyc b/sync/__pycache__/account_sync.cpython-311.pyc index d3bfb8d806c49440a27092717cebe0b35c9fc0f5..924a14605f16b6642b760808a7261f364a6bbf2f 100644 GIT binary patch delta 1731 zcmZ`)TTC2P7(R2|Wp50IEVo@?TNYSgk;_Ucl-&g?7@`#f+ejbCcIO}i!w$|2qLl_o ziTYqnlhf41#6(||#u_!NPsRt^_~yfIvq_sVUS3R$FK$yG8h!EnvxOF1&YXPnU(WxZ z?|eDC^Xp~i-jwfCuh)g>@V?TkTn~KZ3o~vJd^+xbjYyn{Zt>WG`MOe!qAXzNA}@;9E&dX_$r^r>*{6(__idT~gxa6&`wXp{MVsg& zfz0$&lTN49b)Xfu$?0uJv=U5#gq*=i@k6d$(*sp|q9WN*ZtZbo`pA1+kP)*txHC+X zQx_n#HL&V|jEeE5<@vRdB{6ZsAYw5Iw{n^m!8%`C7t?;jN+%wRRN319!sH zx5Lx9nV0h6`9gR;*Yv;X2^2+C-BLuXx8`Tbf7P7}B=SwjT@ujdXl|*S}I6OxxM*2 z-O-Z^j^w3yL5k=0CfRn!i7Hl|4%4&mj5dr7qwhnbEPdS!R|5{a#@o1CLe2Ow?$$AZ z+E!I6oz~Vf=7O9uQwyqMn3kwxb6wA5pE&-2jn~sowv;+ttcajDKp;fHav0b!6fL6% zA=F600L`0W=uHr-C6%!nvd|i2IPlMv~T_SD%NEA}`(;@M6%qdm-6_VegnzNH)1M*(60PXhD+^aAt& z^pop-*Sami2=~#iGWa|e$V40`LH-lQI%@%lDLdr0(c{Gg}dH!VA)&MX%0Wb*QflB8h zHq%QfRn-p(;DaU40z3y$Ru4!Vx+%WL4mbw+NeY%Ltz~4dV$y44Jlu#lh8l-QAnDMt zv96ki#p&9HJ^@9x9Kc{ti_*KKNRq}cc9ZRBEis4uEJ4|KhnCs8W*UyLrR}SzZLk#J zN|MTvX7)QodPkmd-ls8iCL)pTk-@oUYU}U^WAPU>P1S3`ZwH7#P%zimRIJ-VBq4eh zAOUa=z`pAeSOD-fF#biPCtlrNFN`v~)w}60W4p?YrXm8r44xuyCvGz5$W(INY4OVj v{Y}Nl)#PaX!9D(Qo?6x9brr{TO#VuKG5RXYv=>o%yz<&TJM;Gud7JuwhRTtg literal 16863 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 z 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 diff --git a/sync/account_sync.py b/sync/account_sync.py index 9a7fb7d..063474f 100644 --- a/sync/account_sync.py +++ b/sync/account_sync.py @@ -14,8 +14,14 @@ class AccountSyncBatch(BaseSync): """批量同步所有账号的账户信息""" try: logger.info(f"开始批量同步账户信息,共 {len(accounts)} 个账号") + + # 测试 + # res = await self.redis_client._get_account_info_from_redis(10140, 5548, 'mt5') + # print(res) + # return # 收集所有账号的数据 - all_account_data = await self._collect_all_account_data(accounts) + all_account_data = await self.redis_client._collect_all_account_data(accounts) + if not all_account_data: logger.info("无账户信息数据需要同步") @@ -32,187 +38,8 @@ class AccountSyncBatch(BaseSync): except Exception as e: logger.error(f"账户信息批量同步失败: {e}") - async def _collect_all_account_data(self, accounts: Dict[str, Dict]) -> List[Dict]: - """收集所有账号的账户信息数据""" - all_account_data = [] - - try: - # 按交易所分组账号 - account_groups = self._group_accounts_by_exchange(accounts) - - # 并发收集每个交易所的数据 - tasks = [] - for exchange_id, account_list in account_groups.items(): - task = self._collect_exchange_account_data(exchange_id, account_list) - tasks.append(task) - - # 等待所有任务完成并合并结果 - results = await asyncio.gather(*tasks, return_exceptions=True) - - for result in results: - if isinstance(result, list): - all_account_data.extend(result) - - logger.info(f"收集到 {len(all_account_data)} 条账户信息记录") - - except Exception as e: - logger.error(f"收集账户信息数据失败: {e}") - - return all_account_data - - def _group_accounts_by_exchange(self, accounts: Dict[str, Dict]) -> Dict[str, List[Dict]]: - """按交易所分组账号""" - groups = {} - for account_id, account_info in accounts.items(): - exchange_id = account_info.get('exchange_id') - if exchange_id: - if exchange_id not in groups: - groups[exchange_id] = [] - groups[exchange_id].append(account_info) - return groups - - async def _collect_exchange_account_data(self, exchange_id: str, account_list: List[Dict]) -> List[Dict]: - """收集某个交易所的账户信息数据""" - account_data_list = [] - - try: - for account_info in account_list: - k_id = int(account_info['k_id']) - st_id = account_info.get('st_id', 0) - - # 从Redis获取账户信息数据 - account_data = await self._get_account_info_from_redis(k_id, st_id, exchange_id) - account_data_list.extend(account_data) - - logger.debug(f"交易所 {exchange_id}: 收集到 {len(account_data_list)} 条账户信息") - - except Exception as e: - logger.error(f"收集交易所 {exchange_id} 账户信息失败: {e}") - - return account_data_list - - async def _get_account_info_from_redis(self, k_id: int, st_id: int, exchange_id: str) -> List[Dict]: - """从Redis获取账户信息数据(批量优化版本)""" - try: - redis_key = f"{exchange_id}:balance:{k_id}" - redis_funds = self.redis_client.client.hgetall(redis_key) - - if not redis_funds: - return [] - - # 按天统计数据 - from config.settings import SYNC_CONFIG - recent_days = SYNC_CONFIG['recent_days'] - - today = datetime.now() - date_stats = {} - - # 收集所有日期的数据 - for fund_key, fund_json in redis_funds.items(): - try: - fund_data = json.loads(fund_json) - date_str = fund_data.get('lz_time', '') - lz_type = fund_data.get('lz_type', '') - - if not date_str or lz_type not in ['lz_balance', 'deposit', 'withdrawal']: - continue - - # 只处理最近N天的数据 - date_obj = datetime.strptime(date_str, '%Y-%m-%d') - if (today - date_obj).days > recent_days: - continue - - if date_str not in date_stats: - date_stats[date_str] = { - 'balance': 0.0, - 'deposit': 0.0, - 'withdrawal': 0.0, - 'has_balance': False - } - - lz_amount = float(fund_data.get('lz_amount', 0)) - - if lz_type == 'lz_balance': - date_stats[date_str]['balance'] = lz_amount - date_stats[date_str]['has_balance'] = True - elif lz_type == 'deposit': - date_stats[date_str]['deposit'] += lz_amount - elif lz_type == 'withdrawal': - date_stats[date_str]['withdrawal'] += lz_amount - - except (json.JSONDecodeError, ValueError) as e: - logger.debug(f"解析Redis数据失败: {fund_key}, error={e}") - continue - - # 转换为账户信息数据 - account_data_list = [] - sorted_dates = sorted(date_stats.keys()) - - # 获取前一天余额用于计算利润 - prev_balance_map = self._get_previous_balances(redis_funds, sorted_dates) - - for date_str in sorted_dates: - stats = date_stats[date_str] - - # 如果没有余额数据但有充提数据,仍然处理 - if not stats['has_balance'] and stats['deposit'] == 0 and stats['withdrawal'] == 0: - continue - - balance = stats['balance'] - deposit = stats['deposit'] - withdrawal = stats['withdrawal'] - - # 计算利润 - prev_balance = prev_balance_map.get(date_str, 0.0) - profit = balance - deposit - withdrawal - prev_balance - - # 转换时间戳 - date_obj = datetime.strptime(date_str, '%Y-%m-%d') - time_timestamp = int(date_obj.timestamp()) - - account_data = { - 'st_id': st_id, - 'k_id': k_id, - 'balance': balance, - 'withdrawal': withdrawal, - 'deposit': deposit, - 'other': 0.0, # 暂时为0 - 'profit': profit, - 'time': time_timestamp - } - - account_data_list.append(account_data) - - return account_data_list - - except Exception as e: - logger.error(f"获取Redis账户信息失败: k_id={k_id}, error={e}") - return [] - - def _get_previous_balances(self, redis_funds: Dict, sorted_dates: List[str]) -> Dict[str, float]: - """获取前一天的余额""" - prev_balance_map = {} - prev_date = None - - for date_str in sorted_dates: - # 查找前一天的余额 - if prev_date: - for fund_key, fund_json in redis_funds.items(): - try: - fund_data = json.loads(fund_json) - if (fund_data.get('lz_time') == prev_date and - fund_data.get('lz_type') == 'lz_balance'): - prev_balance_map[date_str] = float(fund_data.get('lz_amount', 0)) - break - except: - continue - else: - prev_balance_map[date_str] = 0.0 - - prev_date = date_str - - return prev_balance_map - + + async def _sync_account_info_batch_to_db(self, account_data_list: List[Dict]) -> bool: """批量同步账户信息到数据库(最高效版本)""" session = self.db_manager.get_session() diff --git a/sync/base_sync.py b/sync/base_sync.py index 802eeed..80636d3 100644 --- a/sync/base_sync.py +++ b/sync/base_sync.py @@ -24,11 +24,6 @@ class BaseSync(ABC): 'avg_sync_time': 0 } - - @abstractmethod - async def sync(self): - """执行同步(兼容旧接口)""" - pass @abstractmethod async def sync_batch(self, accounts: Dict[str, Dict]): diff --git a/sync/manager.py b/sync/manager.py index 45920ee..d0b5b73 100644 --- a/sync/manager.py +++ b/sync/manager.py @@ -5,7 +5,6 @@ import sys import time import json from typing import Dict -import re import utils.helpers as helpers from utils.redis_client import RedisClient @@ -24,8 +23,6 @@ class SyncManager: self.is_running = True self.redis_client = RedisClient() self.sync_interval = SYNC_CONFIG['interval'] - self.computer_names = self._get_computer_names() - self.computer_name_pattern = re.compile(COMPUTER_NAME_PATTERN) # 初始化批量同步工具 self.redis_helper = None @@ -70,7 +67,7 @@ class SyncManager: try: # 获取所有账号(只获取一次) - accounts = self.get_accounts_from_redis() + accounts = self.redis_client.get_accounts_from_redis() if not accounts: logger.warning("未获取到任何账号,等待下次同步") @@ -111,239 +108,6 @@ class SyncManager: logger.error("完整堆栈跟踪:\n{traceback}", traceback=error_details['traceback']) await asyncio.sleep(30) - def get_accounts_from_redis(self) -> Dict[str, Dict]: - """从Redis获取所有计算机名的账号配置""" - try: - accounts_dict = {} - total_keys_processed = 0 - - # 方法1:使用配置的计算机名列表 - for computer_name in self.computer_names: - accounts = self._get_accounts_by_computer_name(computer_name) - total_keys_processed += 1 - accounts_dict.update(accounts) - - # 方法2:如果配置的计算机名没有数据,尝试自动发现(备用方案) - if not accounts_dict: - logger.warning("配置的计算机名未找到数据,尝试自动发现...") - accounts_dict = self._discover_all_accounts() - - logger.info(f"从 {len(self.computer_names)} 个计算机名获取到 {len(accounts_dict)} 个账号") - - return accounts_dict - - except Exception as e: - logger.error(f"获取账户信息失败: {e}") - return {} - - def _get_computer_names(self) -> List[str]: - """获取计算机名列表""" - if ',' in COMPUTER_NAMES: - names = [name.strip() for name in COMPUTER_NAMES.split(',')] - logger.info(f"使用配置的计算机名列表: {names}") - return names - return [COMPUTER_NAMES.strip()] - - def _get_accounts_by_computer_name(self, computer_name: str) -> Dict[str, Dict]: - """获取指定计算机名的账号""" - accounts_dict = {} - - try: - # 构建key - redis_key = f"{computer_name}_strategy_api" - - # 从Redis获取数据 - result = self.redis_client.client.hgetall(redis_key) - if not result: - logger.debug(f"未找到 {redis_key} 的策略API配置") - return {} - - logger.info(f"从 {redis_key} 获取到 {len(result)} 个交易所配置") - - for exchange_name, accounts_json in result.items(): - try: - accounts = json.loads(accounts_json) - if not accounts: - continue - - # 格式化交易所ID - exchange_id = self.format_exchange_id(exchange_name) - - for account_id, account_info in accounts.items(): - parsed_account = self.parse_account(exchange_id, account_id, account_info) - if parsed_account: - # 添加计算机名标记 - parsed_account['computer_name'] = computer_name - accounts_dict[account_id] = parsed_account - - except json.JSONDecodeError as e: - logger.error(f"解析交易所 {exchange_name} 的JSON数据失败: {e}") - continue - except Exception as e: - logger.error(f"处理交易所 {exchange_name} 数据异常: {e}") - continue - - logger.info(f"从 {redis_key} 解析到 {len(accounts_dict)} 个账号") - - except Exception as e: - logger.error(f"获取计算机名 {computer_name} 的账号失败: {e}") - - return accounts_dict - - def _discover_all_accounts(self) -> Dict[str, Dict]: - """自动发现所有匹配的账号key""" - accounts_dict = {} - discovered_keys = [] - - try: - # 获取所有匹配模式的key - pattern = "*_strategy_api" - cursor = 0 - - while True: - cursor, keys = self.redis_client.client.scan(cursor, match=pattern, count=100) - - for key in keys: - key_str = key.decode('utf-8') if isinstance(key, bytes) else key - discovered_keys.append(key_str) - - if cursor == 0: - break - - logger.info(f"自动发现 {len(discovered_keys)} 个策略API key") - - # 处理每个发现的key - for key_str in discovered_keys: - # 提取计算机名 - computer_name = key_str.replace('_strategy_api', '') - - # 验证计算机名格式 - if self.computer_name_pattern.match(computer_name): - accounts = self._get_accounts_by_computer_name(computer_name) - accounts_dict.update(accounts) - else: - logger.warning(f"跳过不符合格式的计算机名: {computer_name}") - - logger.info(f"自动发现共获取到 {len(accounts_dict)} 个账号") - - except Exception as e: - logger.error(f"自动发现账号失败: {e}") - - return accounts_dict - - def _discover_all_accounts(self) -> Dict[str, Dict]: - """自动发现所有匹配的账号key""" - accounts_dict = {} - discovered_keys = [] - - try: - # 获取所有匹配模式的key - pattern = "*_strategy_api" - cursor = 0 - - while True: - cursor, keys = self.redis_client.client.scan(cursor, match=pattern, count=100) - - for key in keys: - key_str = key.decode('utf-8') if isinstance(key, bytes) else key - discovered_keys.append(key_str) - - if cursor == 0: - break - - logger.info(f"自动发现 {len(discovered_keys)} 个策略API key") - - # 处理每个发现的key - for key_str in discovered_keys: - # 提取计算机名 - computer_name = key_str.replace('_strategy_api', '') - - # 验证计算机名格式 - if self.computer_name_pattern.match(computer_name): - accounts = self._get_accounts_by_computer_name(computer_name) - accounts_dict.update(accounts) - else: - logger.warning(f"跳过不符合格式的计算机名: {computer_name}") - - logger.info(f"自动发现共获取到 {len(accounts_dict)} 个账号") - - except Exception as e: - logger.error(f"自动发现账号失败: {e}") - - return accounts_dict - - def format_exchange_id(self, key: str) -> str: - """格式化交易所ID""" - key = key.lower().strip() - - # 交易所名称映射 - exchange_mapping = { - 'metatrader': 'mt5', - 'binance_spot_test': 'binance', - 'binance_spot': 'binance', - 'binance': 'binance', - 'gate_spot': 'gate', - 'okex': 'okx', - 'okx': 'okx', - 'bybit': 'bybit', - 'bybit_spot': 'bybit', - 'bybit_test': 'bybit', - 'huobi': 'huobi', - 'huobi_spot': 'huobi', - 'gate': 'gate', - 'gateio': 'gate', - 'kucoin': 'kucoin', - 'kucoin_spot': 'kucoin', - 'mexc': 'mexc', - 'mexc_spot': 'mexc', - 'bitget': 'bitget', - 'bitget_spot': 'bitget' - } - - normalized_key = exchange_mapping.get(key, key) - - # 记录未映射的交易所 - if normalized_key == key and key not in exchange_mapping.values(): - logger.debug(f"未映射的交易所名称: {key}") - - return normalized_key - - def parse_account(self, exchange_id: str, account_id: str, account_info: str) -> Optional[Dict]: - """解析账号信息""" - try: - source_account_info = json.loads(account_info) - # print(source_account_info) - # 基础信息 - account_data = { - 'exchange_id': exchange_id, - 'k_id': account_id, - 'st_id': helpers.safe_int(source_account_info.get('st_id'), 0), - 'add_time': helpers.safe_int(source_account_info.get('add_time'), 0), - 'api_key': source_account_info.get('api_key', ''), - } - - return account_data - - except json.JSONDecodeError as e: - logger.error(f"解析账号 {account_id} JSON数据失败: {e}, 原始数据: {account_info[:100]}...") - return None - except Exception as e: - logger.error(f"处理账号 {account_id} 数据异常: {e}") - return None - - def _group_accounts_by_exchange(self, accounts: Dict[str, Dict]) -> Dict[str, List[Dict]]: - """按交易所分组账号""" - groups = {} - for account_id, account_info in accounts.items(): - exchange_id = account_info.get('exchange_id') - if exchange_id: - if exchange_id not in groups: - groups[exchange_id] = [] - groups[exchange_id].append(account_info) - return groups - - - def _update_stats(self, sync_time: float): diff --git a/sync/position_sync.py b/sync/position_sync.py index bdfc0db..34d3666 100644 --- a/sync/position_sync.py +++ b/sync/position_sync.py @@ -1,12 +1,9 @@ from .base_sync import BaseSync from loguru import logger from typing import List, Dict, Any, Set, Tuple -import json -import asyncio -import utils.helpers as helpers -from datetime import datetime from sqlalchemy import text, and_, select, delete from models.orm_models import StrategyPosition +import utils.helpers as helpers import time class PositionSyncBatch(BaseSync): @@ -18,13 +15,15 @@ class PositionSyncBatch(BaseSync): async def sync_batch(self, accounts: Dict[str, Dict]): """批量同步所有账号的持仓数据""" + return try: logger.info(f"开始批量同步持仓数据,共 {len(accounts)} 个账号") start_time = time.time() # 1. 收集所有账号的持仓数据 - all_positions = await self._collect_all_positions(accounts) + all_positions = await self.redis_client._collect_all_positions(accounts) + if not all_positions: logger.info("无持仓数据需要同步") @@ -421,91 +420,6 @@ class PositionSyncBatch(BaseSync): finally: session.close() - async def _collect_all_positions(self, accounts: Dict[str, Dict]) -> List[Dict]: - """收集所有账号的持仓数据""" - all_positions = [] - - try: - # 按交易所分组账号 - account_groups = self._group_accounts_by_exchange(accounts) - - # 并发收集每个交易所的数据 - tasks = [] - for exchange_id, account_list in account_groups.items(): - task = self._collect_exchange_positions(exchange_id, account_list) - tasks.append(task) - - # 等待所有任务完成并合并结果 - results = await asyncio.gather(*tasks, return_exceptions=True) - - for result in results: - if isinstance(result, list): - all_positions.extend(result) - - except Exception as e: - logger.error(f"收集持仓数据失败: {e}") - - return all_positions - - def _group_accounts_by_exchange(self, accounts: Dict[str, Dict]) -> Dict[str, List[Dict]]: - """按交易所分组账号""" - groups = {} - for account_id, account_info in accounts.items(): - exchange_id = account_info.get('exchange_id') - if exchange_id: - if exchange_id not in groups: - groups[exchange_id] = [] - groups[exchange_id].append(account_info) - return groups - - async def _collect_exchange_positions(self, exchange_id: str, account_list: List[Dict]) -> List[Dict]: - """收集某个交易所的持仓数据""" - positions_list = [] - - try: - tasks = [] - for account_info in account_list: - k_id = int(account_info['k_id']) - st_id = account_info.get('st_id', 0) - task = self._get_positions_from_redis(k_id, st_id, exchange_id) - tasks.append(task) - - # 并发获取 - results = await asyncio.gather(*tasks, return_exceptions=True) - - for result in results: - if isinstance(result, list): - positions_list.extend(result) - - except Exception as e: - logger.error(f"收集交易所 {exchange_id} 持仓数据失败: {e}") - - return positions_list - - async def _get_positions_from_redis(self, k_id: int, st_id: int, exchange_id: str) -> List[Dict]: - """从Redis获取持仓数据""" - try: - redis_key = f"{exchange_id}:positions:{k_id}" - redis_data = self.redis_client.client.hget(redis_key, 'positions') - - if not redis_data: - return [] - - positions = json.loads(redis_data) - - # 添加账号信息 - for position in positions: - # print(position['symbol']) - position['k_id'] = k_id - position['st_id'] = st_id - position['exchange_id'] = exchange_id - - return positions - - except Exception as e: - logger.error(f"获取Redis持仓数据失败: k_id={k_id}, error={e}") - return [] - def _convert_position_data(self, data: Dict) -> Dict: """转换持仓数据格式""" try: @@ -531,7 +445,3 @@ class PositionSyncBatch(BaseSync): logger.error(f"转换持仓数据异常: {data}, error={e}") return {} - async def sync(self): - """兼容旧接口""" - accounts = self.get_accounts_from_redis() - await self.sync_batch(accounts) \ No newline at end of file diff --git a/utils/__pycache__/redis_client.cpython-311.pyc b/utils/__pycache__/redis_client.cpython-311.pyc index 5fdf82e1a85e2bc27d605fae3c912f5d3dee3501..e95d5ff6c9c814a77692b6eee0611309a032fc02 100644 GIT binary patch literal 23340 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 KU*#(4kpB;@m!Gl# delta 817 zcmZuvOHUI~6h3!e9j7k^#v)i-BM8Na(MC5KLZsT1keWbg!fdMPj5ucKG`DS{iAG{r zkmy3a3*sNp5ZsZt*M(bIuxR=Z+(;Exy78O=Oo-mcch9-sdEJxy;UoK!h`oH_op-Rx|Nv~v^3DMS`w8QSsQ?RdHi^0DFespM+z<#c;6g~v=gJ+zwJ zjwH8&)eWIRV8!F&TIkhi59Kl|Zq030s(!8JRGY3}3v%;b3V)dIdnma1hC4c;SmjEvbwH_T~JE7Dj!*(Sur@OhRLrSMPD zQ~Ep-cp2z(PzI--@nM1^h5Rlhr7Iu?<_lUJ$xKAJ^W#H0+0p0VCPGKAbHDEJ=40MZ zcL{)QpUqzLA+OQG2GGnX_k>y~Ddsbh5bPJBG Tu5y`WyYMgkpu4^Q5JB2M(Lc0E diff --git a/utils/redis_client.py b/utils/redis_client.py index 0f25831..c1f6e1e 100644 --- a/utils/redis_client.py +++ b/utils/redis_client.py @@ -1,6 +1,12 @@ +import asyncio import redis +import json +import re from loguru import logger -from config.settings import REDIS_CONFIG +from config.settings import REDIS_CONFIG, COMPUTER_NAMES, COMPUTER_NAME_PATTERN +import utils.helpers as helpers +from typing import List, Dict, Any, Set, Tuple, Optional +from datetime import datetime, timedelta class RedisClient: """Redis客户端管理器""" @@ -18,6 +24,8 @@ class RedisClient: self._pool = None self._client = None self._initialized = True + self.computer_names = self._get_computer_names() + self.computer_name_pattern = re.compile(COMPUTER_NAME_PATTERN) @property def client(self): @@ -47,6 +55,447 @@ class RedisClient: logger.error(f"Redis连接失败: {e}") raise + def get_accounts_from_redis(self) -> Dict[str, Dict]: + """从Redis获取所有计算机名的账号配置""" + try: + accounts_dict = {} + total_keys_processed = 0 + + # 方法1:使用配置的计算机名列表 + for computer_name in self.computer_names: + accounts = self._get_accounts_by_computer_name(computer_name) + total_keys_processed += 1 + accounts_dict.update(accounts) + + # 方法2:如果配置的计算机名没有数据,尝试自动发现(备用方案) + if not accounts_dict: + logger.warning("配置的计算机名未找到数据,尝试自动发现...") + accounts_dict = self._discover_all_accounts() + + logger.info(f"从 {len(self.computer_names)} 个计算机名获取到 {len(accounts_dict)} 个账号") + + return accounts_dict + + except Exception as e: + logger.error(f"获取账户信息失败: {e}") + return {} + + + def _get_computer_names(self) -> List[str]: + """获取计算机名列表""" + if ',' in COMPUTER_NAMES: + names = [name.strip() for name in COMPUTER_NAMES.split(',')] + logger.info(f"使用配置的计算机名列表: {names}") + return names + return [COMPUTER_NAMES.strip()] + + def _get_accounts_by_computer_name(self, computer_name: str) -> Dict[str, Dict]: + """获取指定计算机名的账号""" + accounts_dict = {} + + try: + # 构建key + redis_key = f"{computer_name}_strategy_api" + + # 从Redis获取数据 + result = self.client.hgetall(redis_key) + if not result: + logger.debug(f"未找到 {redis_key} 的策略API配置") + return {} + + # logger.info(f"从 {redis_key} 获取到 {len(result)} 个交易所配置") + + for exchange_name, accounts_json in result.items(): + try: + accounts = json.loads(accounts_json) + if not accounts: + continue + + # 格式化交易所ID + exchange_id = self.format_exchange_id(exchange_name) + + for account_id, account_info in accounts.items(): + parsed_account = self.parse_account(exchange_id, account_id, account_info) + if parsed_account: + # 添加计算机名标记 + parsed_account['computer_name'] = computer_name + accounts_dict[account_id] = parsed_account + + except json.JSONDecodeError as e: + logger.error(f"解析交易所 {exchange_name} 的JSON数据失败: {e}") + continue + except Exception as e: + logger.error(f"处理交易所 {exchange_name} 数据异常: {e}") + continue + + logger.info(f"从 {redis_key} 解析到 {len(accounts_dict)} 个账号") + + except Exception as e: + logger.error(f"获取计算机名 {computer_name} 的账号失败: {e}") + + return accounts_dict + + def _discover_all_accounts(self) -> Dict[str, Dict]: + """自动发现所有匹配的账号key""" + accounts_dict = {} + discovered_keys = [] + + try: + # 获取所有匹配模式的key + pattern = "*_strategy_api" + cursor = 0 + + while True: + cursor, keys = self.client.scan(cursor, match=pattern, count=100) + + for key in keys: + key_str = key.decode('utf-8') if isinstance(key, bytes) else key + discovered_keys.append(key_str) + + if cursor == 0: + break + + logger.info(f"自动发现 {len(discovered_keys)} 个策略API key") + + # 处理每个发现的key + for key_str in discovered_keys: + # 提取计算机名 + computer_name = key_str.replace('_strategy_api', '') + + # 验证计算机名格式 + if self.computer_name_pattern.match(computer_name): + accounts = self._get_accounts_by_computer_name(computer_name) + accounts_dict.update(accounts) + else: + logger.warning(f"跳过不符合格式的计算机名: {computer_name}") + + logger.info(f"自动发现共获取到 {len(accounts_dict)} 个账号") + + except Exception as e: + logger.error(f"自动发现账号失败: {e}") + + return accounts_dict + + + def format_exchange_id(self, key: str) -> str: + """格式化交易所ID""" + key = key.lower().strip() + + # 交易所名称映射 + exchange_mapping = { + 'metatrader': 'mt5', + 'binance_spot_test': 'binance', + 'binance_spot': 'binance', + 'binance': 'binance', + 'gate_spot': 'gate', + 'okex': 'okx', + 'okx': 'okx', + 'bybit': 'bybit', + 'bybit_spot': 'bybit', + 'bybit_test': 'bybit', + 'huobi': 'huobi', + 'huobi_spot': 'huobi', + 'gate': 'gate', + 'gateio': 'gate', + 'kucoin': 'kucoin', + 'kucoin_spot': 'kucoin', + 'mexc': 'mexc', + 'mexc_spot': 'mexc', + 'bitget': 'bitget', + 'bitget_spot': 'bitget' + } + + normalized_key = exchange_mapping.get(key, key) + + # 记录未映射的交易所 + if normalized_key == key and key not in exchange_mapping.values(): + logger.debug(f"未映射的交易所名称: {key}") + + return normalized_key + + def parse_account(self, exchange_id: str, account_id: str, account_info: str) -> Optional[Dict]: + """解析账号信息""" + try: + source_account_info = json.loads(account_info) + # print(source_account_info) + # 基础信息 + account_data = { + 'exchange_id': exchange_id, + 'k_id': account_id, + 'st_id': helpers.safe_int(source_account_info.get('st_id'), 0), + 'add_time': helpers.safe_int(source_account_info.get('add_time'), 0), + 'api_key': source_account_info.get('api_key', ''), + } + + return account_data + + except json.JSONDecodeError as e: + logger.error(f"解析账号 {account_id} JSON数据失败: {e}, 原始数据: {account_info[:100]}...") + return None + except Exception as e: + logger.error(f"处理账号 {account_id} 数据异常: {e}") + return None + + def _group_accounts_by_exchange(self, accounts: Dict[str, Dict]) -> Dict[str, List[Dict]]: + """按交易所分组账号""" + groups = {} + for account_id, account_info in accounts.items(): + exchange_id = account_info.get('exchange_id') + if exchange_id: + if exchange_id not in groups: + groups[exchange_id] = [] + groups[exchange_id].append(account_info) + return groups + + async def _collect_all_positions(self, accounts: Dict[str, Dict]) -> List[Dict]: + """收集所有账号的持仓数据""" + all_positions = [] + + try: + # 按交易所分组账号 + account_groups = self._group_accounts_by_exchange(accounts) + + # 并发收集每个交易所的数据 + tasks = [] + for exchange_id, account_list in account_groups.items(): + task = self._collect_exchange_positions(exchange_id, account_list) + tasks.append(task) + + # 等待所有任务完成并合并结果 + results = await asyncio.gather(*tasks, return_exceptions=True) + + for result in results: + if isinstance(result, list): + all_positions.extend(result) + + except Exception as e: + logger.error(f"收集持仓数据失败: {e}") + + return all_positions + + + async def _collect_exchange_positions(self, exchange_id: str, account_list: List[Dict]) -> List[Dict]: + """收集某个交易所的持仓数据""" + positions_list = [] + + try: + tasks = [] + for account_info in account_list: + k_id = int(account_info['k_id']) + st_id = account_info.get('st_id', 0) + task = self._get_positions_from_redis(k_id, st_id, exchange_id) + tasks.append(task) + + # 并发获取 + results = await asyncio.gather(*tasks, return_exceptions=True) + + for result in results: + if isinstance(result, list): + positions_list.extend(result) + + except Exception as e: + logger.error(f"收集交易所 {exchange_id} 持仓数据失败: {e}") + + return positions_list + + async def _get_positions_from_redis(self, k_id: int, st_id: int, exchange_id: str) -> List[Dict]: + """从Redis获取持仓数据""" + try: + redis_key = f"{exchange_id}:positions:{k_id}" + redis_data = self.client.hget(redis_key, 'positions') + + if not redis_data: + return [] + + positions = json.loads(redis_data) + + # 添加账号信息 + for position in positions: + # print(position['symbol']) + position['k_id'] = k_id + position['st_id'] = st_id + position['exchange_id'] = exchange_id + + return positions + + except Exception as e: + logger.error(f"获取Redis持仓数据失败: k_id={k_id}, error={e}") + return [] + + + async def _collect_all_account_data(self, accounts: Dict[str, Dict]) -> List[Dict]: + """收集所有账号的账户信息数据""" + all_account_data = [] + + try: + # 按交易所分组账号 + account_groups = self._group_accounts_by_exchange(accounts) + + # 并发收集每个交易所的数据 + tasks = [] + for exchange_id, account_list in account_groups.items(): + task = self._collect_exchange_account_data(exchange_id, account_list) + tasks.append(task) + + # 等待所有任务完成并合并结果 + results = await asyncio.gather(*tasks, return_exceptions=True) + + for result in results: + if isinstance(result, list): + all_account_data.extend(result) + + logger.info(f"收集到 {len(all_account_data)} 条账户信息记录") + + except Exception as e: + logger.error(f"收集账户信息数据失败: {e}") + + return all_account_data + + + async def _collect_exchange_account_data(self, exchange_id: str, account_list: List[Dict]) -> List[Dict]: + """收集某个交易所的账户信息数据""" + account_data_list = [] + + try: + for account_info in account_list: + k_id = int(account_info['k_id']) + st_id = account_info.get('st_id', 0) + + # 从Redis获取账户信息数据 + account_data = await self._get_account_info_from_redis(k_id, st_id, exchange_id) + account_data_list.extend(account_data) + + logger.debug(f"交易所 {exchange_id}: 收集到 {len(account_data_list)} 条账户信息") + + except Exception as e: + logger.error(f"收集交易所 {exchange_id} 账户信息失败: {e}") + + return account_data_list + + async def _get_account_info_from_redis(self, k_id: int, st_id: int, exchange_id: str) -> List[Dict]: + """从Redis获取账户信息数据(批量优化版本)""" + try: + redis_key = f"{exchange_id}:balance:{k_id}" + redis_funds = self.client.hgetall(redis_key) + + if not redis_funds: + return [] + + # 按天统计数据 + from config.settings import SYNC_CONFIG + recent_days = SYNC_CONFIG['recent_days'] + + today = datetime.now() + date_stats = {} + + # 收集所有日期的数据 + for fund_key, fund_json in redis_funds.items(): + try: + fund_data = json.loads(fund_json) + date_str = fund_data.get('lz_time', '') + lz_type = fund_data.get('lz_type', '') + + if not date_str or lz_type not in ['lz_balance', 'deposit', 'withdrawal']: + continue + + # 只处理最近N天的数据 + date_obj = datetime.strptime(date_str, '%Y-%m-%d') + if (today - date_obj).days > recent_days: + continue + + if date_str not in date_stats: + date_stats[date_str] = { + 'balance': 0.0, + 'deposit': 0.0, + 'withdrawal': 0.0, + 'has_balance': False + } + + lz_amount = float(fund_data.get('lz_amount', 0)) + + if lz_type == 'lz_balance': + date_stats[date_str]['balance'] = lz_amount + date_stats[date_str]['has_balance'] = True + elif lz_type == 'deposit': + date_stats[date_str]['deposit'] += lz_amount + elif lz_type == 'withdrawal': + date_stats[date_str]['withdrawal'] += lz_amount + + except (json.JSONDecodeError, ValueError) as e: + logger.debug(f"解析Redis数据失败: {fund_key}, error={e}") + continue + + # 转换为账户信息数据 + account_data_list = [] + sorted_dates = sorted(date_stats.keys()) + + # 获取前一天余额用于计算利润 + prev_balance_map = self._get_previous_balances(redis_funds, sorted_dates) + + for date_str in sorted_dates: + stats = date_stats[date_str] + + # 如果没有余额数据但有充提数据,仍然处理 + if not stats['has_balance'] and stats['deposit'] == 0 and stats['withdrawal'] == 0: + continue + + balance = stats['balance'] + deposit = stats['deposit'] + withdrawal = stats['withdrawal'] + + # 计算利润 + prev_balance = prev_balance_map.get(date_str, 0.0) + profit = balance - deposit - withdrawal - prev_balance + + # 转换时间戳 + date_obj = datetime.strptime(date_str, '%Y-%m-%d') + time_timestamp = int(date_obj.timestamp()) + + account_data = { + 'st_id': st_id, + 'k_id': k_id, + 'balance': balance, + 'withdrawal': withdrawal, + 'deposit': deposit, + 'other': 0.0, # 暂时为0 + 'profit': profit, + 'time': time_timestamp + } + + account_data_list.append(account_data) + + return account_data_list + + except Exception as e: + logger.error(f"获取Redis账户信息失败: k_id={k_id}, error={e}") + return [] + + def _get_previous_balances(self, redis_funds: Dict, sorted_dates: List[str]) -> Dict[str, float]: + """获取前一天的余额""" + prev_balance_map = {} + prev_date = None + + for date_str in sorted_dates: + # 查找前一天的余额 + if prev_date: + for fund_key, fund_json in redis_funds.items(): + try: + fund_data = json.loads(fund_json) + if (fund_data.get('lz_time') == prev_date and + fund_data.get('lz_type') == 'lz_balance'): + prev_balance_map[date_str] = float(fund_data.get('lz_amount', 0)) + break + except: + continue + else: + prev_balance_map[date_str] = 0.0 + + prev_date = date_str + + return prev_balance_map + + + def close(self): """关闭连接池""" if self._pool: