Trailing stop orders (#7402)

* Add trailing stop orders base implementation

* Handle trailing stop order prices rounding

* Implement trailing stop orders fill logic

* Minor fill model changes

* Add ApplySplit to fill model interface for models that might need to be aware of splits.

Filling trailing stop orders require keeping track of min/max prices, which need to be split adjusted.

* Add brokerage order updated event for communicating certain order types prices changes

* Add order update event args class for brokerage side order updates

* Revert IFillModel.ApplySplit

* Add trailing stop orders regression algorithm

* Updated order ticket demo algorithm to include trailing stop orders

* Some cleanup

* Support trailing stop orders in IB brokerage model

* Some cleanup

* Fix failing tests

* Fix failing regression algorithm

* Address peer review

* Add trailing stop price calculation unit tests

* Minor changes

* Minor change
This commit is contained in:
Jhonathan Abreu
2023-07-28 17:49:58 -04:00
committed by GitHub
parent 10a9f31d65
commit 906ab20bee
41 changed files with 1892 additions and 170 deletions
@@ -39,7 +39,7 @@ class UpdateOrderRegressionAlgorithm(QCAlgorithm):
self.limit_percentage = 0.025
self.limit_percentage_delta = 0.005
OrderTypeEnum = [OrderType.Market, OrderType.Limit, OrderType.StopMarket, OrderType.StopLimit, OrderType.MarketOnOpen, OrderType.MarketOnClose]
OrderTypeEnum = [OrderType.Market, OrderType.Limit, OrderType.StopMarket, OrderType.StopLimit, OrderType.MarketOnOpen, OrderType.MarketOnClose, OrderType.TrailingStop]
self.order_types_queue = CircularQueue[OrderType](OrderTypeEnum)
self.order_types_queue.CircleCompleted += self.onCircleCompleted
self.tickets = []
@@ -70,7 +70,8 @@ class UpdateOrderRegressionAlgorithm(QCAlgorithm):
if orderType == OrderType.Limit:
limitPrice = (1 + self.limit_percentage)*data["SPY"].High if not isLong else (1 - self.limit_percentage)*data["SPY"].Low
request = SubmitOrderRequest(orderType, self.security.Symbol.SecurityType, "SPY", self.quantity, stopPrice, limitPrice, self.UtcTime, str(orderType))
request = SubmitOrderRequest(orderType, self.security.Symbol.SecurityType, "SPY", self.quantity, stopPrice, limitPrice, 0, 0.01, True,
self.UtcTime, str(orderType))
ticket = self.Transactions.AddOrder(request)
self.tickets.append(ticket)
@@ -90,7 +91,7 @@ class UpdateOrderRegressionAlgorithm(QCAlgorithm):
self.Log("TICKET:: {0}".format(ticket))
updateOrderFields = UpdateOrderFields()
updateOrderFields.LimitPrice = self.security.Price*(1 - copysign(self.limit_percentage_delta, ticket.Quantity))
updateOrderFields.StopPrice = self.security.Price*(1 + copysign(self.stop_percentage_delta, ticket.Quantity))
updateOrderFields.StopPrice = self.security.Price*(1 + copysign(self.stop_percentage_delta, ticket.Quantity)) if ticket.OrderType != OrderType.TrailingStop else None
updateOrderFields.Tag = "Change prices: {0}".format(self.Time.day)
ticket.Update(updateOrderFields)
else: