Skip to content

Latest commit

 

History

History
267 lines (204 loc) · 7.74 KB

File metadata and controls

267 lines (204 loc) · 7.74 KB

Hotfix V2.5.1 - 紧急修复

发布日期: 2025-10-21
版本: V2.5.1 (Hotfix)


🐛 紧急修复的问题

1. RuntimeError: 'There is no current event loop'

错误信息:

File "monitor_whales.py", line 809, in start_monitoring
  self.update_task = asyncio.ensure_future(self._periodic_data_update())
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: There is no current event loop in thread 'MainThread'.

原因分析:

  • asyncio.ensure_future() 需要在事件循环中调用
  • start_monitoring() 是同步方法,没有运行中的事件循环
  • 无法在同步上下文中创建异步任务

解决方案: 使用独立线程运行定期更新任务:

# 修改前(错误)
self.update_task = asyncio.ensure_future(self._periodic_data_update())

# 修改后(正确)
import threading

def run_periodic_update():
    asyncio.run(self._periodic_data_update())

update_thread = threading.Thread(target=run_periodic_update, daemon=True)
update_thread.start()
logging.info("✅ 定期更新任务已启动(后台线程)")

优势:

  • ✅ 后台线程独立运行,不阻塞主程序
  • daemon=True 确保程序退出时自动停止
  • ✅ 使用 asyncio.run() 创建新的事件循环
  • ✅ 简化代码,移除不必要的 update_task 引用

✨ 新增功能

2. 账户获取统计

在每次批量获取账户数据后,显示成功/失败统计:

日志输出示例:

2025-10-21 22:28:49,909 | INFO | ✅ 数据更新完毕,耗时: 39.50秒
2025-10-21 22:28:49,910 | INFO | 📊 统计: 成功 17 个, 失败 0 个 (总计 17 个)

失败时输出:

2025-10-21 22:28:49,909 | INFO | ✅ 数据更新完毕,耗时: 39.50秒
2025-10-21 22:28:49,910 | INFO | 📊 统计: 成功 15 个, 失败 2 个 (总计 17 个)
2025-10-21 22:28:49,911 | WARNING | ⚠️  获取失败的地址:
2025-10-21 22:28:49,912 | WARNING |    - 0x35d1151e...
2025-10-21 22:28:49,913 | WARNING |    - 0x15b32566...

实现代码:

# 统计成功和失败的数量
success_count = sum(1 for result in results if result is not None)
fail_count = sum(1 for result in results if result is None)

logging.info(f"✅ 数据更新完毕,耗时: {elapsed:.2f}秒")
logging.info(f"📊 统计: 成功 {success_count} 个, 失败 {fail_count} 个 (总计 {len(addresses)} 个)")

# 如果有失败的地址,记录日志
if failed_addresses:
    logging.warning(f"⚠️  获取失败的地址:")
    for addr in failed_addresses:
        logging.warning(f"   - {addr[:10]}...")

效果:

  • ✅ 一眼就能看到获取成功率
  • ✅ 快速定位失败的地址
  • ✅ 方便排查网络问题

🔧 修改的文件

monitor_whales.py

删除:

# __init__
- self.update_task = None

# start_monitoring
- self.update_task = asyncio.ensure_future(self._periodic_data_update())

# KeyboardInterrupt
- if self.update_task:
-     self.update_task.cancel()
-     logging.debug("已取消定期更新任务")

新增:

# start_monitoring
+ import threading
+ def run_periodic_update():
+     asyncio.run(self._periodic_data_update())
+ 
+ update_thread = threading.Thread(target=run_periodic_update, daemon=True)
+ update_thread.start()
+ logging.info("✅ 定期更新任务已启动(后台线程)")

position_manager.py

新增:

# update_and_generate_report_async
+ # 统计成功和失败的数量
+ success_count = sum(1 for result in results if result is not None)
+ fail_count = sum(1 for result in results if result is None)
+ 
+ logging.info(f"✅ 数据更新完毕,耗时: {elapsed:.2f}秒")
+ logging.info(f"📊 统计: 成功 {success_count} 个, 失败 {fail_count} 个 (总计 {len(addresses)} 个)")
+ 
+ # 构建结果字典
+ all_account_data = {}
+ failed_addresses = []
+ for addr, data in zip(addresses, results):
+     if data:
+         all_account_data[addr] = data
+     else:
+         failed_addresses.append(addr)
+ 
+ # 如果有失败的地址,记录日志
+ if failed_addresses:
+     logging.warning(f"⚠️  获取失败的地址:")
+     for addr in failed_addresses:
+         logging.warning(f"   - {addr[:10]}...")

