UNPKG

@hackape/tardis-dev

Version:

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

205 lines (182 loc) 6.07 kB
import { BookChange, DerivativeTicker, Liquidation, Trade } from '../types' import { Mapper, PendingTickerInfoHelper } from './mapper' // https://www.cryptofacilities.com/resources/hc/en-us/categories/115000132213-API export const cryptofacilitiesTradesMapper: Mapper<'cryptofacilities', Trade> = { canHandle(message: CryptofacilitiesTrade | CryptofacilitiesTicker | CryptofacilitiesBookSnapshot | CryptofacilitiesBookUpdate) { return message.feed === 'trade' && message.event === undefined }, getFilters(symbols?: string[]) { return [ { channel: 'trade', symbols } ] }, *map(trade: CryptofacilitiesTrade, localTimestamp: Date): IterableIterator<Trade> { yield { type: 'trade', symbol: trade.product_id, exchange: 'cryptofacilities', id: trade.uid, price: trade.price, amount: trade.qty, side: trade.side, timestamp: new Date(trade.time), localTimestamp: localTimestamp } } } const mapBookLevel = ({ price, qty }: CryptofacilitiesBookLevel) => { return { price, amount: qty < 0 ? 0 : qty } } export const cryptofacilitiesBookChangeMapper: Mapper<'cryptofacilities', BookChange> = { canHandle(message: CryptofacilitiesTrade | CryptofacilitiesTicker | CryptofacilitiesBookSnapshot | CryptofacilitiesBookUpdate) { return message.event === undefined && (message.feed === 'book' || message.feed === 'book_snapshot') }, getFilters(symbols?: string[]) { return [ { channel: 'book', symbols }, { channel: 'book_snapshot', symbols } ] }, *map(message: CryptofacilitiesBookSnapshot | CryptofacilitiesBookUpdate, localTimestamp: Date): IterableIterator<BookChange> { if (message.feed === 'book_snapshot') { yield { type: 'book_change', symbol: message.product_id, exchange: 'cryptofacilities', isSnapshot: true, bids: message.bids.map(mapBookLevel), asks: message.asks.map(mapBookLevel), timestamp: message.timestamp !== undefined ? new Date(message.timestamp) : localTimestamp, localTimestamp: localTimestamp } } else { const isAsk = message.side === 'sell' const update = [ { price: message.price, amount: message.qty < 0 ? 0 : message.qty } ] yield { type: 'book_change', symbol: message.product_id, exchange: 'cryptofacilities', isSnapshot: false, bids: isAsk ? [] : update, asks: isAsk ? update : [], timestamp: message.timestamp !== undefined ? new Date(message.timestamp) : localTimestamp, localTimestamp: localTimestamp } } } } export class CryptofacilitiesDerivativeTickerMapper implements Mapper<'cryptofacilities', DerivativeTicker> { private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper() canHandle(message: CryptofacilitiesTrade | CryptofacilitiesTicker | CryptofacilitiesBookSnapshot | CryptofacilitiesBookUpdate) { return message.feed === 'ticker' && message.event === undefined } getFilters(symbols?: string[]) { return [ { channel: 'ticker', symbols } as const ] } *map(ticker: CryptofacilitiesTicker, localTimestamp: Date): IterableIterator<DerivativeTicker> { const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(ticker.product_id, 'cryptofacilities') pendingTickerInfo.updateFundingRate(ticker.funding_rate) pendingTickerInfo.updatePredictedFundingRate(ticker.funding_rate_prediction) pendingTickerInfo.updateFundingTimestamp( ticker.next_funding_rate_time !== undefined ? new Date(ticker.next_funding_rate_time) : undefined ) pendingTickerInfo.updateIndexPrice(ticker.index) pendingTickerInfo.updateMarkPrice(ticker.markPrice) pendingTickerInfo.updateOpenInterest(ticker.openInterest) pendingTickerInfo.updateLastPrice(ticker.last) pendingTickerInfo.updateTimestamp(new Date(ticker.time)) if (pendingTickerInfo.hasChanged()) { yield pendingTickerInfo.getSnapshot(localTimestamp) } } } export const cryptofacilitiesLiquidationsMapper: Mapper<'cryptofacilities', Liquidation> = { canHandle(message: CryptofacilitiesTrade | CryptofacilitiesTicker | CryptofacilitiesBookSnapshot | CryptofacilitiesBookUpdate) { return message.feed === 'trade' && message.event === undefined && message.type === 'liquidation' }, getFilters(symbols?: string[]) { return [ { channel: 'trade', symbols } ] }, *map(liquidationTrade: CryptofacilitiesTrade, localTimestamp: Date): IterableIterator<Liquidation> { yield { type: 'liquidation', symbol: liquidationTrade.product_id, exchange: 'cryptofacilities', id: liquidationTrade.uid, price: liquidationTrade.price, amount: liquidationTrade.qty, side: liquidationTrade.side, timestamp: new Date(liquidationTrade.time), localTimestamp: localTimestamp } } } type CryptofacilitiesTrade = { feed: 'trade' type: 'liquidation' | 'fill' uid: string | undefined event: undefined product_id: string side: 'buy' | 'sell' time: number qty: number price: number } type CryptofacilitiesTicker = { feed: 'ticker' event: undefined product_id: string index: number last: number openInterest: number markPrice: number funding_rate: number | undefined funding_rate_prediction: number | undefined next_funding_rate_time: number | undefined time: number } type CryptofacilitiesBookLevel = { price: number qty: number } type CryptofacilitiesBookSnapshot = { feed: 'book_snapshot' event: undefined product_id: string timestamp: number | undefined bids: CryptofacilitiesBookLevel[] asks: CryptofacilitiesBookLevel[] } type CryptofacilitiesBookUpdate = { feed: 'book' event: undefined product_id: string side: 'buy' | 'sell' price: number qty: number timestamp: number | undefined }