UNPKG

tardis-dev

Version:

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

218 lines 8.66 kB
import { asNonZeroNumberOrUndefined, asNumberOrUndefined } from "../handy.js"; import { PendingTickerInfoHelper } from "./mapper.js"; export class BullishTradesMapper { canHandle(message) { return message.dataType === 'V1TAAnonymousTradeUpdate' && message.type === 'update'; } getFilters(symbols) { return [ { channel: 'V1TAAnonymousTradeUpdate', symbols } ]; } *map(message, localTimestamp) { for (const trade of message.data.trades) { yield { type: 'trade', symbol: trade.symbol, exchange: 'bullish', id: trade.tradeId, price: Number(trade.price), amount: Number(trade.quantity), side: this.mapBullishTradeSide(trade.side, trade.isTaker), timestamp: new Date(trade.createdAtDatetime), localTimestamp }; } } mapBullishTradeSide(side, isTaker) { if (isTaker) { // Bullish side already represents the taker/aggressor side. return side === 'BUY' ? 'buy' : 'sell'; } // Bullish side represents the maker/resting order, so the taker was on the opposite side. return side === 'BUY' ? 'sell' : 'buy'; } } export class BullishBookChangeMapper { canHandle(message) { return message.dataType === 'V1TALevel2'; } getFilters(symbols) { return [ { channel: 'V1TALevel2', symbols } ]; } *map(message, localTimestamp) { yield { type: 'book_change', symbol: message.data.symbol, exchange: 'bullish', isSnapshot: message.type === 'snapshot', bids: this.mapLevels(message.data.bids), asks: this.mapLevels(message.data.asks), timestamp: new Date(message.data.datetime), localTimestamp }; } mapLevels(levels) { const result = new Array(levels.length / 2); for (let index = 0, resultIndex = 0; index < levels.length; index += 2, resultIndex++) { result[resultIndex] = { price: Number(levels[index]), amount: Number(levels[index + 1]) }; } return result; } } export class BullishBookTickerMapper { canHandle(message) { return message.dataType === 'V1TALevel1' && (message.type === 'snapshot' || message.type === 'update'); } getFilters(symbols) { return [ { channel: 'V1TALevel1', symbols } ]; } *map(message, localTimestamp) { yield { type: 'book_ticker', symbol: message.data.symbol, exchange: 'bullish', bidPrice: asNonZeroNumberOrUndefined(message.data.bid[0]), bidAmount: asNonZeroNumberOrUndefined(message.data.bid[1]), askPrice: asNonZeroNumberOrUndefined(message.data.ask[0]), askAmount: asNonZeroNumberOrUndefined(message.data.ask[1]), timestamp: new Date(message.data.datetime), localTimestamp }; } } export class BullishDerivativeTickerMapper { pendingTickerInfoHelper = new PendingTickerInfoHelper(); indexPrices = new Map(); canHandle(message) { if (message.dataType === 'V1TAIndexPrice' && (message.type === 'snapshot' || message.type === 'update')) { return true; } if (message.dataType === 'V1TATickerResponse' && (message.type === 'snapshot' || message.type === 'update')) { const tickerMessage = message; return tickerMessage.data.symbol.endsWith('-PERP') || /-\d{8}$/.test(tickerMessage.data.symbol); } return false; } getFilters(symbols) { return [ { channel: 'V1TATickerResponse', symbols }, { channel: 'V1TAIndexPrice', symbols: symbols === undefined ? undefined : [...new Set(symbols.map((symbol) => symbol.split('-')[0]))] } ]; } *map(message, localTimestamp) { if (message.dataType === 'V1TAIndexPrice') { const price = asNonZeroNumberOrUndefined(message.data.price); if (price !== undefined) { this.indexPrices.set(message.data.assetSymbol, { price, timestamp: new Date(message.data.updatedAtDatetime) }); } return; } const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(message.data.symbol, 'bullish'); const indexAsset = message.data.symbol.split('-')[0]; const indexPrice = this.indexPrices.get(indexAsset); pendingTickerInfo.updateLastPrice(asNonZeroNumberOrUndefined(message.data.last)); pendingTickerInfo.updateMarkPrice(asNonZeroNumberOrUndefined(message.data.markPrice)); pendingTickerInfo.updateFundingRate(asNumberOrUndefined(message.data.fundingRate)); pendingTickerInfo.updateOpenInterest(asNumberOrUndefined(message.data.openInterest)); pendingTickerInfo.updateIndexPrice(indexPrice?.price); if (pendingTickerInfo.hasChanged()) { pendingTickerInfo.updateTimestamp(new Date(message.data.createdAtDatetime)); yield pendingTickerInfo.getSnapshot(localTimestamp); } } } export class BullishOptionSummaryMapper { indexPrices = new Map(); canHandle(message) { if (message.dataType === 'V1TAIndexPrice' && (message.type === 'snapshot' || message.type === 'update')) { return true; } if (message.dataType === 'V1TATickerResponse' && (message.type === 'snapshot' || message.type === 'update')) { const tickerMessage = message; return tickerMessage.data.symbol.endsWith('-C') || tickerMessage.data.symbol.endsWith('-P'); } return false; } getFilters(symbols) { return [ { channel: 'V1TATickerResponse', symbols }, { channel: 'V1TAIndexPrice', symbols: symbols === undefined ? undefined : [...new Set(symbols.map((symbol) => symbol.split('-')[0]))] } ]; } *map(message, localTimestamp) { if (message.dataType === 'V1TAIndexPrice') { const price = asNonZeroNumberOrUndefined(message.data.price); if (price !== undefined) { this.indexPrices.set(message.data.assetSymbol, { price, timestamp: new Date(message.data.updatedAtDatetime) }); } return; } const [indexAsset, , dateText, strikePriceText, optionType] = message.data.symbol.split('-'); const indexPrice = this.indexPrices.get(indexAsset); const expirationDate = new Date(`${dateText.slice(0, 4)}-${dateText.slice(4, 6)}-${dateText.slice(6, 8)}Z`); expirationDate.setUTCHours(8); yield { type: 'option_summary', symbol: message.data.symbol, exchange: 'bullish', optionType: optionType === 'P' ? 'put' : 'call', strikePrice: Number(strikePriceText), expirationDate, bestBidPrice: asNonZeroNumberOrUndefined(message.data.bestBid), bestBidAmount: asNonZeroNumberOrUndefined(message.data.bidVolume), bestBidIV: undefined, bestAskPrice: asNonZeroNumberOrUndefined(message.data.bestAsk), bestAskAmount: asNonZeroNumberOrUndefined(message.data.askVolume), bestAskIV: undefined, lastPrice: asNonZeroNumberOrUndefined(message.data.last), openInterest: asNumberOrUndefined(message.data.openInterest), markPrice: asNumberOrUndefined(message.data.markPrice), markIV: asNonZeroNumberOrUndefined(message.data.impliedVolatility), delta: asNumberOrUndefined(message.data.delta), gamma: asNumberOrUndefined(message.data.gamma), vega: asNumberOrUndefined(message.data.vega), theta: asNumberOrUndefined(message.data.theta), rho: undefined, underlyingPrice: indexPrice?.price, underlyingIndex: indexAsset, timestamp: new Date(message.data.createdAtDatetime), localTimestamp }; } } //# sourceMappingURL=bullish.js.map