Repository: liampauling/flumine
Pull request #428 (2021-05-13 07:47:07)

Task/simualted imp


Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index 6ffa5f6..3d9b43d 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,22 +3,6 @@
 Release History
 ---------------
 
-1.18.8 (2021-05-14)
-+++++++++++++++++++
-
-**Improvements**
-
-- Simulation optimisations
-
-**Bug Fixes**
-
-- #173 dead heat profit calculation (@lunswor)
-- listenerKwargs inplay / MoC / SP orders fix (@jsphon)
-
-**Libraries**
-
-- black upgraded to 21.5b1
-
 1.18.7 (2021-05-10)
 +++++++++++++++++++
 
diff --git a/flumine/__version__.py b/flumine/__version__.py
index 2fa773b..21cea79 100644
--- a/flumine/__version__.py
+++ b/flumine/__version__.py
@@ -1,6 +1,6 @@
 __title__ = "flumine"
 __description__ = "Betfair trading framework"
 __url__ = "https://github.com/liampauling/flumine"
-__version__ = "1.18.8"
+__version__ = "1.18.7"
 __author__ = "Liam Pauling"
 __license__ = "MIT"
diff --git a/flumine/events/events.py b/flumine/events/events.py
index d5ad22a..69a37c6 100644
--- a/flumine/events/events.py
+++ b/flumine/events/events.py
@@ -29,10 +29,12 @@ class QueueType(Enum):
     LOGGING = "Logging queue"
 
 
-class BaseEvent:  # todo __slots__?
+class BaseEvent:
     EVENT_TYPE = None
     QUEUE_TYPE = None
 
+    __slots__ = ["_time_created", "event", "callback"]
+
     def __init__(self, event):
         self._time_created = datetime.datetime.utcnow()
         self.event = event
diff --git a/flumine/markets/middleware.py b/flumine/markets/middleware.py
index c8eea79..4a14ad1 100644
--- a/flumine/markets/middleware.py
+++ b/flumine/markets/middleware.py
@@ -3,7 +3,7 @@ from collections import defaultdict
 from betfairlightweight.resources.bettingresources import RunnerBook
 
 from ..order.order import OrderStatus, OrderTypes
-from ..utils import get_price, wap
+from ..utils import wap
 
 logger = logging.getLogger(__name__)
 
@@ -134,11 +134,11 @@ class SimulatedMiddleware(Middleware):
 
     @staticmethod
     def _process_simulated_orders(market, market_analytics: dict) -> None:
-        for order in market.blotter.live_orders:
+        for order in market.blotter._live_orders:
             if order.simulated and order.status == OrderStatus.EXECUTABLE:
-                runner_analytics = market_analytics.get(
+                runner_analytics = market_analytics[
                     (order.selection_id, order.handicap)
-                )
+                ]
                 order.simulated(market.market_book, runner_analytics)
 
     @staticmethod
@@ -169,36 +169,45 @@ class RunnerAnalytics:
         if update:
             self.middle = self._calculate_middle(self._runner)  # use last update
             self.matched = self._calculate_matched(runner)
-            self.traded = self._calculate_traded(runner.ex.traded_volume)
-            self._traded_volume = runner.ex.traded_volume
+            _tv = runner.ex.traded_volume
+            if self._traded_volume == _tv:
+                self.traded = {}
+            else:
+                self.traded = self._calculate_traded(_tv)
+            self._traded_volume = _tv
             self._runner = runner
         else:
             self.matched = 0
             self.traded = {}
 
     def _calculate_traded(self, traded_volume: list) -> dict:
-        if self._traded_volume == traded_volume:
-            return {}
-        else:
-            p_v, traded = self._p_v, {}
-            # create dictionary
-            c_v = {i["price"]: i["size"] for i in traded_volume}
-            # calculate difference
-            for key, value in c_v.items():
-                if key in p_v:
-                    new_value = float(value) - float(p_v[key])
-                    if new_value > 0:
-                        traded[key] = round(new_value, 2)
-                else:
-                    traded[key] = value
-            # cache for next update
-            self._p_v = c_v
-            return traded
+        p_v, traded = self._p_v, {}
+        # create dictionary
+        c_v = {i["price"]: i["size"] for i in traded_volume}
+        # calculate difference
+        for key, value in c_v.items():
+            if key in p_v:
+                new_value = float(value) - float(p_v[key])
+                if new_value > 0:
+                    traded[key] = round(new_value, 2)
+            else:
+                traded[key] = value
+        # cache for next update
+        self._p_v = c_v
+        return traded
 
     @staticmethod
     def _calculate_middle(runner: RunnerBook) -> float:
-        back = get_price(runner.ex.available_to_back, 0) or 0
-        lay = get_price(runner.ex.available_to_lay, 0) or 1001
+        _back = runner.ex.available_to_back
+        if _back:
+            back = _back[0]["price"]
+        else:
+            back = 0
+        _lay = runner.ex.available_to_lay
+        if _lay:
+            lay = _lay[0]["price"]
+        else:
+            lay = 1001
         return (float(back) + float(lay)) / 2
 
     def _calculate_matched(self, runner: RunnerBook) -> float:
@@ -206,4 +215,7 @@ class RunnerAnalytics:
         total_matched = (
             runner.total_matched or prev_total_matched
         )  # handles non-runner -> 0
-        return round(total_matched - prev_total_matched, 2)
+        if total_matched != prev_total_matched:
+            return round(total_matched - prev_total_matched, 2)
+        else:
+            return 0.0


Test patch:
diff --git a/requirements-test.txt b/requirements-test.txt
index ef0c0d2..7e1a600 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -1,5 +1,5 @@
 # Tests & Linting
-black==21.5b1
+black==21.5b0
 coverage
 
 # Documentation
diff --git a/tests/test_events.py b/tests/test_events.py
index 2e1cf39..86efbd4 100644
--- a/tests/test_events.py
+++ b/tests/test_events.py
@@ -21,6 +21,5 @@ class BaseEventTest(unittest.TestCase):
         self.assertGreaterEqual(self.base_event.elapsed_seconds, 0)
 
     def test_str(self):
-        self.base_event.EVENT_TYPE = events.EventType.MARKET_BOOK
-        self.base_event.QUEUE_TYPE = events.QueueType.HANDLER
+        self.base_event = events.MarketBookEvent(None)
         self.assertEqual(str(self.base_event), "<MARKET_BOOK [HANDLER]>")
diff --git a/tests/test_middleware.py b/tests/test_middleware.py
index 2ae65b2..73806e3 100644
--- a/tests/test_middleware.py
+++ b/tests/test_middleware.py
@@ -170,15 +170,17 @@ class SimulatedMiddlewareTest(unittest.TestCase):
 
     def test__process_simulated_orders(self):
         mock_market_book = mock.Mock()
-        mock_order = mock.Mock()
-        mock_order.status = OrderStatus.EXECUTABLE
         mock_market = mock.Mock()
-        mock_order_two = mock.Mock()
-        mock_order_two.status = OrderStatus.PENDING
-        mock_order_three = mock.Mock()
-        mock_order_three.status = OrderStatus.EXECUTABLE
-        mock_order_three._simulated = False
-        mock_market.blotter.live_orders = [
+        mock_order = mock.Mock(
+            selection_id=123, handicap=1, status=OrderStatus.EXECUTABLE
+        )
+        mock_order_two = mock.Mock(
+            selection_id=123, handicap=1, status=OrderStatus.PENDING
+        )
+        mock_order_three = mock.Mock(
+            selection_id=123, handicap=1, status=OrderStatus.EXECUTABLE, simulated=False
+        )
+        mock_market.blotter._live_orders = [
             mock_order,
             mock_order_two,
             mock_order_three,