Nightly docs
Lighter
Lighter is a decentralized central-limit-order-book exchange for spot and perpetual futures. The venue settles through an Ethereum zero-knowledge rollup, while matching and sequencing run off-chain. The adapter also supports the Robinhood Chain deployment of the Lighter protocol.
The NautilusTrader Lighter adapter is implemented by the nautilus-lighter crate. It provides
Rust data and execution clients, typed REST and WebSocket models, and an in-tree L2 transaction
signer for the venue's Schnorr / ECgFp5 signing flow.
Measured L2 signing cost, including a comparison with the official Go SDK, is recorded in
crates/adapters/lighter/benches/BENCHMARKS.md.
Absolute numbers vary by machine, so only same-machine deltas are meaningful.
Overview
The main components are:
LighterRawHttpClient: low-level REST client for the public and account endpoints.LighterHttpClient: domain client which parses instruments, trades, books, orders, and account state into Nautilus model types.LighterWebSocketClient: reconnecting WebSocket client for public market and private account streams.LighterDataClient: Nautilus data client for instruments, trades, quotes, and L2 MBP books.LighterExecutionClient: Nautilus execution client for account streams, order submission, modification, cancellation, and reconciliation reports.LighterDataClientFactoryandLighterExecutionClientFactory: live-node factory wiring.
The Python surface is intentionally narrow. The Python extension exposes configuration, deployment and environment selection, factory classes, and integrator revocation; data and execution clients are consumed through the Rust trait surface.
Examples
Python examples live in
examples/live/lighter/
and run out of the box: settings live in module-level constants at the top of each file, and
running a script connects and starts immediately. Edit LIGHTER_DEPLOYMENT and
LIGHTER_ENVIRONMENT to select a deployment and environment. The execution tester places real
orders by default (dry_run=False), stated in a warning at the top of the module.
From the repository root:
uv run --project python --no-sync python examples/live/lighter/data_tester.py
uv run --project python --no-sync python examples/live/lighter/exec_tester.pyRust examples live under crates/adapters/lighter/examples/. Both testers connect when run. The
execution tester has DRY_RUN = false and selects Lighter Mainnet in its source, so the command
below can submit live orders:
cargo run --example lighter-data-tester --package nautilus-lighter --features examples
cargo run --example lighter-exec-tester --package nautilus-lighter --features examplesExamples can connect to live venues. Execution examples with live order flow enabled can submit orders when pointed at a funded account on either mainnet deployment. Review the selected instrument, quantity, and environment before running them.
Emergency account cleanup
cargo run --bin lighter-flatten -p nautilus-lighter is a convenience command that cancels open
orders and closes positions for the selected deployment account. It submits Lighter's account-wide
immediate cancellation, reads one position snapshot, and submits reduce-only IOC closes for the
positions in that snapshot.
Stop other writers for the account before running this command. Cleanup is account-wide, not strategy-scoped, so review the active account and positions first.
The command does not confirm the requests or retry until the account is flat. A successful exit means the cancellation and discovered close requests were submitted without a known error. Check the account state after it exits and rerun the command if anything remains. One run can submit at most 15 position closes because the account-wide cancellation uses one slot in its 16-transaction nonce window. An incomplete position snapshot or a request or submission failure returns an error.
Set LIGHTER_DEPLOYMENT to lighter or robinhood and LIGHTER_ENVIRONMENT to mainnet or
testnet; omitted selectors default to Lighter Mainnet and select the matching credential
namespace.
Product support
| Product type | Data feed | Trading | Notes |
|---|---|---|---|
| Spot | ✓ | ✓ | Spot markets; new listings use 64-bit ids from 4095. |
| Perpetual futures | ✓ | ✓ | Linear perpetuals; new listings use 64-bit ids from 4095. |
| Dated futures | - | - | Not supported. |
| Options | - | - | Not supported. |
Limitations
The current adapter scope is deliberately narrower than the venue's full transaction surface:
- Grouped order lists, OCO/OTO groups, brackets, TWAP, trailing stops, and iceberg display size are
not implemented. Batch submit does not use
CreateGroupedOrders. - Order-list submit sends independent transactions sequentially over WebSocket. Batch cancel sends signed cancellations in WebSocket batches of up to 15 transactions. Both commands are capped at 15 transactions.
- The execution client implements
CancelAllOrdersfrom cached open orders filtered by the requested instrument and optionalorder_side, across strategies. Each cancellation retains the order's owning strategy. The native cancel-all transaction cannot enforce the side filter, and the local signing schema has no market restriction. The adapter sends explicit per-order cancellations in WebSocket batches of up to 15 transactions. - Spot trading supports market and limit orders. Conditional stop-loss and take-profit orders are limited to perpetual markets.
- Account state and position reports come from private WebSocket streams.
query_accountand position status generation replay the latest cached stream state. - Unscoped order reconciliation is bounded to configured or observed active markets to avoid a full venue-wide fan-out under the standard REST quota.
Symbology
Lighter identifies markets by numeric market_index values in the venue's 64-bit allocation.
Legacy markets keep their range-partitioned ids, while markets listed after the September 2026
upgrade take the next free index from 4095 for either product type. Product type always comes
from the venue's market_type field, never from the index. The adapter bootstraps the mapping from
GET /api/v1/orderBookDetails, then converts the raw venue symbol into a Nautilus InstrumentId.
| Deployment product | Nautilus symbol format | Example | Notes |
|---|---|---|---|
| Lighter perpetual | {BASE}-PERP.LIGHTER | BTC-PERP.LIGHTER | Raw venue symbol BTC. |
| Lighter spot | {BASE}/{QUOTE}-SPOT.LIGHTER | ETH/USDC-SPOT.LIGHTER | Raw symbol ETH/USDC. |
| Robinhood perpetual | {BASE}-PERP.LIGHTER_ROBINHOOD | SNDK-PERP.LIGHTER_ROBINHOOD | Raw venue symbol SNDK. |
| Robinhood spot | {BASE}/{QUOTE}-SPOT.LIGHTER_ROBINHOOD | SNDK/USDG-SPOT.LIGHTER_ROBINHOOD | Raw symbol SNDK/USDG. |
The suffix separates spot and perpetual listings. Outbound requests strip it and use the cached
market_index; spot symbols retain the venue pair.
Deployments and environments
| Deployment | Environment | REST URL | WebSocket URL | L2 signing chain ID | Settlement | Default venue |
|---|---|---|---|---|---|---|
| Lighter | Mainnet | https://mainnet.zklighter.elliot.ai | wss://mainnet.zklighter.elliot.ai/stream | 304 | USDC | LIGHTER |
| Lighter | Testnet | https://testnet.zklighter.elliot.ai | wss://testnet.zklighter.elliot.ai/stream | 300 | USDC | LIGHTER |
| Robinhood | Mainnet | https://api.rh.lighter.xyz | wss://api.rh.lighter.xyz/stream | 466324 | USDG | LIGHTER_ROBINHOOD |
| Robinhood | Testnet | https://api.rh-testnet.lighter.xyz | wss://api.rh-testnet.lighter.xyz/stream | 300 | USDG | LIGHTER_ROBINHOOD |
These chain IDs are Lighter L2 signing-domain values, not EVM network chain IDs.
Use LighterDeployment::Lighter or LighterDeployment::Robinhood to select the protocol
deployment. Use LighterEnvironment::Mainnet or LighterEnvironment::Testnet to select its
environment. The deployment and environment together control the default URLs, chain ID,
settlement currency, default venue, and attribution policy. Robinhood Testnet and Lighter Testnet
both use chain ID 300, so the adapter does not infer deployment behavior from the numeric chain ID.
URL overrides are available for private gateways and local test fixtures. They replace only the transport endpoint. The selected deployment and environment still control transaction signing, settlement currency, and attribution policy.
Custom venue identity
Set venue on both data and execution configs when separate Lighter-protocol endpoints must have
distinct Nautilus identities. This scopes instruments, cache entries, message topics, socket state,
and execution routing without changing the selected deployment's protocol behavior. ClientId
remains the name supplied when registering each client.
The shared factory name remains LIGHTER for compatibility. When routing a Robinhood client by
ClientId, register it as LIGHTER_ROBINHOOD; the Rust and Python examples derive this name from
LIGHTER_DEPLOYMENT. Explicit custom client names remain supported.
The execution account_id issuer must equal the resolved venue because Nautilus routes account
commands by issuer. For example, venue LIGHTER_RH_ALT requires an account ID such as
LIGHTER_RH_ALT-001. A custom venue does not enable a custom chain ID or custom attribution.
Account and API key setup
Public market data does not require an account. Private account streams and execution require an account index, an API key index, and the API private key from the same deployment and environment. Each row below has a separate account and API-key namespace:
| Deployment | Environment | Account and API key page | Account issuer | Credential prefix |
|---|---|---|---|---|
| Lighter | Mainnet | Lighter Mainnet | LIGHTER | LIGHTER_* |
| Lighter | Testnet | Lighter Testnet | LIGHTER | LIGHTER_TESTNET_* |
| Robinhood | Mainnet | Robinhood Mainnet | LIGHTER_ROBINHOOD | LIGHTER_ROBINHOOD_* |
| Robinhood | Testnet | Robinhood Testnet | LIGHTER_ROBINHOOD | LIGHTER_ROBINHOOD_TESTNET_* |
Do not mix an account index or API key from one row with another. This also applies to the two testnets even though both use L2 signing chain ID 300.
-
Open the account page for the target deployment, sign in with the account used there, and create or select the trading account. Select the intended sub-account before generating its API key.
-
Follow Lighter's account-index lookup against the target deployment's REST URL. This example selects Robinhood Mainnet; replace the URL with the exact value from the deployment table for another row:
LIGHTER_SETUP_API_URL="https://api.rh.lighter.xyz" LIGHTER_SETUP_L1_ADDRESS="0xYOUR_ETHEREUM_ADDRESS" curl -sS --get \ "${LIGHTER_SETUP_API_URL}/api/v1/accountsByL1Address" \ --data-urlencode "l1_address=${LIGHTER_SETUP_L1_ADDRESS}"Read the
indexfrom the required entry insub_accounts. A wallet can own a main account and several sub-accounts, each with a separate account index and API keys. -
On the selected account's API key page, choose Generate API Key. Use an unused index from
4through254; Lighter's API key documentation reserves indexes0-3for its interfaces, while255is an API query sentinel. -
Save the generated private key before closing the dialog. Lighter does not display it again.
-
Configure
account_index,api_key_index, andprivate_keydirectly, or use the environment variables listed in API credentials. The Nautilusaccount_idis separate from the venue account index: use an issuer from the table above, such asLIGHTER-001orLIGHTER_ROBINHOOD-001. -
Confirm that the target deployment recognizes the selected account and key indexes:
LIGHTER_SETUP_ACCOUNT_INDEX="123456" LIGHTER_SETUP_API_KEY_INDEX="4" curl -sS --get \ "${LIGHTER_SETUP_API_URL}/api/v1/apikeys" \ --data-urlencode "account_index=${LIGHTER_SETUP_ACCOUNT_INDEX}" \ --data-urlencode "api_key_index=${LIGHTER_SETUP_API_KEY_INDEX}"A successful response has
"code": 200and lists the selected key. This public lookup confirms the indexes, but it does not expose or validate the private key.
Lighter API keys authorize trading, private account access, and some withdrawal operations. Store the private key in a secret manager or protected environment configuration. Do not commit it to a repository or share it in logs.
Integrator attribution
On Lighter Mainnet, create and modify transactions from Plus and Premium accounts carry the
NautilusTrader integrator account index in L2TxAttributes to measure adapter usage. Maker and taker
integrator fees are zero. The execution client submits the required zero-fee
ApproveIntegrator approval during startup when the account is Plus or Premium and the API key is
not maker-only.
All other account tiers, sessions without an account snapshot, Lighter Testnet, and both Robinhood
environments leave L2TxAttributes empty and omit ApproveIntegrator during startup.
Robinhood Mainnet uses the account-level NAUTILUS referral code instead. During startup,
the execution client authenticates with the configured L2 API key and applies NAUTILUS to the
account's public L1 address. Selecting Robinhood Mainnet opts the account into this
attribution. Application failures log a warning and do not block trading. Robinhood Testnet
performs no referral attribution.
Custom venue names do not change either policy: attribution is evaluated from the typed deployment, environment, and fetched account tier.
On Lighter Mainnet, maker-only API keys cannot submit ApproveIntegrator. The execution client
detects these keys and skips automatic approval. Approval is account-scoped, so a non-maker-only
key on the same account must approve the integrator before a maker-only key can trade through the
adapter.
Revoking the approval
Use revocation as cleanup when leaving the adapter on a Lighter Mainnet account that has previously
approved the integrator, including a Standard account approved by an older adapter version. It sends
ApproveIntegrator with approval_expiry = 0 and zero max fees. The next Plus or Premium Lighter
Mainnet execution-client startup with a non-maker-only key records a new zero-fee approval.
export LIGHTER_API_KEY_INDEX=5
export LIGHTER_API_SECRET=REPLACE_ME
export LIGHTER_ACCOUNT_INDEX=123456
cargo run -p nautilus-lighter --bin lighter-integrator-revoke # Lighter MainnetScript source:
crates/adapters/lighter/bin/integrator_revoke.rs.
# Python (PyO3 binding) - reads the same env vars as the Rust bin
from nautilus_trader.adapters.lighter import revoke_lighter_integrator
await revoke_lighter_integrator() # Lighter Mainnet (default)The Rust script prints a summary of the action and pauses for an Enter keypress before signing or
sending; abort with Ctrl+C before that point if anything in the summary looks wrong. The Python
binding does not prompt: review the active env vars yourself before calling.
Data subscriptions
| Data type | Sub. | Snapshot | Hist. | Nautilus type | Notes |
|---|---|---|---|---|---|
| Instrument metadata | Cache replay | ✓ | - | InstrumentAny | Loaded from orderBookDetails. |
| Trade ticks | ✓ | - | ✓ | TradeTick | WebSocket trades; public recentTrades REST history. |
| Quote ticks | ✓ | - | - | QuoteTick | Best bid and ask ticker stream. |
| Order book deltas | ✓ | ✓ | - | OrderBookDeltas | L2_MBP only. |
| Order book depth | ✓ | - | - | OrderBookDepth | Live top-10 view from maintained book; no REST snapshot. |
| Order book snapshots | - | ✓ | - | OrderBook | REST snapshot, max depth 250. |
| Mark prices | ✓ | - | - | MarkPriceUpdate | Perp market stats stream. |
| Index prices | ✓ | - | - | IndexPriceUpdate | Market and spot stats streams. |
| Funding rates | ✓ | - | ✓ | FundingRateUpdate | Current estimates and REST hourly history. |
| Bars | ✓ | - | ✓ | Bar | WebSocket candle stream; REST history for backfill. |
| Instrument status | REST | ✓ | - | InstrumentStatus | active / inactive snapshots. |
Only BookType::L2_MBP is accepted for book-delta and depth subscriptions. Other book types
return an error before subscribing.
The WebSocket order book initializes only from subscribed/order_book. If an update/order_book
arrives before that snapshot, the adapter drops it and waits for the real snapshot because
incremental updates do not contain the full visible book.
Depth subscriptions use the same WebSocket order_book stream as deltas. The adapter emits a
refreshed top-10 view after each accepted snapshot or incremental update.
Bar subscriptions use the venue's candle/{market_id}/{resolution} WebSocket channel. Lighter
batches in-progress updates for the open bar every ~500 ms; the adapter emits a Nautilus Bar
only when the candle start timestamp advances, so consumers see one event per closed period. The
in-progress cache is cleared on reconnect and on unsubscribe.
The stream supports 1m, 5m, 15m, 30m, 1h, 4h, 12h, and 1d. 1w is REST-only via
request_bars; subscribing to a 1-WEEK bar type returns an error.
REST bar history omits venue gap rows whose open, high, low, or close is missing, null, zero, or negative. These rows cannot form valid Nautilus bars and do not stop later valid rows from loading.
Instrument status subscriptions replay the latest cached orderBookDetails status when available
and otherwise fetch a REST snapshot. Lighter does not expose a WebSocket status-change stream.
See Funding rates for live and historical funding semantics.
Trade subscriptions use the public WebSocket trade stream. Historical trade requests use the
public /api/v1/recentTrades endpoint, which needs no credentials; the adapter clamps the
request to the venue per-call cap and filters the returned ticks to the requested time range.
Unsupported data requests
request_quotes is not implemented. Lighter exposes best bid and offer data through the
WebSocket ticker stream, but the REST endpoints available to the adapter do not provide a
timestamped quote snapshot or quote history that can map safely to QuoteTick.
request_book_depth is not implemented. The documented REST book endpoints do not provide a
venue event timestamp for OrderBookDepth.ts_event; use subscribe_book_depth for a live
depth stream or request_book_snapshot for a REST OrderBook snapshot.
Order book recovery
Sequence validation
The adapter checks each incremental update's begin_nonce against the previous book's nonce.
A mismatch suppresses book output and starts an unsubscribe/subscribe replacement.
The venue's offset is not a continuity counter: it can skip values and change across servers on
reconnect. See the Lighter order book contract.
Snapshot requirements
Initial and replacement subscriptions wait up to book_snapshot_timeout_secs (default 10 seconds)
for a typed subscribed/order_book snapshot after the subscription write completes. Set it to 0
to disable snapshot deadlines. A missing snapshot starts or retries recovery, including when a
control acknowledgement or Already Subscribed response arrives without a book.
Control acknowledgements release subscription slots but do not complete book recovery.
Book output resumes only after a matching snapshot replaces the cached levels. An empty snapshot clears the book too.
Retry limits and reconnects
Each recovery episode makes up to eight replacement attempts within 180 seconds, with exponential backoff and jitter, then continues at an interval that doubles from one minute to fifteen minutes until a snapshot is accepted. Replacement unsubscribe and subscribe writes target the same connection.
Reconnect retires obsolete subscription generations and keeps a running recovery with its remaining budget. A recovery waiting between attempts after its budget retries at once on the new connection.
Consumers and persistent failures
Deltas and depth share a recovery episode for each market:
- Removing one consumer preserves the other.
- Removing the final consumer cancels pending writes and snapshot waits.
- Shutdown cancels all owned work.
Recovery never ends in a failed state. A rejected replacement, or a subscription rejected when replayed after reconnect, keeps recovering at the growing interval, so a late snapshot still restores the book. A venue subscribe failure other than rate limiting fails the initial subscribe call instead while that call waits, even after a recovery has started. The recovery then continues only while another consumer remains. A later subscribe starts afresh. Other markets continue independently.
See Order book recovery ownership for the shared recovery machinery and adapter responsibilities.
Live recovery validation
The lighter-book-stress harness is a development tool for changes to book synchronization and
recovery. It uses Lighter mainnet public market data, submits no orders, and checks six perpetual
books against the book stream contract, including rising nonces within each snapshot episode, and
against an independent reconstruction of the venue feed's best 20 levels.
From the repository root, run:
CARGO_BUILD_JOBS=16 bash scripts/strip-adapter-env.bash \
cargo test -p nautilus-lighter --features examples --test lighter-book-stress -- --timeout 10 --rounds 12--scenario selects the run:
churn(default): checks recovery without reconnects, then rotates nonce gaps, dropped and delayed snapshots, rejected replacements, reconnects, and a restart during recovery.initial: drops each book's first snapshot, in a fresh session per round.boundaries: rejects every attempt in the retry budget, then checks the retry ceiling, a reconnect that ends the ceiling wait, unsubscribe during recovery, and shutdown during a reconnect.
--timeout sets the snapshot timeout in seconds, where 0 disables snapshot deadlines, and
--rounds sets the number of rounds (12 by default).
The harness requires the mainnet WebSocket stream and the public orderBooks and orderBookDetails
APIs. See Stress harnesses for the shared
flags and output format.
Orders capability
Order identification
Lighter uses a numeric venue order index and a caller-supplied client_order_index.
The adapter derives a 31-bit index from the Nautilus ClientOrderId and probes forward on a
collision. Because the collision-probed value cannot be re-derived after restart, order
reconciliation resolves each raw venue order ID through the core cache and restores its actual
client_order_index before translating order and fill reports. Open cached orders return to active
tracking, while terminal orders use bounded replay tracking.
Recovery never infers a client order ID from the integer alone: the cached venue order ID must match. It requires reconciliation to include the order and the core cache to retain its venue-order-ID mapping; otherwise reports use the unique venue order ID as their external client order ID.
Query paths use the numeric venue order ID for active or terminal history. Before that ID is known, a Nautilus client order ID can query active orders by its derived client index. Client-index-only queries do not search terminal history, and duplicate active matches fail as ambiguous.
Order types
| Order type | Perpetuals | Spot | Notes |
|---|---|---|---|
MARKET | ✓ | ✓ | Cap derived from cached far-side quote + slippage. |
LIMIT | ✓ | ✓ | Requires a limit price. |
STOP_MARKET | ✓ | - | Perp only; cap derived from trigger_price + slippage. |
STOP_LIMIT | ✓ | - | Perp only; maps to Lighter stop-loss limit orders. |
MARKET_IF_TOUCHED | ✓ | - | Perp only; cap derived from trigger_price + slippage. |
LIMIT_IF_TOUCHED | ✓ | - | Perp only; maps to Lighter take-profit limit orders. |
MARKET_TO_LIMIT | - | - | Not supported. |
TRAILING_STOP_MARKET | - | - | Not supported. |
TRAILING_STOP_LIMIT | - | - | Not supported. |
TWAP | - | - | Not supported; no Nautilus mapping. |
Conditional orders require trigger_price. The adapter rejects missing triggers for STOP_MARKET
and MARKET_IF_TOUCHED, any trigger that truncates to 0 ticks at the instrument's price
precision, and spot conditionals that Lighter does not support.
Lighter requires a worst-acceptable price for market-style orders. The adapter starts from the
cached far-side QuoteTick for MARKET, or trigger_price for STOP_MARKET and
MARKET_IF_TOUCHED, then applies market_order_slippage_bps (default 50 bps) and rounds at the
instrument's price precision, up for buys or down for sells. A MARKET order without a cached
quote is denied. Override the slippage with SubmitOrder.params["market_order_slippage_bps"].
Contingent orders
| Feature | Perpetuals | Spot | Notes |
|---|---|---|---|
| Stop-loss market | ✓ | - | STOP_MARKET maps to Lighter STOP_LOSS. |
| Stop-loss limit | ✓ | - | STOP_LIMIT maps to Lighter STOP_LOSS_LIMIT. |
| Take-profit market | ✓ | - | MARKET_IF_TOUCHED maps to Lighter TAKE_PROFIT. |
| Take-profit limit | ✓ | - | LIMIT_IF_TOUCHED maps to TAKE_PROFIT_LIMIT. |
| Trigger price | ✓ | - | Required for every supported conditional order. |
| Trigger price type | - | - | Not supported; no trigger source selector. |
| Grouped order lists | - | - | Not supported. |
| OCO / OTO orders | - | - | Not supported. |
| Bracket orders | - | - | Not supported. |
CreateGroupedOrders | - | - | Not supported; order lists use independent txs. |
Order options
| Option | Perpetuals | Spot | Notes |
|---|---|---|---|
post_only | ✓ | ✓ | Maps to Lighter's post-only time-in-force. |
reduce_only | ✓ | - | Passed through to CreateOrder; use only to reduce an existing position. |
quote_quantity | - | - | Not supported; submit base quantity instead. |
display_qty | - | - | Not supported; Lighter exposes no iceberg display quantity field. |
Adapter order params
| Param | Perpetuals | Spot | Notes |
|---|---|---|---|
market_order_slippage_bps | ✓ | ✓ | Overrides the config default for market-style caps. |
post_only through SubmitOrder.params | - | - | Not supported; use the Nautilus order flag. |
reduce_only through SubmitOrder.params | - | - | Not supported; use the Nautilus order flag. |
Time in force
| Time in force | Perpetuals | Spot | Notes |
|---|---|---|---|
GTC | ✓ | ✓ | Limit-style uses GoodTillTime; market-style uses IOC. |
DAY | ✓ | ✓ | Limit-style and conditional orders use a positive order expiry. |
GTD | ✓ | ✓ | Native expiry is 5 minutes to 30 days; see the managed-GTD policy below. |
IOC | ✓ | ✓ | Plain MARKET/LIMIT use expiry 0; conditional limit uses trigger expiry. |
FOK | - | - | Not supported. |
AT_THE_OPEN | - | - | Not supported. |
AT_THE_CLOSE | - | - | Not supported. |
The adapter sends MARKET, STOP_MARKET, and MARKET_IF_TOUCHED as Lighter
ImmediateOrCancel; the venue rejects market-style GoodTillTime orders. Plain MARKET uses
OrderExpiry = 0, while conditional market orders keep a positive expiry until triggered.
The adapter denies Nautilus IOC for conditional market orders because Lighter reserves IOC for
post-trigger execution. Conditional limit orders can use IOC: their trigger rests with a positive
expiry, then the child uses ImmediateOrCancel.
Without an explicit GTD expiry, limit-style GTC, DAY, and GTD orders default to the current
time plus 28 days; conditional GTC, DAY, and limit-style IOC use the same default. The
adapter uses this explicit 28-day expiry because the venue has rejected -1 in these paths with
21711 invalid expiry. Explicit native GTD expiries are currently validated from 5 minutes to 30
days after submission, with a one-second signing and transport margin on the lower bound.
GTD policy
Use local management for short-lived orders and venue-native GTD for longer-lived orders.
use_gtd=True is the default. The strategy expire_time becomes the venue GoodTillTime expiry
and must lie within the adapter's current 5-minute to 30-day validation window.
Set use_gtd=False only when the submitting strategy has manage_gtd_expiry=True. Lighter exposes
no GoodTillCancel time-in-force, so the opt-out cannot switch the wire time-in-force the way the
Binance adapter does: the order still rests as GoodTillTime on the venue's default 28-day
fallback window, while Nautilus cancels it locally at the strategy expiry. The native 5-minute
lower bound is not applied in this mode, but local strategy expiries beyond 28 days are rejected;
use native GTD for those orders. Venue cancel latency still bounds how quickly a locally managed
order is removed.
Execution instructions
| Instruction | Perpetuals | Spot | Notes |
|---|---|---|---|
post_only | ✓ | ✓ | Overrides the TIF and sends Lighter PostOnly. |
reduce_only | ✓ | - | Position-reducing flag for existing derivative positions. |
Use post_only on limit-style orders. The adapter does not synthesize maker-only market orders.
Live Lighter Mainnet testing confirms reduce_only=true for closing perpetual positions. Invalid
reduce-only opens can be dropped by Lighter without a venue order report; the adapter reconciles
them as INFLIGHT_TIMEOUT rather than a venue-supplied rejection reason.
Advanced order features
| Feature | Perpetuals | Spot | Notes |
|---|---|---|---|
| Order modification | ✓ | ✓ | Modify quantity, price, and trigger price on a live order. |
| Bracket orders | - | - | Not supported. |
| Iceberg orders | - | - | Not supported. |
| Trailing stops | - | - | Not supported. |
| Pegged orders | - | - | Not supported. |
| TWAP orders | - | - | Not supported; no Nautilus mapping. |
| Leverage update | ✓ | - | Perp only; submits a signed UpdateLeverage tx. |
| Native cancel-all | - | - | Not supported; adapter scopes cancel-all per instrument. |
| Dead man's switch | - | - | Not supported. |
Order operations
| Operation | Perpetuals | Spot | Notes |
|---|---|---|---|
| Submit order | ✓ | ✓ | Sends a signed L2CreateOrder transaction over WebSocket. |
| Submit order list | ✓ | ✓ | Sequential fanout of up to 15 independent create transactions. |
| Modify order | ✓ | ✓ | Sends a signed ModifyOrder; reports may restate accepts. |
| Cancel order | ✓ | ✓ | Sends a signed L2CancelOrder transaction. |
| Cancel all orders | ✓ | ✓ | Cancels cached orders by instrument and optional side. |
| Set leverage | ✓ | - | Perp only; submits a signed UpdateLeverage tx. |
| Batch cancel orders | ✓ | ✓ | WebSocket batches of up to 15 signed cancel transactions. |
| Query order | ✓ | ✓ | Requires credentials and REST lookup. |
| Query account | ✓ | ✓ | Replays the latest private WebSocket account state. |
| Mass status | ✓ | ✓ | Bounded to account-active markets from WS and REST reports. |
SubmitOrderList signs and sends each child transaction in order through the hash-correlated
WebSocket sendTx path, allocating each nonce after the prior handoff completes.
BatchCancelOrders uses WebSocket jsonapi/sendtxbatch with sequential nonces from the same API key.
CancelAllOrders splits selected orders into batches of up to 15 transactions, including sided
requests. An explicit BatchCancelOrders request containing more than 15 orders is rejected;
automatic chunking applies to CancelAllOrders. A selection of 45 orders normally produces three
15-transaction batches, but concurrent nonce allocation can produce smaller batches. The account's
active-order limits still apply: a Standard account cannot hold
45 active orders on one market.
Each batch uses one API key with consecutive nonces, as required by Lighter's
nonce contract. The adapter uses
skip_nonce=0, so it must preserve nonce order. Its local window permits 16 unconfirmed nonce
allocations per key; this is an adapter capacity limit, not a venue allowance for out-of-order
transactions. Unsigned cancellations wait for capacity or nonce recovery instead of being discarded.
Shutdown stops new dispatch and drops any remaining queued work. Batch responses correlate through
the request ID and each signed transaction hash.
A pre-admission rejection fails the whole batch without consuming its nonces; an invalid-nonce response also triggers nonce refresh. An acknowledgement confirms transaction admission, not order cancellation. Individual cancellations can fail after admission while other transactions in the batch succeed; these execution failures consume their nonces. Order updates and transaction lookups resolve cancellation outcomes. Ambiguous delivery retains pending state for reconciliation instead of resending the batch. Before signing the next chunk, the adapter waits up to 10 seconds for the current chunk's acknowledgements. A timeout allows dispatch to continue while retaining unacknowledged entries for reconciliation. Neither operation provides atomic execution, grouped orders, OCO/OTO, or bracket semantics.
UpdateLeverage is exposed as LighterExecutionClient::update_leverage(instrument_id, initial_margin_fraction, margin_mode). The initial_margin_fraction is in venue ticks
(1e-4 fraction): 500 is 5% initial margin (20x leverage), 1000 is 10% (10x), and so on.
UpdateLeverage, CancelAllOrders, modify orders with integrator attributes, and conditional
create orders are byte-pinned against the signer distributed with the official lighter-python
SDK version 1.1.4.
Order querying and reconciliation
| Feature | Perpetuals | Spot | Notes |
|---|---|---|---|
| Query open orders | ✓ | ✓ | REST accountActiveOrders scoped by market. |
| Query order history | ✓ | ✓ | REST accountInactiveOrders with cursor pagination. |
| Order status updates | ✓ | ✓ | Private WebSocket order streams plus status reports. |
| Trade history | ✓ | ✓ | REST trades; credentials are required for account history. |
| Fill reports | ✓ | ✓ | REST and private WebSocket trade payloads. |
| Position reports | ✓ | - | Perp only; replays cached position stream. |
| Account state | ✓ | ✓ | Replays the cached merged account state snapshot. |
| Mass status | ✓ | ✓ | Combines orders, fills, and cached positions. |
Authenticated inactive-order and fill pagination rejects repeated cursors and stops after 1,000 pages. Fill reconciliation remains repeatable across calls while suppressing fills already emitted from the live WebSocket stream. Historical order and fill reports bind a mapped client index only to its matching venue order ID so reused numeric indexes cannot merge unrelated lifecycles.
Each bounded mass status captures one cutoff for its inactive orders and fills. The adapter marks the report set complete only when the required order, fill, and position sources succeed and every historical fill maps to its order. If a historical source fails, active orders and explicit position reports remain available for reconciliation. Incompleteness does not veto a position report. Bounded historical fills without an in-scope position report follow the engine's order-only projection rules.
The trades endpoint retains only the most recent 3,000 trades per account_index, so a bounded
lookback can request more fill history than the venue serves. Pagination walks back from the newest
trade, and only a trade older than the lookback start proves the window was served:
- Trade older than the start: the report set stays complete.
- Cursor exhausted first: the adapter logs the uncovered span and marks the report set incomplete.
- No retained trades: nothing can have been truncated, so the report set stays complete.
An exhausted cursor cannot distinguish truncation from an account with no older trades, so a young
account reports incomplete even though nothing is missing. Choose a lookback the venue can serve.
The export endpoint serves full trade history for auditing fills the lookback cannot cover, and
the adapter does not read it.
A strategy that opens a position immediately on start can trigger a transient position-check
discrepancy warning (cached=0, venue=N) when the venue's account_all_positions frame arrives a
few milliseconds before the matching fill event is processed. The warning self-resolves once the
fill applies; no reconciliation orders are generated.
Account and position management
Authenticated execution clients subscribe to these private streams:
account_all_orders: order status reports.account_all_trades: fill reports.account_all_positions: initial position snapshot and live updates.account_all_assets: per-asset balance snapshots (spot balance plus perp collateral).user_stats: perp-account margin rollup (collateral and available balance).
The adapter merges account_all_assets and user_stats into a single account state and emits it
only after both streams have delivered their first frame.
The execution client requires credentials before connecting because private account streams and
nonce refresh are mandatory. A client can be constructed without credentials, but live execution
will not connect until private_key, account_index, and api_key_index resolve.
Perpetual positions use netting mode with one position per market; spot balances use account asset
state. A subscribed/account_all_positions frame is an authoritative snapshot: omitted markets and
rows with a zero position value flatten cached positions, and an empty positions map flattens the
entire cache. Cached positions for rows the adapter cannot map or parse are retained, so they do not
cause false flat reports.
For bounded reconciliation, the adapter also records which markets the current connection's snapshot covers. A reconnect invalidates that coverage. An absent touched market produces an explicit flat report only after a current snapshot covers it; an unmapped or malformed row leaves the mass status incomplete instead of proving flat.
An update/account_all_positions frame is incremental. Non-zero rows replace the cached position for
their market, explicit zero rows flatten that market, and omitted markets remain cached. An empty
update retains all cached positions.
| Feature | Perpetuals | Spot | Notes |
|---|---|---|---|
| Account balances | ✓ | ✓ | Merged assets + user_stats, replayed from cache on query. |
| Position state | ✓ | - | Perp only; initial snapshot plus live updates. |
| Netting positions | ✓ | - | One Nautilus position per perpetual market. |
| Cross margin | ✓ | - | Passed through LighterPositionMarginMode::Cross. |
| Isolated margin | ✓ | - | Passed through LighterPositionMarginMode::Isolated. |
| Leverage updates | ✓ | - | Signed UpdateLeverage transaction. |
| Spot margin / borrowing | - | - | Not supported. |
| Deposits / withdrawals | - | - | Use venue tools or Lighter APIs outside the trading adapter. |
Liquidation and ADL handling
| Event or field | Support | Notes |
|---|---|---|
| Liquidation trades | ✓ | Account trade rows can parse as fills, with no special event. |
| Deleverage trades | ✓ | Account trade rows can parse as fills, with no special event. |
| Liquidation price reporting | - | Not supported; reports omit this field. |
| ADL event stream | - | Not supported. |
Funding rates
Perpetual market_stats frames emit MarkPriceUpdate, IndexPriceUpdate, and
FundingRateUpdate. The live funding update uses current_funding_rate as the upcoming estimate;
funding_rate and funding_timestamp describe the last completed payment. Because market stats
provide no future settlement time, live updates leave interval and next_funding_ns unset. Spot
spot_market_stats frames emit IndexPriceUpdate.
Historical requests use public /api/v1/fundings rows at 1h resolution and set interval=60.
direction=long stays positive, while short becomes negative. Pagination covers the requested
range up to the adapter's page cap, subject to an explicit limit; see
Rate limiting. Account-specific positionFunding is not used.
Account tiers
Lighter account tiers set latency, rate limits, fees, and integrator attribution. The execution
client reads the tier from GET /api/v1/account and logs it, including unknown raw account_type
values. Only Plus and Premium accounts include integrator approval and order attribution. If the
account snapshot is unavailable, the client also omits attribution for that session. The client does
not raise limits automatically because a local quota override does not grant a higher venue limit.
| Tier | Latency (maker / taker) | REST weighted limit | sendTx limit | Fees (maker / taker) | Notes |
|---|---|---|---|---|---|
| Standard | 200 ms / 300 ms | 60 req/min | 60 req/min | 0 / 0 | Zero-fee default tier. |
| Premium | 0 ms / 140-200 ms | 24,000 req/min | 4,000-48,000 req/min | 0.28-0.40 / 1.96-2.80 bps | Lowest latency; scales with staked LIT. |
| Plus | 200 ms / 300 ms | 24,000 req/min | 4,000 req/min | 0.5 / 0.5 bps | Raised limits, standard latency. |
| Builder | - | 240,000 req/min | - | - | Highest REST throughput. |
Premium figures scale with staked LIT and can change. Before raising a local quota, confirm that Lighter applies the matching tier limit to the client's traffic, then set the quota explicitly (see Rate limiting).
Rate limiting
Lighter limits both IP and L1 addresses. Each data and execution client owns a separate REST limiter and defaults to the standard-account quota. Configure their combined traffic within the venue limit.
Higher account tiers still require explicit client quotas:
rest_quota_per_min: REST read-bucket quota in requests per minute. Unset keeps 60 req/min. Available on both the data and execution clients.sendtx_quota_per_min: transaction quota in requests per minute, metered in a bucket separate from reads. Unset keeps it at the standard 60 req/min, independent ofrest_quota_per_min. Execution client only.
These options change local pacing only. Public data requests remain unauthenticated, so setting a higher local quota does not make those requests eligible for an account-level venue limit.
Transaction type limits
Lighter documents a default transaction-type limit of 40 requests per minute, with exceptions by
transaction type. This is separate from the account-tier sendTx/sendTxBatch request limit.
A Lighter Mainnet quoting session amending on every quote drift hit
code=23000 (Too Many Requests) after roughly 40 modify transactions in a minute; see
Volume quota and no-fill quoting for the related quota that
modify transactions also spend. Set sendtx_quota_per_min to 40 or lower for transaction-heavy
quoting workloads. The limiter is shared across all sendTx traffic, so a lower quota also paces
creates and cancels.
The local quotas allow bursts; they do not enforce a strict rolling-minute ceiling. A quota of 30 permits an initial burst of 30 requests while replenishing capacity at 30 per minute, so it can still exceed a venue limit of 40 requests in 60 seconds. Leave headroom for that burst and for other clients sharing the L1 address. For bounded Standard-account testing, 15 transaction requests and 5 REST calls per minute leave room for independent account checks.
An uncorrelated WebSocket 23000 response is logged without rejecting a particular transaction.
It can apply to non-transaction traffic, so the adapter does not guess which order or batch failed.
Pending outcomes require reconciliation; do not resend them blindly.
The REST limiter counts one token per call rather than venue endpoint weights. Set
rest_quota_per_min for the effective endpoint mix: a 24,000 weighted req/min premium limit yields
40 calls/minute to /api/v1/recentTrades (weight 600), or 120 calls/minute to
/api/v1/trades (weight 200), before accounting for other requests.
The venue meters transaction requests per L1 address across HTTP and WebSocket in one bucket.
A batch counts as one sendTxBatch request and can carry up to 15 transactions. Standard accounts
remain subject to the 60-request-per-minute limit; the separate venue read and transaction buckets
apply to Plus and Premium accounts. The adapter keeps separate local read and transaction limiters,
so Standard users must budget their combined traffic, including nonce and reconciliation reads.
The execution client enforces sendtx_quota_per_min with a single shared limiter across WebSocket sendTx
and sendTxBatch (including order lists and cancellation batches), and the HTTP sendTx used for
startup integrator approval. Low-level raw sendTx and sendTxBatch calls use that limiter when the client is
constructed with it; otherwise, they fall back to the raw client's REST limiter.
The clients share one WebSocket message limiter per venue URL. It paces non-transaction control
frames at 200 messages/minute across both clients. A closed-loop subscription gate caps
unacknowledged requests at 35, below the venue's 50-message per-IP ceiling; this count depends on
acknowledgement latency, not send rate. sendTx and sendTxBatch do not count against the
client-message bucket or its 50-message inflight cap.
| Scope | Venue limit | Adapter behavior |
|---|---|---|
| REST, standard account | 60 req/min | Default; set rest_quota_per_min to override. |
| REST, premium account | 24,000 weighted req/min | Local override required; venue attribution applies. |
| REST, plus account | 24,000 weighted req/min | Local override required; venue attribution applies. |
| REST, builder account | 240,000 weighted req/min | Local override required; venue attribution applies. |
sendTx / sendTxBatch, standard | 60 req/min | Shared with REST reads; includes HTTP and WebSocket. |
sendTx / sendTxBatch, premium | 4,000-48,000 req/min | Set sendtx_quota_per_min (scales with staked LIT). |
sendTx / sendTxBatch, plus | 4,000 req/min | Set sendtx_quota_per_min to use it. |
| Default transaction type limit | 40 req/min | Applies to tx types not covered by volume quota. |
L2UpdateLeverage transaction limit | 40 req/min | Relevant to update_leverage. |
Active and pending order limits
Lighter's rate-limit documentation specifies these limits by account tier. Each per-market cap applies within the account.
| Account tier | Active per account | Active per market | Pending per account | Pending per market |
|---|---|---|---|---|
| Standard | 250 | 30 | 50 | 10 |
| Plus | 750 | 250 | 500 | 100 |
| Premium | 1,500 | 1,000 | 1,000 | 100 |
Active orders rest on the book. Venue-pending orders include untriggered take-profit, stop-loss,
and TWAP orders; these counts are separate from Nautilus PendingCancel and from unacknowledged
transaction requests. The adapter does not pre-count these venue limits. Leave room for existing
orders when placing new ones. Standard accounts support at most 30 active orders on each market
and 250 across the account. Increasing local quotas does not raise these caps.
Endpoint weights and transport limits
Common REST endpoint weights from the official docs:
| Endpoint group | Weight | Adapter behavior |
|---|---|---|
sendTx, sendTxBatch, nextNonce | 6 | Tx calls use tx limiter; nextNonce uses REST. |
accountInactiveOrders | 100 | Adapter counts one REST token per HTTP call. |
trades | 200 | Adapter counts one REST token per HTTP call. |
recentTrades | 600 | Adapter counts one REST token per HTTP call. |
| Other endpoints | 300 | Adapter counts one REST token per HTTP call. |
| Endpoint or transport | Limit | Notes |
|---|---|---|
/api/v1/trades | 100 rows | Adapter paginates reconciliation at this cap. |
/api/v1/accountInactiveOrders | 100 rows | Adapter follows next_cursor at this cap. |
/api/v1/orderBookOrders | 250 levels | Snapshot depth is clamped to the venue cap. |
/api/v1/candles | 500 rows | Adapter caps REST bar pages at this venue maximum. |
/api/v1/fundings | 100 rows | Adapter paginates funding pages at this venue cap. |
| WebSocket connections | 255 / IP | Venue limit. |
| WebSocket subscriptions / connection | 500 | Venue limit. |
| WebSocket unique accounts / connection | 500 | Venue limit. |
| WebSocket connections / minute | 255 | Venue limit. |
| WebSocket client messages / minute | 200 | Paces non-tx frames; heartbeat pings bypass it. |
| WebSocket inflight messages | 50 | Venue cap; subscriptions use a 35-frame closed loop. |
WebSocket sendTxBatch batch size | 15 txs | Cancel-all chunks; explicit batches above 15 are rejected. |
| WebSocket keepalive | 2 minutes | Adapter sends heartbeats every 30 seconds. |
| WebSocket outbound command queue | Not capped | Paced before writes; no queue-depth cap. |
Historical bar and funding-rate requests stop after 500 REST pages. This covers up to 250,000 bars
or 49,500 hourly funding intervals. If the cap leaves part of the requested range uncovered, the
HTTP client returns LighterHttpError::HistoryIncomplete instead of partial history and does not
retry the capped request. Completion on the final allowed page remains successful. A request with
an explicit start also remains successful when its explicit limit is satisfied. The data client
logs the incomplete error and emits no response; narrow the requested range to continue.
Volume quota and no-fill quoting
Volume quota is separate from transport limits. L2CreateOrder, L2CancelAllOrders,
L2ModifyOrder, and L2CreateGroupedOrders spend it; completed volume and any free allowance
replenish it. The adapter does not inspect remaining quota. See Lighter's
Volume Quota documentation for current
rules and figures.
Repeated no-fill quote refreshes can exhaust this quota even when the WebSocket and sendTx
limiters work. For live tests, prefer slower one-sided quoting, wider refresh thresholds, testnet,
or a bounded strategy that earns enough fills to replenish its quota.
Connection management
The WebSocket client sends heartbeats every 30 seconds and reconnects with exponential backoff from 250 milliseconds to 30 seconds. It treats a connection carrying no inbound frame for 90 seconds as dead and reconnects, which recovers a stalled socket that the venue never closes. The venue answers each heartbeat with a pong, so a healthy connection refreshes that window even when no market data flows. Private subscriptions use auth tokens with an 8-hour maximum TTL; the adapter mints 7-hour tokens, rotates them every 6 hours, and resubscribes. A transparent reconnect triggers a fresh token and account resubscription after tracked subscriptions start replaying.
On execution reconnect, the adapter starts a nonce-baseline refresh through
GET /api/v1/nextNonce. Submit, modify, and single-cancel commands cannot sign until that refresh,
or its background retry, installs the replacement connection's nonce baseline. Batch cancellations
wait for nonce readiness, including requests received during the refresh.
Within a session, venue confirmations advance the local nonce window, definitive rejections or
pre-handoff failures may roll back its latest nonce, and stale state triggers a
GET /api/v1/nextNonce resync. Outcomes that may have reached the venue retain their pending nonce
and order identity for WebSocket or reconciliation recovery.
LighterExecutionClient::connect() waits up to 30 seconds for every account stream
(account_all_orders, account_all_trades, account_all_positions, account_all_assets,
user_stats) to satisfy its readiness condition. For positions, only the
subscribed/account_all_positions snapshot satisfies this wait; a live update does not. The adapter
does not use REST account payloads as a fallback, so connect() blocks on these streams as its ground
truth. Each attempt clears old position and account caches before awaiting the session's frames.
Transparent WebSocket reconnects and auth-token rotations do not re-enter connect(). Both retain
cached positions until the next subscribed/account_all_positions frame applies the snapshot
replacement rules. Live update frames merge into the retained cache without evicting omitted
markets.
API credentials
Lighter signing requires all three credential values:
- Account index: numeric Lighter account identifier.
- API key index: numeric API key slot. Lighter reserves indexes
0-3; use a user-created key in the4-254range. Do not use255; it is anapikeysquery sentinel, not a signing key. - API private key: 40-byte hex private key, with or without a
0xprefix.
Config values take precedence. A missing config field, or a blank API private key (empty or
whitespace only), falls back to the corresponding environment variable selected by deployment
and environment.
| Deployment | Environment | API key index | API private key | Account index |
|---|---|---|---|---|
| Lighter | Mainnet | LIGHTER_API_KEY_INDEX | LIGHTER_API_SECRET | LIGHTER_ACCOUNT_INDEX |
| Lighter | Testnet | LIGHTER_TESTNET_API_KEY_INDEX | LIGHTER_TESTNET_API_SECRET | LIGHTER_TESTNET_ACCOUNT_INDEX |
| Robinhood | Mainnet | LIGHTER_ROBINHOOD_API_KEY_INDEX | LIGHTER_ROBINHOOD_API_SECRET | LIGHTER_ROBINHOOD_ACCOUNT_INDEX |
| Robinhood | Testnet | LIGHTER_ROBINHOOD_TESTNET_API_KEY_INDEX | LIGHTER_ROBINHOOD_TESTNET_API_SECRET | LIGHTER_ROBINHOOD_TESTNET_ACCOUNT_INDEX |
The four namespaces let one process run clients for multiple deployment targets without sharing credentials.
Execution rejects incomplete credentials. The data client runs without credentials: its subscriptions and REST requests (instruments, book, trades, bars, funding) all use public endpoints.
Configuration
Data client configuration options
| Option | Default | Description |
|---|---|---|
environment | Mainnet | LighterEnvironment::Mainnet or Testnet. |
deployment | Lighter | LighterDeployment::Lighter or Robinhood. |
venue | None | Optional Nautilus venue override; defaults from deployment. |
account_index | None | Optional factory field; public data calls do not use it. |
api_key_index | None | Optional factory field; public data calls do not use it. |
private_key | None | Optional factory field; public data calls do not use it. |
base_url_http | None | Optional REST URL override. |
base_url_ws | None | Optional WebSocket URL override. |
proxy_url | None | Optional proxy URL for HTTP and WebSocket. |
http_timeout_secs | 60 | HTTP request timeout in seconds. |
ws_timeout_secs | 30 | WebSocket connection and reconnection timeout. |
update_instruments_interval_mins | 60 | Instrument metadata refresh interval in minutes. |
book_snapshot_timeout_secs | 10 | Initial, reconnect, and recovery snapshot wait. |
rest_quota_per_min | None | REST quota override; unset keeps 60 req/min. |
transport_backend | Default | WebSocket transport backend. |
Execution client configuration options
| Option | Default | Description |
|---|---|---|
environment | Mainnet | LighterEnvironment::Mainnet or Testnet. |
deployment | Lighter | LighterDeployment::Lighter or Robinhood. |
venue | None | Optional Nautilus venue override; defaults from deployment. |
account_id | LIGHTER-001 | Nautilus account ID; issuer must match the resolved venue. |
account_index | None | Lighter account index. |
api_key_index | None | Lighter API key slot. |
private_key | None | Hex private key for auth and L2 transaction signing. |
base_url_http | None | Optional REST URL override. |
base_url_ws | None | Optional WebSocket URL override. |
proxy_url | None | Optional proxy URL for HTTP and WebSocket. |
http_timeout_secs | 60 | HTTP request timeout in seconds. |
ws_timeout_secs | 30 | WebSocket connection and reconnection timeout. |
market_order_slippage_bps | 50 | Slippage cap (bps) for MARKET / STOP_MARKET / MIT. |
rest_quota_per_min | None | REST quota override; unset keeps 60 req/min. |
sendtx_quota_per_min | None | Transaction quota override; unset keeps 60 req/min. |
transport_backend | Default | WebSocket transport backend. |
use_gtd | True | Use venue-native GTD; see GTD policy. |
Configuration example
use nautilus_lighter::{
common::enums::{LighterDeployment, LighterEnvironment},
config::{LighterDataClientConfig, LighterExecutionClientConfig},
};
use nautilus_model::identifiers::AccountId;
let data_config = LighterDataClientConfig::builder()
.environment(LighterEnvironment::Testnet)
.deployment(LighterDeployment::Lighter)
.build();
let exec_config = LighterExecutionClientConfig::builder()
.environment(LighterEnvironment::Testnet)
.deployment(LighterDeployment::Lighter)
.account_id(AccountId::from("LIGHTER-001"))
.build();
let robinhood_data_config = LighterDataClientConfig::builder()
.environment(LighterEnvironment::Mainnet)
.deployment(LighterDeployment::Robinhood)
.build();
let robinhood_exec_config = LighterExecutionClientConfig::builder()
.environment(LighterEnvironment::Mainnet)
.deployment(LighterDeployment::Robinhood)
.account_id(AccountId::from("LIGHTER_ROBINHOOD-001"))
.build();Each execution config resolves credentials from the environment-variable set selected by its
deployment and environment; set the credential fields directly to override them. Use
LiveExecutionEngineConfig.reconciliation_instrument_ids to scope reconciliation and
reconciliation_lookback_mins to bound inactive order and fill replay.
Official documentation
- Get started
- Trading and signing
- API keys
- Account types
- Rate limits
- Volume quota
- Data structures, constants, and errors
- REST OpenAPI
- WebSocket reference
Contributing
For additional features or to contribute to the Lighter adapter, please see our contributing guide.
Kraken
Kraken offers spot and derivatives trading across a wide range of digital assets. This integration connects to Kraken Pro and supports live market data and...
OKX
Founded in 2017, OKX is a cryptocurrency exchange that offers spot, margin, perpetual swap, futures, options, spread, and event contract trading. This...