UNPKG

tardis-dev

Version:

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

167 lines (141 loc) 4.09 kB
import { upperCaseSymbols } from '../handy' import { BookChange, DerivativeTicker, Trade } from '../types' import { Mapper, PendingTickerInfoHelper } from './mapper' // https://docs.coinflex.com/v2/#websocket-api-subscriptions-public export const coinflexTradesMapper: Mapper<'coinflex', Trade> = { canHandle(message: CoinflexTrades) { return message.table === 'trade' }, getFilters(symbols?: string[]) { symbols = upperCaseSymbols(symbols) return [ { channel: 'trade', symbols } ] }, *map(coinflexTrades: CoinflexTrades, localTimestamp: Date): IterableIterator<Trade> { for (const trade of coinflexTrades.data) { yield { type: 'trade', symbol: trade.marketCode, exchange: 'coinflex', id: trade.tradeId, price: Number(trade.price), amount: Number(trade.quantity), side: trade.side === 'SELL' ? 'sell' : 'buy', timestamp: new Date(Number(trade.timestamp)), localTimestamp: localTimestamp } } } } const mapBookLevel = (level: CoinflexBookLevel) => { const price = Number(level[0]) const amount = Number(level[1]) return { price, amount } } export const coinflexBookChangeMapper: Mapper<'coinflex', BookChange> = { canHandle(message: CoinflexBookDepthMessage) { return message.table === 'futures/depth' }, getFilters(symbols?: string[]) { symbols = upperCaseSymbols(symbols) return [ { channel: 'futures/depth', symbols } ] }, *map(depthMessage: CoinflexBookDepthMessage, localTimestamp: Date): IterableIterator<BookChange> { for (const change of depthMessage.data) { yield { type: 'book_change', symbol: change.instrumentId, exchange: 'coinflex', isSnapshot: depthMessage.action === 'partial', bids: change.bids.map(mapBookLevel), asks: change.asks.map(mapBookLevel), timestamp: new Date(Number(change.timestamp)), localTimestamp } } } } export class CoinflexDerivativeTickerMapper implements Mapper<'coinflex', DerivativeTicker> { private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper() canHandle(message: CoinflexTickerMessage) { return message.table === 'ticker' } getFilters(symbols?: string[]) { symbols = upperCaseSymbols(symbols) return [ { channel: 'ticker', symbols } as const ] } *map(message: CoinflexTickerMessage, localTimestamp: Date): IterableIterator<DerivativeTicker> { for (const ticker of message.data) { // exclude spot symbols if (ticker.marketCode.split('-').length === 2) { continue } const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(ticker.marketCode, 'coinflex') if (ticker.markPrice !== undefined) { pendingTickerInfo.updateMarkPrice(Number(ticker.markPrice)) } if (ticker.openInterest !== undefined) { pendingTickerInfo.updateOpenInterest(Number(ticker.openInterest)) } if (ticker.last !== undefined) { pendingTickerInfo.updateLastPrice(Number(ticker.last)) } pendingTickerInfo.updateTimestamp(new Date(Number(ticker.timestamp))) if (pendingTickerInfo.hasChanged()) { yield pendingTickerInfo.getSnapshot(localTimestamp) } } } } type CoinflexTrades = { data: [ { side: 'SELL' | 'BUY' quantity: string price: string marketCode: string tradeId: string timestamp: string } ] table: 'trade' } type CoinflexBookLevel = [number | string, number | string] type CoinflexBookDepthMessage = { data: [ { instrumentId: string asks: CoinflexBookLevel[] bids: CoinflexBookLevel[] timestamp: string } ] action: 'partial' table: 'futures/depth' } type CoinflexTickerMessage = { data: [ { last: string markPrice?: string marketCode: string openInterest: string timestamp: string } ] table: 'ticker' }