Position Tracker
Every trade on the Exchange either opens, grows, shrinks, closes, or reverses a position, and the position tracker is the single bookkeeping authority for what that position is worth. Its central design choice is the split between money already banked and money still at risk: when a fill closes part of a position, the profit on the closed quantity is settled immediately at that fill's own price (realized PnL), while the remainder keeps floating with the mark price (unrealized PnL). The entry price is a volume-weighted average that only ever moves when the position grows — reducing a position never rewrites its history.
From the same state the tracker derives the two prices that govern an account's survival. The liquidation price is where the account's collateral plus floating PnL falls to exactly the maintenance-margin requirement — the point where the Exchange must step in. The bankruptcy price is more adverse still: it is where the collateral is fully consumed and equity reaches zero. The gap between the two is the buffer the liquidation engine has to unwind the position before losses spill beyond the account.
Every fill branches on side into either an entry-price update or a realized-PnL close, and both risk prices are a fan-in of the same two state variables — entry price and collateral.
Setting
A market is described by its parameters: the maintenance margin rate rm, the taker fee βt and maker rebate βr (both in basis points). A position carries a side σ∈{+1,−1} (long, short), a positive size q, and a volume-weighted entry price Pe>0. Fills arrive with a price Pf>0 and quantity qf>0, the market publishes a mark price Pmark>0, and the position is backed by account collateral C≥0. All quantities are exact decimals in the implementation; the formulas below are exact real arithmetic.
q
size
Absolute position size in units of the underlying asset; direction is carried separately by the side.
units of asset
(0, ∞)
Pe
entry_price
Volume-weighted entry price of the position.
USDX per base unit
(0, ∞)
Pmark
mark_price
The Exchange's mark price for the market at valuation time.
USDX per unit of asset
(0, ∞)
σ
side_sign
Direction indicator for the position: +1 for a long position, −1 for a short position.
dimensionless
[-1, 1]
Pf
fill_price
Execution price of an individual fill applied to the position.
USDX per base unit
(0, ∞)
qf
fill_quantity
Quantity of an individual fill applied to the position (always positive; direction comes from the fill side).
base units
(0, ∞)
qc
closed_qty
The portion of an opposing fill that closes existing position size: the smaller of the position size and the fill quantity.
base units
(0, ∞)
C
account_collateral
Collateral backing the position being evaluated.
USDX
[0, ∞)
rm
maintenance_margin_rate
Market maintenance margin rate; strictly less than the initial margin rate.
dimensionless ratio
(0, 1]
βt
taker_fee_bps
Taker fee for the market, in basis points of fill notional.
basis points
[0, ∞)
βr
maker_rebate_bps
Maker rebate for the market, in basis points of fill notional; stored as a signed value whose magnitude is credited.
basis points
[-∞, 0]
The mechanism
Building the position
When a fill lands on the same side as an existing position, the position grows and its entry price becomes the volume-weighted average of the old position and the new fill: the new entry is the total cost of both legs divided by the total quantity. This is the only path on which the entry price changes — reductions, closes, and funding leave it untouched, so Pe always answers the question "what did the currently open size cost, on average?" A fill that opens a fresh position is the degenerate case with q=0: the entry is simply the fill price.
Valuing the position
The floating profit of the open position is the signed distance from entry to mark, scaled by size: a long gains when the mark rises above entry (σ=+1), a short when it falls below (σ=−1). This value is recomputed after every fill that leaves a position open, and again on every mark-price update; it is a pure revaluation and never moves collateral by itself.
Settling reductions
A fill on the opposing side first consumes existing position size. The quantity that closes is capped at the position size: a partial reduce closes the whole fill, a full close consumes exactly the position, and a flip closes the position and carries the excess into a new one. Only this closed portion settles PnL — the excess, if any, opens fresh exposure with no PnL of its own.
Closing qc units at the fill's own price banks the entry-to-fill difference, signed by the position side — the closing analogue of (T.2) with the fill price standing in for the mark. On a partial close this accumulates on the surviving position; on a full close or flip it is returned per fill so the risk layer can settle it into collateral, since the carried position (gone, or newly opened at (T.5)) cannot recover it. Fills that open or increase a position realize exactly zero.
When an opposing fill exceeds the position size, the position reverses through zero: the old side closes fully (realizing (T.4) on qc=q), and the remainder opens a new position on the fill's side with the fill price as its fresh entry. The new position inherits none of the old accumulators.
Fees and funding
Each taker fill charges a fee proportional to its notional value, at the market's taker rate in basis points. The tracker debits this amount from the position's fee PnL accumulator so the full P&L breakdown (entry, funding, fee) is visible in one place; the cash movement itself is settled at the collateral layer. When a fill fully closes the position there is no surviving position to accumulate on, and the fee is settled entirely via collateral transfers.
Maker fills earn a rebate: the magnitude of the (negatively stored) maker rate, applied to the same fill notional as (T.6), is credited to the position's fee PnL. The absolute value guards against the sign convention — the stored rate is negative, but the credit is always positive.
Risk prices
The liquidation price is the mark at which the account's equity — collateral plus the unrealized PnL of (T.2) evaluated at that mark — falls to exactly the maintenance-margin requirement P⋅q⋅rm. Solving C+σ(P−Pe)q=Pqrm for P gives a single closed form covering both sides: for a long (σ=+1) the price sits below entry, for a short (σ=−1) above it. The formula is meaningful for leveraged positions, where collateral is less than notional; a fully collateralized long yields a non-positive (unreachable) result.
The bankruptcy price is where equity reaches zero: the entire collateral pool is consumed by the position's loss. Setting C+σ(P−Pe)q=0 and solving gives the entry price shifted adversely by the per-unit collateral C/q. Because the maintenance requirement in (T.8) is strictly positive, the bankruptcy price is always at least as adverse as the liquidation price — the gap is the liquidation engine's buffer to unwind the position before losses exceed the account.
Invariants
Every open position has q>0 and Pe>0. Why it holds: Opens and flips set size to a positive fill quantity (or positive excess qf−q) and entry to a positive fill price; increases add positive quantities; a reduction that would take size to zero returns no position at all rather than a zero-size one. So no path produces a live position with non-positive size or entry.
Partial closes never change the entry price: after a reducing fill, Pe′=Pe (see (T.1) for the only mutating path). Why it holds: The reduce branch subtracts from size and accumulates realized PnL but does not touch the entry field. Only the same-side (increase) branch recomputes the entry, and full closes and flips discard the old entry entirely.
For leveraged positions (C<Peq), the bankruptcy price is at least as adverse as the liquidation price: σPbkr≤σPliq, i.e. Pbkr≤Pliq for longs and Pbkr≥Pliq for shorts. Why it holds: At the liquidation price equity equals the maintenance requirement Pliqqrm>0; at the bankruptcy price equity is zero. Since equity is monotone in the mark (decreasing for longs, increasing for shorts), the zero-equity price lies strictly further in the adverse direction whenever the maintenance requirement is positive. Verified by the property test prop_p005_bankruptcy_worse_than_liq over randomized sizes, entries, and collateral.
A fill realizes PnL only on the quantity that closes existing opposite-side exposure: opens and increases return exactly zero realized PnL, and a flip realizes on qc=q, never on the newly opened qnew of (T.5). Why it holds: The open and increase branches return a zero realized amount unconditionally. The opposing-side branch computes (T.4) on min(q,qf) before any new position is constructed, so the reopened side starts with fresh, empty accumulators.
Funding accrual is additive and orthogonal: applying a funding payment adds its amount to the funding accumulator and changes no other field — in particular fee PnL, entry, and size are preserved. Why it holds: apply_funding performs a single addition to funding_accrued and returns; the cash flow is handled at the collateral layer. Test f005_funding_tick_preserves_fee_pnl confirms fee PnL survives funding ticks unchanged.
Worked example
A trader opens a long with a buy of 1 unit at Pf=45,000: the position is q=1, Pe=45,000. A second buy of 1 unit at 47,000 increases the position, and (T.1) blends the two legs: Pe′=(1⋅45,000+1⋅47,000)/2=46,000 on a size of q=2. With the mark at Pmark=50,000, (T.2) values the position at uPnL=(50,000−46,000)⋅2=8,000 USDX of floating profit.
The trader now sells 1 unit at 50,000. The fill opposes the long, so (T.3) gives qc=min(2,1)=1, and (T.4) banks (50,000−46,000)⋅1=4,000 USDX. The surviving position has q=1 at the unchanged entry Pe=46,000. If instead the trader had sold 3 units, the position would flip: qc=2 closes the long (realizing 8,000), and (T.5) opens a short of qnew=1 at entry 50,000.
Suppose the surviving 1-unit long is backed by C=10,000 USDX in a market with rm=0.005. (T.8) gives Pliq=(46,000−10,000)/(1⋅0.995)≈36,180.90, and (T.9) gives Pbkr=46,000−10,000=36,000. The mark reaches the liquidation threshold about 181 USDX before equity would hit zero — that gap is the buffer within which the position must be unwound. Each taker fill along the way also cost (T.6): the opening 45,000-notional buy, at βt=5 bps, debited 22.50 USDX of fee PnL.
Analysis
Sensitivity
Elasticities ε = (∂y/∂x)·(x/y), computed numerically from the verified expressions at each worked-example point. |ε| > 1 means the output moves more than proportionally with that input.
vwap_entry
fill_price
0.5109
vwap_entry
entry_price
0.4891
vwap_entry
size
-0.01087
vwap_entry
fill_quantity
0.01087
unrealized_pnl
mark_price
12.5
unrealized_pnl
entry_price
-11.5
unrealized_pnl
side_sign
1
unrealized_pnl
size
1
closed_quantity
fill_quantity
1
closed_quantity
size
0
realized_pnl
fill_price
11
realized_pnl
entry_price
-10
realized_pnl
side_sign
1
realized_pnl
closed_qty
1
flip_size
fill_quantity
2
flip_size
size
-1
taker_fee
fill_quantity
1
taker_fee
fill_price
1
taker_fee
taker_fee_bps
1
maker_rebate
fill_quantity
1
maker_rebate
fill_price
1
maker_rebate
maker_rebate_bps
1
liquidation_price
entry_price
1.111
liquidation_price
size
0.1111
liquidation_price
account_collateral
-0.1111
liquidation_price
side_sign
-0.1061
liquidation_price
maintenance_margin_rate
0.005025
bankruptcy_price
entry_price
1.111
bankruptcy_price
side_sign
-0.1111
bankruptcy_price
account_collateral
-0.1111
bankruptcy_price
size
0.1111
Response curves
More collateral pushes a long's liquidation price further below the 100,000 entry, and larger positions dilute each collateral dollar across more units; maintenance rate held at 0.5%.
Floating PnL is linear in the mark and mirror-imaged between long and short around the 46,000 entry, with size held at 2 units.
The volume-weighted entry moves toward the fill price in proportion to the fill's share of the combined size; existing position held at 2 units entered at 46,000.
References
Derived from and adversarially verified against the Exchange's Rust implementation and its test suite.
Sibling model: funding-rate
Sibling model: insurance-fund
Sibling model: liquidation-engine
Sibling model: margin-math
Sibling model: oracle
Sibling model: order-book
Sibling model: settlement
Last updated