📊 运行示例

正常情况(全部成功)

================================================================================
正在获取用户初始仓位信息...
================================================================================

2025-10-21 22:28:10,414 | INFO | 🚀 开始更新 17 个地址的数据...
2025-10-21 22:28:10,414 | INFO | 🔄 刷新账户数据: 0x5b5d5120...
... (获取过程)
2025-10-21 22:28:49,909 | INFO | ✅ 数据更新完毕,耗时: 39.50秒
2025-10-21 22:28:49,910 | INFO | 📊 统计: 成功 17 个, 失败 0 个 (总计 17 个)
2025-10-21 22:28:49,913 | INFO | ================================================================================
2025-10-21 22:28:49,913 | INFO | 📊 多空持仓统计
2025-10-21 22:28:49,913 | INFO | ================================================================================
2025-10-21 22:28:49,913 | INFO | 🟢 做多: 68 个持仓, 总价值: $267,143,058.89 (15.4%)
2025-10-21 22:28:49,913 | INFO | 🔴 做空: 177 个持仓, 总价值: $1,466,406,559.75 (84.6%)
2025-10-21 22:28:49,913 | INFO | 📈 多空比: 0.18
2025-10-21 22:28:49,913 | INFO | ================================================================================
2025-10-21 22:28:49,921 | INFO | ✅ 持仓信息已保存到: positions/positions_20251021_222810.html
2025-10-21 22:28:49,922 | INFO | ✅ 定期更新任务已启动(后台线程)  ← 新增

================================================================================
正在订阅用户事件...
================================================================================

部分失败情况

2025-10-21 22:06:50,277 | INFO | ✅ 数据更新完毕,耗时: 11.11秒
2025-10-21 22:06:50,278 | INFO | 📊 统计: 成功 15 个, 失败 2 个 (总计 17 个)  ← 新增
2025-10-21 22:06:50,279 | WARNING | ⚠️  获取失败的地址:                      ← 新增
2025-10-21 22:06:50,280 | WARNING |    - 0x35d1151e...                         ← 新增
2025-10-21 22:06:50,281 | WARNING |    - 0x15b32566...                         ← 新增

🎯 技术细节

为什么使用线程而不是事件循环?

原因:

  1. start_monitoring() 是同步方法
  2. 后续代码需要阻塞等待WebSocket连接
  3. 定期更新任务需要在后台独立运行

对比方案:

方案 优势 劣势
asyncio.ensure_future() 简洁 ❌ 需要运行中的事件循环
asyncio.create_task() 标准 ❌ 需要运行中的事件循环
线程 ✅ 独立运行
✅ 不需要事件循环
✅ 简单可靠
略微增加资源消耗

选择线程的原因:

  • ✅ 定期更新是独立任务,不需要与主程序交互
  • daemon=True 确保程序退出时自动清理
  • ✅ 代码更简洁,不需要管理事件循环

🚀 升级说明

从之前版本升级

步骤:

# 1. 更新代码
git pull

# 2. 重启监控
python3 monitor_whales.py

无需修改配置,完全向后兼容!


✅ 测试结果

测试环境

  • Python 3.12.10
  • macOS (darwin 24.4.0)
  • 17个监控地址

测试结果

  • ✅ 程序正常启动
  • ✅ 初始化数据获取成功
  • ✅ 定期更新任务正常运行
  • ✅ WebSocket连接稳定
  • ✅ 统计信息准确显示
  • ✅ 无RuntimeError错误

📝 相关文档

  • BUGFIX_V2.5.1.md - 之前的bug修复
  • SUMMARY_V2.5.1.md - V2.5.1总结
  • README.md - 完整使用文档

版本: V2.5.1 (Hotfix)
发布日期: 2025-10-21
状态: ✅ 稳定版