import { MarketDataManager, MarketData, Ticker24hr, KlineData, DepthData } from './marketDataManager' import { MarketDataCache, CacheConfig } from './marketDataCache' import { EventEmitter } from 'events' /** * 增强行情管理器配置 */ export interface EnhancedMarketManagerConfig { wsUrl?: string reconnectInterval?: number maxReconnectAttempts?: number cacheConfig?: Partial enableCache?: boolean enableAutoReconnect?: boolean enablePingPong?: boolean } /** * 增强的行情管理器 * 整合 WebSocket 连接和缓存管理功能 */ export class EnhancedMarketManager extends EventEmitter { private marketDataManager: MarketDataManager private marketDataCache: MarketDataCache private config: EnhancedMarketManagerConfig private isInitialized: boolean = false constructor(config: EnhancedMarketManagerConfig = {}) { super() this.config = { wsUrl: 'wss://fstream.binance.com/ws', reconnectInterval: 5000, maxReconnectAttempts: 10, enableCache: true, enableAutoReconnect: true, enablePingPong: true, ...config, } // 初始化行情数据管理器 this.marketDataManager = new MarketDataManager( this.config.wsUrl, this.config.reconnectInterval, this.config.maxReconnectAttempts, ) // 初始化缓存管理器 this.marketDataCache = new MarketDataCache(this.config.cacheConfig) // 绑定事件 this.bindEvents() } /** * 初始化连接 */ public async initialize(): Promise { if (this.isInitialized) { return } try { await this.marketDataManager.connect() this.isInitialized = true console.log('✅ 增强行情管理器初始化成功') } catch (error) { console.error('❌ 增强行情管理器初始化失败:', error) throw error } } /** * 订阅行情数据 * @param symbols 交易对列表 * @param intervals K线间隔列表 */ public subscribeMarketData(symbols: string[], intervals: string[] = []): void { if (!this.isInitialized) { throw new Error('请先调用 initialize() 方法初始化连接') } this.marketDataManager.subscribeMarketData(symbols, intervals) } /** * 取消订阅 * @param symbols 交易对列表 */ public unsubscribeMarketData(symbols: string[]): void { this.marketDataManager.unsubscribeMarketData(symbols) } /** * 获取行情数据(优先从缓存获取) */ public getMarketData(symbol: string): MarketData | null { if (this.config.enableCache) { return this.marketDataCache.getMarketData(symbol) } return this.marketDataManager.getMarketData(symbol) } /** * 获取所有行情数据 */ public getAllMarketData(): Map { if (this.config.enableCache) { return this.marketDataCache.getAllMarketData() } return this.marketDataManager.getAllMarketData() } /** * 获取24小时行情数据 */ public getTicker24hr(symbol: string): Ticker24hr | null { if (this.config.enableCache) { return this.marketDataCache.getTicker24hr(symbol) } return this.marketDataManager.getTicker24hr(symbol) } /** * 获取所有24小时行情数据 */ public getAllTicker24hr(): Map { if (this.config.enableCache) { return this.marketDataCache.getAllTicker24hr() } return this.marketDataManager.getAllTicker24hr() } /** * 获取K线数据 */ public getKlineData(symbol: string, interval: string, limit: number = 100): KlineData[] { if (this.config.enableCache) { return this.marketDataCache.getKlineData(symbol, interval, limit) } return this.marketDataManager.getKlineData(symbol, interval, limit) } /** * 获取深度数据 */ public getDepthData(symbol: string): DepthData | null { if (this.config.enableCache) { return this.marketDataCache.getDepthData(symbol) } return this.marketDataManager.getDepthData(symbol) } /** * 获取订阅的符号列表 */ public getSubscribedSymbols(): string[] { return this.marketDataManager.getSubscribedSymbols() } /** * 检查是否已连接 */ public isConnected(): boolean { return this.marketDataManager.isConnectedToWebSocket() } /** * 获取缓存统计信息 */ public getCacheStats() { if (!this.config.enableCache) { return null } return this.marketDataCache.getCacheStats() } /** * 获取指定交易对的所有数据 */ public getSymbolData(symbol: string) { if (this.config.enableCache) { return this.marketDataCache.getSymbolData(symbol) } return { marketData: this.marketDataManager.getMarketData(symbol), ticker24hr: this.marketDataManager.getTicker24hr(symbol), klineData: new Map(), // 需要从 manager 获取 depthData: this.marketDataManager.getDepthData(symbol), } } /** * 检查数据是否过期 */ public isDataExpired(symbol: string, type: 'market' | 'ticker' | 'kline' | 'depth', interval?: string): boolean { if (!this.config.enableCache) { return true // 没有缓存时认为数据已过期 } return this.marketDataCache.isDataExpired(symbol, type, interval) } /** * 获取数据更新时间 */ public getDataTimestamp( symbol: string, type: 'market' | 'ticker' | 'kline' | 'depth', interval?: string, ): number | null { if (!this.config.enableCache) { return null } return this.marketDataCache.getDataTimestamp(symbol, type, interval) } /** * 清理缓存 */ public cleanupCache(): void { if (this.config.enableCache) { this.marketDataCache.cleanup() } } /** * 清空缓存 */ public clearCache(): void { if (this.config.enableCache) { this.marketDataCache.clear() } } /** * 断开连接 */ public disconnect(): void { this.marketDataManager.disconnect() this.isInitialized = false } /** * 销毁管理器 */ public destroy(): void { this.disconnect() if (this.config.enableCache) { this.marketDataCache.destroy() } this.removeAllListeners() } /** * 绑定事件 */ private bindEvents(): void { // 连接事件 this.marketDataManager.on('connected', () => { this.emit('connected') }) this.marketDataManager.on('disconnected', (code: number, reason: string) => { this.emit('disconnected', code, reason) }) this.marketDataManager.on('error', (error: Error) => { this.emit('error', error) }) this.marketDataManager.on('maxReconnectAttemptsReached', () => { this.emit('maxReconnectAttemptsReached') }) // 数据事件 this.marketDataManager.on('marketData', (data: MarketData) => { if (this.config.enableCache) { this.marketDataCache.updateMarketData(data) } this.emit('marketData', data) }) this.marketDataManager.on('ticker24hr', (data: Ticker24hr) => { if (this.config.enableCache) { this.marketDataCache.updateTicker24hr(data) } this.emit('ticker24hr', data) }) this.marketDataManager.on('kline', (data: KlineData) => { if (this.config.enableCache) { this.marketDataCache.updateKlineData(data) } this.emit('kline', data) }) this.marketDataManager.on('depth', (data: DepthData) => { if (this.config.enableCache) { this.marketDataCache.updateDepthData(data) } this.emit('depth', data) }) } /** * 获取实时价格 */ public getCurrentPrice(symbol: string): number | null { const marketData = this.getMarketData(symbol) return marketData ? marketData.price : null } /** * 获取价格变化百分比 */ public getPriceChangePercent(symbol: string): number | null { const ticker = this.getTicker24hr(symbol) return ticker ? parseFloat(ticker.priceChangePercent) : null } /** * 获取24小时最高价 */ public get24hrHigh(symbol: string): number | null { const ticker = this.getTicker24hr(symbol) return ticker ? parseFloat(ticker.highPrice) : null } /** * 获取24小时最低价 */ public get24hrLow(symbol: string): number | null { const ticker = this.getTicker24hr(symbol) return ticker ? parseFloat(ticker.lowPrice) : null } /** * 获取24小时成交量 */ public get24hrVolume(symbol: string): number | null { const ticker = this.getTicker24hr(symbol) return ticker ? parseFloat(ticker.volume) : null } /** * 获取买卖价差 */ public getSpread(symbol: string): number | null { const marketData = this.getMarketData(symbol) if (!marketData) return null return marketData.ask - marketData.bid } /** * 获取买卖价差百分比 */ public getSpreadPercent(symbol: string): number | null { const marketData = this.getMarketData(symbol) if (!marketData) return null const spread = marketData.ask - marketData.bid return (spread / marketData.price) * 100 } /** * 检查价格是否上涨 */ public isPriceUp(symbol: string): boolean | null { const changePercent = this.getPriceChangePercent(symbol) return changePercent !== null ? changePercent > 0 : null } /** * 检查价格是否下跌 */ public isPriceDown(symbol: string): boolean | null { const changePercent = this.getPriceChangePercent(symbol) return changePercent !== null ? changePercent < 0 : null } /** * 获取所有活跃交易对的价格 */ public getAllPrices(): Map { const prices = new Map() const allMarketData = this.getAllMarketData() for (const [symbol, data] of allMarketData) { prices.set(symbol, data.price) } return prices } /** * 获取价格排序的交易对列表 */ public getSymbolsByPrice(sortOrder: 'asc' | 'desc' = 'desc'): string[] { const allMarketData = this.getAllMarketData() const symbols = Array.from(allMarketData.entries()) .sort(([, a], [, b]) => { return sortOrder === 'asc' ? a.price - b.price : b.price - a.price }) .map(([symbol]) => symbol) return symbols } /** * 获取价格变化排序的交易对列表 */ public getSymbolsByChange(sortOrder: 'asc' | 'desc' = 'desc'): string[] { const symbols: Array<{ symbol: string; change: number }> = [] for (const symbol of this.getSubscribedSymbols()) { const changePercent = this.getPriceChangePercent(symbol) if (changePercent !== null) { symbols.push({ symbol, change: changePercent }) } } return symbols .sort((a, b) => { return sortOrder === 'asc' ? a.change - b.change : b.change - a.change }) .map(item => item.symbol) } }