NautilusTrader
Integrations

Nightly docs

These docs track unreleased changes and may change without notice. Their code examples can use APIs that the latest release lacks, so run them with a development wheel or switch to the latest release docs.

Derive

Derive (formerly Lyra) is a decentralized derivatives venue offering European-style options and cash-settled perpetual swaps, and one of the largest on-chain options markets. Trading runs against a per-user smart-contract wallet on the Derive Chain, so collateral stays in the user's custody while orders match through the venue's orderbook.

The Derive Chain is an optimistic rollup that settles to Ethereum. Orders match off chain and settle on chain, pairing orderbook execution with self-custody. Orders are authorized with EIP-712 typed-data signatures from a session key scoped to a subaccount, which keeps the signing key separate from the wallet owner and lets users rotate or revoke access without moving funds.

Overview

The Derive adapter is implemented in Rust under crates/adapters/derive. It exposes:

  • DeriveHttpClient: Low-level REST connectivity to api.lyra.finance (mainnet) or api-demo.lyra.finance (testnet).
  • DeriveWebSocketClient: JSON-RPC WebSocket transport with subscription tracking, reconnect, and signed order entry.
  • DeriveInstrumentProvider: Per-currency instrument fetch and caching.
  • DeriveDataClient: Live market data client.
  • DeriveDataClientFactory: Data client factory for the live node builder.
  • DeriveExecutionClient: Live execution client for signed order, cancel, query, and report flows.
  • DeriveExecutionClientFactory: Execution client factory for the live node builder.

Execution flows use EIP-712 typed-data signing against the Derive Chain per-action module contracts.

Python surface available from nautilus_trader.adapters.derive:

  • DeriveDataClientConfig, DeriveExecutionClientConfig
  • DeriveDataClientFactory, DeriveExecutionClientFactory
  • DeriveEnvironment
  • DERIVE, DERIVE_CLIENT_ID, and DERIVE_VENUE

Examples

Derive documentation

Derive publishes API documentation at docs.derive.xyz. Refer to it alongside this guide for additional details.

Products

Product typeSupportedNotes
ERC-20 spot✓USDC-quoted pairs such as ETH-USDC; parsed as CurrencyPair.
Perpetual swaps✓Cash-settled in USDC, with per-currency listings such as ETH-PERP.
Options (calls / puts)✓European-style options using {CURRENCY}-{EXPIRY}-{STRIKE}-{C|P}.

Symbology

Derive instruments use the native venue symbol with the venue suffix .DERIVE:

  • Spot: ETH-USDC.DERIVE (base currency, quote currency).
  • Perpetual: ETH-PERP.DERIVE, BTC-PERP.DERIVE.
  • Option: ETH-20260626-3000-C.DERIVE (currency, expiry, strike, kind).

The first hyphen-separated segment of the symbol is the underlying currency. The provider fetches public/get_instruments once per currency, so subscribing to a new currency triggers a lazy REST fetch when auto_load_missing_instruments is enabled (the default).

The adapter routes on the venue instrument_type (perp, option, erc20), not on the symbol suffix, so spot pairs need no special symbology parsing. Spot reuses the same Trade-module signing path as perps and options; the in-repo fixtures under crates/adapters/derive/test_data/spot/ capture the spot instrument, order book, ticker, and trade field shapes the parser and execution paths are pinned to.

Spot behavior

Spot trading has had less live exercise than perpetuals and options. Testnet accepts and cancels a passive ETH-USDC limit order at the 0.1 ETH minimum amount, and mainnet place/cancel has been exercised manually.

  • Sparse trades: public spot trade channels (trades.erc20.ETH, trades.ETH-USDC) subscribe successfully but can be low-volume, so expect sparse trade frames.
  • Empty books: the venue still broadcasts ticker and order book frames with a zeroed top of book. The adapter drops those partial quotes (logged at DEBUG), so the quote feed stays silent until a book forms. Trade frames are match-driven and independent of book state, so a trade that empties the book still emits an event.
  • Standard Margin: spot orders are margined by initial margin fraction, not full notional.

Environments

Configure the environment with the DeriveEnvironment enum on either client config.

EnvironmentConfigRESTWebSocket
MainnetDeriveEnvironment::Mainnethttps://api.lyra.financewss://api.lyra.finance/ws
TestnetDeriveEnvironment::Testnethttps://api-demo.lyra.financewss://api-demo.lyra.finance/ws

Testnet is a separate chain with its own session keys and balances. Mainnet and testnet API keys are not interchangeable.

Public market data (book, ticker, trades) does not require credentials.

The EIP-712 protocol constants (DOMAIN_SEPARATOR, ACTION_TYPEHASH, per-action module addresses) for both networks are shipped in crates/adapters/derive/src/common/consts.rs and tracked against Derive's Protocol Constants reference. DeriveExecutionClientConfig::domain_separator, action_typehash, and trade_module_address accept per-instance overrides that take precedence over the shipped values.

Testnet onboarding

Derive labels the demo environment "testnet" in the web app and "demo" in the API hostname. This guide uses "testnet" to match the dashboard and our DeriveEnvironment::Testnet enum. Steps to reach a position where the execution client can submit a signed order:

  1. Sign in to the testnet dashboard. Open testnet.derive.xyz and connect an EVM wallet (MetaMask, WalletConnect, social login, etc.). This is the owner EOA that authorizes the smart-contract wallet below.

  2. Register the Derive Chain smart-contract wallet. First sign-in deploys a per-user smart-contract wallet on the Derive testnet chain. The address shown under "Developers" -> "Derive Wallet" is the wallet_address (and the X-LYRAWALLET header) the client uses. It is distinct from the EOA you just connected.

  3. Create a subaccount. Open a subaccount under the wallet (Standard Margin is the simplest mode for test trading). The integer id is the subaccount_id the client signs each private/order request against.

  4. Generate a session key. Under "Developers" -> "Session Keys", create a session key scoped to the subaccount and copy the raw secp256k1 private key. This is the session_key value; it never leaves the client and is redacted from Debug output. Session keys can be rotated or revoked from the same panel.

  5. Fund the subaccount via the faucet. The testnet dashboard exposes a USDC faucet that drips test collateral. Deposit into the subaccount so the on-chain balance shows non-zero collateral; the API will reject orders until the subaccount has enough margin for the requested size.

  6. Set the environment variables. Export the three values the client reads in testnet mode (or pass them on DeriveExecutionClientConfig, where the config field wins):

    export DERIVE_TESTNET_WALLET_ADDRESS="0x..."  # Derive Chain smart-contract wallet
    export DERIVE_TESTNET_SESSION_PRIVATE_KEY="0x..."  # secp256k1 session-key private key
    export DERIVE_TESTNET_SUBACCOUNT_ID="12345"  # integer subaccount id

Minimum funding

Funding must cover the subaccount's initial-margin requirement for the resulting position. Order acceptance also depends on the venue's price, quantity, and execution rules. Treat these as practical funding estimates for the smallest viable test:

  • Smoke test (submit and cancel, no fills): fund enough to cover the margin required for a passive order at the instrument's minimum_amount.
  • Round-trip an ETH-PERP fill: budget for the worst-case slippage-adjusted notional plus the initial-margin cushion. For one contract at $3500 and the venue's ~10% IM, that is roughly $350 collateral plus $400 cushion. Around $1000 USDC is a comfortable working balance for a first-fill test.
  • Options: size the deposit to cover the venue's margin requirement for the resulting position. public/get_instrument provides contract details but does not report initial-margin requirements.

For order-size limits and taker exceptions, see Instrument loading.

Check account health

Use private/get_subaccount after funding to confirm initial_margin stays positive once the intended order's initial margin is applied. Both health fields report collateral credit minus the corresponding requirement:

Venue fieldMeaningConsequence when negative
initial_marginSigned net initial-margin healthVenue rejects risk-increasing orders that would make this value negative.
maintenance_marginSigned net maintenance-margin healthSubaccount is exposed to liquidation.

The adapter's query_account command emits this snapshot as an AccountState event so the strategy layer can gate trading on it. See Account state for the mapping.

Mainnet onboarding

Mainnet onboarding mirrors testnet against the production dashboard. Use real funds.

  1. Sign in to the mainnet dashboard. Open derive.xyz and connect the EVM owner wallet (MetaMask, WalletConnect, social login, etc.). First sign-in deploys your Derive Chain smart-contract wallet.

  2. Copy the wallet address. Under "Developers" -> "Derive Wallet", copy the smart-contract wallet address. This is the wallet_address the client signs against; it is distinct from the EOA you signed in with. Verify on the Derive Chain explorer that the address has contract code (EOAs do not).

  3. Create or pick a subaccount. Open a subaccount under the wallet (Standard Margin is the simplest mode; switch to Portfolio Margin only once you understand the cross-margin semantics). The integer id is the subaccount_id.

  4. Generate a mainnet session key. Under "Developers" -> "Session Keys", create a session key scoped to the subaccount and copy the raw secp256k1 private key. Session keys can be rotated or revoked from the same panel; prefer short-lived keys for exploratory tester runs.

  5. Fund the subaccount. Deposit USDC (or supported collateral) into the subaccount via the dashboard's deposit flow. Confirm via private/get_subaccount (or the adapter's query_account) that the deposit lands in collaterals_value and initial_margin stays positive after the intended order.

  6. Set the environment variables. Export the three mainnet values (or pass them on DeriveExecutionClientConfig, where the config field wins):

    export DERIVE_WALLET_ADDRESS="0x..."  # Derive Chain smart-contract wallet
    export DERIVE_SESSION_PRIVATE_KEY="0x..."  # secp256k1 session-key private key
    export DERIVE_SUBACCOUNT_ID="12345"  # integer subaccount id

Select the example network

Each Rust example (node_data_tester, node_exec_tester, node_delta_neutral) pins the network with a const DERIVE_ENVIRONMENT: DeriveEnvironment literal near the top of the file. Check that constant before every run and edit it to switch networks; the examples do not read the network from the environment.

Production deployments select the network via DeriveDataClientConfig::environment / DeriveExecutionClientConfig::environment.

Referral code attribution

Every signed order, replace, and trigger order carries the hard-coded NautilusTrader referral code. Derive funds the referral program from its own revenue, so attribution adds no trading cost, needs no approval, and is not configurable. This helps us gauge real usage of the integration and prioritize ongoing maintenance.

Capabilities

Market data

CapabilitySupportedNotes
Request instrument (REST)✓public/get_instrument; loads one instrument into the local cache.
Request all instruments (REST)✓public/get_instruments; salvages valid rows for each currency.
Instrument subscription-Not supported. Use the configured REST refresh interval.
Order book deltas (L2_MBP)✓Channel: orderbook.{instrument}.{group}.{depth}.
Order book depth (L2_MBP)✓Same order book channel with depth=10.
Order book at interval-Not supported. Maintain interval books from deltas locally.
Order book snapshot (REST)-Not supported. The venue has no book snapshot endpoint.
Historical book deltas (REST)-Not supported. The venue has no historical book endpoint.
Quotes (ticker_slim)✓Channel: ticker_slim.{instrument}.{interval}.
Quote snapshot (REST)✓One-shot public/get_tickers; emits a single QuoteTick.
Historical quotes (REST)-Not supported. The venue exposes ticker snapshots only.
Trades✓Channel: trades.{instrument_type}.{currency}.
Historical trades (REST)✓Chronological and deduplicated; limit retains the newest trades.
Bars / OHLC (REST)✓Closed minute, hour, day, and week bars stamped at bucket close.
Bars / OHLC (WS)-Not supported. The venue has no candle subscription channel.
Mark price stream✓Derived from ticker_slim; shares the quote subscription.
Index price stream✓Derived from ticker_slim; shares the quote subscription.
Funding rate stream✓Derived from the funding rate field on perp tickers.
Funding rate history (REST)✓Chronological for perpetuals; limit retains the newest valid rows.
Instrument status-Not supported. The instrument definition carries is_active.
Instrument close-Not supported. The venue publishes option settlement over REST only.
Option greeks✓Derived from option_pricing on option tickers.
Option chain✓Aggregated from quotes and greeks; public/get_tickers bootstraps ATM.

Instrument loading

request_instrument calls public/get_instrument for the requested InstrumentId and caches the returned definition before emitting the response. The cached instrument carries the precision and increment fields used by later quote, trade, book, and bar parsing.

The quantity fields map as follows for perpetuals, options, and spot:

Derive fieldNautilus fieldHandling
minimum_amountinfo["minimum_amount"]Retained as venue metadata; min_quantity stays unset.
amount_stepsize_incrementOrder quantity increment.
maximum_amountmax_quantityMaximum order quantity.

Derive can fill taker orders below minimum_amount, while orders that would rest on the book can be rejected with 11012: Invalid amount. Derive decides whether a sub-minimum order is valid.

Instrument loading treats venue error 12001 as an empty result for the affected product type, so a currency without a perp, option, or spot listing does not block its other products. Invalid instrument rows are logged and skipped while valid rows continue to load.

Historical data

DataREST endpoint
Tradespublic/get_trade_history
Barspublic/get_tradingview_chart_data
Funding ratespublic/get_funding_rate_history
Trade direction and deduplication

Trade history returns one maker row and one taker row per trade under the same trade_id. Each row's direction is that participant's own side, while the public WS trades feed defines direction as the taker's side.

Trade requests emit one TradeTick per trade, with the taker's direction as the aggressor side, independent of row order. Rows with an absent or unknown liquidity_role fall back to treating direction as the taker's side.

Bar requirements and time bounds
  • Aggregation and price: bars require EXTERNAL aggregation and PriceType::Last, since Derive candles are trade-based.
  • Periods: the venue supports 1, 5, 15, and 30 minute, 1, 4, and 8 hour, 1 day, and 1 week steps. Any other bar specification is rejected before the request goes out.
  • Time bounds: the bar end bound selects buckets by their start time at the venue. Responses omit any bucket whose close is after the request time, including the still-forming bucket returned by the venue.

Order book feeds

Derive exposes book deltas and depth snapshots through the same orderbook.{instrument}.{group}.{depth} channel family. subscribe_book_deltas publishes snapshot deltas as OrderBookDeltas, while subscribe_book_depth fixes depth=10 and publishes OrderBookDepth snapshots.

Execution

Derive uses the configured session key for authenticated execution:

  • Order submission and replacement requests carry locally generated EIP-712 signatures.
  • The live execution client sends order writes over the authenticated WebSocket and receives account, order, trade, and balance updates through private channels.
  • Report generation, account refreshes, and instrument lookups use REST.

DeriveHttpClient also exposes HTTP order-entry methods for tooling and tests.

Perpetuals, options, and ERC-20 spot pairs all use the Derive Trade module. Spot has no separate signing path, and reconciliation treats spot instruments like other instrument classes except for the reduce-only guard described below.

The adapter supports ordinary private/order requests: LIMIT and MARKET orders with GTC, IOC, or FOK time-in-force values. It also supports Derive trigger orders for the Nautilus-native stop and if-touched order types listed below. Unsupported Nautilus order types are denied locally with OrderDenied before submission, so they cannot fill at the venue.

Market orders require a cached quote before submission. Without one, the adapter emits OrderDenied and never signs.

After the async submit task resolves the instrument, it refreshes the current ticker snapshot and derives the signed slippage-bound limit_price from that refreshed quote.

Account state

Derive holds margin at the subaccount level. AccountState separates collateral balances, margin requirements, and net account health.

Collateral balances
  • total is the collateral amount (for example USDC or ETH) in its native units.
  • locked is zero because the venue reports no per-collateral reservation.
  • collaterals[].initial_margin is USD credit contributed by that collateral, not locked funds.
Margin requirements

The adapter emits one account-wide MarginBalance:

Nautilus fieldDerive requirement
initialpositions_initial_margin + open_orders_margin
maintenancepositions_maintenance_margin

These venue fields are USD requirements, stamped with the subaccount currency. Immediately after a closing trade, the venue can transiently report negative positions_*_margin values equal to the not-yet-settled cash movement (realized PnL and fees). The fields return to zero once settlement lands in the collateral balance.

Gate trading on net_initial_margin and net_maintenance_margin in AccountState.info, not on the margin requirement fields.

Account metadata

The subaccount's signed net health is not a margin requirement, so it travels in AccountState.info:

  • net_initial_margin and net_maintenance_margin carry net health.
  • positions_initial_margin, positions_maintenance_margin, and open_orders_margin carry requirements.
  • is_under_liquidation carries liquidation status.

Decimal values are JSON strings.

Conditional orders

Derive trigger orders use the WebSocket-only private/trigger_order endpoint, not the normal private/order endpoint. The venue stores them with order_status=untriggered until its trigger worker submits the signed child order. Reconciliation therefore reads both private/get_open_orders and private/get_trigger_orders.

Signature expiry

Derive mainnet requires trigger-order signatures to expire in [30, 90] days from venue time. The adapter signs trigger orders with a fixed 31-day expiry; signature_expiry_secs still controls ordinary private/order and private/replace writes, and must be greater than the 300s venue minimum.

Supported types
Nautilus order typeSupportedDerive order_typeDerive trigger_typeNotes
StopMarket✓marketstoplossUses trigger price as bound.
StopLimit✓limitstoplossSends limit and trigger price.
MarketIfTouched✓markettakeprofitUses trigger price as bound.
LimitIfTouched✓limittakeprofitSends limit and trigger price.
MarketToLimit---Not supported by Derive.
Trailing stops---Not supported by Derive.
TWAP / algo / RFQ---Not exposed by this adapter.

The adapter maps Nautilus TriggerType::Default and TriggerType::MarkPrice to Derive trigger_price_type=mark. Derive's current error-code reference states that index and last-trade trigger price types are not supported yet, so IndexPrice, LastPrice, BidAsk, and other trigger price types are denied locally with OrderDenied before submission.

Updating a trigger

Derive error 11054 states that trigger orders cannot replace or be replaced. The adapter therefore rejects Nautilus modify requests for trigger orders with an OrderModifyRejected event; cancel and resubmit for trigger updates.

