tardis-node
Tardis-node
library provides convenient access to tick-level historical and real-time cryptocurrency market data both in exchange native and normalized formats. Instead of callbacks it relies on async iteration (for await ...of) which also enables composability features like seamless switching between real-time data streaming and historical data replay or computing derived data locally.
const { tardis, normalizeTrades, normalizeBookChanges } = require('tardis-node')
const messages = tardis.streamNormalized(
{
exchange: 'bitmex',
symbols: ['XBTUSD', 'ETHUSD']
},
normalizeTrades,
normalizeBookChanges
)
for await (const message of messages) {
console.log(message)
}
Features
- real-time streaming of tick-level market data with unified API for connecting directly to exchanges public WebSocket APIs without any intermediary/3rd party proxy
- historical tick-level market data replay backed by tardis.dev HTTP API
- support for both exchange native and normalized market data formats (consistent format for accessing market data across multiple exchanges — normalized trades, order book and ticker data)
- seamless switching between real-time streaming and historical market data replay thanks to
async iterables
providing unified way of consuming data messages - transparent historical local data caching (cached data is stored on disk in compressed GZIP format and decompressed on demand when reading the data)
- support for top cryptocurrency exchanges: BitMEX, Binance, Binance Futures, Deribit, Bitfinex, bitFlyer, Bitstamp, Coinbase Pro, Crypto Facilities, Gemini, FTX, Kraken and OKEx.
- automatic closed connections and stale connections reconnection logic for real-time streams
- combining multiple exchanges feeds into single one via
combine
helper function — synchronized historical market data replay and consolidated real-time data streaming from multiple exchanges - computing derived data locally like trade bars and book snapshots via
compute
helper function and computables
, e.g., volume based bars, top 20 levels order book snapshots taken every 10 ms etc. - full limit order book reconstruction both for real-time and historical data via
OrderBook
object - fast and lightweight architecture — low memory footprint and no heavy in-memory buffering
- extensible mapping logic that allows adjusting normalized formats for specific needs
- built-in TypeScript support
Installation
Requires Node.js v12+ installed.
npm install tardis-node --save
Debugging and logging
tardis-node
lib uses debug package for verbose logging and debugging purposes that can be enabled via DEBUG
environment variable set to tardis-node*
.
Documentation
See the official tardis-node docs.
Examples
Real-time spread across multiple exchanges
Example showing how to quickly display real-time spread and best bid/ask info across multiple exchanges at once. It can be easily adapted to do the same for historical data (replayNormalized
instead of streamNormalized
).
const { tardis, normalizeBookChanges, combine, compute,
computeBookSnapshots } = require('tardis-node')
const exchangesToStream = [
{ exchange: 'bitmex', symbols: ['XBTUSD'] },
{ exchange: 'deribit', symbols: ['BTC-PERPETUAL'] },
{ exchange: 'cryptofacilities', symbols: ['PI_XBTUSD'] }
]
const realTimeStreams = exchangesToStream.map(e => {
return tardis.streamNormalized(e, normalizeBookChanges)
})
const messages = combine(...realTimeStreams)
const realTimeQuoteComputable = computeBookSnapshots({
depth: 1,
interval: 0,
name: 'realtime_quote'
})
const messagesWithQuotes = compute(messages, realTimeQuoteComputable)
const spreads = {}
setInterval(() => {
console.clear()
console.log(spreads)
}, 100)
for await (const message of messagesWithQuotes) {
if (message.type === 'book_snapshot') {
spreads[message.exchange] = {
spread: message.asks[0].price - message.bids[0].price,
bestBid: message.bids[0],
bestAsk: message.asks[0]
}
}
}
Seamless switching between real-time streaming and historical market data replay
Example showing simple pattern of providing async iterable
of market data messages to the function that process them no matter if it's is real-time or historical market data. This allows having the same logic for example for both back-testing and live trading.
const { tardis, normalizeTrades, compute, computeTradeBars } = require('tardis-node')
async function produceVolumeBasedTradeBars(messages) {
const withVolumeTradeBars = compute(
messages,
computeTradeBars({
kind: 'volume',
interval: 100 * 1000
})
)
for await (const message of withVolumeTradeBars) {
if (message.type === 'trade_bar') {
console.log(message.name, message)
}
}
}
const historicalMessages = tardis.replayNormalized(
{ exchange: 'bitmex', symbols: ['XBTUSD'], from: '2019-08-01', to: '2019-08-02' },
normalizeTrades
)
const realTimeMessages = tardis.streamNormalized(
{ exchange: 'bitmex', symbols: ['XBTUSD'] },
normalizeTrades
)
await produceVolumeBasedTradeBars(historicalMessages)
Stream real-time market data in exchange native data format
const messages = tardis.stream({
exchange: 'bitmex',
filters: [
{ channel: 'trade', symbols: ['XBTUSD'] },
{ channel: 'orderBookL2', symbols: ['XBTUSD'] }
]
})
for await (const message of messages) {
console.log(message)
}
Replay historical market data in exchange native data format
const messages = tardis.replay({
exchange: 'bitmex',
filters: [
{ channel: 'trade', symbols: ['XBTUSD'] },
{ channel: 'orderBookL2', symbols: ['XBTUSD'] }
],
from: '2019-05-01',
to: '2019-05-02'
})
for await (const message of messages) {
console.log(message)
}