Support asynchronous non-market orders (#8946)
API Tests / build (push) Has been cancelled
Benchmarks / build (push) Has been cancelled
Build & Test Lean / build (push) Has been cancelled
Regression Tests / build (push) Has been cancelled
Report Generator Tests / build (push) Has been cancelled
Research Regression Tests / build (push) Has been cancelled
Syntax Tests / build (push) Has been cancelled
Python Virtual Environments / build (push) Has been cancelled

* Add 'asynchronous' parameter to trading api

* Add regression algorithms

* More fixes for asynchronous orders

* Fix failing unit tests

* Fix failing unit tests

* Add multiple orders requests in transaction handler

Make each transaction thread handle requests corresponding to the same order

* Refactor order state machine in BrokerageTransactionHandler

Now using a single dictionary to hold orders and their state, either pending for submission, open or closed.

* Revert: remove complete orders from new state machine in BTH

* Add order ticket to new BTH open orders state machine

* Run syn in Backtesting transaction handler for new orders submission

* Remove OpenOrderState.SubmissionPending property

* Add Security to OpenOrderState

* Minor fix

* Cleanup

* Some cleanup in BTH

* Cleanup

* Minor fix

* Minor unit test fix

* Minor fix

* Make Brokerage.ConcurrencyEnable property virtual

* Minor change

* Cleanup

* Add 'asynchronous' parameter to SetHoldings api

* Improve regression algorithms
This commit is contained in:
Jhonathan Abreu
2025-09-10 08:29:50 -04:00
committed by GitHub
parent 23afff13fc
commit d82d70dacf
49 changed files with 1226 additions and 242 deletions
@@ -25,6 +25,7 @@ class StopLimitOrderRegressionAlgorithm(QCAlgorithm):
tolerance = 0.001
fast_period = 30
slow_period = 60
asynchronous_orders = False
def initialize(self):
self.set_start_date(2013, 1, 1)
@@ -46,9 +47,9 @@ class StopLimitOrderRegressionAlgorithm(QCAlgorithm):
security = self.securities[self._symbol]
if self._buy_order_ticket is None and self.trend_is_up():
self._buy_order_ticket = self.stop_limit_order(self._symbol, 100, stop_price=security.high * 1.10, limit_price=security.high * 1.11)
self._buy_order_ticket = self.stop_limit_order(self._symbol, 100, stop_price=security.high * 1.10, limit_price=security.high * 1.11, asynchronous=self.asynchronous_orders)
elif self._buy_order_ticket.status == OrderStatus.FILLED and self._sell_order_ticket is None and self.trend_is_down():
self._sell_order_ticket = self.stop_limit_order(self._symbol, -100, stop_price=security.low * 0.99, limit_price=security.low * 0.98)
self._sell_order_ticket = self.stop_limit_order(self._symbol, -100, stop_price=security.low * 0.99, limit_price=security.low * 0.98, asynchronous=self.asynchronous_orders)
def on_order_event(self, order_event: OrderEvent):
if order_event.status == OrderStatus.FILLED:
@@ -67,6 +68,11 @@ class StopLimitOrderRegressionAlgorithm(QCAlgorithm):
raise AssertionError(f"Sell stop limit order should have filled with price greater than or equal to the limit price {limit_price}. "
f"Fill price: {order_event.fill_price}")
def on_end_of_algorithm(self):
for ticket in self.transactions.get_order_tickets():
if ticket.submit_request.asynchronous != self.asynchronous_orders:
raise AssertionError("Expected all orders to have the same asynchronous flag as the algorithm.")
def is_ready(self):
return self._fast.is_ready and self._slow.is_ready