Back to Community
TrailStop Algo with 200Dma Filter, Simple Question - Thanks

Hi, having issues with integrating a N Day Sma Filter to a Long/Short TrailStop strategy. I have the trails calculated somewhat (via min/max) problem is i want to only take Long trail signals if price > 200dma and only short trail signals when < 200dma. Also the price cross below or above N day sma should override any trail stop thats active at that moment. I think i have the if and else conditions wrongly structured, could someone please look it over.
Thanks for your time

Clone Algorithm
9
Loading...
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
import talib
from pytz import timezone

def intradingwindow_check(context):
        lock_dt = get_datetime().astimezone(timezone("US/Eastern"))
        if lock_dt.hour == 15 and lock_dt.minute == 55:
            return True
        else:
            return False
 
def initialize(context):

    # stocks to trade
    context.stock = symbol("AAPL")
    
    # stop-loss percent
    context.stop_pct = .89
    
    # stops dictionary
    context.stop = 11
 
def handle_data(context, data):
    
    if not intradingwindow_check:
        return

    price_history = history(200, "1d", "close_price")
    timeseries = price_history[context.stock]
    maverage = talib.SMA(timeseries, 142)[-1]
    price = data[context.stock].price
    qty = context.portfolio.positions[context.stock].amount
    #cash = context.portfolio.capital_used[context.stock].amount
        
    if qty == 0 and price < maverage:
        order_target_percent(context.stock, -1)

            # set trailing stop-loss
        context.stop = data[context.stock].price * context.stop_pct
            
        # check stop-loss for existing long position
    elif qty > 0:
            
            # if price has dropped below stop-loss
        if data[context.stock].price < context.stop:
                
                # reverse position (negative amount for short minus existing position)
            order_target_percent(context.stock, -1)
                
                # set trailing stop-loss (*above* current price for new short)
            context.stop = data[context.stock].price / context.stop_pct
                
            # otherwise price is still above stop-loss
        else:
                # update trailing stop-loss (*below* current price for existing long)
            context.stop = max(data[context.stock].price * context.stop_pct, context.stop)
                
        # check stop-loss for existing short position
    elif qty < 0:
            
            # if price has risen above stop-loss
        if data[context.stock].price > context.stop:
                
                # reverse position (positive amount for long minus existing position)
            order_target_percent(context.stock, 1)
                
                # set trailing stop-loss (*below* current price for new long)
            context.stop = data[context.stock].price * context.stop_pct
                
            # otherwise price is still below stop-loss
        else:
                # update trailing stop-loss (*above* current price for existing short)
            context.stop = min(data[context.stock].price / context.stop_pct, context.stop)
        
        
    record(Price=data[context.stock].price,
           Sma=maverage,
           Stop=context.stop,
           Position=qty)


