> For the complete documentation index, see [llms.txt](https://docs.nexus.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nexus.xyz/math-engine/order-book.md).

# Order Book

Every market on the Exchange clears through one mechanism: a central limit order book. Traders who are willing to wait post limit orders that rest in the book, forming visible liquidity at discrete price levels; traders who want immediacy send orders that cross the spread and consume that liquidity. The book's contract is price-time priority — a better price always trades first, and at equal prices the earlier order trades first — which rewards the makers who quote tightest and earliest, and gives every taker the best available execution the book can offer.

Because makers commit first, every trade prints at the maker's quoted price: a taker willing to pay more than the best ask still pays only the ask. Around this core, the book layers execution guarantees that protect both sides — fill-or-kill orders that refuse partial execution, post-only orders that refuse to take liquidity, an opt-in self-trade prevention regime, and a server-enforced slippage cap that halts a market order the moment its running average price would drift too far from the mid-price it saw at submission.

![The fill event is a fan-in of resting depth, availability, and self-trade decrements, and each fill feeds back into both the depth it consumes and the running VWAP that bounds the next fill.](/files/naEFGv7c48sTUWiyqgCL)

*The fill event is a fan-in of resting depth, availability, and self-trade decrements, and each fill feeds back into both the depth it consumes and the running VWAP that bounds the next fill.*

## Setting

A market is described by parameters: the tick size $$\delta$$ (minimum price increment), the lot size $$\ell$$ (minimum quantity increment), and minimum and maximum order sizes. The state is a pair of price-level maps — bids and asks — each holding a first-in-first-out queue of resting orders per price, together with the derived best bid $$P\_b$$ and best ask $$P\_a$$. The admissible region for an incoming order requires a strictly positive, tick-aligned limit price and a lot-aligned quantity within the market's size bounds; orders outside it are rejected before touching the book.

| Symbol         | Name               | Description                                                                                                                                   | Units              | Domain  |
| -------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ------- |
| $$q$$          | quantity           | Order quantity in base units of the asset.                                                                                                    | base units         | (0, ∞)  |
| $$q\_f$$       | filled\_qty        | Cumulative quantity of the order already filled.                                                                                              | base units         | \[0, ∞) |
| $$\ell$$       | lot\_size          | Market lot size; order quantities must be integer multiples of it (a zero lot size disables the check).                                       | base units         | \[0, ∞) |
| $$\delta$$     | tick\_size         | Minimum price increment of the market. A non-positive tick disables alignment entirely (the raw price passes the check).                      | USDX per base unit | \[0, ∞) |
| $$P\_{lim}$$   | limit\_price       | Limit price of a resting or incoming limit order; must be strictly positive and tick-aligned.                                                 | USDX per base unit | (0, ∞)  |
| $$P\_b$$       | best\_bid          | Highest resting bid price; undefined when the bid side is empty.                                                                              | USDX per base unit | (0, ∞)  |
| $$P\_a$$       | best\_ask          | Lowest resting ask price; undefined when the ask side is empty.                                                                               | USDX per base unit | (0, ∞)  |
| $$P\_{mid}$$   | mid\_price         | Arithmetic midpoint of the best bid and best ask; the reference price captured once at market-order submission for the slippage cap.          | USDX per base unit | (0, ∞)  |
| $$\beta$$      | max\_slippage\_bps | Taker-supplied slippage cap on a market order, in basis points of the mid-price; absent means no cap.                                         | basis points       | \[0, ∞) |
| $$q\_t$$       | taker\_remaining   | Unfilled quantity remaining on the incoming (taker) order at the moment it meets a maker.                                                     | base units         | (0, ∞)  |
| $$q\_m$$       | maker\_remaining   | Unfilled quantity remaining on the resting (maker) order at the front of the queue.                                                           | base units         | (0, ∞)  |
| $$P\_{mk}$$    | maker\_price       | Limit price of the resting maker order; every fill prints at this price.                                                                      | USDX per base unit | (0, ∞)  |
| $$q^{\star}$$  | fill\_qty          | Quantity exchanged in a single fill between the taker and the front maker.                                                                    | base units         | (0, ∞)  |
| $$P^{\star}$$  | fill\_price        | Price of a single fill — always the maker's limit price.                                                                                      | USDX per base unit | (0, ∞)  |
| $$Q\_{avail}$$ | available\_qty     | Total resting quantity on the opposing side at prices satisfying the taker's limit — the pre-match liquidity visible to a fill-or-kill check. | base units         | \[0, ∞) |
| $$V\_k$$       | running\_notional  | Cumulative notional of the fills accepted so far in the current market-order walk.                                                            | USDX               | \[0, ∞) |
| $$Q\_k$$       | running\_filled    | Cumulative quantity of the fills accepted so far in the current market-order walk.                                                            | base units         | \[0, ∞) |
| $$V$$          | notional           | Total notional accumulated by a hypothetical walk of the opposing side in price-time priority.                                                | USDX               | (0, ∞)  |
| $$q\_{req}$$   | requested\_qty     | Quantity requested by a hypothetical market order in a VWAP preview.                                                                          | base units         | (0, ∞)  |

## The mechanism

### Admissibility

Before an order can touch the book, its quantity must be an exact multiple of the market's lot size $$\ell$$, and must lie within the market's minimum and maximum order sizes. Quantization keeps every resting queue and every fill expressible in whole lots, so partial fills never strand dust below the tradable increment. A zero lot size disables the multiplicity check.

$$
q \bmod \ell = 0 \tag{B.1}
$$

A limit price must be strictly positive and an exact multiple of the tick size $$\delta$$. Positivity is checked separately because zero is tick-aligned for every tick size — without the strict guard, a market booted before its first oracle print could accumulate zero-priced resting orders and print zero-priced trades. A non-positive tick size disables the alignment check but never the positivity one.

$$
P\_{lim} > 0 \quad\text{and}\quad P\_{lim} \bmod \delta = 0 \tag{B.2}
$$

### Book state

When both sides of the book are populated, the mid-price is the arithmetic midpoint of the best bid and best ask. It is the book's instantaneous consensus price and the reference captured once at submission for the market-order slippage cap (B.8). When either side is empty the mid-price is undefined, and a market order carrying a slippage cap is rejected outright rather than executed against an unpriced book.

$$
P\_{mid} = \frac{P\_b + P\_a}{2} \tag{B.3}
$$

### Matching

A fill-or-kill order executes only if the book can satisfy it entirely; otherwise it cancels without touching the book. Before matching, the engine sums the resting quantity $$Q\_{avail}$$ on the opposing side across every price level satisfying the taker's limit, and admits the order to the matching loop only when that sum covers the full request. A rejected fill-or-kill order records an expiry cancellation and generates no fills.

$$
Q\_{avail} \ge q \quad\text{where}\quad Q\_{avail} = \sum\_{\substack{\text{levels } P \text{ satisfying} \ \text{the taker limit}}} ; \sum\_{\text{orders at } P} (q - q\_f) \tag{B.4}
$$

The matching loop walks the opposing side of the book from the best price inward, and within each price level from the oldest order forward — price-time priority. Each encounter between the taker and the front maker exchanges exactly the smaller of the two remaining quantities: the maker cannot give more than it has resting, and the taker cannot take more than it still needs. A fully consumed maker leaves the book; a fully satisfied taker ends the walk.

$$
q^{\star} = \min\left(q\_t,; q\_m\right) \tag{B.5}
$$

Every fill prints at the maker's limit price, not the taker's. The maker committed capital first at a stated price, and the taker who crosses receives that price even when willing to trade at a worse one — the price improvement accrues entirely to the taker. Together with (B.5) this fully determines each fill: a buy taker therefore never pays above its limit, and a sell taker never receives below it.

$$
P^{\star} = P\_{mk} \tag{B.6}
$$

### Self-trade prevention

Self-trade prevention is opt-in and fires per encountered same-account maker, not once at order entry. In cancel-newest mode the taker cancels immediately; in cancel-oldest mode the maker cancels and the taker keeps walking. In decrement-and-cancel mode both orders shrink by the quantity they would have exchanged — the same minimum as (B.5) — but as a reduction of order size rather than a fill, so no trade is recorded. The smaller side is cancelled and the larger continues with reduced quantity; when both sides are equal, both cancel.

$$
\Delta\_{stp} = \min\left(q\_t,; q\_m\right) \tag{B.7}
$$

### Market-order slippage cap

A market order may carry a slippage cap $$\beta$$ in basis points. At submission the engine captures the mid-price (B.3) once and converts the cap into an absolute half-band around it; the running average execution price must remain within $$\[P\_{mid} - h,; P\_{mid} + h]$$ for the walk to continue. If either side of the book is empty at submission the mid-price does not exist and the capped order is rejected with insufficient liquidity rather than executed unbounded.

$$
h = P\_{mid} \cdot \frac{\beta}{10^4} \tag{B.8}
$$

As a capped market order walks the book, the engine evaluates, before accepting each candidate fill, the volume-weighted average price the order would have after that fill. If the prospective average would leave the band defined by (B.8), the fill is refused, the walk halts, and the remainder cancels with a slippage-cap reason — fills already accepted stand. The check is per-fill on the cumulative average, not per-level on the marginal price, so a deep sweep is halted exactly when its blended cost breaches the cap. The cap applies only to market orders; on limit orders it is silently ignored, since limit-or-better execution makes it meaningless.

$$
\bar{P}*{k+1} = \frac{V\_k + q^{\star} P^{\star}}{Q\_k + q^{\star}}, \qquad P*{mid} - h ;\le; \bar{P}*{k+1} ;\le; P*{mid} + h \tag{B.9}
$$

### Execution preview

The book also answers a read-only question: at what average price would a hypothetical market order of size $$q\_{req}$$ execute right now? The preview walks the opposing side in the same price-time order as live matching, accumulating notional $$V$$ until the request is covered, and returns the volume-weighted average. If resting liquidity cannot cover the request — or the requested quantity is non-positive — the preview returns no price rather than a partial estimate. Self-trade prevention and slippage caps are deliberately not applied here; they are concerns of the live submission path.

$$
\bar{P} = \frac{V}{q\_{req}}, \qquad V = \sum\_{\text{walked fills}} q^{\star} P^{\star} \tag{B.10}
$$

## Invariants

* The book is never crossed: whenever both sides are non-empty, $$P\_b < P\_a$$. *Why it holds:* An incoming limit order matches against every opposing level its price crosses before any remainder rests, so a resting bid at or above a resting ask cannot coexist — one would have consumed the other at submission. Post-only orders that would cross are rejected outright, and cancellations only remove orders, which cannot create a crossing.
* No overfill: for every order, cumulative filled quantity never exceeds order quantity, i.e. $$q\_f \le q$$; equivalently the sum of fill quantities equals at most the taker's quantity ((B.5)). *Why it holds:* Every fill quantity is $$\min(q\_t, q\_m)$$ of the two remaining quantities, so each fill reduces both remainders by a non-negative amount that cannot exceed either. The loop terminates the moment the taker's remainder reaches zero, so filled quantity is a monotone sum bounded by the original quantity.
* Limit-or-better execution: every fill of a buy taker satisfies $$P^{\star} \le P\_{lim}$$ and of a sell taker $$P^{\star} \ge P\_{lim}$$ ((B.6)). *Why it holds:* The matching loop selects a maker level only if it satisfies the taker's limit — asks at or below a buy limit, bids at or above a sell limit — and every fill prints at that maker price. Levels beyond the limit terminate the walk before generating fills.
* Index-book consistency: the order index contains exactly the identifiers of orders resting in the book, and every resting order has strictly positive remaining quantity. *Why it holds:* Every mutation path — insertion, cancellation, fill consumption, self-trade removal, and restore — updates the index and the price-level queues together in the same operation. Makers are removed from both the moment their remaining quantity reaches zero, and emptied price levels are deleted, so no zero-quantity order or dangling index entry survives any operation.
* Slippage-cap monotonicity: for the same book and order, a larger cap $$\beta$$ never fills less quantity than a smaller one ((B.8), (B.9)). *Why it holds:* The fills accepted before the first band breach are identical for both caps, since the walk order and the running VWAP sequence do not depend on the cap. A wider band can only move the first breach later in that fixed sequence, so the accepted prefix — and hence the filled quantity — is weakly larger. This is pinned by the property test p021\_slippage\_cap\_monotonic.

## Worked example

Consider a market with tick size $$\delta = 0.5$$ and lot size $$\ell = 0.001$$, and three resting asks from distinct accounts: 1 unit at $$100{,}000$$, 1 unit at $$101{,}000$$, and 1 unit at $$102{,}000$$. A market buy for $$2.5$$ units walks the levels in price priority. At the first level (B.5) gives $$q^{\star} = \min(2.5, 1) = 1$$ at fill price $$P^{\star} = 100{,}000$$ per (B.6); the second level fills another unit at $$101{,}000$$; at the third the taker's remainder is $$0.5$$, so $$q^{\star} = \min(0.5, 1) = 0.5$$ at $$102{,}000$$. The taker fully fills with notional $$V = 1 \cdot 100{,}000 + 1 \cdot 101{,}000 + 0.5 \cdot 102{,}000 = 252{,}000$$, an average price of $$252{,}000 / 2.5 = 100{,}800$$ per (B.10), and the third maker rests with $$0.5$$ units remaining.

Now add a slippage cap. With a bid resting at $$99{,}000$$ and the best ask at $$100{,}000$$, the submission-time mid-price is $$P\_{mid} = (99{,}000 + 100{,}000)/2 = 99{,}500$$ per (B.3). A market buy carrying $$\beta = 50$$ basis points gets a half-band $$h = 99{,}500 \cdot 50 / 10^4 = 497.5$$ per (B.8), so the running VWAP must stay at or below $$99{,}997.5$$. The very first candidate fill at $$100{,}000$$ would set the cumulative VWAP to $$100{,}000 > 99{,}997.5$$ per (B.9), so the fill is refused and the order cancels with a slippage-cap reason and zero fills — exactly the behavior pinned by the Rust test suite.

Finally, self-trade prevention in decrement-and-cancel mode: an account with $$1$$ unit resting sends a $$0.4$$-unit crossing order against itself. Per (B.7) both orders shrink by $$\Delta\_{stp} = \min(0.4, 1) = 0.4$$ with no fill recorded; the taker (the smaller side) cancels, and the maker continues resting with $$1 - 0.4 = 0.6$$ units.

## 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.

| Expression         | Input              | Elasticity ε |
| ------------------ | ------------------ | ------------ |
| `tick_alignment`   | limit\_price       | 0            |
| `tick_alignment`   | tick\_size         | 0            |
| `mid_price`        | best\_ask          | 0.5025       |
| `mid_price`        | best\_bid          | 0.4975       |
| `fok_availability` | available\_qty     | 0            |
| `fok_availability` | quantity           | 0            |
| `fill_quantity`    | taker\_remaining   | 1            |
| `fill_quantity`    | maker\_remaining   | 0            |
| `fill_price`       | maker\_price       | 1            |
| `stp_decrement`    | taker\_remaining   | 1            |
| `stp_decrement`    | maker\_remaining   | 0            |
| `slippage_span`    | mid\_price         | 1            |
| `slippage_span`    | max\_slippage\_bps | 1            |
| `running_vwap`     | running\_filled    | -0.8         |
| `running_vwap`     | running\_notional  | 0.7976       |
| `running_vwap`     | fill\_price        | 0.2024       |
| `running_vwap`     | fill\_qty          | 0.002381     |
| `vwap_estimate`    | notional           | 1            |
| `vwap_estimate`    | requested\_qty     | -1           |

![Sensitivity tornado — Fill quantity](/files/qDTRMyje3fsJvZfCzjpq)

![Sensitivity tornado — Slippage half-band](/files/mdvXDzmTx8lxoNnywEby)

![Sensitivity tornado — Running VWAP cap check](/files/fe0ySpWzIXQPgUww8dFK)

### Response curves

![The absolute price band a capped market order may traverse grows linearly in the basis-point cap, scaled by the submission-time mid-price held constant per series.](/files/6SRkzrCWnIcU1Nc9qpBY)

*The absolute price band a capped market order may traverse grows linearly in the basis-point cap, scaled by the submission-time mid-price held constant per series.*

![Each fill exchanges the minimum of the two remaining quantities: below the maker's size the taker binds, above it the maker binds (regions marked for the 1.0-unit maker).](/files/H1AjSOBVezm2gqWUpmlL)

*Each fill exchanges the minimum of the two remaining quantities: below the maker's size the taker binds, above it the maker binds (regions marked for the 1.0-unit maker).*

![With two units already filled at an average of 100,500, the cumulative VWAP climbs toward the third level's price as more of it is consumed; the worked example's 0.5-unit fill lands at 100,800.](/files/W3a1L107Kx4DYhNUVYqo)

*With two units already filled at an average of 100,500, the cumulative VWAP climbs toward the third level's price as more of it is consumed; the worked example's 0.5-unit fill lands at 100,800.*

## References

* Derived from and adversarially verified against the Exchange's Rust implementation and its test suite.
* Sibling model: [funding-rate](/math-engine/funding-rate.md)
* Sibling model: [insurance-fund](/math-engine/insurance-fund.md)
* Sibling model: [liquidation-engine](/math-engine/liquidation-engine.md)
* Sibling model: [margin-math](/math-engine/margin-math.md)
* Sibling model: [oracle](/math-engine/oracle.md)
* Sibling model: [position-tracker](/math-engine/position-tracker.md)
* Sibling model: [settlement](/math-engine/settlement.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nexus.xyz/math-engine/order-book.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
