UNPKG

@hackape/tardis-dev

Version:

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

178 lines (149 loc) 4.75 kB
import { Mapper, PendingTickerInfoHelper } from './mapper' import { Trade, BookChange, DerivativeTicker } from '../types' // phemex provides timestamps in nanoseconds const fromNanoSecondsToDate = (nanos: number) => { const microtimestamp = Math.floor(nanos / 1000) const timestamp = new Date(microtimestamp / 1000) timestamp.μs = microtimestamp % 1000 return timestamp } function getPriceScale(symbol: string) { if (symbol.startsWith('s')) { return 1e8 } return 1e4 } function getQtyScale(symbol: string) { if (symbol.startsWith('s')) { return 1e8 } return 1 } function getSymbols(symbols?: string[]) { if (symbols === undefined) { return } return symbols.map((symbol) => { if (symbol.startsWith('S')) { return symbol.charAt(0).toLowerCase() + symbol.slice(1) } return symbol }) } export const phemexTradesMapper: Mapper<'phemex', Trade> = { canHandle(message: PhemexTradeMessage) { return 'trades' in message && message.type === 'incremental' }, getFilters(symbols?: string[]) { return [ { channel: 'trades', symbols: getSymbols(symbols) } as const ] }, *map(message: PhemexTradeMessage, localTimestamp: Date): IterableIterator<Trade> { for (const [timestamp, side, priceEp, qty] of message.trades) { const symbol = message.symbol yield { type: 'trade', symbol: symbol.toUpperCase(), exchange: 'phemex', id: undefined, price: priceEp / getPriceScale(symbol), amount: qty / getQtyScale(symbol), side: side === 'Buy' ? 'buy' : 'sell', timestamp: fromNanoSecondsToDate(timestamp), localTimestamp: localTimestamp } } } } const mapBookLevelForSymbol = (symbol: string) => ([priceEp, qty]: PhemexBookLevel) => { return { price: priceEp / getPriceScale(symbol), amount: qty / getQtyScale(symbol) } } export const phemexBookChangeMapper: Mapper<'phemex', BookChange> = { canHandle(message: PhemexBookMessage) { return 'book' in message }, getFilters(symbols?: string[]) { return [ { channel: 'book', symbols: getSymbols(symbols) } as const ] }, *map(message: PhemexBookMessage, localTimestamp: Date): IterableIterator<BookChange> { const symbol = message.symbol const mapBookLevel = mapBookLevelForSymbol(symbol) yield { type: 'book_change', symbol: symbol.toUpperCase(), exchange: 'phemex', isSnapshot: message.type === 'snapshot', bids: message.book.bids.map(mapBookLevel), asks: message.book.asks.map(mapBookLevel), timestamp: fromNanoSecondsToDate(message.timestamp), localTimestamp } } } export class PhemexDerivativeTickerMapper implements Mapper<'phemex', DerivativeTicker> { private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper() canHandle(message: PhemexTicker) { return 'market24h' in message } getFilters(symbols?: string[]) { return [ { channel: 'market24h', symbols } as const ] } *map(message: PhemexTicker, localTimestamp: Date): IterableIterator<DerivativeTicker> { const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(message.market24h.symbol, 'phemex') const phemexTicker = message.market24h pendingTickerInfo.updateFundingRate(phemexTicker.fundingRate / 100000000) pendingTickerInfo.updatePredictedFundingRate(phemexTicker.predFundingRate / 100000000) pendingTickerInfo.updateIndexPrice(phemexTicker.indexPrice / 10000) pendingTickerInfo.updateMarkPrice(phemexTicker.markPrice / 10000) pendingTickerInfo.updateOpenInterest(phemexTicker.openInterest) pendingTickerInfo.updateLastPrice(phemexTicker.close / 10000) pendingTickerInfo.updateTimestamp(fromNanoSecondsToDate(message.timestamp)) if (pendingTickerInfo.hasChanged()) { yield pendingTickerInfo.getSnapshot(localTimestamp) } } } type PhemexTradeMessage = { symbol: string trades: [[number, 'Buy' | 'Sell', number, number]] type: 'incremental' | 'snapshot' } type PhemexBookLevel = [number, number] type PhemexBookMessage = { book: { asks: PhemexBookLevel[] bids: PhemexBookLevel[] } symbol: string timestamp: number type: 'incremental' | 'snapshot' } type PhemexTicker = { market24h: { fundingRate: number indexPrice: number markPrice: number openInterest: number predFundingRate: number symbol: string close: number } timestamp: number }