QuantConnect: Trailing Stops

In this article, we will provide a code snippet/example of how to implement a trailing stop on Quantconnect. At the time of writing, the LEAN API currently does not support this type of stop. Therefore, if we want to use a trailing stop, we need to craft it ourselves with the tools at our disposal.

Trailing Stops

To implement a basic trailing stop, all we need to do is update our stop-loss order frequently. This means determining whether the stop should move up and if so, just moving it ourselves with an order update. Admittedly, this is a bit of a workaround because you can only update your stop level at certain points in time. For example, when OnData()is called. Furthermore, If you are trading on a daily timeframe, that may not be frequent enough for you. However, before you start moving for the close button on the browser, this “workaround” does have a lot of power in disguise. By giving yourself control over when the stop loss level moves, you can create some really interesting trailing stops. Want to trail only behind swings in price action? You can do that! Volatility has picked up and you want to give the stop some more breathing room? Again, you can do that! I am sure you get the idea.

Example Code

Commentary

Because we want to edit and update our stop loss as we go, the first thing we need to do is create an attribute (variable) that will store our stop-loss ticket. Tickets are returned from the API methods (functions) that create orders and we need them to update the order later. For this reason, one of the first things we do is to give the ticket a place to live during initialization.

At the same time, we also create another attribute to track the last trail stop level. This will be used on each bar to check whether the current stop loss level is higher than the last trailing level. If it is, we move the stop loss up. Note that you could also tackle this part by using a rolling window. If you wish to learn more about that, click on that link for an introduction on accessing previous values. The reason why a rolling window was not used in the example, is simply because we never need to access more than the most recent previous value and we are able to track it without the need for a rolling window.

On Data

The rest of the magic happens when OnData()is called. For the purposes of this tutorial, we enter a position immediately and send a stop loss order at the same time. Here, you will notice that we make use of self.sl_order.

Next, we can take a look at the trailing calculation. To do this, we just calculate a “base” stop loss value. That is the current close minus thetrail_dist. If price has moved in our favour, this base value will be above our self.last_trail_level. If so, we then update the ticket with the lines:

Note: For more information regarding the use of UpdateOrderFields()see the official docs here: https://www.quantconnect.com/docs/algorithm-reference/trading-and-orders

After updating the order, notice how we now update the self.last_trail_level at the same time. This will be the new hurdle to beat in subsequent bars.

Finally, if not, we ignore this bar and keep the stop loss level as is. Assuming price never moves in our favor again, this would continue until the SL is hit. This is just as a real trailing stop would work.

Verification

Since there are not any nice plots on the chart, we need to turn to our logs to verify what is going on. Run the backtest and open up your logs. You should see something like this:

Trailing Stop Log

Noice, how the trailing stop starts at $254.66 and is updated on the following bar when price moves and the new base level is calculated at $254.99.