tardis-dev
Version:
Convenient access to tick-level historical and real-time cryptocurrency market data via Node.js
289 lines (248 loc) • 7.3 kB
text/typescript
import { upperCaseSymbols } from '../handy'
import { BookChange, Trade } from '../types'
import { Mapper } from './mapper'
export class PoloniexV2TradesMapper implements Mapper<'poloniex', Trade> {
canHandle(message: any) {
return message.channel === 'trades' && message.data !== undefined && message.data.length > 0
}
getFilters(symbols?: string[]) {
symbols = upperCaseSymbols(symbols)
return [
{
channel: 'trades',
symbols
} as const
]
}
*map(message: PoloniexV2TradesMessage, localTimestamp: Date): IterableIterator<Trade> {
for (const item of message.data) {
yield {
type: 'trade',
symbol: item.symbol,
exchange: 'poloniex',
id: item.id,
price: Number(item.price),
amount: Number(item.quantity),
side: item.takerSide === 'sell' ? 'sell' : 'buy',
timestamp: new Date(item.createTime),
localTimestamp: localTimestamp
}
}
}
}
const mapBookLevelV2 = (level: [string, string]) => {
return {
price: Number(level[0]),
amount: Number(level[1])
}
}
export class PoloniexV2BookChangeMapper implements Mapper<'poloniex', BookChange> {
canHandle(message: any) {
return message.channel === 'book_lv2' && message.data !== undefined && message.data.length > 0
}
getFilters(symbols?: string[]) {
symbols = upperCaseSymbols(symbols)
return [
{
channel: 'book_lv2',
symbols
} as const
]
}
*map(message: PoloniexV2BookMessage, localTimestamp: Date): IterableIterator<BookChange> {
for (const item of message.data) {
const bookSnapshot: BookChange = {
type: 'book_change',
symbol: item.symbol,
exchange: 'poloniex',
isSnapshot: message.action === 'snapshot',
bids: item.bids.map(mapBookLevelV2),
asks: item.asks.map(mapBookLevelV2),
timestamp: new Date(item.ts),
localTimestamp: localTimestamp
}
yield bookSnapshot
}
}
}
export class PoloniexTradesMapper implements Mapper<'poloniex', Trade> {
private readonly _channelIdToSymbolMap: Map<number, string> = new Map()
canHandle(message: PoloniexPriceAggreatedMessage) {
if (Array.isArray(message) === false) {
return false
}
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[]) {
symbols = upperCaseSymbols(symbols)
return [
{
channel: 'price_aggregated_book',
symbols
} as const
]
}
*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 (Array.isArray(message) === false) {
return false
}
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[]) {
symbols = upperCaseSymbols(symbols)
return [
{
channel: 'price_aggregated_book',
symbols
} as const
]
}
*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?]
type PoloniexV2SubscribeMessage = {
event: 'subscribe'
channel: 'trades'
symbols: string[]
}
type PoloniexV2TradesMessage = {
channel: 'trades'
data: [
{
symbol: 'USDD_USDT'
amount: '53.17153856'
quantity: '53.0866'
takerSide: 'sell'
createTime: 1659916859838
price: '1.0016'
id: '60100203'
ts: 1659916859843
}
]
}
type PoloniexV2BookMessage =
| {
channel: 'book_lv2'
data: [
{
symbol: 'AAVE_BTC'
createTime: 1659916859818
asks: [string, string][]
bids: [string, string][]
lastId: 20251
id: 20252
ts: 1659916859824
}
]
action: 'update'
}
| {
channel: 'book_lv2'
data: [
{
symbol: 'AAVE_BTC'
createTime: 1659900600092
asks: [string, string][]
bids: [string, string][]
lastId: 85
id: 86
ts: 1659916800614
}
]
action: 'snapshot'
}