Tardis
Tardis provides granular data for cryptocurrency markets including tick-by-tick order book snapshots & updates, trades, open interest, funding rates, options chains and liquidations data for leading crypto exchanges.
PoseiTrader provides an integration with the Tardis API and data formats, enabling seamless access. The capabilities of this adapter include:
-
TardisCSVDataLoader
: Reads Tardis-format CSV files and converts them into Posei data. -
TardisMachineClient
: Supports live streaming and historical replay of data from the Tardis Machine WebSocket server - converting messages into Posei data. -
TardisHttpClient
: Requests instrument definition metadata from the Tardis HTTP API, parsing it into Posei instrument definitions. -
TardisDataClient
: Provides a live data client for subscribing to data streams from a Tardis Machine WebSocket server. -
TardisInstrumentProvider
: Provides instrument definitions from Tardis through the HTTP instrument metadata API. - Data pipeline functions: Enables replay of historical data from Tardis Machine and writes it to the Posei Parquet format, including direct catalog integration for streamlined data management (see below).
A Tardis API key is required for the adapter to operate correctly. See also environment variables.
Overview
This adapter is implemented in Rust, with optional Python bindings for ease of use in Python-based workflows. It does not require any external Tardis client library dependencies.
There is no need for
additional installation steps for
tardis
. The core components of
the adapter are compiled as static libraries
and automatically linked during the build
process.
Tardis documentation
Tardis provides extensive user documentation. We recommend also referring to the Tardis documentation in conjunction with this PoseiTrader integration guide.
Supported formats
Tardis provides normalized market data—a unified format consistent across all supported exchanges. This normalization is highly valuable because it allows a single parser to handle data from any Tardis-supported exchange, reducing development time and complexity. As a result, PoseiTrader will not support exchange-native market data formats, as it would be inefficient to implement separate parsers for each exchange at this stage.
The following normalized Tardis formats are supported by PoseiTrader:
Tardis format | Posei data type |
---|---|
book_change |
OrderBookDelta
|
book_snapshot_* |
OrderBookDepth10
|
quote |
QuoteTick
|
quote_10s |
QuoteTick
|
trade |
Trade
|
trade_bar_* |
Bar
|
instrument |
CurrencyPair ,
CryptoFuture ,
CryptoPerpetual ,
OptionContract
|
derivative_ticker | Not yet supported |
disconnect | Not applicable |
Notes:
- quote is an alias for book_snapshot_1_0ms.
- quote_10s is an alias for book_snapshot_1_10s.
-
Both quote, quote_10s, and one-level snapshots
are parsed as
QuoteTick
.
See also the Tardis normalized market data APIs.
Bars
The adapter will automatically convert
Tardis trade bar interval and suffix
to Posei BarType
s. This includes the
following:
Tardis suffix | Posei bar aggregation |
---|---|
ms - milliseconds |
MILLISECOND
|
s - seconds |
SECOND
|
m - minutes |
MINUTE
|
ticks - number of ticks |
TICK
|
vol - volume size |
VOLUME
|
Symbology and normalization
The Tardis integration ensures seamless compatibility with PoseiTrader’s crypto exchange adapters by consistently normalizing symbols. Typically, PoseiTrader uses the native exchange naming conventions provided by Tardis. However, for certain exchanges, raw symbols are adjusted to adhere to the Posei symbology normalization, as outlined below:
Common rules
- All symbols are converted to uppercase.
- Market type suffixes are appended with a hyphen for some exchanges (see exchange-specific normalizations).
-
Original exchange symbols are preserved in the
Posei instrument definitions
raw_symbol
field.
Exchange-specific normalizations
-
Binance: Posei appends the
suffix
-PERP
to all perpetual symbols. -
Bybit: Posei uses specific
product category suffixes, including
-SPOT
,-LINEAR
,-INVERSE
,-OPTION
. -
dYdX: Posei appends the suffix
-PERP
to all perpetual symbols. -
Gate.io: Posei appends the
suffix
-PERP
to all perpetual symbols.
For detailed symbology documentation per exchange:
Venues
Some exchanges on Tardis are partitioned into multiple venues. The table below outlines the mappings between Posei venues and corresponding Tardis exchanges, as well as the exchanges that Tardis supports:
Posei venue | Tardis exchange(s) |
---|---|
ASCENDEX
|
ascendex
|
BINANCE
|
binance ,
binance-dex ,
binance-futures ,
binance-jersey ,
binance-options ,
binance-us
|
BINANCE_DELIVERY
|
binance-delivery (COIN-margined contracts)
|
BINANCE_US
|
binance-us
|
BITFINEX
|
bitfinex ,
bitfinex-derivatives
|
BITFLYER
|
bitflyer
|
BITMEX
|
bitmex
|
BITNOMIAL
|
bitnomial
|
BITSTAMP
|
bitstamp
|
BLOCKCHAIN_COM
|
blockchain-com
|
BYBIT
|
bybit ,
bybit-options ,
bybit-spot
|
COINBASE
|
coinbase
|
COINFLEX
|
coinflex (for historical research)
|
CRYPTO_COM
|
crypto-com
|
CRYPTOFACILITIES
|
cryptofacilities
|
DELTA
|
delta
|
DERIBIT
|
deribit
|
DYDX
|
dydx
|
FTX
|
ftx (historical research)
|
FTX_US
|
ftx-us (historical research)
|
GATE_IO
|
gate-io ,
gate-io-futures
|
GEMINI
|
gemini
|
HITBTC
|
hitbtc
|
HUOBI
|
huobi , huobi-dm ,
huobi-dm-linear-swap ,
huobi-dm-options
|
HUOBI_DELIVERY
|
huobi-dm-swap
|
KRAKEN
|
kraken
|
KUCOIN
|
kucoin
|
MANGO
|
mango
|
OKCOIN
|
okcoin
|
OKEX
|
okex ,
okex-futures ,
okex-options ,
okex-swap
|
PHEMEX
|
phemex
|
POLONIEX
|
poloniex
|
SERUM
|
serum (historical research)
|
STARATLAS
|
staratlas
|
UPBIT
|
upbit
|
WOO_X
|
woo-x
|
Environment variables
The following environment variables are used by Tardis and PoseiTrader.
-
TM_API_KEY
: API key for the Tardis Machine. -
TARDIS_API_KEY
: API key for PoseiTrader Tardis clients. -
TARDIS_WS_URL
(optional): WebSocket URL for theTardisMachineClient
in PoseiTrader. -
TARDIS_BASE_URL
(optional): Base URL for theTardisHttpClient
in PoseiTrader. -
NAUTILUS_CATALOG_PATH
(optional): Root directory for writing replay data in the Posei catalog.
Running Tardis Machine historical replays
The Tardis Machine Server is a locally runnable server with built-in data caching, providing both tick-level historical and consolidated real-time cryptocurrency market data through HTTP and WebSocket APIs.
You can perform complete Tardis Machine WebSocket replays of historical data and output the results in Posei Parquet format, using either Python or Rust. Since the function is implemented in Rust, performance is consistent whether run from Python or Rust, letting you choose based on your preferred workflow.
The end-to-end
run_tardis_machine_replay
data
pipeline function utilizes a specified
configuration to
execute the following steps:
- Connect to the Tardis Machine server.
- Request and parse all necessary instrument definitions from the Tardis instruments metadata HTTP API.
- Stream all requested instruments and data types for the specified time ranges from the Tardis Machine server.
-
For each instrument, data type and date (UTC),
generate a
.parquet
file in the Posei format. - Disconnect from the Tardis Marchine server, and terminate the program.
You can request data for the first day of each month without an API key. For all other dates, a Tardis Machine API key is required.
This process is optimized for direct output to a
Posei Parquet data catalog. Ensure that the
NAUTILUS_CATALOG_PATH
environment
variable is set to the root
/catalog/
directory. Parquet files
will then be organized under
/catalog/data/
in the expected
subdirectories corresponding to data type and
instrument.
If no output_path
is specified in the
configuration file and the
NAUTILUS_CATALOG_PATH
environment
variable is unset, the system will default to the
current working directory.
Procedure
First, ensure the
tardis-machine
docker container is
running. Use the following command:
docker run -p 8000:8000 -p 8001:8001 -e "TM_API_KEY=YOUR_API_KEY" -d tardisdev/tardis-machine
This command starts the
tardis-machine
server without a
persistent local cache, which may affect
performance. For improved performance, consider
running the server with a persistent volume. Refer
to the
Tardis Docker documentation
for details.
Configuration
Next, ensure you have a configuration JSON file available.
Configuration JSON format
Field | Type | Description | Default |
---|---|---|---|
tardis_ws_url
|
string (optional) | The Tardis Machine WebSocket URL. |
If null then will use the
TARDIS_WS_URL env var.
|
normalize_symbols
|
bool (optional) | If Posei symbol normalization should be applied. |
If null then will default to
true .
|
output_path
|
string (optional) | The output directory path to write Posei Parquet data to. |
If null then will use the
NAUTILUS_CATALOG_PATH env var,
otherwise the current working directory.
|
options
|
JSON[] | An array of ReplayNormalizedRequestOptions objects. |
An example configuration file,
example_config.json
, is available
here:
{
"tardis_ws_url": "ws://localhost:8001",
"output_path": null,
"options": [
{
"exchange": "bitmex",
"symbols": [
"xbtusd",
"ethusd"
],
"data_types": [
"trade"
],
"from": "2019-10-01",
"to": "2019-10-02"
}
]
}
Python replays
To run a replay in Python, create a script similar to the following:
import asyncio
from posei_trader.core import nautilus_pyo3
async def run():
config_filepath = Path("YOUR_CONFIG_FILEPATH")
await nautilus_pyo3.run_tardis_machine_replay(str(config_filepath.resolve()))
if __name__ == "__main__":
asyncio.run(run())
Rust replays
To run a replay in Rust, create a binary similar to the following:
use std::{env, path::PathBuf};
use nautilus_adapters::tardis::replay::run_tardis_machine_replay_from_config;
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();
let config_filepath = PathBuf::from("YOUR_CONFIG_FILEPATH");
run_tardis_machine_replay_from_config(&config_filepath).await;
}
Make sure to enable Rust logging by exporting the following environment variable:
export RUST_LOG=debug
A working example binary can be found here.
This can also be run using cargo:
cargo run --bin tardis-replay <path_to_your_config>
Loading Tardis CSV data
Tardis-format CSV data can be loaded using either Python or Rust. The loader reads the CSV text data from disk and parses it into Posei data. Since the loader is implemented in Rust, performance remains consistent regardless of whether you run it from Python or Rust, allowing you to choose based on your preferred workflow.
You can also optionally specify a
limit
parameter for the
load_*
functions/methods to control
the maximum number of rows loaded.
Loading mixed-instrument CSV files is challenging due to precision requirements and is not recommended. Use single-instrument CSV files instead (see below).
Loading CSV data in Python
You can load Tardis-format CSV data in Python
using the TardisCSVDataLoader
. When
loading data, you can optionally specify the
instrument ID but must specify both the price
precision, and size precision. Providing the
instrument ID improves loading performance, while
specifying the precisions is required, as they
cannot be inferred from the text data alone.
To load the data, create a script similar to the following:
from posei_trader.adapters.tardis import TardisCSVDataLoader
from posei_trader.model import InstrumentId
instrument_id = InstrumentId.from_str("BTC-PERPETUAL.DERIBIT")
loader = TardisCSVDataLoader(
price_precision=1,
size_precision=0,
instrument_id=instrument_id,
)
filepath = Path("YOUR_CSV_DATA_PATH")
limit = None
deltas = loader.load_deltas(filepath, limit)
Loading CSV data in Rust
You can load Tardis-format CSV data in Rust using the loading functions found here. When loading data, you can optionally specify the instrument ID but must specify both the price precision and size precision. Providing the instrument ID improves loading performance, while specifying the precisions is required, as they cannot be inferred from the text data alone.
For a complete example, see the example binary here.
To load the data, you can use code similar to the following:
use std::path::Path;
use nautilus_adapters::tardis;
use nautilus_model::identifiers::InstrumentId;
#[tokio::main]
async fn main() {
// You must specify precisions and the CSV filepath
let price_precision = 1;
let size_precision = 0;
let filepath = Path::new("YOUR_CSV_DATA_PATH");
// Optionally specify an instrument ID and/or limit
let instrument_id = InstrumentId::from("BTC-PERPETUAL.DERIBIT");
let limit = None;
// Consider propagating any parsing error depending on your workflow
let _deltas = tardis::csv::load_deltas(
filepath,
price_precision,
size_precision,
Some(instrument_id),
limit,
)
.unwrap();
}
Requesting instrument definitions
You can request instrument definitions in both
Python and Rust using the
TardisHttpClient
. This client
interacts with the
Tardis instruments metadata API
to request and parse instrument metadata into
Posei instruments.
The TardisHttpClient
constructor
accepts optional parameters for
api_key
, base_url
, and
timeout_secs
(default is 60 seconds).
The client provides methods to retrieve either a
specific instrument
, or all
instruments
available on a particular
exchange. Ensure that you use Tardis’s lower-kebab
casing convention when referring to a
Tardis-supported exchange.
A Tardis API key is required to access the instruments metadata API.
Requesting instruments in Python
To request instrument definitions in Python, create a script similar to the following:
import asyncio
from posei_trader.core import nautilus_pyo3
async def run():
http_client = nautilus_pyo3.TardisHttpClient()
instrument = await http_client.instrument("bitmex", "xbtusd")
print(f"Received: {instrument}")
instruments = await http_client.instruments("bitmex")
print(f"Received: {len(instruments)} instruments")
if __name__ == "__main__":
asyncio.run(run())
Requesting instruments in Rust
To request instrument definitions in Rust, use code similar to the following. For a complete example, see the example binary here.
use nautilus_adapters::tardis::{enums::Exchange, http::client::TardisHttpClient};
#[tokio::main]
async fn main() {
tracing_subscriber::fmt()
.with_max_level(tracing::Level::DEBUG)
.init();
let client = TardisHttpClient::new(None, None, None).unwrap();
// Posei instrument definitions
let resp = client.instruments(Exchange::Bitmex).await;
println!("Received: {resp:?}");
let resp = client.instrument(Exchange::Bitmex, "ETHUSDT").await;
println!("Received: {resp:?}");
}
Instrument provider
The TardisInstrumentProvider
requests
and parses instrument definitions from Tardis
through the HTTP instrument metadata API. Since
there are multiple
Tardis-supported exchanges,
when loading all instruments, you must filter for
the desired venues using an
InstrumentProviderConfig
:
from posei_trader.config import InstrumentProviderConfig
# See supported venues docs/latestnightly/integrations/tardis#venues
venues = {"BINANCE", "BYBIT"}
filters = {"venues": frozenset(venues)}
instrument_provider_config = InstrumentProviderConfig(load_all=True, filters=filters)
You can also load specific instrument definitions in the usual way:
from posei_trader.config import InstrumentProviderConfig
instrument_ids = [
InstrumentId.from_str("BTCUSDT-PERP.BINANCE"), # Will use the 'binance-futures' exchange
InstrumentId.from_str("BTCUSDT.BINANCE"), # Will use the 'binance' exchange
]
instrument_provider_config = InstrumentProviderConfig(load_ids=instrument_ids)
Instruments must be available in the cache for all subscriptions. For simplicity, it’s recommended to load all instruments for the venues you intend to subscribe to.
Live data client
The TardisDataClient
enables
integration of a Tardis Machine with a running
PoseiTrader system. It supports subscriptions to
the following data types:
-
OrderBookDelta
(L2 granularity from Tardis, includes all changes or full-depth snapshots) -
OrderBookDepth10
(L2 granularity from Tardis, provides snapshots up to 10 levels) QuoteTick
TradeTick
-
Bar
(trade bars with Tardis-supported bar aggregations)
Data WebSockets
The main TardisMachineClient
data
WebSocket manages all stream subscriptions
received during the initial connection phase, up
to the duration specified by
ws_connection_delay_secs
. For any
additional subscriptions made after this period, a
new TardisMachineClient
is created.
This approach optimizes performance by allowing
the main WebSocket to handle potentially hundreds
of subscriptions in a single stream if they are
provided at startup.
When an initial subscription delay is set with
ws_connection_delay_secs
,
unsubscribing from any of these streams will not
actually remove the subscription from the Tardis
Machine stream, as selective unsubscription is not
supported by Tardis. However, the component will
still unsubscribe from message bus publishing as
expected.
All subscriptions made after any initial delay will behave normally, fully unsubscribing from the Tardis Machine stream when requested.
If you anticipate frequent subscription and
unsubscription of data, it is recommended to
set ws_connection_delay_secs
to
zero. This will create a new client for each
initial subscription, allowing them to be
later closed individually upon unsubscription.
Limitations and considerations
The following limitations and considerations are currently known:
- Historical data requests are not supported, as each would require a minimum one-day replay from the Tardis Machine, potentially with a filter. This approach is neither practical nor efficient.