syntax = "proto3"; package kairos.v1; import "kairos/v1/common.proto"; option go_package = "github.com/kairos/proto/kairos/v1"; // OrderbookSide represents one side (bids or asks) of an orderbook message OrderbookSide { repeated PriceLevel levels = 1; } // OutcomeOrderbook represents the orderbook for a single outcome message OutcomeOrderbook { OrderbookSide bids = 1; OrderbookSide asks = 2; } // OrderbookSnapshot represents a complete orderbook snapshot for a contract message OrderbookSnapshot { Provider provider = 1; string contract_id = 2; // Timestamp in microseconds since Unix epoch int64 timestamp_us = 3; // Token IDs for each outcome repeated string token_ids = 4; // Human-readable outcome names repeated string outcome_names = 5; // Orderbooks for each outcome (indexed same as token_ids/outcome_names) repeated OutcomeOrderbook outcomes = 6; // Sequence number for ordering (monotonic per contract) uint64 seq = 7; // Owning streamer-instance epoch (subreg fencing token, bumped on ownership // transfer). Consumers drop a snapshot/delta whose epoch is below the highest // seen for the contract (a superseded owner), so a brief double-publish during // an ownership handoff can't collide seq spaces and freeze the book. 0 = // unfenced (legacy publishers / Redis ownership backend). uint64 epoch = 8; // Divisor for this snapshot's prices. 0 = the global 10000, which every // prediction-market provider uses and which this field does not change. // // Perpetuals need this because one fixed scale cannot carry them: at 10000, // 131 of Hyperliquid's 177 live coins truncate (HMSTR quotes 0.000169 and // would publish as 0.0001, off by 41%), and at a scale fine enough for those // the price of BTC overflows int32. Each perpetual snapshot therefore carries // the smallest power of ten that represents its own levels exactly. This is // safe to vary per snapshot only because perpetual books publish as whole // baselines, so a snapshot is never merged with one at a different scale. int64 price_scale = 9; // Divisor for this snapshot's sizes. 0 = whatever scale the publisher has // always used, so existing providers are unaffected. // // Perpetual depth spans as far as its prices do and breaks in the same silent // way: a fixed 1e12 scale overflows int64 for 6 of 9 sampled Hyperliquid // coins, and HMSTR's real 167M-token depth would clamp to int64 max and // advertise effectively infinite liquidity. Chosen per snapshot by the same // rule as price_scale. int64 size_scale = 10; } // DeltaLevel represents a changed price level. // size_scaled == 0 means the level was removed. message DeltaLevel { // Price scaled by 10000 (same encoding as PriceLevel) int32 price = 1; // Size scaled for precision. 0 = level removed. int64 size_scaled = 2; } // DeltaSide represents changes on one side (bids or asks) of a book. message DeltaSide { repeated DeltaLevel levels = 1; } // OutcomeDelta represents changes for one outcome's orderbook. message OutcomeDelta { DeltaSide bids = 1; DeltaSide asks = 2; } // OrderbookDelta represents incremental changes since the last snapshot/delta. // Clients apply these to their locally reconstructed book. // If a sequence gap is detected, clients should request a full snapshot resync. message OrderbookDelta { string contract_id = 1; int64 timestamp_us = 2; // Delta per outcome (indexed same as snapshot's outcomes) repeated OutcomeDelta outcomes = 3; // Monotonically increasing sequence number per contract uint64 seq = 4; // Sequence number of the baseline snapshot this delta applies to uint64 snapshot_seq = 5; // Owning streamer-instance epoch — see OrderbookSnapshot.epoch. 0 = unfenced. uint64 epoch = 6; }