| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- 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<CacheConfig>
- 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<void> {
- 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<string, MarketData> {
- 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<string, Ticker24hr> {
- 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<string, number> {
- const prices = new Map<string, number>()
- 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)
- }
- }
|