Metadata-Version: 2.4
Name: hft-lob
Version: 0.2.2
Summary: Python wrapper for a high-performance Rust orderbook CLI
Home-page: https://github.com/pratima/hft_lob
Author: Pratima Kumari
Author-email: Pratima Kumari <pratimarmoney@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/pratima/hft_lob
Requires-Python: >=3.7
Description-Content-Type: text/markdown
Dynamic: author
Dynamic: home-page
Dynamic: requires-python

# hft-lob

**hft-lob** is a Python library that wraps a high-performance Rust binary to read and decode NSE (National Stock Exchange) binary market feed files and reconstruct a **Limit Order Book (LOB)** for any instrument token. It gives you a clean Python API and a one-word CLI — no file paths or tokens on the command line, ever.

---

## Features

| # | Feature | Description |
|---|---------|-------------|
| 1 | [**get_all**](#1-get_all) | Load all LOB messages at once into a Python list |
| 2 | [**get_next**](#2-get_next) | Stream messages one at a time using a cursor |
| 3 | [**eof**](#3-eof) | Check whether all messages have been read |

---

## Installation

```bash
pip install hft-lob
```

**Requirements:**
- Linux x86_64
- Python >= 3.7
- No additional dependencies

---

## Setup (one time only)

Create a config file `~/.hft_lob` with your file path and token:

```bash
cat > ~/.hft_lob << 'EOF'
FILE=/path/to/Feed_CM_StreamID_2_29_12_2025.bin
TOKEN=1333
EOF
```

That's it. You never need to type the path or token again.

---

## CLI Usage (shortest commands)

After setup, run any function with a single word:

```bash
hft-lob get_next
```
```bash
hft-lob get_all
```
```bash
hft-lob eof
```

No file path. No token. Everything is read from `~/.hft_lob` automatically.

---

## Feature Details

### 1. `get_all`

**What it does:** Loads every LOB message from the file into memory and prints them all. Best when you want the full dataset.

```bash
hft-lob get_all
```

**Python equivalent:**
```python
from hft_lob.cli import Reader

r = Reader("/path/to/feed.bin", tokens=1333)
messages = r.get_all_messages()

print(f"Total: {len(messages)}")
print(messages[0])   # first row
print(messages[-1])  # last row
```

**Returns:** list of CSV strings, one per LOB update
**After calling:** `eof` becomes `True`

---

### 2. `get_next`

**What it does:** Returns one message at a time. Each call advances an internal cursor. Returns `None` when there are no more messages. Best for processing row by row or stopping early.

```bash
hft-lob get_next
```

**Python equivalent:**
```python
from hft_lob.cli import Reader

r = Reader("/path/to/feed.bin", tokens=1333)

# Single message
print(r.get_next_message())

# Or loop one by one
while True:
    msg = r.get_next_message()
    if msg is None:
        break
    print(msg)
```

**Returns:** one CSV string per call, or `None` when done
**After last message:** `eof` becomes `True`

---

### 3. `eof`

**What it does:** Checks whether all messages have been read. Returns `True` when done, `False` if messages remain.

```bash
hft-lob eof
```

**Python equivalent:**
```python
from hft_lob.cli import Reader

r = Reader("/path/to/feed.bin", tokens=1333)

print(r.is_end_of_file())   # False — nothing read yet
r.get_all_messages()
print(r.is_end_of_file())   # True — all messages read
```

**Returns:** `True` or `False`

---

## Python API

If you prefer using Python directly instead of the CLI:

```python
from hft_lob.cli import Reader

r = Reader("/path/to/feed.bin", tokens=1333)

r.get_all_messages()    # list of all CSV rows
r.get_next_message()    # one CSV row, or None
r.is_end_of_file()      # True / False
r.header                # column names string
r.close()               # no-op, safe to call
```

### Reader(file_path, tokens) parameters

| Parameter | Type | Description |
|-----------|------|-------------|
| `file_path` | `str` | Path to the NSE binary feed `.bin` file |
| `tokens` | `int` or `list[int]` | Instrument token(s) to extract |

---

## CSV Output Format

Each message row has **23 comma-separated fields**:

```
local_ts, exch_ts, mid_price,
bid_price_0, bid_qty_0, ask_price_0, ask_qty_0,
bid_price_1, bid_qty_1, ask_price_1, ask_qty_1,
bid_price_2, bid_qty_2, ask_price_2, ask_qty_2,
bid_price_3, bid_qty_3, ask_price_3, ask_qty_3,
bid_price_4, bid_qty_4, ask_price_4, ask_qty_4
```

| Field | Description |
|-------|-------------|
| `local_ts` | Local timestamp (nanoseconds) when message was received |
| `exch_ts` | Exchange timestamp (nanoseconds) from NSE |
| `mid_price` | (best bid + best ask) / 2 |
| `bid_price_N` | Bid price at depth level N (0 = best bid) |
| `bid_qty_N` | Total quantity at bid level N |
| `ask_price_N` | Ask price at depth level N (0 = best ask) |
| `ask_qty_N` | Total quantity at ask level N |

---

## Examples

### Parse into a dict

```python
from hft_lob.cli import Reader

r = Reader("/path/to/feed.bin", tokens=1333)
messages = r.get_all_messages()
columns = r.header.split(",")

first = dict(zip(columns, messages[0].split(",")))
print(f"Best bid: {first['bid_price_0']} x {first['bid_qty_0']}")
print(f"Best ask: {first['ask_price_0']} x {first['ask_qty_0']}")
```

### Load into pandas

```python
import io, pandas as pd
from hft_lob.cli import Reader

r = Reader("/path/to/feed.bin", tokens=1333)
messages = r.get_all_messages()

df = pd.read_csv(io.StringIO(r.header + "\n" + "\n".join(messages)))
print(df[["local_ts", "mid_price", "bid_price_0", "ask_price_0"]].head())
```

### Multiple tokens

```python
r = Reader("/path/to/feed.bin", tokens=[1333, 2885, 5900])
print(len(r.get_all_messages()))
```

---

## How It Works (Architecture)

```
hft-lob get_next
      |
      v
 ~/.hft_lob (config)         <-- FILE and TOKEN read from here
      |
      v
 hft_lob.cli.Reader          <-- Python class
      |
      v
 Rust Binary (subprocess)    <-- orderbook-linux-x86_64 (bundled)
      |
      v
 NSE Binary Feed File        <-- your .bin file
      |
      v
 CSV Output                  <-- printed to terminal / returned to Python
```

---

## Package Structure

```
hft_lob/
├── __init__.py                  <- package marker
├── cli.py                       <- Reader class + CLI main()
└── bin/
    └── orderbook-linux-x86_64   <- Rust binary (bundled, no install needed)
```

---

## Platform Support

| Platform | Supported |
|----------|-----------|
| Linux x86_64 | Yes |
| macOS | No |
| Windows | No |

---

## License

MIT
