Back to Community
Trending Strategy - Pls give your opinion regarding the return pattern

Breaking down into three section - entry, exit and stop loss

1) entry criteria

buy when prices break above moving average 20 and at the same time moving average 20 (mavg20) is > mavg50

sell when prices break below moving average 20 and at the same time moving average 20 (mavg20) is > mavg50

2) exit

exit when prices break below middle bollinger band for either long or short position (cut all positions)

3) stop loss

cut all position (long/short) when prices get near the (mavg 20 + mavg50)/2

Pls post your opinion on this strat, I hope this strat could be improved as Im new to algo trading (very new)

I only tried this on SPY and i hope this try it on a basket of stocks instead (would need help on this).

Thanks quantopians for your kind response and support.

Clone Algorithm
43
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
# Because this algorithm uses the history function, it will only run in minute mode. 
# We will constrain the trading to once per day at market open in this example. 

#1 import library-------------------------------------------

import talib
import numpy as np
import pandas as pd
import math

#2 Setup our variables-------------------------------------

def initialize(context):
    context.stock = symbol('SPY')
    
   # context.max_cash_per_stock = 1000.0 / len(context.stocks)
   # context.LOW_RSI = 35
   #context.HIGH_RSI = 70
   # set_long_only()

    set_commission(commission.PerTrade(cost=1.00))  
    
    # Create a variable to track the date change
    context.date = None

    
#3 execution algorithmic logic here-------------------------------

def handle_data(context, data):
    todays_date = get_datetime().date()
    
    # Do nothing unless the date has changed
    if todays_date == context.date:
        return
    # Set the new date)
    context.date = todays_date

    # cash = context.portfolio.cash
    
    # Load historical data for the stocks
    prices = history(200, '1d', 'price')
    
    # Use pandas dataframe.apply to get the last RSI value
    # for for each stock in our basket
    # rsi = prices.apply(talib.RSI, timeperiod = 14).iloc[-1]
    
#4 loop through our list of stocks-------------------------------------------

    # for stock in context.stock:
        
        
    # stop_loss = context.portfolio.positions[stock].cost_basis * 0.95
        
    # for stock in context.stocks:  
          
    #getting bollinger bands value
    upper, middle, lower = talib.BBANDS(
            prices[context.stock], 
            timeperiod=20,
            # number of non-biased standard deviations from the mean
            nbdevup=2,
            nbdevdn=2,
            # Moving average type: simple moving average here
            matype=0)
               
    mavg50 = data[context.stock].mavg(50)
    mavg200 = data[context.stock].mavg(200)
    current_position = context.portfolio.positions[context.stock].amount
        
    #cash = context.portfolio.cash
    price = data[context.stock].price
    
    close_prices = history(2, '1d', 'close_price')
    
    #if price near mavg 20 and mavg 20 > mavg 50 then buy
    #and data[context.stock].price > close_prices[context.stock][-1]
    # and data[context.stock].price < close_prices[context.stock][-1]
    
    if mavg50 > mavg200 :
        
        if data[context.stock].price <= 1.02*mavg50 and data[context.stock].price >= 0.98*mavg50 and                               data[context.stock].price > mavg50  :
            order_target_value(context.stock, 10000)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going long {3} shares at {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))
        
        elif data[context.stock].price <= 0.99*middle[-1] and current_position > 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), closing long position {3} shares at                         {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))  

        elif data[context.stock].price <= ((mavg50 + mavg200)/2) and current_position > 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping long position {1} shares at {2}'.format(
                context.stock.symbol, current_position, price
            ))
            
    elif mavg50 < mavg200 :
                
        if data[context.stock].price <= 1.02*mavg50 and data[context.stock].price >= 0.98*mavg50 and                               data[context.stock].price < mavg50 : 
            order_target_value(context.stock, -10000)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going short {3} shares at {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))
        
        elif data[context.stock].price >= 0.99*middle[-1] and current_position < 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), closing shorting position {3} shares         #                at {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))  
            
        elif data[context.stock].price >= ((mavg50 + mavg200)/2) and current_position < 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping short position {1} shares at {2}'.format(
                context.stock.symbol, current_position, price
            ))
            
            
            
            
            
        # RSI is above 70 and we own shares, time to sell
       
        #if rsi[stock] > context.HIGH_RSI and current_position > 0  :
        #    order_target(stock, 0)
        #    log.info('{0}: RSI is at {1}, selling {2} shares at {3}'.format(
        #        stock.symbol, rsi[stock], current_position, price
        #    ))            
            
           
        # elif mavg20*1.05 < mavg30 and current_position >0  :
        #    order_target(stock, 0)
        #    log.info('{0}: moving average is at {1} (5d) and {2} (30d), selling {3} shares at {4}'.format(
        #        stock.symbol, mavg20, mavg30, current_position, price
        #    ))
            

        # RSI is below 30 and we don't have any shares, time to buy
       # elif rsi[stock] < context.LOW_RSI and (cash > (price*10)) and current_position <= 10:
        #    order_value(stock,1000)
         #   log.info('{0}: RSI is at {1}, buying $1000 worth of shares at {2}. Cash is at {3}'.format(
         #       stock.symbol, rsi[stock], price, cash
         #   ))
            
        #Moving average cross component
        #elif mavg20 * 0.95 > mavg30 and (cash > (price*10)) and current_position <= 10:
        #    order_value(stock,1000)
       #     log.info('{0}: moving average is at {1} (5d) and {2} (30d), buying 1000$ worth of shares at {3}.           # Cash is at {4}'.format(
        #        stock.symbol, mavg20, mavg30,  price, cash
        #    ))

            #update bollinger band data
    record(upper=upper[-1],
                   lower=lower[-1],
                   mean=middle[-1],
                   price=price,
                   position_size=current_position)
            
