Created
August 25, 2024 15:08
-
-
Save williamardianto/c57eb47d4e1b84516793c61b9cd8f1b5 to your computer and use it in GitHub Desktop.
Revisions
-
williamardianto created this gist
Aug 25, 2024 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,165 @@ from enum import Enum from typing import List from dataclasses import dataclass, field class OrderType(Enum): LIMIT = 1 STOP = 2 MARKET = 3 @dataclass class Order: id: str symbol: str quantity: int price: float order_type: OrderType @dataclass class Bid: price: float orders: List[Order] = field(default_factory=list) @dataclass class Ask: price: float orders: List[Order] = field(default_factory=list) class OrderBook: def __init__(self): self.bids: List[Bid] = [] self.asks: List[Ask] = [] def place_order(self, order: Order): if order.order_type == OrderType.MARKET: self._match_market_order(order) elif order.order_type == OrderType.LIMIT: self._place_limit_order(order) elif order.order_type == OrderType.STOP: self._place_stop_order(order) def _match_market_order(self, order: Order): if order.quantity > 0: self._match_buy_market_order(order) else: self._match_sell_market_order(order) def _match_buy_market_order(self, order: Order): remaining_quantity = order.quantity while remaining_quantity > 0 and self.asks: ask = self.asks[0] for ask_order in ask.orders: if remaining_quantity <= 0: break matched_quantity = min(remaining_quantity, ask_order.quantity) remaining_quantity -= matched_quantity ask_order.quantity -= matched_quantity print(f"Matched {matched_quantity} shares at price {ask.price}") if not ask.orders: self.asks.pop(0) def _match_sell_market_order(self, order: Order): remaining_quantity = -order.quantity while remaining_quantity > 0 and self.bids: bid = self.bids[-1] for bid_order in bid.orders: if remaining_quantity <= 0: break matched_quantity = min(remaining_quantity, bid_order.quantity) remaining_quantity -= matched_quantity bid_order.quantity -= matched_quantity print(f"Matched {matched_quantity} shares at price {bid.price}") if not bid.orders: self.bids.pop() def _place_limit_order(self, order: Order): if order.quantity > 0: self._place_limit_bid(order) else: self._place_limit_ask(order) def _place_limit_bid(self, order: Order): for ask in self.asks: if order.price >= ask.price: self._match_limit_bid_with_ask(order, ask) if order.quantity == 0: return self._add_bid(order) def _match_limit_bid_with_ask(self, bid_order: Order, ask: Ask): for ask_order in ask.orders: if bid_order.quantity <= 0: break matched_quantity = min(bid_order.quantity, ask_order.quantity) bid_order.quantity -= matched_quantity ask_order.quantity -= matched_quantity print(f"Matched {matched_quantity} shares at price {ask.price}") ask.orders = [order for order in ask.orders if order.quantity > 0] if not ask.orders: self.asks.remove(ask) def _add_bid(self, order: Order): for bid in self.bids: if order.price == bid.price: bid.orders.append(order) return self.bids.append(Bid(order.price, [order])) self.bids.sort(key=lambda b: b.price, reverse=True) def _place_limit_ask(self, order: Order): for bid in self.bids: if order.price <= bid.price: self._match_limit_ask_with_bid(order, bid) if order.quantity == 0: return self._add_ask(order) def _match_limit_ask_with_bid(self, ask_order: Order, bid: Bid): for bid_order in bid.orders: if ask_order.quantity <= 0: break matched_quantity = min(-ask_order.quantity, bid_order.quantity) ask_order.quantity += matched_quantity bid_order.quantity -= matched_quantity print(f"Matched {matched_quantity} shares at price {bid.price}") bid.orders = [order for order in bid.orders if order.quantity > 0] if not bid.orders: self.bids.remove(bid) def _add_ask(self, order: Order): for ask in self.asks: if order.price == ask.price: ask.orders.append(order) return self.asks.append(Ask(order.price, [order])) self.asks.sort(key=lambda a: a.price) def _place_stop_order(self, order: Order): # Simplified implementation, assuming stop orders are placed as market orders when the stop price is reached if order.quantity > 0: for ask in self.asks: if ask.price >= order.price: self._match_market_order(Order(order.id, order.symbol, order.quantity, 0, OrderType.MARKET)) break else: for bid in self.bids: if bid.price <= order.price: self._match_market_order(Order(order.id, order.symbol, order.quantity, 0, OrderType.MARKET)) break # Usage example order_book = OrderBook() # Place limit orders order_book.place_order(Order("1", "AAPL", 100, 150.0, OrderType.LIMIT)) order_book.place_order(Order("2", "AAPL", -50, 160.0, OrderType.LIMIT)) order_book.place_order(Order("3", "AAPL", 200, 140.0, OrderType.LIMIT)) order_book.place_order(Order("4", "AAPL", -100, 155.0, OrderType.LIMIT)) # Place market orders order_book.place_order(Order("5", "AAPL", 150, 0, OrderType.MARKET)) order_book.place_order(Order("6", "AAPL", -120, 0, OrderType.MARKET)) # Place stop orders order_book.place_order(Order("7", "AAPL", 100, 145.0, OrderType.STOP)) order_book.place_order(Order("8", "AAPL", -80, 165.0, OrderType.STOP))