Skip to main content
The cNGN future is a dated, cash-settled future on the naira rate. It is quoted the other way round from spot: every price is cNGN per USDC (about 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 a FutureAsset 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 as symbol on REST endpoints and market on websocket streams
  • contract_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_id
  • contract_multiplier = "1000": one contract is 1,000 USDC of notional
  • ui_size_unit = "USDC of notional (1,000 a contract)", min_size = "1", amount_step = "1"
  • taker_fee_bps = 25, maker_fee_bps = 0
Discover series from 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

A future’s entry carries the 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:
Sign the same order into action_json.data, with two different scales:
  • limitPrice is the price × 1e18: 1380000000000000000000.
  • desiredAmount is the size × amount_scale (1e15): 1000000000000000000, one contract.
  • worstFee caps 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 least 2500000000000000000; the example signs 30 bps (3000000000000000000) to leave headroom.
  • action_json.module is the market’s trade_module_address.
A fill carries its price to the chain and moves no quote leg. The account receives the position, and variation margin settles the gap between the fill price and the mark at once. See Variation margin. 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 within band_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.
Liquidations and the close-out at expiry move positions at the mark and are not bounded.

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/fills reports the mark as mark_price and the VM as vm_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 at last_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 SubAccounts 0x7019244E25FA416e6Ca2ed2F3cA25277aef72843, where future is the market’s asset_address and subId its sub_id. The result is signed contracts at 18 decimals; positive is a long.
  • Margin: MarginEngine.getMargin(subaccountId, true) for the initial-margin surplus, or false for maintenance, in USD at 18 decimals, on margin_manager_address.
Your fills, with their 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.