#5 stop loss------------------------------------------------------

    


There was a runtime error.
7 responses

Nice algorithm. Seems to work pretty good. My suggestion is to use order_target_percent instead of value. This allows for you to earn exponentially on your positions resulting in more profit. Using the target percent order your algorithm achieved about 12% higher gain.

The algorithm performs very well except for 2011 and 2012. I'm not sure why those two years under performed.

Clone Algorithm
23
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
# Because this algorithm uses the history function, it will only run in minute mode. 
# We will constrain the trading to once per day at market open in this example. 

#1 import library-------------------------------------------

import talib
import numpy as np
import pandas as pd
import math

#2 Setup our variables-------------------------------------

def initialize(context):
    context.stock = symbol('SPY')
    
   # context.max_cash_per_stock = 1000.0 / len(context.stocks)
   # context.LOW_RSI = 35
   #context.HIGH_RSI = 70
   # set_long_only()

    set_commission(commission.PerTrade(cost=1.00))  
    
    # Create a variable to track the date change
    context.date = None

    
#3 execution algorithmic logic here-------------------------------

def handle_data(context, data):
    todays_date = get_datetime().date()
    
    # Do nothing unless the date has changed
    if todays_date == context.date:
        return
    # Set the new date)
    context.date = todays_date

    # cash = context.portfolio.cash
    
    # Load historical data for the stocks
    prices = history(200, '1d', 'price')
    
    # Use pandas dataframe.apply to get the last RSI value
    # for for each stock in our basket
    # rsi = prices.apply(talib.RSI, timeperiod = 14).iloc[-1]
    
