market-data-example.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. #!/usr/bin/env tsx
  2. /**
  3. * Pacifica 市场数据管理器使用示例
  4. * 演示如何使用WebSocket获取实时价格和订单簿数据
  5. */
  6. import { MarketDataManager, MarketDataManagerConfig } from '../src/core/MarketDataManager';
  7. import { Logger } from '../src/utils/Logger';
  8. // 配置示例
  9. const config: MarketDataManagerConfig = {
  10. websocket: {
  11. url: 'wss://ws.pacifica.fi/ws', // 主网WebSocket地址
  12. reconnectInterval: 5000,
  13. heartbeatInterval: 30000,
  14. maxReconnectAttempts: 10
  15. },
  16. priceData: {
  17. symbols: ['BTC', 'ETH', 'SOL'], // 订阅的交易对
  18. updateInterval: 1000,
  19. maxDataAge: 10000
  20. },
  21. orderBook: {
  22. symbols: ['BTC', 'ETH', 'SOL'],
  23. aggregationLevels: [1], // 只使用聚合级别1,获取前5档
  24. updateInterval: 1000,
  25. maxDataAge: 10000
  26. },
  27. cleanupInterval: 60000,
  28. maxDataAge: 300000
  29. };
  30. async function runMarketDataExample() {
  31. const logger = Logger.getInstance();
  32. logger.info('🚀 启动Pacifica市场数据示例');
  33. // 创建市场数据管理器
  34. const marketDataManager = new MarketDataManager(config);
  35. // 设置事件监听器
  36. setupEventListeners(marketDataManager);
  37. try {
  38. // 启动市场数据管理器
  39. await marketDataManager.start();
  40. logger.info('✅ 市场数据管理器启动成功');
  41. // 等待数据更新
  42. await waitForData(marketDataManager);
  43. // 演示数据访问
  44. demonstrateDataAccess(marketDataManager);
  45. // 运行状态监控
  46. await runStatusMonitoring(marketDataManager);
  47. } catch (error) {
  48. logger.error(`❌ 市场数据示例运行失败: ${error}`, error as Error);
  49. } finally {
  50. // 停止市场数据管理器
  51. await marketDataManager.stop();
  52. logger.info('🛑 市场数据管理器已停止');
  53. }
  54. }
  55. /**
  56. * 设置事件监听器
  57. */
  58. function setupEventListeners(marketDataManager: MarketDataManager) {
  59. const logger = Logger.getInstance();
  60. // 连接事件
  61. marketDataManager.on('connected', () => {
  62. logger.info('🔗 WebSocket连接已建立');
  63. });
  64. marketDataManager.on('disconnected', (info) => {
  65. logger.warn(`🔌 WebSocket连接断开: ${JSON.stringify(info)}`);
  66. });
  67. marketDataManager.on('error', (error) => {
  68. logger.error(`❌ 市场数据管理器错误: ${error.message}`, error);
  69. });
  70. // 价格数据事件
  71. marketDataManager.on('priceUpdate', (data) => {
  72. logger.info(`💰 价格更新: ${data.symbol} = $${data.getMarkPrice().toFixed(2)}`);
  73. });
  74. marketDataManager.on('priceChange', (change) => {
  75. const direction = change.changePercentage > 0 ? '📈' : '📉';
  76. logger.info(`${direction} 价格变化: ${change.symbol} ${change.changePercentage.toFixed(2)}% (${change.previousPrice.toFixed(2)} → ${change.currentPrice.toFixed(2)})`);
  77. });
  78. // 订单簿数据事件
  79. marketDataManager.on('orderBookUpdate', (data) => {
  80. const bestBid = data.getBestBid();
  81. const bestAsk = data.getBestAsk();
  82. const spread = data.getSpread();
  83. if (bestBid && bestAsk && spread) {
  84. logger.info(`📊 订单簿更新: ${data.symbol} 买价=${bestBid.toFixed(2)} 卖价=${bestAsk.toFixed(2)} 价差=${spread.toFixed(2)}`);
  85. }
  86. });
  87. marketDataManager.on('spreadChange', (change) => {
  88. logger.info(`📊 价差变化: ${change.symbol} ${change.changePercentage.toFixed(2)}% (${change.previousSpread.toFixed(2)} → ${change.currentSpread.toFixed(2)})`);
  89. });
  90. // 批量更新事件
  91. marketDataManager.on('batchPriceUpdate', (data) => {
  92. logger.info(`📦 批量价格更新: ${data.length} 个交易对`);
  93. });
  94. }
  95. /**
  96. * 等待数据更新
  97. */
  98. async function waitForData(marketDataManager: MarketDataManager): Promise<void> {
  99. const logger = Logger.getInstance();
  100. logger.info('⏳ 等待市场数据更新...');
  101. return new Promise((resolve) => {
  102. let priceUpdates = 0;
  103. let orderBookUpdates = 0;
  104. const checkData = () => {
  105. if (priceUpdates >= 3 && orderBookUpdates >= 3) {
  106. logger.info('✅ 已收到足够的数据更新');
  107. resolve();
  108. }
  109. };
  110. marketDataManager.on('priceUpdate', () => {
  111. priceUpdates++;
  112. checkData();
  113. });
  114. marketDataManager.on('orderBookUpdate', () => {
  115. orderBookUpdates++;
  116. checkData();
  117. });
  118. // 超时处理
  119. setTimeout(() => {
  120. logger.warn('⏰ 等待数据超时,继续执行');
  121. resolve();
  122. }, 30000); // 30秒超时
  123. });
  124. }
  125. /**
  126. * 演示数据访问功能
  127. */
  128. function demonstrateDataAccess(marketDataManager: MarketDataManager) {
  129. const logger = Logger.getInstance();
  130. logger.info('📋 演示数据访问功能');
  131. const symbols = ['BTC', 'ETH', 'SOL'];
  132. symbols.forEach(symbol => {
  133. // 价格数据访问
  134. const price = marketDataManager.getLatestPrice(symbol);
  135. const oraclePrice = marketDataManager.getLatestOraclePrice(symbol);
  136. const fundingRate = marketDataManager.getFundingRate(symbol);
  137. const volume24h = marketDataManager.getVolume24h(symbol);
  138. if (price) {
  139. logger.info(`💰 ${symbol} 价格信息:`);
  140. logger.info(` 标记价格: $${price.toFixed(2)}`);
  141. if (oraclePrice) logger.info(` 预言机价格: $${oraclePrice.toFixed(2)}`);
  142. if (fundingRate) logger.info(` 资金费率: ${(fundingRate * 100).toFixed(4)}%`);
  143. if (volume24h) logger.info(` 24h交易量: ${volume24h.toLocaleString()}`);
  144. }
  145. // 订单簿数据访问
  146. const bestBid = marketDataManager.getBestBid(symbol);
  147. const bestAsk = marketDataManager.getBestAsk(symbol);
  148. const spread = marketDataManager.getSpread(symbol);
  149. const spreadPercentage = marketDataManager.getSpreadPercentage(symbol);
  150. if (bestBid && bestAsk) {
  151. logger.info(`📊 ${symbol} 订单簿信息:`);
  152. logger.info(` 最佳买价: $${bestBid.toFixed(2)}`);
  153. logger.info(` 最佳卖价: $${bestAsk.toFixed(2)}`);
  154. if (spread) logger.info(` 价差: $${spread.toFixed(2)}`);
  155. if (spreadPercentage) logger.info(` 价差百分比: ${spreadPercentage.toFixed(4)}%`);
  156. }
  157. // 市场深度信息
  158. const marketDepth = marketDataManager.getMarketDepth(symbol, 5);
  159. if (marketDepth) {
  160. logger.info(`📈 ${symbol} 市场深度 (前5档):`);
  161. logger.info(' 买单:');
  162. marketDepth.bids.forEach((bid, index) => {
  163. logger.info(` ${index + 1}. $${bid.price.toFixed(2)} (${bid.volume.toFixed(2)} 数量, ${bid.orders} 订单)`);
  164. });
  165. logger.info(' 卖单:');
  166. marketDepth.asks.forEach((ask, index) => {
  167. logger.info(` ${index + 1}. $${ask.price.toFixed(2)} (${ask.volume.toFixed(2)} 数量, ${ask.orders} 订单)`);
  168. });
  169. }
  170. // 数据新鲜度检查
  171. const isPriceFresh = marketDataManager.isPriceDataFresh(symbol);
  172. const isOrderBookFresh = marketDataManager.isOrderBookDataFresh(symbol);
  173. const priceAge = marketDataManager.getPriceDataAge(symbol);
  174. const orderBookAge = marketDataManager.getOrderBookDataAge(symbol);
  175. logger.info(`⏱️ ${symbol} 数据新鲜度:`);
  176. logger.info(` 价格数据: ${isPriceFresh ? '✅ 新鲜' : '❌ 过期'} (年龄: ${priceAge}ms)`);
  177. logger.info(` 订单簿数据: ${isOrderBookFresh ? '✅ 新鲜' : '❌ 过期'} (年龄: ${orderBookAge}ms)`);
  178. logger.info(''); // 空行分隔
  179. });
  180. }
  181. /**
  182. * 运行状态监控
  183. */
  184. async function runStatusMonitoring(marketDataManager: MarketDataManager): Promise<void> {
  185. const logger = Logger.getInstance();
  186. logger.info('📊 开始状态监控...');
  187. return new Promise((resolve) => {
  188. const monitoringInterval = setInterval(() => {
  189. // 获取状态信息
  190. const status = marketDataManager.getStatus();
  191. const statistics = marketDataManager.getStatistics();
  192. const healthCheck = marketDataManager.getHealthCheck();
  193. logger.info('📈 系统状态报告:');
  194. logger.info(` WebSocket连接: ${status.websocket.isConnected ? '✅ 已连接' : '❌ 断开'}`);
  195. logger.info(` 价格数据: ${status.priceData.dataCount} 个交易对`);
  196. logger.info(` 订单簿数据: ${status.orderBook.dataCount} 条记录`);
  197. logger.info(` 健康状态: ${healthCheck.status} (${healthCheck.issues.length} 个问题)`);
  198. if (healthCheck.issues.length > 0) {
  199. logger.warn(` 问题列表: ${healthCheck.issues.join(', ')}`);
  200. }
  201. logger.info('📊 统计信息:');
  202. logger.info(` 价格数据: ${statistics.priceData.freshDataCount}/${statistics.priceData.totalSymbols} 新鲜`);
  203. logger.info(` 订单簿数据: ${statistics.orderBook.freshDataCount}/${statistics.orderBook.totalDataRecords} 新鲜`);
  204. logger.info(` 平均数据年龄: ${statistics.priceData.averageAge.toFixed(0)}ms`);
  205. logger.info(''); // 空行分隔
  206. }, 10000); // 每10秒报告一次
  207. // 30秒后停止监控
  208. setTimeout(() => {
  209. clearInterval(monitoringInterval);
  210. logger.info('📊 状态监控结束');
  211. resolve();
  212. }, 30000);
  213. });
  214. }
  215. // 主函数
  216. async function main() {
  217. const args = process.argv.slice(2);
  218. if (args.length === 0) {
  219. // 运行完整示例
  220. await runMarketDataExample();
  221. } else if (args[0] === 'status') {
  222. // 只显示状态
  223. const marketDataManager = new MarketDataManager(config);
  224. await marketDataManager.start();
  225. setTimeout(async () => {
  226. const status = marketDataManager.getStatus();
  227. const healthCheck = marketDataManager.getHealthCheck();
  228. console.log('📊 市场数据管理器状态:');
  229. console.log(JSON.stringify({ status, healthCheck }, null, 2));
  230. await marketDataManager.stop();
  231. }, 5000);
  232. } else if (args[0] === 'test') {
  233. // 测试连接
  234. const marketDataManager = new MarketDataManager(config);
  235. marketDataManager.on('connected', () => {
  236. console.log('✅ WebSocket连接测试成功');
  237. marketDataManager.stop();
  238. });
  239. marketDataManager.on('error', (error) => {
  240. console.log('❌ WebSocket连接测试失败:', error.message);
  241. process.exit(1);
  242. });
  243. await marketDataManager.start();
  244. } else {
  245. console.log('使用方法:');
  246. console.log(' npx tsx examples/market-data-example.ts # 运行完整示例');
  247. console.log(' npx tsx examples/market-data-example.ts status # 显示状态');
  248. console.log(' npx tsx examples/market-data-example.ts test # 测试连接');
  249. }
  250. }
  251. // 运行主函数
  252. if (import.meta.url === `file://${process.argv[1]}`) {
  253. main().catch(console.error);
  254. }
  255. export { MarketDataManager, MarketDataManagerConfig };