Hello 😊 As bracket orders are not integrated in QuantConnect (which is a pity) I figured I would attempt to create the functionality myself. I was hoping I could get some help from the community to finish the functionality, so we can all benefit from using it (I have seen multiple posts requesting functionality for bracket orders). Maybe it can even be used to help QC in creating support for bracket orders.
My idea is to create a class that initiates and handles all new bracket orders (the BracketOrder class in the BracketOrder.py file) - one object per new bracket order. It works decently well, but I have encountered a problem: New bracket orders are stored in a dictionary using the parent ticket's OrderId (self.bracketOrders - the ticket IDs of profit target and stop loss orders are also stored here to reference the same BracketOrder object). Orders are placed asynchronously and whenever an update to an order happens it immediately calls the OnOrderEvent function. On occasion, an order can be filled before I have had the time to create a BracketOrder object. When that happens, the given OrderId is not found in self.bracketOrders which results in an error.
I am not sure if it would help to create the BracketOrder object once it is filled and obtained in OnOrderEvent as multiple partial fills can happen before an object is created causing the same error.
I have attached a backtest displaying the code. Can't attach a backtest with an error, unfortunately. However, I discovered that the error occurs because order is filled before the ticket for the order, and the BracketOrder object of that order has been created. You get the error if you change the end date to self.SetEndDate(2022, 6, 15) # Set End Date.
Louis Szeto
Hi Haakon
Thank you for this contribution! Right now, we support multiple orders to do so. You might want to refer to this docs as reference.
Best
Louis
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Haakon
Louis Szeto The docs you referred to give a decent example of how to create a single OCO order. However, it lacks support for handling partially filled orders, and using the suggested method will be extremely difficult and messy when dealing with many simultaneous bracket orders. That is why I wanted to create a BracketOrder object for each new bracket order.
UPDATE:
I have made some changes to the initial code. The problem regarding order fills before order ticket creation actually came from new orders created by liquidating the portfolio each day. I solved it by adding a tag to the liquidate functions and check for that tag in OnOrderEvent. The updated version (in the backtest of this comment) looks promising, but is not complete nor tested well enough yet. It still lacks support for handling partial fills of profit orders (not sure how these should be handled tbh - currently I just cancel all open orders and liquidate the remaining position which is the same as using a market order as the profit order which is not ideal). Also, the profit and stop loss prices should probably be set by the actual fill price of the initial order, and not the “stop price” for the initial stop limit order.
Hopefully, it can be useful for someone looking to use bracket orders. Suggestions for improvements are very welcome 😊
Louis Szeto
Hi Haakon
Thank you for your contribution! Maybe you'll also want to handle partially filled events. Take a look at this thread. 🚀
Best
Louis
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Haakon
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!