# 价格管理解决方案 ## 问题背景 之前系统存在一个反复出现的问题:价格获取机制复杂且不稳定,需要多层fallback逻辑来处理API失败的情况。这导致: 1. **复杂的fallback逻辑**:多个价格获取方法(API、缓存、历史数据、写死的fallback) 2. **频繁的价格获取失败**:导致系统跳过交易而不是执行使用率控制 3. **代码维护困难**:每次都需要调试和修改价格获取逻辑 4. **不可靠的价格数据**:影响交易决策和使用率控制 ## 解决方案:WebSocket全局价格管理器 ### 核心思路 使用Pacifica官方WebSocket API中的prices订阅,在内存中维护全局实时价格数据。 ### 实现架构 ``` ┌─────────────────────┐ │ Pacifica WebSocket │ │ wss://ws.pacifica.fi/ws └─────────────────────┘ │ │ subscribe to "prices" ▼ ┌─────────────────────┐ │ PriceManager │ │ (全局单例) │ │ ├─ WebSocket连接 │ │ ├─ 价格缓存Map │ │ ├─ 自动重连 │ │ └─ 清理过期数据 │ └─────────────────────┘ │ │ getPrice(symbol) ▼ ┌─────────────────────┐ │ TradingEngine │ │ ├─ 使用率控制 │ │ ├─ 交易执行 │ │ └─ 价格查询 │ └─────────────────────┘ ``` ### WebSocket订阅消息格式 **订阅请求**: ```json { "method": "subscribe", "params": { "source": "prices" } } ``` **返回数据格式**: ```json { "channel": "prices", "data": [ { "symbol": "BTC", "mark": "105473", "oracle": "105473", "funding_rate": "0.0001", "volume_24h": "12345.67", "timestamp": 1640995200000 } ] } ``` ### 核心特性 1. **实时数据**:通过WebSocket获取毫秒级实时价格更新 2. **自动重连**:连接断开时自动重连,最多重试10次 3. **内存缓存**:所有价格数据在内存中维护,查询零延迟 4. **清理机制**:自动清理超过10分钟的过期价格数据 5. **多格式支持**:支持BTC-USD、BTCUSDT、BTC等多种symbol格式 6. **事件驱动**:价格更新时触发事件,可供其他模块监听 ### 代码实现 #### 1. PriceManager (src/modules/price/PriceManager.ts) ```typescript import WebSocket from 'ws' import { EventEmitter } from 'events' export class PriceManager extends EventEmitter { private ws: WebSocket | null = null private priceCache: Map = new Map() // 连接到WebSocket并订阅价格流 private async connect(): Promise { this.ws = new WebSocket(this.wsUrl) this.ws.on('open', () => { // 订阅价格数据 this.ws.send( JSON.stringify({ method: 'subscribe', params: { source: 'prices' }, }), ) }) this.ws.on('message', data => { const message = JSON.parse(data.toString()) if (message.channel === 'prices') { // 更新价格缓存 for (const priceItem of message.data) { this.priceCache.set(priceItem.symbol, priceItem) } } }) } // 同步获取价格 public getPrice(symbol: string): number { const priceData = this.priceCache.get(this.normalizeSymbol(symbol)) return parseFloat(priceData?.mark || '0') } } // 全局单例 export const globalPriceManager = new PriceManager() ``` #### 2. TradingEngine集成 ```typescript import { globalPriceManager } from '../price/PriceManager.js' export class TradingEngine { private getCurrentPriceSync(symbol: string): number { // 直接从全局价格管理器获取实时价格 const price = globalPriceManager.getPrice(symbol) if (price > 0) { return price } // 简单的fallback(仅在WebSocket未连接时使用) if (symbol.includes('BTC')) { return 65000 // BTC基准价格 } return 0 } } ``` ### 系统初始化 在SystemOrchestrator中确保PriceManager在系统启动时自动初始化: ```typescript // src/modules/SystemOrchestrator.ts import { globalPriceManager } from './price/PriceManager.js' export class SystemOrchestrator { async start(): Promise { // 价格管理器会自动启动WebSocket连接 logger.info('全局价格管理器已初始化') // ... 其他服务启动 } } ``` ## 优势对比 ### 之前的方案 ❌ - ✗ 多层复杂的fallback逻辑 - ✗ 频繁的API调用和超时 - ✗ 价格获取失败导致交易跳过 - ✗ 代码难以维护和调试 - ✗ 缓存过期导致价格为0 ### 新方案 ✅ - ✅ 单一数据源,简化架构 - ✅ 实时WebSocket数据,延迟极低 - ✅ 自动重连,高可用性 - ✅ 内存查询,性能极佳 - ✅ 最小化fallback逻辑 - ✅ 易于测试和维护 ## 监控和调试 ### 价格管理器状态检查 ```typescript // 检查价格管理器状态 const status = globalPriceManager.getStatus() console.log(status) // { // connected: true, // symbolCount: 25, // lastUpdate: 1640995200000, // reconnectAttempts: 0 // } ``` ### 事件监听 ```typescript // 监听价格更新事件 globalPriceManager.on('priceUpdate', priceData => { console.log(`价格更新: ${priceData.symbol} = $${priceData.mark}`) }) // 监听连接事件 globalPriceManager.on('connected', () => { console.log('价格WebSocket已连接') }) ``` ### 日志级别配置 在生产环境中,将价格更新的日志级别设置为debug: ```typescript // 减少生产环境日志噪音 logger.debug(`价格缓存更新: ${message.data.length}个交易对`) ``` ## 故障处理 ### 1. WebSocket连接失败 - **症状**:价格获取返回0或fallback价格 - **检查**:`globalPriceManager.getStatus().connected` - **解决**:自动重连机制会处理,或手动调用`globalPriceManager.reconnect()` ### 2. 价格数据过期 - **症状**:缓存中有数据但价格不更新 - **检查**:`globalPriceManager.getStatus().lastUpdate` - **解决**:5分钟自动清理过期数据 ### 3. Symbol格式不匹配 - **症状**:特定symbol总是返回0 - **检查**:调用`globalPriceManager.getAllPrices()`查看可用symbol - **解决**:PriceManager会自动处理多种格式(BTC-USD、BTCUSDT、BTC) ## 部署注意事项 1. **确保WebSocket网络连通性**: - 确认防火墙允许wss://ws.pacifica.fi/ws - 代理配置要支持WebSocket升级 2. **内存使用**: - 价格缓存占用内存很少(每个symbol约100字节) - 25个交易对约2.5KB内存占用 3. **错误监控**: - 监控`globalPriceManager`的错误事件 - 设置重连失败告警 ## 未来扩展 1. **多交易所支持**:可以扩展为支持多个交易所的价格聚合 2. **价格历史**:可以添加价格历史记录功能 3. **价格告警**:基于价格变动的告警机制 4. **负载均衡**:多个WebSocket连接的负载均衡 ## 结论 通过实现基于WebSocket的全局价格管理器,我们彻底解决了价格获取的稳定性问题,简化了系统架构,提高了交易执行的可靠性。 **关键原则**: - **单一数据源**:避免多个数据源的复杂性 - **实时连接**:WebSocket确保数据实时性 - **简化逻辑**:最小化fallback和错误处理 - **全局管理**:统一的价格管理避免重复实现 这个解决方案应该避免我们以后再次遇到类似的价格获取问题。