"""
import talib
from pytz import timezone

# Set trade time at EOD/Close price
def intradingwindow_check(context):
        lock_dt = get_datetime().astimezone(timezone("US/Eastern"))
        if lock_dt.hour == 16 and lock_dt.minute == 0:
            return True
        else:
            return False
 
def initialize(context):

    context.stock = symbol("AAPL")
    context.stop_pct = .89 # stop-loss percent
    context.stop = {} # set an initial stoploss value, no idea why its needed hre since context.stop is defined in code below
 
def handle_data(context, data):
    
    # check if new day
    if not intradingwindow_check:
        return True

    price_history = history(200, "1d", "close_price")
    timeseries = price_history[context.stock]
    maverage = talib.SMA(timeseries, 200)[-1]
    price = data[context.stock].price
    qty = context.portfolio.positions[context.stock].amount
        
    # Set positions long or short, dont know how to set it to ccording to signal, in this case just tolid it to short if there are no pos.
    # I want the algo to trade price/maverage cross, BUT if price above maverage - take only Long signals from context.stop
    # if below maverage, take only Short signals from maverage
    if qty == 0 and price < maverage:
        order_target_percent(context.stock, -1)
        # set trailing stop-loss to the created short pos
        context.stop = data[context.stock].open_price / context.stop_pct
        
    if qty == 0 and price > maverage:
        order_target_percent(context.stock, 1)
        # set trailing stop-loss to the created short pos
        context.stop = data[context.stock].open_price * context.stop_pct
            
    # check stop-loss for existing long position
    elif qty > 0 and price > maverage:
        # if price has dropped below stop-loss
        if data[context.stock].price < context.stop: 
            # go flat
            order_target_percent(context.stock, 0)
            # set the stop for a new buyStop strigger (if price still > maverage)
            context.stop = data[context.stock].open_price / context.stop_pct
            # otherwise price is still above stop-loss
        else:
            # update trailing stop-loss for the existing long position (if price still > maverage)
            context.stop = max(data[context.stock].open_price * context.stop_pct, context.stop)
                
    # check stop-loss for existing short position
    elif qty < 0 and price < maverage:
        # if price has risen above stop-loss
        if data[context.stock].price > context.stop:
            # go flat
            order_target_percent(context.stock, 0)
            # set the stop for a new sellStop strigger (if price still < maverage)
            context.stop = data[context.stock].open_price * context.stop_pct
        # otherwise price is still below stop-loss
        else:
            # update trailing stop-loss (*above* current price for existing short)
            context.stop = min(data[context.stock].open_price / context.stop_pct, context.stop)
        
        
    record(Price=data[context.stock].price,
           Sma=maverage,
           Stop=context.stop,
           Position=qty)
"""
There was a runtime error.
8 responses

Sorry, wrong backtest - here is the new one with code commented properly
Thanks

Clone Algorithm
9
Loading...
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
import talib
from pytz import timezone

def intradingwindow_check(context):
        # Setting trade time to only EOD/Close price
        lock_dt = get_datetime().astimezone(timezone("US/Eastern"))
        if lock_dt.hour == 16 and lock_dt.minute == 0:
            return True
        else:
            return False
 
def initialize(context):
    context.stock = symbol("AAPL")
    # stop-loss percent
    context.stop_pct = .89
    # setting initial value for the stop, not sure why i need to do it here since it will be set when trigger occurs
    # if i dont set it here then i get code error
    context.stop = 11 # Just a generic value - getting it declared here so i dont get code error
 
def handle_data(context, data):
    # Checking if its a new day
    if not intradingwindow_check:
        return
    # Calculating average etc.
    price_history = history(200, "1d", "close_price")
    timeseries = price_history[context.stock]
    maverage = talib.SMA(timeseries, 142)[-1]
    price = data[context.stock].price
    qty = context.portfolio.positions[context.stock].amount

    # START OF TRADE EXECUTION CODE - I need a hand with this, thanks
    # If no position, check if price above or below maverage, initiate a trade accordingly
    if qty <= 0 and price > maverage:
        order_target_percent(context.stock, 1)
        # set trailing stop-loss below open price
        context.stop = data[context.stock].open_price * context.stop_pct
    # if no position and price below maverage, sell   
    if qty >= 0 and price < maverage:
        order_target_percent(context.stock, -1)
        # set trailing stop-loss above open price
        context.stop = data[context.stock].open_price / context.stop_pct
        
    # check for existing long position
    elif qty > 0:
        # if price has dropped below stop-loss but price  > maverage
        if data[context.stock].price < context.stop and price > maverage:
            # go flat
            order_target_percent(context.stock, 0)
            # set a new buy stop above, if triggered when price > maverage, it should buy
            context.stop = data[context.stock].open_price / context.stop_pct
                
        # otherwise price is still above stop-loss
        if data[context.stock].price > context.stop:
            # update trailing stop-loss below the long position
            context.stop = max(data[context.stock].open_price * context.stop_pct, context.stop)
            
    # check for existing short position
    elif qty < 0:
        # if price has rallied above stop-loss but price < maverage
        if data[context.stock].price > context.stop and price < maverage:
            # go flat
            order_target_percent(context.stock, 0)
            # set a new buy stop below, if triggered when price < maverage, it should sell
            context.stop = data[context.stock].open_price * context.stop_pct
                
        # otherwise price is still below stop-loss
        if data[context.stock].price < context.stop:
            # update trailing stop-loss above the short position
            context.stop = min(data[context.stock].open_price / context.stop_pct, context.stop)
                

    record(Price=data[context.stock].price,
           Sma=maverage,
           Stop=context.stop,
           Position=qty)
There was a runtime error.

I think you are on the right track, I changed a couple small things. It checks for the sell conditions first and updates the stop price no matter what since you use the min/max trailing stop. I made all the elif statements if statements because they shouldn't interfere with each other. It doesn't process the rest of the bar if it closes its position, it will wait until the next bar for a buy/sell signal. I also have it initializing the stop price with None.

Clone Algorithm
9
Loading...
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
import talib
from pytz import timezone

def intradingwindow_check(context):
        # Setting trade time to only EOD/Close price
        lock_dt = get_datetime().astimezone(timezone("US/Eastern"))
        if lock_dt.hour == 16 and lock_dt.minute == 0:
            return True
        else:
            return False
 
def initialize(context):
    context.stock = symbol("AAPL")
    set_benchmark(context.stock)
    # stop-loss percent
    context.stop_pct = .89
    # setting initial value for the stop, not sure why i need to do it here since it will be set when trigger occurs
    # if i dont set it here then i get code error
    context.stop = None # Just a generic value - getting it declared here so i dont get code error
 
def handle_data(context, data):
    # Checking if its a new day
    if not intradingwindow_check:
        return
    # Calculating average etc.
    price_history = history(200, "1d", "close_price")
    timeseries = price_history[context.stock]
    maverage = talib.SMA(timeseries, 142)[-1]
    price = data[context.stock].price
    qty = context.portfolio.positions[context.stock].amount
    
    # check for existing long position
    if qty > 0:
        # Update the stoploss no matter what
        context.stop = max(data[context.stock].open_price * context.stop_pct, context.stop)
        
        # if price has dropped below stop-loss but price  > maverage
        if data[context.stock].price < context.stop and price > maverage:
            # go flat
            order_target(context.stock, 0)
            # set a new buy stop above, if triggered when price > maverage, it should buy
            context.stop = None#.open_price / context.stop_pct
            
            # Don't do anything else on this bar
            return
        
            
    # check for existing short position
    if qty < 0:
        context.stop = min(data[context.stock].open_price / context.stop_pct, context.stop)
        # if price has rallied above stop-loss but price < maverage
        if data[context.stock].price > context.stop and price < maverage:
            # go flat
            order_target_percent(context.stock, 0)
            # set a new buy stop below, if triggered when price < maverage, it should sell
            context.stop = None #data[context.stock].open_price * context.stop_pct
            return 
            

    # START OF TRADE EXECUTION CODE - I need a hand with this, thanks
    # If no position, check if price above or below maverage, initiate a trade accordingly
    if qty <= 0 and price > maverage:
        order_target_percent(context.stock, 1)
        # set trailing stop-loss below open price
        context.stop = data[context.stock].open_price * context.stop_pct
        
    # if no position and price below maverage, sell   
    if qty >= 0 and price < maverage:
        order_target_percent(context.stock, -1)
        # set trailing stop-loss above open price
        context.stop = data[context.stock].open_price / context.stop_pct
        
    
            
    
                

    record(Price=data[context.stock].price,
           Sma=maverage,
           Stop=context.stop,
           Position=qty)
There was a runtime error.

Hi David and thanks for the mods, its almost quite what i had in mind, need one more alteration, please look at the graph, hope its clear.
I think the code needs one more set of trade conditions (reverse conditions?) that would define beahaviour in respect to the trail stop (setting and obeying the BuyStop/SellStop depending on on what side of maverage the price is)
https://www.dropbox.com/s/u7mcz6ugkk3niqo/Screen%20Shot%202014-08-18%20at%2023.23.52.png