Trigger price offsets

Derive validates the trigger price side and rejects a trigger that does not sit beyond the current price in the expected direction with error 11051. The trigger price is fixed when the order is signed, so a tight offset on a fast-moving or high-priced instrument can drift onto the wrong side before the venue receives the order.

Size the trigger offset to comfortably exceed expected price movement during submission (for ETH-PERP, tens of dollars rather than a few cents). A too-tight offset produces spurious 11051 rejections.

Bulk cancellation

Selection and routing

Derive supports both multi-order cancellation methods exposed by Strategy.

Strategy methodSupportedParametersNotes
cancel_orders(...)✓client_order_ids, client_id, paramsAll orders must use the same instrument.
cancel_all_orders(...)✓instrument_id, order_side, client_id, strategy_only, paramsDefaults to the calling strategy's orders.

The Derive execution client applies these methods as follows:

  • Explicit orders: cancel_orders cancels each requested regular or trigger order individually.
  • Strategy-only: cancel_all_orders with strategy_only=True expands cached matches into individual cancels.
  • Side-filtered: cancel_all_orders with strategy_only=False and a Buy or Sell filter selects open regular and trigger orders from the cache for the configured execution client, account, exact instrument, and side, then cancels each match. It never widens to both sides.
  • Both sides: cancel_all_orders with strategy_only=False and no side filter selects matching open triggers from the same execution client, account, and instrument scope and cancels them individually, then sends private/cancel_by_instrument for regular orders. It never sends private/cancel_all.

cancel_all_orders treats the cache as authoritative and does not query venue order state before cancellation. Eligibility follows the cache-selection rules above.

Failure handling

If an eligible cached order lacks a venue order ID, the command fails closed, logs a warning, sends no cancellation request, and emits no order event.

private/cancel_by_instrument cancels regular open orders only. A successful request with cancelled_orders == 0 is an expected no-op and logs at debug level.

A failed trigger cancellation logs a warning but does not suppress the regular instrument cancellation. A failed bulk request has no per-order outcome to emit; private channel updates and later reconciliation remain responsible for observed order state.

Execution instructions

InstructionSupportedDerive valueNotes
post_only✓post_onlyRequires GTC; rejects if the order would take liquidity.
reduce_only✓reduce_onlyPerps and options, market or IOC/FOK only; spot denied.

Time in force

Derive documents gtc, post_only, fok, and ioc as its time_in_force values. Nautilus values with no Derive equivalent are denied locally with OrderDenied before submission. Derive exposes post-only as a time_in_force value, so post_only cannot combine with IOC or FOK.

Time in forceSupportedDerive valueNotes
GTC✓gtcGood Till Canceled.
IOC✓iocImmediate or Cancel.
FOK✓fokFill or Kill.
GTD--Not supported by Derive.
DAY--Not supported by Derive.
AT_THE_OPEN--Not supported by Derive.
AT_THE_CLOSE--Not supported by Derive.

Spot reduce-only orders

Derive spot has no position concept, so a reduce-only spot order can never reduce anything. The venue always rejects it with error 11025; the adapter avoids that round-trip when it knows the instrument is spot. Cached spot instruments are denied with OrderDenied; lazily resolved spot instruments are rejected with OrderRejected during submit.

Reduce-only orders for perpetuals and options still reach the venue, where the outcome depends on the subaccount's position state. The derive-flatten bin closes derivative positions only and never spot, since flattening a spot balance would dump the base asset into a different quote.

Reduce-only time-in-force limits

Derive only honors reduce_only on market orders or non-resting limits (IOC/FOK). A resting GTC or post-only limit with reduce_only is rejected by the venue with error 11024 Reduce only not supported with this time in force.

A Nautilus bracket whose take-profit leg is a reduce-only GTC limit cannot rest on Derive: the entry and stop-loss legs submit, but the take-profit is rejected. Use a reduce-only IOC/FOK close or a non-reduce-only take-profit when targeting Derive.

Order rejection semantics

State-changing writes (submit_order, modify_order, cancel_order) are sent once over the WebSocket and are not replayed. The WebSocket request outcome determines whether the adapter emits a terminal rejection or waits for reconciliation.

Definitive failures

The adapter emits a terminal rejection event (OrderRejected, OrderModifyRejected, OrderCancelRejected) for definitive venue failures:

  • Signed-action rejections such as invalid params, insufficient margin, or unknown orders.
  • Venue business codes such as 11009 Zero liquidity.
  • Post-only crossing rejections (11008 Post only order cannot cross the market), reported as OrderRejected with due_post_only=true.
  • Rate-limit responses (-32000 Rate limit exceeded), where the gateway rejects the request before the matching engine sees it.
  • A successful private/cancel_by_label response with cancelled_orders == 0, which means no open order matched the client order ID label.

