Repository: liampauling/flumine
Pull request #393 (2021-03-12 08:34:00)

limit warning to only first attempt (retries will inherently have a d…
…elay)


Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index e469826..989af21 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,17 +3,6 @@
 Release History
 ---------------
 
-1.17.10 (2021-03-12)
-+++++++++++++++++++
-
-**Improvements**
-
-- Execution logging improvements
-
-**Bug Fixes**
-
-- Handle race condition (seen daily) where cancel is not correctly update to execution complete
-
 1.17.9 (2021-03-09)
 +++++++++++++++++++
 
diff --git a/flumine/__version__.py b/flumine/__version__.py
index 3e092d1..9cde18a 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.17.10"
+__version__ = "1.17.9"
 __author__ = "Liam Pauling"
 __license__ = "MIT"
diff --git a/flumine/execution/betfairexecution.py b/flumine/execution/betfairexecution.py
index fde4654..69ea67e 100644
--- a/flumine/execution/betfairexecution.py
+++ b/flumine/execution/betfairexecution.py
@@ -66,7 +66,9 @@ class BetfairExecution(BaseExecution):
                     if instruction_report.status == "SUCCESS":
                         if (
                             instruction_report.size_cancelled == order.size_remaining
-                        ):  # todo what if?
+                            or order.size_remaining
+                            == 0  # handle orders stream update / race condition
+                        ):
                             order.execution_complete()
                         else:
                             order.executable()
@@ -219,7 +221,7 @@ class BetfairExecution(BaseExecution):
         order_package: BaseOrderPackage,
         http_session: requests.Session,
     ):
-        if order_package.elapsed_seconds > 0.1:
+        if order_package.elapsed_seconds > 0.1 and order_package.retry_count == 0:
             logger.warning(
                 "High latency between current time and OrderPackage creation time, it is likely that the thread pool is currently exhausted",
                 extra={
diff --git a/flumine/order/orderpackage.py b/flumine/order/orderpackage.py
index f86c2b7..3edb62c 100644
--- a/flumine/order/orderpackage.py
+++ b/flumine/order/orderpackage.py
@@ -96,6 +96,10 @@ class BaseOrderPackage(BaseEvent):
     def orders(self) -> list:
         return [o for o in self._orders if o.status != OrderStatus.VIOLATION]
 
+    @property
+    def retry_count(self) -> int:
+        return self._retry_count
+
     @property
     def info(self) -> dict:
         return {


Test patch:
diff --git a/tests/test_execution.py b/tests/test_execution.py
index abc8ecb..72545c8 100644
--- a/tests/test_execution.py
+++ b/tests/test_execution.py
@@ -345,6 +345,39 @@ class BetfairExecutionTest(unittest.TestCase):
         mock_order.trade.__enter__.assert_called_with()
         mock_order.trade.__exit__.assert_called_with(None, None, None)
 
+    @mock.patch("flumine.execution.betfairexecution.BetfairExecution._order_logger")
+    @mock.patch("flumine.execution.betfairexecution.BetfairExecution.cancel")
+    @mock.patch("flumine.execution.betfairexecution.BetfairExecution._execution_helper")
+    def test_execute_cancel_success_race(
+        self, mock__execution_helper, mock_cancel, mock__order_logger
+    ):
+        mock_session = mock.Mock()
+        mock_order = mock.Mock()
+        mock_order.trade.__enter__ = mock.Mock()
+        mock_order.trade.__exit__ = mock.Mock()
+        mock_order.bet_id = 123
+        mock_order.size_remaining = 0
+        mock_order_package = mock.Mock()
+        mock_order_package.__iter__ = mock.Mock(return_value=iter([mock_order]))
+        mock_order_package.info = {}
+        mock_report = mock.Mock()
+        mock_instruction_report = mock.Mock()
+        mock_instruction_report.status = "SUCCESS"
+        mock_instruction_report.instruction.bet_id = 123
+        mock_instruction_report.size_cancelled = 2
+        mock_report.cancel_instruction_reports = [mock_instruction_report]
+        mock__execution_helper.return_value = mock_report
+        self.execution.execute_cancel(mock_order_package, mock_session)
+        mock__execution_helper.assert_called_with(
+            mock_cancel, mock_order_package, mock_session
+        )
+        mock__order_logger.assert_called_with(
+            mock_order, mock_instruction_report, OrderPackageType.CANCEL
+        )
+        mock_order.execution_complete.assert_called_with()
+        mock_order.trade.__enter__.assert_called_with()
+        mock_order.trade.__exit__.assert_called_with(None, None, None)
+
     @mock.patch("flumine.execution.betfairexecution.BetfairExecution._order_logger")
     @mock.patch("flumine.execution.betfairexecution.BetfairExecution.cancel")
     @mock.patch("flumine.execution.betfairexecution.BetfairExecution._execution_helper")
@@ -682,6 +715,21 @@ class BetfairExecutionTest(unittest.TestCase):
         mock_trading_function.assert_called_with(mock_order_package, mock_session)
         mock__return_http_session.assert_called_with(mock_session)
 
+    @mock.patch(
+        "flumine.execution.betfairexecution.BetfairExecution._return_http_session"
+    )
+    def test__execution_helper_warning(self, mock__return_http_session):
+        mock_trading_function = mock.Mock()
+        mock_trading_function.__name__ = "test"
+        mock_session = mock.Mock()
+        mock_order_package = mock.Mock(elapsed_seconds=0.2, retry_count=0)
+        mock_order_package.info = {}
+        self.execution._execution_helper(
+            mock_trading_function, mock_order_package, mock_session
+        )
+        mock_trading_function.assert_called_with(mock_order_package, mock_session)
+        mock__return_http_session.assert_called_with(mock_session)
+
     @mock.patch(
         "flumine.execution.betfairexecution.BetfairExecution._return_http_session"
     )
diff --git a/tests/test_orderpackage.py b/tests/test_orderpackage.py
index 40a319a..fa912d6 100644
--- a/tests/test_orderpackage.py
+++ b/tests/test_orderpackage.py
@@ -105,6 +105,10 @@ class OrderPackageTest(unittest.TestCase):
         ]
         self.assertEqual(len(self.order_package.orders), 2)
 
+    def test_retry_count(self):
+        self.order_package._retry_count = 1
+        self.assertEqual(self.order_package.retry_count, 1)
+
     def test_info(self):
         self.assertEqual(
             self.order_package.info,