Skip to content

Instantly share code, notes, and snippets.

@williamardianto
Created August 25, 2024 15:08
Show Gist options
  • Select an option

  • Save williamardianto/c57eb47d4e1b84516793c61b9cd8f1b5 to your computer and use it in GitHub Desktop.

Select an option

Save williamardianto/c57eb47d4e1b84516793c61b9cd8f1b5 to your computer and use it in GitHub Desktop.
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))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment