dYdX
We are currently working on this integration guide.
dYdX is one of the largest decentralized cryptocurrency exchanges in terms of daily trading volume for crypto derivative products. dYdX runs on smart contracts on the Ethereum blockchain, and allows users to trade with no intermediaries. This integration supports live market data ingestion and order execution with dYdX v4, which is the first version of the protocol to be fully decentralized with no central components.
Installation
To install the latest nautilus_trader
package along with the dydx
dependencies using pip:
pip install -U "nautilus_trader[dydx]"
To install from source using poetry:
poetry install --extras dydx
Examples
You can find working live example scripts here.
Overview
The following documentation assumes a trader is setting up for both live market data feeds, and trade execution. The full dYdX integration consists of an assortment of components, which can be used together or separately depending on the user's needs.
DYDXHttpClient
: Low-level HTTP API connectivity.DYDXWebSocketClient
: Low-level WebSocket API connectivity.DYDXAccountGRPCAPI
: Low-level gRPC API connectivity for account updates.DYDXInstrumentProvider
: Instrument parsing and loading functionality.DYDXDataClient
: A market data feed manager.DYDXExecutionClient
: An account management and trade execution gateway.DYDXLiveDataClientFactory
: Factory for dYdX data clients (used by the trading node builder).DYDXLiveExecClientFactory
: Factory for dYdX execution clients (used by the trading node builder).
Most users will simply define a configuration for a live trading node (as below), and won't need to necessarily work with these lower level components directly.
Symbology
Only perpetual contracts are available on dYdX. To be consistent with other adapters and to be
futureproof in case other products become available on dYdX, NautilusTrader appends -PERP
for all
available perpetual symbols. For example, the Bitcoin/USD-C perpetual futures contract is identified
as BTC-USD-PERP
. The quote currency for all markets is USD-C. Therefore, dYdX abbreviates it to USD.
Order types
dYdX offers a flexible combination of trigger types, enabling a broader range of Nautilus orders. However, the execution engine currently only supports submitting market and limit orders. Stop orders and trailing stop orders can be implemented later.
Short-term and long-term orders
dYdX makes a distinction between short-term orders and long-term orders (or stateful orders). Short-term orders are meant to be placed immediately and belongs in the same block the order was received. These orders stay in-memory up to 20 blocks, with only their fill amount and expiry block height being committed to state. Short-term orders are mainly intended for use by market makers with high throughput or for market orders.
By default, all orders are sent as short-term orders. To construct long-term orders, you can attach a tag to an order like this:
from nautilus_trader.adapters.dydx.common.common import DYDXOrderTags
order: LimitOrder = self.order_factory.limit(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=self.instrument.make_qty(self.trade_size),
price=self.instrument.make_price(price),
time_in_force=TimeInForce.GTD,
expire_time=self.clock.utc_now() + pd.Timedelta(minutes=10),
post_only=True,
emulation_trigger=self.emulation_trigger,
tags=[DYDXOrderTags(is_short_term_order=False).value],
)
To specify the number of blocks that an order is active:
from nautilus_trader.adapters.dydx.common.common import DYDXOrderTags
order: LimitOrder = self.order_factory.limit(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=self.instrument.make_qty(self.trade_size),
price=self.instrument.make_price(price),
time_in_force=TimeInForce.GTD,
expire_time=self.clock.utc_now() + pd.Timedelta(seconds=5),
post_only=True,
emulation_trigger=self.emulation_trigger,
tags=[DYDXOrderTags(is_short_term_order=True, num_blocks_open=5).value],
)
Market orders
Market orders require specifying a price to for price slippage protection and use hidden orders. By setting a price for a market order, you can limit the potential price slippage. For example, if you set the price of $100 for a market buy order, the order will only be executed if the market price is at or below $100. If the market price is above $100, the order will not be executed.
Some exchanges, including dYdX, support hidden orders. A hidden order is an order that is not visible to other market participants, but is still executable. By setting a price for a market order, you can create a hidden order that will only be executed if the market price reaches the specified price.
If the market price is not specified, a default value of 0 is used.
To specify the price when creating a market order:
order = self.order_factory.market(
instrument_id=self.instrument_id,
order_side=OrderSide.BUY,
quantity=self.instrument.make_qty(self.trade_size),
time_in_force=TimeInForce.IOC,
tags=[DYDXOrderTags(is_short_term_order=True, market_order_price=Price.from_str("10_000")).value],
)
Configuration
The product types for each client must be specified in the configurations.
Execution clients
The account type must be a margin account to trade the perpetual futures contracts.
The most common use case is to configure a live TradingNode
to include dYdX
data and execution clients. To achieve this, add a DYDX
section to your client
configuration(s):
from nautilus_trader.live.node import TradingNode
config = TradingNodeConfig(
..., # Omitted
data_clients={
"DYDX": {
"wallet_address": "YOUR_DYDX_WALLET_ADDRESS",
"is_testnet": False,
},
},
exec_clients={
"DYDX": {
"wallet_address": "YOUR_DYDX_WALLET_ADDRESS",
"subaccount": "YOUR_DYDX_SUBACCOUNT_NUMBER"
"mnemonic": "YOUR_MNEMONIC",
"is_testnet": False,
},
},
)
Then, create a TradingNode
and add the client factories:
from nautilus_trader.adapters.dydx.factories import DYDXLiveDataClientFactory
from nautilus_trader.adapters.dydx.factories import DYDXLiveExecClientFactory
from nautilus_trader.live.node import TradingNode
# Instantiate the live trading node with a configuration
node = TradingNode(config=config)
# Register the client factories with the node
node.add_data_client_factory("DYDX", DYDXLiveDataClientFactory)
node.add_exec_client_factory("DYDX", DYDXLiveExecClientFactory)
# Finally build the node
node.build()
API credentials
There are two options for supplying your credentials to the dYdX clients.
Either pass the corresponding wallet_address
and mnemonic
values to the configuration objects, or
set the following environment variables:
For dYdX live clients, you can set:
DYDX_WALLET_ADDRESS
DYDX_MNEMONIC
For dYdX testnet clients, you can set:
DYDX_TESTNET_WALLET_ADDRESS
DYDX_TESTNET_MNEMONIC
The data client is using the wallet address to determine the trading fees. The trading fees are used during back tests only.
Testnets
It's also possible to configure one or both clients to connect to the dYdX testnet.
Simply set the is_testnet
option to True
(this is False
by default):
config = TradingNodeConfig(
..., # Omitted
data_clients={
"DYDX": {
"wallet_address": "YOUR_DYDX_WALLET_ADDRESS",
"is_testnet": True,
},
},
exec_clients={
"DYDX": {
"wallet_address": "YOUR_DYDX_WALLET_ADDRESS",
"subaccount": "YOUR_DYDX_SUBACCOUNT_NUMBER"
"mnemonic": "YOUR_MNEMONIC",
"is_testnet": True,
},
},
)
Parser warnings
Some dYdX instruments are unable to be parsed into Nautilus objects if they contain enormous field values beyond what can be handled by the platform. In these cases, a warn and continue approach is taken (the instrument will not be available).
Order books
Order books can be maintained at full depth or top-of-book quotes depending on the
subscription. The venue does not provide quotes, but the adapter subscribes to order
book deltas and sends new quotes to the DataEngine
when there is a top-of-book price or size change.