From e8c910e52d1807e2fcca3b43d80a9df6acac5387 Mon Sep 17 00:00:00 2001
From: Joel Grunbaum <joelgrun@gmail.com>
Date: Wed, 12 Jan 2022 06:26:46 +0000
Subject: [PATCH] write price level to each book

---
 book.py |  177 +++++++++++++++++++++++++++++++++++++++-------------------
 1 files changed, 118 insertions(+), 59 deletions(-)

diff --git a/book.py b/book.py
index a506adb..50543ef 100644
--- a/book.py
+++ b/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

--
Gitblit v1.9.3