dYdX v3
This is the legacy pure-Python dYdX adapter (nautilus_trader.adapters.dydx).
For new projects, use the Rust-backed dYdX v4 adapter which provides
better performance and additional features.
dYdX is one of the largest decentralized cryptocurrency exchanges for crypto derivative products. This integration supports live market data ingestion and order execution with dYdX v4, running on its own Cosmos SDK application-specific blockchain (dYdX Chain) with CometBFT consensus.
Installation
To install NautilusTrader with dYdX support:
uv pip install "nautilus_trader[dydx]"
To build from source with all extras (including dYdX):
uv sync --all-extras
Overview
This adapter is implemented in pure Python. It provides integration with dYdX's Indexer API (REST/WebSocket) for market data and gRPC for transaction submission.
Product support
| Product Type | Data Feed | Trading | Notes |
|---|---|---|---|
| Perpetual Futures | ✓ | ✓ | All perpetuals are USDC-settled on v4. |
| Spot | - | - | Not available on dYdX v4. |
| Options | - | - | Not available on dYdX v4. |
dYdX v4 exclusively supports perpetual futures contracts. All markets are quoted in USD and settled in USDC. The protocol does not support spot trading or options.
Examples
You can find live example scripts here.
Architecture
The dYdX adapter includes multiple components which can be used together or separately:
DYDXHttpClient: Low-level HTTP API connectivity for Indexer queries.DYDXWebSocketClient: Low-level WebSocket API connectivity for real-time data.DYDXInstrumentProvider: Instrument parsing and loading functionality.DYDXDataClient: Market data feed manager.DYDXExecutionClient: 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 define a configuration for a live trading node (as below), and won't need to necessarily work with these lower level components directly.
A dYdX v4 trading account (sub-account 0) is created only after the wallet’s first deposit or trade.
Until then, every gRPC/Indexer query returns NOT_FOUND, so DYDXExecutionClient.connect() fails.
Action → Before starting a live TradingNode, send any positive amount of USDC (≥ 1 wei) or other supported collateral from the same wallet on the same network (mainnet / testnet).
Once the transaction has finalised (a few blocks) restart the node; the client will connect cleanly.
Troubleshooting
StatusCode.NOT_FOUND — account … /0 not found
Cause The wallet/sub-account has never been funded and therefore does not yet exist on-chain.
Fix
- Deposit any positive amount of USDC to sub-account 0 on the correct network.
- Wait for finality (≈ 30 s on mainnet, longer on testnet).
- Restart the
TradingNode; the connection should now succeed.
In unattended deployments, wrap the connect() call in an exponential-backoff loop so the client retries until the deposit appears.
Symbology
dYdX v4 uses specific symbol conventions for perpetual futures contracts.
Symbol format
Format: {Base}-USD-PERP
All perpetuals on dYdX v4 are:
- Quoted in USD
- Settled in USDC
- Use the
.DYDXvenue suffix in Nautilus
Examples:
BTC-USD-PERP.DYDX- Bitcoin perpetual futuresETH-USD-PERP.DYDX- Ethereum perpetual futuresSOL-USD-PERP.DYDX- Solana perpetual futures
To subscribe in your strategy:
InstrumentId.from_str("BTC-USD-PERP.DYDX")
InstrumentId.from_str("ETH-USD-PERP.DYDX")
The -PERP suffix is appended for consistency with other adapters and future-proofing. While dYdX v4
currently only supports perpetuals, this naming convention allows for potential expansion to other
product types.
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 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 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],
)
Stop limit and stop market orders
Both stop limit and stop market conditional orders can be submitted. dYdX only supports long-term orders for conditional orders.
Orders capability
dYdX supports perpetual futures trading with a comprehensive set of order types and execution features.
Order Types
| Order Type | Perpetuals | Notes |
|---|---|---|
MARKET | ✓ | Requires price for slippage protection. Quote quantity not supported. |
LIMIT | ✓ | |
STOP_MARKET | ✓ | Long-term orders only. |
STOP_LIMIT | ✓ | Long-term orders only. |
MARKET_IF_TOUCHED | - | Not supported. |
LIMIT_IF_TOUCHED | - | Not supported. |
TRAILING_STOP_MARKET | - | Not supported. |
Execution Instructions
| Instruction | Perpetuals | Notes |
|---|---|---|
post_only | ✓ | Supported on all order types. |
reduce_only | ✓ | Supported on all order types. |
Time in force options
| Time in force | Perpetuals | Notes |
|---|---|---|
GTC | ✓ | Good Till Canceled. |
GTD | ✓ | Good Till Date. |
FOK | ✓ | Fill or Kill. |
IOC | ✓ | Immediate or Cancel. |
Advanced Order Features
| Feature | Perpetuals | Notes |
|---|---|---|
| Order Modification | ✓ | Short-term orders only; cancel-replace method. |
| Bracket/OCO Orders | - | Not supported. |
| Iceberg Orders | - | Not supported. |
Batch operations
| Operation | Perpetuals | Notes |
|---|---|---|
| Batch Submit | - | Not supported. |
| Batch Modify | - | Not supported. |
| Batch Cancel | - | Not supported. |
Position management
| Feature | Perpetuals | Notes |
|---|---|---|
| Query positions | ✓ | Real-time position updates. |
| Position mode | - | Net position mode only. |
| Leverage control | ✓ | Per-market leverage settings. |
| Margin mode | - | Cross margin only. |
Order querying
| Feature | Perpetuals | Notes |
|---|---|---|
| Query open orders | ✓ | List all active orders. |
| Query order history | ✓ | Historical order data. |
| Order status updates | ✓ | Real-time order state changes. |
| Trade history | ✓ | Execution and fill reports. |
Contingent orders
| Feature | Perpetuals | Notes |
|---|---|---|
| Order lists | - | Not supported. |
| OCO orders | - | Not supported. |
| Bracket orders | - | Not supported. |
| Conditional orders | ✓ | Stop market and stop limit orders. |
Order classification
dYdX classifies orders as either short-term or long-term orders:
- Short-term orders: Default for all orders; intended for high-frequency trading and market orders.
- Long-term orders: Required for conditional orders; use
DYDXOrderTagsto specify.
Subaccounts
dYdX v4 supports multiple subaccounts per wallet address, allowing segregation of trading strategies and risk management within a single wallet.
Key concepts
- Each wallet address can have multiple numbered subaccounts (0, 1, 2, ..., 127)
- Subaccount 0 is the default and is automatically created on first deposit
- Each subaccount maintains its own:
- Positions
- Open orders
- Collateral balance
- Margin requirements
Configuration
Specify the subaccount number in the execution client config:
config = TradingNodeConfig(
exec_clients={
"DYDX": {
"wallet_address": "YOUR_WALLET_ADDRESS",
"subaccount": 0, # Default subaccount
"mnemonic": "YOUR_MNEMONIC",
},
},
)
Most users will use subaccount 0 (the default). Advanced users can configure multiple execution
clients for different subaccounts to implement strategy segregation or risk isolation.
Configuration
Configure the dYdX adapter through the trading node configuration. Both data and execution clients support environment variable fallbacks for credentials and network-specific settings.
Data client configuration options
| Option | Default | Description |
|---|---|---|
wallet_address | None | Wallet address for fee calculation. Falls back to DYDX_WALLET_ADDRESS (mainnet) or DYDX_TESTNET_WALLET_ADDRESS (testnet). |
is_testnet | False | Connect to dYdX testnet when True. |
update_instruments_interval_mins | 60 | Interval (minutes) between reloading instruments from the venue. Set None to disable. |
max_retries | None | Maximum retry attempts for REST/WebSocket recovery. |
retry_delay_initial_ms | None | Initial delay (milliseconds) between retries. |
retry_delay_max_ms | None | Maximum delay (milliseconds) between retries. |
proxy_url | None | Proxy URL for HTTP requests. |
Execution client configuration options
| Option | Default | Description |
|---|---|---|
wallet_address | None | Wallet address for the account. Falls back to DYDX_WALLET_ADDRESS (mainnet) or DYDX_TESTNET_WALLET_ADDRESS (testnet). |
subaccount | 0 | Subaccount number (0-127). Subaccount 0 is the default. |
mnemonic | None | BIP-39 mnemonic for transaction signing. Falls back to DYDX_MNEMONIC (mainnet) or DYDX_TESTNET_MNEMONIC (testnet). |
base_url_http | None | HTTP client custom endpoint override. |
base_url_ws | None | WebSocket client custom endpoint override. |
is_testnet | False | Connect to dYdX testnet when True. |
max_retries | None | Maximum retry attempts for order operations. |
retry_delay_initial_ms | None | Initial delay (milliseconds) between retries. |
retry_delay_max_ms | None | Maximum delay (milliseconds) between retries. |
proxy_url | None | Proxy URL for HTTP requests. |
track_cancel_timeout_secs | 60 | Maximum time (seconds) to track an order after sending a cancel request. |
track_cancel_interval_secs | 0.1 | Interval (seconds) between checking order status after sending a cancel request. |
Environment variable resolution: The adapter automatically resolves credentials from environment
variables based on the is_testnet setting. This allows secure credential management without
hardcoding sensitive values in configuration files.
Basic setup
Configure a live TradingNode to include dYdX data and execution clients by adding a DYDX
section to your client configurations:
from nautilus_trader.config import TradingNodeConfig
config = TradingNodeConfig(
..., # Omitted
data_clients={
"DYDX": {
"wallet_address": "dydx1...", # Or use environment variable
"is_testnet": False,
},
},
exec_clients={
"DYDX": {
"wallet_address": "dydx1...", # Or use environment variable
"subaccount": 0,
"mnemonic": "word1 word2 ...", # Or use environment variable
"is_testnet": False,
},
},
)
Then, create a TradingNode and add the client factories:
from nautilus_trader.adapters.dydx import DYDXLiveDataClientFactory
from nautilus_trader.adapters.dydx 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
The dYdX adapter supports two methods for supplying credentials:
- Direct configuration: Pass
wallet_addressandmnemonicin the config - Environment variables: Set environment variables (recommended for security)
Environment variables
The adapter automatically selects environment variables based on the is_testnet setting:
Mainnet:
DYDX_WALLET_ADDRESS- Your dYdX wallet addressDYDX_MNEMONIC- BIP-39 mnemonic phrase for signing
Testnet:
DYDX_TESTNET_WALLET_ADDRESS- Your testnet wallet addressDYDX_TESTNET_MNEMONIC- Testnet mnemonic phrase
Use environment variables for credential management. This keeps sensitive information out of configuration files and source control.
The data client uses the wallet address to determine trading fees for backtesting purposes. This does not affect live trading fee calculation, which is determined by the blockchain state.
Testnet configuration
Configure clients to connect to the dYdX testnet by setting is_testnet: True:
config = TradingNodeConfig(
..., # Omitted
data_clients={
"DYDX": {
"is_testnet": True, # Will use DYDX_TESTNET_* environment variables
},
},
exec_clients={
"DYDX": {
"subaccount": 0,
"is_testnet": True, # Will use DYDX_TESTNET_* environment variables
},
},
)
Ensure you have testnet credentials in the appropriate environment variables (DYDX_TESTNET_WALLET_ADDRESS
and DYDX_TESTNET_MNEMONIC) before connecting to testnet.
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.
Contributing
For additional features or to contribute to the dYdX adapter, please see our contributing guide.