"""Order book checksum for WebSocket v2 (docs.kraken.com/exchange/guides/websockets/book-checksum-v2). Top 10 asks (low→high) then top 10 bids (high→low); each level encoded as strip_leading_zeros(price without '.') + strip_leading_zeros(qty without '.'); CRC32 as unsigned int. Prices/quantities must be kept as *strings or Decimal* with the exchange's precision. """ from __future__ import annotations import zlib from decimal import Decimal def _enc(x: Decimal | str) -> str: s = str(x) if "E" in s or "e" in s: # Decimal may render exponent notation for tiny numbers s = format(Decimal(s), "f") return s.replace(".", "").lstrip("0") or "0" def book_checksum(asks: list[tuple[Decimal | str, Decimal | str]], bids: list[tuple[Decimal | str, Decimal | str]]) -> int: """asks/bids are (price, qty) with exchange precision already applied (price_decimals / qty_decimals).""" a = sorted(asks, key=lambda lv: Decimal(str(lv[0])))[:10] b = sorted(bids, key=lambda lv: Decimal(str(lv[0])), reverse=True)[:10] s = "".join(_enc(p) + _enc(q) for p, q in a) + "".join(_enc(p) + _enc(q) for p, q in b) return zlib.crc32(s.encode()) & 0xFFFFFFFF def fmt_fixed(x: Decimal, decimals: int) -> str: """Format with exactly `decimals` decimals (what Kraken uses in the checksum string).""" q = Decimal(1).scaleb(-decimals) return format(x.quantize(q), "f")