Download tests/test_order_book.py from lablab-ai-amd-developer-hackathon/Marketmind: direct link, hf CLI and curl.
- Browser
- Download file 8.22 kB
-
https://huggingface.co/spaces/lablab-ai-amd-developer-hackathon/Marketmind/resolve/main/tests/test_order_book.py
- Command line
-
hf download hf://spaces/lablab-ai-amd-developer-hackathon/Marketmind/tests/test_order_book.py
-
curl -L -o test_order_book.py https://huggingface.co/spaces/lablab-ai-amd-developer-hackathon/Marketmind/resolve/main/tests/test_order_book.py
8.22 kB
| """ | |
| Unit tests for the CDA Order Book engine. | |
| Tests per Phase 1 spec: | |
| - Crossing orders execute correctly | |
| - Non-crossing orders rest in book | |
| - Price-time priority | |
| - Partial fills | |
| - Trade log accuracy | |
| """ | |
| import sys | |
| import os | |
| # Add parent to path so we can import marketmind | |
| sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..")) | |
| from engine.order_book import OrderBook, Order, Side, Trade | |
| def test_non_crossing_orders_rest(): | |
| """Non-crossing orders should rest in the book without matching.""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| # Bid at 99, Ask at 101 — no cross | |
| bid = Order(agent_id="agent_a", side=Side.BUY, price=99.0, quantity=5, timestamp=1) | |
| ask = Order(agent_id="agent_b", side=Side.SELL, price=101.0, quantity=5, timestamp=1) | |
| trades_bid = book.submit_order(bid) | |
| trades_ask = book.submit_order(ask) | |
| assert trades_bid == [], "Non-crossing bid should not produce trades" | |
| assert trades_ask == [], "Non-crossing ask should not produce trades" | |
| assert book.best_bid == 99.0 | |
| assert book.best_ask == 101.0 | |
| assert book.mid_price == 100.0 | |
| assert book.spread == 2.0 | |
| assert len(book.bids) == 1 | |
| assert len(book.asks) == 1 | |
| print("✓ test_non_crossing_orders_rest") | |
| def test_crossing_orders_execute(): | |
| """When a buy crosses the ask, a trade should execute.""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| # Resting ask at 100 | |
| ask = Order(agent_id="seller", side=Side.SELL, price=100.0, quantity=5, timestamp=1) | |
| book.submit_order(ask) | |
| # Incoming buy at 100 — crosses the ask | |
| buy = Order(agent_id="buyer", side=Side.BUY, price=100.0, quantity=5, timestamp=2) | |
| trades = book.submit_order(buy) | |
| assert len(trades) == 1 | |
| t = trades[0] | |
| assert t.price == 100.0 | |
| assert t.quantity == 5 | |
| assert t.buyer_id == "buyer" | |
| assert t.seller_id == "seller" | |
| assert t.aggressor_side == Side.BUY | |
| # Both sides fully filled — book should be empty | |
| assert len(book.bids) == 0 | |
| assert len(book.asks) == 0 | |
| print("✓ test_crossing_orders_execute") | |
| def test_partial_fill(): | |
| """A larger buy should partially fill against a smaller ask, with residual resting.""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| # Resting ask: 3 units at 100 | |
| ask = Order(agent_id="seller", side=Side.SELL, price=100.0, quantity=3, timestamp=1) | |
| book.submit_order(ask) | |
| # Incoming buy: 5 units at 100 — should fill 3, rest 2 | |
| buy = Order(agent_id="buyer", side=Side.BUY, price=100.0, quantity=5, timestamp=2) | |
| trades = book.submit_order(buy) | |
| assert len(trades) == 1 | |
| assert trades[0].quantity == 3 | |
| assert len(book.asks) == 0 # ask fully consumed | |
| assert len(book.bids) == 1 # residual buy rests | |
| assert book.bids[0].quantity == 2 | |
| assert book.bids[0].agent_id == "buyer" | |
| print("✓ test_partial_fill") | |
| def test_price_priority(): | |
| """Best price should match first (highest bid, lowest ask).""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| # Two bids at different prices | |
| bid_low = Order(agent_id="bidder_low", side=Side.BUY, price=98.0, quantity=5, timestamp=1) | |
| bid_high = Order(agent_id="bidder_high", side=Side.BUY, price=100.0, quantity=5, timestamp=2) | |
| book.submit_order(bid_low) | |
| book.submit_order(bid_high) | |
| assert book.best_bid == 100.0, f"Best bid should be 100, got {book.best_bid}" | |
| # Incoming sell at 99 — should match the 100 bid (better price), not the 98 bid | |
| sell = Order(agent_id="seller", side=Side.SELL, price=99.0, quantity=3, timestamp=3) | |
| trades = book.submit_order(sell) | |
| assert len(trades) == 1 | |
| assert trades[0].buyer_id == "bidder_high" | |
| assert trades[0].price == 100.0 # fills at passive order's price | |
| assert trades[0].quantity == 3 | |
| print("✓ test_price_priority") | |
| def test_time_priority(): | |
| """At the same price level, earlier orders should fill first (FIFO).""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| # Two asks at same price, different timestamps | |
| ask_early = Order(agent_id="early_seller", side=Side.SELL, price=100.0, quantity=5, timestamp=1) | |
| ask_late = Order(agent_id="late_seller", side=Side.SELL, price=100.0, quantity=5, timestamp=2) | |
| book.submit_order(ask_early) | |
| book.submit_order(ask_late) | |
| # Buy 3 at 100 — should match the earlier ask | |
| buy = Order(agent_id="buyer", side=Side.BUY, price=100.0, quantity=3, timestamp=3) | |
| trades = book.submit_order(buy) | |
| assert len(trades) == 1 | |
| assert trades[0].seller_id == "early_seller" | |
| print("✓ test_time_priority") | |
| def test_multi_level_fill(): | |
| """A large aggressive order should sweep through multiple price levels.""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| # Ask book: 3 @ 100, 5 @ 101, 2 @ 102 | |
| book.submit_order(Order("s1", Side.SELL, 100.0, 3, 1)) | |
| book.submit_order(Order("s2", Side.SELL, 101.0, 5, 2)) | |
| book.submit_order(Order("s3", Side.SELL, 102.0, 2, 3)) | |
| # Buy 7 @ 102 — should eat through 100 and 101 levels | |
| buy = Order(agent_id="buyer", side=Side.BUY, price=102.0, quantity=7, timestamp=4) | |
| trades = book.submit_order(buy) | |
| assert len(trades) == 2 | |
| assert trades[0].price == 100.0 and trades[0].quantity == 3 # first level | |
| assert trades[1].price == 101.0 and trades[1].quantity == 4 # partial second level | |
| # s2 should have 1 unit remaining at 101 | |
| assert len(book.asks) == 2 | |
| assert book.asks[0].price == 101.0 | |
| assert book.asks[0].quantity == 1 | |
| assert book.asks[1].price == 102.0 | |
| # No residual buy (7 filled: 3 + 4) | |
| assert len(book.bids) == 0 | |
| print("✓ test_multi_level_fill") | |
| def test_trade_log(): | |
| """Trade log should accumulate all executed trades.""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| book.submit_order(Order("s1", Side.SELL, 100.0, 5, 1)) | |
| book.submit_order(Order("b1", Side.BUY, 100.0, 3, 2)) | |
| book.set_tick(2) | |
| book.submit_order(Order("s2", Side.SELL, 99.0, 2, 3)) | |
| book.submit_order(Order("b2", Side.BUY, 99.0, 2, 4)) | |
| assert len(book.trade_log) == 2 | |
| assert book.trade_log[0].tick == 1 | |
| assert book.trade_log[1].tick == 2 | |
| print("✓ test_trade_log") | |
| def test_snapshot(): | |
| """Snapshot should return correct book state.""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| book.submit_order(Order("b1", Side.BUY, 99.0, 10, 1)) | |
| book.submit_order(Order("s1", Side.SELL, 101.0, 8, 2)) | |
| snap = book.snapshot() | |
| assert snap["best_bid"] == 99.0 | |
| assert snap["best_ask"] == 101.0 | |
| assert snap["mid_price"] == 100.0 | |
| assert snap["spread"] == 2.0 | |
| assert snap["bid_depth"] == 10 | |
| assert snap["ask_depth"] == 8 | |
| assert snap["last_trade_price"] is None # no trades yet | |
| print("✓ test_snapshot") | |
| def test_cancel_agent_orders(): | |
| """Canceling an agent's orders should remove only their orders.""" | |
| book = OrderBook() | |
| book.set_tick(1) | |
| book.submit_order(Order("a1", Side.BUY, 99.0, 5, 1)) | |
| book.submit_order(Order("a2", Side.BUY, 98.0, 5, 2)) | |
| book.submit_order(Order("a1", Side.SELL, 102.0, 5, 3)) | |
| book.cancel_agent_orders("a1") | |
| assert len(book.bids) == 1 | |
| assert book.bids[0].agent_id == "a2" | |
| assert len(book.asks) == 0 | |
| print("✓ test_cancel_agent_orders") | |
| def test_self_trade_prevention_not_required(): | |
| """ | |
| Note: The spec doesn't require self-trade prevention. | |
| Documenting that an agent CAN match against itself (this is fine in a simulation). | |
| """ | |
| book = OrderBook() | |
| book.set_tick(1) | |
| book.submit_order(Order("same_agent", Side.SELL, 100.0, 5, 1)) | |
| trades = book.submit_order(Order("same_agent", Side.BUY, 100.0, 3, 2)) | |
| # Self-trade is allowed in this simulation | |
| assert len(trades) == 1 | |
| assert trades[0].buyer_id == "same_agent" | |
| assert trades[0].seller_id == "same_agent" | |
| print("✓ test_self_trade (allowed in simulation)") | |
| if __name__ == "__main__": | |
| test_non_crossing_orders_rest() | |
| test_crossing_orders_execute() | |
| test_partial_fill() | |
| test_price_priority() | |
| test_time_priority() | |
| test_multi_level_fill() | |
| test_trade_log() | |
| test_snapshot() | |
| test_cancel_agent_orders() | |
| test_self_trade_prevention_not_required() | |
| print("\n✅ All order book tests passed.") | |