For other cancelled_orders values, the adapter emits no terminal event and waits for the venue order notification or later reconciliation to settle the state. The venue may return cancelled_orders == -1 for a cancel that matched its label-wildcard path; this is treated as success and settled the same way.

Post-only classification

For post-only orders that reach the venue, Derive rejects a crossing order with JSON-RPC 11008 and message Post only order cannot cross the market. The adapter marks that terminal rejection with due_post_only=true; if a WebSocket/order-report rejection carries the same reason, the tracked order path applies the same classification. Local denials for unsupported post-only IOC/FOK combinations are OrderDenied events without due_post_only, because they do not represent a venue crossing rejection.

Ambiguous outcomes

For ambiguous write outcomes, the adapter emits no terminal event and lets WebSocket reconciliation or later status reports settle the state. The ambiguous set is deliberately narrow:

  • -32603, a generic JSON-RPC internal error.
  • A response that cannot be decoded (the action may have been processed).
  • Request timeouts, dropped responses on reconnect, and transport errors.

This distinction protects both sides of the order lifecycle. A false terminal rejection can make the engine treat a live order as rejected; a false ambiguous outcome can leave an unplaced order hanging in Submitted forever because no WebSocket frame will arrive.

Rate limiting

Window model

Derive refills every request allowance discretely at fixed five-second window boundaries, not one request at a time (source: venue rate limits). The adapter mirrors this with a fixed-window limiter: each request class may spend its full window allowance in one burst, and the next request waits for the boundary before it can depart.

Windows are aligned to client construction because the venue's own window phase cannot be observed from the client, so a wait is at most one full window and the long-run average rate stays at the venue allowance. A burst can still straddle a venue window boundary, in which case the venue answers with -32000 Rate limit exceeded, which the adapter surfaces as a definitive rejection (see order rejection semantics).

Request buckets

Each window allowance is the documented requests-per-second rate times the five-second window, so the configured max_matching_requests_per_second and max_per_instrument_matching_requests_per_second (1 each for Trader) admit five requests per window:

BucketTrader-tier allowance
Matching (account-wide)5 requests per window
Per-instrument matching5 requests per window
REST non-matching (per IP)50 requests per window
WebSocket non-matching (logged in)25 requests per window
private/cancel_all5 requests per window
Unscoped private/cancel_by_label50 requests per window

Session and connection limits

  • REST: the per-IP allowance is flat across tiers.
  • Authenticated WebSocket: the non-matching allowance applies to sessions authorized via public/login.
  • Unauthenticated WebSocket: the venue applies a reduced, unspecified allowance, so public data-client traffic can hit venue limits earlier.
  • Connections: the venue caps concurrent WebSocket connections per IP (4 for a Trader).

Matching write allocation

Matching-engine writes that carry an instrument (order, replace, trigger order, single-order cancel, and private/cancel_by_instrument) draw on both the account-wide matching bucket and that instrument's independent bucket, so a Market Maker's account-wide override never inflates the per-instrument allowance.

Trigger order create and cancel methods are paced as matching writes even though the venue does not list them explicitly; private/cancel_trigger_order carries no instrument and draws on the account-wide bucket only. This conservative classification stays within Derive's documented rate contract.

Signing and venue responses

Pacing waits happen before the request is signed, so a delay never consumes the validity of the REST X-LYRA* authentication headers or of the nonces and EIP-712 signatures on the WebSocket order path. A matching write whose window rolls between signing and dispatch is re-paced once before departing (at most one further window, covered by the >300s signature TTL). A venue rate-limit response remains a definitive rejection; see order rejection semantics.

The remaining live allowances can be checked manually over the WebSocket via private/getRateLimits; the adapter does not call it.

WebSocket recovery

The data and execution clients reconnect automatically after a peer close, transport error, or heartbeat timeout. The adapter sends protocol Ping frames every 30 seconds and treats 60 seconds without any inbound frame as a dead connection; the selected transport can report a missed Pong sooner. The transport retries connections with exponential backoff and jitter.

Recovery completes in this order:

  1. The transport reconnects. If another disconnect occurs, recovery follows the latest connection.
  2. Credentialed sessions log in again, then every session replays its confirmed subscriptions. Acknowledged unsubscriptions are not replayed.
  3. The execution client refreshes account state and generates mass status for orders, fills, and positions.

