Repository: liampauling/flumine
Pull request #456 (2021-06-23 22:12:32)

Iss454 nr adjustments
https://github.com/liampauling/flumine/issues/454


Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index 9d47d29..d868ca5 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,18 +3,6 @@
 Release History
 ---------------
 
-1.19.6 (2021-07-09)
-+++++++++++++++++++
-
-**Improvements**
-
-- #452 transaction force parameter (@flxbe)
-
-**Bug Fixes**
-
-- #454 SP nr adjustments (@jsphon)
-- Handle missing mc from historic files (@mlabour)
-
 1.19.5 (2021-07-05)
 +++++++++++++++++++
 
diff --git a/flumine/__version__.py b/flumine/__version__.py
index b622618..76c3946 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.19.6"
+__version__ = "1.19.5"
 __author__ = "Liam Pauling"
 __license__ = "MIT"
diff --git a/flumine/markets/middleware.py b/flumine/markets/middleware.py
index 61eff19..bafe57c 100644
--- a/flumine/markets/middleware.py
+++ b/flumine/markets/middleware.py
@@ -99,7 +99,40 @@ class SimulatedMiddleware(Middleware):
                         extra=order.info,
                     )
                 else:
+                    # TODO: "Where an SP lay bet in a win market has a maximum odds limit specified,..."
                     if (
+                        order.order_type.ORDER_TYPE == OrderTypes.MARKET_ON_CLOSE
+                    ) and order.side == "LAY":
+                        if market.market_type == "WIN":
+                            runner = [
+                                x
+                                for x in market.market_book.runners
+                                if x.selection_id == order.selection_id
+                                and x.handicap == order.handicap
+                            ][0]
+                            runner_adjustment_factor = runner.adjustment_factor
+                            # See https://github.com/liampauling/flumine/issues/454
+                            multiplier = 1 - (
+                                removal_adjustment_factor
+                                / (100 - runner_adjustment_factor)
+                            )
+                            order.order_type.liability *= multiplier
+                            logger.warning(
+                                "WIN MARKET_ON_CLOSE Order adjusted due to non runner {0}".format(
+                                    order.selection_id
+                                ),
+                                extra=order.info,
+                            )
+                        elif market.market_type in {"PLACE", "OTHER_PLACE"}:
+                            multiplier = (100 - removal_adjustment_factor) * 0.01
+                            order.order_type.liability *= multiplier
+                            logger.warning(
+                                "PLACE MARKET_ON_CLOSE Order adjusted due to non runner {0}".format(
+                                    order.selection_id
+                                ),
+                                extra=order.info,
+                            )
+                    elif (
                         removal_adjustment_factor
                         and removal_adjustment_factor >= WIN_MINIMUM_ADJUSTMENT_FACTOR
                     ):
@@ -114,7 +147,7 @@ class SimulatedMiddleware(Middleware):
                         logger.warning(
                             "Order adjusted due to non runner {0}".format(
                                 order.selection_id
-                            ).format(order.selection_id),
+                            ),
                             extra=order.info,
                         )
 


Test patch:
diff --git a/tests/test_middleware.py b/tests/test_middleware.py
index 5feebd9..4cc68bd 100644
--- a/tests/test_middleware.py
+++ b/tests/test_middleware.py
@@ -10,6 +10,7 @@ from flumine.markets.middleware import (
     WIN_MINIMUM_ADJUSTMENT_FACTOR,
     PLACE_MINIMUM_ADJUSTMENT_FACTOR,
 )
+from flumine.order.ordertype import MarketOnCloseOrder
 
 
 class MiddlewareTest(unittest.TestCase):
@@ -136,6 +137,43 @@ class SimulatedMiddlewareTest(unittest.TestCase):
         self.middleware._process_runner_removal(mock_market, 12345, 0, None)
         self.assertEqual(mock_order.simulated.matched, [[123, 8.6, 10]])
 
+    def test__process_runner_removal_sp_win(self):
+        order_type = MarketOnCloseOrder(liability=200)
+        mock_order = mock.Mock(
+            selection_id=1234, handicap=0, order_type=order_type, info={}, side="LAY"
+        )
+
+        mock_market_book = mock.Mock()
+        mock_market_book.runners = [
+            mock.Mock(selection_id=1234, handicap=0, adjustment_factor=20)
+        ]
+        mock_market = mock.Mock(
+            market_type="WIN", blotter=[mock_order], market_book=mock_market_book
+        )
+        self.middleware._process_runner_removal(mock_market, 12345, 0, 50)
+
+        # The liability of £200 is adjusted by the multiplier of 37.5%, which s
+        # defined in the example here: https://github.com/liampauling/flumine/issues/454
+        self.assertEqual(mock_order.order_type.liability, 75)
+
+    def test__process_runner_removal_sp_place(self):
+        order_type = MarketOnCloseOrder(liability=200)
+        mock_order = mock.Mock(
+            selection_id=1234, handicap=0, order_type=order_type, info={}, side="LAY"
+        )
+
+        mock_market_book = mock.Mock()
+        mock_market_book.runners = [
+            mock.Mock(selection_id=1234, handicap=0, adjustment_factor=20)
+        ]
+        mock_market = mock.Mock(
+            market_type="PLACE", blotter=[mock_order], market_book=mock_market_book
+        )
+        self.middleware._process_runner_removal(mock_market, 12345, 0, 50)
+
+        # The liability of £200 is reduced by the non runner's adjustment factor of 50%
+        self.assertEqual(mock_order.order_type.liability, 100)
+
     def test__process_streaming_update(self):
         mock_market_book = mock.Mock(
             streaming_update={"img": True, "rc": [{"id": 3}, {"id": 4}]},