Skip to content

Commit

Permalink
#538 passive; prevent double counting of traded size
Browse files Browse the repository at this point in the history
  • Loading branch information
liampauling committed Dec 13, 2021
1 parent bdd46e2 commit d0edf5c
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 29 deletions.
30 changes: 17 additions & 13 deletions flumine/backtest/simulated.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ def __init__(self, order):
self._piq = 0.0
self._bsp_reconciled = False

def __call__(self, market_book: MarketBook, runner_analytics) -> None:
def __call__(self, market_book: MarketBook, traded: dict) -> None:
# simulates order matching
if self._bsp_reconciled is False and market_book.bsp_reconciled:
if self.take_sp:
Expand All @@ -52,10 +52,8 @@ def __call__(self, market_book: MarketBook, runner_analytics) -> None:
return

# todo estimated piq cancellations
if runner_analytics.traded:
self._process_traded(
market_book.publish_time_epoch, runner_analytics.traded
)
if traded:
self._process_traded(market_book.publish_time_epoch, traded)

def place(
self, order_package, market_book: MarketBook, instruction: dict, bet_id: int
Expand Down Expand Up @@ -331,14 +329,18 @@ def _process_traded(self, publish_time: int, traded: dict) -> None:
)
)
if side == "BACK" and traded_price >= price:
self._calculate_process_traded(publish_time, traded_size)
matched = self._calculate_process_traded(publish_time, traded_size)
if matched:
traded[traded_price] = traded_size - matched
elif side == "LAY" and traded_price <= price:
self._calculate_process_traded(publish_time, traded_size)

def _calculate_process_traded(self, publish_time: int, traded_size: float) -> None:
traded_size = traded_size / 2
if self._piq - traded_size < 0:
size = traded_size - self._piq
matched = self._calculate_process_traded(publish_time, traded_size)
if matched:
traded[traded_price] = traded_size - matched

def _calculate_process_traded(self, publish_time: int, traded_size: float) -> float:
_traded_size = traded_size / 2
if self._piq - _traded_size < 0:
size = _traded_size - self._piq
size = round(min(self.size_remaining, size), 2)
if size:
self._update_matched(
Expand All @@ -349,12 +351,14 @@ def _calculate_process_traded(self, publish_time: int, traded_size: float) -> No
] # todo takes the worst price, i.e what was asked
)
self._piq = 0
return size * 2
else:
self._piq -= traded_size
self._piq -= _traded_size
if logger.isEnabledFor(logging.DEBUG):
logger.debug(
"Simulated order {0} PIQ: {1}".format(self.order.id, self._piq)
)
return traded_size

@property
def take_sp(self) -> bool:
Expand Down
7 changes: 3 additions & 4 deletions flumine/markets/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,11 @@ def _calculate_reduction_factor(price: float, adjustment_factor: float) -> float

@staticmethod
def _process_simulated_orders(market, market_analytics: dict) -> None:
_lookup = {k: v.traded.copy() for k, v in market_analytics.items()}
for order in market.blotter.live_orders:
if order.status == OrderStatus.EXECUTABLE and order.simulated:
runner_analytics = market_analytics[
(order.selection_id, order.handicap)
]
order.simulated(market.market_book, runner_analytics)
runner_traded = _lookup[(order.selection_id, order.handicap)]
order.simulated(market.market_book, runner_traded)

@staticmethod
def _process_runner(
Expand Down
6 changes: 4 additions & 2 deletions tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,10 +287,12 @@ def test__process_simulated_orders(self):
mock_order_two,
mock_order_three,
]
mock_market_analytics = {(mock_order.selection_id, mock_order.handicap): "test"}
mock_market_analytics = {
(mock_order.selection_id, mock_order.handicap): mock.Mock(traded={1: 2})
}
mock_market.market_book = mock_market_book
self.middleware._process_simulated_orders(mock_market, mock_market_analytics)
mock_order.simulated.assert_called_with(mock_market_book, "test")
mock_order.simulated.assert_called_with(mock_market_book, {1: 2})
mock_order_two.simulated.assert_not_called()

@mock.patch("flumine.markets.middleware.RunnerAnalytics")
Expand Down
20 changes: 10 additions & 10 deletions tests/test_simulated.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,12 @@ def test_init(self):
def test_call_process_traded(
self, mock__process_sp, mock__process_traded, _, mock__get_runner
):
mock_market_book = mock.Mock()
mock_market_book.bsp_reconciled = False
mock_runner_analytics = mock.Mock()
self.simulated(mock_market_book, mock_runner_analytics)
mock_market_book = mock.Mock(bsp_reconciled=False)
traded = {1: 2}
self.simulated(mock_market_book, traded)
mock__process_sp.assert_not_called()
mock__process_traded.assert_called_with(
mock_market_book.publish_time_epoch, mock_runner_analytics.traded
mock_market_book.publish_time_epoch, traded
)

@mock.patch("flumine.backtest.simulated.Simulated._get_runner")
Expand Down Expand Up @@ -605,22 +604,23 @@ def test__process_traded_lay_no(self, mock__calculate_process_traded):
mock__calculate_process_traded.assert_not_called()

def test__calculate_process_traded(self):
self.simulated._calculate_process_traded(1234582, 2.00)
self.simulated._calculate_process_traded(1234583, 2.00)
self.simulated._calculate_process_traded(1234584, 2.00)
self.assertEqual(self.simulated._calculate_process_traded(1234582, 2.00), 2)
self.assertEqual(self.simulated._calculate_process_traded(1234583, 2.00), 2)
self.assertEqual(self.simulated._calculate_process_traded(1234584, 2.00), 0)
self.assertEqual(
self.simulated.matched, [[1234582, 12, 1.00], [1234583, 12, 1.00]]
)
self.assertEqual(self.simulated._piq, 0)

def test__calculate_process_traded_piq(self):
self.simulated._piq = 2.00
self.simulated._calculate_process_traded(1234585, 4.00)
self.assertEqual(self.simulated._calculate_process_traded(1234585, 4.00), 4)
self.assertEqual(self.simulated.matched, [])
self.assertEqual(self.simulated._piq, 0)
self.simulated._calculate_process_traded(1234586, 4.00)
self.assertEqual(self.simulated._calculate_process_traded(1234586, 4.00), 4)
self.assertEqual(self.simulated.matched, [[1234586, 12, 2.00]])
self.assertEqual(self.simulated._piq, 0)
self.assertEqual(self.simulated._calculate_process_traded(1234586, 4.00), 0)

def test_take_sp(self):
self.assertFalse(self.simulated.take_sp)
Expand Down

0 comments on commit d0edf5c

Please sign in to comment.