Disclosure: AI assistance was used in preparing this technical article. The code is an illustrative monitoring example, not a production liquidation engine or a live exchange integration.
A derivatives trading system can receive three different prices for the same contract:
Last traded price.
Index price.
Mark price.
All three may be valid, but they are not interchangeable.
A common engineering mistake is to use the last traded price for every downstream calculation, including unrealized profit and loss, margin monitoring, stop-loss simulation, and liquidation-risk estimation.
That can produce incorrect risk states.
This article develops a minimal monitoring approach that preserves the meanings of different price fields and treats the exchange's account-level margin data as separate inputs.
1. Define the failure scenario
Consider a hypothetical BTCUSDT perpetual long position.
| Field | Value |
|---|---|
| Last price | 100,100 |
| Index price | 99,900 |
| Mark price | 99,850 |
| Estimated liquidation level | 99,900 |
The last traded price remains above the estimated liquidation level.
The mark price is below it.
For a contract whose liquidation risk depends on the mark price and applicable maintenance margin requirements, those values describe different potential risk conclusions.
The correct engineering response is not to assume that the last-price chart is wrong.
It is to identify which field the exchange uses for each function and which account conditions are needed to evaluate the position.
2. Maintain separate market and account data
A reliable risk snapshot should contain at least:
Market data
- Instrument and exchange identifiers.
- Last traded price.
- Index price.
- Mark price.
- Source event timestamps.
- Local receipt timestamps.
Position data
- Contract type and size.
- Entry or average position cost.
- Margin mode.
- Funding-related adjustments.
- Applicable maintenance margin tier.
Account data
- Margin balance or equivalent risk-account equity.
- Maintenance margin requirement.
- Exchange-reported risk ratio.
- Relevant restrictions and pending orders.
Not every account mode provides a meaningful single liquidation price.
For example, cross-margin arrangements may depend on other positions and collateral in the same account.
The implementation should therefore prefer official account-level risk fields where available.
A locally estimated liquidation level can be retained as a diagnostic, but it should not override the exchange's actual account state.
3. Build a small monitoring function
The following Python example distinguishes the prices, checks data freshness, and compares illustrative margin-account values.
It does not attempt to reproduce Binance, Bybit, or OKX liquidation formulas.
from dataclasses import dataclass from datetime import datetime, timezone, timedelta import math @dataclass(frozen=True) class RiskSnapshot: instrument: str last_price: float index_price: float mark_price: float margin_balance: float maintenance_margin: float mark_timestamp: datetime def inspect_risk(snapshot, observed_at, max_age_seconds=5): values = [ snapshot.last_price, snapshot.index_price, snapshot.mark_price, snapshot.margin_balance, snapshot.maintenance_margin, ] if not all(math.isfinite(v) for v in values): raise ValueError("Non-finite numerical input.") if min( snapshot.last_price, snapshot.index_price, snapshot.mark_price ) <= 0: raise ValueError("Prices must be positive.") if snapshot.maintenance_margin < 0: raise ValueError("Invalid maintenance margin.") if snapshot.mark_timestamp.tzinfo is None: raise ValueError("Timestamp must be timezone-aware.") if observed_at.tzinfo is None: raise ValueError("Observation time must be timezone-aware.") age = observed_at - snapshot.mark_timestamp if age < timedelta(seconds=0) or age > timedelta( seconds=max_age_seconds ): return { "state": "UNVERIFIED", "reason": "Mark-price data is stale or future-dated" } divergence_bps = 10_000 * ( snapshot.mark_price / snapshot.last_price - 1 ) # A diagnostic only. It does not reproduce the # venue's official liquidation-engine decision. margin_breach_candidate = ( snapshot.margin_balance <= snapshot.maintenance_margin ) return { "state": ( "MARGIN_BREACH_CANDIDATE" if margin_breach_candidate else "NO_BREACH_IN_THIS_SIMPLE_CHECK" ), "mark_last_divergence_bps": divergence_bps, "margin_buffer": ( snapshot.margin_balance - snapshot.maintenance_margin ), "mark_timestamp": snapshot.mark_timestamp.isoformat() } now = datetime.now(timezone.utc) example = RiskSnapshot( instrument="BTCUSDT_PERPETUAL", last_price=100_100.0, index_price=99_900.0, mark_price=99_850.0, margin_balance=980.0, maintenance_margin=1_000.0, mark_timestamp=now ) print(inspect_risk(example, observed_at=now)) The example returns a margin-breach candidate because the supplied margin balance is below the supplied maintenance requirement.
Those two amounts are illustrative inputs. They are not derived from the hypothetical BTC position above.
The code must not be used to predict an exchange's liquidation decision without the exact account mode, maintenance rules, collateral treatment, and risk-engine behavior.
4. Separate mark-price divergence from liquidation eligibility
A useful monitoring feature is:
Dₜ = 10,000 × (Mark Priceₜ / Last Priceₜ − 1)
This measures the difference between the current mark price and the latest traded price in basis points.
A large negative value may be important for a long position, but the divergence alone does not prove that liquidation is imminent.
The account might have substantial collateral.
Alternatively, a relatively small divergence could matter for a position already very close to its maintenance margin limit.
That is why a practical monitor should track both:
Market divergence: How far mark price differs from the latest trade and index reference.
Margin buffer: How much room remains between the account's relevant risk equity and required maintenance margin.
The second value must follow the venue's account conventions.
For instance, some exchanges report a risk ratio in which a higher number indicates greater danger, while others present maintenance margin ratios with different definitions.
A monitoring system must normalize these semantics explicitly rather than assuming the same field name has the same meaning everywhere.
5. Distinguish stop triggers from liquidation events
Stop-loss simulation also requires separate state.
A conditional stop might use:
- Last price.
- Mark price.
- Index price.
The configured trigger source should be stored with the order.
For example:
stop_trigger_source = "LAST_PRICE"
stop_trigger_price = 99900
The stop's activation logic should read only the selected price source.
Even when its trigger condition is met, the monitor must distinguish these subsequent states:
Trigger observed.
Order submitted.
Order accepted.
Order partially or fully filled.
Order rejected, canceled, or expired.
A stop order that has merely triggered is not a completed hedge.
Similarly, an exchange's liquidation process cannot be reconstructed solely from stop-order data.
The two workflows should remain independent in the event model.
6. Backtesting requirements
A historical liquidation-risk study needs more than minute-level OHLCV candles.
Mark prices may change between ordinary trade prints, and the risk engine may use account information that cannot be reconstructed from market prices alone.
A more credible dataset should preserve:
- Exchange-published mark-price updates.
- Trade and index-price observations.
- Event and receipt timestamps.
- Funding-related account adjustments.
- Position and collateral changes.
- Maintenance margin tiers and rule versions.
- Stop-trigger configuration and execution records.
- Official liquidation events, where available.
Researchers should also test failure conditions.
What happens when the mark-price feed becomes stale?
What happens when index and mark prices diverge sharply?
What happens if the exchange changes its pricing rules?
What happens if account-level margin data become temporarily unavailable?
A conservative system may flag the account as unverified and restrict additional risk instead of replacing missing official mark prices with a convenient approximation.
For KAEL AI's quantitative trading research, the key engineering lesson is that prediction models, execution systems, and risk engines must share consistent timestamps and instrument identifiers while retaining distinct price semantics.
Conclusion
The difference between last price and mark price is not just a display issue.
It affects unrealized P&L, stop-order behavior, margin-risk assessment, and the reconstruction of historical liquidation events.
A reliable monitoring architecture should maintain distinct price fields, use authenticated exchange account data, detect stale information, and avoid presenting simplified calculations as official liquidation decisions.
The objective is not to duplicate an exchange's private risk engine from incomplete market data.
It is to detect inconsistencies early and prevent an automated strategy from treating an unreliable view of its margin state as safe.
Official documentation
Binance Futures — Liquidation Protocols:
https://www.binance.com/en/support/faq/detail/360033525271
Bybit — Mark Price Calculation:
https://www.bybit.com/en/help-center/article/Mark-Price-Calculation-Perpetual-Expiry-Contracts
OKX — Forced Liquidation FAQ:
https://www.okx.com/en-us/help/forced-liquidation-faq
