Skip to content

Commit

Permalink
#187 runner context additions
Browse files Browse the repository at this point in the history
strategy
 - max live trade count allows more than one live order per strategy/runner
 - max trade count limits total number of trades per strategy/runner
trade
 - place reset seconds, allows delay between orders being placed based on last place
 - reset seconds, allows delay between orders being placed based on last reset (execution complete)
  • Loading branch information
liampauling committed Aug 17, 2020
1 parent 69d6890 commit 22e8a6f
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 4 deletions.
4 changes: 4 additions & 0 deletions flumine/order/trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ def __init__(
fill_kill=None,
offset=None,
green=None,
place_reset_seconds: float = 0.0, # seconds to wait since `runner_context.reset` before allowing another order
reset_seconds: float = 0.0, # seconds to wait since `runner_context.place` before allowing another order
):
self.id = uuid.uuid1()
self.market_id = market_id
Expand All @@ -45,6 +47,8 @@ def __init__(
self.fill_kill = fill_kill # todo
self.offset = offset # todo
self.green = green # todo
self.place_reset_seconds = place_reset_seconds
self.reset_seconds = reset_seconds
self.orders = [] # all orders linked to trade
self.offset_orders = [] # pending offset orders once initial order has matched
self.status_log = []
Expand Down
20 changes: 18 additions & 2 deletions flumine/strategy/strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def __init__(
max_selection_exposure: float = 100,
max_order_exposure: float = 10,
client: BaseClient = None,
max_trade_count: int = 1e6, # max total number of trades per runner
max_live_trade_count: int = 1, # max live (with executable orders) trades per runner
):
"""
Processes data from streams.
Expand All @@ -58,6 +60,8 @@ def __init__(
self.max_selection_exposure = max_selection_exposure
self.max_order_exposure = max_order_exposure
self.client = client
self.max_trade_count = max_trade_count
self.max_live_trade_count = max_live_trade_count

self._invested = {} # {(marketId, selectionId, handicap): RunnerContext}
self.streams = [] # list of streams strategy is subscribed
Expand Down Expand Up @@ -119,8 +123,20 @@ def replace_order(self, market: Market, order, new_price: float) -> None:
market.replace_order(order, new_price)

def validate_order(self, runner_context: RunnerContext, order) -> bool:
# todo multi/count
if runner_context.executable_orders:
# validate context
if runner_context.trade_count >= self.max_trade_count:
return False
elif runner_context.live_trade_count >= self.max_live_trade_count:
return False
elif (
runner_context.placed_elapsed_seconds
and runner_context.placed_elapsed_seconds < order.trade.place_reset_seconds
):
return False
elif (
runner_context.reset_elapsed_seconds
and runner_context.reset_elapsed_seconds < order.trade.reset_seconds
):
return False
else:
return True
Expand Down
31 changes: 29 additions & 2 deletions tests/test_strategy.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ def setUp(self) -> None:
max_selection_exposure=1,
max_order_exposure=2,
client=self.mock_client,
max_trade_count=3,
max_live_trade_count=4,
)

def test_init(self):
Expand All @@ -64,6 +66,8 @@ def test_init(self):
self.assertEqual(self.strategy.max_selection_exposure, 1)
self.assertEqual(self.strategy.max_order_exposure, 2)
self.assertEqual(self.strategy.client, self.mock_client)
self.assertEqual(self.strategy.max_trade_count, 3)
self.assertEqual(self.strategy.max_live_trade_count, 4)

def test_check_market_no_subscribed(self):
mock_market = mock.Mock()
Expand Down Expand Up @@ -161,9 +165,32 @@ def test_replace_order(self):

def test_validate_order(self):
mock_order = mock.Mock()
runner_context = mock.Mock(executable_orders=False)
runner_context = mock.Mock(
trade_count=0,
live_trade_count=0,
placed_elapsed_seconds=None,
reset_elapsed_seconds=None,
)
self.assertTrue(self.strategy.validate_order(runner_context, mock_order))
runner_context.executable_orders = True
# trade count
runner_context.trade_count = 3
self.assertFalse(self.strategy.validate_order(runner_context, mock_order))
# live trade count
runner_context.trade_count = 1
runner_context.live_trade_count = 4
self.assertFalse(self.strategy.validate_order(runner_context, mock_order))
# place elapsed
runner_context.trade_count = 1
runner_context.live_trade_count = 1
runner_context.placed_elapsed_seconds = 0.49
mock_order.trade.place_reset_seconds = 0.5
self.assertFalse(self.strategy.validate_order(runner_context, mock_order))
# reset elapsed
runner_context.trade_count = 1
runner_context.live_trade_count = 1
runner_context.placed_elapsed_seconds = None
runner_context.reset_elapsed_seconds = 0.49
mock_order.trade.reset_seconds = 0.5
self.assertFalse(self.strategy.validate_order(runner_context, mock_order))

def test_executable_orders(self):
Expand Down
4 changes: 4 additions & 0 deletions tests/test_trade.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ def setUp(self) -> None:
self.mock_fill_kill,
self.mock_offset,
self.mock_green,
12,
34,
)

def test_init(self):
Expand All @@ -41,6 +43,8 @@ def test_init(self):
self.assertIsNotNone(self.trade.date_time_created)
self.assertIsNone(self.trade.date_time_complete)
self.assertIsNone(self.trade.market_notes)
self.assertEqual(self.trade.place_reset_seconds, 12)
self.assertEqual(self.trade.reset_seconds, 34)

@mock.patch("flumine.order.trade.get_market_notes")
def test_update_market_notes(self, mock_get_market_notes):
Expand Down

0 comments on commit 22e8a6f

Please sign in to comment.