UNPKG

tardis-dev

Version:

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

212 lines 7.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FTXBookTickerMapper = exports.FTXLiquidationsMapper = exports.FTXDerivativeTickerMapper = exports.FTXBookChangeMapper = exports.mapBookLevel = exports.FTXTradesMapper = void 0; const handy_1 = require("../handy"); const mapper_1 = require("./mapper"); // https://docs.ftx.com/#websocket-api class FTXTradesMapper { constructor(_exchange) { this._exchange = _exchange; } canHandle(message) { if (message.data == undefined) { return false; } return message.channel === 'trades'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: 'trades', symbols } ]; } *map(ftxTrades, localTimestamp) { for (const ftxTrade of ftxTrades.data) { const timestamp = new Date(ftxTrade.time); timestamp.μs = (0, handy_1.parseμs)(ftxTrade.time); yield { type: 'trade', symbol: ftxTrades.market, exchange: this._exchange, id: ftxTrade.id !== null ? String(ftxTrade.id) : undefined, price: ftxTrade.price, amount: ftxTrade.size, side: ftxTrade.side, timestamp, localTimestamp }; } } } exports.FTXTradesMapper = FTXTradesMapper; const mapBookLevel = (level) => { const price = level[0]; const amount = level[1]; return { price, amount }; }; exports.mapBookLevel = mapBookLevel; class FTXBookChangeMapper { constructor(_exchange) { this._exchange = _exchange; } canHandle(message) { if (message.data == undefined) { return false; } return message.channel === 'orderbook'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: 'orderbook', symbols } ]; } *map(ftxOrderBook, localTimestamp) { const isEmptyUpdate = ftxOrderBook.type === 'update' && ftxOrderBook.data.bids.length === 0 && ftxOrderBook.data.asks.length === 0; if (isEmptyUpdate) { return; } const timestamp = new Date(ftxOrderBook.data.time * 1000); timestamp.μs = Math.floor(ftxOrderBook.data.time * 1000000) % 1000; yield { type: 'book_change', symbol: ftxOrderBook.market, exchange: this._exchange, isSnapshot: ftxOrderBook.type === 'partial', bids: ftxOrderBook.data.bids.map(exports.mapBookLevel), asks: ftxOrderBook.data.asks.map(exports.mapBookLevel), timestamp, localTimestamp }; } } exports.FTXBookChangeMapper = FTXBookChangeMapper; class FTXDerivativeTickerMapper { constructor(_exchange) { this._exchange = _exchange; this.pendingTickerInfoHelper = new mapper_1.PendingTickerInfoHelper(); } canHandle(message) { if (message.data == undefined) { return false; } return message.channel === 'instrument'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: 'instrument', symbols: symbols !== undefined ? symbols.filter((s) => s.includes('/') === false) : undefined } ]; } *map(message, localTimestamp) { const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(message.market, this._exchange); const { stats, info } = message.data; const currentFundingTimestamp = pendingTickerInfo.getCurrentFundingTimestamp(); const updatedFundingTimestamp = stats.nextFundingTime !== undefined ? new Date(stats.nextFundingTime) : undefined; // due to how instrument info messages are sourced (from REST API) it can sometimes return data that is stale (cached perhaps by the API) // let's skip such messages const isStaleInfo = updatedFundingTimestamp !== undefined && currentFundingTimestamp !== undefined && currentFundingTimestamp.valueOf() > updatedFundingTimestamp.valueOf(); if (isStaleInfo) { return; } if (updatedFundingTimestamp !== undefined) { pendingTickerInfo.updateFundingTimestamp(updatedFundingTimestamp); pendingTickerInfo.updateFundingRate(stats.nextFundingRate); } pendingTickerInfo.updateIndexPrice(info.index); pendingTickerInfo.updateMarkPrice(info.mark); pendingTickerInfo.updateLastPrice(info.last); pendingTickerInfo.updateOpenInterest(stats.openInterest); pendingTickerInfo.updateTimestamp(localTimestamp); if (pendingTickerInfo.hasChanged()) { yield pendingTickerInfo.getSnapshot(localTimestamp); } } } exports.FTXDerivativeTickerMapper = FTXDerivativeTickerMapper; class FTXLiquidationsMapper { canHandle(message) { if (message.data == undefined) { return false; } return message.channel === 'trades'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: 'trades', symbols } ]; } *map(ftxTrades, localTimestamp) { for (const ftxTrade of ftxTrades.data) { if (ftxTrade.liquidation) { const timestamp = new Date(ftxTrade.time); timestamp.μs = (0, handy_1.parseμs)(ftxTrade.time); yield { type: 'liquidation', symbol: ftxTrades.market, exchange: 'ftx', id: ftxTrade.id !== null ? String(ftxTrade.id) : undefined, price: ftxTrade.price, amount: ftxTrade.size, side: ftxTrade.side, timestamp, localTimestamp }; } } } } exports.FTXLiquidationsMapper = FTXLiquidationsMapper; class FTXBookTickerMapper { constructor(_exchange) { this._exchange = _exchange; } canHandle(message) { if (message.data == undefined) { return false; } return message.channel === 'ticker'; } getFilters(symbols) { symbols = (0, handy_1.upperCaseSymbols)(symbols); return [ { channel: 'ticker', symbols } ]; } *map(ftxTicker, localTimestamp) { const timestamp = new Date(ftxTicker.data.time * 1000); timestamp.μs = Math.floor(ftxTicker.data.time * 1000000) % 1000; const ticker = { type: 'book_ticker', symbol: ftxTicker.market, exchange: this._exchange, askAmount: (0, handy_1.asNumberIfValid)(ftxTicker.data.askSize), askPrice: (0, handy_1.asNumberIfValid)(ftxTicker.data.ask), bidPrice: (0, handy_1.asNumberIfValid)(ftxTicker.data.bid), bidAmount: (0, handy_1.asNumberIfValid)(ftxTicker.data.bidSize), timestamp, localTimestamp: localTimestamp }; yield ticker; } } exports.FTXBookTickerMapper = FTXBookTickerMapper; //# sourceMappingURL=ftx.js.map