UNPKG

@hackape/tardis-dev

Version:

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

151 lines (125 loc) 4.29 kB
import { BookChange, Trade } from '../types' import { Mapper } from './mapper' // https://docs.poloniex.com/#websocket-api export class PoloniexTradesMapper implements Mapper<'poloniex', Trade> { private readonly _channelIdToSymbolMap: Map<number, string> = new Map() canHandle(message: PoloniexPriceAggreatedMessage) { if (message.length < 3) { return false } // store mapping between channel id and symbols if (message[2][0][0] === 'i') { this._channelIdToSymbolMap.set(message[0], message[2][0][1].currencyPair) } return message[2].some((m) => m[0] === 't') } getFilters(symbols?: string[]) { return [ { channel: 'price_aggregated_book', symbols } ] } *map(message: PoloniexPriceAggreatedMessage, localTimestamp: Date): IterableIterator<Trade> { const lastItem = message[message.length - 1] const symbol = typeof lastItem === 'string' ? lastItem : this._channelIdToSymbolMap.get(message[0]) if (symbol === undefined) { return } for (const item of message[2]) { if (item[0] !== 't') { continue } const [_, id, side, price, size, timestamp] = item yield { type: 'trade', symbol, exchange: 'poloniex', id: String(id), price: Number(price), amount: Number(size), side: side === 1 ? 'buy' : 'sell', timestamp: new Date(timestamp * 1000), localTimestamp: localTimestamp } } } } const mapSnapshotLevels = (levels: { [key: string]: string }) => { return Object.keys(levels).map((key) => { return { price: Number(key), amount: Number(levels[key]) } }) } const mapBookLevel = (level: PoloniexBookUpdate) => { return { price: Number(level[2]), amount: Number(level[3]) } } export class PoloniexBookChangeMapper implements Mapper<'poloniex', BookChange> { private readonly _channelIdToSymbolMap: Map<number, string> = new Map() canHandle(message: PoloniexPriceAggreatedMessage) { if (message.length < 3) { return false } // store mapping between channel id and symbols if (message[2][0][0] === 'i') { this._channelIdToSymbolMap.set(message[0], message[2][0][1].currencyPair) } return message[2].some((m) => m[0] === 'i' || m[0] === 'o') } getFilters(symbols?: string[]) { return [ { channel: 'price_aggregated_book', symbols } ] } *map(message: PoloniexPriceAggreatedMessage, localTimestamp: Date): IterableIterator<BookChange> { const lastItem = message[message.length - 1] const symbol = typeof lastItem === 'string' ? lastItem : this._channelIdToSymbolMap.get(message[0]) if (symbol === undefined) { return } let updates = [] for (const item of message[2]) { if (item[0] === 'i') { const bookSnapshot: BookChange = { type: 'book_change', symbol, exchange: 'poloniex', isSnapshot: true, bids: mapSnapshotLevels(item[1].orderBook[1]), asks: mapSnapshotLevels(item[1].orderBook[0]), timestamp: localTimestamp, localTimestamp: localTimestamp } yield bookSnapshot } else if (item[0] === 'o') { updates.push(item) } } if (updates.length > 0) { const bookUpdate: BookChange = { type: 'book_change', symbol, exchange: 'poloniex', isSnapshot: false, bids: updates.filter((u) => u[1] == 1).map(mapBookLevel), asks: updates.filter((u) => u[1] == 0).map(mapBookLevel), timestamp: localTimestamp, localTimestamp: localTimestamp } yield bookUpdate } } } type PoloniexBookSnapshot = ['i', { currencyPair: string; orderBook: [{ [key: string]: string }, { [key: string]: string }] }] type PoloniexBookUpdate = ['o', 0 | 1, string, string] type PoloniexTrade = ['t', string, 1 | 0, string, string, number] type PoloniexPriceAggreatedMessage = [number, number, (PoloniexBookSnapshot | PoloniexBookUpdate | PoloniexTrade)[], string?]