#4 loop through our list of stocks-------------------------------------------

    # for stock in context.stock:
        
        
    # stop_loss = context.portfolio.positions[stock].cost_basis * 0.95
        
    # for stock in context.stocks:  
          
    #getting bollinger bands value
    upper, middle, lower = talib.BBANDS(
            prices[context.stock], 
            timeperiod=20,
            # number of non-biased standard deviations from the mean
            nbdevup=2,
            nbdevdn=2,
            # Moving average type: simple moving average here
            matype=0)
               
    mavg50 = data[context.stock].mavg(50)
    mavg200 = data[context.stock].mavg(200)
    current_position = context.portfolio.positions[context.stock].amount
        
    #cash = context.portfolio.cash
    price = data[context.stock].price
    
    close_prices = history(2, '1d', 'close_price')
    
    #if price near mavg 20 and mavg 20 > mavg 50 then buy
    #and data[context.stock].price > close_prices[context.stock][-1]
    # and data[context.stock].price < close_prices[context.stock][-1]
    
    if mavg50 > mavg200 :
        
        if data[context.stock].price <= 1.02*mavg50 and data[context.stock].price >= 0.98*mavg50 and                               data[context.stock].price > mavg50  :
            order_target_percent(context.stock, 1)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going long {3} shares at {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))
        
        elif data[context.stock].price <= 0.99*middle[-1] and current_position > 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), closing long position {3} shares at                         {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))  

        elif data[context.stock].price <= ((mavg50 + mavg200)/2) and current_position > 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping long position {1} shares at {2}'.format(
                context.stock.symbol, current_position, price
            ))
            
    elif mavg50 < mavg200 :
                
        if data[context.stock].price <= 1.02*mavg50 and data[context.stock].price >= 0.98*mavg50 and                               data[context.stock].price < mavg50 : 
            order_target_percent(context.stock, -1)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going short {3} shares at {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))
        
        elif data[context.stock].price >= 0.99*middle[-1] and current_position < 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), closing shorting position {3} shares         #                at {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))  
            
        elif data[context.stock].price >= ((mavg50 + mavg200)/2) and current_position < 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping short position {1} shares at {2}'.format(
                context.stock.symbol, current_position, price
            ))
            
            
            
            
            
        # RSI is above 70 and we own shares, time to sell
       
        #if rsi[stock] > context.HIGH_RSI and current_position > 0  :
        #    order_target(stock, 0)
        #    log.info('{0}: RSI is at {1}, selling {2} shares at {3}'.format(
        #        stock.symbol, rsi[stock], current_position, price
        #    ))            
            
           
        # elif mavg20*1.05 < mavg30 and current_position >0  :
        #    order_target(stock, 0)
        #    log.info('{0}: moving average is at {1} (5d) and {2} (30d), selling {3} shares at {4}'.format(
        #        stock.symbol, mavg20, mavg30, current_position, price
        #    ))
            

        # RSI is below 30 and we don't have any shares, time to buy
       # elif rsi[stock] < context.LOW_RSI and (cash > (price*10)) and current_position <= 10:
        #    order_value(stock,1000)
         #   log.info('{0}: RSI is at {1}, buying $1000 worth of shares at {2}. Cash is at {3}'.format(
         #       stock.symbol, rsi[stock], price, cash
         #   ))
            
        #Moving average cross component
        #elif mavg20 * 0.95 > mavg30 and (cash > (price*10)) and current_position <= 10:
        #    order_value(stock,1000)
       #     log.info('{0}: moving average is at {1} (5d) and {2} (30d), buying 1000$ worth of shares at {3}.           # Cash is at {4}'.format(
        #        stock.symbol, mavg20, mavg30,  price, cash
        #    ))

            #update bollinger band data
    record(upper=upper[-1],
                   lower=lower[-1],
                   mean=middle[-1],
                   price=price,
                   position_size=current_position)
            
#5 stop loss------------------------------------------------------

    


There was a runtime error.

Thanks Michael,

What's in my mind is that, this strategy will not work well or say maybe stagnant return during a sideway market (not quite sure that's the absolute good answer).

With that said, it is still possible to profit from sideway market as positions opened will be close immediately when price touches middle bollinger band, which is normally above the moving average 50 (entry price triggered for long positions).

Another thing in mind is that, I am still a beginner to algo trading.

Would anyone comment on the quality of the programming, could it be good enough to be used in a live trading environment? If not, why so.

Personally, I believe this code could be backtested with well return from the historical data perspective. But, putting it live trading would bring forth a lot of unforeseen issues.

In my mind, those issues could be:
liquidity / slicing effect / entry signal triggered could not be bought or fully filled
slippage
inconsistent price feed from broker ( possibly counterparty risk)
platform breakdown from the broker side

I cloned the algorithm and removed the commented out lines for easier reading. I also updated the moving average lines to use pandas rolling transformations instead of the built-in simple mavg transformation.

The built-in mavg function begins returning the true value only when the window is full. So for a 200-day moving average, this will begin returning the correct value on day 201. Here's a simple example to show the values for a 3-day moving average:

Day 1: report's the first day price
Day 2: report the average of the 2 day price
Day 3: report the average of the 3 day price. At the end of day 3, the moving average is now "filled" and will act as a true 3 day moving average
Day 4: Moving average of days 1-3
Day 5: Moving average of days 2-4

I can't comment on the recommendation to live trade this algo because we don't give out trading advice, but I would suggest to take a look at this thread: https://www.quantopian.com/posts/dark-side-of-technical-analysis

Looking at the backtest below, this strategy under-performed the market in 2007, hit a big position in 2008, and is riding those returns in subsequent years. If you are considering live trading an algorithm, I'd suggest to backtest it and try paper trading on Quantopian or using your IB paper account to see how it performs in the current market. Then if you're comfortable, you can choose to begin live trading.

Clone Algorithm
30
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
# Because this algorithm uses the history function, it will only run in minute mode. 
# We will constrain the trading to once per day at market open in this example. 

#1 import library-------------------------------------------

import talib
import numpy as np
import pandas as pd
import math

#2 Setup our variables-------------------------------------

def initialize(context):
    context.stock = symbol('SPY')
    #set_long_only()
    set_commission(commission.PerTrade(cost=1.00))  
    
    # Create a variable to track the date change
    context.date = None

    
#3 execution algorithmic logic here-------------------------------

def handle_data(context, data):
    todays_date = get_datetime().date()
    
    # Do nothing unless the date has changed
    if todays_date == context.date:
        return
    # Set the new date)
    context.date = todays_date
    
    # Load historical data for the stocks
    prices = history(200, '1d', 'price')
          
    #getting bollinger bands value
    upper, middle, lower = talib.BBANDS(
            prices[context.stock], 
            timeperiod=20,
            # number of non-biased standard deviations from the mean
            nbdevup=2,
            nbdevdn=2,
            # Moving average type: simple moving average here
            matype=0)
              
    mavg50 = prices[-50:].mean()
    mavg200= prices.mean()
    current_position = context.portfolio.positions[context.stock].amount
        
    price = data[context.stock].price
    
    close_prices = history(2, '1d', 'close_price')
    

    if mavg50 > mavg200 :
        if data[context.stock].price <= 1.02*mavg50 and data[context.stock].price >= 0.98*mavg50 and                               data[context.stock].price > mavg50  :
            order_target_percent(context.stock, 1)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going long {3} shares at {4}'\
                     .format(context.stock.symbol, mavg50, mavg200, current_position, price))
        
        elif data[context.stock].price <= 0.99*middle[-1] and current_position > 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), closing long position {3} shares at{4}'.format(context.stock.symbol, mavg50, mavg200, current_position, price))  

        elif data[context.stock].price <= ((mavg50 + mavg200)/2) and current_position > 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping long position {1} shares at {2}'.format(
                context.stock.symbol, current_position, price
            ))
            
    elif mavg50 < mavg200:
        if data[context.stock].price <= 1.02*mavg50 and data[context.stock].price >= 0.98*mavg50 and data[context.stock].price < mavg50: 
            order_target_percent(context.stock, -1)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going short {3} shares at {4}'\
                     .format(context.stock.symbol, mavg50, mavg200, current_position, price))
        
        elif data[context.stock].price >= 0.99*middle[-1] and current_position < 0:
            order_target_value(context.stock, 0)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), closing shorting position {3} shares # at {4}'\
                     .format(context.stock.symbol, mavg50, mavg200, current_position, price))  
            
        elif data[context.stock].price >= ((mavg50 + mavg200)/2) and current_position < 0:
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping short position {1} shares at {2}'\
                     .format(context.stock.symbol, current_position, price))
    
    # update bollinger band data
    record(upper=upper[-1],
                   lower=lower[-1],
                   mean=middle[-1],
                   cash = context.portfolio.cash,
                   #price=price,
                   position_size=current_position)
There was a runtime error.
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.

Kian,
That's a tough question, is your code good enough to trade live? I'm also pretty new to algo trading, so I don't have any wisdom for you, just my perspective. As far as the strategy goes, your guess is as good as mine, so I don't have any advice there, but I can give you my objective opinion regarding code implementation.

I saw that you're only using the middle band of talib.BBANDS. The middle Bollinger band is a 20 day moving average (as coded), so your code can be simplified to use 3 different moving averages. Do you know that you're not actually using bollinger bands? I also found a couple redundant statements, which makes it seem like there could be holes in the analysis of the underlying strategy.

For algos that depend on moving average crossovers and other boolean triggers, I would suggest starting with the math and a visualization of the possible states your algo can take on. Representing the states as a matrix of boolean variables (or nodes on a graph) can help you simplify a strategy into a clear/concise form before coding it up.

My workflow is something along these lines:
1. Research
2. Backtest, if not satisfied, go to 1.
3. paper trade, if not satisfied, go to 1, or back to 2 and adjust.
4. Trade it live, if satisfied, it goes in the strategy portfolio, else, trash it and return to 1.
5. Re-assess
6. go to 1.

I'd be careful testing strategies that short stocks through the financial crisis because there was a period of time where short sales were either not allowed, or difficult to execute. If you are the only one allowed to short, you'll probably make a killing doing it. Your algo is a good example of that effect.

If you have not checked out zipline, Quantopian's backtesting engine, I recommend you do. Working with zipline will help you understand the tools you are working with. Because we rely on software to execute strategies, it's on you to play forward possible scenarios, and incorporate those views into your software. There will always be outside influences, like liquidity/slippage, but if you know how your code behaves (and that it works), you're probably heading in the right direction. It will also be easier to identify the issues you run into. Code does exactly what it's programmed to do. That means you need to thoroughly understand what you've written, if you are satisfied with the strategy, paper trade for a while, and then send it live.

Investing is risky, we can't eliminate the risk, but if it's managed intelligently, you can learn from mistakes and have the capital to trade another day. At the end of the day, we're all more or less feeling around in the dark, experienced traders might have a candle, but it's still a dimly lit room at best. Trading stocks successfully over the long haul requires sound strategy and a sense for the market, but it's always a learning process, the trick is to stay in the game.

I'd love for somebody with more experience to weigh in on this, otherwise it's just the blind leading the blind.

David

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
# Because this algorithm uses the history function, it will only run in minute mode. 
# We will constrain the trading to once per day at market open in this example. 

#1 import library-------------------------------------------

import talib
import numpy as np
import pandas as pd
import math

#2 Setup our variables-------------------------------------

def initialize(context):
    context.stock = symbol('SPY')
    #set_long_only()
    set_commission(commission.PerTrade(cost=1.00))  
    
    # Create a variable to track the date change
    context.date = None

    
#3 execution algorithmic logic here-------------------------------

