Repository: liampauling/flumine
Pull request #329 (2020-11-16 09:55:30)

history and version update


Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index d23f870..e061c42 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,6 +3,17 @@
 Release History
 ---------------
 
+1.14.8 (2020-11-16)
++++++++++++++++++++
+
+**Improvements**
+
+- Config event added and processed on start
+
+**Bug Fixes**
+
+- #320 prevent market on close limit order when below min bsp liability
+
 1.14.7 (2020-11-14)
 +++++++++++++++++++
 
diff --git a/flumine/__version__.py b/flumine/__version__.py
index 864a1a3..e9581ca 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.14.7"
+__version__ = "1.14.8"
 __author__ = "Liam Pauling"
 __license__ = "MIT"
diff --git a/flumine/baseflumine.py b/flumine/baseflumine.py
index ba6d359..073e5bf 100644
--- a/flumine/baseflumine.py
+++ b/flumine/baseflumine.py
@@ -359,6 +359,8 @@ class BaseFlumine:
         # start logging controls
         for c in self._logging_controls:
             c.start()
+        # process config (logging)
+        self.log_control(events.ConfigEvent(config))
         # start strategies
         self.strategies.start()
         # start streams
diff --git a/flumine/controls/loggingcontrols.py b/flumine/controls/loggingcontrols.py
index e49521e..978532e 100644
--- a/flumine/controls/loggingcontrols.py
+++ b/flumine/controls/loggingcontrols.py
@@ -2,7 +2,6 @@ import logging
 import queue
 from threading import Thread
 
-from .. import config
 from ..events import events
 from ..events.events import EventType
 
@@ -42,11 +41,11 @@ class LoggingControl(Thread):
                         extra={"event": event},
                     )
 
-    def process_config(self, config: config):
-        logger.debug("process_config: %s" % config)
-
     def process_event(self, event: events.BaseEvent):
-        if event.EVENT_TYPE == EventType.STRATEGY:
+        if event.EVENT_TYPE == EventType.CONFIG:
+            self._process_config(event)
+
+        elif event.EVENT_TYPE == EventType.STRATEGY:
             self._process_strategy(event)
 
         elif event.EVENT_TYPE == EventType.MARKET:
@@ -86,6 +85,9 @@ class LoggingControl(Thread):
         else:
             logger.error("Unwanted item in logging control: {0}".format(event))
 
+    def _process_config(self, event):
+        logger.debug("process_config: %s" % event)
+
     def _process_strategy(self, event):
         logger.debug("process_strategy: %s" % event)
 
diff --git a/flumine/events/events.py b/flumine/events/events.py
index f728c00..0ce21a5 100644
--- a/flumine/events/events.py
+++ b/flumine/events/events.py
@@ -3,6 +3,7 @@ from enum import Enum
 
 
 class EventType(Enum):
+    CONFIG = "Config"
     TERMINATOR = "Terminator"
     # betfair objects
     MARKET_CATALOGUE = "MarketCatalogue"
@@ -100,6 +101,11 @@ class NewDayEvent(BaseEvent):
 # LOGGING
 
 
+class ConfigEvent(BaseEvent):
+    EVENT_TYPE = EventType.CONFIG
+    QUEUE_TYPE = QueueType.LOGGING
+
+
 class ClearedOrdersMetaEvent(BaseEvent):
     EVENT_TYPE = EventType.CLEARED_ORDERS_META
     QUEUE_TYPE = QueueType.LOGGING


Test patch:
diff --git a/flumine/backtest/simulated.py b/flumine/backtest/simulated.py
index 41927c0..4ce1e2b 100644
--- a/flumine/backtest/simulated.py
+++ b/flumine/backtest/simulated.py
@@ -206,9 +206,15 @@ class Simulated:
                     size = self.size_remaining
                 else:
                     remaining_risk = (_order_type.price - 1.0) * self.size_remaining
