edgeX
A perpetual-futures DEX (V2 API), with contracts quoted in USDC. Private endpoints are authenticated by HMAC with the edgeX Perps V2 API Key, API Secret and API Passphrase, and orders are additionally EIP-712-signed with the trading private key (SDK Signer); create both sets of credentials on edgeX and note the account ID before configuring the exchange object. Configurations from the old V1 scheme (only AccountID and the StarkEx private key Secret Key) no longer work: private endpoints report missing V2 credentials, so create V2 API credentials on edgeX and fill in all five fields.
Names and Configuration
exchange.GetName(): Futures_EdgeX (Futures); aliases: EdgeX.
| Field | Required | Description |
|---|---|---|
| AccountID | Yes | The edgeX account ID (numeric). |
| API Key | Yes | The edgeX Perps V2 API Key, used with the API Secret and API Passphrase for HMAC authentication of private endpoints. |
| API Secret | Yes | The edgeX Perps V2 API Secret (HMAC key). |
| API Passphrase | Yes | The edgeX Perps V2 API Passphrase. |
| Trading Private Key | Yes | The private key (hex) of the edgeX Perps V2 SDK Signer, used for the EIP-712 signature of orders; the IO command calcOrderHashAndSign also uses it for Stark signatures. |
Trading Pairs and Contract Codes
Pair examples: BTC_USDC, ETH_USDC
All edgeX perpetuals are quoted in USDC: write the trading pair as BTC_USDC and so on, with full symbols such as BTC_USDC.swap; BTC_USDT or BTC_USD fails with the error symbol not found: BTCUSDT (or BTCUSD). exchange.SetCurrency() keeps the case as given (exchange.GetCurrency() returns it unchanged), contracts are looked up case-insensitively; symbols in data returned by the exchange (orders, positions, etc.) are upper case, while the Symbol of exchange.GetTicker() keeps the case passed in or currently set, so upper case is recommended.
| Contract code | Description |
|---|---|
swap | USDC perpetual contract (the only contract type). |
edgeX lists perpetuals only; contract codes other than swap are rejected.
Exchange-specific IO Commands
| Command | Arguments | Description | Returns |
|---|---|---|---|
calcOrderHashAndSign | json | Legacy (StarkEx) limit-order signature, kept only so that old strategies keep working; computes the Pedersen hash of a LIMIT_ORDER_WITH_FEES order and signs it with Stark ECDSA using the configured TradingPrivateKey. (more below the table) | A 128-character lowercase hex string (r and s, 64 characters each, without 0x). |
api | method, path[, params[, raw[, sign]]] | Call an edgeX endpoint directly. (more below the table) | The data of the response; an error is raised when the response code is not SUCCESS. |
The rest of the longer descriptions in the table:
calcOrderHashAndSign: The argument is a JSON string or object with 10 keys, see the notes. edgeX V2 orders use EIP-712 signatures and do not accept this signature, and this exchange object does not use it when placing orders.api: By default the request is HMAC-signed with the API Key, API Secret and API Passphrase (these three V2 credentials must be filled in); withsignset tofalse(it may also be given directly as the 4th argument) it is sent unsigned, which only works forGET.GETparameters go into the query string, other methods send a JSON body.rawis not a request body but a parameter table (a JSON object, a JSON string ora=1&b=2) that replacesparamsentirely when non-empty. Orders are not EIP-712-signed for the caller.
For the common commands base and currency see exchange.IO.
Common Usage
Call public endpoints and signed account endpoints with api
javascript
function main() {
// Public endpoints: false as the 4th argument sends the request unsigned (GET only);
// the data of the response is returned
var meta = exchange.IO("api", "GET", "/api/v2/public/meta/getMetaData", {}, false)
var c = null
for (var i = 0; i < meta.contractList.length; i++) {
if (meta.contractList[i].contractName == "BTCUSDC") {
c = meta.contractList[i]
}
}
var p = {contractId: c.contractId}
var t = exchange.IO("api", "GET", "/api/v2/public/quote/getTicker", p, false)
Log(c.contractName, "contract ID:", c.contractId, "last:", t[0].lastPrice)
// Account endpoints are HMAC-signed by default; accountId is in the Info of GetAccount()
var accountId = exchange.GetAccount().Info.account.id
var params = {accountId: accountId, size: "50"}
var orders = exchange.IO("api", "GET", "/api/v2/private/order/getActiveOrderPage", params)
Log("Open orders:", orders.dataList.length)
}
Compute a legacy (StarkEx) limit-order signature for an old strategy
javascript
function main() {
// Exactly 10 keys; an accountID beyond JavaScript integer precision is a decimal string
var sig = exchange.IO("calcOrderHashAndSign", JSON.stringify({
assetIdSynthetic: "0x4554482d3900000000000000000000",
assetIdCollateral: "0x2ce625e94458d39dd0bf3b45a843544dd4a14b8169045a3a3d15aa564b936c5",
assetIdFee: "0x2ce625e94458d39dd0bf3b45a843544dd4a14b8169045a3a3d15aa564b936c5",
isBuyingSynthetic: true,
amountSynthetic: 10000000,
amountCollateral: 13020000,
amountFee: 6250,
nonce: 676432751,
accountID: "601416704693633632",
expirationTimestamp: 484831
}))
// 128 hex characters: the first 64 are r, the last 64 are s
Log("r:", sig.slice(0, 64), "s:", sig.slice(64))
}
Function Support
Not supported (the call fails with an error and returns null): exchange.GetTickers, exchange.GetTrades, exchange.ModifyOrder, exchange.ModifyConditionOrder, exchange.SetMarginLevel.
Served through a fallback:
exchange.GetRecords: Native periods are 1m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 1w, 1M; other periods that are a multiple of 60 seconds are synthesized by the docker from native bars, and the rest (such as second-level periods) are not available (the exchange has no trades endpoint).
Margin, Account and Simulation
Margin mode: edgeX uses cross margin; a position's MarginLevel is the current leverage reported by the exchange. exchange.SetMarginLevel() is not supported; set leverage on edgeX yourself.
Position mode: One-way (net) positions.
Account: The account, positions and orders are queried by the configured AccountID. exchange.GetAssets() lists collateral assets per coin, and exchange.GetAccount() takes the row of the current pair's quote currency (USDC).
Notes
| Function | Behavior on Futures_EdgeX |
|---|---|
| exchange.GetTicker() | The ticker endpoint has no bid/ask, so each call makes an extra order book request to fill them in (two requests in all); if the order book request fails, the whole call fails. Time is the server time of the order book response (as is the Time of exchange.GetDepth()), not the ticker's endTime (the end of the 24-hour statistics window, which advances in 15-minute steps); endTime is still available in Info |
| exchange.GetTickers() | Not supported: edgeX has no endpoint that returns the tickers of all contracts at once (its ticker endpoint returns an empty list without a contract ID), so the call reports an error and returns null. To get several contracts' tickers, call exchange.GetTicker(symbol) for each one (such as exchange.GetTicker("BTC_USDC.swap")) |
| exchange.GetFundings() | With a symbol (such as BTC_USDC.swap) it returns that contract's entry; without arguments it queries every tradable perpetual of the current quote currency (such as USDC.swap, which can also be passed directly). edgeX has no batch funding endpoint, so a range query sends one request per contract and takes over ten seconds for the hundred-plus contracts; pass a specific symbol when calling it often. Rate is the exchange's forecast (next) rate and Time the next settlement time |
| exchange.CreateOrder() | Order amounts are in coins (1 contract = 1 coin). Limit orders support GTC, IOC, FOK and post-only; market orders are IOC by default, cannot be post-only, and are bounded by the oracle price: buys at no more than 1.2 times it, sells at no less than 0.8 times it |
| exchange.CreateConditionOrder() | Take-profit and stop-loss only, no OCO (place the two legs separately), triggered by the last trade price; with an order price of -1 (market) the order executes at market once triggered, with the price bound computed from the oracle price at creation. To modify a conditional order, cancel it and create a new one |
| exchange.GetOrders(), exchange.GetConditionOrders() | Without a symbol, open orders of all contracts are returned. Conditional and regular orders share one order table, so untriggered conditional orders also appear in the result of exchange.GetOrders() |
| exchange.GetHistoryOrders() | At most 100 orders are returned when limit is omitted; finished conditional orders are included |
| exchange.GetHistoryConditionOrders() | The third parameter keeps its legacy meaning and is not a count: a value above 1e12 is taken as the end time (millisecond timestamp) and smaller values are ignored; the number of results is not limited. Without since the call pages through the contract's whole order history and fails beyond about 10,000 orders, so passing since is recommended |
The argument of exchange.IO("calcOrderHashAndSign", json) must have exactly 10 keys: assetIdSynthetic, assetIdCollateral, assetIdFee (hex), isBuyingSynthetic (bool), amountSynthetic, amountCollateral, amountFee, nonce, accountID and expirationTimestamp (integers, or decimal strings; an accountID beyond JavaScript integer precision must be a string). A missing or malformed key reports argument X error, and extra keys report argument error. The signing key is the configured TradingPrivateKey (used as a Stark private key), not the Stark key of an old account; the signing nonce is deterministic (RFC 6979), so the same input always gives the same signature, which differs from the old docker's but is equally valid.