Insurance Fund & ADL
ZTDX's USDⓈ-M futures market protects users from socialised loss using a two-stage waterfall:
- Insurance fund — a per-symbol pool that absorbs bad debt when a liquidated position's remaining collateral goes negative.
- Auto-Deleveraging (ADL) — only kicks in when the insurance fund cannot fully cover the shortfall; reduces top-ranked profitable opposing positions to make the books whole.
This page documents the mechanism, the public REST endpoints, and how to detect when an account has been touched by either system.
Bad-Debt Waterfall
When a position breaches its maintenance margin and is force-closed at
mark_price:
remaining_collateral = collateral_amount
+ realized_pnl(mark_price)
- accumulated_funding_fee
- accumulated_borrowing_fee
- liquidation_fee (size_in_usd × 0.5%)
- insurance_contribution (size_in_usd × 0.1%)
- liquidator_reward (size_in_usd × 0.1%, if any)
Stage 1 — User collateral
If remaining_collateral ≥ 0, the user is fully bankrupt-proof: the position
closes, fees are paid, and any positive remainder is credited back to
available_balance. Insurance fund receives the insurance_contribution
slice and ADL is not engaged.
Stage 2 — Insurance fund payout
If remaining_collateral < 0, the insurance fund covers the shortfall up to:
insurance_payout = min( |remaining_collateral|,
fund.balance × max_insurance_payout_rate )
max_insurance_payout_rate defaults to 0.5 (50% of the fund's current
balance per single liquidation event), preventing one outlier event from
draining the fund.
Stage 3 — ADL (Auto-Deleveraging)
If a residual shortfall remains after the insurance fund payout, the engine
emits an adl event. Profitable positions on the opposite side of the
liquidated position are ranked and partially (or fully) reduced at the
current mark price; the realized PnL slice they would have collected is
redirected to cover the residual shortfall.
For unified-margin accounts, the per-step record's liquidation_type is set
to "adl" whenever this branch fires (see
Unified-Margin Liquidation History).
Insurance Fund Funding
The fund is per symbol, not global. Each symbol's pool is fed by a fixed
0.1% (10 bps) of position notional charged to every liquidated position
(insurance_fund_fee_rate, configurable per market). Trading fees, funding
fees, and borrow fees do not flow into the insurance fund — they go to
protocol revenue.
Withdrawals from the fund occur only when Stage 2 (above) fires.
ADL Ranking
ADL only considers positions that are profitable at the current mark price
(unrealized_pnl > 0) and on the opposite side of the position being
liquidated. Each candidate gets a score:
adl_score = pnl_weight × pnl_percentage
+ leverage_weight × leverage
+ size_weight × (size / max_size_in_market)
Positions are ranked descending by score; rank 1 is reduced first. The
authoritative ranking — including the actual rank, adl_score, and the
inputs used to compute it — is exposed via
GET /api/v1/adl/{symbol}/rankings?side=long|short.
Per-market ADL behaviour (weights, max positions per event, min/max reduction
ratios, per-symbol enable flag) is exposed via
GET /api/v1/adl/{symbol}/config.
Rankings are recomputed every 30 seconds by a background worker.
Note on
/fapi/v1/adlQuantile— the Binance-compatible endpoint currently returns a coarse, simplified quantile derived only from each position's side (it does not yet read liveadl_rankingsdata). For the precise ranking, use the nativeGET /api/v1/adl/{symbol}/rankingsendpoint described below.
Public REST Endpoints
All endpoints under /api/v1/... are public (no auth, no signing). Endpoints
under /fapi/v1/... are Binance-compatible and signed (HMAC SHA256).
| Endpoint | Returns |
|---|---|
GET /api/v1/insurance-fund/{symbol} | Current per-symbol fund balance + lifetime totals |
GET /api/v1/liquidations/{symbol} | Recent liquidations on a market (incl. insurance_fund_contribution) |
GET /api/v1/liquidations/{symbol}/config | Liquidation parameters for a market (insurance_fund_fee_rate, max_insurance_payout_rate, etc.) |
GET /api/v1/adl/{symbol}/rankings | Live ADL ranking snapshot (per side) |
GET /api/v1/adl/{symbol}/events | History of ADL events on a market |
GET /api/v1/adl/{symbol}/config | Per-market ADL parameters and enabled flag |
GET /fapi/v1/adlQuantile | Per-position ADL quantile (0–4); Binance-compatible, signed |
GET /fapi/v1/forceOrders | Caller's liquidation orders; Binance-compatible, signed |
For the full schema of liquidation history records, see
forceOrders (Binance-compatible) and
unified/liquidations (ZTDX-native,
unified-margin only).
GET /api/v1/insurance-fund/{symbol}
Returns the live insurance fund state for a single symbol. Public; no authentication.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
| symbol | STRING | YES | e.g. BTCUSDT |
Response
{
"fund": {
"id": "8e7c2a1b-4d3e-4f5a-9b0c-1d2e3f4a5b6c",
"symbol": "BTCUSDT",
"balance": "14448.566075868791505285",
"total_contributions": "27508.804093804413605641",
"total_payouts": "13060.238017935622100451",
"updated_at": "2026-05-07T08:12:52.919276Z",
"created_at": "2025-11-14T03:00:00.000000Z"
}
}
| Field | Meaning |
|---|---|
balance | Current funds available to cover bad debt for this symbol |
total_contributions | Lifetime sum credited from liquidations (0.1% × notional) |
total_payouts | Lifetime sum debited to cover bad debt |
updated_at | Last time the row was touched (i.e. last liquidation on this symbol) |
If the symbol has never been touched, the endpoint creates a zero-balance row on demand and returns it.
GET /api/v1/liquidations/{symbol}/config
Returns the liquidation parameters used by the engine for this market.
{
"config": {
"symbol": "BTCUSDT",
"liquidation_fee_rate": "0.005",
"max_leverage": 50,
"maintenance_margin_rate": "0.005",
"min_collateral_usd": "10",
"insurance_fund_fee_rate": "0.001",
"max_insurance_payout_rate": "0.5",
"liquidator_reward_rate": "0.001"
}
}
These values are also stamped into every liquidations row, so downstream
analytics never have to assume the live config is authoritative for past
events.
GET /api/v1/adl/{symbol}/rankings
Returns the current ranking snapshot for one side, ordered by rank ascending
(rank 1 = first to be reduced if ADL fires next). Rankings are recomputed
every 30s.
Query parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
| side | STRING | YES | — | "long" or "short" |
| limit | INT | NO | 50 | Page size |
Response
{
"market_symbol": "BTCUSDT",
"side": "long",
"rankings": [
{
"id": "...",
"market_symbol": "BTCUSDT",
"side": "long",
"position_id": "...",
"user_address": "0x...",
"position_size": "50000.00",
"unrealized_pnl": "1234.56",
"pnl_percentage": "12.345",
"leverage": "10",
"adl_score": "1.7234",
"rank": 1,
"computed_at": "2026-05-07T08:12:30Z"
}
]
}
Only profitable positions appear in the ranking; unprofitable positions are never candidates.
GET /api/v1/adl/{symbol}/events
History of ADL executions for the market. An empty list means the insurance fund has covered every shortfall to date, which is the steady state.
{
"events": [
{
"id": "...",
"market_symbol": "BTCUSDT",
"liquidation_id": "...",
"insurance_fund_shortfall": "850.000000000000000000",
"total_reduced_size": "8500.000000000000000000",
"total_pnl_realized": "850.000000000000000000",
"positions_affected": 3,
"status": "completed",
"created_at": "2026-04-13T05:12:34.567890Z",
"completed_at": "2026-04-13T05:12:34.892011Z"
}
]
}
status is one of pending (in flight), completed (shortfall fully
covered), partial (couldn't cover entire shortfall — exceptional), or
failed (no profitable counterparties — exceptional).
Detecting Insurance / ADL Impact in Account Data
| You want to know… | Where to look |
|---|---|
| Was my position liquidated? | /fapi/v1/forceOrders — Binance-compatible |
| Was my unified-margin account liquidated step-by-step? | /api/v1/unified/liquidations. liquidation_type == "adl" ⇒ ADL was engaged for this step |
| Am I likely to be ADL'd next? | GET /api/v1/adl/{symbol}/rankings?side=... — find your position_id; lower rank = earlier in the queue. (/fapi/v1/adlQuantile is currently a coarse stub — use the native endpoint.) |
| Was a specific position reduced by ADL? | The position will appear in adl_reductions; check the user-side trade history for a synthetic close at the ADL execution price |
Code Example — fetch all insurance fund balances
import requests
BASE_URL = "https://api.ztdx.io"
# 1. Get the list of active symbols
markets = requests.get(f"{BASE_URL}/api/v1/markets").json()
symbols = [m["symbol"] for m in markets]
# 2. Fan out
total_balance = 0.0
for symbol in symbols:
r = requests.get(f"{BASE_URL}/api/v1/insurance-fund/{symbol}")
fund = r.json()["fund"]
bal = float(fund["balance"])
total_balance += bal
print(f"{symbol:14s} balance={bal:>14.4f} "
f"contrib={float(fund['total_contributions']):>14.4f} "
f"payouts={float(fund['total_payouts']):>14.4f}")
print(f"\nTotal insurance fund across all markets: {total_balance:,.2f} USDT")
FAQ
Why is the insurance fund per-symbol and not global? Per-symbol funds prevent contagion: a flash crash on a thinly-traded altcoin can't drain the BTC market's reserve.
Can the insurance fund be topped up manually? Not via a public endpoint. The only credit path is the 0.1% liquidation contribution. Operational top-ups (e.g. a protocol-funded boost) are admin operations and not part of the public API surface.
What happens if the insurance fund goes to zero? Stage 2 simply pays out 0, and Stage 3 (ADL) covers the entire bankrupt slice. The market keeps running.
Why does the 50% cap exist? A single anomalous liquidation should not be able to wipe out the entire fund. With the cap, even a worst-case liquidation only consumes half of the available balance, leaving the other half to absorb the next event. The remaining shortfall flows into ADL, which is correctly designed to handle unbounded events.
Are insurance contributions visible in protocol_fee_ledger?
Yes. Each liquidation writes three rows: liquidation_fee (positive,
protocol revenue), insurance_contribution (positive, mirrors the credit to
the insurance fund), and liquidator_reward (negative when paid to a
keeper, since it physically leaves the vault).