#!/usr/bin/env tsx /** * Pacifica 市场数据管理器使用示例 * 演示如何使用WebSocket获取实时价格和订单簿数据 */ import { MarketDataManager, MarketDataManagerConfig } from '../src/core/MarketDataManager'; import { Logger } from '../src/utils/Logger'; // 配置示例 const config: MarketDataManagerConfig = { websocket: { url: 'wss://ws.pacifica.fi/ws', // 主网WebSocket地址 reconnectInterval: 5000, heartbeatInterval: 30000, maxReconnectAttempts: 10 }, priceData: { symbols: ['BTC', 'ETH', 'SOL'], // 订阅的交易对 updateInterval: 1000, maxDataAge: 10000 }, orderBook: { symbols: ['BTC', 'ETH', 'SOL'], aggregationLevels: [1], // 只使用聚合级别1,获取前5档 updateInterval: 1000, maxDataAge: 10000 }, cleanupInterval: 60000, maxDataAge: 300000 }; async function runMarketDataExample() { const logger = Logger.getInstance(); logger.info('🚀 启动Pacifica市场数据示例'); // 创建市场数据管理器 const marketDataManager = new MarketDataManager(config); // 设置事件监听器 setupEventListeners(marketDataManager); try { // 启动市场数据管理器 await marketDataManager.start(); logger.info('✅ 市场数据管理器启动成功'); // 等待数据更新 await waitForData(marketDataManager); // 演示数据访问 demonstrateDataAccess(marketDataManager); // 运行状态监控 await runStatusMonitoring(marketDataManager); } catch (error) { logger.error(`❌ 市场数据示例运行失败: ${error}`, error as Error); } finally { // 停止市场数据管理器 await marketDataManager.stop(); logger.info('🛑 市场数据管理器已停止'); } } /** * 设置事件监听器 */ function setupEventListeners(marketDataManager: MarketDataManager) { const logger = Logger.getInstance(); // 连接事件 marketDataManager.on('connected', () => { logger.info('🔗 WebSocket连接已建立'); }); marketDataManager.on('disconnected', (info) => { logger.warn(`🔌 WebSocket连接断开: ${JSON.stringify(info)}`); }); marketDataManager.on('error', (error) => { logger.error(`❌ 市场数据管理器错误: ${error.message}`, error); }); // 价格数据事件 marketDataManager.on('priceUpdate', (data) => { logger.info(`💰 价格更新: ${data.symbol} = $${data.getMarkPrice().toFixed(2)}`); }); marketDataManager.on('priceChange', (change) => { const direction = change.changePercentage > 0 ? '📈' : '📉'; logger.info(`${direction} 价格变化: ${change.symbol} ${change.changePercentage.toFixed(2)}% (${change.previousPrice.toFixed(2)} → ${change.currentPrice.toFixed(2)})`); }); // 订单簿数据事件 marketDataManager.on('orderBookUpdate', (data) => { const bestBid = data.getBestBid(); const bestAsk = data.getBestAsk(); const spread = data.getSpread(); if (bestBid && bestAsk && spread) { logger.info(`📊 订单簿更新: ${data.symbol} 买价=${bestBid.toFixed(2)} 卖价=${bestAsk.toFixed(2)} 价差=${spread.toFixed(2)}`); } }); marketDataManager.on('spreadChange', (change) => { logger.info(`📊 价差变化: ${change.symbol} ${change.changePercentage.toFixed(2)}% (${change.previousSpread.toFixed(2)} → ${change.currentSpread.toFixed(2)})`); }); // 批量更新事件 marketDataManager.on('batchPriceUpdate', (data) => { logger.info(`📦 批量价格更新: ${data.length} 个交易对`); }); } /** * 等待数据更新 */ async function waitForData(marketDataManager: MarketDataManager): Promise { const logger = Logger.getInstance(); logger.info('⏳ 等待市场数据更新...'); return new Promise((resolve) => { let priceUpdates = 0; let orderBookUpdates = 0; const checkData = () => { if (priceUpdates >= 3 && orderBookUpdates >= 3) { logger.info('✅ 已收到足够的数据更新'); resolve(); } }; marketDataManager.on('priceUpdate', () => { priceUpdates++; checkData(); }); marketDataManager.on('orderBookUpdate', () => { orderBookUpdates++; checkData(); }); // 超时处理 setTimeout(() => { logger.warn('⏰ 等待数据超时,继续执行'); resolve(); }, 30000); // 30秒超时 }); } /** * 演示数据访问功能 */ function demonstrateDataAccess(marketDataManager: MarketDataManager) { const logger = Logger.getInstance(); logger.info('📋 演示数据访问功能'); const symbols = ['BTC', 'ETH', 'SOL']; symbols.forEach(symbol => { // 价格数据访问 const price = marketDataManager.getLatestPrice(symbol); const oraclePrice = marketDataManager.getLatestOraclePrice(symbol); const fundingRate = marketDataManager.getFundingRate(symbol); const volume24h = marketDataManager.getVolume24h(symbol); if (price) { logger.info(`💰 ${symbol} 价格信息:`); logger.info(` 标记价格: $${price.toFixed(2)}`); if (oraclePrice) logger.info(` 预言机价格: $${oraclePrice.toFixed(2)}`); if (fundingRate) logger.info(` 资金费率: ${(fundingRate * 100).toFixed(4)}%`); if (volume24h) logger.info(` 24h交易量: ${volume24h.toLocaleString()}`); } // 订单簿数据访问 const bestBid = marketDataManager.getBestBid(symbol); const bestAsk = marketDataManager.getBestAsk(symbol); const spread = marketDataManager.getSpread(symbol); const spreadPercentage = marketDataManager.getSpreadPercentage(symbol); if (bestBid && bestAsk) { logger.info(`📊 ${symbol} 订单簿信息:`); logger.info(` 最佳买价: $${bestBid.toFixed(2)}`); logger.info(` 最佳卖价: $${bestAsk.toFixed(2)}`); if (spread) logger.info(` 价差: $${spread.toFixed(2)}`); if (spreadPercentage) logger.info(` 价差百分比: ${spreadPercentage.toFixed(4)}%`); } // 市场深度信息 const marketDepth = marketDataManager.getMarketDepth(symbol, 5); if (marketDepth) { logger.info(`📈 ${symbol} 市场深度 (前5档):`); logger.info(' 买单:'); marketDepth.bids.forEach((bid, index) => { logger.info(` ${index + 1}. $${bid.price.toFixed(2)} (${bid.volume.toFixed(2)} 数量, ${bid.orders} 订单)`); }); logger.info(' 卖单:'); marketDepth.asks.forEach((ask, index) => { logger.info(` ${index + 1}. $${ask.price.toFixed(2)} (${ask.volume.toFixed(2)} 数量, ${ask.orders} 订单)`); }); } // 数据新鲜度检查 const isPriceFresh = marketDataManager.isPriceDataFresh(symbol); const isOrderBookFresh = marketDataManager.isOrderBookDataFresh(symbol); const priceAge = marketDataManager.getPriceDataAge(symbol); const orderBookAge = marketDataManager.getOrderBookDataAge(symbol); logger.info(`⏱️ ${symbol} 数据新鲜度:`); logger.info(` 价格数据: ${isPriceFresh ? '✅ 新鲜' : '❌ 过期'} (年龄: ${priceAge}ms)`); logger.info(` 订单簿数据: ${isOrderBookFresh ? '✅ 新鲜' : '❌ 过期'} (年龄: ${orderBookAge}ms)`); logger.info(''); // 空行分隔 }); } /** * 运行状态监控 */ async function runStatusMonitoring(marketDataManager: MarketDataManager): Promise { const logger = Logger.getInstance(); logger.info('📊 开始状态监控...'); return new Promise((resolve) => { const monitoringInterval = setInterval(() => { // 获取状态信息 const status = marketDataManager.getStatus(); const statistics = marketDataManager.getStatistics(); const healthCheck = marketDataManager.getHealthCheck(); logger.info('📈 系统状态报告:'); logger.info(` WebSocket连接: ${status.websocket.isConnected ? '✅ 已连接' : '❌ 断开'}`); logger.info(` 价格数据: ${status.priceData.dataCount} 个交易对`); logger.info(` 订单簿数据: ${status.orderBook.dataCount} 条记录`); logger.info(` 健康状态: ${healthCheck.status} (${healthCheck.issues.length} 个问题)`); if (healthCheck.issues.length > 0) { logger.warn(` 问题列表: ${healthCheck.issues.join(', ')}`); } logger.info('📊 统计信息:'); logger.info(` 价格数据: ${statistics.priceData.freshDataCount}/${statistics.priceData.totalSymbols} 新鲜`); logger.info(` 订单簿数据: ${statistics.orderBook.freshDataCount}/${statistics.orderBook.totalDataRecords} 新鲜`); logger.info(` 平均数据年龄: ${statistics.priceData.averageAge.toFixed(0)}ms`); logger.info(''); // 空行分隔 }, 10000); // 每10秒报告一次 // 30秒后停止监控 setTimeout(() => { clearInterval(monitoringInterval); logger.info('📊 状态监控结束'); resolve(); }, 30000); }); } // 主函数 async function main() { const args = process.argv.slice(2); if (args.length === 0) { // 运行完整示例 await runMarketDataExample(); } else if (args[0] === 'status') { // 只显示状态 const marketDataManager = new MarketDataManager(config); await marketDataManager.start(); setTimeout(async () => { const status = marketDataManager.getStatus(); const healthCheck = marketDataManager.getHealthCheck(); console.log('📊 市场数据管理器状态:'); console.log(JSON.stringify({ status, healthCheck }, null, 2)); await marketDataManager.stop(); }, 5000); } else if (args[0] === 'test') { // 测试连接 const marketDataManager = new MarketDataManager(config); marketDataManager.on('connected', () => { console.log('✅ WebSocket连接测试成功'); marketDataManager.stop(); }); marketDataManager.on('error', (error) => { console.log('❌ WebSocket连接测试失败:', error.message); process.exit(1); }); await marketDataManager.start(); } else { console.log('使用方法:'); console.log(' npx tsx examples/market-data-example.ts # 运行完整示例'); console.log(' npx tsx examples/market-data-example.ts status # 显示状态'); console.log(' npx tsx examples/market-data-example.ts test # 测试连接'); } } // 运行主函数 if (import.meta.url === `file://${process.argv[1]}`) { main().catch(console.error); } export { MarketDataManager, MarketDataManagerConfig };