State-changing requests follow the order rejection semantics: the adapter sends them once and never replays them. After three failed login or subscription recovery attempts, the client logs the error, marks itself disconnected, and stops that WebSocket session.

ws_timeout_secs applies to individual WebSocket operations, not heartbeat detection or reconnect backoff.

Subscription parameters

subscribe_book_deltas and subscribe_book_depth accept these subscribe_params keys:

KeyTypeDefaultAllowed
groupstring"1""1", "10", "100"
depthstring"10""1", "10", "20", "100"

subscribe_quotes accepts:

KeyTypeDefaultAllowed
intervalstring"1000""100", "1000"

Unknown values are rejected at subscribe time.

Shared ticker subscription

Quotes, mark prices, index prices, funding rates, and option greeks are all derived from the same ticker_slim.{instrument}.{interval} WebSocket subscription. The adapter reference-counts the underlying WS subscribe call:

  • The first feed subscribed for an instrument opens the channel.
  • The last unsubscribe closes it.

The first subscription's interval wins. Subsequent feeds subscribing with a different interval share the existing channel.

Ticker fields

Mark prices, index prices, funding rates, and option greeks read fields from the ticker payload. Both the full ticker shape and the compact ticker_slim shape carry these fields, so derived feeds work on either:

FieldsPresenceFeed behavior
mark_price, index_priceRequiredA missing field fails deserialization and is logged, not silently dropped.
funding_rateOptional; perpetuals onlySupplies funding-rate events.
option_pricingOptional; options onlySupplies option greeks.
Bid/askPresent in both shapesQuote feed works with either shape.

Instrument class restrictions

Funding rates are only meaningful for perpetuals, and option greeks only for options. Subscribing the wrong feed for an instrument's class (e.g. funding rates for an option) is accepted and the WebSocket subscription opens, but the parser returns no events for that feed because the venue payload omits the funding rate field for non-perps and option_pricing for non-options. Verify the instrument class before subscribing to derivative-specific feeds.

Configuration

Data client configuration options

Class/struct: DeriveDataClientConfig.

OptionDefaultDescription
base_url_restNoneOverride for the REST base URL.
base_url_wsNoneOverride for the WebSocket base URL.
proxy_urlNoneOptional proxy URL for HTTP and WebSocket transports.
environmentMainnetNetwork selector (MAINNET or TESTNET in Python).
http_timeout_secs10REST request timeout in seconds.
ws_timeout_secsNonePer-operation WebSocket timeout (login, subscribe, read, write) in seconds. Unset uses 10s.
update_instruments_interval_mins60Interval in minutes between instrument refreshes.
currencies[]Currencies to bulk-load on connect. Empty means lazy-load on demand.
include_expiredfalseInclude expired option rows from public/get_instruments.
auto_load_missing_instrumentstrueLazy-load an unknown instrument before sending a subscribe request.
transport_backendSockudoWebSocket transport when transport-sockudo is enabled.

auto_load_missing_instruments covers subscribe commands only. Before requesting quotes, trades, bars, or funding rates, bulk-load the instrument's currency or subscribe first.

  • request_quotes, request_trades, request_bars, and request_funding_rates fail when the instrument is not already cached.
  • request_instrument is the exception: it always fetches public/get_instrument.
  • Option-chain subscriptions require a cached option from the series to fetch the initial reference price.

Execution client configuration options

Class/struct: DeriveExecutionClientConfig.

Account and credentials

OptionDefaultDescription
account_idVenueNautilus account identifier; defaults to DERIVE-001.
wallet_addressNoneDerive Chain smart-contract wallet address. Falls back to env vars below.
session_keyNonesecp256k1 session-key private key. Falls back to env vars below.
subaccount_idNoneDerive subaccount id. Falls back to env vars below.

Connectivity and retries

OptionDefaultDescription
base_url_restNoneOverride for the REST base URL.
base_url_wsNoneOverride for the WebSocket base URL.
proxy_urlNoneOptional proxy URL for HTTP and WebSocket transports.
environmentMainnetNetwork selector (MAINNET or TESTNET in Python).
http_timeout_secs10REST request timeout in seconds.
ws_timeout_secsNonePer-operation WebSocket timeout (login, subscribe, read, write) in seconds. Unset uses 10s.
transport_backendSockudoWebSocket transport when transport-sockudo is enabled.
max_retries3Retry attempts for idempotent REST reads. Order writes are sent once and never replayed.
retry_delay_initial_ms100Initial retry delay in milliseconds.
retry_delay_max_ms5,000Maximum retry delay in milliseconds.

The default transport falls back to Tungstenite when the build disables the transport-sockudo feature.

