Joel Grunbaum
2022-01-10 2c515f0de70ad675b5f5d25b6a496d67d8dc0463
book.py
@@ -10,8 +10,8 @@
class OrderSide(Enum):
    """Order side enum."""
    Buy = 0,
    Sell = 1
    Buy = "BUY",
    Sell = "SELL"
class ProductTypeEnum(Enum):
@@ -37,14 +37,18 @@
    side: OrderSide
    remaining_volume: int
    filled_volume: int
    timestamp: float
    id: str
    def __init__(self, price: decimal.Decimal(3), side: OrderSide,
                 volume: int):
                 volume: int, timestamp: float, id: str):
        """Initialise class."""
        self.price = price
        self.side = side
        self.remaining_volume = volume
        self.filled_volume = 0
        self.timestamp = timestamp
        self.id = id
class Level:
@@ -52,44 +56,97 @@
    price: decimal.Decimal
    volume: int
    side: OrderSide
    timestamp: float
    id: str
    def __init__(self, price: decimal.Decimal(3), volume):
    def __init__(self, order: Order):
        """Initialise class."""
        self.priority = int(price)
        self.price = price
        self.volume = volume
        self.price = order.price
        self.volume = order.remaining_volume
        self.side = order.side
        self.timestamp = order.timestamp
        self.id = order.id
    def __lt__(self, other):
        """Less than comparator."""
        if (self.price < other.price):
            return True
        if (self.side == OrderSide.Sell):
            if (self.price < other.price):
                return True
            elif (self.price == other.price and
                  self.timestamp < other.timestamp):
                return True
            else:
                return False
        else:
            return False
            if (self.price > other.price):
                return True
            elif (self.price == other.price and
                  self.timestamp < other.timestamp):
                return True
            else:
                return False
    def __gt__(self, other):
        """Greater than comparator."""
        if (self.price > other.price):
            return True
        if (self.side == OrderSide.Sell):
            if (self.price > other.price):
                return True
            elif (self.price == other.price and
                  self.timestamp < other.timestamp):
                return True
            else:
                return False
        else:
            return False
            if (self.price < other.price):
                return True
            elif (self.price == other.price and
                  self.timestamp < other.timestamp):
                return True
            else:
                return False
    def __le__(self, other):
        """Less than or equal compatator."""
        if (self.price <= other.price):
            return True
        if (self.side == OrderSide.Sell):
            if (self.price <= other.price):
                return True
            elif (self.price == other.price and
                  self.timestamp <= other.timestamp):
                return True
            else:
                return False
        else:
            return False
            if (self.price >= other.price):
                return True
            elif (self.price == other.price and
                  self.timestamp <= other.timestamp):
                return True
            else:
                return False
    def __ge__(self, other):
        """Greater than or equal comparator."""
        if (self.price >= other.price):
            return True
        if (self.side == OrderSide.Sell):
            if (self.price >= other.price):
                return True
            elif (self.price == other.price and
                  self.timestamp <= other.timestamp):
                return True
            else:
                return False
        else:
            return False
            if (self.price <= other.price):
                return True
            elif (self.price == other.price and
                  self.timestamp <= other.timestamp):
                return True
            else:
                return False
    def __eq__(self, other):
        """Equalty compatator."""
        if (self.price == other.price):
        if (self.price == other.price and self.timestamp == other.timestamp):
            return True
        else:
            return False
@@ -100,7 +157,8 @@
    def __str__(self):
        """Turn into str for printing."""
        return "Price: " + str(self.price) + ", volume: " + str(self.volume)
        return ("Price: " + str(self.price) + ", volume: " + str(self.volume) +
                ", time: " + str(self.timestamp) + ", id: " + self.id)
class Side:
@@ -111,6 +169,13 @@
    def __init__(self):
        """Initialise class."""
        self.levels = []
    def delete(self, orderId: str):
        """Delete order from side."""
        for i in self.levels:
            if (i.id == orderId):
                self.levels.remove(i)
                heapq.heapify(self.levels)
