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

# Maintain a live price book

> Register the events you care about and keep a correct book from offer, remove_offer and clear_events.

A correct book is a dictionary keyed by `(sport, event_id, bet_type)` whose values are the latest `price_list`. Keep it correct with three rules.

## The three rules

1. **`offer` is a full replacement** for that triple, not a delta. Overwrite, do not merge.
2. **`remove_offer`** means that bet type has no liquidity left. Delete it. Do not leave last-known prices in the book.
3. **`clear_events`** means the server lost its upstream feed. Drop everything and wait for the fresh snapshot and `sync`.

## The code

```python theme={"dark"}
import json, os
from websockets.sync.client import connect

KEY = os.environ["MAGICMARKETS_API_KEY"]
book = {}
events = {}

def key(p):
    return (p["sport"], p["event_id"], p["bet_type"])

def best(price_list):
    return price_list[0]["effective"]["price"] if price_list else None

with connect(f"wss://magicmarkets.com/v2/stream?api_key={KEY}") as ws:
    synced = False
    while not synced:
        for entry in json.loads(ws.recv())["data"]:
            if entry[0] == "event":
                events[entry[1]["event_id"]] = entry[1]
            elif entry[0] == "sync":
                synced = True

    for ev in list(events.values())[:10]:
        ws.send(json.dumps(["register_event", ev["sport"], ev["event_id"]]))

    while True:
        for entry in json.loads(ws.recv())["data"]:
            tag = entry[0]
            p = entry[1] if len(entry) > 1 else None
            if tag == "offer":
                book[key(p)] = p["price_list"]
            elif tag == "remove_offer":
                book.pop(key(p), None)
            elif tag == "event":
                events[p["event_id"]] = p
            elif tag == "remove_event":
                events.pop(p["event_id"], None)
                for k in [k for k in book if k[1] == p["event_id"]]:
                    del book[k]
            elif tag == "clear_events":
                book.clear()
                events.clear()
```

## Reading the book

`price_list` is sorted by decimal price descending, so `price_list[0]` is the highest advertised price and its `max` is the stake advertised there. Offer prices are indicative. A book can show prices that cross, and not every level can be traded. The price you can trade is the `pmm` quote for your betslip. An `against` offer is priced as odds on the outcome not happening, so do not compare its price directly with the `for` price. To put both sides on one scale, convert an `against` price `p` to the equivalent lay price `1 / (1 - 1/p)`.

```python theme={"dark"}
for (sport, event_id, bet_type), pl in book.items():
    if bet_type.startswith("for,") and pl:
        print(events[event_id]["event_name"], bet_type, best(pl), pl[0]["effective"]["max"])
```

## Depth

Each entry in `price_list` is one price level. Summing `max` across levels gives the advertised depth on that side. Offer prices are indicative, and not every level can be traded. Convert the `against` offer as shown above, then compare it with the `for` offer for the same selection to see the spread and where the size sits.

## Things that go wrong

* **Merging instead of replacing.** Stale levels linger after the market moves. Always overwrite the whole list.
* **Ignoring `remove_offer`.** You quote against liquidity that is gone.
* **Ignoring `clear_events`.** Everything you hold is stale until the next `sync`.
* **Reading too slowly.** Backpressure closes the socket with code 1008, or with a bare TCP close if you stopped reading. Hand frames to a queue if processing is heavy.

See [WebSocket stream](/developers/websocket-stream) for the full protocol and [Stream many events](/developers/guides/multi-event-streaming) for scaling this up.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.