-                    size = round(remaining_risk / (actual_sp - 1.0), 2)
-                    # Cancel remaining size
-                    self.size_cancelled += round(self.size_remaining - size, 2)
+                    client = self.order.trade.client
+                    if remaining_risk >= client.min_bsp_liability:
+                        size = round(remaining_risk / (actual_sp - 1.0), 2)
+                        # Cancel remaining size
+                        self.size_cancelled += round(self.size_remaining - size, 2)
+                    else:  # lapse
+                        self.size_lapsed += self.size_remaining
+                        self.order.lapsed()
+                        return
             elif _order_type.ORDER_TYPE == OrderTypes.LIMIT_ON_CLOSE:
                 if self.side == "BACK":
                     if actual_sp < _order_type.price:
diff --git a/tests/test_baseflumine.py b/tests/test_baseflumine.py
index 05d98a6..f95a891 100644
--- a/tests/test_baseflumine.py
+++ b/tests/test_baseflumine.py
@@ -395,6 +395,7 @@ class BaseFlumineTest(unittest.TestCase):
         with self.base_flumine:
             self.assertTrue(self.base_flumine._running)
             self.mock_client.login.assert_called_with()
+            mock_log_control.assert_called_with(mock_events.ConfigEvent(None))
 
         self.assertFalse(self.base_flumine._running)
         self.mock_client.logout.assert_called_with()
diff --git a/tests/test_loggingcontrols.py b/tests/test_loggingcontrols.py
index b09683c..57ee850 100644
--- a/tests/test_loggingcontrols.py
+++ b/tests/test_loggingcontrols.py
@@ -23,6 +23,13 @@ class TestLoggingControl(unittest.TestCase):
         self.logging_control.logging_queue.put(None)
         self.logging_control.run()
 
+    @mock.patch("flumine.controls.loggingcontrols.LoggingControl._process_config")
+    def test_process_event_config(self, mock_process_config):
+        mock_event = mock.Mock()
+        mock_event.EVENT_TYPE = EventType.CONFIG
+        self.logging_control.process_event(mock_event)
+        mock_process_config.assert_called_with(mock_event)
+
     @mock.patch("flumine.controls.loggingcontrols.LoggingControl._process_strategy")
     def test_process_event_strategy(self, mock_process_strategy):
         mock_event = mock.Mock()
@@ -117,7 +124,7 @@ class TestLoggingControl(unittest.TestCase):
         self.assertIsNone(self.logging_control.logging_queue.get())
 
     def test_process_config(self):
-        self.logging_control.process_config(None)
+        self.logging_control._process_config(None)
 
     def test_process_strategy(self):
         self.logging_control._process_strategy(None)
diff --git a/tests/test_simulated.py b/tests/test_simulated.py
index f1efccd..d9f32a1 100644
--- a/tests/test_simulated.py
+++ b/tests/test_simulated.py
@@ -10,7 +10,7 @@ class SimulatedTest(unittest.TestCase):
         self.mock_order_type = mock.Mock(
             price=12, size=2.00, ORDER_TYPE=OrderTypes.LIMIT
         )
-        mock_client = mock.Mock(paper_trade=False)
+        mock_client = mock.Mock(paper_trade=False, min_bsp_liability=10)
         mock_trade = mock.Mock(client=mock_client)
         self.mock_order = mock.Mock(
             selection_id=1234,
@@ -342,6 +342,17 @@ class SimulatedTest(unittest.TestCase):
         self.assertTrue(self.simulated._bsp_reconciled)
         self.simulated.order.execution_complete.assert_called()
 
+    def test__process_sp_lay_liability(self):
+        self.simulated.size_matched = 1.90
+        mock_runner = mock.Mock()
+        mock_runner.sp.actual_sp = 12.20
+        self.simulated.order.side = "LAY"
+        self.simulated._process_sp(1234571, mock_runner)
+        self.assertEqual(self.simulated.matched, [])
+        self.assertEqual(self.simulated.size_lapsed, 0.10)
+        self.assertTrue(self.simulated._bsp_reconciled)
+        self.simulated.order.lapsed.assert_called()
+
     def test__process_sp_none(self):
         mock_runner = mock.Mock()
         mock_runner.sp.actual_sp = None