Back to Community
Trailing Stop with multiple securities does not work as intended

Hi guys,
I have a problem regarding the coding for a trailing stop set at 1% from the security’s high (which obviously changes during the day depending on the high). When I had a look at the forum I found some posts about trailing stops, so I had a look and tried to incorporate them into my idea (just buy those three securities that have the highest MACD). I am restricting myself to the ‘Q1500US’ dataset.

Basically, there are two algorithms that I am presenting here, the only difference between them lying in line 74 and 75. The first algorithm I post here uses line 75 (instead of 74) and the result is that all securities that are bought during a day are held until 10pm (despite the selling condition of the trailing stop). The second algorithm uses line 74 and the result here is that the trailing stop works for one security but not for the other 2 securities (if 3 securities are bought at all).
Hence, I have the following questions:
1. Why is on some days only one security bought? Does that have to do with pipeline screening among all securities and choosing the top 3 MACD among those, while my filter puts another constraint (Q1500US) on there so that in the end only those in the top 3 MACD of all securities AND those in Q1500US are included? How can I change the coding so that the top 3 MACD securities from US1500 are chosen?
2. With regards to the first algorithm, why doesn’t it sell before 10pm?
3. With regards to the second algorithm, why does the trailing stop only works for one security in the portfolio but not for all of them?

Clone Algorithm
11
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 593537dd53d6a06dded4a0b9
There was a runtime error.
4 responses

And thi is the second algorithm.
Thank you very much for your help in advance!

Clone Algorithm
11
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 593538e51acd536e693d65dc
There was a runtime error.

Ok, your problem lies in set_trailing_stop() and handle_data() functions in the way you are storing the stop price and the way you are calling the set_trailing_stop() function.

def set_trailing_stop(context, data, security):  
        price2 = data.current(security, 'high')  
        #context.stop_price needs to be a dictionary to store a different highest price for each security  
        context.stop_price[security] = max(context.stop_price[security], price2)  
        log.info("Trail set {} at {}".format(security.symbol, context.stop_price*context.stop_pct))  
def handle_data(context, data):  
    for security in context.portfolio.positions:  
        current_position = context.portfolio.positions[security].amount  
        #Call the function to find the highest price for this security  
        set_trailing_stop(context,data, security)  
        #Set your stop price to your highest price times the stop percent  
        stop_price = context.stop_price[security] * context.stop_pct  
        if (data.current(security, 'price') < stop_price) and (current_position > 0):  
            order_target_percent(security, 0)  
            #Reset the highest price  
            context.stop_price[security] = 0.0  
            log.info("Trail Selling {} at {}".format(security.symbol, data.current(security, 'price')))  

There are other ways to do it (I see some of your code was trying to do it the other way but you mixed two methods and thats why it wasn't working) but this was just the way I wrote it.

If you wanted to use context.stop_price2=set_trailing_stop(context,data) you would need to include a line like this in your set_trailing_stop() function:
return stop_price if you set a variable to a function it has to return something to set the variable to.

Hi Luke, apologies for the late reply! I got it working with your help. A huge thank you!!! Jannik :)

Jannik - can you repost your algo with the working code?