def handle_data(context, data):
    todays_date = get_datetime().date()
    # As is, this only trades on the first bar of data it receives each day.
    
    # Do nothing unless the date has changed
    if todays_date == context.date:
        return
    # Set the new date)
    context.date = todays_date
    
    # Load historical data for the stocks
    prices = history(200, '1d', 'price')
          
    #getting bollinger bands value
    upper, middle, lower = talib.BBANDS(
            prices[context.stock], 
            timeperiod=20,
            # number of non-biased standard deviations from the mean
            nbdevup=2,
            nbdevdn=2,
            # Moving average type: simple moving average here
            matype=0)
              
    mavg50 = prices[-50:].mean()
    mavg200= prices.mean()
    current_position = context.portfolio.positions[context.stock].amount
        
    price = data[context.stock].price
    
    close_prices = history(2, '1d', 'close_price')
    

    if mavg50 > mavg200 :
        # Redundant statement
        # data[context.stock].price >= 0.98*mavg50 and data[context.stock].price > mavg50
        # This is equivalent to "if price > mavg50"
        if data[context.stock].price <= 1.02*mavg50 and data[context.stock].price > mavg50:
            order_target_percent(context.stock, 1)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going long {3} shares at {4}'\
                     .format(context.stock.symbol, mavg50, mavg200, current_position, price))
        
        # middle[-1] is equivalent to using the 20 day moving average. The middle in BBANDS is a moving average
        elif data[context.stock].price <= 0.99*middle[-1] and current_position > 0:
            order_target_value(context.stock, 0)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), closing long position {3} shares at{4}'\
                     .format(context.stock.symbol, mavg50, mavg200, current_position, price))  

        elif data[context.stock].price <= ((mavg50 + mavg200) / 2) and current_position > 0:
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping long position {1} shares at {2}'.format(
                context.stock.symbol, current_position, price
            ))
            
    elif mavg50 < mavg200:
        # Redundant statement
        # data[context.stock].price <= 1.02*mavg50 and data[context.stock].price < mavg50:
        # This is equivalent to "if price < mavg50"
        if data[context.stock].price >= 0.98*mavg50 and data[context.stock].price < mavg50: 
            order_target_percent(context.stock, -1)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going short {3} shares at {4}'\
                     .format(context.stock.symbol, mavg50, mavg200, current_position, price))
        
        elif data[context.stock].price >= 0.99 * middle[-1] and current_position < 0:
            order_target_value(context.stock, 0)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), closing shorting position {3} shares # at {4}'\
                     .format(context.stock.symbol, mavg50, mavg200, current_position, price))  
            
        elif data[context.stock].price >= ((mavg50 + mavg200)/2) and current_position < 0:
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping short position {1} shares at {2}'\
                     .format(context.stock.symbol, current_position, price))
    
    # update bollinger band data
    record(upper=upper[-1],
           lower=lower[-1],
           mean=middle[-1],
           cash = context.portfolio.cash,
           # price=price,
           position_size=current_position)
There was a runtime error.

Kian,

Your strategy is well reasoned and certainly does well on that segment of SPY. So I tried it on a year-to-date segment of IWM during which that index performed badly. As you can see, I got radically different results. Possibly the fluctuations about the 0% level aren't handled well? Incidentally, SPY does very well on the same time segment. In any case, despite all the math and theorizing, this is a very, very empirical process that requires exhaustive testing against meaningful scenarios. Hope this helps?

Best regards,
Tom

Clone Algorithm
0
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
# Because this algorithm uses the history function, it will only run in minute mode. 
# We will constrain the trading to once per day at market open in this example. 

#1 import library-------------------------------------------

import talib
import numpy as np
import pandas as pd
import math

#2 Setup our variables-------------------------------------

def initialize(context):
    # context.stock = symbol('SPY')
    set_benchmark(symbol('IWM'))
    context.stock = symbol('IWM')
    # context.max_cash_per_stock = 1000.0 / len(context.stocks)
    # context.LOW_RSI = 35
    # context.HIGH_RSI = 70
    # set_long_only()
    set_commission(commission.PerTrade(cost=1.00))  
    # Create a variable to track the date change
    context.date = None

#3 execution algorithmic logic here-------------------------------

def handle_data(context, data):
    todays_date = get_datetime().date()
    # Do nothing unless the date has changed
    if todays_date == context.date:
        return
    # Set the new date)
    context.date = todays_date
    # cash = context.portfolio.cash
    # Load historical data for the stocks
    prices = history(200, '1d', 'price')
    # Use pandas dataframe.apply to get the last RSI value
    # for for each stock in our basket
    # rsi = prices.apply(talib.RSI, timeperiod = 14).iloc[-1]
    
#4 loop through our list of stocks-------------------------------------------

    # for stock in context.stock:
    # stop_loss = context.portfolio.positions[stock].cost_basis * 0.95
    # for stock in context.stocks:  
    #getting bollinger bands value
    upper, middle, lower = talib.BBANDS(
            prices[context.stock], 
            timeperiod=20,
            # number of non-biased standard deviations from the mean
            nbdevup=2,
            nbdevdn=2,
            # Moving average type: simple moving average here
            matype=0)
    mavg50 = data[context.stock].mavg(50)
    mavg200 = data[context.stock].mavg(200)
    current_position = context.portfolio.positions[context.stock].amount
    #cash = context.portfolio.cash
    price = data[context.stock].price
    # close_prices = history(2, '1d', 'close_price')
    #if price near mavg 20 and mavg 20 > mavg 50 then buy
    #and data[context.stock].price > close_prices[context.stock][-1]
    # and data[context.stock].price < close_prices[context.stock][-1]
    if mavg50 > mavg200 :
        if (data[context.stock].price <= 1.02*mavg50 and
            data[context.stock].price >= 0.98*mavg50 and
            data[context.stock].price > mavg50):
            order_target_value(context.stock, 10000)
            log.info(
                '{0}: moving average is at {1} (50d) and {2} (200d), going long {3} shares at {4}'.format(
                    context.stock.symbol, mavg50, mavg200, current_position, price
                )
            )
        elif data[context.stock].price <= 0.99*middle[-1] and current_position > 0 :
            order_target_value(context.stock, 0)
            log.info(
                '{0}: moving average is at {1} (50d) and ' + 
                '{2} (200d), closing long position {3} shares {4}'.format(                                                                                                                                context.stock.symbol, mavg50, mavg200, current_position, price
            ))  

        elif data[context.stock].price <= ((mavg50 + mavg200)/2) and current_position > 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping long position {1} shares at {2}'.format(
                context.stock.symbol, current_position, price
            ))
    elif mavg50 < mavg200 :
        if (data[context.stock].price <= 1.02*mavg50 and
            data[context.stock].price >= 0.98*mavg50 and
            data[context.stock].price < mavg50): 
            order_target_value(context.stock, -10000)
            log.info('{0}: moving average is at {1} (50d) and {2} (200d), going short {3} shares at {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))
        elif data[context.stock].price >= 0.99 * middle[-1] and current_position < 0 :
            order_target_value(context.stock, 0)
            log.info(
                '{0}: moving average is at {1} (50d) and {2} (200d), ' +
                'closing shorting position {3} shares at {4}'.format(
                context.stock.symbol, mavg50, mavg200, current_position, price
            ))  
            
        elif data[context.stock].price >= ((mavg50 + mavg200)/2) and current_position < 0 :
            order_target_value(context.stock, 0)
            log.info('{0}: Stop loss hit, stopping short position {1} shares at {2}'.format(
                context.stock.symbol, current_position, price
            ))
        # RSI is above 70 and we own shares, time to sell
        # if rsi[stock] > context.HIGH_RSI and current_position > 0  :
        #    order_target(stock, 0)
        #    log.info('{0}: RSI is at {1}, selling {2} shares at {3}'.format(
        #        stock.symbol, rsi[stock], current_position, price
        #    ))            
        # elif mavg20*1.05 < mavg30 and current_position >0  :
        #    order_target(stock, 0)
        #    log.info('{0}: moving average is at {1} (5d) and {2} (30d), selling {3} shares at {4}'.format(
        #        stock.symbol, mavg20, mavg30, current_position, price
        #    ))
        # RSI is below 30 and we don't have any shares, time to buy
        # elif rsi[stock] < context.LOW_RSI and (cash > (price*10)) and current_position <= 10:
        #    order_value(stock,1000)
        #   log.info('{0}: RSI is at {1}, buying $1000 worth of shares at {2}. Cash is at {3}'.format(
        #       stock.symbol, rsi[stock], price, cash
        #   ))
        # Moving average cross component
        # elif mavg20 * 0.95 > mavg30 and (cash > (price*10)) and current_position <= 10:
        #    order_value(stock,1000)
        #     log.info('{0}: moving average is at {1} (5d) and {2} (30d), buying 1000$ worth of shares at {3}.            # Cash is at {4}'.format(
        #        stock.symbol, mavg20, mavg30,  price, cash
        #    ))
        #update bollinger band data
    record(upper=upper[-1],
                   lower=lower[-1],
                   mean=middle[-1],
                   price=price,
                   position_size=current_position)
            
#5 stop loss------------------------------------------------------

    


There was a runtime error.

Cant comment much on the coding, but it does seem that this strategy may catch some false breakouts , hence a stagnant performance in a non trending scenario. seems like if you caught a mjor uptrend, it would bank, but many strategies would do so, the key is in the ranging time frames, "how do you take advantage of those" type thoughts.