├── .gitattributes ├── README.md ├── config ├── .DS_Store ├── exchanges │ ├── API_KEY_SETUP.md │ ├── backpack_config.yaml │ ├── edgex_config.yaml │ ├── hyperliquid_config.yaml │ └── hyperliquid_example.yaml ├── grid │ ├── backpack_follow_long_grid.yaml │ ├── backpack_follow_short_grid.yaml │ ├── backpack_long_grid.yaml │ ├── backpack_martingale_long_grid.yaml │ ├── backpack_martingale_short_grid.yaml │ ├── backpack_short_grid.yaml │ └── default_grid.yaml └── logging.yaml ├── core ├── .DS_Store ├── __init__.py ├── adapters │ ├── __init__.py │ └── exchanges │ │ ├── .DS_Store │ │ ├── __init__.py │ │ ├── adapter.py │ │ ├── adapters │ │ ├── .DS_Store │ │ ├── __init__.py │ │ ├── backpack.py │ │ ├── backpack_backup.py.md │ │ ├── backpack_base.py │ │ ├── backpack_rest.py │ │ ├── backpack_websocket.py │ │ ├── binance.py │ │ ├── binance_base.py │ │ ├── binance_rest.py │ │ ├── binance_websocket.py │ │ ├── edgex.py │ │ ├── edgex_backup.md │ │ ├── edgex_base.py │ │ ├── edgex_rest.py │ │ ├── edgex_websocket.py │ │ ├── hyperliquid.py │ │ ├── hyperliquid_base copy.md │ │ ├── hyperliquid_base.py │ │ ├── hyperliquid_original_backup.md │ │ ├── hyperliquid_rest.py │ │ ├── hyperliquid_websocket.py │ │ ├── hyperliquid_websocket_native.py │ │ ├── okx.py │ │ ├── okx_base.py │ │ ├── okx_rest.py │ │ └── okx_websocket.py │ │ ├── factory.py │ │ ├── interface.py │ │ ├── manager.py │ │ ├── models.py │ │ ├── subscription_manager.py │ │ └── websocket_manager.py ├── di │ ├── __init__.py │ ├── container.py │ ├── decorators.py │ ├── modules.py │ └── scopes.py ├── domain │ ├── .DS_Store │ ├── entities │ │ └── __init__.py │ ├── models │ │ └── __init__.py │ └── value_objects │ │ └── __init__.py ├── infrastructure │ ├── .DS_Store │ ├── cache │ │ └── __init__.py │ ├── config_manager.py │ ├── database │ │ └── __init__.py │ ├── messaging │ │ └── __init__.py │ └── stats_config.py ├── logging │ ├── __init__.py │ └── logger.py └── services │ ├── .DS_Store │ ├── arbitrage │ ├── __init__.py │ ├── coordinator │ │ └── arbitrage_coordinator.py │ ├── decision │ │ ├── arbitrage_decision_engine.py │ │ └── opportunity_processor.py │ ├── execution │ │ ├── exchange_registry.py │ │ └── trade_execution_manager.py │ ├── initialization │ │ ├── arbitrage_initializer.py │ │ └── precision_manager.py │ ├── position_manager │ │ ├── __init__.py │ │ ├── position_manager.py │ │ └── position_models.py │ ├── risk_manager │ │ ├── __init__.py │ │ ├── risk_manager.py │ │ └── risk_models.py │ └── shared │ │ ├── config.py │ │ ├── models.py │ │ └── precision_cache.py │ ├── events │ ├── __init__.py │ ├── event.py │ └── event_handler.py │ ├── grid │ ├── __init__.py │ ├── coordinator │ │ ├── __init__.py │ │ └── grid_coordinator.py │ ├── implementations │ │ ├── __init__.py │ │ ├── grid_engine_impl.py │ │ ├── grid_strategy_impl.py │ │ ├── order_monitor.py │ │ └── position_tracker_impl.py │ ├── interfaces │ │ ├── __init__.py │ │ ├── grid_engine.py │ │ ├── grid_strategy.py │ │ └── position_tracker.py │ ├── models │ │ ├── __init__.py │ │ ├── grid_config.py │ │ ├── grid_metrics.py │ │ ├── grid_order.py │ │ └── grid_state.py │ └── terminal_ui.py │ ├── implementations │ ├── __init__.py │ ├── config_service.py │ └── enhanced_monitoring_service.py │ ├── interfaces │ ├── __init__.py │ ├── base.py │ ├── config_service.py │ └── monitoring_service.py │ └── symbol_manager │ ├── __init__.py │ ├── implementations │ ├── __init__.py │ ├── symbol_cache_service.py │ └── symbol_conversion_service.py │ ├── interfaces │ ├── __init__.py │ ├── symbol_cache.py │ └── symbol_conversion_service.py │ └── models │ ├── __init__.py │ ├── symbol_cache_models.py │ └── symbol_normalization.py ├── logs └── .DS_Store ├── requirements.txt ├── run_grid_trading.py ├── start_all_grids.sh └── 网格系统运行指南.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 网格交易系统 (Grid Trading System) 2 | 3 | 一个功能强大的加密货币网格交易系统,支持多种网格策略和多个交易所。 4 | 5 | ## ✨ 特性 6 | 7 | - 🎯 **三种网格模式** 8 | - 普通网格:固定金额,适合震荡行情 9 | - 马丁网格:递增金额,适合回归行情(高风险) 10 | - 价格移动网格:自动跟随价格,适合趋势行情 11 | 12 | - 🔄 **智能订单监控** 13 | - WebSocket实时监控(主要) 14 | - REST API轮询(备用) 15 | - 自动切换和恢复机制 16 | 17 | - 📊 **实时终端界面** 18 | - 网格运行状态 19 | - 订单统计 20 | - 持仓信息 21 | - 盈亏统计 22 | - 触发统计 23 | - 最近成交订单 24 | 25 | - 🏦 **支持多个交易所** 26 | - Backpack 27 | - EdgeX 28 | - Hyperliquid 29 | - Binance 30 | - OKX 31 | 32 | ## 📋 系统要求 33 | 34 | - Python 3.8+ 35 | - 稳定的网络连接 36 | - 交易所API密钥 37 | 38 | ## 🚀 快速开始 39 | 40 | ### 1. 安装依赖 41 | 42 | ```bash 43 | pip install -r requirements.txt 44 | ``` 45 | 46 | ### 2. 配置API密钥 47 | 48 | 编辑 `config/exchanges/backpack_config.yaml`(或其他交易所配置文件): 49 | 50 | ```yaml 51 | authentication: 52 | api_key: "your_api_key_here" 53 | private_key: "your_private_key_here" 54 | ``` 55 | 56 | **⚠️ 安全提示**: 57 | - 不要将包含真实API密钥的配置文件提交到Git 58 | - 建议使用环境变量存储API密钥 59 | - 确保API密钥只有必要的权限(交易权限) 60 | 61 | ### 3. 配置网格参数 62 | 63 | 编辑 `config/grid/` 目录下的配置文件,例如 `backpack_long_grid.yaml`: 64 | 65 | ```yaml 66 | grid_system: 67 | exchange: "backpack" 68 | symbol: "BTC_USDC_PERP" 69 | grid_type: "long" # 网格类型 70 | 71 | upper_price: 123500.00 # 价格上限 72 | lower_price: 103600.00 # 价格下限 73 | grid_interval: 100.00 # 网格间隔 74 | order_amount: 0.0001 # 每格订单数量 75 | fee_rate: 0.0001 # 手续费率 76 | ``` 77 | 78 | ### 4. 运行网格系统 79 | 80 | ```bash 81 | # 普通做多网格 82 | python run_grid_trading.py --config config/grid/backpack_long_grid.yaml 83 | 84 | # 马丁做多网格 85 | python run_grid_trading.py --config config/grid/backpack_martingale_long_grid.yaml 86 | 87 | # 价格移动做多网格 88 | python run_grid_trading.py --config config/grid/backpack_follow_long_grid.yaml 89 | ``` 90 | 91 | ## 📖 详细文档 92 | 93 | - [网格系统运行指南](docs/网格系统运行指南.md) - 完整的使用指南 94 | - [三种网格模式完整指南](docs/三种网格模式完整指南.md) - 三种模式的详细说明 95 | - [网格交易系统快速入门](docs/网格交易系统快速入门.md) - 快速入门教程 96 | - [网格重置订单验证机制](docs/网格重置订单验证机制.md) - 价格移动网格的重置机制 97 | 98 | ## 🎯 网格模式对比 99 | 100 | | 特性 | 普通网格 | 马丁网格 | 价格移动网格 | 101 | |------|----------|----------|------------| 102 | | **订单金额** | 固定 | 递增 | 固定 | 103 | | **价格区间** | 固定 | 固定 | 动态跟随 | 104 | | **风险等级** | 低-中 | 高 | 中 | 105 | | **资金要求** | 较少 | 较多 | 中等 | 106 | | **适用场景** | 震荡行情 | 回归行情 | 趋势行情 | 107 | | **网格重置** | 无 | 无 | 自动重置 | 108 | 109 | ## ⚙️ 配置文件说明 110 | 111 | ### 普通网格配置 112 | 113 | ```yaml 114 | grid_system: 115 | grid_type: "long" # long=做多, short=做空 116 | upper_price: 123500.00 117 | lower_price: 103600.00 118 | grid_interval: 100.00 119 | order_amount: 0.0001 # 固定金额 120 | ``` 121 | 122 | ### 马丁网格配置 123 | 124 | ```yaml 125 | grid_system: 126 | grid_type: "martingale_long" 127 | upper_price: 123500.00 128 | lower_price: 103600.00 129 | grid_interval: 100.00 130 | order_amount: 0.001 # 基础金额 131 | martingale_increment: 0.001 # 递增金额 132 | max_position: 20.0 # 必须设置最大持仓 133 | ``` 134 | 135 | ### 价格移动网格配置 136 | 137 | ```yaml 138 | grid_system: 139 | grid_type: "follow_long" 140 | # 不需要设置 upper_price 和 lower_price 141 | follow_grid_count: 200 # 网格数量 142 | grid_interval: 50.00 143 | follow_timeout: 300 # 脱离超时(秒) 144 | follow_distance: 2 # 脱离距离(格数) 145 | order_amount: 0.0001 146 | ``` 147 | 148 | ## 🔧 运行控制 149 | 150 | ### 启动系统 151 | 152 | ```bash 153 | python run_grid_trading.py --config config/grid/your_config.yaml 154 | ``` 155 | 156 | ### 停止系统 157 | 158 | - **快捷键**:按 `Ctrl+C` 优雅退出 159 | - **终端命令**: 160 | - `[P]` 暂停 161 | - `[S]` 停止 162 | - `[Q]` 退出 163 | 164 | ### 查看日志 165 | 166 | ```bash 167 | # 主日志 168 | tail -f logs/core.services.grid.coordinator.grid_coordinator.log 169 | 170 | # 引擎日志 171 | tail -f logs/core.services.grid.implementations.grid_engine_impl.log 172 | ``` 173 | 174 | ## ⚠️ 风险提示 175 | 176 | - **普通网格**:单边行情可能持续亏损 177 | - **马丁网格**:持仓增长极快(二次方增长),风险极高,必须设置 `max_position` 178 | - **价格移动网格**:会自动重置网格,需注意资金管理 179 | 180 | **强烈建议**: 181 | 1. ✅ 小额测试:先用最小金额测试 182 | 2. ✅ 设置限制:必须设置 `max_position`(马丁网格) 183 | 3. ✅ 密切监控:随时关注持仓变化 184 | 4. ✅ 止损准备:准备好止损方案 185 | 186 | ## 📊 终端界面示例 187 | 188 | ``` 189 | ┌─────────────────────────────────────────────────┐ 190 | │ 网格交易系统实时监控 - BACKPACK/BTC_USDC_PERP │ 191 | ├─────────────────────────────────────────────────┤ 192 | │ 运行状态 │ 193 | │ ├─ 网格策略: 做多网格(普通) (199格) │ 194 | │ ├─ 价格区间: $103,600.00 - $123,500.00 │ 195 | │ ├─ 当前价格: $122,029.30 当前位置: Grid 10/199│ 196 | │ └─ 运行时长: 0:08:17 │ 197 | ├─────────────────────────────────────────────────┤ 198 | │ 订单统计 │ 199 | │ ├─ 监控方式: 📡 WebSocket │ 200 | │ ├─ 未成交买单: 147个 ⏳ │ 201 | │ ├─ 未成交卖单: 10个 ⏳ │ 202 | │ └─ 总挂单数量: 157个 │ 203 | ├─────────────────────────────────────────────────┤ 204 | │ 盈亏统计 │ 205 | │ ├─ 已实现: +$0.00 网格收益: +$0.00 │ 206 | │ ├─ 未实现: $-0.74 手续费: -$0.06 │ 207 | │ └─ 总盈亏: $-0.74 (-0.04%) 净收益: $-0.80 │ 208 | └─────────────────────────────────────────────────┘ 209 | ``` 210 | 211 | ## 🏗️ 项目结构 212 | 213 | ``` 214 | trading_strategy_sys/ 215 | ├── config/ # 配置文件 216 | │ ├── exchanges/ # 交易所配置 217 | │ │ ├── backpack_config.yaml 218 | │ │ ├── edgex_config.yaml 219 | │ │ └── hyperliquid_config.yaml 220 | │ ├── grid/ # 网格配置 221 | │ │ ├── backpack_long_grid.yaml 222 | │ │ ├── backpack_short_grid.yaml 223 | │ │ ├── backpack_martingale_long_grid.yaml 224 | │ │ ├── backpack_martingale_short_grid.yaml 225 | │ │ ├── backpack_follow_long_grid.yaml 226 | │ │ └── backpack_follow_short_grid.yaml 227 | │ └── logging.yaml # 日志配置 228 | ├── core/ # 核心代码 229 | │ ├── adapters/ # 交易所适配器 230 | │ ├── services/ # 业务服务 231 | │ │ └── grid/ # 网格系统 232 | │ ├── domain/ # 领域模型 233 | │ ├── infrastructure/ # 基础设施 234 | │ └── di/ # 依赖注入 235 | ├── docs/ # 文档 236 | ├── logs/ # 日志文件 237 | ├── run_grid_trading.py # 网格系统启动脚本 238 | ├── requirements.txt # 依赖列表 239 | └── README.md # 本文件 240 | ``` 241 | 242 | ## 🤝 贡献 243 | 244 | 欢迎提交Issue和Pull Request! 245 | 246 | ## 📄 许可证 247 | 248 | MIT License 249 | 250 | ## 📧 联系方式 251 | 252 | 如有问题或建议,请提交Issue。 253 | 254 | --- 255 | 256 | **⚠️ 免责声明**:本软件仅供学习和研究使用。使用本软件进行实际交易的风险由用户自行承担。作者不对任何交易损失负责。 257 | -------------------------------------------------------------------------------- /config/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptocj520/grid/4b2ae95f2afcd2e5381e5ab2f2673eb60d51b9a0/config/.DS_Store -------------------------------------------------------------------------------- /config/exchanges/API_KEY_SETUP.md: -------------------------------------------------------------------------------- 1 | # API密钥配置指南 2 | 3 | ## ⚠️ 重要安全提示 4 | 5 | **请勿将包含真实API密钥的配置文件提交到Git仓库!** 6 | 7 | ## 📋 配置步骤 8 | 9 | ### 1. Backpack交易所 10 | 11 | 编辑 `config/exchanges/backpack_config.yaml`: 12 | 13 | ```yaml 14 | authentication: 15 | method: "ed25519" 16 | api_key: "your_api_key_here" # 替换为你的API Key 17 | private_key: "your_private_key_here" # 替换为你的私钥 18 | ``` 19 | 20 | **获取API密钥**: 21 | 1. 登录 [Backpack Exchange](https://backpack.exchange) 22 | 2. 进入 API 管理页面 23 | 3. 创建新的API密钥 24 | 4. 确保只启用"交易"权限(不需要"提现"权限) 25 | 5. 保存API Key和私钥 26 | 27 | ### 2. EdgeX交易所 28 | 29 | 编辑 `config/exchanges/edgex_config.yaml`: 30 | 31 | ```yaml 32 | authentication: 33 | method: "hmac_sha256" 34 | api_key: "your_api_key_here" # 替换为你的API Key 35 | api_secret: "your_api_secret_here" # 替换为你的API Secret 36 | ``` 37 | 38 | ### 3. Hyperliquid交易所 39 | 40 | 编辑 `config/exchanges/hyperliquid_config.yaml`: 41 | 42 | ```yaml 43 | authentication: 44 | private_key: 'your_private_key_here' # 替换为你的钱包私钥 45 | wallet_address: 'your_wallet_address_here' # 替换为你的钱包地址 46 | ``` 47 | 48 | **⚠️ Hyperliquid特别注意**: 49 | - Hyperliquid使用钱包签名认证 50 | - 私钥格式:`0x...`(以0x开头的64位十六进制字符串) 51 | - 钱包地址格式:`0x...`(以0x开头的40位十六进制字符串) 52 | 53 | ## 🔐 安全最佳实践 54 | 55 | ### 方式一:使用环境变量(推荐) 56 | 57 | 在 `~/.bashrc` 或 `~/.zshrc` 中添加: 58 | 59 | ```bash 60 | # Backpack 61 | export BACKPACK_API_KEY="your_api_key" 62 | export BACKPACK_API_SECRET="your_private_key" 63 | 64 | # EdgeX 65 | export EDGEX_API_KEY="your_api_key" 66 | export EDGEX_API_SECRET="your_api_secret" 67 | 68 | # Hyperliquid 69 | export HYPERLIQUID_PRIVATE_KEY="your_private_key" 70 | export HYPERLIQUID_WALLET_ADDRESS="your_wallet_address" 71 | ``` 72 | 73 | 然后在配置文件中引用: 74 | 75 | ```yaml 76 | authentication: 77 | api_key: "${BACKPACK_API_KEY}" 78 | private_key: "${BACKPACK_API_SECRET}" 79 | ``` 80 | 81 | ### 方式二:使用单独的密钥文件 82 | 83 | 创建 `config/exchanges/.secrets.yaml`(已在 `.gitignore` 中): 84 | 85 | ```yaml 86 | backpack: 87 | api_key: "your_api_key" 88 | private_key: "your_private_key" 89 | 90 | edgex: 91 | api_key: "your_api_key" 92 | api_secret: "your_api_secret" 93 | 94 | hyperliquid: 95 | private_key: "your_private_key" 96 | wallet_address: "your_wallet_address" 97 | ``` 98 | 99 | **确保将 `.secrets.yaml` 添加到 `.gitignore`!** 100 | 101 | ## ✅ 验证配置 102 | 103 | 运行测试脚本验证API密钥是否正确: 104 | 105 | ```bash 106 | # 测试Backpack连接 107 | python -c "from core.adapters.exchanges.factory import create_adapter; adapter = create_adapter('backpack'); print('✅ Backpack连接成功')" 108 | ``` 109 | 110 | ## 🆘 常见问题 111 | 112 | ### Q1: "Invalid signature" 错误 113 | 114 | **原因**:API密钥或私钥不正确,或者签名算法有误。 115 | 116 | **解决方案**: 117 | 1. 确认API密钥和私钥是否正确复制(没有多余空格) 118 | 2. 确认API密钥是否已激活 119 | 3. 确认API密钥权限是否正确 120 | 121 | ### Q2: "Unauthorized" 错误 122 | 123 | **原因**:API密钥没有足够的权限。 124 | 125 | **解决方案**: 126 | 1. 检查API密钥权限设置 127 | 2. 确保启用了"交易"权限 128 | 3. 重新创建API密钥 129 | 130 | ### Q3: Hyperliquid "Invalid private key" 错误 131 | 132 | **原因**:私钥格式不正确。 133 | 134 | **解决方案**: 135 | 1. 确认私钥以 `0x` 开头 136 | 2. 确认私钥是64位十六进制字符串 137 | 3. 不要包含任何空格或换行符 138 | 139 | ## 📞 获取帮助 140 | 141 | 如果遇到问题,请: 142 | 1. 检查日志文件:`logs/core.services.grid.coordinator.grid_coordinator.log` 143 | 2. 查看文档:`docs/网格系统运行指南.md` 144 | 3. 提交Issue到GitHub 145 | 146 | --- 147 | 148 | **最后更新**:2025-10-05 149 | -------------------------------------------------------------------------------- /config/exchanges/backpack_config.yaml: -------------------------------------------------------------------------------- 1 | backpack: 2 | # 基础配置 3 | name: "Backpack" 4 | exchange_id: "backpack" 5 | enabled: true # 🔥 启用Backpack交易所 6 | type: "spot" 7 | 8 | # 📡 订阅模式配置 - 支持硬编码和动态两种模式 9 | subscription_mode: 10 | # 订阅模式选择 11 | # "predefined" - 硬编码模式:使用配置文件中预定义的交易对 12 | # "dynamic" - 动态模式:从市场获取交易对后订阅 13 | mode: "dynamic" # 🔥 使用动态模式从市场获取交易对 14 | 15 | # 硬编码模式配置 16 | predefined: 17 | # 要订阅的交易对列表 18 | symbols: 19 | # 主流现货交易对 20 | - "SOL_USDC" 21 | - "BTC_USDC" 22 | - "ETH_USDC" 23 | - "AVAX_USDC" 24 | - "DOGE_USDC" 25 | - "WIF_USDC" 26 | - "BONK_USDC" 27 | - "JUP_USDC" 28 | - "PYTH_USDC" 29 | - "JTO_USDC" 30 | 31 | # 要订阅的数据类型 32 | data_types: 33 | ticker: true # 🔥 订阅行情数据获取价格 34 | orderbook: false # 🔥 不订阅订单簿数据 35 | trades: false # 成交数据 36 | user_data: false # 用户数据 37 | 38 | # 批量订阅配置 39 | batch_subscription: 40 | enabled: true # 是否启用批量订阅 41 | batch_size: 5 # 批量大小 42 | delay_between_batches: 1 # 批次间延迟(秒) 43 | 44 | # 动态模式配置 45 | dynamic: 46 | # 市场发现配置 47 | discovery: 48 | enabled: true 49 | # 过滤条件 50 | filter_criteria: 51 | market_types: ["perpetual"] # 🔥 只获取永续合约,不获取现货 52 | volume_threshold: 500000 # 最小交易量过滤 53 | max_symbols: 1000 # 🔥 修改:大幅提高限制,订阅所有可用的永续合约 54 | exclude_symbols: [] # 排除的交易对 55 | include_patterns: ["*_PERP"] # 🔥 只包含永续合约模式 56 | exclude_patterns: ["*SPOT*", "*TEST*"] # 🔥 排除现货和测试交易对 57 | 58 | # 要订阅的数据类型 59 | data_types: 60 | ticker: true # 🔥 订阅行情数据获取价格 61 | orderbook: false # 🔥 不订阅订单簿数据 62 | trades: false # 成交数据 63 | user_data: false # 用户数据 64 | 65 | # 动态订阅配置 66 | dynamic_subscription: 67 | auto_discovery_interval: 600 # 自动发现间隔(秒) 68 | max_retry_attempts: 3 # 最大重试次数 69 | retry_delay: 5 # 重试延迟(秒) 70 | 71 | # 🎯 自定义订阅组合配置 72 | custom_subscriptions: 73 | # 预定义的订阅组合 74 | combinations: 75 | # 主流币种组合 76 | major_coins: 77 | description: "🔥 主流币种永续合约价格数据订阅" 78 | symbols: 79 | - "SOL_USDC_PERP" # 🔥 改为永续合约格式 80 | - "BTC_USDC_PERP" 81 | - "ETH_USDC_PERP" 82 | data_types: 83 | ticker: true # 🔥 订阅ticker获取价格 84 | orderbook: false # 🔥 不订阅订单簿数据 85 | trades: false 86 | 87 | # 全量数据组合 88 | full_data: 89 | description: "🔥 永续合约价格数据订阅" 90 | symbols: 91 | - "SOL_USDC_PERP" # 🔥 改为永续合约格式 92 | - "BTC_USDC_PERP" 93 | data_types: 94 | ticker: true # 🔥 订阅ticker获取价格 95 | orderbook: false # 🔥 不订阅订单簿数据 96 | trades: false # 🔥 不订阅trades 97 | user_data: false # 🔥 不订阅用户数据 98 | 99 | # 仅价格数据组合 100 | price_only: 101 | description: "🔥 永续合约价格数据订阅" 102 | symbols: 103 | - "SOL_USDC_PERP" # 🔥 改为永续合约格式 104 | - "BTC_USDC_PERP" 105 | - "ETH_USDC_PERP" 106 | - "AVAX_USDC_PERP" 107 | - "DOGE_USDC_PERP" 108 | data_types: 109 | ticker: true # 🔥 订阅ticker获取价格 110 | orderbook: false # 🔥 不订阅订单簿数据 111 | trades: false 112 | 113 | # Solana生态币种组合 114 | solana_ecosystem: 115 | description: "🔥 Solana生态永续合约价格数据订阅" 116 | symbols: 117 | - "SOL_USDC_PERP" # 🔥 改为永续合约格式 118 | - "WIF_USDC_PERP" 119 | - "BONK_USDC_PERP" 120 | - "JUP_USDC_PERP" 121 | - "PYTH_USDC_PERP" 122 | - "JTO_USDC_PERP" 123 | data_types: 124 | ticker: true # 🔥 订阅ticker获取价格 125 | orderbook: false # 🔥 不订阅订单簿数据 126 | trades: false 127 | 128 | # 活动的订阅组合 129 | active_combination: "solana_ecosystem" # 可选值: "major_coins", "full_data", "price_only", "solana_ecosystem", "custom" 130 | 131 | # 自定义组合配置 (当active_combination为"custom"时使用) 132 | custom: 133 | symbols: [] 134 | data_types: 135 | ticker: true # 🔥 订阅ticker获取价格 136 | orderbook: false # 🔥 不订阅订单簿数据 137 | trades: false 138 | user_data: false 139 | 140 | # API配置 141 | api: 142 | base_url: "https://api.backpack.exchange" 143 | ws_url: "wss://ws.backpack.exchange" 144 | version: "v1" 145 | timeout: 30 146 | 147 | # 认证配置 148 | authentication: 149 | method: "ed25519" 150 | api_key: "" # 请在此处填入你的API Key 151 | private_key: "" # 请在此处填入你的私钥 (敏感信息) 152 | 153 | # 频率限制 154 | rate_limits: 155 | rest_api: 100 # 每秒REST API请求数 156 | websocket: 10 # 每秒WebSocket订阅数 157 | 158 | # 精度配置 159 | precision: 160 | price: 161 | default: 6 162 | "SOL_USDC": 4 163 | "BTC_USDC": 2 164 | "ETH_USDC": 2 165 | "AVAX_USDC": 4 166 | "DOGE_USDC": 6 167 | 168 | quantity: 169 | default: 6 170 | "SOL_USDC": 3 171 | "BTC_USDC": 5 172 | "ETH_USDC": 4 173 | "AVAX_USDC": 3 174 | "DOGE_USDC": 0 175 | 176 | # 符号映射 177 | symbol_mapping: 178 | "SOL/USDC": "SOL_USDC" 179 | "BTC/USDC": "BTC_USDC" 180 | "ETH/USDC": "ETH_USDC" 181 | "AVAX/USDC": "AVAX_USDC" 182 | "DOGE/USDC": "DOGE_USDC" 183 | "WIF/USDC": "WIF_USDC" 184 | "BONK/USDC": "BONK_USDC" 185 | "JUP/USDC": "JUP_USDC" 186 | "PYTH/USDC": "PYTH_USDC" 187 | "JTO/USDC": "JTO_USDC" 188 | 189 | # 手续费配置 190 | fees: 191 | maker: 0.0000 # 0% 192 | taker: 0.0010 # 0.10% 193 | 194 | # 交易配置 195 | trading: 196 | min_order_size: 0.001 197 | max_order_size: 10000 198 | 199 | # 市场数据配置 200 | market_data: 201 | orderbook_limit: 50 202 | ticker_interval: 1000 203 | trade_history_limit: 500 204 | 205 | # WebSocket配置 206 | websocket: 207 | enabled: true 208 | auto_reconnect: true 209 | max_reconnect_attempts: 5 210 | reconnect_delay: 5 211 | ping_interval: 30 212 | 213 | # 订阅黑名单 214 | blacklisted_symbols: 215 | - "TEST_USDC" 216 | - "DEMO_USDC" 217 | 218 | # 错误处理配置 219 | error_handling: 220 | max_retries: 3 221 | retry_delay: 1 222 | retry_backoff: 2 223 | 224 | # 日志配置 225 | logging: 226 | level: "INFO" 227 | format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 228 | 229 | # 健康检查配置 230 | health_check: 231 | enabled: true 232 | interval: 60 233 | timeout: 10 234 | 235 | # 开发配置 236 | development: 237 | sandbox: false 238 | debug: false 239 | mock_data: false 240 | 241 | # 使用示例: 242 | # 243 | # 1. 硬编码模式 + 主流币种: 244 | # subscription_mode.mode = "predefined" 245 | # custom_subscriptions.active_combination = "major_coins" 246 | # 247 | # 2. 动态模式 + 全量数据: 248 | # subscription_mode.mode = "dynamic" 249 | # custom_subscriptions.active_combination = "full_data" 250 | # 251 | # 3. 硬编码模式 + Solana生态: 252 | # subscription_mode.mode = "predefined" 253 | # custom_subscriptions.active_combination = "solana_ecosystem" 254 | # 255 | # 4. 动态模式 + 自定义过滤: 256 | # subscription_mode.mode = "dynamic" 257 | # subscription_mode.dynamic.discovery.filter_criteria.max_symbols = 30 258 | # subscription_mode.dynamic.discovery.filter_criteria.volume_threshold = 1000000 -------------------------------------------------------------------------------- /config/exchanges/edgex_config.yaml: -------------------------------------------------------------------------------- 1 | edgex: 2 | # 基础配置 - EdgeX专注永续合约 3 | name: "EdgeX" 4 | exchange_id: "edgex" 5 | enabled: true # 🔥 启用EdgeX交易所 6 | type: "perpetual" # EdgeX只有永续合约 7 | 8 | # 📡 订阅模式配置 - 支持硬编码和动态两种模式 9 | subscription_mode: 10 | # 订阅模式选择 11 | # "predefined" - 硬编码模式:使用配置文件中预定义的交易对 12 | # "dynamic" - 动态模式:从市场获取交易对后订阅 13 | mode: "dynamic" # 🔥 使用动态模式从市场获取交易对 14 | 15 | # 硬编码模式配置 16 | predefined: 17 | # 要订阅的交易对列表(EdgeX永续合约) 18 | symbols: 19 | - "BTC_USDT_PERP" 20 | - "ETH_USDT_PERP" 21 | - "SOL_USDT_PERP" 22 | - "AVAX_USDT_PERP" 23 | - "DOGE_USDT_PERP" 24 | - "ADA_USDT_PERP" 25 | - "MATIC_USDT_PERP" 26 | - "DOT_USDT_PERP" 27 | - "LINK_USDT_PERP" 28 | - "UNI_USDT_PERP" 29 | 30 | # 要订阅的数据类型 31 | data_types: 32 | ticker: true # 🔥 订阅行情数据获取价格 33 | orderbook: false # 🔥 不订阅订单簿数据 34 | trades: false # 成交数据 35 | user_data: false # 用户数据 36 | 37 | # 批量订阅配置 38 | batch_subscription: 39 | enabled: true # 是否启用批量订阅 40 | batch_size: 10 # 批量大小 41 | delay_between_batches: 1 # 批次间延迟(秒) 42 | 43 | # 动态模式配置 44 | dynamic: 45 | # 市场发现配置 46 | discovery: 47 | enabled: true 48 | # 过滤条件 49 | filter_criteria: 50 | market_types: ["perpetual"] # 市场类型过滤(EdgeX只有合约) 51 | volume_threshold: 500000 # 最小交易量过滤 52 | max_symbols: 1000 # 🔥 修改:大幅提高限制,订阅所有可用的永续合约 53 | exclude_symbols: [] # 排除的交易对 54 | include_patterns: ["*_USDT_PERP"] # 包含的交易对模式 55 | exclude_patterns: ["*TEST*"] # 排除的交易对模式 56 | 57 | # 要订阅的数据类型 58 | data_types: 59 | ticker: true # 🔥 订阅行情数据获取价格 60 | orderbook: false # 🔥 不订阅订单簿数据 61 | trades: false # 成交数据 62 | user_data: false # 用户数据 63 | 64 | # 动态订阅配置 65 | dynamic_subscription: 66 | auto_discovery_interval: 600 # 自动发现间隔(秒) 67 | max_retry_attempts: 3 # 最大重试次数 68 | retry_delay: 5 # 重试延迟(秒) 69 | 70 | # 🎯 自定义订阅组合配置 71 | custom_subscriptions: 72 | # 预定义的订阅组合 73 | combinations: 74 | # 主流币种组合 75 | major_coins: 76 | description: "🔥 主流币种永续合约价格数据订阅" 77 | symbols: 78 | - "BTC_USDT_PERP" 79 | - "ETH_USDT_PERP" 80 | - "SOL_USDT_PERP" 81 | data_types: 82 | ticker: true # 🔥 订阅ticker获取价格 83 | orderbook: false # 🔥 不订阅订单簿数据 84 | trades: false 85 | 86 | # 全量数据组合 87 | full_data: 88 | description: "🔥 永续合约价格数据订阅" 89 | symbols: 90 | - "BTC_USDT_PERP" 91 | - "ETH_USDT_PERP" 92 | data_types: 93 | ticker: true # 🔥 订阅ticker获取价格 94 | orderbook: false # 🔥 不订阅订单簿数据 95 | trades: false # 🔥 不订阅trades 96 | user_data: false # 🔥 不订阅用户数据 97 | 98 | # 仅价格数据组合 99 | price_only: 100 | description: "🔥 永续合约价格数据订阅" 101 | symbols: 102 | - "BTC_USDT_PERP" 103 | - "ETH_USDT_PERP" 104 | - "SOL_USDT_PERP" 105 | - "AVAX_USDT_PERP" 106 | - "DOGE_USDT_PERP" 107 | data_types: 108 | ticker: true # 🔥 订阅ticker获取价格 109 | orderbook: false # 🔥 不订阅订单簿数据 110 | trades: false 111 | 112 | # 高交易量组合 113 | high_volume: 114 | description: "🔥 高交易量永续合约价格数据订阅" 115 | symbols: 116 | - "BTC_USDT_PERP" 117 | - "ETH_USDT_PERP" 118 | - "SOL_USDT_PERP" 119 | - "AVAX_USDT_PERP" 120 | - "MATIC_USDT_PERP" 121 | - "DOT_USDT_PERP" 122 | data_types: 123 | ticker: true # 🔥 订阅ticker获取价格 124 | orderbook: false # 🔥 不订阅订单簿数据 125 | trades: false 126 | 127 | # 活动的订阅组合 128 | active_combination: "major_coins" # 可选值: "major_coins", "full_data", "price_only", "high_volume", "custom" 129 | 130 | # 自定义组合配置 (当active_combination为"custom"时使用) 131 | custom: 132 | symbols: [] 133 | data_types: 134 | ticker: true # 🔥 订阅ticker获取价格 135 | orderbook: false # 🔥 不订阅订单簿数据 136 | trades: false 137 | user_data: false 138 | 139 | # API配置 140 | api: 141 | base_url: "https://pro.edgex.exchange/" 142 | ws_url: "wss://quote.edgex.exchange/api/v1/public/ws" 143 | version: "v1" 144 | timeout: 30 145 | 146 | # 认证配置 147 | authentication: 148 | method: "hmac_sha256" 149 | api_key: "" # 在运行时设置 150 | api_secret: "" # 在运行时设置 151 | 152 | # 频率限制 153 | rate_limits: 154 | rest_api: 100 # 每秒REST API请求数 155 | websocket: 10 # 每秒WebSocket订阅数 156 | order_creation: 20 # 每秒下单数 157 | order_cancellation: 50 # 每秒撤单数 158 | 159 | # 精度配置 160 | precision: 161 | price: 162 | default: 2 163 | BTC_USDT_PERP: 2 164 | ETH_USDT_PERP: 2 165 | SOL_USDT_PERP: 4 166 | AVAX_USDT_PERP: 4 167 | DOGE_USDT_PERP: 6 168 | ADA_USDT_PERP: 6 169 | MATIC_USDT_PERP: 6 170 | DOT_USDT_PERP: 4 171 | LINK_USDT_PERP: 4 172 | UNI_USDT_PERP: 4 173 | 174 | quantity: 175 | default: 4 176 | BTC_USDT_PERP: 4 177 | ETH_USDT_PERP: 4 178 | SOL_USDT_PERP: 3 179 | AVAX_USDT_PERP: 3 180 | DOGE_USDT_PERP: 0 181 | ADA_USDT_PERP: 0 182 | MATIC_USDT_PERP: 0 183 | DOT_USDT_PERP: 2 184 | LINK_USDT_PERP: 2 185 | UNI_USDT_PERP: 2 186 | 187 | # 符号映射配置已移除 - 现在由执行器统一处理格式转换 188 | 189 | # 手续费配置 190 | fees: 191 | maker: 0.0002 # 0.02% 192 | taker: 0.0005 # 0.05% 193 | funding: 0.0001 # 0.01% 194 | 195 | # 交易配置 196 | trading: 197 | min_order_size: 0.001 # 最小订单大小 198 | max_order_size: 10000 # 最大订单大小 199 | max_leverage: 100 # 最大杠杆 200 | default_leverage: 10 # 默认杠杆 201 | margin_mode: "cross" # 默认保证金模式 202 | 203 | # 市场数据配置 204 | market_data: 205 | orderbook_limit: 100 # 默认订单簿深度 206 | ticker_interval: 1000 # 行情更新间隔(毫秒) 207 | trade_history_limit: 500 # 历史成交记录限制 208 | 209 | # WebSocket配置 210 | websocket: 211 | enabled: true 212 | auto_reconnect: true 213 | max_reconnect_attempts: -1 # 🔥 优化:无限重试,移除次数限制 214 | reconnect_delay: 5 # 🔥 优化:重连延迟从5秒增加到5秒(基础延迟) 215 | ping_interval: 60 # 🔥 优化:心跳间隔从30秒增加到60秒,降低服务器压力 216 | heartbeat_interval: 30 # 🔥 新增:心跳检测间隔30秒 217 | max_silence_time: 180 # 🔥 新增:最大静默时间180秒,增加容忍度 218 | connection_timeout: 30 # 连接超时时间 219 | close_timeout: 10 # 关闭超时时间 220 | 221 | # 错误处理配置 222 | error_handling: 223 | max_retries: 3 224 | retry_delay: 1 # 重试延迟(秒) 225 | retry_backoff: 2 # 重试退避倍数 226 | 227 | # 日志配置 228 | logging: 229 | level: "INFO" 230 | format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 231 | 232 | # 健康检查配置 233 | health_check: 234 | enabled: true 235 | interval: 60 # 健康检查间隔(秒) 236 | timeout: 10 # 健康检查超时(秒) 237 | 238 | # 开发配置 239 | development: 240 | sandbox: false # 是否使用沙盒环境 241 | debug: false # 是否启用调试模式 242 | mock_data: false # 是否使用模拟数据 -------------------------------------------------------------------------------- /config/exchanges/hyperliquid_example.yaml: -------------------------------------------------------------------------------- 1 | # Hyperliquid交易所配置示例 2 | # 此文件展示如何配置Hyperliquid交易所的市场类型 3 | 4 | hyperliquid: 5 | # 基础配置 6 | name: "Hyperliquid" 7 | exchange_id: "hyperliquid" 8 | 9 | # 🚀 示例1:只订阅永续合约市场 10 | market_types: 11 | perpetual: 12 | enabled: true # 启用永续合约 13 | suffix: ":PERP" 14 | description: "永续合约市场" 15 | 16 | spot: 17 | enabled: false # 禁用现货市场 18 | suffix: ":SPOT" 19 | description: "现货市场" 20 | 21 | priority: "perpetual" # 优先级设置为永续合约 22 | default_market: "perpetual" 23 | 24 | # 🚀 示例2:只订阅现货市场 25 | # 如果您只想订阅现货,请将上面的配置改为: 26 | # market_types: 27 | # perpetual: 28 | # enabled: false 29 | # spot: 30 | # enabled: true 31 | # priority: "spot" 32 | # default_market: "spot" 33 | 34 | # 🚀 示例3:同时订阅两种市场 35 | # 如果您想同时订阅,请将上面的配置改为: 36 | # market_types: 37 | # perpetual: 38 | # enabled: true 39 | # spot: 40 | # enabled: true 41 | # priority: "both" 42 | # default_market: "perpetual" # 默认优先永续合约 43 | 44 | # API配置 45 | api: 46 | base_url: "https://api.hyperliquid.xyz" 47 | ws_url: "wss://api.hyperliquid.xyz/ws" 48 | 49 | # 认证配置(可选) 50 | authentication: 51 | api_key: "" 52 | wallet_address: "" 53 | 54 | # 支持的交易对配置 55 | symbols: 56 | # 永续合约交易对 57 | perpetual: 58 | - "BTC/USDC:PERP" 59 | - "ETH/USDC:PERP" 60 | - "SOL/USDC:PERP" 61 | - "AVAX/USDC:PERP" 62 | - "DOGE/USDC:PERP" 63 | - "ADA/USDC:PERP" 64 | - "LINK/USDC:PERP" 65 | - "UNI/USDC:PERP" 66 | 67 | # 现货交易对 68 | spot: 69 | - "BTC/USDC:SPOT" 70 | - "ETH/USDC:SPOT" 71 | - "SOL/USDC:SPOT" 72 | - "AVAX/USDC:SPOT" 73 | 74 | # 符号映射 75 | symbol_mapping: 76 | perpetual: 77 | "BTC/USDC:PERP": "BTC" 78 | "ETH/USDC:PERP": "ETH" 79 | "SOL/USDC:PERP": "SOL" 80 | "AVAX/USDC:PERP": "AVAX" 81 | "DOGE/USDC:PERP": "DOGE" 82 | "ADA/USDC:PERP": "ADA" 83 | "LINK/USDC:PERP": "LINK" 84 | "UNI/USDC:PERP": "UNI" 85 | 86 | spot: 87 | "BTC/USDC:SPOT": "BTC" 88 | "ETH/USDC:SPOT": "ETH" 89 | "SOL/USDC:SPOT": "SOL" 90 | "AVAX/USDC:SPOT": "AVAX" 91 | 92 | # WebSocket配置 93 | websocket: 94 | enabled: true 95 | auto_reconnect: true 96 | max_reconnect_attempts: 5 97 | reconnect_delay: 5 98 | 99 | # 订阅配置 100 | subscriptions: 101 | perpetual: 102 | allMids: true # 所有中间价(ticker数据) 103 | l2Book: true # 订单簿深度 104 | trades: false # 交易记录(可选) 105 | activeAssetCtx: true # 活跃资产上下文 106 | 107 | spot: 108 | allMids: true # 所有中间价 109 | l2Book: true # 订单簿深度 110 | trades: false # 交易记录 111 | activeAssetCtx: false # 现货通常不需要 112 | 113 | # 日志配置 114 | logging: 115 | level: "INFO" 116 | 117 | # 开发配置 118 | development: 119 | debug: false 120 | 121 | # 🔧 配置说明: 122 | # 123 | # 1. 只订阅永续合约: 124 | # - 设置 perpetual.enabled = true 125 | # - 设置 spot.enabled = false 126 | # - 设置 priority = "perpetual" 127 | # 128 | # 2. 只订阅现货: 129 | # - 设置 perpetual.enabled = false 130 | # - 设置 spot.enabled = true 131 | # - 设置 priority = "spot" 132 | # 133 | # 3. 同时订阅两种市场: 134 | # - 设置 perpetual.enabled = true 135 | # - 设置 spot.enabled = true 136 | # - 设置 priority = "both" 137 | # - 设置 default_market 为主要使用的市场 138 | # 139 | # 4. 符号格式: 140 | # - 永续合约:BTC/USDC:PERP 141 | # - 现货:BTC/USDC:SPOT 142 | # - 系统会根据配置自动转换基础币种(如BTC)为相应格式 -------------------------------------------------------------------------------- /config/grid/backpack_follow_long_grid.yaml: -------------------------------------------------------------------------------- 1 | # Backpack 价格移动做多网格配置示例 2 | 3 | grid_system: 4 | # 基础设置 5 | exchange: "backpack" # 交易所 6 | symbol: "BTC_USDC_PERP" # 交易对 7 | 8 | # 网格类型 9 | grid_type: "follow_long" # follow_long=价格移动做多网格 10 | 11 | # 价格移动网格参数(不需要设置upper_price和lower_price) 12 | follow_grid_count: 200 # 网格数量(用户指定) 13 | grid_interval: 50.00 # 网格间隔 14 | follow_timeout: 300 # 脱离超时时间(秒,默认5分钟) 15 | follow_distance: 2 # 脱离距离(网格数,默认1格) 16 | 17 | # 订单设置 18 | order_amount: 0.0001 # 每格订单数量(BTC) 19 | 20 | # 可选设置 21 | max_position: 5.0 # 最大持仓限制(建议设置) 22 | enable_notifications: true # 是否启用通知 23 | fee_rate: 0.0001 # 手续费率(默认0.0001=万分之1) 24 | 25 | # 订单健康检查 26 | order_health_check_interval: 600 # 订单健康检查间隔(秒,默认600=10分钟) 27 | 28 | # 说明: 29 | # 1. 价格区间自动计算: 30 | # - 假设当前价格为 100100 31 | # - 最高价格 = 100100(当前价格) 32 | # - 最低价格 = 100100 - (200 * 100) = 80100 33 | # - 挂单范围:80200 ~ 100000(200个买单) 34 | # 35 | # 2. 价格向上脱离(盈利方向): 36 | # - 条件:当前价格 > 最高价格 + (1 * 100) 37 | # - 持续时间 > 300秒 38 | # - 操作:取消所有订单,以新价格为最高价,重新挂200个买单 39 | # 40 | # 3. 价格向下脱离(亏损方向): 41 | # - 不做任何操作,等待价格恢复 42 | # 43 | # 4. 适用场景: 44 | # - 上涨趋势行情 45 | # - 自动跟随价格上涨 46 | # - 避免网格被价格甩在后面 47 | -------------------------------------------------------------------------------- /config/grid/backpack_follow_short_grid.yaml: -------------------------------------------------------------------------------- 1 | # Backpack 价格移动做空网格配置示例 2 | 3 | grid_system: 4 | # 基础设置 5 | exchange: "backpack" # 交易所 6 | symbol: "BTC_USDC_PERP" # 交易对 7 | 8 | # 网格类型 9 | grid_type: "follow_short" # follow_short=价格移动做空网格 10 | 11 | # 价格移动网格参数(不需要设置upper_price和lower_price) 12 | follow_grid_count: 200 # 网格数量(用户指定) 13 | grid_interval: 100.00 # 网格间隔 14 | follow_timeout: 300 # 脱离超时时间(秒,默认5分钟) 15 | follow_distance: 1 # 脱离距离(网格数,默认1格) 16 | 17 | # 订单设置 18 | order_amount: 0.0001 # 每格订单数量(BTC) 19 | 20 | # 可选设置 21 | max_position: 5.0 # 最大持仓限制(建议设置) 22 | enable_notifications: true # 是否启用通知 23 | fee_rate: 0.0001 # 手续费率(默认0.0001=万分之1) 24 | 25 | # 订单健康检查 26 | order_health_check_interval: 600 # 订单健康检查间隔(秒,默认600=10分钟) 27 | 28 | # 说明: 29 | # 1. 价格区间自动计算: 30 | # - 假设当前价格为 100100 31 | # - 最低价格 = 100100(当前价格) 32 | # - 最高价格 = 100100 + (200 * 100) = 120100 33 | # - 挂单范围:100200 ~ 120100(200个卖单) 34 | # 35 | # 2. 价格向下脱离(盈利方向): 36 | # - 条件:当前价格 < 最低价格 - (1 * 100) 37 | # - 持续时间 > 300秒 38 | # - 操作:取消所有订单,以新价格为最低价,重新挂200个卖单 39 | # 40 | # 3. 价格向上脱离(亏损方向): 41 | # - 不做任何操作,等待价格恢复 42 | # 43 | # 4. 适用场景: 44 | # - 下跌趋势行情 45 | # - 自动跟随价格下跌 46 | # - 避免网格被价格甩在后面 47 | -------------------------------------------------------------------------------- /config/grid/backpack_long_grid.yaml: -------------------------------------------------------------------------------- 1 | # Backpack BTC 做多网格配置示例 2 | 3 | grid_system: 4 | # 基础设置 5 | exchange: "backpack" # 交易所 6 | symbol: "BTC_USDC_PERP" # 交易对 7 | 8 | # 网格类型 9 | grid_type: "long" # long=做多网格, short=做空网格 10 | 11 | # 价格区间设置(做多网格:从高到低) 12 | price_range: 13 | upper_price: 123500.00 # 价格上限 14 | lower_price: 103600.00 # 价格下限 15 | 16 | grid_interval: 100.00 # 网格间隔(等差) 17 | 18 | # 订单设置 19 | order_amount: 0.0001 # 每格订单数量(BTC) 20 | 21 | # 可选设置 22 | max_position: 2.0 # 最大持仓限制(可选) 23 | enable_notifications: true # 是否启用通知 24 | fee_rate: 0.0001 # 手续费率(默认0.0001=万分之1) 25 | 26 | # 订单健康检查 27 | order_health_check_interval: 600 # 订单健康检查间隔(秒,默认600=10分钟) 28 | 29 | # 说明: 30 | # 1. 网格数量自动计算:(100000 - 80000) / 100 = 200个网格 31 | # 2. 第一个订单价格:99900(上限 - 1格) 32 | # 3. 每个网格预期利润:100 * 0.025 = 2.5 USDC 33 | # 4. 震荡100次收益:250 USDC(减去手续费) 34 | 35 | -------------------------------------------------------------------------------- /config/grid/backpack_martingale_long_grid.yaml: -------------------------------------------------------------------------------- 1 | # Backpack BTC 马丁做多网格配置示例 2 | 3 | grid_system: 4 | # 基础设置 5 | exchange: "backpack" # 交易所 6 | symbol: "BTC_USDC_PERP" # 交易对 7 | 8 | # 网格类型 9 | grid_type: "martingale_long" # martingale_long=马丁做多网格 10 | 11 | # 价格区间设置(做多网格:从高到低) 12 | price_range: 13 | upper_price: 123500.00 # 价格上限 14 | lower_price: 103600.00 # 价格下限 15 | 16 | grid_interval: 100.00 # 网格间隔(等差) 17 | 18 | # 订单设置 19 | order_amount: 0.001 # 基础订单数量(BTC) 20 | 21 | # 马丁网格设置 22 | martingale_increment: 0.001 # 每格递增金额(BTC) 23 | 24 | # 可选设置 25 | max_position: 20.0 # 最大持仓限制(可选) 26 | enable_notifications: true # 是否启用通知 27 | fee_rate: 0.0001 # 手续费率(默认0.0001=万分之1) 28 | 29 | # 订单健康检查 30 | order_health_check_interval: 600 # 订单健康检查间隔(秒,默认600=10分钟) 31 | 32 | # 说明: 33 | # 1. 网格数量自动计算:(123500 - 103600) / 100 = 199个网格 34 | # 2. 马丁网格订单金额递增: 35 | # Grid 1 (123400): 0.001 BTC ← 最高价格,最小金额 36 | # Grid 2 (123300): 0.002 BTC 37 | # Grid 3 (123200): 0.003 BTC 38 | # ... 39 | # Grid 199 (103700): 0.199 BTC ← 最低价格,最大金额 40 | # 3. 反向订单金额 = 成交订单的实际金额 41 | # 4. 风险提示:马丁网格在价格持续下跌时会大幅增加持仓,请谨慎设置! 42 | # 5. 建议设置 max_position 限制最大持仓 43 | 44 | -------------------------------------------------------------------------------- /config/grid/backpack_martingale_short_grid.yaml: -------------------------------------------------------------------------------- 1 | # Backpack BTC 马丁做空网格配置示例 2 | 3 | grid_system: 4 | # 基础设置 5 | exchange: "backpack" # 交易所 6 | symbol: "BTC_USDC_PERP" # 交易对 7 | 8 | # 网格类型 9 | grid_type: "martingale_short" # martingale_short=马丁做空网格 10 | 11 | # 价格区间设置(做空网格:从低到高) 12 | price_range: 13 | upper_price: 123500.00 # 价格上限 14 | lower_price: 103600.00 # 价格下限 15 | 16 | grid_interval: 100.00 # 网格间隔(等差) 17 | 18 | # 订单设置 19 | order_amount: 0.001 # 基础订单数量(BTC) 20 | 21 | # 马丁网格设置 22 | martingale_increment: 0.001 # 每格递增金额(BTC) 23 | 24 | # 可选设置 25 | max_position: 20.0 # 最大持仓限制(可选) 26 | enable_notifications: true # 是否启用通知 27 | fee_rate: 0.0001 # 手续费率(默认0.0001=万分之1) 28 | 29 | # 订单健康检查 30 | order_health_check_interval: 600 # 订单健康检查间隔(秒,默认600=10分钟) 31 | 32 | # 说明: 33 | # 1. 网格数量自动计算:(123500 - 103600) / 100 = 199个网格 34 | # 2. 马丁网格订单金额递增: 35 | # Grid 1 (103700): 0.001 BTC ← 最低价格,最小金额 36 | # Grid 2 (103800): 0.002 BTC 37 | # Grid 3 (103900): 0.003 BTC 38 | # ... 39 | # Grid 199 (123400): 0.199 BTC ← 最高价格,最大金额 40 | # 3. 反向订单金额 = 成交订单的实际金额 41 | # 4. 风险提示:马丁网格在价格持续上涨时会大幅增加持仓,请谨慎设置! 42 | # 5. 建议设置 max_position 限制最大持仓 43 | -------------------------------------------------------------------------------- /config/grid/backpack_short_grid.yaml: -------------------------------------------------------------------------------- 1 | # Backpack BTC 做空网格配置示例 2 | 3 | grid_system: 4 | # 基础设置 5 | exchange: "backpack" # 交易所 6 | symbol: "BTC_USDC_PERP" # 交易对 7 | 8 | # 网格类型 9 | grid_type: "short" # long=做多网格, short=做空网格 10 | 11 | # 价格区间设置(做空网格:从低到高) 12 | price_range: 13 | lower_price: 80000.00 # 价格下限 14 | upper_price: 100000.00 # 价格上限 15 | 16 | grid_interval: 100.00 # 网格间隔(等差) 17 | 18 | # 订单设置 19 | order_amount: 0.025 # 每格订单数量(BTC) 20 | 21 | # 可选设置 22 | max_position: 2.0 # 最大持仓限制(可选) 23 | enable_notifications: true # 是否启用通知 24 | fee_rate: 0.0001 # 手续费率(默认0.0001=万分之1) 25 | 26 | # 订单健康检查 27 | order_health_check_interval: 600 # 订单健康检查间隔(秒,默认600=10分钟) 28 | 29 | # 说明: 30 | # 1. 网格数量自动计算:(100000 - 80000) / 100 = 200个网格 31 | # 2. 第一个订单价格:80100(下限 + 1格) 32 | # 3. 每个网格预期利润:100 * 0.025 = 2.5 USDC 33 | # 4. 震荡100次收益:250 USDC(减去手续费) 34 | 35 | -------------------------------------------------------------------------------- /config/grid/default_grid.yaml: -------------------------------------------------------------------------------- 1 | # 默认网格配置模板 2 | 3 | grid_system: 4 | # 基础设置 5 | exchange: "backpack" # 交易所:backpack, binance, okx 6 | symbol: "BTC_USDC_PERP" # 交易对 7 | 8 | # 网格类型 9 | grid_type: "long" # long=做多网格, short=做空网格 10 | 11 | # 价格区间设置 12 | price_range: 13 | upper_price: 100000.00 # 价格上限 14 | lower_price: 80000.00 # 价格下限 15 | 16 | grid_interval: 300.00 # 网格间隔(等差) 17 | 18 | # 订单设置 19 | order_amount: 0.01 # 每格订单数量 20 | 21 | # 可选设置 22 | max_position: null # 最大持仓限制(null=无限制) 23 | enable_notifications: false # 是否启用通知 24 | fee_rate: 0.0001 # 手续费率(默认0.0001=万分之1) 25 | 26 | # 订单健康检查 27 | order_health_check_interval: 600 # 订单健康检查间隔(秒,默认600=10分钟) 28 | 29 | # 交易所连接设置 30 | exchange_config: 31 | # API密钥从环境变量或交易所配置文件读取 32 | # 请在 config/exchanges/backpack_config.yaml 中配置API密钥 33 | # 或设置环境变量: 34 | # export BACKPACK_API_KEY="your_api_key" 35 | # export BACKPACK_API_SECRET="your_api_secret" 36 | 37 | # 连接参数 38 | timeout: 30 # 请求超时(秒) 39 | enable_rate_limit: true # 启用限频 40 | 41 | # 日志设置 42 | logging: 43 | level: "INFO" # DEBUG, INFO, WARNING, ERROR 44 | file: "logs/grid_trading/grid_system.log" 45 | max_size: "100MB" 46 | backup_count: 10 47 | 48 | # 终端界面设置 49 | terminal: 50 | refresh_rate: 4 # 刷新频率(次/秒) 51 | history_limit: 10 # 显示历史订单数量 52 | enable_colors: true # 启用彩色输出 53 | 54 | -------------------------------------------------------------------------------- /config/logging.yaml: -------------------------------------------------------------------------------- 1 | # MESA交易系统日志配置 2 | # 版本: 1.0.0 3 | 4 | version: "1.0" 5 | environment: "development" # development, testing, production 6 | root_level: "INFO" 7 | disable_existing_loggers: false 8 | log_directory: "logs" 9 | async_logging: false 10 | buffer_size: 1000 11 | flush_interval: 1.0 12 | enable_sensitive_data_filter: true 13 | log_file_permissions: 0o640 14 | 15 | # 处理器配置 16 | handlers: 17 | # 控制台处理器 - 开发环境实时查看 18 | console: 19 | type: "console" 20 | level: "INFO" 21 | format: "colored" 22 | enabled: true 23 | include_module: true 24 | include_thread: false 25 | include_process: false 26 | date_format: "%H:%M:%S" 27 | exclude_modules: 28 | - "websockets" 29 | - "aiohttp" 30 | - "asyncio" 31 | - "urllib3" 32 | 33 | # 主系统日志文件 (优化: 将级别从DEBUG提升到INFO以减少磁盘压力) 34 | main_file: 35 | type: "rotating_file" 36 | level: "INFO" 37 | format: "json" 38 | enabled: true 39 | filename: "logs/trading_system.log" 40 | max_bytes: 52428800 # 50MB 41 | backup_count: 10 42 | include_module: true 43 | include_thread: false 44 | include_process: false 45 | date_format: "%Y-%m-%d %H:%M:%S" 46 | 47 | # 错误日志文件 48 | error_file: 49 | type: "rotating_file" 50 | level: "ERROR" 51 | format: "json" 52 | enabled: true 53 | filename: "logs/error.log" 54 | max_bytes: 10485760 # 10MB 55 | backup_count: 5 56 | include_module: true 57 | include_thread: true 58 | include_process: false 59 | date_format: "%Y-%m-%d %H:%M:%S" 60 | 61 | # 数据流日志文件 62 | data_file: 63 | type: "rotating_file" 64 | level: "INFO" 65 | format: "json" 66 | enabled: true 67 | filename: "logs/data.log" 68 | max_bytes: 20971520 # 20MB 69 | backup_count: 3 70 | include_module: false 71 | include_thread: false 72 | include_process: false 73 | date_format: "%Y-%m-%d %H:%M:%S" 74 | exclude_modules: 75 | - "core.logging" 76 | 77 | # 交易日志文件 78 | trading_file: 79 | type: "rotating_file" 80 | level: "INFO" 81 | format: "json" 82 | enabled: true 83 | filename: "logs/trading.log" 84 | max_bytes: 20971520 # 20MB 85 | backup_count: 5 86 | include_module: true 87 | include_thread: false 88 | include_process: false 89 | date_format: "%Y-%m-%d %H:%M:%S" 90 | 91 | # 性能日志文件 92 | performance_file: 93 | type: "rotating_file" 94 | level: "INFO" 95 | format: "performance" 96 | enabled: true 97 | filename: "logs/performance.log" 98 | max_bytes: 10485760 # 10MB 99 | backup_count: 3 100 | include_module: true 101 | include_thread: false 102 | include_process: false 103 | date_format: "%Y-%m-%d %H:%M:%S" 104 | 105 | # 交易所日志文件 106 | exchange_file: 107 | type: "rotating_file" 108 | level: "INFO" 109 | format: "json" 110 | enabled: true 111 | filename: "logs/exchanges.log" 112 | max_bytes: 20971520 # 20MB 113 | backup_count: 5 114 | include_module: true 115 | include_thread: false 116 | include_process: false 117 | date_format: "%Y-%m-%d %H:%M:%S" 118 | 119 | # 日志记录器配置 120 | loggers: 121 | # 根日志记录器 122 | root: 123 | level: "INFO" 124 | handlers: ["console", "main_file", "error_file"] 125 | propagate: false 126 | enabled: true 127 | include_context: true 128 | include_correlation_id: false 129 | include_performance_metrics: false 130 | 131 | # 系统日志记录器 132 | system: 133 | level: "INFO" 134 | handlers: ["console", "main_file"] 135 | propagate: false 136 | enabled: true 137 | include_context: true 138 | include_correlation_id: false 139 | include_performance_metrics: false 140 | 141 | # 数据日志记录器 142 | data: 143 | level: "INFO" 144 | handlers: ["data_file"] 145 | propagate: false 146 | enabled: true 147 | include_context: true 148 | include_correlation_id: false 149 | include_performance_metrics: true 150 | max_message_length: 1000 151 | 152 | # 错误日志记录器 153 | errors: 154 | level: "WARNING" 155 | handlers: ["console", "main_file", "error_file"] 156 | propagate: false 157 | enabled: true 158 | include_context: true 159 | include_correlation_id: true 160 | include_performance_metrics: false 161 | 162 | # 性能日志记录器 163 | performance: 164 | level: "INFO" 165 | handlers: ["performance_file"] 166 | propagate: false 167 | enabled: true 168 | include_context: true 169 | include_correlation_id: false 170 | include_performance_metrics: true 171 | 172 | # 交易日志记录器 173 | trading: 174 | level: "INFO" 175 | handlers: ["console", "main_file", "trading_file"] 176 | propagate: false 177 | enabled: true 178 | include_context: true 179 | include_correlation_id: true 180 | include_performance_metrics: false 181 | 182 | # 交易所日志记录器 183 | exchanges: 184 | level: "INFO" 185 | handlers: ["console", "main_file", "exchange_file"] 186 | propagate: false 187 | enabled: true 188 | include_context: true 189 | include_correlation_id: true 190 | include_performance_metrics: false 191 | 192 | # 核心模块日志配置 193 | core: 194 | level: "INFO" 195 | handlers: ["console", "main_file"] 196 | propagate: false 197 | enabled: true 198 | include_context: true 199 | 200 | # Socket.IO服务器日志 201 | socketio: 202 | level: "INFO" 203 | handlers: ["console", "main_file"] 204 | propagate: false 205 | enabled: true 206 | include_context: true 207 | 208 | # EdgeX交易所日志 209 | edgex: 210 | level: "INFO" 211 | handlers: ["console", "exchange_file"] 212 | propagate: false 213 | enabled: true 214 | include_context: true 215 | include_correlation_id: true 216 | 217 | # Backpack交易所日志 218 | backpack: 219 | level: "INFO" 220 | handlers: ["console", "exchange_file"] 221 | propagate: false 222 | enabled: true 223 | include_context: true 224 | include_correlation_id: true 225 | 226 | # 🔥 新增:Hyperliquid交易所日志 227 | hyperliquid: 228 | level: "INFO" 229 | handlers: ["console", "exchange_file"] 230 | propagate: false 231 | enabled: true 232 | include_context: true 233 | include_correlation_id: true 234 | 235 | # WebSocket数据相关服务日志优化 (减少详细日志以节省磁盘空间) 236 | MarketDataService: 237 | level: "WARNING" 238 | handlers: ["console", "main_file"] 239 | propagate: false 240 | enabled: true 241 | include_context: true 242 | 243 | EnhancedMonitoringServiceImpl: 244 | level: "WARNING" 245 | handlers: ["console", "main_file"] 246 | propagate: false 247 | enabled: true 248 | include_context: true 249 | 250 | SubscriptionService: 251 | level: "WARNING" 252 | handlers: ["console", "main_file"] 253 | propagate: false 254 | enabled: true 255 | include_context: true 256 | 257 | # 第三方库日志控制 258 | websockets: 259 | level: "ERROR" 260 | handlers: ["error_file"] 261 | propagate: false 262 | enabled: true 263 | 264 | aiohttp: 265 | level: "ERROR" 266 | handlers: ["error_file"] 267 | propagate: false 268 | enabled: true 269 | 270 | asyncio: 271 | level: "ERROR" 272 | handlers: ["error_file"] 273 | propagate: false 274 | enabled: true 275 | 276 | urllib3: 277 | level: "ERROR" 278 | handlers: ["error_file"] 279 | propagate: false 280 | enabled: true 281 | 282 | # 🔥 新增:交易所统计信息打印频率配置 283 | exchange_statistics_frequency: 284 | # 根据交易所支持的币种数量动态调整统计信息打印频率 285 | # 币种数量越多,打印频率越低,避免日志过于频繁 286 | 287 | # 默认配置(适用于小型交易所) 288 | default: 289 | message_stats_frequency: 100 # 每100条消息打印一次统计 290 | callback_stats_frequency: 50 # 每50个回调打印一次统计 291 | orderbook_stats_frequency: 50 # 每50个orderbook打印一次统计 292 | global_callback_frequency: 50 # 每50个全局回调打印一次统计 293 | 294 | # EdgeX交易所(支持约50种币种) 295 | edgex: 296 | message_stats_frequency: 100 # 每100条消息打印一次统计 297 | callback_stats_frequency: 50 # 每50个回调打印一次统计 298 | orderbook_stats_frequency: 50 # 每50个orderbook打印一次统计 299 | global_callback_frequency: 50 # 每50个全局回调打印一次统计 300 | 301 | # Backpack交易所(支持约30种币种) 302 | backpack: 303 | message_stats_frequency: 100 # 每100条消息打印一次统计 304 | callback_stats_frequency: 30 # 每30个回调打印一次统计 305 | orderbook_stats_frequency: 30 # 每30个orderbook打印一次统计 306 | global_callback_frequency: 30 # 每30个全局回调打印一次统计 307 | 308 | # 🔥 Hyperliquid交易所(支持数百种币种)- 大幅降低打印频率 309 | hyperliquid: 310 | message_stats_frequency: 1000 # 每1000条消息打印一次统计 311 | callback_stats_frequency: 500 # 每500个回调打印一次统计 312 | orderbook_stats_frequency: 500 # 每500个orderbook打印一次统计 313 | global_callback_frequency: 500 # 每500个全局回调打印一次统计 314 | 315 | # 自适应配置规则 316 | adaptive_rules: 317 | # 根据币种数量自动调整频率 318 | # 如果币种数量超过threshold,则使用对应的multiplier 319 | thresholds: 320 | small_exchange: 321 | max_symbols: 50 322 | multiplier: 1.0 323 | medium_exchange: 324 | max_symbols: 100 325 | multiplier: 2.0 326 | large_exchange: 327 | max_symbols: 200 328 | multiplier: 5.0 329 | huge_exchange: 330 | max_symbols: 500 331 | multiplier: 10.0 -------------------------------------------------------------------------------- /core/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptocj520/grid/4b2ae95f2afcd2e5381e5ab2f2673eb60d51b9a0/core/.DS_Store -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | Trading System 核心模块 3 | 4 | 新架构的核心模块,提供依赖注入和服务接口。 5 | 6 | 主要组件: 7 | - di: 依赖注入容器 8 | - services: 服务层接口和实现 9 | - domain: 领域模型 10 | - infrastructure: 基础设施层 11 | - adapters: 适配器层 12 | """ 13 | 14 | __version__ = "2.0.0" 15 | __author__ = "Trading System Team" 16 | 17 | # 导入新架构的核心组件 18 | from .di.container import get_container, DIContainer 19 | from .services.interfaces.base import IService, BaseService 20 | # 日志服务已简化,直接使用统一入口 21 | # from .services.interfaces.logging import ILoggingService 22 | from .services.interfaces.monitoring_service import MonitoringService 23 | 24 | __all__ = [ 25 | "get_container", 26 | "DIContainer", 27 | "IService", 28 | "BaseService", 29 | # "ILoggingService", # 已简化,使用 core.logging 统一入口 30 | "MonitoringService" 31 | ] 32 | -------------------------------------------------------------------------------- /core/adapters/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/adapters/exchanges/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptocj520/grid/4b2ae95f2afcd2e5381e5ab2f2673eb60d51b9a0/core/adapters/exchanges/.DS_Store -------------------------------------------------------------------------------- /core/adapters/exchanges/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | MESA交易所适配层模块 3 | 4 | 本模块提供统一的交易所接口和适配器实现,支持多种交易所的统一管理。 5 | 采用事件驱动架构,与MESA引擎核心组件无缝集成。 6 | 7 | 核心组件: 8 | - ExchangeInterface: 标准化交易所接口 9 | - ExchangeAdapter: 交易所适配器基类 10 | - ExchangeFactory: 交易所工厂,统一管理和创建交易所实例 11 | - ExchangeManager: 交易所管理器,处理生命周期管理 12 | - 具体交易所实现: HyperliquidAdapter, BackpackAdapter, BinanceAdapter 13 | 14 | 特性: 15 | - 异步优先的API设计 16 | - 事件驱动的数据流 17 | - 统一的错误处理机制 18 | - 自动重连和健康检查 19 | - 配置驱动的适配器创建 20 | 21 | 版本: 1.0.0 22 | 作者: MESA开发团队 23 | """ 24 | 25 | from .interface import ExchangeInterface, ExchangeConfig, ExchangeStatus 26 | from .models import ( 27 | ExchangeType, 28 | OrderSide, 29 | OrderType, 30 | OrderStatus, 31 | PositionSide, 32 | MarginMode, 33 | OrderData, 34 | PositionData, 35 | BalanceData, 36 | TickerData, 37 | OHLCVData, 38 | OrderBookData, 39 | TradeData 40 | ) 41 | from .adapter import ExchangeAdapter 42 | from .factory import ExchangeFactory, get_exchange_factory 43 | from .manager import ExchangeManager 44 | 45 | # 具体交易所适配器 46 | from .adapters.hyperliquid import HyperliquidAdapter 47 | from .adapters.backpack import BackpackAdapter 48 | from .adapters.binance import BinanceAdapter 49 | 50 | __all__ = [ 51 | # 核心接口和基类 52 | 'ExchangeInterface', 53 | 'ExchangeConfig', 54 | 'ExchangeStatus', 55 | 'ExchangeAdapter', 56 | 57 | # 数据模型 58 | 'ExchangeType', 59 | 'OrderSide', 60 | 'OrderType', 61 | 'OrderStatus', 62 | 'PositionSide', 63 | 'MarginMode', 64 | 'OrderData', 65 | 'PositionData', 66 | 'BalanceData', 67 | 'TickerData', 68 | 'OHLCVData', 69 | 'OrderBookData', 70 | 'TradeData', 71 | 72 | # 管理组件 73 | 'ExchangeFactory', 74 | 'get_exchange_factory', 75 | 'ExchangeManager', 76 | 77 | # 具体适配器 78 | 'HyperliquidAdapter', 79 | 'BackpackAdapter', 80 | 'BinanceAdapter', 81 | ] 82 | 83 | # 版本信息 84 | __version__ = '1.0.0' 85 | -------------------------------------------------------------------------------- /core/adapters/exchanges/adapters/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptocj520/grid/4b2ae95f2afcd2e5381e5ab2f2673eb60d51b9a0/core/adapters/exchanges/adapters/.DS_Store -------------------------------------------------------------------------------- /core/adapters/exchanges/adapters/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 交易所适配器子模块 3 | 4 | 包含各个具体交易所的适配器实现,每个适配器都基于统一的ExchangeInterface 5 | 接口,提供标准化的交易所功能。 6 | 7 | 支持的交易所: 8 | - Hyperliquid: 永续合约交易所 9 | - Backpack: 永续合约交易所 10 | - Binance: 期货交易所 11 | - OKX: 现货、永续合约、期货、期权交易所 12 | - EdgeX: 永续合约交易所 13 | 14 | 每个适配器都包含: 15 | - 完整的交易功能实现 16 | - WebSocket实时数据流支持 17 | - 自动重连和错误处理 18 | - 符合MESA事件驱动架构 19 | """ 20 | 21 | from .hyperliquid import HyperliquidAdapter 22 | from .backpack import BackpackAdapter 23 | from .binance import BinanceAdapter 24 | from .okx import OKXAdapter 25 | from .edgex import EdgeXAdapter 26 | 27 | __all__ = [ 28 | 'HyperliquidAdapter', 29 | 'BackpackAdapter', 30 | 'BinanceAdapter', 31 | 'OKXAdapter', 32 | 'EdgeXAdapter' 33 | ] 34 | -------------------------------------------------------------------------------- /core/adapters/exchanges/adapters/hyperliquid_base copy.md: -------------------------------------------------------------------------------- 1 | def _setup_symbol_mappings(self): 2 | """设置符号映射""" 3 | # 🚀 根据配置文件创建符号映射 4 | self._default_symbol_mapping = {} 5 | 6 | # 🔥 优先使用配置文件中的映射 7 | if hasattr(self, 'market_config') and self.market_config: 8 | symbol_mappings = self.market_config.get('symbol_mapping', {}) 9 | 10 | # 添加 Backpack 格式映射(最重要的映射) 11 | backpack_mappings = symbol_mappings.get('backpack_to_hyperliquid', {}) 12 | if backpack_mappings: 13 | self._default_symbol_mapping.update(backpack_mappings) 14 | if self.logger: 15 | self.logger.info(f"✅ 从配置文件加载 {len(backpack_mappings)} 个Backpack格式映射") 16 | 17 | # 添加永续合约映射 18 | if hasattr(self, 'perpetual_enabled') and self.perpetual_enabled: 19 | perpetual_mappings = symbol_mappings.get('perpetual', {}) 20 | if perpetual_mappings: 21 | self._default_symbol_mapping.update(perpetual_mappings) 22 | if self.logger: 23 | self.logger.info(f"✅ 从配置文件加载 {len(perpetual_mappings)} 个永续合约映射") 24 | 25 | # 添加现货映射 26 | if hasattr(self, 'spot_enabled') and self.spot_enabled: 27 | spot_mappings = symbol_mappings.get('spot', {}) 28 | if spot_mappings: 29 | self._default_symbol_mapping.update(spot_mappings) 30 | if self.logger: 31 | self.logger.info(f"✅ 从配置文件加载 {len(spot_mappings)} 个现货映射") 32 | 33 | # 🔥 备用映射:如果配置文件映射失败,使用基本映射 34 | if not self._default_symbol_mapping: 35 | if self.logger: 36 | self.logger.warning("⚠️ 配置文件中没有符号映射,使用备用硬编码映射") 37 | 38 | # 基本的Backpack格式映射 39 | self._default_symbol_mapping = { 40 | # 🔥 核心映射:Backpack格式 -> Hyperliquid格式 41 | "BTC_USDC_PERP": "BTC/USDC:USDC", 42 | "ETH_USDC_PERP": "ETH/USDC:USDC", 43 | "SOL_USDC_PERP": "SOL/USDC:USDC", 44 | "AVAX_USDC_PERP": "AVAX/USDC:USDC", 45 | "DOGE_USDC_PERP": "DOGE/USDC:USDC", 46 | "ADA_USDC_PERP": "ADA/USDC:USDC", 47 | "LINK_USDC_PERP": "LINK/USDC:USDC", 48 | 49 | # 标准格式保持不变 50 | "BTC/USDC:USDC": "BTC/USDC:USDC", 51 | "ETH/USDC:USDC": "ETH/USDC:USDC", 52 | "SOL/USDC:USDC": "SOL/USDC:USDC", 53 | "AVAX/USDC:USDC": "AVAX/USDC:USDC" 54 | } 55 | 56 | # 合并用户配置的符号映射(最高优先级) 57 | if self.config and hasattr(self.config, 'symbol_mapping') and self.config.symbol_mapping: 58 | self._default_symbol_mapping.update(self.config.symbol_mapping) 59 | if self.logger: 60 | self.logger.info(f"✅ 从用户配置加载 {len(self.config.symbol_mapping)} 个额外映射") 61 | 62 | def map_symbol(self, symbol: str) -> str: 63 | """映射交易对符号到Hyperliquid格式""" 64 | # 🔍 调试:检查映射字典内容 65 | if self.logger and not hasattr(self, '_debug_logged'): 66 | self.logger.info(f"🔍 映射字典大小: {len(self._default_symbol_mapping)}") 67 | if self._default_symbol_mapping: 68 | sample_mappings = dict(list(self._default_symbol_mapping.items())[:3]) 69 | self.logger.info(f"🔍 映射字典示例: {sample_mappings}") 70 | self._debug_logged = True 71 | 72 | mapped = self._default_symbol_mapping.get(symbol, symbol) 73 | 74 | # 添加调试日志 75 | if self.logger and mapped != symbol: 76 | self.logger.info(f"🔄 Hyperliquid符号映射: {symbol} -> {mapped}") 77 | elif self.logger and mapped == symbol: 78 | self.logger.warning(f"⚠️ Hyperliquid符号未映射: {symbol} (保持原样)") 79 | 80 | return mapped 81 | 82 | def reverse_map_symbol(self, exchange_symbol: str) -> str: 83 | """反向映射交易对符号从Hyperliquid格式""" 84 | # 🔧 修复:首先尝试完整映射 85 | reverse_mapping = {v: k for k, v in self._default_symbol_mapping.items()} 86 | result = reverse_mapping.get(exchange_symbol, None) 87 | 88 | if result: 89 | return result 90 | 91 | # 🚀 修复:根据配置的市场类型进行转换 92 | if exchange_symbol and '/' not in exchange_symbol and ':' not in exchange_symbol: 93 | # 这是一个基础币种,转换为标准格式 94 | base_coin = exchange_symbol.upper() 95 | 96 | # 🔥 修复:统一使用:USDC格式以匹配系统其他部分 97 | standard_symbol = f"{base_coin}/USDC:USDC" 98 | 99 | # 🔧 修复:添加调试信息 100 | if self.logger: 101 | self.logger.debug(f"🔄 动态币种转换: {exchange_symbol} -> {standard_symbol} (统一格式)") 102 | 103 | return standard_symbol 104 | 105 | # 🔧 修复:对于其他格式,尝试规范化后再转换 106 | if exchange_symbol: 107 | # 尝试处理不同的格式 108 | if exchange_symbol.endswith('-USD'): 109 | # BTC-USD -> BTC/USDC:USDC(统一格式) 110 | base_coin = exchange_symbol.replace('-USD', '') 111 | standard_symbol = f"{base_coin}/USDC:USDC" 112 | if self.logger: 113 | self.logger.debug(f"🔄 USD格式转换: {exchange_symbol} -> {standard_symbol}") 114 | return standard_symbol 115 | elif exchange_symbol.endswith('/USDC:USDC'): 116 | # BTC/USDC:USDC -> BTC/USDC:USDC(保持不变) 117 | if self.logger: 118 | self.logger.debug(f"🔄 USDC格式保持: {exchange_symbol}") 119 | return exchange_symbol 120 | 121 | # 如果都没有匹配,返回原值 122 | if self.logger: 123 | self.logger.debug(f"⚠️ 无法转换符号: {exchange_symbol}") 124 | return exchange_symbol 125 | 126 | -> 127 | 128 | # symbol mapping相关方法已移除 - 现在由执行器统一处理格式转换 -------------------------------------------------------------------------------- /core/di/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/di/container.py: -------------------------------------------------------------------------------- 1 | """ 2 | 依赖注入容器 3 | 4 | 基于 Python-injector 的依赖注入容器实现 5 | """ 6 | 7 | from injector import Injector, Module, singleton, provider 8 | from typing import Dict, Any, Type, Optional, List 9 | 10 | # 使用简化的统一日志入口 11 | from ..logging import get_system_logger 12 | 13 | 14 | class DIContainer: 15 | """依赖注入容器""" 16 | 17 | def __init__(self, modules: List[Module] = None): 18 | self.modules = modules or [] 19 | self.injector = Injector(self.modules) 20 | self.logger = get_system_logger() 21 | self.initialized = False 22 | 23 | def register_module(self, module: Module): 24 | """注册模块""" 25 | self.modules.append(module) 26 | self.injector = Injector(self.modules) 27 | self.logger.info(f"注册模块: {module.__class__.__name__}") 28 | 29 | def register_modules(self, modules: List[Module]): 30 | """注册多个模块""" 31 | for module in modules: 32 | self.modules.append(module) 33 | self.injector = Injector(self.modules) 34 | self.logger.info(f"注册了 {len(modules)} 个模块") 35 | 36 | def get(self, interface: Type): 37 | """获取实例""" 38 | return self.injector.get(interface) 39 | 40 | def create_child_injector(self, modules: list = None): 41 | """创建子注入器""" 42 | child_modules = self.modules + (modules or []) 43 | return Injector(child_modules) 44 | 45 | def initialize(self): 46 | """初始化容器""" 47 | if not self.initialized: 48 | # 自动注册默认模块 49 | from .modules import ALL_MODULES 50 | self.register_modules([module() for module in ALL_MODULES]) 51 | self.initialized = True 52 | self.logger.info("依赖注入容器已初始化") 53 | 54 | 55 | # 全局容器实例 56 | container = DIContainer() 57 | 58 | 59 | def get_container() -> DIContainer: 60 | """获取全局容器""" 61 | if not container.initialized: 62 | container.initialize() 63 | return container 64 | -------------------------------------------------------------------------------- /core/di/decorators.py: -------------------------------------------------------------------------------- 1 | """ 2 | 依赖注入装饰器 3 | 4 | 提供便捷的依赖注入装饰器 5 | """ 6 | 7 | from injector import inject, singleton 8 | from typing import Type, Callable 9 | import functools 10 | 11 | 12 | def injectable(scope: str = "transient"): 13 | """注册为可注入的服务""" 14 | def decorator(cls: Type): 15 | if scope == "singleton": 16 | cls = singleton(cls) 17 | return cls 18 | return decorator 19 | 20 | 21 | def service(interface: Type = None, scope: str = "transient"): 22 | """服务装饰器""" 23 | def decorator(cls: Type): 24 | cls = injectable(scope)(cls) 25 | if interface: 26 | # 注册接口映射 27 | pass 28 | return cls 29 | return decorator 30 | 31 | 32 | def auto_inject(func: Callable): 33 | """自动注入装饰器""" 34 | @functools.wraps(func) 35 | @inject 36 | def wrapper(*args, **kwargs): 37 | return func(*args, **kwargs) 38 | return wrapper 39 | -------------------------------------------------------------------------------- /core/di/modules.py: -------------------------------------------------------------------------------- 1 | """ 2 | 依赖注入模块配置 3 | 4 | 定义各个模块的依赖注入绑定规则 5 | """ 6 | 7 | from injector import Module, singleton, provider 8 | 9 | # 服务接口和实现 10 | from ..services.interfaces.config_service import IConfigurationService 11 | from ..services.implementations.config_service import ConfigurationServiceImpl 12 | from ..services.interfaces.monitoring_service import MonitoringService 13 | from ..services.implementations.enhanced_monitoring_service import EnhancedMonitoringServiceImpl 14 | from ..services.events.event_handler import EventHandler 15 | 16 | # 符号服务 - 统一从symbol_manager模块导入 17 | from ..services.symbol_manager.interfaces.symbol_conversion_service import ISymbolConversionService 18 | from ..services.symbol_manager.implementations.symbol_conversion_service import SymbolConversionService 19 | from ..services.symbol_manager.interfaces.symbol_cache import ISymbolCacheService 20 | from ..services.symbol_manager.implementations.symbol_cache_service import SymbolCacheServiceImpl 21 | 22 | # 适配器和数据模块 23 | from ..adapters.exchanges.manager import ExchangeManager 24 | from ..adapters.exchanges.factory import ExchangeFactory 25 | from ..data_aggregator import DataAggregator 26 | 27 | 28 | class ConfigModule(Module): 29 | """配置模块""" 30 | 31 | def configure(self, binder): 32 | binder.bind(IConfigurationService, to=ConfigurationServiceImpl, scope=singleton) 33 | 34 | 35 | class EventModule(Module): 36 | """事件模块""" 37 | 38 | def configure(self, binder): 39 | binder.bind(EventHandler, to=EventHandler, scope=singleton) 40 | 41 | 42 | class ExchangeModule(Module): 43 | """交易所模块""" 44 | 45 | def configure(self, binder): 46 | binder.bind(ExchangeManager, to=ExchangeManager, scope=singleton) 47 | binder.bind(ExchangeFactory, to=ExchangeFactory, scope=singleton) 48 | 49 | 50 | class SymbolModule(Module): 51 | """符号服务模块""" 52 | 53 | def configure(self, binder): 54 | # 符号转换服务 - 使用singleton绑定 55 | binder.bind(ISymbolConversionService, to=SymbolConversionService, scope=singleton) 56 | 57 | @singleton 58 | @provider 59 | def provide_symbol_cache_service(self, 60 | exchange_manager: ExchangeManager, 61 | symbol_conversion_service: ISymbolConversionService) -> ISymbolCacheService: 62 | """提供符号缓存服务实例""" 63 | return SymbolCacheServiceImpl(exchange_manager, symbol_conversion_service) 64 | 65 | 66 | class DataModule(Module): 67 | """数据模块""" 68 | 69 | def configure(self, binder): 70 | binder.bind(DataAggregator, to=DataAggregator, scope=singleton) 71 | 72 | 73 | class MonitoringModule(Module): 74 | """监控模块""" 75 | 76 | def configure(self, binder): 77 | binder.bind(MonitoringService, to=EnhancedMonitoringServiceImpl, scope=singleton) 78 | 79 | 80 | # 所有模块的集合 - 按依赖顺序排列 81 | ALL_MODULES = [ 82 | ConfigModule, # 配置服务 - 基础服务 83 | EventModule, # 事件处理 84 | ExchangeModule, # 交易所管理 85 | SymbolModule, # 符号转换和缓存服务 86 | DataModule, # 数据聚合 87 | MonitoringModule # 监控服务 - 依赖其他服务 88 | ] -------------------------------------------------------------------------------- /core/di/scopes.py: -------------------------------------------------------------------------------- 1 | """ 2 | 依赖注入作用域 3 | 4 | 定义服务的生命周期作用域 5 | """ 6 | 7 | from enum import Enum 8 | from typing import Dict, Any, Type, Optional 9 | import threading 10 | 11 | 12 | class ServiceScope(Enum): 13 | """服务作用域""" 14 | SINGLETON = "singleton" # 单例 15 | TRANSIENT = "transient" # 瞬态 16 | SCOPED = "scoped" # 作用域 17 | 18 | 19 | class ScopeManager: 20 | """作用域管理器""" 21 | 22 | def __init__(self): 23 | self.scopes: Dict[str, Dict[Type, Any]] = {} 24 | self.lock = threading.Lock() 25 | 26 | def get_instance(self, scope: ServiceScope, service_type: Type, factory: callable): 27 | """获取服务实例""" 28 | with self.lock: 29 | if scope == ServiceScope.SINGLETON: 30 | return self._get_singleton(service_type, factory) 31 | elif scope == ServiceScope.TRANSIENT: 32 | return factory() 33 | elif scope == ServiceScope.SCOPED: 34 | return self._get_scoped(service_type, factory) 35 | 36 | def _get_singleton(self, service_type: Type, factory: callable): 37 | """获取单例实例""" 38 | if service_type not in self.scopes.get("singleton", {}): 39 | if "singleton" not in self.scopes: 40 | self.scopes["singleton"] = {} 41 | self.scopes["singleton"][service_type] = factory() 42 | return self.scopes["singleton"][service_type] 43 | 44 | def _get_scoped(self, service_type: Type, factory: callable): 45 | """获取作用域实例""" 46 | # 实现作用域逻辑 47 | return factory() 48 | -------------------------------------------------------------------------------- /core/domain/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptocj520/grid/4b2ae95f2afcd2e5381e5ab2f2673eb60d51b9a0/core/domain/.DS_Store -------------------------------------------------------------------------------- /core/domain/entities/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/domain/models/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 领域模型 3 | 4 | 定义核心业务实体和数据结构 5 | """ 6 | 7 | from dataclasses import dataclass, field 8 | from typing import Dict, List, Optional, Any, Set 9 | from datetime import datetime 10 | from decimal import Decimal 11 | from enum import Enum 12 | 13 | 14 | class DataType(Enum): 15 | """支持的数据类型枚举""" 16 | TICKER = "ticker" 17 | ORDERBOOK = "orderbook" 18 | TRADES = "trades" 19 | USER_DATA = "user_data" 20 | 21 | @classmethod 22 | def get_all_types(cls) -> List[str]: 23 | """获取所有支持的数据类型""" 24 | return [dt.value for dt in cls] 25 | 26 | @classmethod 27 | def from_string(cls, value: str) -> 'DataType': 28 | """从字符串创建数据类型""" 29 | for dt in cls: 30 | if dt.value == value.lower(): 31 | return dt 32 | raise ValueError(f"不支持的数据类型: {value}") 33 | 34 | @classmethod 35 | def from_list(cls, values: List[str]) -> List['DataType']: 36 | """从字符串列表创建数据类型列表""" 37 | return [cls.from_string(v) for v in values] 38 | 39 | 40 | @dataclass 41 | class DataTypeConfig: 42 | """数据类型配置""" 43 | enabled_types: Set[DataType] = field(default_factory=set) 44 | disabled_types: Set[DataType] = field(default_factory=set) 45 | 46 | def __post_init__(self): 47 | """初始化后处理""" 48 | # 如果没有指定启用类型,默认启用ticker和orderbook 49 | if not self.enabled_types and not self.disabled_types: 50 | self.enabled_types = {DataType.TICKER, DataType.ORDERBOOK} 51 | 52 | def is_enabled(self, data_type: DataType) -> bool: 53 | """检查数据类型是否启用""" 54 | if self.disabled_types and data_type in self.disabled_types: 55 | return False 56 | if self.enabled_types: 57 | return data_type in self.enabled_types 58 | return True 59 | 60 | def get_enabled_types(self) -> List[DataType]: 61 | """获取启用的数据类型列表""" 62 | if self.enabled_types: 63 | return [dt for dt in self.enabled_types if dt not in self.disabled_types] 64 | else: 65 | # 如果没有明确启用的类型,返回所有类型除了禁用的 66 | return [dt for dt in DataType if dt not in self.disabled_types] 67 | 68 | def get_enabled_type_names(self) -> List[str]: 69 | """获取启用的数据类型名称列表""" 70 | return [dt.value for dt in self.get_enabled_types()] 71 | 72 | 73 | @dataclass 74 | class ExchangeDataTypeConfig: 75 | """交易所数据类型配置""" 76 | exchange_id: str 77 | data_types: DataTypeConfig = field(default_factory=DataTypeConfig) 78 | max_symbols_per_type: Dict[DataType, int] = field(default_factory=dict) 79 | priority_symbols: List[str] = field(default_factory=list) 80 | 81 | def get_max_symbols(self, data_type: DataType) -> Optional[int]: 82 | """获取指定数据类型的最大符号数""" 83 | return self.max_symbols_per_type.get(data_type) 84 | 85 | def set_max_symbols(self, data_type: DataType, max_symbols: int): 86 | """设置指定数据类型的最大符号数""" 87 | self.max_symbols_per_type[data_type] = max_symbols 88 | 89 | 90 | @dataclass 91 | class MonitoringDataTypeConfig: 92 | """监控数据类型配置""" 93 | global_enabled_types: Set[DataType] = field(default_factory=lambda: {DataType.TICKER, DataType.ORDERBOOK}) 94 | exchange_configs: Dict[str, ExchangeDataTypeConfig] = field(default_factory=dict) 95 | 96 | def get_exchange_config(self, exchange_id: str) -> Optional[ExchangeDataTypeConfig]: 97 | """获取交易所配置""" 98 | return self.exchange_configs.get(exchange_id) 99 | 100 | def set_exchange_config(self, exchange_id: str, config: ExchangeDataTypeConfig): 101 | """设置交易所配置""" 102 | self.exchange_configs[exchange_id] = config 103 | 104 | def get_enabled_types_for_exchange(self, exchange_id: str) -> List[DataType]: 105 | """获取指定交易所的启用数据类型""" 106 | exchange_config = self.get_exchange_config(exchange_id) 107 | if exchange_config: 108 | return exchange_config.data_types.get_enabled_types() 109 | else: 110 | # 如果没有交易所特定配置,使用全局配置 111 | return list(self.global_enabled_types) 112 | 113 | 114 | @dataclass 115 | class SubscriptionStatus: 116 | """订阅状态""" 117 | exchange_id: str 118 | symbol: str 119 | data_type: DataType 120 | status: str = "pending" # pending, active, error, cancelled 121 | error_message: Optional[str] = None 122 | last_update: datetime = field(default_factory=datetime.now) 123 | 124 | def is_active(self) -> bool: 125 | """检查订阅是否活跃""" 126 | return self.status == "active" 127 | 128 | def is_error(self) -> bool: 129 | """检查订阅是否有错误""" 130 | return self.status == "error" 131 | 132 | 133 | @dataclass 134 | class SubscriptionSummary: 135 | """订阅摘要""" 136 | total_subscriptions: int = 0 137 | active_subscriptions: int = 0 138 | error_subscriptions: int = 0 139 | pending_subscriptions: int = 0 140 | 141 | by_exchange: Dict[str, Dict[str, int]] = field(default_factory=dict) 142 | by_data_type: Dict[DataType, Dict[str, int]] = field(default_factory=dict) 143 | 144 | def update_from_status(self, status: SubscriptionStatus): 145 | """从订阅状态更新摘要""" 146 | self.total_subscriptions += 1 147 | 148 | if status.is_active(): 149 | self.active_subscriptions += 1 150 | elif status.is_error(): 151 | self.error_subscriptions += 1 152 | else: 153 | self.pending_subscriptions += 1 154 | 155 | # 更新按交易所统计 156 | if status.exchange_id not in self.by_exchange: 157 | self.by_exchange[status.exchange_id] = {"total": 0, "active": 0, "error": 0, "pending": 0} 158 | 159 | self.by_exchange[status.exchange_id]["total"] += 1 160 | if status.is_active(): 161 | self.by_exchange[status.exchange_id]["active"] += 1 162 | elif status.is_error(): 163 | self.by_exchange[status.exchange_id]["error"] += 1 164 | else: 165 | self.by_exchange[status.exchange_id]["pending"] += 1 166 | 167 | # 更新按数据类型统计 168 | if status.data_type not in self.by_data_type: 169 | self.by_data_type[status.data_type] = {"total": 0, "active": 0, "error": 0, "pending": 0} 170 | 171 | self.by_data_type[status.data_type]["total"] += 1 172 | if status.is_active(): 173 | self.by_data_type[status.data_type]["active"] += 1 174 | elif status.is_error(): 175 | self.by_data_type[status.data_type]["error"] += 1 176 | else: 177 | self.by_data_type[status.data_type]["pending"] += 1 178 | 179 | 180 | @dataclass 181 | class ExchangeData: 182 | """交易所数据""" 183 | exchange_id: str 184 | name: str 185 | base_url: str 186 | ws_url: str 187 | testnet: bool = True 188 | connected: bool = False 189 | last_update: datetime = None 190 | 191 | def __post_init__(self): 192 | if self.last_update is None: 193 | self.last_update = datetime.now() 194 | 195 | 196 | @dataclass 197 | class PriceData: 198 | """价格数据""" 199 | symbol: str 200 | exchange: str 201 | price: float 202 | volume: float 203 | timestamp: datetime 204 | last_update: datetime 205 | 206 | def __post_init__(self): 207 | if self.last_update is None: 208 | self.last_update = datetime.now() 209 | 210 | 211 | @dataclass 212 | class SpreadData: 213 | """价差数据""" 214 | symbol: str 215 | exchange1: str 216 | exchange2: str 217 | price1: float 218 | price2: float 219 | spread: float 220 | spread_pct: float 221 | volume1: float 222 | volume2: float 223 | timestamp: datetime 224 | 225 | def __post_init__(self): 226 | if self.timestamp is None: 227 | self.timestamp = datetime.now() 228 | 229 | 230 | @dataclass 231 | class SymbolInfo: 232 | """交易对信息""" 233 | symbol: str 234 | base_currency: str 235 | quote_currency: str 236 | contract_type: str 237 | price_precision: int 238 | quantity_precision: int 239 | min_quantity: Decimal 240 | max_quantity: Decimal 241 | min_price: Decimal 242 | max_price: Decimal 243 | active: bool = True 244 | 245 | 246 | @dataclass 247 | class MarketData: 248 | """市场数据""" 249 | symbol: str 250 | exchange: str 251 | ticker: Optional[Dict[str, Any]] = None 252 | orderbook: Optional[Dict[str, Any]] = None 253 | trades: Optional[List[Dict[str, Any]]] = None 254 | last_update: datetime = None 255 | 256 | def __post_init__(self): 257 | if self.last_update is None: 258 | self.last_update = datetime.now() 259 | 260 | 261 | @dataclass 262 | class ExchangeStatus: 263 | """交易所状态""" 264 | exchange_id: str 265 | connected: bool 266 | authenticated: bool 267 | websocket_connected: bool 268 | last_heartbeat: datetime 269 | message_count: int 270 | error_count: int 271 | uptime: float 272 | 273 | def __post_init__(self): 274 | if self.last_heartbeat is None: 275 | self.last_heartbeat = datetime.now() 276 | 277 | 278 | # 导出所有类 279 | __all__ = [ 280 | 'DataType', 281 | 'DataTypeConfig', 282 | 'ExchangeDataTypeConfig', 283 | 'MonitoringDataTypeConfig', 284 | 'SubscriptionStatus', 285 | 'SubscriptionSummary', 286 | 'ExchangeData', 287 | 'PriceData', 288 | 'SpreadData', 289 | 'SymbolInfo', 290 | 'MarketData', 291 | 'ExchangeStatus' 292 | ] 293 | -------------------------------------------------------------------------------- /core/domain/value_objects/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/infrastructure/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptocj520/grid/4b2ae95f2afcd2e5381e5ab2f2673eb60d51b9a0/core/infrastructure/.DS_Store -------------------------------------------------------------------------------- /core/infrastructure/cache/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/infrastructure/database/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/infrastructure/messaging/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/infrastructure/stats_config.py: -------------------------------------------------------------------------------- 1 | """ 2 | 统计信息配置读取器 3 | 根据交易所类型和币种数量动态调整统计信息打印频率 4 | """ 5 | 6 | import yaml 7 | import os 8 | from typing import Dict, Any, Optional 9 | from pathlib import Path 10 | 11 | 12 | class StatsConfigReader: 13 | """统计信息配置读取器""" 14 | 15 | def __init__(self, config_path: str = "config/logging.yaml"): 16 | """初始化配置读取器""" 17 | self.config_path = config_path 18 | self._config = None 19 | self._load_config() 20 | 21 | def _load_config(self) -> None: 22 | """加载配置文件""" 23 | try: 24 | config_file = Path(self.config_path) 25 | if config_file.exists(): 26 | with open(config_file, 'r', encoding='utf-8') as f: 27 | self._config = yaml.safe_load(f) 28 | else: 29 | self._config = {} 30 | except Exception as e: 31 | print(f"加载统计配置失败: {e}") 32 | self._config = {} 33 | 34 | def get_stats_frequency(self, exchange_id: str, symbol_count: Optional[int] = None) -> Dict[str, int]: 35 | """获取交易所的统计信息打印频率配置 36 | 37 | Args: 38 | exchange_id: 交易所ID (如: hyperliquid, backpack, edgex) 39 | symbol_count: 交易所支持的币种数量(可选,用于自适应配置) 40 | 41 | Returns: 42 | Dict[str, int]: 包含各种统计信息打印频率的字典 43 | """ 44 | if not self._config: 45 | return self._get_default_frequency() 46 | 47 | stats_config = self._config.get('exchange_statistics_frequency', {}) 48 | 49 | # 1. 优先使用交易所特定配置 50 | if exchange_id.lower() in stats_config: 51 | return stats_config[exchange_id.lower()] 52 | 53 | # 2. 如果提供了币种数量,使用自适应配置 54 | if symbol_count is not None: 55 | adaptive_config = self._get_adaptive_frequency(symbol_count, stats_config) 56 | if adaptive_config: 57 | return adaptive_config 58 | 59 | # 3. 使用默认配置 60 | return stats_config.get('default', self._get_default_frequency()) 61 | 62 | def _get_adaptive_frequency(self, symbol_count: int, stats_config: Dict[str, Any]) -> Optional[Dict[str, int]]: 63 | """根据币种数量获取自适应频率配置""" 64 | try: 65 | adaptive_rules = stats_config.get('adaptive_rules', {}) 66 | thresholds = adaptive_rules.get('thresholds', {}) 67 | default_freq = stats_config.get('default', self._get_default_frequency()) 68 | 69 | # 确定适用的阈值 70 | multiplier = 1.0 71 | for threshold_name, threshold_config in thresholds.items(): 72 | max_symbols = threshold_config.get('max_symbols', 0) 73 | if symbol_count >= max_symbols: 74 | multiplier = threshold_config.get('multiplier', 1.0) 75 | 76 | # 应用倍数 77 | if multiplier > 1.0: 78 | adapted_freq = {} 79 | for key, value in default_freq.items(): 80 | adapted_freq[key] = int(value * multiplier) 81 | return adapted_freq 82 | 83 | return None 84 | except Exception as e: 85 | print(f"自适应频率配置失败: {e}") 86 | return None 87 | 88 | def _get_default_frequency(self) -> Dict[str, int]: 89 | """获取默认统计信息打印频率""" 90 | return { 91 | 'message_stats_frequency': 100, 92 | 'callback_stats_frequency': 50, 93 | 'orderbook_stats_frequency': 50, 94 | 'global_callback_frequency': 50 95 | } 96 | 97 | def get_exchange_log_level(self, exchange_id: str) -> str: 98 | """获取交易所的日志级别""" 99 | if not self._config: 100 | return "INFO" 101 | 102 | loggers = self._config.get('loggers', {}) 103 | exchange_logger = loggers.get(exchange_id.lower(), {}) 104 | return exchange_logger.get('level', 'INFO') 105 | 106 | def should_reduce_logging(self, exchange_id: str) -> bool: 107 | """判断是否应该减少日志输出""" 108 | # 对于大型交易所,建议减少日志输出 109 | large_exchanges = ['hyperliquid', 'binance', 'okx', 'bybit'] 110 | return exchange_id.lower() in large_exchanges 111 | 112 | def get_stats_summary(self, exchange_id: str, symbol_count: Optional[int] = None) -> str: 113 | """获取统计配置摘要信息""" 114 | freq_config = self.get_stats_frequency(exchange_id, symbol_count) 115 | 116 | if symbol_count: 117 | return (f"📊 {exchange_id.upper()}统计配置 (支持{symbol_count}种币): " 118 | f"消息统计每{freq_config['message_stats_frequency']}条, " 119 | f"回调统计每{freq_config['callback_stats_frequency']}个, " 120 | f"订单簿统计每{freq_config['orderbook_stats_frequency']}个") 121 | else: 122 | return (f"📊 {exchange_id.upper()}统计配置: " 123 | f"消息统计每{freq_config['message_stats_frequency']}条, " 124 | f"回调统计每{freq_config['callback_stats_frequency']}个, " 125 | f"订单簿统计每{freq_config['orderbook_stats_frequency']}个") 126 | 127 | 128 | # 全局配置实例 129 | _stats_config = None 130 | 131 | def get_stats_config() -> StatsConfigReader: 132 | """获取全局统计配置实例""" 133 | global _stats_config 134 | if _stats_config is None: 135 | _stats_config = StatsConfigReader() 136 | return _stats_config 137 | 138 | 139 | def get_exchange_stats_frequency(exchange_id: str, symbol_count: Optional[int] = None) -> Dict[str, int]: 140 | """便捷函数:获取交易所统计频率配置""" 141 | return get_stats_config().get_stats_frequency(exchange_id, symbol_count) 142 | 143 | 144 | def get_exchange_stats_summary(exchange_id: str, symbol_count: Optional[int] = None) -> str: 145 | """便捷函数:获取交易所统计配置摘要""" 146 | return get_stats_config().get_stats_summary(exchange_id, symbol_count) -------------------------------------------------------------------------------- /core/logging/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | MESA交易系统 - 统一日志入口 (v3.0) 3 | 4 | 这是日志系统的统一入口,提供: 5 | - 简洁的API接口 6 | - 自动初始化 7 | - 完整的日志功能 8 | 9 | 推荐使用方式: 10 | from core.logging import get_logger, get_system_logger, get_trading_logger 11 | 12 | # 通用日志器 13 | logger = get_logger(__name__) 14 | logger.info("这是一条信息日志") 15 | 16 | # 系统日志器 17 | system_logger = get_system_logger("MyService") 18 | system_logger.startup("MyService", "1.0") 19 | 20 | # 交易日志器 21 | trading_logger = get_trading_logger() 22 | trading_logger.trade("买入", "BTC", 1.0) 23 | """ 24 | 25 | import os 26 | from typing import Dict, Any 27 | 28 | # 直接导入logger.py中的所有功能,重命名避免冲突 29 | from .logger import ( 30 | # 配置类 31 | LogConfig, 32 | 33 | # 核心日志器类 34 | BaseLogger, 35 | SystemLogger, 36 | TradingLogger, 37 | DataLogger, 38 | ErrorLogger, 39 | ExchangeLogger, 40 | PerformanceLogger, 41 | 42 | # 配置管理 43 | get_config, 44 | set_config, 45 | 46 | # 便捷函数(重命名避免冲突) 47 | get_logger as _get_logger, 48 | get_system_logger as _get_system_logger, 49 | get_trading_logger as _get_trading_logger, 50 | get_data_logger as _get_data_logger, 51 | get_error_logger as _get_error_logger, 52 | get_exchange_logger as _get_exchange_logger, 53 | get_performance_logger as _get_performance_logger, 54 | 55 | # 生命周期管理 56 | initialize_logging, 57 | shutdown_logging, 58 | 59 | # 健康状态 60 | get_health_status 61 | ) 62 | 63 | # 自动初始化标记 64 | _auto_initialized = False 65 | 66 | 67 | def _ensure_initialized(): 68 | """确保日志系统已初始化""" 69 | global _auto_initialized 70 | if not _auto_initialized: 71 | # 检查是否有配置文件 72 | config_path = "config/logging.yaml" 73 | if os.path.exists(config_path): 74 | # 使用默认配置(YAML配置暂不支持) 75 | initialize_logging() 76 | else: 77 | # 使用默认配置 78 | initialize_logging() 79 | _auto_initialized = True 80 | 81 | 82 | # 统一入口函数 - 自动初始化 83 | def get_logger(name: str) -> BaseLogger: 84 | """获取通用日志器(自动初始化)""" 85 | _ensure_initialized() 86 | return _get_logger(name) 87 | 88 | 89 | def get_system_logger(name: str = "system") -> SystemLogger: 90 | """获取系统日志器(自动初始化)""" 91 | _ensure_initialized() 92 | return _get_system_logger(name) 93 | 94 | 95 | def get_trading_logger() -> TradingLogger: 96 | """获取交易日志器(自动初始化)""" 97 | _ensure_initialized() 98 | return _get_trading_logger() 99 | 100 | 101 | def get_data_logger(name: str = "data") -> DataLogger: 102 | """获取数据日志器(自动初始化)""" 103 | _ensure_initialized() 104 | return _get_data_logger(name) 105 | 106 | 107 | def get_error_logger() -> ErrorLogger: 108 | """获取错误日志器(自动初始化)""" 109 | _ensure_initialized() 110 | return _get_error_logger() 111 | 112 | 113 | def get_exchange_logger(exchange_name: str) -> ExchangeLogger: 114 | """获取交易所日志器(自动初始化)""" 115 | _ensure_initialized() 116 | return _get_exchange_logger(exchange_name) 117 | 118 | 119 | def get_performance_logger() -> PerformanceLogger: 120 | """获取性能日志器(自动初始化)""" 121 | _ensure_initialized() 122 | return _get_performance_logger() 123 | 124 | 125 | # 向后兼容的别名 126 | initialize = initialize_logging 127 | shutdown = shutdown_logging 128 | 129 | 130 | # 导出所有核心功能 131 | __all__ = [ 132 | # 配置类 133 | 'LogConfig', 134 | 135 | # 核心日志器类 136 | 'BaseLogger', 137 | 'SystemLogger', 138 | 'TradingLogger', 139 | 'DataLogger', 140 | 'ErrorLogger', 141 | 'ExchangeLogger', 142 | 'PerformanceLogger', 143 | 144 | # 便捷函数(推荐使用) 145 | 'get_logger', 146 | 'get_system_logger', 147 | 'get_trading_logger', 148 | 'get_data_logger', 149 | 'get_error_logger', 150 | 'get_exchange_logger', 151 | 'get_performance_logger', 152 | 153 | # 生命周期管理 154 | 'initialize_logging', 155 | 'shutdown_logging', 156 | 157 | # 向后兼容别名 158 | 'initialize', 159 | 'shutdown', 160 | 161 | # 配置管理 162 | 'get_config', 163 | 'set_config', 164 | 165 | # 健康状态 166 | 'get_health_status' 167 | ] -------------------------------------------------------------------------------- /core/services/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptocj520/grid/4b2ae95f2afcd2e5381e5ab2f2673eb60d51b9a0/core/services/.DS_Store -------------------------------------------------------------------------------- /core/services/arbitrage/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 重构后的套利系统模块 3 | 4 | 基于分层架构设计的套利系统,包含精度管理、决策引擎、交易执行和协调器等核心组件。 5 | 6 | 模块结构: 7 | - initialization/: 初始化模块 8 | - precision_manager.py: 精度管理器 9 | - arbitrage_initializer.py: 套利系统初始化器 10 | - execution/: 执行模块 11 | - trade_execution_manager.py: 统一交易执行管理器 12 | - exchange_registry.py: 交易所注册器 13 | - decision/: 决策模块 14 | - arbitrage_decision_engine.py: 套利决策引擎 15 | - opportunity_processor.py: 机会处理器(与现有监视器模块集成) 16 | - coordinator/: 协调模块 17 | - arbitrage_coordinator.py: 套利协调器 18 | - risk_manager/: 风险管理模块 19 | - risk_manager.py: 风险管理器 20 | - risk_models.py: 风险管理数据模型 21 | - position_manager/: 持仓管理模块 22 | - position_manager.py: 持仓管理器 23 | - position_models.py: 持仓管理数据模型 24 | - shared/: 共享模块 25 | - models.py: 数据模型 26 | - precision_cache.py: 精度缓存 27 | - config.py: 配置管理 28 | """ 29 | 30 | # 核心组件导出 31 | from .initialization.precision_manager import PrecisionManager 32 | from .initialization.arbitrage_initializer import ArbitrageInitializer 33 | 34 | from .execution.trade_execution_manager import TradeExecutionManager 35 | from .execution.exchange_registry import ExchangeRegistry 36 | 37 | from .decision.arbitrage_decision_engine import ArbitrageDecisionEngine 38 | from .decision.opportunity_processor import OpportunityProcessor 39 | 40 | from .coordinator.arbitrage_coordinator import ArbitrageCoordinator 41 | 42 | from .risk_manager.risk_manager import RiskManager 43 | from .risk_manager.risk_models import ( 44 | RiskLevel, RiskAssessmentResult, RiskMetrics, RiskAlert, RiskLimit, RiskConfiguration 45 | ) 46 | 47 | from .position_manager.position_manager import PositionManager 48 | from .position_manager.position_models import ( 49 | PositionStatus, PositionType, PositionSummary, PositionMetrics, PositionEvent, PositionConfiguration 50 | ) 51 | 52 | # 共享模块导出 53 | from .shared.models import ( 54 | # 枚举类 55 | ArbitrageDirection, 56 | ArbitrageStatus, 57 | OrderType, 58 | ExecutionStrategy, 59 | 60 | # 数据模型 61 | PrecisionInfo, 62 | MarketSnapshot, 63 | TradePlan, 64 | OrderInfo, 65 | ExecutionResult, 66 | ArbitragePosition, 67 | RiskAssessment, 68 | ArbitrageOpportunity, 69 | 70 | # 工具函数 71 | adjust_precision, 72 | calculate_spread_percentage, 73 | determine_direction 74 | ) 75 | 76 | from .shared.precision_cache import PrecisionCache, PrecisionCacheManager 77 | 78 | from .shared.config import ( 79 | PrecisionConfig, 80 | DecisionConfig, 81 | ExecutionConfig, 82 | RiskConfig, 83 | MonitoringConfig, 84 | IntegrationConfig, 85 | ArbitrageSystemConfig, 86 | ArbitrageConfigManager 87 | ) 88 | 89 | # 便捷导出 90 | __all__ = [ 91 | # 核心组件 92 | 'PrecisionManager', 93 | 'ArbitrageInitializer', 94 | 'TradeExecutionManager', 95 | 'ExchangeRegistry', 96 | 'ArbitrageDecisionEngine', 97 | 'OpportunityProcessor', 98 | 'ArbitrageCoordinator', 99 | 100 | # 风险管理 101 | 'RiskManager', 102 | 'RiskLevel', 103 | 'RiskAssessmentResult', 104 | 'RiskMetrics', 105 | 'RiskAlert', 106 | 'RiskLimit', 107 | 'RiskConfiguration', 108 | 109 | # 持仓管理 110 | 'PositionManager', 111 | 'PositionStatus', 112 | 'PositionType', 113 | 'PositionSummary', 114 | 'PositionMetrics', 115 | 'PositionEvent', 116 | 'PositionConfiguration', 117 | 118 | # 枚举类 119 | 'ArbitrageDirection', 120 | 'ArbitrageStatus', 121 | 'OrderType', 122 | 'ExecutionStrategy', 123 | 124 | # 数据模型 125 | 'PrecisionInfo', 126 | 'MarketSnapshot', 127 | 'TradePlan', 128 | 'OrderInfo', 129 | 'ExecutionResult', 130 | 'ArbitragePosition', 131 | 'RiskAssessment', 132 | 'ArbitrageOpportunity', 133 | 134 | # 缓存管理 135 | 'PrecisionCache', 136 | 'PrecisionCacheManager', 137 | 138 | # 配置管理 139 | 'PrecisionConfig', 140 | 'DecisionConfig', 141 | 'ExecutionConfig', 142 | 'RiskConfig', 143 | 'MonitoringConfig', 144 | 'IntegrationConfig', 145 | 'ArbitrageSystemConfig', 146 | 'ArbitrageConfigManager', 147 | 148 | # 工具函数 149 | 'adjust_precision', 150 | 'calculate_spread_percentage', 151 | 'determine_direction' 152 | ] 153 | 154 | 155 | # 版本信息 156 | __version__ = '2.1.0' 157 | __author__ = 'Arbitrage System Team' 158 | __description__ = '重构后的套利系统模块 - 包含独立风险管理和持仓管理' 159 | 160 | 161 | # 快速使用示例 162 | def create_arbitrage_system(exchange_adapters, config_path=None): 163 | """ 164 | 创建套利系统的便捷函数 165 | 166 | Args: 167 | exchange_adapters: 交易所适配器字典 168 | config_path: 配置文件路径 169 | 170 | Returns: 171 | ArbitrageInitializer: 套利系统初始化器 172 | """ 173 | initializer = ArbitrageInitializer(exchange_adapters) 174 | return initializer 175 | 176 | 177 | # 使用说明 178 | __doc__ += """ 179 | 180 | 使用示例: 181 | 182 | 1. 基本使用: 183 | ```python 184 | from core.services.arbitrage import create_arbitrage_system 185 | 186 | # 创建套利系统 187 | arbitrage_system = create_arbitrage_system(exchange_adapters) 188 | 189 | # 初始化 190 | await arbitrage_system.initialize( 191 | config_path="config/arbitrage/default.yaml", 192 | overlapping_symbols=["BTC/USDT", "ETH/USDT"] 193 | ) 194 | 195 | # 启动 196 | await arbitrage_system.start() 197 | 198 | # 处理市场数据 199 | await arbitrage_system.handle_spread_analysis_result(spread_data) 200 | ``` 201 | 202 | 2. 高级使用: 203 | ```python 204 | from core.services.arbitrage import ( 205 | ArbitrageInitializer, 206 | ArbitrageCoordinator, 207 | OpportunityProcessor, 208 | RiskManager, 209 | PositionManager 210 | ) 211 | 212 | # 创建初始化器 213 | initializer = ArbitrageInitializer(exchange_adapters) 214 | 215 | # 注册回调 216 | initializer.register_integration_callback( 217 | 'market_data_callback', 218 | my_market_data_handler 219 | ) 220 | 221 | # 获取组件 222 | coordinator = initializer.get_arbitrage_coordinator() 223 | processor = initializer.get_opportunity_processor() 224 | 225 | # 独立使用风险管理器 226 | risk_manager = RiskManager() 227 | await risk_manager.start_monitoring() 228 | 229 | # 独立使用持仓管理器 230 | position_manager = PositionManager() 231 | await position_manager.start_monitoring() 232 | ``` 233 | 234 | 3. 与现有监视器模块集成: 235 | ```python 236 | # 在现有监视器模块中 237 | from core.services.arbitrage import ArbitrageInitializer 238 | 239 | # 创建套利系统 240 | arbitrage_system = ArbitrageInitializer(exchange_adapters) 241 | await arbitrage_system.initialize(overlapping_symbols=symbols) 242 | await arbitrage_system.start() 243 | 244 | # 在价差分析完成后 245 | await arbitrage_system.handle_spread_analysis_result(spread_analysis_result) 246 | 247 | # 在ticker更新时 248 | await arbitrage_system.handle_ticker_update(ticker_data) 249 | ``` 250 | 251 | 核心特性: 252 | - 🎯 精度管理:自动获取和缓存交易所精度信息 253 | - 🧠 智能决策:基于价差分析的套利决策引擎 254 | - ⚡ 统一执行:标准化的交易执行管理器 255 | - 🔄 无缝集成:与现有监视器模块完美集成 256 | - 📊 实时监控:完整的统计信息和性能监控 257 | - 🛡️ 风险控制:独立的风险管理器,多层风险评估和控制机制 258 | - 📈 持仓管理:专业的持仓管理器,完整的持仓生命周期管理 259 | - 🔧 配置管理:灵活的配置系统和热更新支持 260 | - 🚨 告警系统:智能风险告警和事件通知 261 | - 📋 事件追踪:完整的操作事件记录和分析 262 | 263 | 架构优势: 264 | - 模块化设计,易于维护和扩展 265 | - 依赖注入,降低耦合度 266 | - 异步处理,高性能执行 267 | - 错误处理,健壮性保证 268 | - 占位符设计,渐进式完善 269 | """ 270 | -------------------------------------------------------------------------------- /core/services/arbitrage/execution/exchange_registry.py: -------------------------------------------------------------------------------- 1 | """ 2 | 交易所注册器 3 | 4 | 负责管理交易所适配器的注册和访问 5 | """ 6 | 7 | from typing import Dict, List, Optional, Any 8 | from core.logging import get_logger 9 | from core.adapters.exchanges.interface import ExchangeInterface 10 | 11 | 12 | class ExchangeRegistry: 13 | """交易所注册器""" 14 | 15 | def __init__(self, exchange_adapters: Dict[str, ExchangeInterface] = None): 16 | """ 17 | 初始化交易所注册器 18 | 19 | Args: 20 | exchange_adapters: 初始交易所适配器字典 21 | """ 22 | self._adapters: Dict[str, ExchangeInterface] = exchange_adapters or {} 23 | self.logger = get_logger(__name__) 24 | 25 | def register_exchange(self, name: str, adapter: ExchangeInterface): 26 | """ 27 | 注册交易所适配器 28 | 29 | Args: 30 | name: 交易所名称 31 | adapter: 交易所适配器 32 | """ 33 | self._adapters[name] = adapter 34 | self.logger.info(f"注册交易所适配器: {name}") 35 | 36 | def unregister_exchange(self, name: str) -> bool: 37 | """ 38 | 注销交易所适配器 39 | 40 | Args: 41 | name: 交易所名称 42 | 43 | Returns: 44 | 是否成功注销 45 | """ 46 | if name in self._adapters: 47 | del self._adapters[name] 48 | self.logger.info(f"注销交易所适配器: {name}") 49 | return True 50 | return False 51 | 52 | def get_adapter(self, name: str) -> Optional[ExchangeInterface]: 53 | """ 54 | 获取交易所适配器 55 | 56 | Args: 57 | name: 交易所名称 58 | 59 | Returns: 60 | 交易所适配器,如果不存在则返回None 61 | """ 62 | return self._adapters.get(name) 63 | 64 | def get_all_exchanges(self) -> List[str]: 65 | """ 66 | 获取所有已注册的交易所名称 67 | 68 | Returns: 69 | 交易所名称列表 70 | """ 71 | return list(self._adapters.keys()) 72 | 73 | def get_all_adapters(self) -> Dict[str, ExchangeInterface]: 74 | """ 75 | 获取所有已注册的交易所适配器 76 | 77 | Returns: 78 | 交易所适配器字典 79 | """ 80 | return self._adapters.copy() 81 | 82 | def is_registered(self, name: str) -> bool: 83 | """ 84 | 检查交易所是否已注册 85 | 86 | Args: 87 | name: 交易所名称 88 | 89 | Returns: 90 | 是否已注册 91 | """ 92 | return name in self._adapters 93 | 94 | async def check_all_health(self) -> Dict[str, bool]: 95 | """ 96 | 检查所有交易所的健康状态 97 | 98 | Returns: 99 | 健康状态字典 100 | """ 101 | health_status = {} 102 | 103 | for name, adapter in self._adapters.items(): 104 | try: 105 | is_healthy = adapter.is_connected() 106 | if not is_healthy: 107 | # 尝试重新连接 108 | await adapter.connect() 109 | is_healthy = adapter.is_connected() 110 | 111 | health_status[name] = is_healthy 112 | 113 | except Exception as e: 114 | self.logger.error(f"检查交易所健康状态失败: {name} - {e}") 115 | health_status[name] = False 116 | 117 | return health_status 118 | 119 | def get_adapter_count(self) -> int: 120 | """ 121 | 获取已注册适配器数量 122 | 123 | Returns: 124 | 适配器数量 125 | """ 126 | return len(self._adapters) 127 | 128 | def clear_all(self): 129 | """清空所有适配器""" 130 | self._adapters.clear() 131 | self.logger.info("清空所有交易所适配器") 132 | 133 | # TODO: 高级功能占位符 134 | async def auto_discover_exchanges(self, config_path: str): 135 | """ 136 | 自动发现并注册交易所 137 | 138 | Args: 139 | config_path: 配置文件路径 140 | """ 141 | # TODO: 实现自动发现机制 142 | pass 143 | 144 | async def load_exchange_configs(self, config_data: Dict[str, Any]): 145 | """ 146 | 从配置加载交易所 147 | 148 | Args: 149 | config_data: 配置数据 150 | """ 151 | # TODO: 实现配置加载 152 | pass 153 | 154 | def get_exchange_capabilities(self, name: str) -> Dict[str, Any]: 155 | """ 156 | 获取交易所能力信息 157 | 158 | Args: 159 | name: 交易所名称 160 | 161 | Returns: 162 | 能力信息 163 | """ 164 | # TODO: 实现能力查询 165 | return {} 166 | 167 | async def test_exchange_connectivity(self, name: str) -> Dict[str, Any]: 168 | """ 169 | 测试交易所连通性 170 | 171 | Args: 172 | name: 交易所名称 173 | 174 | Returns: 175 | 连通性测试结果 176 | """ 177 | # TODO: 实现连通性测试 178 | return { 179 | 'status': 'not_implemented', 180 | 'exchange': name 181 | } -------------------------------------------------------------------------------- /core/services/arbitrage/initialization/arbitrage_initializer.py: -------------------------------------------------------------------------------- 1 | """ 2 | 套利系统初始化器 3 | 4 | 负责协调整个套利系统的启动和集成 5 | """ 6 | 7 | import asyncio 8 | from typing import Dict, List, Optional, Any, Callable 9 | from decimal import Decimal 10 | 11 | from core.logging import get_logger 12 | from core.adapters.exchanges.interface import ExchangeInterface 13 | from ..coordinator.arbitrage_coordinator import ArbitrageCoordinator 14 | from ..decision.opportunity_processor import OpportunityProcessor 15 | from ..shared.config import ArbitrageConfigManager, ArbitrageSystemConfig 16 | 17 | 18 | class ArbitrageInitializer: 19 | """套利系统初始化器""" 20 | 21 | def __init__(self, exchange_adapters: Dict[str, ExchangeInterface]): 22 | """ 23 | 初始化套利系统初始化器 24 | 25 | Args: 26 | exchange_adapters: 交易所适配器字典 27 | """ 28 | self.exchange_adapters = exchange_adapters 29 | self.logger = get_logger(__name__) 30 | 31 | # 核心组件 32 | self.config_manager = ArbitrageConfigManager() 33 | self.arbitrage_coordinator: Optional[ArbitrageCoordinator] = None 34 | self.opportunity_processor: Optional[OpportunityProcessor] = None 35 | 36 | # 系统状态 37 | self.initialized = False 38 | self.running = False 39 | 40 | # 集成接口 41 | self.integration_callbacks: Dict[str, Callable] = {} 42 | 43 | async def initialize(self, config_path: Optional[str] = None, 44 | overlapping_symbols: Optional[List[str]] = None) -> bool: 45 | """ 46 | 初始化套利系统 47 | 48 | Args: 49 | config_path: 配置文件路径 50 | overlapping_symbols: 重叠交易对列表 51 | 52 | Returns: 53 | 是否成功初始化 54 | """ 55 | try: 56 | self.logger.info("开始初始化套利系统...") 57 | 58 | # 1. 加载配置 59 | config = self.config_manager.load_config(config_path) 60 | 61 | if not config.enabled: 62 | self.logger.info("套利系统已禁用") 63 | return False 64 | 65 | # 2. 验证配置 66 | if not self.config_manager.validate_config(config): 67 | self.logger.error("配置验证失败") 68 | return False 69 | 70 | # 3. 初始化套利协调器 71 | self.arbitrage_coordinator = ArbitrageCoordinator( 72 | self.exchange_adapters, 73 | config.to_dict() 74 | ) 75 | 76 | # 4. 初始化精度管理和核心组件 77 | if overlapping_symbols: 78 | init_success = await self.arbitrage_coordinator.initialize(overlapping_symbols) 79 | if not init_success: 80 | self.logger.error("套利协调器初始化失败") 81 | return False 82 | 83 | # 5. 初始化机会处理器 84 | self.opportunity_processor = OpportunityProcessor(self.arbitrage_coordinator) 85 | 86 | # 6. 设置集成回调 87 | self._setup_integration_callbacks() 88 | 89 | self.initialized = True 90 | self.logger.info("套利系统初始化完成") 91 | return True 92 | 93 | except Exception as e: 94 | self.logger.error(f"初始化套利系统失败: {e}") 95 | return False 96 | 97 | async def start(self) -> bool: 98 | """ 99 | 启动套利系统 100 | 101 | Returns: 102 | 是否成功启动 103 | """ 104 | try: 105 | if not self.initialized: 106 | self.logger.error("系统未初始化") 107 | return False 108 | 109 | if self.running: 110 | self.logger.warning("系统已经在运行中") 111 | return True 112 | 113 | # 启动套利协调器 114 | await self.arbitrage_coordinator.start() 115 | 116 | self.running = True 117 | self.logger.info("套利系统已启动") 118 | return True 119 | 120 | except Exception as e: 121 | self.logger.error(f"启动套利系统失败: {e}") 122 | return False 123 | 124 | async def stop(self): 125 | """停止套利系统""" 126 | try: 127 | if not self.running: 128 | return 129 | 130 | self.running = False 131 | 132 | # 停止套利协调器 133 | if self.arbitrage_coordinator: 134 | await self.arbitrage_coordinator.stop() 135 | 136 | self.logger.info("套利系统已停止") 137 | 138 | except Exception as e: 139 | self.logger.error(f"停止套利系统失败: {e}") 140 | 141 | def _setup_integration_callbacks(self): 142 | """设置集成回调""" 143 | config = self.config_manager.get_config() 144 | 145 | # 设置市场数据回调 146 | if self.arbitrage_coordinator: 147 | self.arbitrage_coordinator.set_market_data_callback( 148 | self._on_market_data_processed 149 | ) 150 | 151 | self.arbitrage_coordinator.set_execution_callback( 152 | self._on_execution_completed 153 | ) 154 | 155 | async def _on_market_data_processed(self, market_data: Dict[str, Any], trade_plan: Optional[Any]): 156 | """市场数据处理回调""" 157 | if 'market_data_callback' in self.integration_callbacks: 158 | await self.integration_callbacks['market_data_callback'](market_data, trade_plan) 159 | 160 | async def _on_execution_completed(self, trade_plan: Any, result: Any): 161 | """执行完成回调""" 162 | if 'execution_callback' in self.integration_callbacks: 163 | await self.integration_callbacks['execution_callback'](trade_plan, result) 164 | 165 | def register_integration_callback(self, callback_type: str, callback: Callable): 166 | """ 167 | 注册集成回调 168 | 169 | Args: 170 | callback_type: 回调类型 171 | callback: 回调函数 172 | """ 173 | self.integration_callbacks[callback_type] = callback 174 | self.logger.info(f"注册集成回调: {callback_type}") 175 | 176 | def get_opportunity_processor(self) -> Optional[OpportunityProcessor]: 177 | """获取机会处理器""" 178 | return self.opportunity_processor 179 | 180 | def get_arbitrage_coordinator(self) -> Optional[ArbitrageCoordinator]: 181 | """获取套利协调器""" 182 | return self.arbitrage_coordinator 183 | 184 | def get_config(self) -> ArbitrageSystemConfig: 185 | """获取配置""" 186 | return self.config_manager.get_config() 187 | 188 | def get_stats(self) -> Dict[str, Any]: 189 | """获取统计信息""" 190 | stats = { 191 | 'initialized': self.initialized, 192 | 'running': self.running, 193 | 'exchange_count': len(self.exchange_adapters), 194 | 'integration_callbacks': len(self.integration_callbacks) 195 | } 196 | 197 | if self.arbitrage_coordinator: 198 | stats['arbitrage_stats'] = self.arbitrage_coordinator.get_stats() 199 | 200 | if self.opportunity_processor: 201 | stats['processor_stats'] = self.opportunity_processor.get_stats() 202 | 203 | return stats 204 | 205 | # 与现有监视器模块集成的便捷方法 206 | async def handle_spread_analysis_result(self, spread_data: Dict[str, Any]): 207 | """ 208 | 处理价差分析结果(便捷方法) 209 | 210 | Args: 211 | spread_data: 价差分析结果 212 | """ 213 | if self.opportunity_processor and self.running: 214 | await self.opportunity_processor.process_spread_analysis_result(spread_data) 215 | 216 | async def handle_ticker_update(self, ticker_data: Dict[str, Any]): 217 | """ 218 | 处理ticker更新(便捷方法) 219 | 220 | Args: 221 | ticker_data: ticker数据 222 | """ 223 | if self.opportunity_processor and self.running: 224 | await self.opportunity_processor.process_ticker_update(ticker_data) 225 | 226 | async def handle_price_monitor_data(self, price_data: Dict[str, Any]): 227 | """ 228 | 处理价格监控数据(便捷方法) 229 | 230 | Args: 231 | price_data: 价格监控数据 232 | """ 233 | if self.opportunity_processor and self.running: 234 | await self.opportunity_processor.process_price_monitor_data(price_data) 235 | 236 | async def handle_generic_market_data(self, data: Dict[str, Any], data_type: str = 'generic'): 237 | """ 238 | 处理通用市场数据(便捷方法) 239 | 240 | Args: 241 | data: 市场数据 242 | data_type: 数据类型 243 | """ 244 | if self.opportunity_processor and self.running: 245 | await self.opportunity_processor.process_generic_data(data, data_type) 246 | 247 | # TODO: 高级功能占位符 248 | async def reload_config(self, config_path: Optional[str] = None): 249 | """ 250 | 重新加载配置 251 | 252 | Args: 253 | config_path: 配置文件路径 254 | """ 255 | # TODO: 实现配置重载 256 | pass 257 | 258 | async def health_check(self) -> Dict[str, Any]: 259 | """ 260 | 健康检查 261 | 262 | Returns: 263 | 健康检查结果 264 | """ 265 | # TODO: 实现健康检查 266 | return { 267 | 'status': 'healthy', 268 | 'initialized': self.initialized, 269 | 'running': self.running 270 | } 271 | 272 | async def backup_state(self, backup_path: str): 273 | """ 274 | 备份系统状态 275 | 276 | Args: 277 | backup_path: 备份路径 278 | """ 279 | # TODO: 实现状态备份 280 | pass 281 | 282 | async def restore_state(self, backup_path: str): 283 | """ 284 | 恢复系统状态 285 | 286 | Args: 287 | backup_path: 备份路径 288 | """ 289 | # TODO: 实现状态恢复 290 | pass 291 | 292 | async def get_performance_metrics(self) -> Dict[str, Any]: 293 | """ 294 | 获取性能指标 295 | 296 | Returns: 297 | 性能指标 298 | """ 299 | # TODO: 实现性能指标收集 300 | return { 301 | 'status': 'not_implemented' 302 | } -------------------------------------------------------------------------------- /core/services/arbitrage/position_manager/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 持仓管理模块 3 | 4 | 独立的持仓管理功能,包含持仓创建、更新、关闭和监控等核心功能 5 | """ 6 | 7 | from .position_manager import PositionManager 8 | from .position_models import ( 9 | PositionStatus, 10 | PositionType, 11 | PositionSummary, 12 | PositionMetrics, 13 | PositionEvent, 14 | PositionConfiguration 15 | ) 16 | 17 | __all__ = [ 18 | 'PositionManager', 19 | 'PositionStatus', 20 | 'PositionType', 21 | 'PositionSummary', 22 | 'PositionMetrics', 23 | 'PositionEvent', 24 | 'PositionConfiguration' 25 | ] -------------------------------------------------------------------------------- /core/services/arbitrage/risk_manager/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 风险管理模块 3 | 4 | 独立的风险管理功能,包含风险评估、风险监控、风险控制等核心功能 5 | """ 6 | 7 | from .risk_manager import RiskManager 8 | from .risk_models import ( 9 | RiskLevel, 10 | RiskAssessmentResult, 11 | RiskMetrics, 12 | RiskAlert, 13 | RiskLimit, 14 | RiskEvent 15 | ) 16 | 17 | __all__ = [ 18 | 'RiskManager', 19 | 'RiskLevel', 20 | 'RiskAssessmentResult', 21 | 'RiskMetrics', 22 | 'RiskAlert', 23 | 'RiskLimit', 24 | 'RiskEvent' 25 | ] -------------------------------------------------------------------------------- /core/services/arbitrage/risk_manager/risk_models.py: -------------------------------------------------------------------------------- 1 | """ 2 | 风险管理相关数据模型 3 | 4 | 定义风险评估、风险监控、风险控制等功能的数据结构 5 | """ 6 | 7 | from dataclasses import dataclass, field 8 | from enum import Enum 9 | from datetime import datetime, timedelta 10 | from typing import Dict, List, Optional, Any 11 | from decimal import Decimal 12 | 13 | 14 | class RiskLevel(Enum): 15 | """风险等级""" 16 | LOW = "low" # 低风险 17 | MEDIUM = "medium" # 中风险 18 | HIGH = "high" # 高风险 19 | CRITICAL = "critical" # 临界风险 20 | EMERGENCY = "emergency" # 紧急风险 21 | 22 | 23 | class RiskType(Enum): 24 | """风险类型""" 25 | MARKET = "market" # 市场风险 26 | LIQUIDITY = "liquidity" # 流动性风险 27 | COUNTERPARTY = "counterparty" # 交易对手风险 28 | OPERATIONAL = "operational" # 操作风险 29 | TECHNICAL = "technical" # 技术风险 30 | REGULATORY = "regulatory" # 监管风险 31 | 32 | 33 | class RiskAlertType(Enum): 34 | """风险告警类型""" 35 | POSITION_LIMIT = "position_limit" # 持仓限制 36 | LOSS_LIMIT = "loss_limit" # 损失限制 37 | VOLUME_LIMIT = "volume_limit" # 成交量限制 38 | SPREAD_ANOMALY = "spread_anomaly" # 价差异常 39 | EXPOSURE_LIMIT = "exposure_limit" # 敞口限制 40 | EMERGENCY_STOP = "emergency_stop" # 紧急停止 41 | 42 | 43 | @dataclass 44 | class RiskLimit: 45 | """风险限制配置""" 46 | limit_type: str 47 | max_value: Decimal 48 | warning_threshold: Decimal # 警告阈值(通常为最大值的80%) 49 | current_value: Decimal = Decimal('0') 50 | 51 | @property 52 | def utilization_ratio(self) -> float: 53 | """使用率""" 54 | if self.max_value == 0: 55 | return 0.0 56 | return float(self.current_value / self.max_value) 57 | 58 | @property 59 | def is_warning(self) -> bool: 60 | """是否达到警告阈值""" 61 | return self.current_value >= self.warning_threshold 62 | 63 | @property 64 | def is_exceeded(self) -> bool: 65 | """是否超过限制""" 66 | return self.current_value >= self.max_value 67 | 68 | 69 | @dataclass 70 | class RiskMetrics: 71 | """风险指标""" 72 | symbol: str 73 | timestamp: datetime = field(default_factory=datetime.now) 74 | 75 | # 持仓风险 76 | position_count: int = 0 77 | total_exposure: Decimal = Decimal('0') 78 | max_single_position: Decimal = Decimal('0') 79 | 80 | # 盈亏风险 81 | unrealized_pnl: Decimal = Decimal('0') 82 | realized_pnl: Decimal = Decimal('0') 83 | daily_pnl: Decimal = Decimal('0') 84 | max_drawdown: Decimal = Decimal('0') 85 | 86 | # 成交量风险 87 | daily_volume: Decimal = Decimal('0') 88 | avg_volume: Decimal = Decimal('0') 89 | volume_ratio: float = 0.0 90 | 91 | # 价差风险 92 | current_spread: Decimal = Decimal('0') 93 | avg_spread: Decimal = Decimal('0') 94 | spread_volatility: float = 0.0 95 | 96 | # 时间风险 97 | max_holding_time: timedelta = timedelta(minutes=5) 98 | avg_holding_time: timedelta = timedelta(minutes=0) 99 | 100 | # 流动性风险 101 | bid_ask_spread: Decimal = Decimal('0') 102 | market_depth: Decimal = Decimal('0') 103 | 104 | def to_dict(self) -> Dict[str, Any]: 105 | """转换为字典格式""" 106 | return { 107 | 'symbol': self.symbol, 108 | 'timestamp': self.timestamp.isoformat(), 109 | 'position_count': self.position_count, 110 | 'total_exposure': float(self.total_exposure), 111 | 'max_single_position': float(self.max_single_position), 112 | 'unrealized_pnl': float(self.unrealized_pnl), 113 | 'realized_pnl': float(self.realized_pnl), 114 | 'daily_pnl': float(self.daily_pnl), 115 | 'max_drawdown': float(self.max_drawdown), 116 | 'daily_volume': float(self.daily_volume), 117 | 'avg_volume': float(self.avg_volume), 118 | 'volume_ratio': self.volume_ratio, 119 | 'current_spread': float(self.current_spread), 120 | 'avg_spread': float(self.avg_spread), 121 | 'spread_volatility': self.spread_volatility, 122 | 'max_holding_time': self.max_holding_time.total_seconds(), 123 | 'avg_holding_time': self.avg_holding_time.total_seconds(), 124 | 'bid_ask_spread': float(self.bid_ask_spread), 125 | 'market_depth': float(self.market_depth) 126 | } 127 | 128 | 129 | @dataclass 130 | class RiskAssessmentResult: 131 | """风险评估结果""" 132 | symbol: str 133 | assessment_time: datetime = field(default_factory=datetime.now) 134 | 135 | # 风险评分 136 | overall_risk_score: float = 0.0 # 总体风险评分 (0-1) 137 | risk_level: RiskLevel = RiskLevel.LOW # 风险等级 138 | 139 | # 分项风险评分 140 | market_risk_score: float = 0.0 # 市场风险 141 | liquidity_risk_score: float = 0.0 # 流动性风险 142 | operational_risk_score: float = 0.0 # 操作风险 143 | 144 | # 风险因子 145 | risk_factors: Dict[str, float] = field(default_factory=dict) 146 | 147 | # 风险警告 148 | warnings: List[str] = field(default_factory=list) 149 | 150 | # 建议 151 | recommendations: List[str] = field(default_factory=list) 152 | 153 | # 限制建议 154 | max_position_size: Decimal = Decimal('0') 155 | recommended_size: Decimal = Decimal('0') 156 | 157 | # 执行建议 158 | can_execute: bool = True 159 | should_reduce_position: bool = False 160 | should_close_all: bool = False 161 | 162 | @property 163 | def is_acceptable(self) -> bool: 164 | """风险是否可接受""" 165 | return self.overall_risk_score < 0.8 and self.risk_level != RiskLevel.CRITICAL 166 | 167 | 168 | @dataclass 169 | class RiskAlert: 170 | """风险告警""" 171 | alert_id: str 172 | alert_type: RiskAlertType 173 | risk_level: RiskLevel 174 | symbol: str 175 | message: str 176 | details: Dict[str, Any] = field(default_factory=dict) 177 | created_at: datetime = field(default_factory=datetime.now) 178 | acknowledged: bool = False 179 | resolved: bool = False 180 | 181 | def to_dict(self) -> Dict[str, Any]: 182 | """转换为字典格式""" 183 | return { 184 | 'alert_id': self.alert_id, 185 | 'alert_type': self.alert_type.value, 186 | 'risk_level': self.risk_level.value, 187 | 'symbol': self.symbol, 188 | 'message': self.message, 189 | 'details': self.details, 190 | 'created_at': self.created_at.isoformat(), 191 | 'acknowledged': self.acknowledged, 192 | 'resolved': self.resolved 193 | } 194 | 195 | 196 | @dataclass 197 | class RiskEvent: 198 | """风险事件""" 199 | event_id: str 200 | event_type: str 201 | symbol: str 202 | description: str 203 | risk_level: RiskLevel 204 | impact: str # 影响描述 205 | action_taken: str # 采取的行动 206 | created_at: datetime = field(default_factory=datetime.now) 207 | resolved_at: Optional[datetime] = None 208 | 209 | def to_dict(self) -> Dict[str, Any]: 210 | """转换为字典格式""" 211 | return { 212 | 'event_id': self.event_id, 213 | 'event_type': self.event_type, 214 | 'symbol': self.symbol, 215 | 'description': self.description, 216 | 'risk_level': self.risk_level.value, 217 | 'impact': self.impact, 218 | 'action_taken': self.action_taken, 219 | 'created_at': self.created_at.isoformat(), 220 | 'resolved_at': self.resolved_at.isoformat() if self.resolved_at else None 221 | } 222 | 223 | 224 | @dataclass 225 | class RiskConfiguration: 226 | """风险配置""" 227 | # 基础风险限制 228 | max_daily_loss: Decimal = Decimal('1000') # 最大日损失 229 | max_position_count: int = 5 # 最大持仓数量 230 | max_exposure_per_symbol: Decimal = Decimal('5000') # 每个符号的最大敞口 231 | max_total_exposure: Decimal = Decimal('20000') # 最大总敞口 232 | 233 | # 阈值设置 234 | stop_loss_threshold: Decimal = Decimal('-100') # 止损阈值 235 | take_profit_threshold: Decimal = Decimal('200') # 止盈阈值 236 | warning_threshold_ratio: float = 0.8 # 警告阈值比例 237 | 238 | # 价差风险 239 | max_spread_threshold: Decimal = Decimal('5.0') # 最大价差阈值 240 | min_spread_threshold: Decimal = Decimal('0.05') # 最小价差阈值 241 | spread_volatility_threshold: float = 0.3 # 价差波动率阈值 242 | 243 | # 流动性风险 244 | min_volume_threshold: Decimal = Decimal('1000') # 最小成交量阈值 245 | max_bid_ask_spread: Decimal = Decimal('0.01') # 最大买卖价差 246 | 247 | # 时间风险 248 | max_holding_time: timedelta = timedelta(minutes=30) # 最大持仓时间 249 | position_timeout: timedelta = timedelta(minutes=5) # 持仓超时时间 250 | 251 | # 检查间隔 252 | risk_check_interval: int = 10 # 风险检查间隔(秒) 253 | metrics_update_interval: int = 60 # 指标更新间隔(秒) 254 | 255 | def to_dict(self) -> Dict[str, Any]: 256 | """转换为字典格式""" 257 | return { 258 | 'max_daily_loss': float(self.max_daily_loss), 259 | 'max_position_count': self.max_position_count, 260 | 'max_exposure_per_symbol': float(self.max_exposure_per_symbol), 261 | 'max_total_exposure': float(self.max_total_exposure), 262 | 'stop_loss_threshold': float(self.stop_loss_threshold), 263 | 'take_profit_threshold': float(self.take_profit_threshold), 264 | 'warning_threshold_ratio': self.warning_threshold_ratio, 265 | 'max_spread_threshold': float(self.max_spread_threshold), 266 | 'min_spread_threshold': float(self.min_spread_threshold), 267 | 'spread_volatility_threshold': self.spread_volatility_threshold, 268 | 'min_volume_threshold': float(self.min_volume_threshold), 269 | 'max_bid_ask_spread': float(self.max_bid_ask_spread), 270 | 'max_holding_time': self.max_holding_time.total_seconds(), 271 | 'position_timeout': self.position_timeout.total_seconds(), 272 | 'risk_check_interval': self.risk_check_interval, 273 | 'metrics_update_interval': self.metrics_update_interval 274 | } -------------------------------------------------------------------------------- /core/services/arbitrage/shared/models.py: -------------------------------------------------------------------------------- 1 | """ 2 | 重构后的套利系统数据模型 3 | 4 | 定义精度信息、交易计划、执行结果等核心数据结构 5 | """ 6 | 7 | from dataclasses import dataclass, field 8 | from enum import Enum 9 | from datetime import datetime, timedelta 10 | from typing import Dict, List, Optional, Any 11 | from decimal import Decimal 12 | 13 | 14 | class ArbitrageDirection(Enum): 15 | """套利方向""" 16 | LONG_A_SHORT_B = "long_a_short_b" # A交易所买入,B交易所卖出 17 | LONG_B_SHORT_A = "long_b_short_a" # B交易所买入,A交易所卖出 18 | NEUTRAL = "neutral" # 无套利机会 19 | 20 | 21 | class ArbitrageStatus(Enum): 22 | """套利状态""" 23 | PENDING = "pending" # 待执行 24 | EXECUTING = "executing" # 执行中 25 | ACTIVE = "active" # 活跃中 26 | CLOSING = "closing" # 平仓中 27 | CLOSED = "closed" # 已平仓 28 | FAILED = "failed" # 执行失败 29 | CANCELLED = "cancelled" # 已取消 30 | 31 | 32 | class OrderType(Enum): 33 | """订单类型""" 34 | MARKET = "market" # 市价单 35 | LIMIT = "limit" # 限价单 36 | STOP = "stop" # 止损单 37 | 38 | 39 | class ExecutionStrategy(Enum): 40 | """执行策略""" 41 | IMMEDIATE = "immediate" # 立即执行 42 | TWAP = "twap" # 时间加权平均价格 43 | AGGRESSIVE = "aggressive" # 激进执行 44 | 45 | 46 | @dataclass 47 | class PrecisionInfo: 48 | """交易精度信息""" 49 | symbol: str 50 | exchange: str 51 | price_precision: int # 价格小数位数 52 | amount_precision: int # 数量小数位数 53 | min_order_size: Decimal # 最小订单数量 54 | max_order_size: Decimal # 最大订单数量 55 | tick_size: Decimal # 最小价格变动 56 | step_size: Decimal # 最小数量变动 57 | last_updated: datetime = field(default_factory=datetime.now) 58 | 59 | 60 | @dataclass 61 | class MarketSnapshot: 62 | """市场快照数据""" 63 | symbol: str 64 | timestamp: datetime 65 | exchanges_data: Dict[str, Any] # 每个交易所的数据 66 | spread_percentage: Decimal # 价差百分比 67 | direction: ArbitrageDirection # 套利方向 68 | best_bid: Decimal # 最佳买价 69 | best_ask: Decimal # 最佳卖价 70 | volume_info: Dict[str, Decimal] # 成交量信息 71 | 72 | 73 | @dataclass 74 | class TradePlan: 75 | """交易计划""" 76 | plan_id: str 77 | symbol: str 78 | direction: ArbitrageDirection 79 | 80 | # 交易参数 81 | long_exchange: str # 买入交易所 82 | short_exchange: str # 卖出交易所 83 | quantity: Decimal # 交易数量 84 | expected_profit: Decimal # 预期利润 85 | 86 | # 执行参数 87 | order_type: OrderType = OrderType.MARKET 88 | execution_strategy: ExecutionStrategy = ExecutionStrategy.IMMEDIATE 89 | 90 | # 风险控制 91 | max_slippage: Decimal = Decimal('0.01') # 最大滑点 92 | timeout: int = 30 # 超时时间(秒) 93 | 94 | # 时间信息 95 | created_at: datetime = field(default_factory=datetime.now) 96 | 97 | def to_dict(self) -> Dict[str, Any]: 98 | """转换为字典格式""" 99 | return { 100 | 'plan_id': self.plan_id, 101 | 'symbol': self.symbol, 102 | 'direction': self.direction.value, 103 | 'long_exchange': self.long_exchange, 104 | 'short_exchange': self.short_exchange, 105 | 'quantity': str(self.quantity), 106 | 'expected_profit': str(self.expected_profit), 107 | 'order_type': self.order_type.value, 108 | 'execution_strategy': self.execution_strategy.value, 109 | 'max_slippage': str(self.max_slippage), 110 | 'timeout': self.timeout, 111 | 'created_at': self.created_at.isoformat() 112 | } 113 | 114 | 115 | @dataclass 116 | class OrderInfo: 117 | """订单信息""" 118 | order_id: str 119 | exchange: str 120 | symbol: str 121 | side: str # 'buy' or 'sell' 122 | amount: Decimal 123 | price: Optional[Decimal] = None 124 | filled_amount: Decimal = Decimal('0') 125 | status: str = "pending" 126 | created_at: datetime = field(default_factory=datetime.now) 127 | updated_at: Optional[datetime] = None 128 | 129 | 130 | @dataclass 131 | class ExecutionResult: 132 | """执行结果""" 133 | plan_id: str 134 | success: bool 135 | long_order: Optional[OrderInfo] = None 136 | short_order: Optional[OrderInfo] = None 137 | actual_profit: Optional[Decimal] = None 138 | execution_time: Optional[float] = None # 执行耗时(秒) 139 | error_message: Optional[str] = None 140 | timestamp: datetime = field(default_factory=datetime.now) 141 | 142 | 143 | @dataclass 144 | class ArbitragePosition: 145 | """套利持仓""" 146 | position_id: str 147 | symbol: str 148 | direction: ArbitrageDirection 149 | status: ArbitrageStatus 150 | 151 | # 持仓信息 152 | long_exchange: str 153 | short_exchange: str 154 | quantity: Decimal 155 | entry_price_diff: Decimal # 入场价差 156 | current_price_diff: Optional[Decimal] = None # 当前价差 157 | 158 | # 订单信息 159 | long_order: Optional[OrderInfo] = None 160 | short_order: Optional[OrderInfo] = None 161 | 162 | # 盈亏信息 163 | unrealized_pnl: Decimal = Decimal('0') 164 | realized_pnl: Optional[Decimal] = None 165 | 166 | # 时间信息 167 | created_at: datetime = field(default_factory=datetime.now) 168 | updated_at: Optional[datetime] = None 169 | closed_at: Optional[datetime] = None 170 | 171 | 172 | @dataclass 173 | class RiskAssessment: 174 | """风险评估结果""" 175 | symbol: str 176 | risk_score: float # 风险得分 (0-1) 177 | max_position_size: Decimal # 最大持仓规模 178 | recommended_size: Decimal # 建议持仓规模 179 | warnings: List[str] = field(default_factory=list) 180 | risk_factors: Dict[str, float] = field(default_factory=dict) 181 | 182 | @property 183 | def is_acceptable(self) -> bool: 184 | """风险是否可接受""" 185 | return self.risk_score < 0.8 # 80%以下的风险可接受 186 | 187 | @property 188 | def can_execute(self) -> bool: 189 | """是否可以执行""" 190 | return self.risk_score < 0.9 and self.recommended_size > 0 191 | 192 | 193 | @dataclass 194 | class ArbitrageOpportunity: 195 | """套利机会""" 196 | opportunity_id: str 197 | symbol: str 198 | direction: ArbitrageDirection 199 | spread_percentage: Decimal 200 | expected_profit: Decimal 201 | confidence: float # 置信度 (0-1) 202 | urgency: float # 紧急程度 (0-1) 203 | market_snapshot: MarketSnapshot 204 | risk_assessment: RiskAssessment 205 | expires_at: datetime # 机会过期时间 206 | detected_at: datetime = field(default_factory=datetime.now) 207 | 208 | @property 209 | def is_expired(self) -> bool: 210 | """是否已过期""" 211 | return datetime.now() > self.expires_at 212 | 213 | @property 214 | def is_valid(self) -> bool: 215 | """是否有效""" 216 | return not self.is_expired and self.risk_assessment.can_execute 217 | 218 | 219 | # 工具函数 220 | def adjust_precision(value: Decimal, precision: int) -> Decimal: 221 | """调整数值精度""" 222 | if precision <= 0: 223 | return value.quantize(Decimal('1')) 224 | else: 225 | quantizer = Decimal('0.1') ** precision 226 | return value.quantize(quantizer) 227 | 228 | 229 | def calculate_spread_percentage(price_a: Decimal, price_b: Decimal) -> Decimal: 230 | """计算价差百分比""" 231 | if price_a == 0 or price_b == 0: 232 | return Decimal('0') 233 | 234 | avg_price = (price_a + price_b) / 2 235 | spread = abs(price_a - price_b) 236 | return (spread / avg_price) * 100 237 | 238 | 239 | def determine_direction(price_a: Decimal, price_b: Decimal) -> ArbitrageDirection: 240 | """确定套利方向""" 241 | if price_a > price_b: 242 | return ArbitrageDirection.LONG_B_SHORT_A # B交易所买入,A交易所卖出 243 | elif price_a < price_b: 244 | return ArbitrageDirection.LONG_A_SHORT_B # A交易所买入,B交易所卖出 245 | else: 246 | return ArbitrageDirection.NEUTRAL -------------------------------------------------------------------------------- /core/services/arbitrage/shared/precision_cache.py: -------------------------------------------------------------------------------- 1 | """ 2 | 精度缓存模块 3 | 4 | 负责存储和管理不同交易所的精度信息,提供快速查询接口 5 | """ 6 | 7 | import asyncio 8 | from datetime import datetime, timedelta 9 | from typing import Dict, Optional, List, Tuple 10 | from decimal import Decimal 11 | 12 | from core.logging import get_logger 13 | from .models import PrecisionInfo 14 | 15 | 16 | class PrecisionCache: 17 | """精度信息缓存""" 18 | 19 | def __init__(self, cache_ttl: int = 3600): 20 | """ 21 | 初始化精度缓存 22 | 23 | Args: 24 | cache_ttl: 缓存过期时间(秒),默认1小时 25 | """ 26 | self.cache_ttl = cache_ttl 27 | self._cache: Dict[str, PrecisionInfo] = {} 28 | self._lock = asyncio.Lock() 29 | self.logger = get_logger(__name__) 30 | 31 | def _get_cache_key(self, exchange: str, symbol: str) -> str: 32 | """生成缓存键""" 33 | return f"{exchange}:{symbol}" 34 | 35 | async def get(self, exchange: str, symbol: str) -> Optional[PrecisionInfo]: 36 | """ 37 | 获取精度信息 38 | 39 | Args: 40 | exchange: 交易所名称 41 | symbol: 交易对符号 42 | 43 | Returns: 44 | 精度信息,如果不存在或过期则返回None 45 | """ 46 | cache_key = self._get_cache_key(exchange, symbol) 47 | 48 | async with self._lock: 49 | precision_info = self._cache.get(cache_key) 50 | 51 | if precision_info is None: 52 | return None 53 | 54 | # 检查是否过期 55 | if self._is_expired(precision_info): 56 | del self._cache[cache_key] 57 | return None 58 | 59 | return precision_info 60 | 61 | async def set(self, exchange: str, symbol: str, precision_info: PrecisionInfo): 62 | """ 63 | 设置精度信息 64 | 65 | Args: 66 | exchange: 交易所名称 67 | symbol: 交易对符号 68 | precision_info: 精度信息 69 | """ 70 | cache_key = self._get_cache_key(exchange, symbol) 71 | 72 | async with self._lock: 73 | self._cache[cache_key] = precision_info 74 | 75 | self.logger.debug(f"缓存精度信息: {cache_key}") 76 | 77 | async def get_all_for_exchange(self, exchange: str) -> List[PrecisionInfo]: 78 | """ 79 | 获取指定交易所的所有精度信息 80 | 81 | Args: 82 | exchange: 交易所名称 83 | 84 | Returns: 85 | 精度信息列表 86 | """ 87 | result = [] 88 | 89 | async with self._lock: 90 | for key, precision_info in self._cache.items(): 91 | if key.startswith(f"{exchange}:") and not self._is_expired(precision_info): 92 | result.append(precision_info) 93 | 94 | return result 95 | 96 | async def get_all_for_symbol(self, symbol: str) -> List[PrecisionInfo]: 97 | """ 98 | 获取指定交易对的所有精度信息 99 | 100 | Args: 101 | symbol: 交易对符号 102 | 103 | Returns: 104 | 精度信息列表 105 | """ 106 | result = [] 107 | 108 | async with self._lock: 109 | for key, precision_info in self._cache.items(): 110 | if key.endswith(f":{symbol}") and not self._is_expired(precision_info): 111 | result.append(precision_info) 112 | 113 | return result 114 | 115 | async def remove(self, exchange: str, symbol: str) -> bool: 116 | """ 117 | 移除精度信息 118 | 119 | Args: 120 | exchange: 交易所名称 121 | symbol: 交易对符号 122 | 123 | Returns: 124 | 是否成功移除 125 | """ 126 | cache_key = self._get_cache_key(exchange, symbol) 127 | 128 | async with self._lock: 129 | if cache_key in self._cache: 130 | del self._cache[cache_key] 131 | return True 132 | return False 133 | 134 | async def clear(self): 135 | """清空缓存""" 136 | async with self._lock: 137 | self._cache.clear() 138 | 139 | self.logger.info("精度缓存已清空") 140 | 141 | async def clear_expired(self): 142 | """清理过期缓存""" 143 | expired_keys = [] 144 | 145 | async with self._lock: 146 | for key, precision_info in self._cache.items(): 147 | if self._is_expired(precision_info): 148 | expired_keys.append(key) 149 | 150 | for key in expired_keys: 151 | del self._cache[key] 152 | 153 | if expired_keys: 154 | self.logger.info(f"清理了 {len(expired_keys)} 个过期的精度缓存") 155 | 156 | def _is_expired(self, precision_info: PrecisionInfo) -> bool: 157 | """检查精度信息是否过期""" 158 | if self.cache_ttl <= 0: 159 | return False 160 | 161 | now = datetime.now() 162 | return (now - precision_info.last_updated).total_seconds() > self.cache_ttl 163 | 164 | async def get_cache_stats(self) -> Dict[str, int]: 165 | """ 166 | 获取缓存统计信息 167 | 168 | Returns: 169 | 缓存统计信息 170 | """ 171 | async with self._lock: 172 | total_count = len(self._cache) 173 | expired_count = sum(1 for info in self._cache.values() if self._is_expired(info)) 174 | valid_count = total_count - expired_count 175 | 176 | # 按交易所统计 177 | exchange_stats = {} 178 | for key in self._cache.keys(): 179 | exchange = key.split(':')[0] 180 | exchange_stats[exchange] = exchange_stats.get(exchange, 0) + 1 181 | 182 | return { 183 | 'total_count': total_count, 184 | 'valid_count': valid_count, 185 | 'expired_count': expired_count, 186 | 'exchange_stats': exchange_stats 187 | } 188 | 189 | async def exists(self, exchange: str, symbol: str) -> bool: 190 | """ 191 | 检查精度信息是否存在且有效 192 | 193 | Args: 194 | exchange: 交易所名称 195 | symbol: 交易对符号 196 | 197 | Returns: 198 | 是否存在有效的精度信息 199 | """ 200 | precision_info = await self.get(exchange, symbol) 201 | return precision_info is not None 202 | 203 | async def batch_get(self, requests: List[Tuple[str, str]]) -> Dict[str, Optional[PrecisionInfo]]: 204 | """ 205 | 批量获取精度信息 206 | 207 | Args: 208 | requests: 请求列表,每个元素为(exchange, symbol) 209 | 210 | Returns: 211 | 结果字典,key为"exchange:symbol",value为精度信息 212 | """ 213 | results = {} 214 | 215 | for exchange, symbol in requests: 216 | cache_key = self._get_cache_key(exchange, symbol) 217 | precision_info = await self.get(exchange, symbol) 218 | results[cache_key] = precision_info 219 | 220 | return results 221 | 222 | async def batch_set(self, precision_data: Dict[str, PrecisionInfo]): 223 | """ 224 | 批量设置精度信息 225 | 226 | Args: 227 | precision_data: 精度数据字典,key为"exchange:symbol" 228 | """ 229 | async with self._lock: 230 | for cache_key, precision_info in precision_data.items(): 231 | self._cache[cache_key] = precision_info 232 | 233 | self.logger.info(f"批量设置了 {len(precision_data)} 个精度信息") 234 | 235 | 236 | class PrecisionCacheManager: 237 | """精度缓存管理器""" 238 | 239 | def __init__(self, cache_ttl: int = 3600, cleanup_interval: int = 300): 240 | """ 241 | 初始化精度缓存管理器 242 | 243 | Args: 244 | cache_ttl: 缓存过期时间(秒) 245 | cleanup_interval: 清理间隔(秒) 246 | """ 247 | self.cache = PrecisionCache(cache_ttl) 248 | self.cleanup_interval = cleanup_interval 249 | self._cleanup_task: Optional[asyncio.Task] = None 250 | self.logger = get_logger(__name__) 251 | 252 | async def start(self): 253 | """启动缓存管理器""" 254 | if self._cleanup_task is None: 255 | self._cleanup_task = asyncio.create_task(self._cleanup_loop()) 256 | self.logger.info("精度缓存管理器已启动") 257 | 258 | async def stop(self): 259 | """停止缓存管理器""" 260 | if self._cleanup_task: 261 | self._cleanup_task.cancel() 262 | try: 263 | await self._cleanup_task 264 | except asyncio.CancelledError: 265 | pass 266 | self._cleanup_task = None 267 | self.logger.info("精度缓存管理器已停止") 268 | 269 | async def _cleanup_loop(self): 270 | """定期清理过期缓存""" 271 | while True: 272 | try: 273 | await asyncio.sleep(self.cleanup_interval) 274 | await self.cache.clear_expired() 275 | except asyncio.CancelledError: 276 | break 277 | except Exception as e: 278 | self.logger.error(f"清理过期缓存时出错: {e}") 279 | 280 | async def get_precision(self, exchange: str, symbol: str) -> Optional[PrecisionInfo]: 281 | """获取精度信息""" 282 | return await self.cache.get(exchange, symbol) 283 | 284 | async def set_precision(self, exchange: str, symbol: str, precision_info: PrecisionInfo): 285 | """设置精度信息""" 286 | await self.cache.set(exchange, symbol, precision_info) 287 | 288 | async def get_stats(self) -> Dict[str, int]: 289 | """获取缓存统计信息""" 290 | return await self.cache.get_cache_stats() -------------------------------------------------------------------------------- /core/services/events/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 事件模块 3 | 4 | 定义新架构中使用的事件基类和简化的事件处理机制 5 | """ 6 | 7 | from .event import Event, ComponentStoppedEvent, HealthCheckEvent 8 | from .event_handler import EventHandler, EventCallback 9 | 10 | __all__ = ['Event', 'ComponentStoppedEvent', 'HealthCheckEvent', 'EventHandler', 'EventCallback'] -------------------------------------------------------------------------------- /core/services/events/event.py: -------------------------------------------------------------------------------- 1 | """ 2 | 事件基类 3 | 4 | 定义新架构中使用的基础事件类型 5 | """ 6 | 7 | import uuid 8 | from datetime import datetime 9 | from typing import Any, Dict, Optional 10 | from dataclasses import dataclass, field 11 | from abc import ABC 12 | from decimal import Decimal 13 | 14 | 15 | @dataclass 16 | class Event(ABC): 17 | """ 18 | 事件基类 19 | 20 | 所有事件都继承此基类,包含基础的事件元数据。 21 | 事件是不可变的,一旦创建就不能修改。 22 | """ 23 | 24 | # 事件元数据 25 | event_id: str = field(default_factory=lambda: str(uuid.uuid4())) 26 | event_type: str = field(init=False) 27 | timestamp: datetime = field(default_factory=datetime.utcnow) 28 | correlation_id: Optional[str] = None 29 | 30 | # 事件来源信息 31 | source: Optional[str] = None 32 | source_id: Optional[str] = None 33 | 34 | # 事件优先级(1=最高,5=最低) 35 | priority: int = 3 36 | 37 | # 额外的事件数据 38 | metadata: Dict[str, Any] = field(default_factory=dict) 39 | 40 | def __post_init__(self): 41 | """设置事件类型为类名""" 42 | if not hasattr(self, 'event_type') or not self.event_type: 43 | self.event_type = self.__class__.__name__ 44 | 45 | def to_dict(self) -> Dict[str, Any]: 46 | """将事件转换为字典格式""" 47 | return { 48 | 'event_id': self.event_id, 49 | 'event_type': self.event_type, 50 | 'timestamp': self.timestamp.isoformat(), 51 | 'correlation_id': self.correlation_id, 52 | 'source': self.source, 53 | 'source_id': self.source_id, 54 | 'priority': self.priority, 55 | 'metadata': self.metadata, 56 | 'data': self._get_data() 57 | } 58 | 59 | def _get_data(self) -> Dict[str, Any]: 60 | """获取事件的业务数据,子类可以重写此方法""" 61 | # 排除基类字段,只返回业务数据 62 | base_fields = {'event_id', 'event_type', 'timestamp', 'correlation_id', 63 | 'source', 'source_id', 'priority', 'metadata'} 64 | 65 | data = {} 66 | for key, value in self.__dict__.items(): 67 | if key not in base_fields: 68 | # 处理特殊类型的序列化 69 | if isinstance(value, Decimal): 70 | data[key] = float(value) 71 | elif isinstance(value, datetime): 72 | data[key] = value.isoformat() 73 | else: 74 | data[key] = value 75 | 76 | return data 77 | 78 | 79 | @dataclass 80 | class ComponentStoppedEvent(Event): 81 | """ 82 | 组件停止事件 83 | 84 | 当系统组件停止时发出此事件 85 | """ 86 | 87 | component: str = field(default="unknown") 88 | 89 | def __post_init__(self): 90 | super().__post_init__() 91 | self.source = self.component 92 | 93 | 94 | @dataclass 95 | class HealthCheckEvent(Event): 96 | """ 97 | 健康检查事件 98 | 99 | 当系统组件进行健康检查时发出此事件 100 | """ 101 | 102 | component: str = field(default="unknown") 103 | check_name: str = field(default="health_check") 104 | status: str = field(default="unknown") 105 | details: Dict[str, Any] = field(default_factory=dict) 106 | 107 | def __post_init__(self): 108 | super().__post_init__() 109 | self.source = self.component -------------------------------------------------------------------------------- /core/services/events/event_handler.py: -------------------------------------------------------------------------------- 1 | """ 2 | 简化的事件处理器 3 | 4 | 提供统一的事件处理机制,替代复杂的事件总线系统 5 | """ 6 | 7 | import asyncio 8 | from typing import Dict, List, Callable, Optional, Any, Union 9 | from dataclasses import dataclass 10 | from datetime import datetime 11 | 12 | # 使用简化的统一日志入口 13 | from ...logging import get_system_logger 14 | 15 | from .event import Event 16 | 17 | 18 | # 事件回调类型定义 19 | EventCallback = Callable[[Union[Event, Dict[str, Any]]], None] 20 | AsyncEventCallback = Callable[[Union[Event, Dict[str, Any]]], Any] 21 | 22 | 23 | @dataclass 24 | class EventSubscription: 25 | """事件订阅记录""" 26 | event_type: str 27 | callback: Union[EventCallback, AsyncEventCallback] 28 | subscriber_id: str 29 | created_at: datetime 30 | 31 | 32 | class EventHandler: 33 | """ 34 | 简化的事件处理器 35 | 36 | 提供统一的事件发布和订阅机制,支持同步和异步回调 37 | """ 38 | 39 | def __init__(self, name: str = "EventHandler"): 40 | self.name = name 41 | self.logger = get_system_logger() 42 | 43 | # 事件订阅管理 44 | self._subscriptions: Dict[str, List[EventSubscription]] = {} 45 | self._subscriber_counters: Dict[str, int] = {} 46 | 47 | # 统计信息 48 | self._stats = { 49 | 'events_published': 0, 50 | 'events_processed': 0, 51 | 'errors': 0, 52 | 'subscribers': 0 53 | } 54 | 55 | # 异步任务管理 56 | self._background_tasks: List[asyncio.Task] = [] 57 | 58 | self.logger.info(f"事件处理器初始化完成: {name}") 59 | 60 | def subscribe(self, event_type: str, callback: Union[EventCallback, AsyncEventCallback], 61 | subscriber_id: Optional[str] = None) -> str: 62 | """ 63 | 订阅事件 64 | 65 | Args: 66 | event_type: 事件类型 67 | callback: 回调函数(支持同步和异步) 68 | subscriber_id: 订阅者ID(可选) 69 | 70 | Returns: 71 | 订阅ID 72 | """ 73 | # 生成订阅者ID 74 | if subscriber_id is None: 75 | counter = self._subscriber_counters.get(event_type, 0) + 1 76 | self._subscriber_counters[event_type] = counter 77 | subscriber_id = f"{event_type}_subscriber_{counter}" 78 | 79 | # 创建订阅记录 80 | subscription = EventSubscription( 81 | event_type=event_type, 82 | callback=callback, 83 | subscriber_id=subscriber_id, 84 | created_at=datetime.now() 85 | ) 86 | 87 | # 添加到订阅列表 88 | if event_type not in self._subscriptions: 89 | self._subscriptions[event_type] = [] 90 | 91 | self._subscriptions[event_type].append(subscription) 92 | self._stats['subscribers'] += 1 93 | 94 | self.logger.debug(f"新增订阅: {event_type} <- {subscriber_id}") 95 | return subscriber_id 96 | 97 | def unsubscribe(self, event_type: str, subscriber_id: str) -> bool: 98 | """ 99 | 取消订阅 100 | 101 | Args: 102 | event_type: 事件类型 103 | subscriber_id: 订阅者ID 104 | 105 | Returns: 106 | 是否成功取消 107 | """ 108 | if event_type not in self._subscriptions: 109 | return False 110 | 111 | # 查找并移除订阅 112 | subscriptions = self._subscriptions[event_type] 113 | for i, subscription in enumerate(subscriptions): 114 | if subscription.subscriber_id == subscriber_id: 115 | subscriptions.pop(i) 116 | self._stats['subscribers'] -= 1 117 | self.logger.debug(f"取消订阅: {event_type} <- {subscriber_id}") 118 | 119 | # 如果没有订阅者了,清理事件类型 120 | if not subscriptions: 121 | del self._subscriptions[event_type] 122 | 123 | return True 124 | 125 | return False 126 | 127 | async def publish(self, event: Union[Event, Dict[str, Any], str], data: Optional[Dict[str, Any]] = None) -> None: 128 | """ 129 | 发布事件 130 | 131 | Args: 132 | event: 事件对象、事件数据字典或事件类型字符串 133 | data: 事件数据(当event为字符串时使用) 134 | """ 135 | try: 136 | self._stats['events_published'] += 1 137 | 138 | # 处理不同的事件输入格式 139 | if isinstance(event, str): 140 | # 字符串事件类型 141 | event_type = event 142 | event_data = data or {} 143 | elif isinstance(event, dict): 144 | # 字典格式事件 145 | event_type = event.get('event_type', 'unknown') 146 | event_data = event 147 | elif isinstance(event, Event): 148 | # Event类实例 149 | event_type = event.event_type 150 | event_data = event.to_dict() 151 | else: 152 | self.logger.warning(f"不支持的事件类型: {type(event)}") 153 | return 154 | 155 | # 获取订阅者 156 | subscriptions = self._subscriptions.get(event_type, []) 157 | if not subscriptions: 158 | self.logger.debug(f"没有订阅者的事件: {event_type}") 159 | return 160 | 161 | # 并发处理所有订阅者 162 | tasks = [] 163 | for subscription in subscriptions: 164 | task = asyncio.create_task( 165 | self._safe_callback(subscription, event_data) 166 | ) 167 | tasks.append(task) 168 | 169 | # 等待所有回调完成 170 | if tasks: 171 | await asyncio.gather(*tasks, return_exceptions=True) 172 | 173 | self._stats['events_processed'] += 1 174 | self.logger.debug(f"事件发布完成: {event_type} -> {len(subscriptions)} 个订阅者") 175 | 176 | except Exception as e: 177 | self._stats['errors'] += 1 178 | self.logger.error(f"发布事件失败: {e}") 179 | 180 | async def _safe_callback(self, subscription: EventSubscription, event_data: Dict[str, Any]) -> None: 181 | """ 182 | 安全执行回调函数 183 | 184 | Args: 185 | subscription: 订阅记录 186 | event_data: 事件数据 187 | """ 188 | try: 189 | callback = subscription.callback 190 | 191 | # 检查是否为异步回调 192 | if asyncio.iscoroutinefunction(callback): 193 | await callback(event_data) 194 | else: 195 | # 同步回调 196 | callback(event_data) 197 | 198 | except Exception as e: 199 | self._stats['errors'] += 1 200 | self.logger.error( 201 | f"回调执行失败 [{subscription.subscriber_id}]: {e}" 202 | ) 203 | 204 | async def emit(self, event_type: str, data: Dict[str, Any]) -> None: 205 | """ 206 | 发出事件(兼容旧的接口) 207 | 208 | Args: 209 | event_type: 事件类型 210 | data: 事件数据 211 | """ 212 | await self.publish(event_type, data) 213 | 214 | def get_stats(self) -> Dict[str, Any]: 215 | """获取统计信息""" 216 | return { 217 | 'name': self.name, 218 | 'events_published': self._stats['events_published'], 219 | 'events_processed': self._stats['events_processed'], 220 | 'errors': self._stats['errors'], 221 | 'subscribers': self._stats['subscribers'], 222 | 'event_types': list(self._subscriptions.keys()), 223 | 'subscriptions_count': { 224 | event_type: len(subs) 225 | for event_type, subs in self._subscriptions.items() 226 | } 227 | } 228 | 229 | def get_subscriptions(self) -> Dict[str, List[str]]: 230 | """获取所有订阅信息""" 231 | return { 232 | event_type: [sub.subscriber_id for sub in subscriptions] 233 | for event_type, subscriptions in self._subscriptions.items() 234 | } 235 | 236 | async def cleanup(self) -> None: 237 | """清理资源""" 238 | # 取消所有后台任务 239 | for task in self._background_tasks: 240 | if not task.done(): 241 | task.cancel() 242 | 243 | # 等待任务完成 244 | if self._background_tasks: 245 | await asyncio.gather(*self._background_tasks, return_exceptions=True) 246 | 247 | # 清理订阅 248 | self._subscriptions.clear() 249 | self._subscriber_counters.clear() 250 | self._background_tasks.clear() 251 | 252 | self.logger.info(f"事件处理器清理完成: {self.name}") 253 | 254 | 255 | # 全局默认事件处理器 256 | default_event_handler = EventHandler("Default") 257 | 258 | 259 | def get_event_handler(name: str = "Default") -> EventHandler: 260 | """获取事件处理器实例""" 261 | if name == "Default": 262 | return default_event_handler 263 | else: 264 | return EventHandler(name) -------------------------------------------------------------------------------- /core/services/grid/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格交易系统模块 3 | 4 | 完整的网格交易系统实现,支持: 5 | - 做多网格(Long Grid) 6 | - 做空网格(Short Grid) 7 | - 等差网格间隔 8 | - 自动反向挂单 9 | - 批量成交处理 10 | - 实时终端监控 11 | 12 | 使用示例: 13 | from core.services.grid import GridCoordinator, GridConfig, GridType 14 | 15 | # 创建配置 16 | config = GridConfig( 17 | exchange="backpack", 18 | symbol="BTC_USDC_PERP", 19 | grid_type=GridType.LONG, 20 | lower_price=Decimal("80000"), 21 | upper_price=Decimal("100000"), 22 | grid_interval=Decimal("100"), 23 | order_amount=Decimal("0.025") 24 | ) 25 | 26 | # 创建协调器并启动 27 | coordinator = GridCoordinator(config, strategy, engine, tracker) 28 | await coordinator.start() 29 | """ 30 | 31 | # 数据模型 32 | from .models import ( 33 | GridConfig, 34 | GridType, 35 | GridDirection, 36 | GridState, 37 | GridLevel, 38 | GridStatus, 39 | GridOrder, 40 | GridOrderStatus, 41 | GridOrderSide, 42 | GridMetrics, 43 | GridStatistics 44 | ) 45 | 46 | # 接口 47 | from .interfaces import ( 48 | IGridStrategy, 49 | IGridEngine, 50 | IPositionTracker 51 | ) 52 | 53 | # 实现 54 | from .implementations import ( 55 | GridStrategyImpl, 56 | GridEngineImpl, 57 | PositionTrackerImpl 58 | ) 59 | 60 | # 协调器 61 | from .coordinator import GridCoordinator 62 | 63 | # 终端界面 64 | from .terminal_ui import GridTerminalUI 65 | 66 | __all__ = [ 67 | # 模型 68 | 'GridConfig', 69 | 'GridType', 70 | 'GridDirection', 71 | 'GridState', 72 | 'GridLevel', 73 | 'GridStatus', 74 | 'GridOrder', 75 | 'GridOrderStatus', 76 | 'GridOrderSide', 77 | 'GridMetrics', 78 | 'GridStatistics', 79 | 80 | # 接口 81 | 'IGridStrategy', 82 | 'IGridEngine', 83 | 'IPositionTracker', 84 | 85 | # 实现 86 | 'GridStrategyImpl', 87 | 'GridEngineImpl', 88 | 'PositionTrackerImpl', 89 | 90 | # 协调器 91 | 'GridCoordinator', 92 | 93 | # 终端界面 94 | 'GridTerminalUI', 95 | ] 96 | 97 | __version__ = '1.0.0' 98 | 99 | -------------------------------------------------------------------------------- /core/services/grid/coordinator/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格交易系统协调器 3 | 4 | 整合策略、执行引擎、持仓跟踪器,管理整个网格系统的运行 5 | """ 6 | 7 | from .grid_coordinator import GridCoordinator 8 | 9 | __all__ = ['GridCoordinator'] 10 | 11 | -------------------------------------------------------------------------------- /core/services/grid/implementations/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格交易系统实现层 3 | 4 | 包含各个接口的具体实现 5 | """ 6 | 7 | from .grid_strategy_impl import GridStrategyImpl 8 | from .grid_engine_impl import GridEngineImpl 9 | from .position_tracker_impl import PositionTrackerImpl 10 | 11 | __all__ = [ 12 | 'GridStrategyImpl', 13 | 'GridEngineImpl', 14 | 'PositionTrackerImpl', 15 | ] 16 | 17 | -------------------------------------------------------------------------------- /core/services/grid/implementations/grid_strategy_impl.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格策略实现 3 | 4 | 实现网格策略的核心逻辑: 5 | - 做多网格(Long Grid) 6 | - 做空网格(Short Grid) 7 | - 统一的反向挂单机制 8 | """ 9 | 10 | from typing import List, Tuple 11 | from decimal import Decimal 12 | from datetime import datetime 13 | 14 | from ....logging import get_logger 15 | from ..interfaces.grid_strategy import IGridStrategy 16 | from ..models import ( 17 | GridConfig, GridOrder, GridOrderSide, GridOrderStatus, 18 | GridType 19 | ) 20 | 21 | 22 | class GridStrategyImpl(IGridStrategy): 23 | """ 24 | 网格策略实现 25 | 26 | 核心原则: 27 | 1. 做多和做空网格本质相同,只是初始化方向不同 28 | 2. 任何订单成交后立即挂反向订单 29 | 3. 买单成交 → 向上移动一格挂卖单 30 | 4. 卖单成交 → 向下移动一格挂买单 31 | """ 32 | 33 | def __init__(self): 34 | self.logger = get_logger(__name__) 35 | self.config: GridConfig = None 36 | self.grid_prices: List[Decimal] = [] 37 | 38 | def initialize(self, config: GridConfig) -> List[GridOrder]: 39 | """ 40 | 初始化网格 - 一次性生成所有网格订单 41 | 42 | 做多网格:为每个网格价格挂买单(200个买单) 43 | 做空网格:为每个网格价格挂卖单(200个卖单) 44 | 45 | Args: 46 | config: 网格配置 47 | 48 | Returns: 49 | 所有网格的初始订单列表(200个订单) 50 | """ 51 | self.config = config 52 | self.grid_prices = self._calculate_grid_prices() 53 | 54 | # 🔥 价格移动网格:价格区间在运行时动态设置 55 | if config.is_follow_mode(): 56 | self.logger.info( 57 | f"初始化{config.grid_type.value}网格: " 58 | f"区间[动态跟随], " 59 | f"间隔{config.grid_interval}, {config.grid_count}个网格" 60 | ) 61 | else: 62 | self.logger.info( 63 | f"初始化{config.grid_type.value}网格: " 64 | f"区间[{config.lower_price}, {config.upper_price}], " 65 | f"间隔{config.grid_interval}, {config.grid_count}个网格" 66 | ) 67 | 68 | # 为所有网格创建初始订单 69 | all_orders = self._create_all_initial_orders() 70 | 71 | self.logger.info(f"生成{len(all_orders)}个初始订单,准备批量挂单") 72 | 73 | return all_orders 74 | 75 | def _calculate_grid_prices(self) -> List[Decimal]: 76 | """ 77 | 计算所有网格价格 78 | 79 | Returns: 80 | 价格列表(按网格ID排序) 81 | """ 82 | prices = [] 83 | for grid_id in range(1, self.config.grid_count + 1): 84 | price = self.config.get_grid_price(grid_id) 85 | prices.append(price) 86 | 87 | return prices 88 | 89 | def _create_all_initial_orders(self) -> List[GridOrder]: 90 | """ 91 | 创建所有网格的初始订单 92 | 93 | 做多网格:为每个网格价格创建买单 94 | 做空网格:为每个网格价格创建卖单 95 | 96 | Returns: 97 | 所有网格的初始订单列表 98 | """ 99 | all_orders = [] 100 | 101 | if self.config.grid_type in [GridType.LONG, GridType.MARTINGALE_LONG, GridType.FOLLOW_LONG]: 102 | # 做多网格:为每个网格挂买单(包括普通、马丁、价格移动) 103 | for grid_id in range(1, self.config.grid_count + 1): 104 | price = self.config.get_grid_price(grid_id) 105 | # 🔥 使用动态金额(普通/价格移动=固定,马丁=递增) 106 | amount = self.config.get_grid_order_amount(grid_id) 107 | 108 | order = GridOrder( 109 | order_id="", # 等待执行引擎填充 110 | grid_id=grid_id, 111 | side=GridOrderSide.BUY, 112 | price=price, 113 | amount=amount, # 动态金额 114 | status=GridOrderStatus.PENDING, 115 | created_at=datetime.now() 116 | ) 117 | all_orders.append(order) 118 | 119 | self.logger.info( 120 | f"做多网格:生成{len(all_orders)}个买单," 121 | f"价格范围 ${all_orders[0].price:,.2f} - ${all_orders[-1].price:,.2f}" 122 | ) 123 | 124 | else: # SHORT, MARTINGALE_SHORT, FOLLOW_SHORT 125 | # 做空网格:为每个网格挂卖单(包括普通、马丁、价格移动) 126 | for grid_id in range(1, self.config.grid_count + 1): 127 | price = self.config.get_grid_price(grid_id) 128 | # 🔥 使用动态金额(普通/价格移动=固定,马丁=递增) 129 | amount = self.config.get_grid_order_amount(grid_id) 130 | 131 | order = GridOrder( 132 | order_id="", # 等待执行引擎填充 133 | grid_id=grid_id, 134 | side=GridOrderSide.SELL, 135 | price=price, 136 | amount=amount, # 动态金额 137 | status=GridOrderStatus.PENDING, 138 | created_at=datetime.now() 139 | ) 140 | all_orders.append(order) 141 | 142 | self.logger.info( 143 | f"做空网格:生成{len(all_orders)}个卖单," 144 | f"价格范围 ${all_orders[0].price:,.2f} - ${all_orders[-1].price:,.2f}" 145 | ) 146 | 147 | return all_orders 148 | 149 | def calculate_reverse_order( 150 | self, 151 | filled_order: GridOrder, 152 | grid_interval: Decimal 153 | ) -> Tuple[GridOrderSide, Decimal, int]: 154 | """ 155 | 计算反向订单参数 156 | 157 | 核心逻辑: 158 | - 买单成交 → 向上移动一格挂卖单 159 | - 卖单成交 → 向下移动一格挂买单 160 | 161 | Args: 162 | filled_order: 已成交订单 163 | grid_interval: 网格间隔 164 | 165 | Returns: 166 | (订单方向, 价格, 网格ID) 167 | """ 168 | if filled_order.is_buy_order(): 169 | # 买单成交 → 挂卖单 170 | new_side = GridOrderSide.SELL 171 | new_price = filled_order.filled_price + grid_interval 172 | # 网格ID保持不变或向上移动(取决于具体实现) 173 | new_grid_id = filled_order.grid_id 174 | 175 | self.logger.debug( 176 | f"买单成交@{filled_order.filled_price}, " 177 | f"挂卖单@{new_price} (向上移动{grid_interval})" 178 | ) 179 | else: 180 | # 卖单成交 → 挂买单 181 | new_side = GridOrderSide.BUY 182 | new_price = filled_order.filled_price - grid_interval 183 | new_grid_id = filled_order.grid_id 184 | 185 | self.logger.debug( 186 | f"卖单成交@{filled_order.filled_price}, " 187 | f"挂买单@{new_price} (向下移动{grid_interval})" 188 | ) 189 | 190 | return (new_side, new_price, new_grid_id) 191 | 192 | def calculate_batch_reverse_orders( 193 | self, 194 | filled_orders: List[GridOrder], 195 | grid_interval: Decimal 196 | ) -> List[Tuple[GridOrderSide, Decimal, int, Decimal]]: 197 | """ 198 | 批量计算反向订单参数 199 | 200 | 用于处理多个订单同时成交的情况 201 | 202 | Args: 203 | filled_orders: 已成交订单列表 204 | grid_interval: 网格间隔 205 | 206 | Returns: 207 | [(订单方向, 价格, 网格ID, 数量), ...] 208 | """ 209 | reverse_orders = [] 210 | 211 | for order in filled_orders: 212 | side, price, grid_id = self.calculate_reverse_order(order, grid_interval) 213 | # 数量与成交订单保持一致 214 | amount = order.filled_amount or order.amount 215 | reverse_orders.append((side, price, grid_id, amount)) 216 | 217 | self.logger.info( 218 | f"批量成交: {len(filled_orders)}个订单, " 219 | f"准备挂{len(reverse_orders)}个反向订单" 220 | ) 221 | 222 | return reverse_orders 223 | 224 | def get_grid_prices(self) -> List[Decimal]: 225 | """获取所有网格价格""" 226 | return self.grid_prices.copy() 227 | 228 | def validate_price_range(self, current_price: Decimal) -> bool: 229 | """ 230 | 验证当前价格是否在网格区间内 231 | 232 | Args: 233 | current_price: 当前价格 234 | 235 | Returns: 236 | 是否在区间内 237 | """ 238 | in_range = self.config.is_price_in_range(current_price) 239 | 240 | if not in_range: 241 | self.logger.warning( 242 | f"价格{current_price}超出网格区间" 243 | f"[{self.config.lower_price}, {self.config.upper_price}]" 244 | ) 245 | 246 | return in_range 247 | 248 | def get_grid_id_by_price(self, price: Decimal) -> int: 249 | """ 250 | 根据价格获取网格ID 251 | 252 | Args: 253 | price: 价格 254 | 255 | Returns: 256 | 网格ID 257 | """ 258 | return self.config.get_grid_index_by_price(price) 259 | 260 | def __repr__(self) -> str: 261 | if self.config: 262 | return ( 263 | f"GridStrategy({self.config.grid_type.value}, " 264 | f"{self.config.grid_count} grids)" 265 | ) 266 | return "GridStrategy(not initialized)" 267 | 268 | -------------------------------------------------------------------------------- /core/services/grid/implementations/order_monitor.py: -------------------------------------------------------------------------------- 1 | """ 2 | 订单监控器 - REST API轮询方式 3 | 4 | 由于Backpack WebSocket不支持用户数据流订阅, 5 | 采用REST API轮询方式监控订单成交情况 6 | """ 7 | import asyncio 8 | from typing import Dict, Set, Callable, List, Optional 9 | from decimal import Decimal 10 | from datetime import datetime 11 | 12 | from ....logging import get_logger 13 | from ....adapters.exchanges import ExchangeInterface, OrderStatus 14 | from ..models import GridOrder, GridOrderStatus 15 | 16 | 17 | class OrderMonitor: 18 | """ 19 | 订单监控器 20 | 21 | 功能: 22 | 1. 定期轮询检查订单状态 23 | 2. 检测订单成交 24 | 3. 触发成交回调 25 | """ 26 | 27 | def __init__( 28 | self, 29 | exchange: ExchangeInterface, 30 | symbol: str, 31 | poll_interval: float = 2.0 # 默认2秒轮询一次 32 | ): 33 | """ 34 | 初始化订单监控器 35 | 36 | Args: 37 | exchange: 交易所适配器 38 | symbol: 交易对 39 | poll_interval: 轮询间隔(秒) 40 | """ 41 | self.logger = get_logger(__name__) 42 | self.exchange = exchange 43 | self.symbol = symbol 44 | self.poll_interval = poll_interval 45 | 46 | # 监控的订单 47 | self._monitored_orders: Dict[str, GridOrder] = {} # order_id -> GridOrder 48 | 49 | # 订单成交回调 50 | self._fill_callbacks: List[Callable] = [] 51 | 52 | # 运行状态 53 | self._running = False 54 | self._monitor_task: Optional[asyncio.Task] = None 55 | 56 | # 统计信息 57 | self._total_checks = 0 58 | self._total_fills = 0 59 | self._last_check_time: Optional[datetime] = None 60 | 61 | self.logger.info( 62 | f"订单监控器初始化: {symbol}, " 63 | f"轮询间隔={poll_interval}秒" 64 | ) 65 | 66 | def add_order(self, order: GridOrder): 67 | """ 68 | 添加订单到监控列表 69 | 70 | Args: 71 | order: 网格订单 72 | """ 73 | if not order.order_id or order.order_id == "pending": 74 | self.logger.warning(f"订单ID无效,跳过监控: {order.order_id}") 75 | return 76 | 77 | self._monitored_orders[order.order_id] = order 78 | self.logger.debug( 79 | f"添加订单监控: {order.order_id} " 80 | f"(Grid {order.grid_id}, {order.side.value} {order.amount}@{order.price})" 81 | ) 82 | 83 | def remove_order(self, order_id: str): 84 | """ 85 | 从监控列表移除订单 86 | 87 | Args: 88 | order_id: 订单ID 89 | """ 90 | if order_id in self._monitored_orders: 91 | del self._monitored_orders[order_id] 92 | self.logger.debug(f"移除订单监控: {order_id}") 93 | 94 | def add_fill_callback(self, callback: Callable): 95 | """ 96 | 添加订单成交回调 97 | 98 | Args: 99 | callback: 回调函数,接收 GridOrder 参数 100 | """ 101 | self._fill_callbacks.append(callback) 102 | self.logger.debug(f"添加成交回调: {callback}") 103 | 104 | async def start(self): 105 | """启动监控""" 106 | if self._running: 107 | self.logger.warning("订单监控器已在运行") 108 | return 109 | 110 | self._running = True 111 | self._monitor_task = asyncio.create_task(self._monitor_loop()) 112 | 113 | self.logger.info("✅ 订单监控器已启动") 114 | 115 | async def stop(self): 116 | """停止监控""" 117 | if not self._running: 118 | return 119 | 120 | self._running = False 121 | 122 | if self._monitor_task: 123 | self._monitor_task.cancel() 124 | try: 125 | await self._monitor_task 126 | except asyncio.CancelledError: 127 | pass 128 | 129 | self.logger.info("⏹️ 订单监控器已停止") 130 | 131 | async def _monitor_loop(self): 132 | """监控循环""" 133 | self.logger.info(f"订单监控循环启动,间隔={self.poll_interval}秒") 134 | 135 | while self._running: 136 | try: 137 | await self._check_orders() 138 | await asyncio.sleep(self.poll_interval) 139 | except asyncio.CancelledError: 140 | break 141 | except Exception as e: 142 | self.logger.error(f"监控循环异常: {e}") 143 | await asyncio.sleep(self.poll_interval) 144 | 145 | self.logger.info("订单监控循环已退出") 146 | 147 | async def _check_orders(self): 148 | """检查所有监控的订单""" 149 | if not self._monitored_orders: 150 | return 151 | 152 | self._total_checks += 1 153 | self._last_check_time = datetime.now() 154 | 155 | # 批量查询所有挂单 156 | try: 157 | open_orders = await self.exchange.get_open_orders(self.symbol) 158 | open_order_ids = {order.id for order in open_orders if order.id} 159 | 160 | # 检查哪些订单已成交(不在挂单列表中) 161 | filled_order_ids: Set[str] = set() 162 | 163 | for order_id, grid_order in list(self._monitored_orders.items()): 164 | # 如果订单不在挂单列表中,说明已成交或取消 165 | if order_id not in open_order_ids: 166 | filled_order_ids.add(order_id) 167 | 168 | # 处理已成交订单 169 | if filled_order_ids: 170 | await self._process_filled_orders(filled_order_ids) 171 | 172 | # 日志统计 173 | if self._total_checks % 30 == 0: # 每30次检查记录一次 174 | self.logger.debug( 175 | f"监控统计: " 176 | f"检查次数={self._total_checks}, " 177 | f"成交数={self._total_fills}, " 178 | f"当前监控={len(self._monitored_orders)}个订单" 179 | ) 180 | 181 | except Exception as e: 182 | self.logger.error(f"检查订单失败: {e}") 183 | 184 | async def _process_filled_orders(self, filled_order_ids: Set[str]): 185 | """ 186 | 处理已成交订单 187 | 188 | Args: 189 | filled_order_ids: 已成交的订单ID集合 190 | """ 191 | for order_id in filled_order_ids: 192 | if order_id not in self._monitored_orders: 193 | continue 194 | 195 | grid_order = self._monitored_orders[order_id] 196 | 197 | try: 198 | # 查询订单详情(获取实际成交价格和数量) 199 | exchange_order = await self.exchange.get_order(order_id, self.symbol) 200 | 201 | # 检查订单状态 202 | if exchange_order.status == OrderStatus.FILLED: 203 | # 获取成交信息 204 | filled_price = exchange_order.average or exchange_order.price or grid_order.price 205 | filled_amount = exchange_order.filled or grid_order.amount 206 | 207 | # 标记订单已成交 208 | grid_order.mark_filled(filled_price, filled_amount) 209 | 210 | self.logger.info( 211 | f"✅ 订单成交: {grid_order.side.value} " 212 | f"{filled_amount}@{filled_price} " 213 | f"(Grid {grid_order.grid_id}, Order {order_id})" 214 | ) 215 | 216 | # 从监控列表移除 217 | del self._monitored_orders[order_id] 218 | 219 | # 更新统计 220 | self._total_fills += 1 221 | 222 | # 触发成交回调 223 | await self._trigger_fill_callbacks(grid_order) 224 | 225 | elif exchange_order.status == OrderStatus.CANCELED: 226 | # 订单被取消 227 | self.logger.warning( 228 | f"订单已取消: {order_id} " 229 | f"(Grid {grid_order.grid_id})" 230 | ) 231 | del self._monitored_orders[order_id] 232 | 233 | else: 234 | # 其他状态(部分成交等) 235 | self.logger.debug( 236 | f"订单状态={exchange_order.status.value}: {order_id}" 237 | ) 238 | 239 | except Exception as e: 240 | self.logger.error( 241 | f"处理成交订单失败 {order_id}: {e}" 242 | ) 243 | 244 | async def _trigger_fill_callbacks(self, filled_order: GridOrder): 245 | """ 246 | 触发成交回调 247 | 248 | Args: 249 | filled_order: 已成交订单 250 | """ 251 | for callback in self._fill_callbacks: 252 | try: 253 | if asyncio.iscoroutinefunction(callback): 254 | await callback(filled_order) 255 | else: 256 | callback(filled_order) 257 | except Exception as e: 258 | self.logger.error(f"成交回调执行失败: {e}") 259 | 260 | def get_statistics(self) -> Dict: 261 | """ 262 | 获取监控统计信息 263 | 264 | Returns: 265 | 统计字典 266 | """ 267 | return { 268 | "total_checks": self._total_checks, 269 | "total_fills": self._total_fills, 270 | "monitored_orders": len(self._monitored_orders), 271 | "last_check_time": self._last_check_time, 272 | "poll_interval": self.poll_interval, 273 | "is_running": self._running 274 | } 275 | 276 | def __repr__(self) -> str: 277 | return ( 278 | f"OrderMonitor(" 279 | f"symbol={self.symbol}, " 280 | f"monitored={len(self._monitored_orders)}, " 281 | f"checks={self._total_checks}, " 282 | f"fills={self._total_fills})" 283 | ) 284 | 285 | -------------------------------------------------------------------------------- /core/services/grid/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格交易系统接口定义 3 | 4 | 定义网格系统各个组件的抽象接口 5 | """ 6 | 7 | from .grid_strategy import IGridStrategy 8 | from .grid_engine import IGridEngine 9 | from .position_tracker import IPositionTracker 10 | 11 | __all__ = [ 12 | 'IGridStrategy', 13 | 'IGridEngine', 14 | 'IPositionTracker', 15 | ] 16 | 17 | -------------------------------------------------------------------------------- /core/services/grid/interfaces/grid_engine.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格执行引擎接口 3 | 4 | 定义网格交易执行引擎的抽象接口 5 | """ 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import List, Optional, Callable 9 | from decimal import Decimal 10 | 11 | from ..models import GridOrder, GridConfig 12 | 13 | 14 | class IGridEngine(ABC): 15 | """ 16 | 网格执行引擎接口 17 | 18 | 负责订单的执行和管理 19 | """ 20 | 21 | @abstractmethod 22 | async def initialize(self, config: GridConfig): 23 | """ 24 | 初始化执行引擎 25 | 26 | Args: 27 | config: 网格配置 28 | """ 29 | pass 30 | 31 | @abstractmethod 32 | async def place_order(self, order: GridOrder) -> GridOrder: 33 | """ 34 | 下单 35 | 36 | Args: 37 | order: 网格订单 38 | 39 | Returns: 40 | 更新后的订单(包含交易所订单ID) 41 | """ 42 | pass 43 | 44 | @abstractmethod 45 | async def place_batch_orders(self, orders: List[GridOrder]) -> List[GridOrder]: 46 | """ 47 | 批量下单 48 | 49 | Args: 50 | orders: 订单列表 51 | 52 | Returns: 53 | 更新后的订单列表 54 | """ 55 | pass 56 | 57 | @abstractmethod 58 | async def cancel_order(self, order_id: str) -> bool: 59 | """ 60 | 取消订单 61 | 62 | Args: 63 | order_id: 订单ID 64 | 65 | Returns: 66 | 是否成功 67 | """ 68 | pass 69 | 70 | @abstractmethod 71 | async def cancel_all_orders(self) -> int: 72 | """ 73 | 取消所有订单 74 | 75 | Returns: 76 | 取消的订单数量 77 | """ 78 | pass 79 | 80 | @abstractmethod 81 | async def get_order_status(self, order_id: str) -> Optional[GridOrder]: 82 | """ 83 | 查询订单状态 84 | 85 | Args: 86 | order_id: 订单ID 87 | 88 | Returns: 89 | 订单信息 90 | """ 91 | pass 92 | 93 | @abstractmethod 94 | async def get_current_price(self) -> Decimal: 95 | """ 96 | 获取当前市场价格 97 | 98 | Returns: 99 | 当前价格 100 | """ 101 | pass 102 | 103 | @abstractmethod 104 | def subscribe_order_updates(self, callback: Callable): 105 | """ 106 | 订阅订单更新 107 | 108 | Args: 109 | callback: 回调函数,接收订单更新 110 | """ 111 | pass 112 | 113 | @abstractmethod 114 | async def start(self): 115 | """启动执行引擎""" 116 | pass 117 | 118 | @abstractmethod 119 | async def stop(self): 120 | """停止执行引擎""" 121 | pass 122 | 123 | -------------------------------------------------------------------------------- /core/services/grid/interfaces/grid_strategy.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格策略接口 3 | 4 | 定义网格策略的抽象接口 5 | """ 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import List, Dict, Tuple 9 | from decimal import Decimal 10 | 11 | from ..models import GridConfig, GridOrder, GridOrderSide 12 | 13 | 14 | class IGridStrategy(ABC): 15 | """ 16 | 网格策略接口 17 | 18 | 定义网格策略的核心功能 19 | """ 20 | 21 | @abstractmethod 22 | def initialize(self, config: GridConfig) -> List[GridOrder]: 23 | """ 24 | 初始化网格 25 | 26 | Args: 27 | config: 网格配置 28 | 29 | Returns: 30 | 初始订单列表 31 | """ 32 | pass 33 | 34 | @abstractmethod 35 | def calculate_reverse_order( 36 | self, 37 | filled_order: GridOrder, 38 | grid_interval: Decimal 39 | ) -> Tuple[GridOrderSide, Decimal, int]: 40 | """ 41 | 计算反向订单参数 42 | 43 | Args: 44 | filled_order: 已成交订单 45 | grid_interval: 网格间隔 46 | 47 | Returns: 48 | (订单方向, 价格, 网格ID) 49 | """ 50 | pass 51 | 52 | @abstractmethod 53 | def get_grid_prices(self) -> List[Decimal]: 54 | """ 55 | 获取所有网格价格 56 | 57 | Returns: 58 | 价格列表 59 | """ 60 | pass 61 | 62 | @abstractmethod 63 | def validate_price_range(self, current_price: Decimal) -> bool: 64 | """ 65 | 验证当前价格是否在网格区间内 66 | 67 | Args: 68 | current_price: 当前价格 69 | 70 | Returns: 71 | 是否在区间内 72 | """ 73 | pass 74 | 75 | -------------------------------------------------------------------------------- /core/services/grid/interfaces/position_tracker.py: -------------------------------------------------------------------------------- 1 | """ 2 | 持仓跟踪器接口 3 | 4 | 定义持仓跟踪的抽象接口 5 | """ 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Dict, List 9 | from decimal import Decimal 10 | from datetime import datetime 11 | 12 | from ..models import GridOrder, GridStatistics, GridMetrics 13 | 14 | 15 | class IPositionTracker(ABC): 16 | """ 17 | 持仓跟踪器接口 18 | 19 | 跟踪网格系统的持仓和盈亏 20 | """ 21 | 22 | @abstractmethod 23 | def record_filled_order(self, order: GridOrder): 24 | """ 25 | 记录成交订单 26 | 27 | Args: 28 | order: 成交订单 29 | """ 30 | pass 31 | 32 | @abstractmethod 33 | def get_current_position(self) -> Decimal: 34 | """ 35 | 获取当前持仓 36 | 37 | Returns: 38 | 持仓数量(正数=多头,负数=空头) 39 | """ 40 | pass 41 | 42 | @abstractmethod 43 | def get_average_cost(self) -> Decimal: 44 | """ 45 | 获取平均持仓成本 46 | 47 | Returns: 48 | 平均成本 49 | """ 50 | pass 51 | 52 | @abstractmethod 53 | def calculate_unrealized_pnl(self, current_price: Decimal) -> Decimal: 54 | """ 55 | 计算未实现盈亏 56 | 57 | Args: 58 | current_price: 当前价格 59 | 60 | Returns: 61 | 未实现盈亏 62 | """ 63 | pass 64 | 65 | @abstractmethod 66 | def get_realized_pnl(self) -> Decimal: 67 | """ 68 | 获取已实现盈亏 69 | 70 | Returns: 71 | 已实现盈亏 72 | """ 73 | pass 74 | 75 | @abstractmethod 76 | def get_total_pnl(self, current_price: Decimal) -> Decimal: 77 | """ 78 | 获取总盈亏(已实现+未实现) 79 | 80 | Args: 81 | current_price: 当前价格 82 | 83 | Returns: 84 | 总盈亏 85 | """ 86 | pass 87 | 88 | @abstractmethod 89 | def get_statistics(self) -> GridStatistics: 90 | """ 91 | 获取统计数据 92 | 93 | Returns: 94 | 网格统计数据 95 | """ 96 | pass 97 | 98 | @abstractmethod 99 | def get_metrics(self) -> GridMetrics: 100 | """ 101 | 获取性能指标 102 | 103 | Returns: 104 | 网格性能指标 105 | """ 106 | pass 107 | 108 | @abstractmethod 109 | def get_trade_history(self, limit: int = 10) -> List[Dict]: 110 | """ 111 | 获取交易历史 112 | 113 | Args: 114 | limit: 返回记录数 115 | 116 | Returns: 117 | 交易记录列表 118 | """ 119 | pass 120 | 121 | @abstractmethod 122 | def reset(self): 123 | """重置跟踪器""" 124 | pass 125 | 126 | -------------------------------------------------------------------------------- /core/services/grid/models/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格交易系统数据模型 3 | 4 | 包含网格配置、网格状态、订单、持仓等核心数据结构 5 | """ 6 | 7 | from .grid_config import GridConfig, GridType, GridDirection 8 | from .grid_state import GridState, GridLevel, GridStatus 9 | from .grid_order import GridOrder, GridOrderStatus, GridOrderSide 10 | from .grid_metrics import GridMetrics, GridStatistics 11 | 12 | __all__ = [ 13 | 'GridConfig', 14 | 'GridType', 15 | 'GridDirection', 16 | 'GridState', 17 | 'GridLevel', 18 | 'GridStatus', 19 | 'GridOrder', 20 | 'GridOrderStatus', 21 | 'GridOrderSide', 22 | 'GridMetrics', 23 | 'GridStatistics', 24 | ] 25 | 26 | -------------------------------------------------------------------------------- /core/services/grid/models/grid_config.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格配置模型 3 | 4 | 定义网格交易系统的配置参数 5 | """ 6 | 7 | from dataclasses import dataclass, field 8 | from enum import Enum 9 | from typing import Optional 10 | from decimal import Decimal 11 | 12 | 13 | class GridType(Enum): 14 | """网格类型""" 15 | LONG = "long" # 做多网格(普通) 16 | SHORT = "short" # 做空网格(普通) 17 | MARTINGALE_LONG = "martingale_long" # 马丁做多网格 18 | MARTINGALE_SHORT = "martingale_short" # 马丁做空网格 19 | FOLLOW_LONG = "follow_long" # 价格移动做多网格 20 | FOLLOW_SHORT = "follow_short" # 价格移动做空网格 21 | 22 | 23 | class GridDirection(Enum): 24 | """网格方向(内部使用)""" 25 | UP = "up" # 向上(价格上涨方向) 26 | DOWN = "down" # 向下(价格下跌方向) 27 | 28 | 29 | @dataclass 30 | class GridConfig: 31 | """ 32 | 网格配置 33 | 34 | 所有参数由用户在配置文件中设置 35 | """ 36 | 37 | # 基础参数(必需参数) 38 | exchange: str # 交易所名称 (如 "backpack") 39 | symbol: str # 交易对符号 (如 "BTC_USDC_PERP") 40 | grid_type: GridType # 网格类型(做多/做空) 41 | grid_interval: Decimal # 网格间隔(等差) 42 | order_amount: Decimal # 每格订单数量(基础金额) 43 | 44 | # 价格区间参数(可选参数,价格移动网格时不需要) 45 | lower_price: Optional[Decimal] = None # 价格下限(价格移动网格时可选) 46 | upper_price: Optional[Decimal] = None # 价格上限(价格移动网格时可选) 47 | 48 | # 计算得出的参数 49 | grid_count: int = field(init=False) # 网格数量(自动计算或用户指定) 50 | 51 | # 可选参数 52 | max_position: Optional[Decimal] = None # 最大持仓限制 53 | enable_notifications: bool = True # 是否启用通知 54 | order_health_check_interval: int = 600 # 订单健康检查间隔(秒,默认10分钟) 55 | fee_rate: Decimal = Decimal('0.0001') # 手续费率(默认万分之1) 56 | 57 | # 马丁网格参数(可选) 58 | martingale_increment: Optional[Decimal] = None # 马丁网格递增金额(None表示不启用马丁模式) 59 | 60 | # 价格移动网格参数(可选) 61 | follow_grid_count: Optional[int] = None # 价格移动网格数量(用户指定) 62 | follow_timeout: int = 300 # 脱离超时时间(秒,默认5分钟) 63 | follow_distance: int = 1 # 脱离距离(网格数,默认1格) 64 | 65 | def __post_init__(self): 66 | """初始化后计算网格数量""" 67 | # 🔥 价格移动网格:使用用户指定的网格数量 68 | if self.is_follow_mode(): 69 | if self.follow_grid_count is None: 70 | raise ValueError("价格移动网格必须指定 follow_grid_count") 71 | self.grid_count = self.follow_grid_count 72 | # 价格区间将在运行时根据当前价格动态计算 73 | else: 74 | # 普通网格和马丁网格:根据价格区间计算网格数量 75 | if self.upper_price is None or self.lower_price is None: 76 | raise ValueError("普通网格和马丁网格必须指定 upper_price 和 lower_price") 77 | price_range = abs(self.upper_price - self.lower_price) 78 | self.grid_count = int(price_range / self.grid_interval) 79 | 80 | # 验证参数 81 | self._validate() 82 | 83 | def _validate(self): 84 | """验证配置参数""" 85 | # 价格移动网格的价格区间在运行时动态设置,跳过验证 86 | if self.is_follow_mode(): 87 | if self.follow_grid_count is None or self.follow_grid_count <= 0: 88 | raise ValueError("价格移动网格必须指定有效的 follow_grid_count") 89 | if self.grid_interval is None or self.grid_interval <= 0: 90 | raise ValueError("网格间隔必须大于0") 91 | return 92 | 93 | # 普通网格和马丁网格验证 94 | if self.lower_price >= self.upper_price: 95 | raise ValueError("下限价格必须小于上限价格") 96 | 97 | if self.grid_interval <= 0: 98 | raise ValueError("网格间隔必须大于0") 99 | 100 | if self.order_amount <= 0: 101 | raise ValueError("订单数量必须大于0") 102 | 103 | if self.grid_count <= 0: 104 | raise ValueError(f"网格数量必须大于0,当前计算结果: {self.grid_count}") 105 | 106 | def get_first_order_price(self) -> Decimal: 107 | """ 108 | 获取第一个订单的价格 109 | 110 | 做多网格:上限 - 1个网格间隔 111 | 做空网格:下限 + 1个网格间隔 112 | """ 113 | if self.grid_type == GridType.LONG: 114 | return self.upper_price - self.grid_interval 115 | else: # SHORT 116 | return self.lower_price + self.grid_interval 117 | 118 | def get_grid_price(self, grid_index: int) -> Decimal: 119 | """ 120 | 获取指定网格索引的价格 121 | 122 | Args: 123 | grid_index: 网格索引 (1-based) 124 | 125 | Returns: 126 | 该网格的价格 127 | """ 128 | if self.grid_type == GridType.LONG: 129 | # 做多网格:从上限开始递减 130 | return self.upper_price - (grid_index * self.grid_interval) 131 | else: # SHORT 132 | # 做空网格:从下限开始递增 133 | return self.lower_price + (grid_index * self.grid_interval) 134 | 135 | def get_grid_index_by_price(self, price: Decimal) -> int: 136 | """ 137 | 根据价格获取网格索引 138 | 139 | Args: 140 | price: 价格 141 | 142 | Returns: 143 | 网格索引 (1-based) 144 | """ 145 | if self.grid_type == GridType.LONG: 146 | # 做多网格 147 | index = int((self.upper_price - price) / self.grid_interval) 148 | else: # SHORT 149 | # 做空网格 150 | index = int((price - self.lower_price) / self.grid_interval) 151 | 152 | # 确保索引在有效范围内 153 | return max(0, min(index, self.grid_count)) 154 | 155 | def is_price_in_range(self, price: Decimal) -> bool: 156 | """检查价格是否在网格区间内""" 157 | return self.lower_price <= price <= self.upper_price 158 | 159 | def is_martingale_mode(self) -> bool: 160 | """ 161 | 判断是否为马丁网格模式 162 | 163 | Returns: 164 | True: 马丁网格模式 165 | False: 普通网格模式 166 | """ 167 | return ( 168 | self.grid_type in [GridType.MARTINGALE_LONG, GridType.MARTINGALE_SHORT] or 169 | self.martingale_increment is not None 170 | ) 171 | 172 | def is_follow_mode(self) -> bool: 173 | """ 174 | 判断是否为价格移动网格模式 175 | 176 | Returns: 177 | True: 价格移动网格模式 178 | False: 其他模式 179 | """ 180 | return self.grid_type in [GridType.FOLLOW_LONG, GridType.FOLLOW_SHORT] 181 | 182 | def update_price_range_for_follow_mode(self, current_price: Decimal): 183 | """ 184 | 为价格移动网格动态更新价格区间 185 | 186 | Args: 187 | current_price: 当前市场价格 188 | 189 | 逻辑: 190 | 做多网格:以当前价格为上限,向下计算下限 191 | 做空网格:以当前价格为下限,向上计算上限 192 | """ 193 | if not self.is_follow_mode(): 194 | return 195 | 196 | if self.grid_type == GridType.FOLLOW_LONG: 197 | # 做多网格:当前价格为上限 198 | self.upper_price = current_price 199 | self.lower_price = current_price - (self.grid_count * self.grid_interval) 200 | elif self.grid_type == GridType.FOLLOW_SHORT: 201 | # 做空网格:当前价格为下限 202 | self.lower_price = current_price 203 | self.upper_price = current_price + (self.grid_count * self.grid_interval) 204 | 205 | def check_price_escape(self, current_price: Decimal) -> tuple[bool, str]: 206 | """ 207 | 检查价格是否脱离网格范围 208 | 209 | Args: 210 | current_price: 当前市场价格 211 | 212 | Returns: 213 | (是否需要重置, 脱离方向) 214 | 215 | 逻辑: 216 | 做多网格:只在向上脱离时重置(盈利方向) 217 | 做空网格:只在向下脱离时重置(盈利方向) 218 | """ 219 | if not self.is_follow_mode(): 220 | return False, "" 221 | 222 | escape_threshold = self.grid_interval * self.follow_distance 223 | 224 | if self.grid_type == GridType.FOLLOW_LONG: 225 | # 做多网格:检查向上脱离(盈利方向) 226 | if current_price > self.upper_price + escape_threshold: 227 | return True, "up" 228 | # 向下脱离(亏损方向)不重置 229 | return False, "" 230 | 231 | elif self.grid_type == GridType.FOLLOW_SHORT: 232 | # 做空网格:检查向下脱离(盈利方向) 233 | if current_price < self.lower_price - escape_threshold: 234 | return True, "down" 235 | # 向上脱离(亏损方向)不重置 236 | return False, "" 237 | 238 | return False, "" 239 | 240 | def get_grid_order_amount(self, grid_index: int) -> Decimal: 241 | """ 242 | 获取指定网格的订单金额 243 | 244 | Args: 245 | grid_index: 网格索引 (1-based) 246 | 247 | Returns: 248 | 该网格的订单金额 249 | 250 | 逻辑: 251 | 普通网格:固定金额 = order_amount 252 | 马丁网格:递增金额 = order_amount + (grid_index - 1) * martingale_increment 253 | 价格移动网格:固定金额 = order_amount 254 | """ 255 | if not self.is_martingale_mode(): 256 | # 普通网格和价格移动网格:固定金额 257 | return self.order_amount 258 | 259 | # 马丁网格:递增金额 260 | return self.order_amount + (grid_index - 1) * self.martingale_increment 261 | 262 | def __repr__(self) -> str: 263 | mode = "Martingale" if self.is_martingale_mode() else "Normal" 264 | return ( 265 | f"GridConfig(exchange={self.exchange}, symbol={self.symbol}, " 266 | f"type={self.grid_type.value}, mode={mode}, " 267 | f"range=[{self.lower_price}, {self.upper_price}], " 268 | f"interval={self.grid_interval}, grids={self.grid_count})" 269 | ) 270 | 271 | -------------------------------------------------------------------------------- /core/services/grid/models/grid_metrics.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格指标模型 3 | 4 | 定义网格系统的性能指标和统计数据 5 | """ 6 | 7 | from dataclasses import dataclass, field 8 | from typing import List, Dict 9 | from decimal import Decimal 10 | from datetime import datetime, timedelta 11 | 12 | 13 | @dataclass 14 | class GridStatistics: 15 | """ 16 | 网格统计数据 17 | 18 | 用于终端界面显示 19 | """ 20 | 21 | # 基本信息 22 | grid_count: int # 总网格数 23 | grid_interval: Decimal # 网格间隔 24 | price_range: tuple # 价格区间 (lower, upper) 25 | 26 | # 当前状态 27 | current_price: Decimal # 当前价格 28 | current_grid_id: int # 当前网格位置 29 | current_position: Decimal # 当前持仓 30 | average_cost: Decimal # 平均成本 31 | 32 | # 订单统计 33 | pending_buy_orders: int # 挂单中的买单数 34 | pending_sell_orders: int # 挂单中的卖单数 35 | total_pending_orders: int # 总挂单数 36 | 37 | # 成交统计 38 | filled_buy_count: int # 买单成交次数 39 | filled_sell_count: int # 卖单成交次数 40 | completed_cycles: int # 完成循环次数 41 | 42 | # 盈亏统计 43 | realized_profit: Decimal # 已实现盈亏 44 | unrealized_profit: Decimal # 未实现盈亏 45 | total_profit: Decimal # 总盈亏 46 | total_fees: Decimal # 总手续费 47 | net_profit: Decimal # 净利润 48 | profit_rate: Decimal # 收益率 49 | 50 | # 网格利用率 51 | grid_utilization: float # 网格利用率(百分比) 52 | 53 | # 资金信息 54 | available_balance: Decimal # 可用资金 55 | frozen_balance: Decimal # 冻结资金 56 | total_balance: Decimal # 总资金 57 | capital_utilization: float # 资金利用率 58 | 59 | # 时间信息 60 | running_time: timedelta # 运行时长 61 | last_trade_time: datetime # 最后成交时间 62 | 63 | # 监控方式 64 | monitoring_mode: str = "WebSocket" # 监控方式:WebSocket 或 REST轮询 65 | 66 | def to_display_dict(self) -> Dict: 67 | """转换为显示字典""" 68 | return { 69 | 'grid_count': self.grid_count, 70 | 'grid_interval': float(self.grid_interval), 71 | 'price_range': { 72 | 'lower': float(self.price_range[0]), 73 | 'upper': float(self.price_range[1]) 74 | }, 75 | 'current_price': float(self.current_price), 76 | 'current_grid_id': self.current_grid_id, 77 | 'current_position': float(self.current_position), 78 | 'average_cost': float(self.average_cost), 79 | 'pending_orders': { 80 | 'buy': self.pending_buy_orders, 81 | 'sell': self.pending_sell_orders, 82 | 'total': self.total_pending_orders 83 | }, 84 | 'filled_orders': { 85 | 'buy': self.filled_buy_count, 86 | 'sell': self.filled_sell_count, 87 | 'cycles': self.completed_cycles 88 | }, 89 | 'profit': { 90 | 'realized': float(self.realized_profit), 91 | 'unrealized': float(self.unrealized_profit), 92 | 'total': float(self.total_profit), 93 | 'fees': float(self.total_fees), 94 | 'net': float(self.net_profit), 95 | 'rate': float(self.profit_rate) 96 | }, 97 | 'grid_utilization': self.grid_utilization, 98 | 'balance': { 99 | 'available': float(self.available_balance), 100 | 'frozen': float(self.frozen_balance), 101 | 'total': float(self.total_balance), 102 | 'utilization': self.capital_utilization 103 | }, 104 | 'time': { 105 | 'running_time': str(self.running_time), 106 | 'last_trade': self.last_trade_time.isoformat() 107 | } 108 | } 109 | 110 | 111 | @dataclass 112 | class GridMetrics: 113 | """ 114 | 网格性能指标 115 | 116 | 用于分析网格系统的运行效果 117 | """ 118 | 119 | # 收益指标 120 | total_profit: Decimal = Decimal('0') # 总利润 121 | profit_rate: Decimal = Decimal('0') # 收益率 122 | daily_profit: Decimal = Decimal('0') # 日均收益 123 | 124 | # 交易指标 125 | total_trades: int = 0 # 总交易次数 126 | win_trades: int = 0 # 盈利交易次数 127 | loss_trades: int = 0 # 亏损交易次数 128 | win_rate: float = 0.0 # 胜率 129 | 130 | # 效率指标 131 | avg_profit_per_trade: Decimal = Decimal('0') # 平均每笔收益 132 | avg_holding_time: timedelta = timedelta() # 平均持仓时间 133 | grid_efficiency: float = 0.0 # 网格效率 134 | 135 | # 风险指标 136 | max_drawdown: Decimal = Decimal('0') # 最大回撤 137 | max_position: Decimal = Decimal('0') # 最大持仓 138 | avg_position: Decimal = Decimal('0') # 平均持仓 139 | 140 | # 成本指标 141 | total_fees: Decimal = Decimal('0') # 总手续费 142 | fee_rate: Decimal = Decimal('0') # 手续费率 143 | 144 | # 时间指标 145 | running_days: int = 0 # 运行天数 146 | uptime_percentage: float = 100.0 # 运行时间百分比 147 | 148 | def calculate_metrics(self, 149 | trades: List, 150 | start_time: datetime, 151 | end_time: datetime, 152 | initial_balance: Decimal): 153 | """ 154 | 计算所有指标 155 | 156 | Args: 157 | trades: 交易记录列表 158 | start_time: 开始时间 159 | end_time: 结束时间 160 | initial_balance: 初始资金 161 | """ 162 | if not trades: 163 | return 164 | 165 | # 计算交易指标 166 | self.total_trades = len(trades) 167 | 168 | # 计算胜率 169 | for trade in trades: 170 | if trade.get('profit', 0) > 0: 171 | self.win_trades += 1 172 | elif trade.get('profit', 0) < 0: 173 | self.loss_trades += 1 174 | 175 | if self.total_trades > 0: 176 | self.win_rate = (self.win_trades / self.total_trades) * 100 177 | 178 | # 计算收益率 179 | if initial_balance > 0: 180 | self.profit_rate = (self.total_profit / initial_balance) * 100 181 | 182 | # 计算运行天数 183 | running_time = end_time - start_time 184 | self.running_days = running_time.days 185 | 186 | # 计算日均收益 187 | if self.running_days > 0: 188 | self.daily_profit = self.total_profit / Decimal(str(self.running_days)) 189 | 190 | def to_dict(self) -> Dict: 191 | """转换为字典""" 192 | return { 193 | 'profit': { 194 | 'total': float(self.total_profit), 195 | 'rate': float(self.profit_rate), 196 | 'daily': float(self.daily_profit) 197 | }, 198 | 'trades': { 199 | 'total': self.total_trades, 200 | 'win': self.win_trades, 201 | 'loss': self.loss_trades, 202 | 'win_rate': self.win_rate 203 | }, 204 | 'efficiency': { 205 | 'avg_profit_per_trade': float(self.avg_profit_per_trade), 206 | 'grid_efficiency': self.grid_efficiency 207 | }, 208 | 'risk': { 209 | 'max_drawdown': float(self.max_drawdown), 210 | 'max_position': float(self.max_position), 211 | 'avg_position': float(self.avg_position) 212 | }, 213 | 'cost': { 214 | 'total_fees': float(self.total_fees), 215 | 'fee_rate': float(self.fee_rate) 216 | }, 217 | 'time': { 218 | 'running_days': self.running_days, 219 | 'uptime_percentage': self.uptime_percentage 220 | } 221 | } 222 | 223 | -------------------------------------------------------------------------------- /core/services/grid/models/grid_order.py: -------------------------------------------------------------------------------- 1 | """ 2 | 网格订单模型 3 | 4 | 定义网格交易订单的数据结构 5 | """ 6 | 7 | from dataclasses import dataclass 8 | from enum import Enum 9 | from typing import Optional 10 | from decimal import Decimal 11 | from datetime import datetime 12 | 13 | 14 | class GridOrderSide(Enum): 15 | """订单方向""" 16 | BUY = "buy" # 买单 17 | SELL = "sell" # 卖单 18 | 19 | 20 | class GridOrderStatus(Enum): 21 | """订单状态""" 22 | PENDING = "pending" # 挂单中(等待成交) 23 | FILLED = "filled" # 已成交 24 | CANCELLED = "cancelled" # 已取消 25 | FAILED = "failed" # 失败 26 | 27 | 28 | @dataclass 29 | class GridOrder: 30 | """ 31 | 网格订单 32 | 33 | 代表网格系统中的一个限价订单 34 | """ 35 | 36 | # 订单标识 37 | order_id: str # 交易所订单ID 38 | grid_id: int # 所属网格层级 (1-based) 39 | 40 | # 订单参数 41 | side: GridOrderSide # 订单方向(买/卖) 42 | price: Decimal # 限价价格 43 | amount: Decimal # 订单数量 44 | 45 | # 订单状态 46 | status: GridOrderStatus # 订单状态 47 | 48 | # 时间信息 49 | created_at: datetime # 创建时间 50 | filled_at: Optional[datetime] = None # 成交时间 51 | 52 | # 成交信息 53 | filled_price: Optional[Decimal] = None # 实际成交价格 54 | filled_amount: Optional[Decimal] = None # 实际成交数量 55 | 56 | # 关联信息 57 | parent_order_id: Optional[str] = None # 父订单ID(如果是反向订单) 58 | reverse_order_id: Optional[str] = None # 反向订单ID(成交后创建的订单) 59 | 60 | # 额外数据 61 | exchange_data: dict = None # 交易所原始数据 62 | 63 | def __post_init__(self): 64 | """初始化后处理""" 65 | if self.exchange_data is None: 66 | self.exchange_data = {} 67 | 68 | def mark_filled(self, filled_price: Decimal, filled_amount: Decimal): 69 | """标记订单为已成交""" 70 | self.status = GridOrderStatus.FILLED 71 | self.filled_at = datetime.now() 72 | self.filled_price = filled_price 73 | self.filled_amount = filled_amount 74 | 75 | def mark_cancelled(self): 76 | """标记订单为已取消""" 77 | self.status = GridOrderStatus.CANCELLED 78 | 79 | def mark_failed(self): 80 | """标记订单为失败""" 81 | self.status = GridOrderStatus.FAILED 82 | 83 | def is_buy_order(self) -> bool: 84 | """是否为买单""" 85 | return self.side == GridOrderSide.BUY 86 | 87 | def is_sell_order(self) -> bool: 88 | """是否为卖单""" 89 | return self.side == GridOrderSide.SELL 90 | 91 | def is_filled(self) -> bool: 92 | """是否已成交""" 93 | return self.status == GridOrderStatus.FILLED 94 | 95 | def is_pending(self) -> bool: 96 | """是否挂单中""" 97 | return self.status == GridOrderStatus.PENDING 98 | 99 | def get_total_value(self) -> Decimal: 100 | """获取订单总价值""" 101 | return self.price * self.amount 102 | 103 | def get_profit_from_reverse(self, reverse_price: Decimal) -> Decimal: 104 | """ 105 | 计算与反向订单的利润 106 | 107 | Args: 108 | reverse_price: 反向订单的价格 109 | 110 | Returns: 111 | 利润金额(不含手续费) 112 | """ 113 | if self.is_buy_order(): 114 | # 买单:反向卖单价格更高才有利润 115 | return (reverse_price - self.price) * self.amount 116 | else: 117 | # 卖单:反向买单价格更低才有利润 118 | return (self.price - reverse_price) * self.amount 119 | 120 | def __repr__(self) -> str: 121 | return ( 122 | f"GridOrder(id={self.order_id}, grid={self.grid_id}, " 123 | f"{self.side.value} {self.amount}@{self.price}, status={self.status.value})" 124 | ) 125 | 126 | -------------------------------------------------------------------------------- /core/services/implementations/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/services/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | """新架构模块""" 2 | -------------------------------------------------------------------------------- /core/services/interfaces/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | 基础服务接口 3 | 4 | 定义所有服务的基础接口 5 | """ 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Dict, Any, Optional, List 9 | import asyncio 10 | 11 | 12 | class IService(ABC): 13 | """基础服务接口""" 14 | 15 | @abstractmethod 16 | async def initialize(self) -> bool: 17 | """初始化服务""" 18 | pass 19 | 20 | @abstractmethod 21 | async def shutdown(self) -> bool: 22 | """关闭服务""" 23 | pass 24 | 25 | @abstractmethod 26 | def get_health_status(self) -> Dict[str, Any]: 27 | """获取健康状态""" 28 | pass 29 | 30 | 31 | class IConfigurable(ABC): 32 | """可配置接口""" 33 | 34 | @abstractmethod 35 | def configure(self, config: Dict[str, Any]) -> bool: 36 | """配置服务""" 37 | pass 38 | 39 | 40 | class IMonitorable(ABC): 41 | """可监控接口""" 42 | 43 | @abstractmethod 44 | def get_metrics(self) -> Dict[str, Any]: 45 | """获取监控指标""" 46 | pass 47 | 48 | 49 | class BaseService(IService, IConfigurable, IMonitorable): 50 | """基础服务实现""" 51 | 52 | def __init__(self, name: str): 53 | self.name = name 54 | self.initialized = False 55 | self.config = {} 56 | self.metrics = {} 57 | 58 | async def initialize(self) -> bool: 59 | """初始化服务""" 60 | self.initialized = True 61 | return True 62 | 63 | async def shutdown(self) -> bool: 64 | """关闭服务""" 65 | self.initialized = False 66 | return True 67 | 68 | def get_health_status(self) -> Dict[str, Any]: 69 | """获取健康状态""" 70 | return { 71 | "service": self.name, 72 | "initialized": self.initialized, 73 | "status": "healthy" if self.initialized else "unhealthy" 74 | } 75 | 76 | def configure(self, config: Dict[str, Any]) -> bool: 77 | """配置服务""" 78 | self.config.update(config) 79 | return True 80 | 81 | def get_metrics(self) -> Dict[str, Any]: 82 | """获取监控指标""" 83 | return self.metrics 84 | -------------------------------------------------------------------------------- /core/services/interfaces/config_service.py: -------------------------------------------------------------------------------- 1 | """ 2 | 配置服务接口 3 | 4 | 定义配置管理功能的标准接口 5 | """ 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Dict, Any, Optional, List 9 | from dataclasses import dataclass 10 | 11 | 12 | @dataclass 13 | class ExchangeConfig: 14 | """交易所配置""" 15 | exchange_id: str 16 | name: str 17 | enabled: bool 18 | base_url: str 19 | ws_url: str 20 | testnet: bool 21 | api_key: Optional[str] = None 22 | api_secret: Optional[str] = None 23 | max_symbols: int = 50 24 | rate_limit: int = 1000 25 | timeout: int = 30 26 | 27 | 28 | @dataclass 29 | class SymbolConfig: 30 | """交易对配置""" 31 | symbol: str 32 | exchange_id: str 33 | enabled: bool 34 | priority: int = 1 35 | min_volume: float = 0.0 36 | max_spread: float = 0.05 37 | category: str = "crypto" 38 | 39 | 40 | @dataclass 41 | class SubscriptionConfig: 42 | """订阅配置""" 43 | exchange_id: str 44 | data_types: List[str] # ['ticker', 'orderbook', 'trades'] 45 | symbols: List[str] 46 | batch_size: int = 10 47 | retry_count: int = 3 48 | retry_delay: int = 5 49 | 50 | 51 | @dataclass 52 | class MonitoringConfiguration: 53 | """监控配置""" 54 | exchanges: Dict[str, ExchangeConfig] 55 | subscriptions: Dict[str, SubscriptionConfig] 56 | symbols: Dict[str, SymbolConfig] 57 | global_settings: Dict[str, Any] 58 | 59 | 60 | class IConfigurationService(ABC): 61 | """配置服务接口""" 62 | 63 | @abstractmethod 64 | async def initialize(self) -> bool: 65 | """初始化配置服务""" 66 | pass 67 | 68 | @abstractmethod 69 | async def load_config(self, config_path: str = None) -> MonitoringConfiguration: 70 | """加载配置""" 71 | pass 72 | 73 | @abstractmethod 74 | async def save_config(self, config: MonitoringConfiguration, config_path: str = None) -> bool: 75 | """保存配置""" 76 | pass 77 | 78 | @abstractmethod 79 | async def get_exchange_config(self, exchange_id: str) -> Optional[ExchangeConfig]: 80 | """获取交易所配置""" 81 | pass 82 | 83 | @abstractmethod 84 | async def get_subscription_config(self, exchange_id: str) -> Optional[SubscriptionConfig]: 85 | """获取订阅配置""" 86 | pass 87 | 88 | @abstractmethod 89 | async def get_symbol_config(self, symbol: str, exchange_id: str) -> Optional[SymbolConfig]: 90 | """获取交易对配置""" 91 | pass 92 | 93 | @abstractmethod 94 | async def get_enabled_exchanges(self) -> List[str]: 95 | """获取启用的交易所""" 96 | pass 97 | 98 | @abstractmethod 99 | async def get_symbols_for_exchange(self, exchange_id: str) -> List[str]: 100 | """获取交易所的交易对""" 101 | pass 102 | 103 | @abstractmethod 104 | async def update_exchange_config(self, exchange_id: str, config: ExchangeConfig) -> bool: 105 | """更新交易所配置""" 106 | pass 107 | 108 | @abstractmethod 109 | async def update_subscription_config(self, exchange_id: str, config: SubscriptionConfig) -> bool: 110 | """更新订阅配置""" 111 | pass 112 | 113 | @abstractmethod 114 | async def reload_config(self) -> bool: 115 | """重新加载配置""" 116 | pass 117 | 118 | @abstractmethod 119 | def get_config_snapshot(self) -> Dict[str, Any]: 120 | """获取配置快照""" 121 | pass -------------------------------------------------------------------------------- /core/services/interfaces/monitoring_service.py: -------------------------------------------------------------------------------- 1 | """ 2 | 监控服务接口 3 | 4 | 定义交易所数据监控、WebSocket连接管理、数据聚合等功能的标准接口 5 | """ 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Dict, List, Optional, Any, Callable 9 | from datetime import datetime 10 | from dataclasses import dataclass 11 | from enum import Enum 12 | 13 | from ...domain.models import ExchangeData, PriceData, SpreadData 14 | 15 | 16 | class SubscriptionStrategy(Enum): 17 | """订阅策略""" 18 | TICKER_ONLY = "ticker_only" # 只订阅ticker数据 19 | ORDERBOOK_ONLY = "orderbook_only" # 只订阅orderbook数据 20 | BOTH = "both" # 同时订阅ticker和orderbook 21 | CUSTOM = "custom" # 自定义订阅策略 22 | 23 | 24 | @dataclass 25 | class ExchangeSubscriptionConfig: 26 | """交易所订阅配置""" 27 | exchange_id: str 28 | strategy: SubscriptionStrategy = SubscriptionStrategy.TICKER_ONLY 29 | ticker_symbols: List[str] = None # ticker订阅的交易对 30 | orderbook_symbols: List[str] = None # orderbook订阅的交易对 31 | enabled: bool = True 32 | 33 | def __post_init__(self): 34 | if self.ticker_symbols is None: 35 | self.ticker_symbols = [] 36 | if self.orderbook_symbols is None: 37 | self.orderbook_symbols = [] 38 | 39 | 40 | @dataclass 41 | class MonitoringStats: 42 | """监控统计信息""" 43 | total_messages: int = 0 44 | exchange_messages: Dict[str, int] = None 45 | connected_exchanges: int = 0 46 | errors: int = 0 47 | uptime: float = 0.0 48 | 49 | def __post_init__(self): 50 | if self.exchange_messages is None: 51 | self.exchange_messages = {} 52 | 53 | 54 | @dataclass 55 | class MonitoringConfig: 56 | """监控配置 - 统一版本""" 57 | # WebSocket和Socket.IO配置 58 | socketio_port: int = 8765 59 | refresh_interval: float = 1.0 60 | max_symbols: int = 200 61 | 62 | # 订阅策略配置 63 | default_strategy: SubscriptionStrategy = SubscriptionStrategy.TICKER_ONLY 64 | exchange_configs: Dict[str, ExchangeSubscriptionConfig] = None 65 | 66 | # 交易所基础配置 67 | exchanges: Dict[str, Dict[str, Any]] = None 68 | 69 | # Web界面配置 70 | enable_web_interface: bool = True 71 | web_port: int = 8080 72 | 73 | # 指标收集配置 74 | enable_metrics: bool = True 75 | metrics_interval: int = 60 76 | 77 | # 告警配置 78 | enable_alerts: bool = True 79 | alert_channels: List[str] = None 80 | 81 | # 日志配置 82 | log_level: str = "INFO" 83 | log_file: Optional[str] = None 84 | 85 | def __post_init__(self): 86 | if self.exchanges is None: 87 | self.exchanges = { 88 | 'edgex': { 89 | 'name': 'EdgeX Exchange', 90 | 'enabled': True, 91 | 'base_url': 'https://pro.edgex.exchange', 92 | 'ws_url': 'wss://quote.edgex.exchange/api/v1/public/ws', 93 | 'testnet': True 94 | }, 95 | 'backpack': { 96 | 'name': 'Backpack Exchange', 97 | 'enabled': True, 98 | 'base_url': 'https://api.backpack.exchange', 99 | 'ws_url': 'wss://ws.backpack.exchange', 100 | 'testnet': True 101 | }, 102 | 'hyperliquid': { 103 | 'name': 'Hyperliquid', 104 | 'enabled': True, 105 | 'base_url': 'https://api.hyperliquid.xyz', 106 | 'ws_url': 'wss://api.hyperliquid.xyz/ws', 107 | 'testnet': False 108 | } 109 | } 110 | 111 | if self.exchange_configs is None: 112 | self.exchange_configs = {} 113 | 114 | if self.alert_channels is None: 115 | self.alert_channels = ["email", "webhook"] 116 | 117 | 118 | class MonitoringService(ABC): 119 | """监控服务接口""" 120 | 121 | @abstractmethod 122 | async def start(self) -> bool: 123 | """启动监控服务""" 124 | pass 125 | 126 | @abstractmethod 127 | async def stop(self) -> None: 128 | """停止监控服务""" 129 | pass 130 | 131 | @abstractmethod 132 | async def get_stats(self) -> MonitoringStats: 133 | """获取监控统计信息""" 134 | pass 135 | 136 | @abstractmethod 137 | async def get_price_data(self) -> Dict[str, PriceData]: 138 | """获取价格数据""" 139 | pass 140 | 141 | @abstractmethod 142 | async def get_spread_data(self) -> Dict[str, SpreadData]: 143 | """获取价差数据""" 144 | pass 145 | 146 | @abstractmethod 147 | async def subscribe_updates(self, callback: Callable[[Dict[str, Any]], None]) -> None: 148 | """订阅数据更新""" 149 | pass 150 | 151 | @abstractmethod 152 | async def health_check(self) -> Dict[str, Any]: 153 | """健康检查""" 154 | pass 155 | 156 | # === 新增灵活订阅方法 === 157 | 158 | @abstractmethod 159 | async def subscribe_ticker(self, exchange_id: str, symbols: List[str]) -> bool: 160 | """订阅ticker数据""" 161 | pass 162 | 163 | @abstractmethod 164 | async def subscribe_orderbook(self, exchange_id: str, symbols: List[str]) -> bool: 165 | """订阅orderbook数据""" 166 | pass 167 | 168 | @abstractmethod 169 | async def unsubscribe_ticker(self, exchange_id: str, symbols: List[str]) -> bool: 170 | """取消订阅ticker数据""" 171 | pass 172 | 173 | @abstractmethod 174 | async def unsubscribe_orderbook(self, exchange_id: str, symbols: List[str]) -> bool: 175 | """取消订阅orderbook数据""" 176 | pass 177 | 178 | @abstractmethod 179 | async def configure_exchange_subscription(self, config: ExchangeSubscriptionConfig) -> bool: 180 | """配置交易所订阅策略""" 181 | pass 182 | 183 | @abstractmethod 184 | async def get_subscription_status(self) -> Dict[str, Dict[str, Any]]: 185 | """获取订阅状态""" 186 | pass -------------------------------------------------------------------------------- /core/services/symbol_manager/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 符号管理模块 3 | 4 | 提供统一的符号管理功能: 5 | - 符号格式转换(标准格式 ↔ 交易所格式) 6 | - 交易所交易对获取和缓存 7 | - 重叠交易对计算 8 | - 订阅符号列表管理 9 | """ 10 | 11 | from .interfaces.symbol_cache import ISymbolCacheService 12 | from .interfaces.symbol_conversion_service import ISymbolConversionService, SymbolFormat 13 | from .implementations.symbol_cache_service import SymbolCacheServiceImpl 14 | from .implementations.symbol_conversion_service import SymbolConversionService 15 | from .models.symbol_cache_models import SymbolCacheData, SymbolOverlapConfig 16 | 17 | __all__ = [ 18 | # 符号缓存服务 19 | 'ISymbolCacheService', 20 | 'SymbolCacheServiceImpl', 21 | 'SymbolCacheData', 22 | 'SymbolOverlapConfig', 23 | # 符号转换服务 24 | 'ISymbolConversionService', 25 | 'SymbolConversionService', 26 | 'SymbolFormat' 27 | ] -------------------------------------------------------------------------------- /core/services/symbol_manager/implementations/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 符号管理实现模块 3 | """ 4 | 5 | from .symbol_cache_service import SymbolCacheServiceImpl 6 | from .symbol_conversion_service import SymbolConversionService 7 | 8 | __all__ = [ 9 | 'SymbolCacheServiceImpl', 10 | 'SymbolConversionService' 11 | ] -------------------------------------------------------------------------------- /core/services/symbol_manager/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 符号管理接口模块 3 | """ 4 | 5 | from .symbol_cache import ISymbolCacheService 6 | from .symbol_conversion_service import ISymbolConversionService, SymbolFormat 7 | 8 | __all__ = [ 9 | 'ISymbolCacheService', 10 | 'ISymbolConversionService', 11 | 'SymbolFormat' 12 | ] -------------------------------------------------------------------------------- /core/services/symbol_manager/interfaces/symbol_cache.py: -------------------------------------------------------------------------------- 1 | """ 2 | 符号缓存服务接口 3 | 4 | 定义符号缓存管理的核心接口,支持: 5 | - 一次性获取和缓存交易对 6 | - 计算重叠交易对 7 | - 为各交易所提供固定的符号列表 8 | """ 9 | 10 | from abc import ABC, abstractmethod 11 | from typing import Dict, List, Optional, Any 12 | from dataclasses import dataclass 13 | 14 | @dataclass 15 | class SymbolCacheData: 16 | """符号缓存数据结构""" 17 | exchange_symbols: Dict[str, List[str]] # 各交易所支持的符号 {"hyperliquid": ["BTC_USDT_PERP", ...]} 18 | overlap_symbols: List[str] # 重叠的符号列表 19 | subscription_symbols: Dict[str, List[str]] # 各交易所应该订阅的符号列表 20 | timestamp: float # 缓存时间戳 21 | total_symbols: int # 总符号数量 22 | overlap_count: int # 重叠符号数量 23 | metadata: Dict[str, Any] # 元数据 24 | 25 | @dataclass 26 | class SymbolOverlapConfig: 27 | """符号重叠配置""" 28 | min_exchange_count: int = 2 # 最小交易所重叠数量 29 | use_overlap_only: bool = True # 是否只使用重叠符号 30 | max_symbols_per_exchange: int = 0 # 每个交易所最大符号数量(0表示无限制) 31 | exchange_priority: List[str] = None # 交易所优先级 32 | include_patterns: List[str] = None # 包含模式 33 | exclude_patterns: List[str] = None # 排除模式 34 | 35 | class ISymbolCacheService(ABC): 36 | """符号缓存服务接口""" 37 | 38 | @abstractmethod 39 | async def initialize_cache(self, exchange_ids: List[str], config: Optional[SymbolOverlapConfig] = None) -> bool: 40 | """初始化符号缓存(只在启动时调用一次) 41 | 42 | Args: 43 | exchange_ids: 交易所ID列表 44 | config: 重叠配置 45 | 46 | Returns: 47 | bool: 初始化是否成功 48 | """ 49 | pass 50 | 51 | @abstractmethod 52 | def get_symbols_for_exchange(self, exchange_id: str) -> List[str]: 53 | """获取指定交易所应该订阅的符号列表 54 | 55 | Args: 56 | exchange_id: 交易所ID 57 | 58 | Returns: 59 | List[str]: 符号列表 60 | """ 61 | pass 62 | 63 | @abstractmethod 64 | def get_overlap_symbols(self) -> List[str]: 65 | """获取重叠的符号列表 66 | 67 | Returns: 68 | List[str]: 重叠符号列表 69 | """ 70 | pass 71 | 72 | @abstractmethod 73 | def get_all_exchange_symbols(self) -> Dict[str, List[str]]: 74 | """获取所有交易所的符号列表 75 | 76 | Returns: 77 | Dict[str, List[str]]: 交易所符号映射 78 | """ 79 | pass 80 | 81 | @abstractmethod 82 | def is_cache_valid(self) -> bool: 83 | """检查缓存是否有效 84 | 85 | Returns: 86 | bool: 缓存是否有效 87 | """ 88 | pass 89 | 90 | @abstractmethod 91 | def get_cache_stats(self) -> Dict[str, Any]: 92 | """获取缓存统计信息 93 | 94 | Returns: 95 | Dict[str, Any]: 缓存统计 96 | """ 97 | pass 98 | 99 | @abstractmethod 100 | def clear_cache(self) -> None: 101 | """清空缓存""" 102 | pass -------------------------------------------------------------------------------- /core/services/symbol_manager/interfaces/symbol_conversion_service.py: -------------------------------------------------------------------------------- 1 | """ 2 | 符号转换服务接口 3 | 4 | 统一处理所有交易所的符号格式转换,消除架构冗余 5 | """ 6 | 7 | from abc import ABC, abstractmethod 8 | from typing import Dict, List, Optional, Any 9 | from enum import Enum 10 | 11 | 12 | class SymbolFormat(Enum): 13 | """符号格式枚举""" 14 | STANDARD = "standard" # 系统标准格式:BTC-USDC-PERP 15 | HYPERLIQUID = "hyperliquid" # Hyperliquid格式:BTC/USDC:PERP 16 | BACKPACK = "backpack" # Backpack格式:BTC_USDC_PERP 17 | EDGEX = "edgex" # EdgeX格式:BTC_USDT_PERP 18 | BINANCE = "binance" # Binance格式:BTCUSDT 19 | 20 | 21 | class ISymbolConversionService(ABC): 22 | """符号转换服务接口""" 23 | 24 | @abstractmethod 25 | async def convert_to_exchange_format(self, standard_symbol: str, exchange: str) -> str: 26 | """ 27 | 将系统标准格式转换为交易所特定格式 28 | 29 | Args: 30 | standard_symbol: 系统标准格式符号(如 BTC-USDC-PERP) 31 | exchange: 交易所名称(如 'hyperliquid', 'backpack', 'edgex') 32 | 33 | Returns: 34 | 交易所特定格式符号 35 | """ 36 | pass 37 | 38 | @abstractmethod 39 | async def convert_from_exchange_format(self, exchange_symbol: str, exchange: str) -> str: 40 | """ 41 | 将交易所特定格式转换为系统标准格式 42 | 43 | Args: 44 | exchange_symbol: 交易所特定格式符号 45 | exchange: 交易所名称 46 | 47 | Returns: 48 | 系统标准格式符号 49 | """ 50 | pass 51 | 52 | @abstractmethod 53 | async def batch_convert_to_exchange_format(self, symbols: List[str], exchange: str) -> Dict[str, str]: 54 | """ 55 | 批量转换符号到交易所格式 56 | 57 | Args: 58 | symbols: 系统标准格式符号列表 59 | exchange: 交易所名称 60 | 61 | Returns: 62 | 符号映射字典 {标准格式: 交易所格式} 63 | """ 64 | pass 65 | 66 | @abstractmethod 67 | async def batch_convert_from_exchange_format(self, symbols: List[str], exchange: str) -> Dict[str, str]: 68 | """ 69 | 批量转换符号从交易所格式 70 | 71 | Args: 72 | symbols: 交易所特定格式符号列表 73 | exchange: 交易所名称 74 | 75 | Returns: 76 | 符号映射字典 {交易所格式: 标准格式} 77 | """ 78 | pass 79 | 80 | @abstractmethod 81 | async def get_supported_exchanges(self) -> List[str]: 82 | """ 83 | 获取支持的交易所列表 84 | 85 | Returns: 86 | 支持的交易所名称列表 87 | """ 88 | pass 89 | 90 | @abstractmethod 91 | async def get_exchange_symbol_format(self, exchange: str) -> SymbolFormat: 92 | """ 93 | 获取交易所的符号格式类型 94 | 95 | Args: 96 | exchange: 交易所名称 97 | 98 | Returns: 99 | 符号格式枚举 100 | """ 101 | pass 102 | 103 | @abstractmethod 104 | async def validate_standard_symbol(self, symbol: str) -> bool: 105 | """ 106 | 验证标准格式符号是否有效 107 | 108 | Args: 109 | symbol: 标准格式符号 110 | 111 | Returns: 112 | 是否有效 113 | """ 114 | pass 115 | 116 | @abstractmethod 117 | async def validate_exchange_symbol(self, symbol: str, exchange: str) -> bool: 118 | """ 119 | 验证交易所格式符号是否有效 120 | 121 | Args: 122 | symbol: 交易所格式符号 123 | exchange: 交易所名称 124 | 125 | Returns: 126 | 是否有效 127 | """ 128 | pass 129 | 130 | @abstractmethod 131 | async def get_symbol_info(self, symbol: str) -> Dict[str, Any]: 132 | """ 133 | 获取符号信息 134 | 135 | Args: 136 | symbol: 符号(标准格式或交易所格式) 137 | 138 | Returns: 139 | 符号信息字典 140 | """ 141 | pass 142 | 143 | @abstractmethod 144 | async def reload_configuration(self) -> bool: 145 | """ 146 | 重新加载配置 147 | 148 | Returns: 149 | 是否成功重新加载 150 | """ 151 | pass -------------------------------------------------------------------------------- /core/services/symbol_manager/models/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | 符号管理数据模型 3 | """ 4 | 5 | from .symbol_cache_models import SymbolCacheData, SymbolOverlapConfig 6 | 7 | __all__ = ['SymbolCacheData', 'SymbolOverlapConfig'] -------------------------------------------------------------------------------- /core/services/symbol_manager/models/symbol_cache_models.py: -------------------------------------------------------------------------------- 1 | """ 2 | 符号缓存相关数据模型 3 | """ 4 | 5 | from dataclasses import dataclass, field 6 | from typing import Dict, List, Optional, Any 7 | from datetime import datetime 8 | 9 | @dataclass 10 | class SymbolCacheData: 11 | """符号缓存数据结构""" 12 | exchange_symbols: Dict[str, List[str]] # 各交易所支持的符号 13 | overlap_symbols: List[str] # 重叠的符号列表 14 | subscription_symbols: Dict[str, List[str]] # 各交易所应该订阅的符号列表 15 | timestamp: float # 缓存时间戳 16 | total_symbols: int # 总符号数量 17 | overlap_count: int # 重叠符号数量 18 | metadata: Dict[str, Any] = field(default_factory=dict) # 元数据 19 | 20 | @dataclass 21 | class SymbolOverlapConfig: 22 | """符号重叠配置""" 23 | min_exchange_count: int = 2 # 最小交易所重叠数量 24 | use_overlap_only: bool = True # 是否只使用重叠符号 25 | max_symbols_per_exchange: int = 0 # 每个交易所最大符号数量(0表示无限制) 26 | exchange_priority: List[str] = field(default_factory=list) # 交易所优先级 27 | include_patterns: List[str] = field(default_factory=list) # 包含模式 28 | exclude_patterns: List[str] = field(default_factory=list) # 排除模式 29 | 30 | def __post_init__(self): 31 | """初始化后处理""" 32 | if self.exchange_priority is None: 33 | self.exchange_priority = [] 34 | if self.include_patterns is None: 35 | self.include_patterns = [] 36 | if self.exclude_patterns is None: 37 | self.exclude_patterns = [] 38 | 39 | @dataclass 40 | class SymbolAnalysisResult: 41 | """符号分析结果""" 42 | symbol: str # 符号名称 43 | exchanges: List[str] # 支持的交易所 44 | exchange_count: int # 支持的交易所数量 45 | is_overlap: bool # 是否为重叠符号 46 | metadata: Dict[str, Any] = field(default_factory=dict) # 元数据 47 | 48 | def __post_init__(self): 49 | """初始化后处理""" 50 | self.exchange_count = len(self.exchanges) 51 | self.is_overlap = self.exchange_count >= 2 -------------------------------------------------------------------------------- /logs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cryptocj520/grid/4b2ae95f2afcd2e5381e5ab2f2673eb60d51b9a0/logs/.DS_Store -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # 新架构依赖 2 | fastapi==0.104.1 3 | uvicorn==0.24.0 4 | pydantic==2.5.0 5 | injector==0.21.0 6 | asyncio 7 | websockets==12.0 8 | redis==5.0.1 9 | sqlalchemy==2.0.23 10 | alembic==1.13.1 11 | 12 | # 保留原有依赖 13 | ccxt==4.1.64 14 | pandas==2.1.3 15 | numpy==1.24.3 16 | aiohttp==3.9.1 17 | websocket-client==1.6.4 18 | pyyaml==6.0.1 19 | -------------------------------------------------------------------------------- /start_all_grids.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "🚀 启动所有网格交易系统..." 4 | 5 | # 检查tmux是否安装 6 | if ! command -v tmux &> /dev/null; then 7 | echo "❌ tmux未安装,请先安装: brew install tmux" 8 | exit 1 9 | fi 10 | 11 | # 获取脚本所在目录 12 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 13 | 14 | # 启动BTC网格 15 | echo "📊 启动BTC网格..." 16 | tmux new -s grid_btc -d "cd $SCRIPT_DIR && python run_grid_trading.py --config config/grid/backpack_long_grid.yaml" 17 | 18 | # 等待1秒 19 | sleep 1 20 | 21 | # 启动ETH网格 22 | echo "📊 启动ETH网格..." 23 | tmux new -s grid_eth -d "cd $SCRIPT_DIR && python run_grid_trading.py --config config/grid/backpack_eth_long_grid.yaml" 24 | 25 | # 等待1秒 26 | sleep 1 27 | 28 | # 启动SOL网格 29 | echo "📊 启动SOL网格..." 30 | tmux new -s grid_sol -d "cd $SCRIPT_DIR && python run_grid_trading.py --config config/grid/backpack_sol_long_grid.yaml" 31 | 32 | echo "" 33 | echo "✅ 所有网格已启动!" 34 | echo "" 35 | echo "查看运行状态:" 36 | echo " tmux ls" 37 | echo "" 38 | echo "连接到某个网格:" 39 | echo " tmux attach -t grid_btc" 40 | echo " tmux attach -t grid_eth" 41 | echo " tmux attach -t grid_sol" 42 | echo "" 43 | echo "停止所有网格:" 44 | echo " ./stop_all_grids.sh" 45 | --------------------------------------------------------------------------------