From a8603fab75770f3523da743f46a1778cd58b3047 Mon Sep 17 00:00:00 2001 From: Peter Dekkers Date: Sat, 6 Jul 2024 13:12:22 +0200 Subject: [PATCH] back to older approach without expiration --- roboquant/brokers/simbroker.py | 6 +----- roboquant/order.py | 11 +++-------- roboquant/strategies/basestrategy.py | 19 ++++++++----------- tests/unit/test_simbroker.py | 2 +- 4 files changed, 13 insertions(+), 25 deletions(-) diff --git a/roboquant/brokers/simbroker.py b/roboquant/brokers/simbroker.py index 17fa1a0..6f5944e 100644 --- a/roboquant/brokers/simbroker.py +++ b/roboquant/brokers/simbroker.py @@ -29,8 +29,7 @@ def __init__( self, initial_deposit=1_000_000.0, price_type="OPEN", - slippage=0.001, - clean_up_orders=True, + slippage=0.001 ): super().__init__() self._account = Account() @@ -42,7 +41,6 @@ def __init__( self.slippage = slippage self.price_type = price_type - self.clean_up_orders = clean_up_orders self.initial_deposit = initial_deposit def reset(self): @@ -156,7 +154,6 @@ def _process_modify_orders(self): def _process_open_orders(self, prices: dict[str, PriceItem]): for order in self._account.orders: - if (item := prices.get(order.symbol)) is not None: trx = self._execute(order, item) if trx is not None: @@ -204,7 +201,6 @@ def sync(self, event: Event | None = None) -> Account: acc.last_update = event.time prices = event.price_items if event else {} - acc.orders += self._create_orders self._create_orders = [] diff --git a/roboquant/order.py b/roboquant/order.py index 9976452..db1f08d 100644 --- a/roboquant/order.py +++ b/roboquant/order.py @@ -41,8 +41,8 @@ class Order: limit: float info: dict[str, Any] - id: str | None - fill: Decimal + id: str | None = None + fill: Decimal = Decimal(0) def __init__( self, symbol: str, size: Decimal | str | int | float, limit: float, **kwargs @@ -78,7 +78,7 @@ def modify(self, size: Decimal | str | int | float | None = None, limit: float | You can only update existing orders that are still open and have an id. """ - assert self.id is not None, "Can only update an already assigned id" + assert self.id, "Can only update an already assigned id" size = Decimal(size) if size is not None else None if size is not None: assert not size.is_zero(), "size cannot be set to zero, use order.cancel() to cancel an order" @@ -99,11 +99,6 @@ def is_cancellation(self): """Return True if this is a cancellation order, False otherwise""" return self.size.is_zero() - @property - def type(self) -> OrderType: - """Return the order type""" - return OrderType.BUY if self.is_buy else OrderType.SELL - @property def is_buy(self): """Return True if this is a BUY order, False otherwise""" diff --git a/roboquant/strategies/basestrategy.py b/roboquant/strategies/basestrategy.py index 8af736f..da35752 100644 --- a/roboquant/strategies/basestrategy.py +++ b/roboquant/strategies/basestrategy.py @@ -28,6 +28,7 @@ def __init__(self) -> None: self.buy_price = "DEFAULT" self.sell_price = "DEFAULT" self.fractional_order_digits = 0 + self.cancel_existing_orders = True def create_orders(self, event: Event, account: Account) -> list[Order]: self.orders = [] @@ -39,15 +40,9 @@ def create_orders(self, event: Event, account: Account) -> list[Order]: self.process(event, account) return self.orders - def _get_size(self, symbol: str, order_type: OrderType, limit: float) -> Decimal: + def _get_size(self, symbol: str, limit: float) -> Decimal: value_one = self.account.contract_value(symbol, limit) - size = round(Decimal(self.order_value / value_one), self.fractional_order_digits) - - pos_size = self.account.get_position_size(symbol) - if order_type.is_closing(pos_size) and abs(size) > abs(pos_size): - return -pos_size - - return size if order_type.is_buy else size * -1 + return round(Decimal(self.order_value / value_one), self.fractional_order_digits) def _required_buyingpower(self, symbol: str, size: Decimal, limit: float) -> float: pos_size = self.account.get_position_size(symbol) @@ -57,7 +52,7 @@ def _required_buyingpower(self, symbol: str, size: Decimal, limit: float) -> flo def add_buy_order(self, symbol: str, limit: float | None = None): if limit := limit or self._get_limit(symbol, OrderType.BUY): - if size := self._get_size(symbol, OrderType.BUY, limit): + if size := self._get_size(symbol, limit): return self.add_order(symbol, size, limit) return False @@ -69,7 +64,7 @@ def add_exit_order(self, symbol: str, limit: float | None = None): def add_sell_order(self, symbol: str, limit: float | None = None): if limit := limit or self._get_limit(symbol, OrderType.SELL): - if size := self._get_size(symbol, OrderType.SELL, limit): + if size := self._get_size(symbol, limit) * -1: return self.add_order(symbol, size, limit) return False @@ -80,12 +75,14 @@ def _get_limit(self, symbol: str, order_type: OrderType) -> float | None: def add_order(self, symbol: str, size: Decimal, limit: float) -> bool: bp = self._required_buyingpower(symbol, size, limit) - print(f"symbol={symbol} size={size} limit={limit} required={bp} available={self.buying_power}") + logger.info("symbol=%s size=%s limit=%s required=%s available=%s", symbol, size, limit, bp, self.buying_power) if bp and bp > self.buying_power: logger.info("not enough buying power remaining") return False self.buying_power -= bp + if self.cancel_existing_orders: + self.cancel_open_orders(symbol) order = Order(symbol, size, limit) self.orders.append(order) return True diff --git a/tests/unit/test_simbroker.py b/tests/unit/test_simbroker.py index 99f19b4..b012f1f 100644 --- a/tests/unit/test_simbroker.py +++ b/tests/unit/test_simbroker.py @@ -21,7 +21,7 @@ def assert_orders(self, account: Account): self.assertTrue(o.fill < o.size if o.is_buy else o.fill > o.size) def test_simbroker(self): - broker = SimBroker(clean_up_orders=False) + broker = SimBroker() account = broker.sync() self.assertEqual(1_000_000.0, account.buying_power)