Back to Community
Long Price Action Algo

I couldn't successfully hedge this one and it doesn't pass beta so I figured I'd share in case someone can improve on it.

Stocks were randomly chosen

Clone Algorithm
48
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 datetime import datetime
import numpy as np


def initialize(context):
    context.max_notional = 100000
    context.stocks = [symbol('SPY'), symbol('FLS'), symbol('DRI'), symbol('CCE'), symbol('BBBY'), symbol('BK'), symbol('AMT'), symbol('AMG'), symbol('ETFC'), symbol('DNB'), symbol('CAH'), symbol('AMGN'), symbol('AAPL'), symbol('BIIB'), symbol('CAM'), symbol('AA'), symbol('BLK'), symbol('FOSL'), symbol('AON'), symbol('DVN'), symbol('EXPD'), symbol('CCI'), symbol('ADBE'), symbol('AN'), symbol('CTAS'), symbol('BAX'), symbol('DGX'), symbol('AET'), symbol('DHR'), symbol('APH'), symbol('FFIV'), symbol('BRCM'), symbol('ESV'), symbol('APA'), symbol('BXP'), symbol('EQT'), symbol('AIV'), symbol('CB'), symbol('AKAM'), symbol('BDX'), symbol('BWA'), symbol('EXC'), symbol('ESS'), symbol('EL'), symbol('CTXS'), symbol('DOW'), symbol('COF'), symbol('DO'), symbol('FOXA'), symbol('CTSH'), symbol('EBAY'), symbol('CINF'), symbol('DLTR'), symbol('AME'), symbol('ABT'), symbol('COP')]
    set_benchmark(symbol('spy'))
    
    context.RSI_timeperiod  = 7


    context.charttype = '1d'
    #context.percent = .25


    #pct_per_algo = 1.0 / len(context.stocks)
    pct_per_algo = .07
    


    context.algos = [rsi_strat(stock, pct_per_algo) for stock in context.stocks]
    
    #set_slippage(slippage.FixedSlippage(spread = 0.00))
    #set_commission(commission.PerShare(0.0075))


def handle_data(context, data):
    
    for stock in context.stocks:
        if stock.security_end_date < get_datetime():
            print stock
            context.stocks.remove(stock)    

    # Call each individual algorithm's handle_data method.
    for algo in context.algos:
        algo.handle_data(context, data)


