Type/to search
Built-in Functions
Structures
Built-in Variables and Constants
Conventions
Exchanges
Capability Matrix
Centralized Exchanges
Decentralized Exchanges (DEX)
Hyperliquid
Lighter
edgeX
Aster
Aevo
Pendle
WOOFi Pro
Uniswap / PancakeSwap
Aerodrome / Velodrome
KyberSwap
1inch
EVM DEX Common Commands
Jupiter
OKX DEX
DEX Strategy Examples
Prediction Markets
Securities and Futures
On-chain & Custom

A perpetual-futures DEX on a zk rollup, quoted and settled in USDC. The exchange object connects to Lighter perpetuals: placing, modifying and canceling orders and setting leverage are L2 transactions signed with the API key private key, and open/historical order queries use an auth token generated with the same key. Create an API key on Lighter first and note its API key index and the account index.

Names and Configuration

exchange.GetName(): Futures_Lighter (Futures); aliases: zkLighter.

FieldRequiredDefaultDescription
API Key Private KeyYes—The API key private key created on Lighter (40-byte hex, 0x prefix optional), used to sign L2 transactions and generate auth tokens.
API Key IndexYes—API key index number, range 3-254 (0-2 reserved for system)
Account IndexYes—Lighter account index for identifying master or sub-account
SimulateNoUncheckedConnect to the Lighter testnet when checked.

Trading Pairs and Contract Codes

Pair examples: BTC_USDC, ETH_USDC

Only USDC-quoted perpetuals are listed; write the trading pair as BTC_USDC, and the full symbol looks like BTC_USDC.swap; other quote currencies are rejected. Pairs are case-insensitive and returned in upper case.

Contract codeDescription
swapUSDC perpetual contract (the only contract type).

Lighter lists perpetuals only; contract codes other than swap are rejected.

