UNPKG

tardis-dev

Version:

Convenient access to tick-level historical and real-time cryptocurrency market data via Node.js

95 lines 5.34 kB
import { onlyUnique } from "../handy.js"; import { MultiConnectionRealTimeFeedBase, RealTimeFeedBase } from "./realtimefeed.js"; export class BinanceEuropeanOptionsRealTimeFeed extends MultiConnectionRealTimeFeedBase { *_getRealTimeFeeds(exchange, filters, timeoutIntervalMS, onError) { // V2 API uses two separate WebSocket endpoints: // 1. Public path: for optionTrade, depth20, bookTicker, optionTicker // 2. Market path: for optionIndexPrice, optionMarkPrice, optionOpenInterest const publicChannels = ['optionTrade', 'depth20', 'bookTicker', 'optionTicker']; const marketChannels = ['optionIndexPrice', 'optionMarkPrice', 'optionOpenInterest']; const publicFilters = filters.filter((f) => publicChannels.includes(f.channel)); const marketFilters = filters.filter((f) => marketChannels.includes(f.channel)); if (publicFilters.length > 0) { yield new BinanceEuropeanOptionsSingleFeed('wss://fstream.binance.com/public/stream', exchange, publicFilters, filters, // Pass all filters so we can look up optionTicker when processing optionOpenInterest timeoutIntervalMS, onError); } if (marketFilters.length > 0) { yield new BinanceEuropeanOptionsSingleFeed('wss://fstream.binance.com/market/stream', exchange, marketFilters, filters, // Pass all filters so we can look up optionTicker when processing optionOpenInterest timeoutIntervalMS, onError); } } } class BinanceEuropeanOptionsSingleFeed extends RealTimeFeedBase { wssURL; _allFilters; constructor(wssURL, exchange, filters, _allFilters, timeoutIntervalMS, onError) { super(exchange, filters, timeoutIntervalMS, onError); this.wssURL = wssURL; this._allFilters = _allFilters; } mapToSubscribeMessages(filters) { const payload = filters.map((filter, index) => { if (!filter.symbols || filter.symbols.length === 0) { throw new Error('BinanceEuropeanOptionsRealTimeFeed requires explicitly specified symbols when subscribing to live feed'); } return { method: 'SUBSCRIBE', params: filter.symbols .map((symbol) => { const lowerSymbol = symbol.toLowerCase(); // Public path channels - use lowercase symbol directly if (filter.channel === 'optionTrade') { return [`${lowerSymbol}@${filter.channel}`]; } if (filter.channel === 'depth20') { return [`${lowerSymbol}@${filter.channel}@100ms`]; } if (filter.channel === 'bookTicker') { return [`${lowerSymbol}@${filter.channel}`]; } if (filter.channel === 'optionTicker') { return [`${lowerSymbol}@${filter.channel}`]; } // Market path channels - use lowercase underlying if (filter.channel === 'optionIndexPrice' || filter.channel === 'optionMarkPrice') { // Symbol is the underlying (e.g., 'btcusdt') return [`${lowerSymbol}@${filter.channel}`]; } if (filter.channel === 'optionOpenInterest') { // Need to extract expirations from option symbols // The symbol here is the underlying (e.g., 'btcusdt') // We need to find all option symbols that match this underlying to extract expirations // Look for optionTicker filter in all filters to get actual option symbols const optionTickerFilter = this._allFilters.find((f) => f.channel === 'optionTicker'); if (optionTickerFilter !== undefined) { // Extract expirations from option symbols that match this underlying const underlyingBase = lowerSymbol.replace('usdt', '').toUpperCase(); const expirations = optionTickerFilter .symbols.filter((s) => s.toUpperCase().startsWith(underlyingBase + '-')) .map((s) => { const symbolParts = s.split('-'); return symbolParts[1]; // Extract expiration (e.g., '251219') }) .filter(onlyUnique) .map((exp) => exp.toLowerCase()); return expirations.map((expiration) => { return `${lowerSymbol}@${filter.channel}@${expiration}`; }); } } return [`${lowerSymbol}@${filter.channel}`]; }) .flatMap((s) => s), id: index + 1 }; }); return payload; } messageIsError(message) { if (message.data !== undefined && message.data.e === 'error') { return true; } return false; } } //# sourceMappingURL=binanceeuropeanoptions.js.map