tardis-dev
Version:
Convenient access to tick-level historical and real-time cryptocurrency market data via Node.js
272 lines (228 loc) • 7.93 kB
text/typescript
import { upperCaseSymbols } from '../handy'
import { BookChange, DerivativeTicker, Exchange, Trade, BookTicker } from '../types'
import { Mapper, PendingTickerInfoHelper } from './mapper'
// https://www.gate.io/docs/futures/ws/index.html
export class GateIOFuturesTradesMapper implements Mapper<'gate-io-futures', Trade> {
constructor(private readonly _exchange: Exchange) {}
canHandle(message: any) {
return message.channel === 'futures.trades' && message.event === 'update'
}
getFilters(symbols?: string[]) {
symbols = upperCaseSymbols(symbols)
return [
{
channel: 'trades',
symbols
} as const
]
}
*map(tradesMessage: GateIOFuturesTrades, localTimestamp: Date): IterableIterator<Trade> {
for (const trade of tradesMessage.result) {
const timestamp = trade.create_time_ms !== undefined ? new Date(trade.create_time_ms) : new Date(trade.create_time * 1000)
yield {
type: 'trade',
symbol: trade.contract,
exchange: this._exchange,
id: trade.id.toString(),
price: Number(trade.price),
amount: Math.abs(trade.size),
side: trade.size < 0 ? 'sell' : 'buy',
timestamp,
localTimestamp: localTimestamp
}
}
}
}
const mapBookLevel = (level: GateIOFuturesSnapshotLevel) => {
const price = Number(level.p)
return { price, amount: Math.abs(level.s) }
}
export class GateIOFuturesBookChangeMapper implements Mapper<'gate-io-futures', BookChange> {
constructor(private readonly _exchange: Exchange) {}
canHandle(message: GateIOFuturesOrderBookSnapshot | GateIOFuturesOrderBookUpdate) {
return message.channel === 'futures.order_book' && (message.event === 'all' || message.event === 'update')
}
getFilters(symbols?: string[]) {
symbols = upperCaseSymbols(symbols)
return [
{
channel: 'order_book',
symbols
} as const
]
}
*map(depthMessage: GateIOFuturesOrderBookSnapshot | GateIOFuturesOrderBookUpdate, localTimestamp: Date): IterableIterator<BookChange> {
if (depthMessage.event === 'all') {
if (depthMessage.result.t === 0) {
return
}
const timestamp = depthMessage.result.t !== undefined ? new Date(depthMessage.result.t) : new Date(depthMessage.time * 1000)
// snapshot
yield {
type: 'book_change',
symbol: depthMessage.result.contract,
exchange: this._exchange,
isSnapshot: true,
bids: depthMessage.result.bids.map(mapBookLevel),
asks: depthMessage.result.asks.map(mapBookLevel),
timestamp,
localTimestamp: localTimestamp
}
} else if (depthMessage.result.length > 0) {
// update
const timestamp = depthMessage.result[0].t !== undefined ? new Date(depthMessage.result[0].t) : new Date(depthMessage.time * 1000)
yield {
type: 'book_change',
symbol: depthMessage.result[0].c,
exchange: this._exchange,
isSnapshot: false,
bids: depthMessage.result.filter((l) => l.s >= 0).map(mapBookLevel),
asks: depthMessage.result.filter((l) => l.s <= 0).map(mapBookLevel),
timestamp,
localTimestamp: localTimestamp
}
}
}
}
export class GateIOFuturesDerivativeTickerMapper implements Mapper<'gate-io-futures', DerivativeTicker> {
private readonly pendingTickerInfoHelper = new PendingTickerInfoHelper()
canHandle(message: GateIOFuturesTicker) {
return message.channel === 'futures.tickers' && message.event === 'update'
}
getFilters(symbols?: string[]) {
symbols = upperCaseSymbols(symbols)
return [
{
channel: 'tickers',
symbols
} as const
]
}
*map(message: GateIOFuturesTicker, localTimestamp: Date): IterableIterator<DerivativeTicker> {
const tickers = Array.isArray(message.result) ? message.result : [message.result]
for (const futuresTicker of tickers) {
if (futuresTicker.contract === undefined) {
return
}
const timestamp = message.time_ms !== undefined ? new Date(message.time_ms) : new Date(message.time * 1000)
const pendingTickerInfo = this.pendingTickerInfoHelper.getPendingTickerInfo(futuresTicker.contract, 'gate-io-futures')
pendingTickerInfo.updateFundingRate(Number(futuresTicker.funding_rate))
pendingTickerInfo.updatePredictedFundingRate(Number(futuresTicker.funding_rate_indicative))
pendingTickerInfo.updateIndexPrice(Number(futuresTicker.index_price))
pendingTickerInfo.updateMarkPrice(Number(futuresTicker.mark_price))
pendingTickerInfo.updateLastPrice(Number(futuresTicker.last))
pendingTickerInfo.updateTimestamp(timestamp)
if (futuresTicker.total_size !== undefined) {
pendingTickerInfo.updateOpenInterest(Number(futuresTicker.total_size))
}
if (pendingTickerInfo.hasChanged()) {
yield pendingTickerInfo.getSnapshot(localTimestamp)
}
}
}
}
export class GateIOFuturesBookTickerMapper implements Mapper<'gate-io-futures', BookTicker> {
constructor(private readonly _exchange: Exchange) {}
canHandle(message: any) {
return message.channel === 'futures.book_ticker' && message.event === 'update'
}
getFilters(symbols?: string[]) {
symbols = upperCaseSymbols(symbols)
return [
{
channel: 'book_ticker',
symbols
} as const
]
}
*map(gateIoFuturesBookTickerMessage: GateIOFuturesBookTicker, localTimestamp: Date): IterableIterator<BookTicker> {
const gateIoFuturesBookTicker = gateIoFuturesBookTickerMessage.result
if (gateIoFuturesBookTicker.t === 0) {
return
}
const ticker: BookTicker = {
type: 'book_ticker',
symbol: gateIoFuturesBookTicker.s,
exchange: this._exchange,
askAmount: gateIoFuturesBookTicker.A !== 0 ? gateIoFuturesBookTicker.A : undefined,
askPrice: gateIoFuturesBookTicker.a !== '' ? Number(gateIoFuturesBookTicker.a) : undefined,
bidPrice: gateIoFuturesBookTicker.b !== '' ? Number(gateIoFuturesBookTicker.b) : undefined,
bidAmount: gateIoFuturesBookTicker.B !== 0 ? gateIoFuturesBookTicker.B : undefined,
timestamp: gateIoFuturesBookTicker.t !== undefined ? new Date(gateIoFuturesBookTicker.t) : localTimestamp,
localTimestamp: localTimestamp
}
yield ticker
}
}
type GateIOFuturesTrade = {
size: number
id: number
create_time: number
create_time_ms?: number
price: string
contract: string
}
type GateIOFuturesTrades = {
time: number
channel: 'futures.trades'
event: 'update'
result: GateIOFuturesTrade[]
}
type GateIOFuturesSnapshotLevel = { p: string; s: number }
type GateIOFuturesOrderBookSnapshot = {
time: number
channel: 'futures.order_book'
event: 'all'
result: {
t?: number
contract: string
asks: GateIOFuturesSnapshotLevel[]
bids: GateIOFuturesSnapshotLevel[]
}
}
type GateIOFuturesOrderBookUpdate = {
time: number
channel: 'futures.order_book'
event: 'update'
result: {
t?: number
p: string
s: number
c: string
}[]
}
type GateIOFuturesTicker = {
time: number
time_ms?: number
channel: 'futures.tickers'
event: 'update'
result:
| [
{
contract: string
last: string
funding_rate: string
mark_price: string
index_price: string
funding_rate_indicative: string
total_size: string | undefined
}
]
| {
contract: string
last: string
funding_rate: string
mark_price: string
index_price: string
funding_rate_indicative: string
total_size: string | undefined
}
}
type GateIOFuturesBookTicker = {
id: null
time: 1648771200
channel: 'futures.book_ticker'
event: 'update'
error: null
result: { t: number; u: 3502782378; s: 'BTC_USD'; b: string; B: number; a: string; A: number }
}