Exchange-specific IO Commands
CommandArgumentsDescriptionReturns
crossbool[, symbol]Cross (true) / isolated (false) margin, for the current contract when symbol is omitted. (more below the table){symbol, leverage, marginMode, initialMarginFraction, txHash, ok}; txHash is the hash of the on-chain transaction.
expirynumberLifetime of subsequent limit orders and conditional orders (milliseconds, must be greater than 0), 29 days by default (the exchange's maximum); an order expires at the time of placing plus 10 minutes plus this duration. Market orders are not affected.true
apimethod, path[, params[, raw[, sign]]]Call a Lighter endpoint directly; only GET and POST are supported. (more below the table)The raw exchange response; an error is raised when the response code is not 200.

The rest of the longer descriptions in the table:

  • cross: Lighter sets margin mode and leverage in the same on-chain transaction, which also writes the instrument's current leverage (read from the instrument's setting in the exchange account data; a value set in this run within the last 60 seconds takes precedence; the market's default leverage when neither exists).
  • api: By default the auth token generated with the API key private key is attached (the private key and account index must be filled in); with sign set to false (it may also be given directly as the 4th argument) no token is sent, which only works for public GET endpoints. raw is not a request body but a parameter table (a JSON object or a=1&b=2) that replaces params entirely when non-empty; it goes into the query string for GET and a form body for POST. L2 transactions are not signed for the caller.

For the common commands base and currency see exchange.IO.

Common Usage
Set the lifetime of limit orders
javascript
function main() { // Later limit and conditional orders expire 10 minutes plus 1 hour after they are placed // (29 days by default); market orders are not affected exchange.IO("expiry", 60 * 60 * 1000) var id = exchange.CreateOrder("ETH_USDC.swap", "buy", 2000, 0.01) Log("Order ID:", id) }
Call public endpoints and account endpoints that need the auth token with api
javascript
function main() { // Public endpoints: false as the 4th argument sends no auth token var books = exchange.IO("api", "GET", "/api/v1/orderBooks", {}, false) Log("Markets:", books.order_books.length) var d = exchange.IO("api", "GET", "/api/v1/orderBookDetails", {market_id: 0}, false) Log(d.order_book_details[0].symbol, "last:", d.order_book_details[0].last_trade_price) // Account endpoints carry the auth token by default; the account index is in the Info // of GetAccount() var idx = exchange.GetAccount().Info.account_index var params = {account_index: idx, market_id: 0} var r = exchange.IO("api", "GET", "/api/v1/accountActiveOrders", params) Log("Open orders on market_id 0:", r.orders.length) }

Function Support

No unsupported standard functions.

Served through a fallback:

  • exchange.GetRecords: Native periods are 1m, 5m, 15m, 30m, 1h, 4h, 12h, 1d, 1w; other periods are synthesized by the docker.

Margin, Account and Simulation

Margin mode: Switch cross/isolated margin per contract with exchange.IO("cross", bool) and set leverage with exchange.SetMarginLevel(). On Lighter both are the same on-chain transaction (UpdateLeverage); every call sends one and always writes both leverage and margin mode, keeping the other one at the instrument's current value: exchange.SetMarginLevel() keeps the current margin mode and exchange.IO("cross", ...) keeps the current leverage. The current values are read from the instrument's setting in the exchange account data (present even without a position); a value set in this run within the last 60 seconds takes precedence (the exchange data lags); without either, the market's default leverage and cross. exchange.SetMarginLevel() also accepts {marginMode: "isolated"} (or cross) in the extra parameters to set the margin mode at the same time. A position's MarginLevel is derived from the initial margin fraction in the exchange's position data.

Position mode: One-way (net) positions only; hedge mode is not supported.

Account: The account index selects the master account or a sub-account; the account and positions are queried by account index, and USDC is the only asset.

Simulation: The Simulate box connects to the Lighter testnet (https://testnet.zklighter.elliot.ai). The API address can also be switched with exchange.SetBase() (or exchange.IO("base", url)): transactions are signed for the testnet when the address contains testnet, otherwise for the mainnet.

Notes
FunctionBehavior on Futures_Lighter
exchange.GetTicker()Bid and ask come from the order book; the exchange's market data has no timestamp, so Time is the local time
exchange.GetTickers()Buy and Sell are each instrument's last trade price (the exchange has no batch order book endpoint); use exchange.GetTicker() or exchange.GetDepth() when you need the best bid and ask. Placeholder instruments whose last price, 24h high/low and volume are all zero are omitted
exchange.GetDepth()The exchange returns individual resting orders; each order is its own level and orders at the same price are not merged, so a price may appear more than once
exchange.GetFundings()Rate is the exchange's rate divided by 8 (an hourly rate), Interval is 1 hour and Time is the next full hour
exchange.CreateOrder()Limit orders support GTC (resting for the exchange.IO("expiry", ...) lifetime), IOC and post-only; FOK is not supported. A market order is an IOC order whose worst fill price is the best opposite price at the time of placing plus or minus a slippage (a buy no higher than the best ask × (1 + slippage), a sell no lower than the best bid × (1 − slippage)); the slippage defaults to 0.5% and can be set with the order extra parameter slippage (such as 0.01, greater than 0 and less than 1, the same parameter as for market conditional orders); whatever the book cannot fill within that price is canceled. An order that fills nothing is canceled with a DealAmount of 0, and status in Info gives the reason (such as canceled-too-much-slippage)
exchange.CreateConditionOrder()Take-profit and stop-loss only, no OCO. With an order price it is a limit conditional order; with an order price of -1 (market) it executes at market once triggered (IOC) with a worst fill price of the trigger price ±5% (up for buys, down for sells), adjustable with {slippage: 0.1} in the extra parameters
exchange.ModifyOrder()Modifies in place, the order ID stays the same; a price or amount that is not passed keeps its current value
exchange.GetOrders(), exchange.GetConditionOrders()The exchange API requires an instrument: without a symbol, or with an empty string, only the current instrument is queried. GetOrders returns limit and market orders only and GetConditionOrders take-profit/stop-loss orders only (other types such as TWAP appear in neither); range arguments such as USDC.swap are not supported
exchange.GetOrder()Searches only the open orders and the latest 100 historical orders of the instrument; older orders return null
exchange.ModifyConditionOrder()Modifies the amount, trigger price and order price in place; the order ID stays the same. The limit/market variant cannot change: an order price of -1 on a limit conditional order, or a positive one on a market conditional order, fails (cancel and recreate instead); a market conditional order's worst fill price is recomputed from the new trigger price
exchange.GetHistoryOrders(), exchange.GetHistoryConditionOrders()The exchange API requires an instrument: the current one is queried when omitted, and an empty string or a range raises an error; the since parameter is not supported and raises an error; without limit the latest 100 and 500 orders are returned respectively