Order signing and pricing

max_fee_per_contract is required and must be greater than zero. Execution-client construction fails before creating venue clients when the field is missing or non-positive.

OptionDefaultDescription
max_fee_per_contractRequiredPositive per-contract USDC fee cap signed into each order.
domain_separatorNoneOptional EIP-712 domain separator override.
action_typehashNoneOptional EIP-712 action typehash override.
trade_module_addressNoneOptional Trade module contract address override.
signature_expiry_secs600Order/replace TTL; must be >300s. Trigger orders use fixed 31-day TTL.
market_order_slippage_bps50Slippage bound for market-order limit prices.

Matching request limits

Both limits default to the Trader-tier rate of 1 request per second when unset; raise them for Market Maker accounts. Matching writes include order, replace, and cancel requests, including trigger methods. The per-instrument limit is enforced independently of the account-wide limit.

OptionDefaultDescription
max_matching_requests_per_secondNoneAccount-wide matching write requests per second.
max_per_instrument_matching_requests_per_secondNonePer-instrument matching write requests per second.

Credential environment variables

The wallet_address, session_key, and subaccount_id fall back to environment variables when unset:

FieldMainnet variableTestnet variable
wallet_addressDERIVE_WALLET_ADDRESSDERIVE_TESTNET_WALLET_ADDRESS
session_keyDERIVE_SESSION_PRIVATE_KEYDERIVE_TESTNET_SESSION_PRIVATE_KEY
subaccount_idDERIVE_SUBACCOUNT_IDDERIVE_TESTNET_SUBACCOUNT_ID

The session key is the secp256k1 private key registered on the wallet for API signing. The session_key field is redacted in Debug output and Python repr.

Python live node

Python nodes use LiveNode.builder(...) and pass concrete factory instances. The node supplies the trader identifier, while DeriveExecutionClientConfig supplies the account identifier.

from decimal import Decimal

from nautilus_trader.adapters.derive import DeriveDataClientConfig
from nautilus_trader.adapters.derive import DeriveDataClientFactory
from nautilus_trader.adapters.derive import DeriveEnvironment
from nautilus_trader.adapters.derive import DeriveExecutionClientConfig
from nautilus_trader.adapters.derive import DeriveExecutionClientFactory
from nautilus_trader.common import Environment
from nautilus_trader.live import LiveNode
from nautilus_trader.model import AccountId
from nautilus_trader.model import TraderId

trader_id = TraderId("TESTER-001")

data_config = DeriveDataClientConfig(
    environment=DeriveEnvironment.TESTNET,
    currencies=["ETH", "BTC"],
)

exec_config = DeriveExecutionClientConfig(
    account_id=AccountId("DERIVE-001"),
    environment=DeriveEnvironment.TESTNET,
    max_fee_per_contract=Decimal("1000"),
)

node = (
    LiveNode.builder("DERIVE-001", trader_id, Environment.LIVE)
    .add_data_client(None, DeriveDataClientFactory(), data_config)
    .add_exec_client(None, DeriveExecutionClientFactory(), exec_config)
    .build()
)

Rust data client

use nautilus_derive::{
    common::enums::DeriveEnvironment,
    config::DeriveDataClientConfig,
};

let config = DeriveDataClientConfig {
    environment: DeriveEnvironment::Testnet,
    currencies: vec!["ETH".to_string(), "BTC".to_string()],
    ..Default::default()
};

Rust execution client

use nautilus_derive::{
    common::enums::DeriveEnvironment,
    config::DeriveExecutionClientConfig,
};
use rust_decimal::Decimal;

let config = DeriveExecutionClientConfig {
    wallet_address: Some("0x...".to_string()),
    session_key: Some("0x...".to_string()),
    subaccount_id: Some(1),
    environment: DeriveEnvironment::Testnet,
    max_fee_per_contract: Some(Decimal::from(1000)),
    ..Default::default()
};

Known limitations

  • request_instruments requires at least one configured currency in DeriveDataClientConfig::currencies; the venue's public/get_instruments endpoint is scoped per-currency and the adapter does not enumerate the currency universe.
  • The venue does not push instrument status, instrument close, or candle subscriptions; the instrument definition carries is_active and the scheduled activation/deactivation timestamps, and bars are REST-only.
  • The book snapshot REST endpoint and historical book deltas / historical quote endpoints are not exposed by the venue. See the capabilities table above.
  • Derive's official REST docs mark public/get_ticker as deprecated in favor of public/get_tickers as of December 1, 2025. The adapter uses public/get_tickers for quote snapshots and option-chain reference-price bootstrap.

On this page