Back

[Feature] OrderTickets and Updating Orders

Recently we deployed a new version of the LEAN engine. In this new version there are load of new goodies. Here I showcase an updated version of the canonical QCU algorithm, How Do I Use Limit Orders. We've spent some time to make this easier, so I hope you guys like it!

In the new deploy, the standard order functions (MarketOrder, LimitOrder, ect...) will return you an OrderTicket object. The OrderTicket is your reference to your order. You can use it to update, cancel, and even check the status of the order.OrderTicket limitOrderTicket = LimitOrder("SPY", 100, 205);
In order to perform updates, you can call the Update method on the OrderTicket. The Update method takes an UpdateOrderFields object which defines what properties of the order should be updated. We can easily change the limit price using the following line of code: limitOrderTicket.Update(new UpdateOrderFields{LimitPrice = 207.50};
This will submit a request to update the order in our system.
Likewise, you can easily cancel your order using the Cancel method:limitOrderTicket.Cancel();
Check out the attached algorithm which shows updating of the limit price. Check out the UpdateOrderFields class for the other properties that can be updated.
Update Backtest






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.



Is it possible to retrieve the fill price of a successful order? I see that the OrderTicket class contains a private Order instance, but there's no accessor for it (yet?). Is there another way to get this info?

For example, say I want to execute a MarketOrder, then immediately place a LimitOrder with a limit relative to the executed price.
0

The executed price is currently available through the order events collection. I'll add an accessor for the average fill price to make this easier, but for now this code should work:
var ticket = MarketOrder("SPY", 100);
if (ticket.Status == OrderStatus.Filled)
{
// grab the fill events
var fills = ticket.OrderEvents.Where(orderEvent => orderEvent.Status.IsFill()).ToList();
// to compute average price we want a weighted average = SUM(n*p)/n
var sumQuantityPrice = fills.Sum(fill => fill.FillQuantity * fill.FillPrice);
var sumQuantity = fills.Sum(fill => fill.FillQuantity);
var fillPrice = sumQuantityPrice / sumQuantity;
}
0

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.


@Adam Hedges - I've added OrderTicket.AverageFillPrice and OrderTicket.QuantityFilled, these will be available in our next deploy. See commit on github.
0

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.


I've also thrown together a fairly extensive order ticket demo algorithm to showcase the various supported order types and how to update/cancel them. Here it is in all it's glory!

As always, let me know what you guys think and/or have any questions!
3

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.


Awesome, thanks!
0

Those examples are super helpful. Thanks!
0

Ok. I need a little clarification.

Let's say I want to set up a position with profit taking and risk management:
Long order, sell on 2% limit, 1% stop loss, with a 0.08% trailing stop loss.

Would that look something like this?

var longOrder = StopLimitOrder(Symbol, quantity, currentPrice * 1.02m, currentPrice);
var stopLoss = StopLimitOrder(Symbol, -quantity, currentPrice * 0.99m, currentPrice);

// elsewhere, update on new highs
stopLoss.Update(new UpdateOrderFields { StopPrice = newPrice * 0.92m });


Basically, I'll need 2 orders (one with the upper target, one with the lower target), then update the lower target on new highs?
0

Hey Jonathan, does this code assume we've already entered a position?

Assuming we've entered a position (say +10 shares SPY), and we want to submit a profit taking order at 2%:// submit order to sell at +2% current price
var profitTakingTicket = LimitOrder(Symbol, -10, currentPrice*1.02m);

If we'd like to submit a 1% stop loss:// submit order to execute when price drops below 1%
var stopLossTicket = StopMarketOrder(Symbol, -10, currentPrice*.99m);

If we'd like to update our stop loss so that it 'trails' the current price:// update stop loss order on new highs
if (currentPrice > previousHigh)
stopLossTicket.Update(new UpdateOrderFields{StopPrice = currentPrice*.99m);


Let me know if you require further clarification with this, or if I've misunderstood your requirements.

Also, I would recommend to use StopMarketOrder for stop loss instead of StopLimitOrder.
1

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.


Thanks! I'll try that out. That's exactly what I was looking for.

Edit: Also, what do I do to check if the profit taking or stop losses have been executed? just use ticket.Filled?
0

You can check if a ticket is still open using:if (ticket.Status.IsOpen()) { // open ticket }Likewise, there's also one for closed:if (ticket.Status.IsClosed()) { // closed ticket }
0

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.


Ok... I have something of an issue here.

I can use either LimitOrders or StopMarketOrders, but not both -- once I enable both, I start getting swarmed with MarginCall errors. I think the problem is, when either the LimitOrder or StopMarketOrder gets filled, the other order doesn't get cancelled, and so ends up executing even when I'm out of the market.

Is there an easy way to tie the LimitOrder and StopMarketOrder together, so that when one executes the other gets cancelled?
0

Hey Jonathan, currently we don't support OCA (one cancels all) order types. You'll need to maintain the state required to mimic these. This can be done by grouping the orders into a container and each time you get an OrderEvent, if it is a fill, cancel the others. I've attached a sample that does this.

Let me know if this works for you, and if you improve it be sure it share it back to the community! :)
2

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.


Ahhhh, there's an OnOrderEvent method that I can tie into. Sweet -- that's what I was missing. Perfect. I'll give that a shot.

Thanks for the help!
3

Ok... this is driving me crazy. I used code similar to yours (but more explicit for my simpler use case). It works 100% fine for either the StopMarketOrder or LimitOrder, but not for both at the same time.

According to the logs, it's sending the cancel events, but the orders are still showing up as "filled" in the trade list, causing bad behavior.

Log of attempted order cancels

Here is the project, with my "super-secret" algo (trend-following w/ SMA crossover, mean-reversion w/ RSI). ;) Please excuse the code... it's really experimental and exploratory, so it's quite messy. The code for creating/canceling the orders is in Position.cs.
0


I think what's happening here is the daily bars have a rather large range, so it possible for both the limit/stop loss to fill on the same bar if the high/low spread is wide enough. Changing the input data resolution to Minute removes all the insufficient funds warnings and gives a more impressive equity curve. I would only use daily data when making decisions on a weekly or greater basis, you always want your data resolution to be an order finer than your decision making resolution, so for a monthly rebalance, daily data is great. When looking for 2% swings, it's typically better to have the granularity of minute data for trade execution and order management. I view daily as 'run every day at midnight' which is very infrequent!

When I cloned and reviewed the trades tab it looked like most of the time it works (cancelling either stop loss or profit taker), but sometimes it doesn't, which I assume is due to a volatile day.

Also, I like to have the cancellation code inside the OnOrderEvent, so that as soon as the limit/stop loss fills, I can cancel the other immediately.
0

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.


So simple... So much hair pulling, and the answer is so simple... Thanks Michael! I finally have what I want working.
1

Hi there folks!

I’m trying to figure out how the OnOrderEvent override method works. I made this silly algo, with an objective in mind; to check if my understanding of the order status is correct.

Question 1: From the strings in the switch (line 40); did I understood the order status meaning?

However, it seems I found a bug, in the Order.Direction field (line 77). The algorithm only sends buy market orders, but the log is:
2013-10-06 20:00:00 Launching analysis for 3c8694c30fd6bc9a2bebbf2137903b1f with LEAN Engine v2.1.3.5
2013-10-07 09:31:00 10/07/2013 09:31:00 : Sell Market Order Id 1 of AIG was submitted.
2013-10-07 09:31:00 10/07/2013 09:31:00 : Buy Market Order Id 1 of AIG was filled at $48.265499725.
2013-10-07 09:31:00 10/07/2013 09:31:00 : Sell Market Order Id 2 of BAC was submitted.
2013-10-07 09:31:00 10/07/2013 09:31:00 : Buy Market Order Id 2 of BAC was filled at $13.70672050.
2013-10-07 09:31:00 10/07/2013 09:31:00 : Sell Market Order Id 3 of IBM was submitted.
2013-10-07 09:31:00 10/07/2013 09:31:00 : Buy Market Order Id 3 of IBM was filled at $174.310339515.
2013-10-07 09:31:00 10/07/2013 09:31:00 : Sell Market Order Id 4 of SPY was submitted.
2013-10-07 09:31:00 10/07/2013 09:31:00 : Buy Market Order Id 4 of SPY was filled at $161.795815272.


Like the direction changes if the order is filled or not.

Question 2: Why do you said
This method can be called asynchronously and so should only be used by seasoned C# experts.
in the OnOrderEven help? For the unseasoned like me is very intimidating!

Best, JJ
1

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.


Hey JJ! Long time no see, welcome back!!

It looks like there is a bug in the OrderEvent.Direction property. It is computed via the FilledQuantity. It looks like you grock the order status values. Here's the open source page with documentation.

The documentation is offering a warning that code that runs within the OnOrderEvent must be thread safe. This can be accomplished by using concurrent data structures from the System.Collections.Concurrent namespace or through explicit locking. Minimally have yourself a short read of some of the things to think about when writing asynchronous code.

Let me know if you have other specific questions regarding multithreading and/or the order events in a new thead! This one is slowly drifting off topic! Thanks!
0

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.


Thank you very much @Michael!
0

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.


That 's very useful, how would one do the same in Python though? It would be great to see a Python version of the attached example

0

Hi Olivier; the generic answer to that question is in the API tab on the left side of the IDE. We actually have more examples of python than C# now! =) The Order Ticket example link is below.

https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/OrderTicketDemoAlgorithm.py
1

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.


From the link above:

# submit another limit order to sell 10 shares at .1% above the bar's close
newTicket = self.LimitOrder(self.spy, -10, close * d.Decimal(1.001))
self.__openLimitOrders.append(newTicket)

 

What if you want to close the position? How do you programmatically obtain the current number of shares and what would that look like in place of "10"?

More specifically, I'd like to set stop and limit for closing positions as soon as limit orders to open them have filled, and this would need correcting

 

def OnOrderEvent(self, OrderEvent):
if OrderEvent.Status == OrderStatus.PartiallyFilled:
self.Log(' partial {}'.format(OrderEvent.Symbol))
elif OrderEvent.Status == 3 and OrderEvent.FillQuantity > 0:
self.Log(' filled {} {}'.format(OrderEvent.FillQuantity, OrderEvent.Symbol))
self.LimitOrder( OrderEvent.Symbol, -self.Securities[OrderEvent.Symbol].Quantity, self.Securities[OrderEvent.Symbol].Price * decimal.Decimal(1.02), tag='')
self.StopMarketOrder(OrderEvent.Symbol, -self.Securities[OrderEvent.Symbol].Quantity, self.Securities[OrderEvent.Symbol].Price * decimal.Decimal(.99), tag='')

0

-self.Portfolio[OrderEvent.Symbol].Quantity for the current number of shares. This is in OnOrderEvent()

 

self.LimitOrder(OrderEvent.Symbol, -self.Portfolio[OrderEvent.Symbol].Quantity, self.Securities[OrderEvent.Symbol].Price * decimal.Decimal(1.02), tag='')
0

check also the docu for canceling specific orders:

https://www.quantconnect.com/docs/algorithm-reference/trading-and-orders# Creating an Order:
limitOrderTicket = self.LimitOrder("SPY", 100, 205)

# Updating an Order:
updateOrderFields = UpdateOrderFields()
updateOrderFields.LimitPrice = decimal.Decimal(207.50)
limitOrderTicket.Update(updateOrderFields)

# Cancel an Order:
limitOrderTicket.Cancel()

# Cancel all open orders from SPY
cancelledOrders = self.Transactions.CancelOpenOrders("SPY")

# Cancel order #10
cancelledOrder = self.Transactions.CancelOrder(10)

# Get open orders
openOrders = self.Transactions.GetOpenOrders()

# Get open orders from SPY
openOrders = self.Transactions.GetOpenOrders("SPY")

# Get open order #10
openOrder = self.Transactions.GetOrderById(10)

# Get all orders
orders = self.Transactions.GetOrders()

# Get order ticket #10
orderTicket = self.Transactions.GetOrderTicket(10)

# Get all orders tickets
openOrderTickets = self.Transactions.GetOrderTickets()
0

Update Backtest





0

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.


Loading...

This discussion is closed