1380) and every size is USDC of
notional. A long (buy) gains when cNGN weakens against the dollar, so more cNGN buys a USDC.
A short (sell) gains when cNGN strengthens. Read this before integrating against the future.
What the market is
Each series is aFutureAsset series on Base under the MarginEngine, the risk manager that
holds margin, settles variation margin and liquidates. Orders are signed for the same TradeModule
as spot, and a wallet has one trading account under the MarginEngine for both markets. Spot
balances and futures margin share that account, so cNGN bought on spot counts toward futures margin
at its factor. Your first deposit opens the account.
A series is listed as USDC-cNGN-<DDMONYY>, named for its expiry date. The series listed now is
USDC-cNGN-30NOV26:
market = "USDC-cNGN-30NOV26": the identifier you pass assymbolon REST endpoints andmarketon websocket streamscontract_type = "future",settlement_type = "cash_settled_future"base_asset_symbol = "USDC",quote_asset_symbol = "cNGN",display_label = "cNGN per USDC"expiry_timestamp = 1796047200(2026-11-30 14:00 UTC), which is also the series’sub_idcontract_multiplier = "1000": one contract is 1,000 USDC of notionalui_size_unit = "USDC of notional (1,000 a contract)",min_size = "1",amount_step = "1"taker_fee_bps = 25,maker_fee_bps = 0
GET /v1/markets rather than hard-coding one. A new series gets a new
identifier, a new sub_id and its own expiry.
Discover the market
ui_* and engine_* contract fields, with
engine_side_policy = "same_as_ui", plus these:
The
future object is the series as the chain has it. Prices are cNGN per USDC, up to 18 decimals.
An absent optional field could not be read, so treat it as unknown, not as zero.
Place an order
Futures take raw engine values only.order_entry_spec and ui_intent are refused on a future.
In the body, limit_price is in cNGN per USDC and desired_amount in whole USDC of notional, both
human decimals. A long of one contract (1,000 USDC) at 1,380 cNGN per USDC:
action_json.data, with two different scales:
limitPriceis the price × 1e18:1380000000000000000000.desiredAmountis the size ×amount_scale(1e15):1000000000000000000, one contract.worstFeecaps the fee per contract filled, in USDC × 1e18. The fee is 25 bps of the notional, so 2.5 USDC a contract at any price. Sign at least2500000000000000000; the example signs 30 bps (3000000000000000000) to leave headroom.action_json.moduleis the market’strade_module_address.
reduce_only: true lets an order only shrink the account’s position in the series. It is refused
when the account has no position, or when the order is on the same side as the position. The
matcher clamps each fill so it never crosses through zero. It is refused on spot.
See Authentication and signing for building the signed payload, and
Create order for the full request body.
Orders the venue refuses
The venue refuses a futures order the chain could not settle, rather than resting it as depth no fill can take:The fill band
The chain refuses a fill priced too far from the index. A fill must sit withinband_width of
index_price, so between fill_band_low and fill_band_high. The band is 10% either side of the
index, and narrows linearly to 1% over the last 14 days before expiry.
The venue applies the same test with the chain’s own arithmetic:
- On submission, an order whose signed limit is outside the band now is refused.
- Before each fill, the matcher re-checks the fill price against a band read at most two seconds earlier. A resting order the index has moved away from is held back, not cancelled. It fills again once the index comes back within reach.
- While the index is stale (
band_status = "index_stale"), the chain refuses every fill. The venue refuses new orders until the index updates.
Margin
Margin is held under the MarginEngine in USDC cash and cNGN. USDC counts at par. cNGN counts at its base margin factor (0.5), valued at the index. Futures margin is charged on the USDC notional,
gross, with no offset between series or against other positions:
While cNGN trades below its depeg threshold, the MarginEngine adds a penalty to initial margin.
A trade that only reduces a futures position is held to maintenance margin, not initial, so you can
always deleverage. Open interest in each series is capped on chain.
Before submitting a fill, the matcher estimates each account’s initial-margin surplus after it.
If an account comes up short, its order is held back for 30 seconds. After three refusals, at least a
minute apart from the first, the order is cancelled with
cancel_reason: "insufficient_margin". The
estimate is deliberately generous, so the MarginEngine on chain remains the authority.
Variation margin
Variation margin (VM) settles in cNGN: a move of the mark byΔmark cNGN per USDC is
Δmark × 1,000 cNGN per contract. A long receives it when the mark rises, and a short pays it.
- At the fill. A fill is marked to the mark at once. A buy above the mark, or a sell below it,
pays the gap.
GET /v1/fillsreports the mark asmark_priceand the VM asvm_cngn. - At each mark. The mark is pulled from a signed forward feed at most once an hour. Each update may move at most 5%, and must sit inside the band around the index. The MarginEngine settles VM before every risk check, and anyone can trigger it for an account.
- Who pays what. A payer pays from its cNGN first, then the rest from USDC at the index. A winner is paid in cNGN while the engine’s pool holds it, then in USDC.
Settlement
Trading stops atlast_trade_time, one hour before expiry. From then on only the MarginEngine moves
positions, through liquidations and the close-out.
The settlement price is the time-weighted average of the index over the fixing window, the last
hour before expiry. Each open position is closed out at it, and the final variation margin is paid
as above. If the fixing is incomplete, a fallback price may be set after 24 hours, within 2% of the
samples’ average.
Read a position
The Numo API does not serve futures positions. Read them on chain, where they are public:- Position:
SubAccounts.getBalance(subaccountId, future, subId)on SubAccounts0x7019244E25FA416e6Ca2ed2F3cA25277aef72843, wherefutureis the market’sasset_addressandsubIditssub_id. The result is signed contracts at 18 decimals; positive is a long. - Margin:
MarginEngine.getMargin(subaccountId, true)for the initial-margin surplus, orfalsefor maintenance, in USD at 18 decimals, onmargin_manager_address.
mark_price and vm_cngn, are on
GET /v1/fills.
Market data
The book, trades and candles work for a future as for spot: pass the series’market as symbol
on REST endpoints, or as market on the websocket stream. Prices are
cNGN per USDC and sizes USDC of notional. The /v1/integrations/* endpoints serve spot only and
refuse a future’s ticker_id.
