> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sory.pro/llms.txt
> Use this file to discover all available pages before exploring further.

# Market data

> One consolidated, fee-adjusted book across every venue.

```python theme={"dark"}
book = sory.book("BTC/USDT")

book.best_bid.price     # Decimal, all-in
book.best_ask.venue     # who is on the touch
book.venues             # who is in this book
book.excluded           # {venue: why it is not}
book.crossed            # was a cross present before resolution
```

Every level carries its `venue` and `symbol`, so you always know where liquidity is and which instrument it is in.

## The pipeline

Once per emit interval, for each book:

<Steps>
  <Step title="Take each routable venue's latest snapshot">
    Stale and offline venues are dropped, with reasons.
  </Step>

  <Step title="Apply your fee, signed">
    `bid × (1 − fee)`, `ask × (1 + fee)`. A maker rebate is a negative fee and needs no special case.
  </Step>

  <Step title="Merge, keeping every level">
    The emitted view is truncated to `depth`; the book routing walks is not.
  </Step>

  <Step title="Net off any cross">
    Then bucket into VWAPs, if the subscription asked for that.
  </Step>
</Steps>

<Warning>
  `book.all_in` travels with the data so a raw price and an all-in price can never meet in the same comparison by accident. If you hold a raw price — your own limit price — convert it before comparing. The router does this per venue for you.
</Warning>

## Venue health

| Status    | Meaning                                                |
| --------- | ------------------------------------------------------ |
| `Online`  | receiving updates                                      |
| `Stale`   | connected, but silent for longer than `stale_after_ms` |
| `Offline` | disconnected, symbol not listed, or not authenticated  |

```python theme={"dark"}
sory.health("BTC/USDT")   # {'binance': Health.ONLINE, 'okx': Health.STALE}
```

**Only `Online` venues appear in the book or receive orders.** A socket that stays open while silently delivering nothing is the failure that fills a hedge far through the touch, so silence is treated as a fault rather than as "no news".

A dropped stream reconnects with exponential backoff and flips health on the way out and back. The *transition* is logged, not every retry, so an outage produces two lines rather than thousands.

## VWAP depth

Ask for the price to fill a given size, and SORY returns both the VWAP and the limit price needed to achieve it. The gap between them is your expected slippage.

```python theme={"dark"}
size_buckets = {"BTC/USDT": [1, 5, 10]}             # base units
amount_buckets = {"ETH/USDT": [10_000, 50_000]}   # quote units
```

```python theme={"dark"}
for level in sory.book("BTC/USDT").asks:
    print(level.amount, level.price, level.limit_price)
# 1   100.00   100.00
# 5   101.20   103.50   <- 230 bps of slippage to fill 5
```

Each bucket is measured **from the touch**, independently: `[1, 5, 10]` means "the VWAP to fill 1", "to fill 5", "to fill 10" — not three consecutive slices.

<Note>
  A bucket the book cannot fill is omitted rather than reported short. There is no VWAP for a fill that cannot happen, and sizing off a number that was never achievable is worse than having no number.
</Note>

## Crossed markets

Aggregating across venues *will* cross, especially once fees move prices around. By default the overlapping quantity is netted out before the router sees it. Either way `book.crossed` tells you it happened — a crossed book never reaches routing unnoticed.

## Streaming

```python theme={"dark"}
async def on_book(book):
    ...

sory.on_book(on_book)
```

Called at `emit_interval_ms` (default 100ms), never under a lock, and gathered so one slow consumer cannot stall another.

## Trades

Optional. `start(trades=True)` subscribes to the public tape.

```python theme={"dark"}
await sory.start(trades=True)
sory.on_trade(handler)
sory.latest_trades(symbol="BTC/USDT")   # non-destructive; two consumers can coexist
```

Buffers are bounded. Prices are the venue's own, unadjusted — a print is a print.
