syntax = "proto3"; option java_multiple_files = true; option java_package = "com.dexorder.proto"; // Exchange rate for a single quote currency → USD conversion message QuoteCurrencyRate { string currency = 1; // "BTC", "ETH", "USDT", "USDC" double usd_rate = 2; // conversion rate to USD (1.0 for USD stablecoins) string source_ticker = 3; // "BTC/USDT.BINANCE" — source market used for rate uint64 timestamp = 4; // nanoseconds when rate was observed } // Index of quote currency → USD rates used to compute std_quote_volume. // Embedded in Ticker24h so consumers have full audit trail. message QuoteCurrencyIndex { repeated QuoteCurrencyRate rates = 1; uint64 generated_at = 2; // nanoseconds } // 24-hour rolling market stats for a single symbol message TickerStats { // Required: always present for any valid ticker string ticker = 1; // "BTC/USDT.BINANCE" string exchange_id = 2; // "BINANCE" string base_asset = 3; // "BTC" string quote_asset = 4; // "USDT" double last_price = 5; // last traded price in quote currency double price_change_pct = 6; // 24h price change as percentage (e.g. 2.5 = +2.5%) double quote_volume_24h = 7; // raw 24h volume in quote asset uint64 timestamp = 8; // nanoseconds, snapshot time // Optional: not all exchanges / markets provide these optional double bid_price = 9; optional double ask_price = 10; optional double open_24h = 11; optional double high_24h = 12; optional double low_24h = 13; optional double volume_24h = 14; // base-asset volume (0 is valid on tiny markets) optional double std_quote_volume = 15; // quote_volume_24h normalized to USD; null if conversion unknown optional uint32 num_trades = 16; // 24h trade count (0 is valid on tiny markets) } // Full Ticker24h snapshot for one exchange: all symbols + currency index // Published via ZMQ XPUB topic: "{exchange_id}|ticker24h" (scheduled) // or "RESPONSE:{client_id}" (client-initiated) message Ticker24h { string exchange_id = 1; repeated TickerStats tickers = 2; uint64 generated_at = 3; // nanoseconds QuoteCurrencyIndex currency_index = 4; } // Kafka message written by ingestor after fetchTickers() call (topic: market-ticker) message TickerBatch { string exchange_id = 1; repeated TickerStats tickers = 2; uint64 fetched_at = 3; // nanoseconds optional string client_id = 4; // non-empty = client-initiated; absent = scheduled broadcast optional string request_id = 5; // echoed for tracing }