# Guide — lob-orderbook
High-performance limit order book for multi-broker trading systems.
## Import
```toml
[dependencies]
lob-orderbook = "0.1.0"
```
## Quick Start
### Option A — Full System (NATS + Health Server + Market Window)
Each broker runs as its own process with unique config:
```rust
use lob_orderbook::{run_limit_order_book_full, BrokerConfig};
#[tokio::main]
async fn main() {
let config = BrokerConfig {
broker_name: "zerodha".to_string(),
health_port: 8081,
};
let store = run_limit_order_book_full(config).await.unwrap();
// store: Arc<OrderBookStore> — keep for queries
tokio::signal::ctrl_c().await.unwrap();
}
```
### Option B — Just the Order Book Store (no NATS)
```rust
use lob_orderbook::{run_limit_order_book, init_module_logger};
use jsonl_logger::jsonl_logger;
#[tokio::main]
async fn main() {
let logger = jsonl_logger::init().unwrap().clone();
let store = run_limit_order_book(logger, "my_broker").await.unwrap();
}
```
## Feeding Market Data
Deserialize exchange data into `MarketDepthData` and call `update_book`:
```rust
use lob_orderbook::MarketDepthData;
let data = MarketDepthData {
exch_timestamp: 1700000000123,
unified_symbol: "BTCUSD".to_string(),
bids: vec![(50000.0, 10), (49900.0, 20)],
asks: vec![(50100.0, 5), (50200.0, 15)],
};
store.update_book(&data)?;
```
> Timestamp gating: strictly older timestamps are rejected. Equal timestamps are allowed (safe for exchange reconnects).
## Querying the Book
```rust
let best_bid = store.get_best_bid("BTCUSD")?; // Some(50000.0)
let best_ask = store.get_best_ask("BTCUSD")?; // Some(50100.0)
let mid = store.calculate_mid_price("BTCUSD")?; // Some(50050.0)
let spread = store.calculate_spread("BTCUSD")?; // Some(100.0)
let liquidity = store.calculate_order_book_liquidity("BTCUSD")?;
let symbols = store.get_all_symbols();
```
## Pre-Trade Checks
Check if an order is fillable:
```rust
// Is there 30+ units of BTC on the bid side at price >= 49900?
let available = store.check_quantity_availability_with_price("BTCUSD", 49900.0, 30, true)?;
```
Simulate market impact:
```rust
// Walk the ask book for a buy order of 50 units
let result = store.calculate_market_impact("BTCUSD", 50, true)?;
if let Some((avg_price, impact_price, executed, filled)) = result {
println!("Avg: {avg_price}, Filled: {filled}");
}
```
## Multi-Broker Setup
Run one process per broker, each with unique `BrokerConfig`:
| Zerodha | `"zerodha"` | `8081` | `ORDER_MANAGER_zerodha` | `limit_order_book_zerodha.db` |
| ICICI | `"icici"` | `8082` | `ORDER_MANAGER_icici` | `limit_order_book_icici.db` |
| Angel | `"angel"` | `8083` | `ORDER_MANAGER_angel` | `limit_order_book_angel.db` |
## Environment Variables
| `NATS_PORT` | Yes | NATS server port (e.g. `4222`) |
| `PROJECT_DIRECTORY` | Yes | Root path for logs + metrics DB |
## Public API
| `BrokerConfig` | Per-broker config: `broker_name`, `health_port` |
| `OrderBookStore` | Thread-safe order book store (dashmap) |
| `MarketDepthData` | Input data struct: `exch_timestamp`, `unified_symbol`, `bids`, `asks` |
| `OrderBook` | Per-symbol book with `BTreeMap`-based price levels |
| `MarketWindowConfig` | Trading hours window config |
| `run_limit_order_book_full(config)` | Full system entry point (NATS + health server + market window) |
| `run_limit_order_book(logger, name)` | Store-only entry point |
| `process_buffered_messages(messages, store, logger)` | Batch process pre-serialized JSON messages |
| `print_best_ask_loop(store, logger, symbol)` | Debug monitor for best ask |
| `init_module_logger(name)` | Initialize logger with broker prefix |
## Notes
- **One broker per process** — each process runs independently with its own `BrokerConfig`
- All brokers subscribe to the same NATS subject `"marketdepth.data"`
- NATS URL is always `nats://127.0.0.1:{NATS_PORT}` (from env, no `NATS_URL` override)
- Market window uses `trading_hours` library — standard across all brokers