UNPKG

tardis-dev

Version:

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

201 lines (174 loc) 5.8 kB
import { upperCaseSymbols } from '../handy' import { BookChange, BookTicker, DerivativeTicker, Trade } from '../types' import { Mapper, PendingTickerInfoHelper } from './mapper' export class AscendexTradesMapper implements Mapper<'ascendex', Trade> { canHandle(message: AscendexTrade) { return message.m === 'trades' } getFilters(symbols?: string[]) { symbols = upperCaseSymbols(symbols) return [ { channel: 'trades', symbols } as const ] } *map(message: AscendexTrade, localTimestamp: Date): IterableIterator<Trade> { for (let trade of message.data) { yield { type: 'trade', symbol: message.symbol, exchange: 'ascendex', id: undefined, price: Number(trade.p), amount: Number(trade.q), side: trade.bm === true ? 'sell' : 'buy', timestamp: new Date(trade.ts), localTimestamp: localTimestamp } } } } export class AscendexBookChangeMapper implements Mapper<'ascendex', BookChange> { canHandle(message: AscendexDepthRealTime | AscendexDepthRealTimeSnapshot) { return message.m === 'depth-realtime' || message.m === 'depth-snapshot-realtime' } getFilters(symbols?: string[]) { symbols = upperCaseSymbols(symbols) return [ { channel: 'depth-realtime', symbols } as const, { channel: 'depth-snapshot-realtime', symbols } as const ] } *map(message: AscendexDepthRealTime | AscendexDepthRealTimeSnapshot, localTimestamp: Date): IterableIterator<BookChange> { if (!message.symbol || !message.data.bids || !message.data.asks) { return } yield { type: 'book_change', symbol: message.symbol, exchange: 'ascendex', isSnapshot: message.m === 'depth-snapshot-realtime', bids: message.data.bids.map(this.mapBookLevel), asks: message.data.asks.map(this.mapBookLevel), timestamp: message.data.ts > 0 ? new Date(message.data.ts) : localTimestamp, localTimestamp } } protected mapBookLevel(level: AscendexPriceLevel) { const price = Number(level[0]) const amount = Number(level[1]) return { price, amount } } } export class AscendexDerivativeTickerMapper implements Mapper<'ascendex', DerivativeTicker> { private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper() canHandle(message: AscendexFuturesData | AscendexTrade) { return message.m === 'futures-pricing-data' || message.m === 'trades' } getFilters(symbols?: string[]) { symbols = upperCaseSymbols(symbols) return [ { channel: 'futures-pricing-data', symbols: [] as string[] } as const, { channel: 'trades', symbols } as const ] } *map(message: AscendexFuturesData | AscendexTrade, localTimestamp: Date): IterableIterator<DerivativeTicker> { if (message.m === 'trades') { const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(message.symbol, 'ascendex') pendingTickerInfo.updateLastPrice(Number(message.data[message.data.length - 1].p)) return } for (const futuresData of message.con) { const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(futuresData.s, 'ascendex') pendingTickerInfo.updateIndexPrice(Number(futuresData.ip)) pendingTickerInfo.updateMarkPrice(Number(futuresData.mp)) pendingTickerInfo.updateOpenInterest(Number(futuresData.oi)) pendingTickerInfo.updateTimestamp(new Date(futuresData.t)) pendingTickerInfo.updateFundingTimestamp(new Date(futuresData.f)) pendingTickerInfo.updateFundingRate(Number(futuresData.r)) if (pendingTickerInfo.hasChanged()) { yield pendingTickerInfo.getSnapshot(localTimestamp) } } } } export class AscendexBookTickerMapper implements Mapper<'ascendex', BookTicker> { canHandle(message: AscendexTicker) { return message.m === 'bbo' } getFilters(symbols?: string[]) { symbols = upperCaseSymbols(symbols) return [ { channel: 'bbo', symbols } as const ] } *map(message: AscendexTicker, localTimestamp: Date): IterableIterator<BookTicker> { const ask = message.data.ask const bid = message.data.bid yield { type: 'book_ticker', symbol: message.symbol, exchange: 'ascendex', askAmount: ask !== undefined && ask[1] !== undefined ? Number(ask[1]) : undefined, askPrice: ask !== undefined && ask[0] !== undefined ? Number(ask[0]) : undefined, bidPrice: bid !== undefined && bid[0] !== undefined ? Number(bid[0]) : undefined, bidAmount: bid !== undefined && bid[1] !== undefined ? Number(bid[1]) : undefined, timestamp: new Date(message.data.ts), localTimestamp: localTimestamp } } } type AscendexTrade = { m: 'trades' symbol: string data: [{ p: string; q: string; ts: number; bm: boolean; seqnum: number }] } type AscendexPriceLevel = [string, string] type AscendexDepthRealTime = { m: 'depth-realtime' symbol: 'XRP/USDT' data: { ts: 1621814400204; seqnum: 39862426; asks: AscendexPriceLevel[]; bids: AscendexPriceLevel[] } } type AscendexDepthRealTimeSnapshot = { m: 'depth-snapshot-realtime' symbol: 'XRP/USDT' data: { ts: 0 seqnum: 39862426 asks: AscendexPriceLevel[] bids: AscendexPriceLevel[] } } type AscendexTicker = { m: 'bbo'; symbol: string; data: { ts: number; bid?: AscendexPriceLevel; ask?: AscendexPriceLevel } } type AscendexFuturesData = { m: 'futures-pricing-data' con: [ { t: 1621814404114 s: 'BTC-PERP' mp: '34878.075977904' ip: '34697.17' oi: '80.6126' r: '0.000093633' f: 1621843200000 fi: 28800000 } ] }