Repository: liampauling/flumine
Pull request #381 (2021-02-26 12:44:39)

transaction id added to give details on how many per market have been…
… created

minor tests improvements


Patch:
diff --git a/HISTORY.rst b/HISTORY.rst
index 644b73e..bb3230a 100644
--- a/HISTORY.rst
+++ b/HISTORY.rst
@@ -3,6 +3,14 @@
 Release History
 ---------------
 
+1.17.4 (2021-02-26)
++++++++++++++++++++
+
+**Improvements**
+
+- Transaction id and logging added
+- max_workers moved to config to allow int to be configurable
+
 1.17.3 (2021-02-25)
 +++++++++++++++++++
 
diff --git a/docs/advanced.md b/docs/advanced.md
index 336a61a..30d414a 100644
--- a/docs/advanced.md
+++ b/docs/advanced.md
@@ -189,3 +189,7 @@ Used for backtesting
 ### raise_errors
 
 Raises errors on strategy functions, see [Error Handling](/advanced/#error-handling)
+
+### max_workers
+
+Max number of workers in execution thread pool
diff --git a/flumine/__version__.py b/flumine/__version__.py
index b6fc20b..16d2113 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.3"
+__version__ = "1.17.4"
 __author__ = "Liam Pauling"
 __license__ = "MIT"
diff --git a/flumine/baseflumine.py b/flumine/baseflumine.py
index 0039efc..d4daa63 100644
--- a/flumine/baseflumine.py
+++ b/flumine/baseflumine.py
@@ -57,8 +57,8 @@ class BaseFlumine:
         self.streams.add_client(client)
 
         # order execution class
-        self.simulated_execution = SimulatedExecution(self)
-        self.betfair_execution = BetfairExecution(self)
+        self.simulated_execution = SimulatedExecution(self, config.max_workers)
+        self.betfair_execution = BetfairExecution(self, config.max_workers)
 
         # logging controls (e.g. database logger)
         self._logging_controls = []
diff --git a/flumine/config.py b/flumine/config.py
index 6736fae..6da8a8a 100644
--- a/flumine/config.py
+++ b/flumine/config.py
@@ -14,3 +14,5 @@ process_id = os.getpid()  # process id of app
 current_time = None  # used for backtesting
 
 raise_errors = False  # used for call_check_market / call_process_market_book
+
+max_workers = 32  # max number of workers in execution thread pool
diff --git a/flumine/execution/baseexecution.py b/flumine/execution/baseexecution.py
index 92c81d1..d0b21b7 100644
--- a/flumine/execution/baseexecution.py
+++ b/flumine/execution/baseexecution.py
@@ -8,7 +8,6 @@ from ..events.events import OrderEvent
 
 logger = logging.getLogger(__name__)
 
-MAX_WORKERS = 32
 MAX_SESSION_AGE = 200  # seconds since last request
 BET_ID_START = 100000000000  # simulated start betId->
 
@@ -17,7 +16,7 @@ class BaseExecution:
 
     EXCHANGE = None
 
-    def __init__(self, flumine, max_workers: int = MAX_WORKERS):
+    def __init__(self, flumine, max_workers: int = None):
         self.flumine = flumine
         self._max_workers = max_workers
         self._thread_pool = ThreadPoolExecutor(max_workers=self._max_workers)
diff --git a/flumine/execution/transaction.py b/flumine/execution/transaction.py
index 83a96ea..1ba5715 100644
--- a/flumine/execution/transaction.py
+++ b/flumine/execution/transaction.py
@@ -30,8 +30,9 @@ class Transaction:
             t.place_order(order)  # both executed on transaction __exit__
     """
 
-    def __init__(self, market):
+    def __init__(self, market, id_: int):
         self.market = market
+        self._id = id_  # unique per market only
         self._pending_orders = False
         self._pending_place = []  # list of (<Order>, market_version)
         self._pending_cancel = []  # list of (<Order>, None)
@@ -116,6 +117,7 @@ class Transaction:
                 extra={
                     "market_id": self.market.market_id,
                     "order_packages": [o.info for o in packages],
+                    "transaction_id": self._id,
                 },
             )
             self._pending_orders = False
diff --git a/flumine/markets/market.py b/flumine/markets/market.py
index 1ade5da..1ce3e88 100644
--- a/flumine/markets/market.py
+++ b/flumine/markets/market.py
@@ -34,6 +34,7 @@ class Market:
         self.update_market_catalogue = True
         self.context = {"simulated": {}}  # data store (raceCard / scores etc)
         self.blotter = Blotter(market_id)
+        self._transaction_id = 0
 
     def __call__(self, market_book: MarketBook):
         if self.market_book and market_book.version != self.market_book.version:
@@ -56,7 +57,8 @@ class Market:
         )
 
     def transaction(self) -> Transaction:
-        return Transaction(self)
+        self._transaction_id += 1
+        return Transaction(self, id_=self._transaction_id)
 
     # order
     def place_order(


Test patch:
diff --git a/flumine/backtest/backtest.py b/flumine/backtest/backtest.py
index 9b530d6..502bd89 100644
--- a/flumine/backtest/backtest.py
+++ b/flumine/backtest/backtest.py
@@ -6,7 +6,6 @@ from ..events import events
 from .. import config, utils
 from ..clients import ExchangeType
 from ..exceptions import RunError
-from ..order.orderpackage import OrderPackageType
 from ..order.trade import TradeStatus
 from ..order import process
 
diff --git a/tests/test_config.py b/tests/test_config.py
new file mode 100644
index 0000000..899a1e6
--- /dev/null
+++ b/tests/test_config.py
@@ -0,0 +1,13 @@
+import unittest
+
+from flumine import config
+
+
+class ConfigTest(unittest.TestCase):
+    def test_init(self):
+        self.assertFalse(config.simulated)
+        self.assertIsInstance(config.hostname, str)
+        self.assertIsInstance(config.process_id, int)
+        self.assertIsNone(config.current_time)
+        self.assertFalse(config.raise_errors)
+        self.assertEqual(config.max_workers, 32)
diff --git a/tests/test_execution.py b/tests/test_execution.py
index f33710c..7763d65 100644
--- a/tests/test_execution.py
+++ b/tests/test_execution.py
@@ -7,7 +7,6 @@ from betfairlightweight import BetfairError
 from flumine.clients.clients import ExchangeType
 from flumine.exceptions import OrderExecutionError
 from flumine.execution.baseexecution import (
-    MAX_WORKERS,
     MAX_SESSION_AGE,
     BET_ID_START,
     BaseExecution,
@@ -23,7 +22,6 @@ class BaseExecutionTest(unittest.TestCase):
         self.execution = BaseExecution(self.mock_flumine, max_workers=2)
 
     def test_init(self):
-        self.assertEqual(MAX_WORKERS, 32)
         self.assertEqual(MAX_SESSION_AGE, 200)
         self.assertEqual(BET_ID_START, 100000000000)
         self.assertEqual(self.execution.flumine, self.mock_flumine)
diff --git a/tests/test_integration.py b/tests/test_integration.py
index f31d4c4..8c04bc8 100644
--- a/tests/test_integration.py
+++ b/tests/test_integration.py
@@ -97,21 +97,18 @@ class IntegrationTest(unittest.TestCase):
         self.assertEqual(len(framework.markets), 1)
 
         for market in framework.markets:
-            limit_orders = [
-                o for o in market.blotter if o.trade.strategy == limit_strategy
-            ]
+            limit_orders = market.blotter.strategy_orders(limit_strategy)
             self.assertEqual(
                 round(sum([o.simulated.profit for o in limit_orders]), 2), 18.96
             )
             self.assertEqual(len(limit_orders), 15)
-
-            market_orders = [
-                o for o in market.blotter if o.trade.strategy == market_strategy
-            ]
+            market_orders = market.blotter.strategy_orders(market_strategy)
             self.assertEqual(
                 round(sum([o.simulated.profit for o in market_orders]), 2), -6.68
             )
             self.assertEqual(len(market_orders), 14)
+            # check transaction count
+            self.assertEqual(market._transaction_id, 180)
 
     def tearDown(self) -> None:
         config.simulated = False
diff --git a/tests/test_markets.py b/tests/test_markets.py
index ae2ed43..6346885 100644
--- a/tests/test_markets.py
+++ b/tests/test_markets.py
@@ -130,6 +130,14 @@ class MarketTest(unittest.TestCase):
         self.assertTrue(self.market.closed)
         self.assertIsNotNone(self.market.date_time_closed)
 
+    @mock.patch("flumine.markets.market.Transaction")
+    def test_transaction(self, mock_transaction):
+        transaction = self.market.transaction()
+        mock_transaction.assert_called_with(
+            self.market, id_=self.market._transaction_id
+        )
+        self.assertEqual(transaction, mock_transaction())
+
     @mock.patch("flumine.markets.market.Market.transaction")
     def test_place_order(self, mock_transaction):
         mock_transaction.return_value.__enter__.return_value = mock_transaction
diff --git a/tests/test_transaction.py b/tests/test_transaction.py
index 6560870..b3a8c5d 100644
--- a/tests/test_transaction.py
+++ b/tests/test_transaction.py
@@ -10,10 +10,11 @@ class TransactionTest(unittest.TestCase):
     def setUp(self) -> None:
         mock_blotter = {}
         self.mock_market = mock.Mock(blotter=mock_blotter)
-        self.transaction = Transaction(self.mock_market)
+        self.transaction = Transaction(self.mock_market, 1)
 
     def test_init(self):
         self.assertEqual(self.transaction.market, self.mock_market)
+        self.assertEqual(self.transaction._id, 1)
         self.assertFalse(self.transaction._pending_orders)
         self.assertEqual(self.transaction._pending_place, [])
         self.assertEqual(self.transaction._pending_cancel, [])