UNPKG

tardis-dev

Version:

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

796 lines 32.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OkexBookTickerMapper = exports.OkexLiquidationsMapper = exports.OkexOptionSummaryMapper = exports.OkexDerivativeTickerMapper = exports.OkexBookChangeMapper = exports.OkexTradesMapper = exports.OkexV5OptionSummaryMapper = exports.OkexV5LiquidationsMapper = exports.OkexV5DerivativeTickerMapper = exports.OkexV5BookTickerMapper = exports.OkexV5BookChangeMapper = exports.OkexV5TradesMapper = void 0; const handy_1 = require("../handy"); const mapper_1 = require("./mapper"); // V5 Okex API mappers // https://www.okex.com/docs-v5/en/#websocket-api-public-channel-trades-channel class OkexV5TradesMapper { constructor(_exchange, _useTradesAll) { this._exchange = _exchange; this._useTradesAll = _useTradesAll; } canHandle(message) { if (message.event !== undefined || message.arg === undefined) { return false; } return message.arg.channel === 'trades' || message.arg.channel === 'trades-all'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); if (this._useTradesAll) { return [ { channel: `trades-all`, symbols } ]; } return [ { channel: `trades`, symbols } ]; } *map(okexTradesMessage, localTimestamp) { for (const okexTrade of okexTradesMessage.data) { yield { type: 'trade', symbol: okexTrade.instId, exchange: this._exchange, id: okexTrade.tradeId, price: Number(okexTrade.px), amount: Number(okexTrade.sz), side: okexTrade.side === 'buy' ? 'buy' : 'sell', timestamp: new Date(Number(okexTrade.ts)), localTimestamp: localTimestamp }; } } } exports.OkexV5TradesMapper = OkexV5TradesMapper; const mapV5BookLevel = (level) => { const price = Number(level[0]); const amount = Number(level[1]); return { price, amount }; }; class OkexV5BookChangeMapper { constructor(_exchange, usePublicBooksChannel) { this._exchange = _exchange; this._hasCredentials = process.env.OKX_API_KEY !== undefined; this._hasVip5Access = process.env.OKX_API_VIP_5 !== undefined; this._hasColoAccess = process.env.OKX_API_COLO !== undefined; this._channelName = this._getBooksChannelName(usePublicBooksChannel); } canHandle(message) { if (message.event !== undefined || message.arg === undefined) { return false; } return message.arg.channel === this._channelName; } _getBooksChannelName(usePublicBooksChannel) { if (usePublicBooksChannel === false) { // historical data always uses books-l2-tbt return 'books-l2-tbt'; } if (this._hasCredentials && this._hasVip5Access) { return 'books-l2-tbt'; } if (this._hasColoAccess) { return 'books-l2-tbt'; } if (this._hasCredentials) { return 'books50-l2-tbt'; } return 'books'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: this._channelName, symbols } ]; } *map(okexDepthDataMessage, localTimestamp) { for (const message of okexDepthDataMessage.data) { if (okexDepthDataMessage.action === 'update' && message.bids.length === 0 && message.asks.length === 0) { continue; } const timestamp = new Date(Number(message.ts)); if (timestamp.valueOf() === 0) { continue; } yield { type: 'book_change', symbol: okexDepthDataMessage.arg.instId, exchange: this._exchange, isSnapshot: okexDepthDataMessage.action === 'snapshot', bids: message.bids.map(mapV5BookLevel), asks: message.asks.map(mapV5BookLevel), timestamp, localTimestamp: localTimestamp }; } } } exports.OkexV5BookChangeMapper = OkexV5BookChangeMapper; class OkexV5BookTickerMapper { constructor(_exchange, _useTbtTickerChannel) { this._exchange = _exchange; this._useTbtTickerChannel = _useTbtTickerChannel; } canHandle(message) { if (message.event !== undefined || message.arg === undefined) { return false; } if (this._useTbtTickerChannel) { return message.arg.channel === 'bbo-tbt'; } return message.arg.channel === 'tickers'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); if (this._useTbtTickerChannel) { return [ { channel: `bbo-tbt`, symbols } ]; } return [ { channel: `tickers`, symbols } ]; } map(message, localTimestamp) { if (message.arg.channel === 'bbo-tbt') { return this._mapFromTbtTicker(message, localTimestamp); } else { return this._mapFromTicker(message, localTimestamp); } } *_mapFromTbtTicker(message, localTimestamp) { if (!message.data) { return; } for (const tbtTicker of message.data) { const bestAsk = tbtTicker.asks !== undefined && tbtTicker.asks[0] ? mapBookLevel(tbtTicker.asks[0]) : undefined; const bestBid = tbtTicker.bids !== undefined && tbtTicker.bids[0] ? mapBookLevel(tbtTicker.bids[0]) : undefined; const ticker = { type: 'book_ticker', symbol: message.arg.instId, exchange: this._exchange, askAmount: bestAsk === null || bestAsk === void 0 ? void 0 : bestAsk.amount, askPrice: bestAsk === null || bestAsk === void 0 ? void 0 : bestAsk.price, bidPrice: bestBid === null || bestBid === void 0 ? void 0 : bestBid.price, bidAmount: bestBid === null || bestBid === void 0 ? void 0 : bestBid.amount, timestamp: new Date(Number(tbtTicker.ts)), localTimestamp: localTimestamp }; yield ticker; } } *_mapFromTicker(message, localTimestamp) { for (const okexTicker of message.data) { const ticker = { type: 'book_ticker', symbol: okexTicker.instId, exchange: this._exchange, askAmount: (0, handy_1.asNumberIfValid)(okexTicker.askSz), askPrice: (0, handy_1.asNumberIfValid)(okexTicker.askPx), bidPrice: (0, handy_1.asNumberIfValid)(okexTicker.bidPx), bidAmount: (0, handy_1.asNumberIfValid)(okexTicker.bidSz), timestamp: new Date(Number(okexTicker.ts)), localTimestamp: localTimestamp }; yield ticker; } } } exports.OkexV5BookTickerMapper = OkexV5BookTickerMapper; class OkexV5DerivativeTickerMapper { constructor(_exchange) { this._exchange = _exchange; this.pendingTickerInfoHelper = new mapper_1.PendingTickerInfoHelper(); this._indexPrices = new Map(); this._futuresChannels = ['tickers', 'open-interest', 'mark-price', 'index-tickers']; this._swapChannels = ['tickers', 'open-interest', 'mark-price', 'index-tickers', 'funding-rate']; } canHandle(message) { const channels = this._exchange === 'okex-futures' ? this._futuresChannels : this._swapChannels; if (message.event !== undefined || message.arg === undefined) { return false; } return channels.includes(message.arg.channel); } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); const channels = this._exchange === 'okex-futures' ? this._futuresChannels : this._swapChannels; return channels.map((channel) => { if (channel === 'index-tickers') { const indexes = symbols !== undefined ? symbols.map((s) => { const symbolParts = s.split('-'); const quotePart = symbolParts[1] === 'USDC' ? 'USD' : symbolParts[1]; return `${symbolParts[0]}-${quotePart}`; }) : undefined; return { channel, symbols: indexes }; } return { channel, symbols }; }); } *map(message, localTimestamp) { if (message.arg.channel === 'index-tickers') { for (const dataMessage of message.data) { const indexTickerMessage = dataMessage; const lastIndexPrice = Number(indexTickerMessage.idxPx); if (lastIndexPrice > 0) { this._indexPrices.set(indexTickerMessage.instId, lastIndexPrice); } } return; } for (const dataMessage of message.data) { const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(dataMessage.instId, this._exchange); const symbolParts = dataMessage.instId.split('-'); const quotePart = symbolParts[1] === 'USDC' ? 'USD' : symbolParts[1]; const indexSymbol = `${symbolParts[0]}-${quotePart}`; const indexPrice = this._indexPrices.get(indexSymbol); if (indexPrice !== undefined) { pendingTickerInfo.updateIndexPrice(indexPrice); } if (message.arg.channel === 'mark-price') { const markPriceMessage = dataMessage; const markPrice = Number(markPriceMessage.markPx); if (markPrice > 0) { pendingTickerInfo.updateMarkPrice(markPrice); pendingTickerInfo.updateTimestamp(new Date(Number(markPriceMessage.ts))); } } if (message.arg.channel === 'open-interest') { const openInterestMessage = dataMessage; const openInterest = Number(openInterestMessage.oi); if (openInterest > 0) { pendingTickerInfo.updateOpenInterest(openInterest); pendingTickerInfo.updateTimestamp(new Date(Number(openInterestMessage.ts))); } } if (message.arg.channel === 'funding-rate') { const fundingRateMessage = dataMessage; if (fundingRateMessage.fundingRate !== undefined) { pendingTickerInfo.updateFundingRate(Number(fundingRateMessage.fundingRate)); } if (fundingRateMessage.fundingTime !== undefined) { pendingTickerInfo.updateFundingTimestamp(new Date(Number(fundingRateMessage.fundingTime))); } if (fundingRateMessage.nextFundingRate !== undefined && fundingRateMessage.nextFundingRate !== '') { pendingTickerInfo.updatePredictedFundingRate(Number(fundingRateMessage.nextFundingRate)); } } if (message.arg.channel === 'tickers') { const tickerMessage = dataMessage; const lastPrice = Number(tickerMessage.last); if (lastPrice > 0) { pendingTickerInfo.updateLastPrice(lastPrice); pendingTickerInfo.updateTimestamp(new Date(Number(tickerMessage.ts))); } } if (pendingTickerInfo.hasChanged()) { yield pendingTickerInfo.getSnapshot(localTimestamp); } } } } exports.OkexV5DerivativeTickerMapper = OkexV5DerivativeTickerMapper; class OkexV5LiquidationsMapper { constructor(_exchange) { this._exchange = _exchange; this._isFirstMessage = true; } canHandle(message) { if (message.event !== undefined || message.arg === undefined) { return false; } return message.arg.channel === 'liquidations' || message.arg.channel === 'liquidation-orders'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: 'liquidations', symbols }, { channel: 'liquidation-orders', symbols } ]; } *map(okexLiquidationMessage, localTimestamp) { if (okexLiquidationMessage.arg.channel === 'liquidation-orders') { if (this._isFirstMessage) { this._isFirstMessage = false; return; } for (const okexLiquidation of okexLiquidationMessage.data) { for (const detail of okexLiquidation.details) { const liquidation = { type: 'liquidation', symbol: okexLiquidation.instId, exchange: this._exchange, id: undefined, price: Number(detail.bkPx), amount: Number(detail.sz), side: detail.side === 'buy' ? 'buy' : 'sell', timestamp: new Date(Number(detail.ts)), localTimestamp: localTimestamp }; yield liquidation; } } } else { for (const okexLiquidation of okexLiquidationMessage.data) { const liquidation = { type: 'liquidation', symbol: okexLiquidationMessage.arg.instId, exchange: this._exchange, id: undefined, price: Number(okexLiquidation.bkPx), amount: Number(okexLiquidation.sz), side: okexLiquidation.side === 'buy' ? 'buy' : 'sell', timestamp: new Date(Number(okexLiquidation.ts)), localTimestamp: localTimestamp }; yield liquidation; } } } } exports.OkexV5LiquidationsMapper = OkexV5LiquidationsMapper; class OkexV5OptionSummaryMapper { constructor() { this._indexPrices = new Map(); this._openInterests = new Map(); this._markPrices = new Map(); this._tickers = new Map(); this.expiration_regex = /(\d{2})(\d{2})(\d{2})/; } canHandle(message) { if (message.event !== undefined || message.arg === undefined) { return false; } return (message.arg.channel === 'opt-summary' || message.arg.channel === 'index-tickers' || message.arg.channel === 'tickers' || message.arg.channel === 'open-interest' || message.arg.channel === 'mark-price'); } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); const indexes = symbols !== undefined ? symbols.map((s) => { const symbolParts = s.split('-'); return `${symbolParts[0]}-${symbolParts[1]}`; }) : undefined; return [ { channel: `opt-summary`, symbols: [] }, { channel: `index-tickers`, symbols: indexes }, { channel: `tickers`, symbols: symbols }, { channel: `open-interest`, symbols: symbols }, { channel: `mark-price`, symbols: symbols } ]; } *map(message, localTimestamp) { if (message.arg.channel === 'index-tickers') { for (const dataMessage of message.data) { const indexTickerMessage = dataMessage; const lastIndexPrice = (0, handy_1.asNumberIfValid)(indexTickerMessage.idxPx); if (lastIndexPrice !== undefined) { this._indexPrices.set(indexTickerMessage.instId, lastIndexPrice); } } return; } if (message.arg.channel === 'open-interest') { for (const dataMessage of message.data) { const openInterestMessage = dataMessage; const openInterestValue = (0, handy_1.asNumberIfValid)(openInterestMessage.oi); if (openInterestValue !== undefined) { this._openInterests.set(openInterestMessage.instId, openInterestValue); } } return; } if (message.arg.channel === 'mark-price') { for (const dataMessage of message.data) { const markPriceMessage = dataMessage; const markPrice = (0, handy_1.asNumberIfValid)(markPriceMessage.markPx); if (markPrice !== undefined) { this._markPrices.set(markPriceMessage.instId, markPrice); } } return; } if (message.arg.channel === 'tickers') { for (const dataMessage of message.data) { const tickerMessage = dataMessage; this._tickers.set(tickerMessage.instId, tickerMessage); } return; } if (message.arg.channel === 'opt-summary') { for (const dataMessage of message.data) { const summary = dataMessage; const symbolParts = summary.instId.split('-'); const isPut = symbolParts[4] === 'P'; const strikePrice = Number(symbolParts[3]); var dateArray = this.expiration_regex.exec(symbolParts[2]); const expirationDate = new Date(Date.UTC(+('20' + dateArray[1]), +dateArray[2] - 1, +dateArray[3], 8, 0, 0, 0)); const lastUnderlyingPrice = this._indexPrices.get(summary.uly); const lastOpenInterest = this._openInterests.get(summary.instId); const lastMarkPrice = this._markPrices.get(summary.instId); const lastTickerInfo = this._tickers.get(summary.instId); const optionSummary = { type: 'option_summary', symbol: summary.instId, exchange: 'okex-options', optionType: isPut ? 'put' : 'call', strikePrice, expirationDate, bestBidPrice: lastTickerInfo !== undefined ? (0, handy_1.asNumberIfValid)(lastTickerInfo.bidPx) : undefined, bestBidAmount: lastTickerInfo !== undefined ? (0, handy_1.asNumberIfValid)(lastTickerInfo.bidSz) : undefined, bestBidIV: (0, handy_1.asNumberIfValid)(summary.bidVol), bestAskPrice: lastTickerInfo !== undefined ? (0, handy_1.asNumberIfValid)(lastTickerInfo.askPx) : undefined, bestAskAmount: lastTickerInfo !== undefined ? (0, handy_1.asNumberIfValid)(lastTickerInfo.askSz) : undefined, bestAskIV: (0, handy_1.asNumberIfValid)(summary.askVol), lastPrice: lastTickerInfo !== undefined ? (0, handy_1.asNumberIfValid)(lastTickerInfo.last) : undefined, openInterest: lastOpenInterest, markPrice: lastMarkPrice, markIV: (0, handy_1.asNumberIfValid)(summary.markVol), delta: (0, handy_1.asNumberIfValid)(summary.delta), gamma: (0, handy_1.asNumberIfValid)(summary.gamma), vega: (0, handy_1.asNumberIfValid)(summary.vega), theta: (0, handy_1.asNumberIfValid)(summary.theta), rho: undefined, underlyingPrice: lastUnderlyingPrice, underlyingIndex: summary.uly, timestamp: new Date(Number(summary.ts)), localTimestamp: localTimestamp }; yield optionSummary; } } } } exports.OkexV5OptionSummaryMapper = OkexV5OptionSummaryMapper; //--- //V3 Okex API mappers // https://www.okex.com/docs/en/#ws_swap-README class OkexTradesMapper { constructor(_exchange, _market) { this._exchange = _exchange; this._market = _market; } canHandle(message) { return message.table === `${this._market}/trade`; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: `${this._market}/trade`, symbols } ]; } *map(okexTradesMessage, localTimestamp) { for (const okexTrade of okexTradesMessage.data) { const symbol = okexTrade.instrument_id; yield { type: 'trade', symbol, exchange: this._exchange, id: typeof okexTrade.trade_id === 'string' ? okexTrade.trade_id : undefined, price: Number(okexTrade.price), amount: okexTrade.qty !== undefined ? Number(okexTrade.qty) : Number(okexTrade.size), side: okexTrade.side, timestamp: new Date(okexTrade.timestamp), localTimestamp: localTimestamp }; } } } exports.OkexTradesMapper = OkexTradesMapper; const mapBookLevel = (level) => { const price = Number(level[0]); const amount = Number(level[1]); return { price, amount }; }; class OkexBookChangeMapper { constructor(_exchange, _market, _canUseTickByTickChannel) { this._exchange = _exchange; this._market = _market; this._canUseTickByTickChannel = _canUseTickByTickChannel; } canHandle(message) { const channelSuffix = this._canUseTickByTickChannel ? 'depth_l2_tbt' : 'depth'; return message.table === `${this._market}/${channelSuffix}`; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); if (this._canUseTickByTickChannel) { return [ { channel: `${this._market}/depth_l2_tbt`, symbols } ]; } // subscribe to both book channels and in canHandle decide which one to use // as one can subscribe to date range period that overlaps both when only depth channel has been available // and when both were available (both depth and depth_l2_tbt) return [ { channel: `${this._market}/depth_l2_tbt`, symbols }, { channel: `${this._market}/depth`, symbols } ]; } *map(okexDepthDataMessage, localTimestamp) { for (const message of okexDepthDataMessage.data) { if (message.bids.length === 0 && message.asks.length === 0 && okexDepthDataMessage.action !== 'partial') { continue; } const timestamp = new Date(message.timestamp); if (timestamp.valueOf() === 0) { continue; } yield { type: 'book_change', symbol: message.instrument_id, exchange: this._exchange, isSnapshot: okexDepthDataMessage.action === 'partial', bids: message.bids.map(mapBookLevel), asks: message.asks.map(mapBookLevel), timestamp, localTimestamp: localTimestamp }; } } } exports.OkexBookChangeMapper = OkexBookChangeMapper; class OkexDerivativeTickerMapper { constructor(_exchange) { this._exchange = _exchange; this.pendingTickerInfoHelper = new mapper_1.PendingTickerInfoHelper(); this._futuresChannels = ['futures/ticker', 'futures/mark_price']; this._swapChannels = ['swap/ticker', 'swap/mark_price', 'swap/funding_rate']; } canHandle(message) { const channels = this._exchange === 'okex-futures' ? this._futuresChannels : this._swapChannels; return channels.includes(message.table); } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); const channels = this._exchange === 'okex-futures' ? this._futuresChannels : this._swapChannels; return channels.map((channel) => { return { channel, symbols }; }); } *map(message, localTimestamp) { for (const okexMessage of message.data) { const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(okexMessage.instrument_id, this._exchange); if ('funding_rate' in okexMessage) { pendingTickerInfo.updateFundingRate(Number(okexMessage.funding_rate)); pendingTickerInfo.updateFundingTimestamp(new Date(okexMessage.funding_time)); if (okexMessage.estimated_rate !== undefined) { pendingTickerInfo.updatePredictedFundingRate(Number(okexMessage.estimated_rate)); } } if ('mark_price' in okexMessage) { pendingTickerInfo.updateMarkPrice(Number(okexMessage.mark_price)); } if ('open_interest' in okexMessage) { const openInterest = Number(okexMessage.open_interest); if (openInterest > 0) { pendingTickerInfo.updateOpenInterest(Number(okexMessage.open_interest)); } } if ('last' in okexMessage) { pendingTickerInfo.updateLastPrice(Number(okexMessage.last)); } if (okexMessage.timestamp !== undefined) { pendingTickerInfo.updateTimestamp(new Date(okexMessage.timestamp)); } if (pendingTickerInfo.hasChanged()) { yield pendingTickerInfo.getSnapshot(localTimestamp); } } } } exports.OkexDerivativeTickerMapper = OkexDerivativeTickerMapper; class OkexOptionSummaryMapper { constructor() { this._indexPrices = new Map(); this.expiration_regex = /(\d{2})(\d{2})(\d{2})/; } canHandle(message) { return message.table === 'index/ticker' || message.table === 'option/summary'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); const indexes = symbols !== undefined ? symbols.map((s) => { const symbolParts = s.split('-'); return `${symbolParts[0]}-${symbolParts[1]}`; }) : undefined; return [ { channel: `option/summary`, symbols }, { channel: `index/ticker`, symbols: indexes } ]; } *map(message, localTimestamp) { if (message.table === 'index/ticker') { for (const index of message.data) { const lastIndexPrice = Number(index.last); if (lastIndexPrice > 0) { this._indexPrices.set(index.instrument_id, lastIndexPrice); } } return; } for (const summary of message.data) { const symbolParts = summary.instrument_id.split('-'); const isPut = symbolParts[4] === 'P'; const strikePrice = Number(symbolParts[3]); var dateArray = this.expiration_regex.exec(symbolParts[2]); const expirationDate = new Date(Date.UTC(+('20' + dateArray[1]), +dateArray[2] - 1, +dateArray[3], 8, 0, 0, 0)); const lastUnderlyingPrice = this._indexPrices.get(summary.underlying); const optionSummary = { type: 'option_summary', symbol: summary.instrument_id, exchange: 'okex-options', optionType: isPut ? 'put' : 'call', strikePrice, expirationDate, bestBidPrice: (0, handy_1.asNumberIfValid)(summary.best_bid), bestBidAmount: (0, handy_1.asNumberIfValid)(summary.best_bid_size), bestBidIV: (0, handy_1.asNumberIfValid)(summary.bid_vol), bestAskPrice: (0, handy_1.asNumberIfValid)(summary.best_ask), bestAskAmount: (0, handy_1.asNumberIfValid)(summary.best_ask_size), bestAskIV: (0, handy_1.asNumberIfValid)(summary.ask_vol), lastPrice: (0, handy_1.asNumberIfValid)(summary.last), openInterest: (0, handy_1.asNumberIfValid)(summary.open_interest), markPrice: (0, handy_1.asNumberIfValid)(summary.mark_price), markIV: (0, handy_1.asNumberIfValid)(summary.mark_vol), delta: (0, handy_1.asNumberIfValid)(summary.delta), gamma: (0, handy_1.asNumberIfValid)(summary.gamma), vega: (0, handy_1.asNumberIfValid)(summary.vega), theta: (0, handy_1.asNumberIfValid)(summary.theta), rho: undefined, underlyingPrice: lastUnderlyingPrice, underlyingIndex: summary.underlying, timestamp: new Date(summary.timestamp), localTimestamp: localTimestamp }; yield optionSummary; } } } exports.OkexOptionSummaryMapper = OkexOptionSummaryMapper; class OkexLiquidationsMapper { constructor(_exchange, _market) { this._exchange = _exchange; this._market = _market; } canHandle(message) { return message.table === `${this._market}/liquidation`; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: `${this._market}/liquidation`, symbols } ]; } *map(okexLiquidationDataMessage, localTimestamp) { for (const okexLiquidation of okexLiquidationDataMessage.data) { const liquidation = { type: 'liquidation', symbol: okexLiquidation.instrument_id, exchange: this._exchange, id: undefined, price: Number(okexLiquidation.price), amount: Number(okexLiquidation.size), side: okexLiquidation.type === '3' ? 'sell' : 'buy', timestamp: new Date(okexLiquidation.created_at), localTimestamp: localTimestamp }; yield liquidation; } } } exports.OkexLiquidationsMapper = OkexLiquidationsMapper; class OkexBookTickerMapper { constructor(_exchange, _market) { this._exchange = _exchange; this._market = _market; } canHandle(message) { return message.table === `${this._market}/ticker`; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: `${this._market}/ticker`, symbols } ]; } *map(message, localTimestamp) { for (const okexTicker of message.data) { const ticker = { type: 'book_ticker', symbol: okexTicker.instrument_id, exchange: this._exchange, askAmount: (0, handy_1.asNumberIfValid)(okexTicker.best_ask_size), askPrice: (0, handy_1.asNumberIfValid)(okexTicker.best_ask), bidPrice: (0, handy_1.asNumberIfValid)(okexTicker.best_bid), bidAmount: (0, handy_1.asNumberIfValid)(okexTicker.best_bid_size), timestamp: new Date(okexTicker.timestamp), localTimestamp: localTimestamp }; yield ticker; } } } exports.OkexBookTickerMapper = OkexBookTickerMapper; //# sourceMappingURL=okex.js.map