class rsi_strat(object):

    # Initialize with a single stock and assign a proportion of the account.
    def __init__(self, security, pct_of_account, ma_window=20):
        self.security = security
        self.percent = pct_of_account
        
        self.lookback = 500
        self.rsi_low = 30
        self.rsi_high = 70
        
        self.entry = 0
        self.stop = 0
        self.target = 0
        self.position = 0
        
        self.stop_multiplier = 1.5
        
        self.pattern_long_start = False
        self.pattern_pt1_start = False
        self.pt1_open_long = []
        self.pt1_high_long = []
        self.pt1_low_long = []
        self.pt1_close_long = []
        self.pt1_rsi_long = []
        self.pt2_open_long = []
        self.pt2_high_long = []
        self.pt2_low_long = []
        self.pt2_close_long = []   
      

        
        self.pattern = False
        
        self.max_lvrg = 3
        self.position = 0



    def higher_trough(self):
        trough1 = self.pt1_open_long+self.pt1_close_long
        trough2 = self.pt2_open_long+self.pt2_close_long
     

        try:
            if min(trough2) >= min(trough1):
                return True
        except:
            return False


    def define_stop_target_long(self,context,prices_low):

        good_bad = ()

        stop = min(self.pt2_low_long)
        stop = prices_low[-1]
        target = max(self.pt1_high_long)
        
        

        entry = self.pt2_close_long[-1]

        stop_amnt = entry - stop
        target_amnt = target - context.portfolio.positions[self.security].cost_basis
        
        stop_amnt = (target - context.portfolio.positions[self.security].cost_basis) / 2.5
        
        stop = context.portfolio.positions[self.security].cost_basis - stop_amnt
        
        
        #if target_amnt >= (stop_amnt * self.stop_multiplier):
            #good_bad = 'good'

        #else:
            #good_bad = 'BAD'

        return entry,stop,target,good_bad


    def handle_data(self, context, data):


        #print 'debug class'
        #print context.percent
        
        prices_open = history(self.lookback, context.charttype, 'open_price')[self.security]
        prices_open = list(prices_open.values.flatten())    
        prices_high = history(self.lookback, context.charttype, 'high')[self.security]       
        prices_high = list(prices_high.values.flatten())    
        prices_low = history(self.lookback, context.charttype, 'low')[self.security]
        prices_low = list(prices_low.values.flatten())    
        prices_close = history(self.lookback, context.charttype, 'close_price')[self.security]
        prices_close = list(prices_close.values.flatten())   

        prices = history(self.lookback, context.charttype, 'price')[self.security]

        
        rsi = talib.RSI(prices, timeperiod=context.RSI_timeperiod)
        #rsi = rsi
        
        #print 'cost basis test'+str(context.portfolio.positions[context.stock].cost_basis)
        openprice = prices_open[-1]
        highprice = prices_high[-1]
        lowprice = prices_low[-1]
        closeprice = prices_close[-1]
        


        short_SMA = talib.SMA(prices, timeperiod=50)
        long_SMA = talib.SMA(prices, timeperiod=200)
        
        short_SMA = short_SMA.tolist()
        long_SMA = long_SMA.tolist()
        
        
        try:
            if rsi[-2] > self.rsi_high and rsi[-3] < rsi[-2] and rsi[-1] < rsi[-2]:
                self.pattern_long_start = True
                #print 'debug '+str(self.security)
                #print self.pattern_long_start
                #print self.pattern_pt1_start
        except:
            raise

        if self.pattern_long_start == True and self.pattern_pt1_start == False:
            self.pt1_open_long.append(openprice)
            self.pt1_high_long.append(highprice)
            self.pt1_low_long.append(lowprice)
            self.pt1_close_long.append(closeprice)
            self.pt1_rsi_long.append(rsi[-1])
            
            #print 'debug '+str(self.security)


                    
        try:
           if rsi[-2] > self.rsi_high and rsi[-3] < rsi[-2] and rsi[-1] < rsi[-2] and len(self.pt1_rsi_long) >= 2 and min(self.pt1_rsi_long) <= self.rsi_low:
                self.pattern_pt1_start = True
                self.pattern_long_start_ovl = True
        except:
            raise


        if self.pattern_pt1_start == True:
            self.pt2_open_long.append(openprice)
            self.pt2_high_long.append(highprice)
            self.pt2_low_long.append(lowprice)
            self.pt2_close_long.append(closeprice)
            self.pt1_rsi_long.append(rsi[-1])

        if self.pattern_pt1_start == True and rsi[-2] < self.rsi_low and rsi[-3] > rsi[-2] and rsi[-1] > rsi[-2]:

            rsi_strat.higher_trough(self)

            if rsi_strat.higher_trough(self) == True:

            #if context.position == 0:
                #print symbol,date
                #print 'debug 4'
                
                if short_SMA[-1] > long_SMA[-1] and context.account.leverage <= self.max_lvrg:
                    
                    order_target_percent(self.security, self.percent)
                    st = rsi_strat.define_stop_target_long(self,context,prices_low)
                    currentshares = context.portfolio.positions[self.security].amount
                    if currentshares > 0.0:
                        self.stop = st[1]
                        self.target = st[2]
                        self.position = 1
                        #print '----entering position----'
                        #print 'my cost basis '+str(context.portfolio.positions[context.stock].cost_basis)
                        #print 'my stop '+ str(context.stop)
                        #print 'my target '+ str(context.target)
                        #print '------end-------'

                    


            self.pattern_pt1_start = False               
            self.pattern_long_start = False
            self.pt1_open_long = []
            self.pt1_high_long = []
            self.pt1_low_long = []
            self.pt1_close_long = []
            self.pt1_rsi_long = []

            self.pt2_open_long = []
            self.pt2_high_long = []
            self.pt2_low_long = []
            self.pt2_close_long = []




        if data[self.security].price <= self.stop and self.position == 1:
        #if data[context.stock].price <= context.stop and context.stop != 0:

            order_target(self.security, 0)
            self.position = 0
            #print 'stop hit for long position'
            
            #print context.stop

        
            self.entry = 0
            self.stop = 0
            self.target = 0
        
        if data[self.security].price >= self.target and self.position == 1:
        #if data[context.stock].price >= context.target and context.target != 0:
            order_target(self.security, 0)
            self.position = 0
            currentshares = context.portfolio.positions[self.security].amount
            #print 'target hit for long position'
            #print 'current amt of shares after exiting '+str(currentshares)

           
            #print context.target

            context.entry = 0
            context.stop = 0
            context.target = 0


        if short_SMA[-1] < long_SMA[-1]:
            currentshares = context.portfolio.positions[self.security].amount
            if currentshares > 0.0:
                #print 'shares that should have been sold '+str(currentshares)
                #print 'trying to get rid of em '
                order_target(self.security, 0)

                #currentshares = context.portfolio.positions[context.stock].amount
                
                #print 'checking again: '+str(currentshares)    









        
        
There was a runtime error.
2 responses

Chris, I thought it would be interesting to take your algorithm and run it through the tearsheet to analyze the behavior. This is powered by Pyfolio, our open-sourced library to evaluate an algorithm.

If you want to use it in your algorithm then take the backtest ID (it's available at the top of your source code in this post) or from the URL:
https://www.quantopian.com/algorithms/algorithm_id/backtest_id

A few things that caught my eye:

  • You're right that the hedge isn't quite balanced. Take a look at this exposure chart:

  • And this causes a high beta-to-spy, reaching a value around 2.5 in the backtest

  • In 2012, the algo had a 37% drawdown. Ouch!

If you keep iterating on the algo, I'd suggest to try running your strategy through the tearsheet to monitor the behavior. If you're not familiar with it, here's a tutorial: https://www.quantopian.com/research/notebooks/Tutorials%20and%20Documentation/Tutorial%20-%20Analyzing%20Backtest%20Results.ipynb

Good luck!

Alisa

Loading notebook preview...
Disclaimer

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 Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian 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.

thanks Alisa, this gives some helpful insight. I like how Pyfolio can identify the top performers.

I created a short version of this strategy however it only performed well on the inverse ETFs but tanks otherwise. I'll keep hacking away.