class Book:
@@ -166,64 +231,58 @@
    def ask(self, order: Order):
        """Add ask to book."""
        while(len(self.bidSide.levels) > 0 and
              self.bidSide.levels[0][1].price >= order.price):
            if (self.bidSide.levels[0][1].volume > order.remaining_volume):
                temp = self.bidSide.levels[0][1].volume
                order.filled_volume += self.bidSide.levels[0][1].volume
                self.bidSide.levels[0][1].volume -= order.remaining_volume
              self.bidSide.levels[0].price >= order.price):
            if (self.bidSide.levels[0].volume > order.remaining_volume):
                temp = self.bidSide.levels[0].volume
                order.filled_volume += self.bidSide.levels[0].volume
                self.bidSide.levels[0].volume -= order.remaining_volume
                order.remaining_volume -= temp
                break
            else:
                order.remaining_volume -= self.bidSide.levels[0][1].volume
                order.filled_volume += self.bidSide.levels[0][1].volume
                order.remaining_volume -= self.bidSide.levels[0].volume
                order.filled_volume += self.bidSide.levels[0].volume
                heapq.heappop(self.bidSide.levels)
        if (order.remaining_volume > 0):
            if (len(self.askSide.levels) > 0 and
                    self.askSide.levels[0][1].price == order.price):
                self.askSide.levels[0][1].addVolume(order.remaining_volume)
            else:
                heapq.heappush(self.askSide.levels,
                               (order.price,
                                Level(order.price, order.remaining_volume)))
            heapq.heappush(self.askSide.levels, Level(order))
    def bid(self, order: Order):
        """Add bid to book."""
        while(len(self.askSide.levels) > 0 and
              self.askSide.levels[0][1].price <= order.price):
            if (self.askSide.levels[0][1].volume > order.remaining_volume):
                temp = self.askSide.levels[0][1].volume
                order.filled_volume += self.askSide.levels[0][1].volume
                self.askSide.levels[0][1].volume -= order.remaining_volume
              self.askSide.levels[0].price <= order.price):
            if (self.askSide.levels[0].volume > order.remaining_volume):
                temp = self.askSide.levels[0].volume
                order.filled_volume += self.askSide.levels[0].volume
                self.askSide.levels[0].volume -= order.remaining_volume
                order.remaining_volume -= temp
                break
            else:
                order.remaining_volume -= self.askSide.levels[0][1].volume
                order.filled_volume -= self.askSide.levels[0][1].volume
                order.remaining_volume -= self.askSide.levels[0].volume
                order.filled_volume -= self.askSide.levels[0].volume
                heapq.heappop(self.askSide.levels)
        if (order.remaining_volume > 0):
            if (len(self.bidSide.levels) > 0 and
                    self.bidSide.levels[0][1].price == order.price):
                self.bidSide.levels[0][1].addVolume(order.remaining_volume)
            else:
                heapq.heappush(self.bidSide.levels,
                               (100 - order.price,
                                Level(order.price, order.remaining_volume)))
            heapq.heappush(self.bidSide.levels, Level(order))
    def printBook(self):
        """Test print book. Book is a heap so not strictly sorted."""
        print("Sell side")
        for i in sorted(self.askSide.levels, reverse=True):
            print(i[1])
        for i in sorted(self.askSide.levels, reverse=True)[-10:]:
            print(i)
        print("Buy side")
        for i in sorted(self.bidSide.levels):
            print(str(i[1]))
        for i in sorted(self.bidSide.levels)[:10]:
            print(str(i))
def testBook():
def testBook(orders: int = 10, printBook=True):
    """Test an example book."""
    b = Book()
    for i in range(1, 10):
        b.addOrder(Order(i, OrderSide.Buy, 10))
    for i in range(11, 20):
        b.addOrder(Order(i, OrderSide.Sell, 10))
    b.printBook()
    time = 1
    for i in range(1, orders):
        b.addOrder(Order(price=i, side=OrderSide.Buy, volume=10,
                         timestamp=time, id="a"))
        time += 1
    for i in range(orders + 1, 2 * orders):
        b.addOrder(Order(i, OrderSide.Sell, 10, time, "a"))
        time += 1
    if (printBook):
        b.printBook()
    return b