I took a closer look and I think I see your problem, correct me if I'm wrong. When your trailing stop is triggered, it does try to go flat, but because it is still above its moving average, it immediately re-enters the position on the next bar. It's is probably symmetric on the short side too.

If that's the problem, you'll have to come up with some logic to handle when your algo enters that no-mans land after a trailing stop is triggered, but before the price has crossed to the other side of the moving average. You'll need some type of re-entry rule before it can trade on the same side again. Hopefully it's an easy fix, but I think that's what is causing the problem

David, you are correct. I got it so far that it behaves as it should when in long mode (price > maverage) and it even trails the stop down when in short mode (price

Clone Algorithm
3
Loading...
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
import talib
from pytz import timezone

def intradingwindow_check(context):
        # Setting trade time to only EOD/Close price
        lock_dt = get_datetime().astimezone(timezone("US/Eastern"))
        if lock_dt.hour == 16 and lock_dt.minute == 0:
            return True
        else:
            return False
 
def initialize(context):
    context.stock = symbol("AAPL")
    set_benchmark(context.stock)
    # stop-loss percent
    context.stop_pct = .89
    context.stop = 10 # setting it to a number, so i can get an entry condition
    context.longmode = None
 
def handle_data(context, data):
    # Checking if its a new day
    if not intradingwindow_check:
        return

    price_history = history(200, "1d", "close_price")
    timeseries = price_history[context.stock]
    maverage = talib.SMA(timeseries, 142)[-1]
    price = data[context.stock].price
    qty = context.portfolio.positions[context.stock].amount
    
## LONG MODE (PRICE > MAVERAGE)
    # check for existing long position
    if qty > 0 and price > maverage:
        # if price has dropped below stop-loss
        if data[context.stock].price < context.stop:
            # go flat
            order_target(context.stock, 0)
            # set a new buy stop above
            context.stop = data[context.stock].open_price / context.stop_pct
            
            # otherwise trail the stop up
        else:
            context.stop = max(data[context.stock].open_price * context.stop_pct, context.stop)
    
    # If algo has hit a stop/is flat while price > maverage    
    if qty == 0 and price > maverage:
        # if price has rallied above the Buy Stop
        if data[context.stock].price > context.stop:
            # go long again
            order_target(context.stock, 1)
            # set a new buy stop below
            context.stop = data[context.stock].open_price * context.stop_pct
            
            # otherwise trail the buy stop down
        else:
            context.stop = min(data[context.stock].open_price / context.stop_pct, context.stop)
            
## SHORT MODE (PRICE < MAVERAGE)
    # check for existing short position
    if qty < 0 and price < maverage:
        # if price has dropped below stop-loss and price < maverage
        if data[context.stock].price < context.stop:
            # go short
            order_target(context.stock, -1)
            # set a new buy stop above
            context.stop = data[context.stock].open_price / context.stop_pct
            
            # otherwise trail the stop up
        else:
            context.stop = max(data[context.stock].open_price * context.stop_pct, context.stop)
    
    # If algo has hit a stop while in long mode (price > maverage)     
    if qty == 0 and price < maverage:
        # if price has risen above stop-loss and below maverage
        if data[context.stock].price > context.stop:
            # go short
            order_target(context.stock, 0)
            # set a new sell stop below
            context.stop = data[context.stock].open_price * context.stop_pct
            
            # otherwise trail the buy stop down
        else:
            context.stop = min(data[context.stock].open_price / context.stop_pct, context.stop)            
        
            

        
    
            
    
                

    record(Price=data[context.stock].price,
           Sma=maverage,
           Stop=context.stop,
           Position=qty)
There was a runtime error.

Damit, it cropped all the text i had, here it is again

Its almost there, in long mode it behaves correct, here are the remaining issues
1. It should go long or short at the price crossing the maverage, no matter what stop is saying at that moment
2. Position sizes dont make sense, it only trades 1-2 shares max at this version
3. Stop behaviour when price below maverage is not correct, that is it trails down well but not when stopped out of short, you can see it on the graph when disabling Position plot

Additional stuff:
- Tried to add your datetime check for eod trading, but it did not proceed at all, i added this code below handle data

    time = str(get_datetime().astimezone(timezone("US/Eastern")))  
    if time != '16:00:00': # only trading at this time once a day  
        return  
  • Would it be better off using talib.atr ? (less code, as dont have to min/max the stops manually)

Thanks

Darell,
You could certainly use something like atr for your stops, theres no correct answer to that one really. This might be useful, but its pretty math heavy, Optimal Trading Stops and Algorithmic Trading. I'll take a closer look later.

It looks like you were using order_target when you meant to use order_target_percent, I changed that and now it doesn't just get the 1-2 shares.

Clone Algorithm
399
Loading...
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
import talib
from pytz import timezone

def intradingwindow_check(context):
        # Setting trade time to only EOD/Close price
        lock_dt = get_datetime().astimezone(timezone("US/Eastern"))
        if lock_dt.hour == 16 and lock_dt.minute == 0:
            return True
        else:
            return False
 
def initialize(context):
    context.stock = symbol("AAPL")
    set_benchmark(context.stock)
    # stop-loss percent
    context.stop_pct = .89
    context.stop = 10 # setting it to a number, so i can get an entry condition
    context.longmode = None
 
def handle_data(context, data):
    # Checking if its a new day
    if not intradingwindow_check:
        return

    price_history = history(200, "1d", "close_price")
    timeseries = price_history[context.stock]
    maverage = talib.SMA(timeseries, 142)[-1]
    price = data[context.stock].price
    qty = context.portfolio.positions[context.stock].amount
    
## LONG MODE (PRICE > MAVERAGE)
    # check for existing long position
    if qty > 0 and price > maverage:
        # if price has dropped below stop-loss
        if data[context.stock].price < context.stop:
            # go flat
            order_target(context.stock, 0)
            # set a new buy stop above
            context.stop = data[context.stock].open_price / context.stop_pct
            
            # otherwise trail the stop up
        else:
            context.stop = max(data[context.stock].open_price * context.stop_pct, context.stop)
    
    # If algo has hit a stop/is flat while price > maverage    
    if qty == 0 and price > maverage:
        # if price has rallied above the Buy Stop
        if data[context.stock].price > context.stop:
            # go long again
            order_target_percent(context.stock, 1)
            # set a new buy stop below
            context.stop = data[context.stock].open_price * context.stop_pct
            
            # otherwise trail the buy stop down
        else:
            context.stop = min(data[context.stock].open_price / context.stop_pct, context.stop)
            
## SHORT MODE (PRICE < MAVERAGE)
    # check for existing short position
    if qty < 0 and price < maverage:
        # if price has dropped below stop-loss and price < maverage
        if data[context.stock].price < context.stop:
            # go short
            order_target_percent(context.stock, -1)
            # set a new buy stop above
            context.stop = data[context.stock].open_price / context.stop_pct
            
            # otherwise trail the stop up
        else:
            context.stop = max(data[context.stock].open_price * context.stop_pct, context.stop)
    
    # If algo has hit a stop while in long mode (price > maverage)     
    if qty == 0 and price < maverage:
        # if price has risen above stop-loss and below maverage
        if data[context.stock].price > context.stop:
            # go short
            order_target(context.stock, 0)
            # set a new sell stop below
            context.stop = data[context.stock].open_price * context.stop_pct
            
            # otherwise trail the buy stop down
        else:
            context.stop = min(data[context.stock].open_price / context.stop_pct, context.stop)            
        
            

        
    
            
    
                

    record(Price=data[context.stock].price,
           Sma=maverage,
           Stop=context.stop,
           Position=qty)
There was a runtime error.