Files
poly-maker/tests/test_orderbook.py
Daniel Sapkota c7b686116e Getting there
2026-07-05 17:50:04 -04:00

95 lines
2.9 KiB
Python

"""Unit tests for the order book and its analytics."""
from __future__ import annotations
import pytest
from polymaker.domain import Side
from polymaker.marketdata.orderbook import OrderBook, to_no_price
def make_book() -> OrderBook:
ob = OrderBook(tick_size=0.01)
ob.apply_snapshot(
bids=[(0.40, 100), (0.41, 200), (0.42, 50)], # best bid 0.42
asks=[(0.45, 80), (0.46, 150), (0.44, 30)], # best ask 0.44
ts=1.0,
)
return ob
def test_best_bid_ask():
ob = make_book()
assert ob.best_bid().price == 0.42
assert ob.best_bid().size == 50
assert ob.best_ask().price == 0.44
assert ob.best_ask().size == 30
def test_apply_delta_add_and_remove():
ob = make_book()
ob.apply_delta(Side.BUY, 0.43, 25, ts=2.0)
assert ob.best_bid().price == 0.43
ob.apply_delta(Side.BUY, 0.43, 0, ts=3.0) # size 0 removes the level
assert ob.best_bid().price == 0.42
assert ob.last_update_ts == 3.0
def test_empty_book_views_are_none():
ob = OrderBook()
assert ob.best_bid() is None
assert ob.best_ask() is None
assert ob.microprice() is None
assert ob.is_empty
v = ob.view()
assert v.mid is None
assert v.spread is None
assert v.imbalance == 0.0
def test_microprice_pulls_toward_thin_side():
ob = OrderBook(tick_size=0.01)
# bid side much heavier than ask side -> microprice near the ask
ob.apply_snapshot(bids=[(0.40, 1000)], asks=[(0.42, 10)], ts=1.0)
mp = ob.microprice(levels=1)
assert mp is not None
assert 0.41 < mp <= 0.42 # dragged up toward the thin ask
# symmetric sizes -> mid
ob.apply_snapshot(bids=[(0.40, 100)], asks=[(0.42, 100)], ts=2.0)
assert ob.microprice(levels=1) == pytest.approx(0.41)
def test_best_with_min_size_skips_dust():
ob = OrderBook(tick_size=0.01)
# a dust order (size 1) sits at the touch; real size is one level back
ob.apply_snapshot(bids=[(0.42, 1), (0.41, 500)], asks=[(0.44, 1), (0.45, 500)], ts=1.0)
price, size, top = ob.best_with_min_size(Side.BUY, min_size=5)
assert price == 0.41 and size == 500
assert top == 0.42 # the dust touch is still reported as top
price, size, top = ob.best_with_min_size(Side.SELL, min_size=5)
assert price == 0.45 and size == 500
assert top == 0.44
def test_depth_within_band():
ob = make_book()
# bids at 0.40,0.41,0.42 all within [0.40, 0.42]
assert ob.depth_within(Side.BUY, 0.40, 0.42) == 350
assert ob.depth_within(Side.BUY, 0.415, 0.42) == 50
def test_view_second_levels_and_imbalance():
ob = make_book()
v = ob.view(min_size=0.0)
assert v.best_bid == 0.42
assert v.second_bid == 0.41
assert v.best_ask == 0.44
assert v.second_ask == 0.45
assert -1.0 <= v.imbalance <= 1.0
def test_no_price_mirror():
assert to_no_price(0.42) == pytest.approx(0.58)
assert to_no_price(0.0) == 1.0
assert to_no_price(1.0) == 0.0