Back to Community
Simple Pipleline RSI Example - Beginner Question

Hello all:

I apologize for being such a raw beginner at this, but the code used in Quantopian seems to be changing quite quickly and as a beginner it is challenging to keep up. I have experience with FORTRAN, BASIC, and C as well as NinjaTrader and MetaTrader. I know more about the stock market than I do computers though. I see the power of the Pipeline API; it allows for automation not possible with other the above systems.

By watching this video: https://www.youtube.com/watch?v=BLJHuFGjBDg

I was able to put together a Pipeline screen that assembles a nice list of about 10 stocks with high EPS growth, profit margins, and market cap, as well as low debt.

I would like to buy the top ten stocks I produce in my Pipeline screen with 8% stop-losses and 25% profit targets if the RSI of the SPY falls below 30 and move the entire portfolio to cash if the RSI of the SPY rises above 70.

I found this RSI example that works well, but it only works with three coded stocks. I don't understand how to refer to the Pipeline I have created in the for loop that buys when the SPY RSI is below 30. https://www.quantopian.com/posts/simple-system

In the YouTube video the for loops reads:

for stock in context. top500.index:

In the Quantopian RSI example, with only the three coded stocks and no pipeline, the for loop reads:

for stock in context.stocks:

It appears to me that the method used in the YouTube video may be outdated, as I get runtime errors that direct me to this link:
https://www.quantopian.com/quantopian2/migration#data-history

Here is my code that is successfully building a nice looking list of stocks using Pipeline:

An algorithm that uses Pipeline to screen the ten $15+ stocks with highest EPS growth among those with debt near zero, market cap above $5 billion, and profit margins above 20%.

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar

def initialize(context):
# Create and attach an empty Pipeline.
pipe = Pipeline()
attach_pipeline(pipe,'universe')

# Get EPS growth.  
revenuegrowth = morningstar.earnings_ratios.diluted_eps_growth.latest  
pipe.add(revenuegrowth, 'revenuegrowth')  

# Get market cap.  
marketcap = morningstar.valuation.market_cap.latest  
pipe.add (marketcap, 'marketcap')  

# Get debt to equity ratio.  
debt = morningstar.operation_ratios.long_term_debt_equity_ratio.latest  
pipe.add (debt, 'debt')  

# Get price.  
price = USEquityPricing.close.latest  
pipe.add(price, 'price')  

# Get profit margin.  
profitmargin = morningstar.operation_ratios.normalized_net_profit_margin.latest  
pipe.add (profitmargin, 'profitmargin')  

# Screen for min $5B market cap, 25 EPS growth, no debt, $15+, 20%+ profit margin companies.  
pipe.set_screen((marketcap > 5000000000) & (revenuegrowth > 0.25) & (debt < 0.05) & (price > 15) & (profitmargin > 0.20))  

def before_trading_start(context, data):
context.output = pipeline_output('universe')
universe = context.output.fillna(0)

universe['sid'] = universe.index  
universe['symbol'] = universe.sid.apply(lambda x: x.symbol)  
universe = universe[universe.symbol.apply(lambda x: not x.endswith('_WI'))]  

log.info(context.output.head(10))

Here is how I have attempted to integrate the sample RSI algorithm to buy the list of stocks created in my Pipeline when the RSI of the SPY falls below 30 and sell when it rises above 70. I haven't progressed to the point adding stop-losses and profit targets yet.

An algorithm that buys the ten $15+ stocks with highest EPS growth among those with

debt near zero, market cap above $5 billion, and profit margins above 20%.

import talib

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar

def initialize(context):
# From 'Practice RSI Example'
context.stocks = symbols('SPY')
context.max_cash_per_stock = 100000.0 / len(context.stocks)
context.LOW_RSI = 30
context.HIGH_RSI = 70
# Create a variable to track the date change
context.date = None
# End 'Practice RSI Example' code

# Create and attach an empty Pipeline.  
pipe = Pipeline()  
attach_pipeline(pipe,'universe')  

# Get EPS growth.  
revenuegrowth = morningstar.earnings_ratios.diluted_eps_growth.latest  
pipe.add(revenuegrowth, 'revenuegrowth')  

# Get market cap.  
marketcap = morningstar.valuation.market_cap.latest  
pipe.add (marketcap, 'marketcap')  

# Get debt to equity ratio.  
debt = morningstar.operation_ratios.long_term_debt_equity_ratio.latest  
pipe.add (debt, 'debt')  

# Get price.  
price = USEquityPricing.close.latest  
pipe.add(price, 'price')  

# Get profit margin.  
profitmargin = morningstar.operation_ratios.normalized_net_profit_margin.latest  
pipe.add (profitmargin, 'profitmargin')  

# Screen for min $5B market cap, 25 EPS growth, no debt, $15+, 20%+ profit margin companies.  
pipe.set_screen((marketcap > 5000000000) & (revenuegrowth > 0.25) & (debt < 0.05) & (price > 15) & (profitmargin > 0.20))  

def before_trading_start(context, data):
context.output = pipeline_output('universe')
universe = context.output.fillna(0)

universe['sid'] = universe.index  
universe['symbol'] = universe.sid.apply(lambda x: x.symbol)  
universe = universe[universe.symbol.apply(lambda x: not x.endswith('_WI'))]  

log.info(context.output.head(10))  

# From 'Practice RSI Example'  

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(15, '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]  
# Loop through our list of stocks  

#Baffled by correct way to refer to the list of stocks created in Pipeline in this for loop.  
for stock in context.universe.index:  
    current_position = context.portfolio.positions[stock].amount  
    # RSI is above 70 and we own shares, time to sell  
    if rsi[sid(8554)] > context.HIGH_RSI and current_position > 0:  
        order_target(stock, 0)  
        log.info('{0}: RSI is at {1}, selling {2} shares'.format(  
            stock.symbol, rsi[sid(8554)], current_position  
        ))  
    # RSI is below 30 and we don't have any shares, time to buy  
    elif rsi[sid(8554)] < context.LOW_RSI and current_position == 0:  
        # Use floor division to get a whole number of shares  
        target_shares = cash // data[stock].price  
        order_target(stock, target_shares)  
        log.info('{0}: RSI is at {1}, buying {2} shares.'.format(  
            stock.symbol, rsi[sid(8554)], target_shares  
        ))

# record the current RSI values of each stock  
record(spy_rsi=rsi[symbol('SPY')])  
# End 'Practice RSI Example' code

Can anyone help me? Being able to get this one under my belt would give me the tools I need to learn more. I would be forever grateful. Thanks so much!

5 responses

Hi Stephen,

Welcome to Quantopian!
I'd be happy to help you debug your code, but it's a little hard to read.
Would you be able to comment out the problem spots and post a full backtest here?
(it allows other community members to clone and work on your algorithm)

Thanks,
Lotanna Ezenwa

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.

Hi Lotanna,

Thanks so much. I really appreciate it. I have included my code that isn't working. I believe the problem is in the for loop that begins on line 76. It seems that it is done differently in the YouTube video and the RSI example. I have a version of the code with just the Pipeline that is producing a nice list of stocks.

Thanks again Lotanna!

Clone Algorithm
14
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
# An algorithim that buys the ten $15+ stocks with highest EPS growth among those with 
# debt near zero, market cap above $5 billion, and profit margins above 20%.

import talib

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar

def initialize(context):
    # From 'Practice RSI Example'
    context.stocks = symbols('SPY')  
    context.max_cash_per_stock = 100000.0 / len(context.stocks)  
    context.LOW_RSI = 30  
    context.HIGH_RSI = 70  
    # Create a variable to track the date change  
    context.date = None
    # End 'Practice RSI Example'

    # Create and attach an empty Pipeline.
    pipe = Pipeline()
    attach_pipeline(pipe,'universe')
     
    # Get EPS growth.
    revenuegrowth = morningstar.earnings_ratios.diluted_eps_growth.latest
    pipe.add(revenuegrowth, 'revenuegrowth')
    
    # Get market cap.
    marketcap = morningstar.valuation.market_cap.latest
    pipe.add (marketcap, 'marketcap')
    
    # Get debt to equity ratio.
    debt = morningstar.operation_ratios.long_term_debt_equity_ratio.latest
    pipe.add (debt, 'debt')
    
    # Get price. 
    price = USEquityPricing.close.latest
    pipe.add(price, 'price')
    
    # Get profit margin.
    profitmargin = morningstar.operation_ratios.normalized_net_profit_margin.latest
    pipe.add (profitmargin, 'profitmargin')
    
    # Screen for min $5B market cap, 25 EPS growth, no debt, $15+, 20%+ profit margin companies.
    pipe.set_screen((marketcap > 5000000000) & (revenuegrowth > 0.25) & (debt < 0.05) & (price > 15) & (profitmargin > 0.20))
                
def before_trading_start(context, data):
    context.output = pipeline_output('universe') 
    universe = context.output.fillna(0)
    
    universe['sid'] = universe.index
    universe['symbol'] = universe.sid.apply(lambda x: x.symbol)
    universe = universe[universe.symbol.apply(lambda x: not x.endswith('_WI'))]
  
    log.info(context.output.head(10))                           
    
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(15, '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]  
    # Loop through our list of stocks 
    
    #Baffled by correct way to refer to the list of stocks created in the pipeline in this for loop.
    for stock in context.universe.index:  
        current_position = context.portfolio.positions[stock].amount  
        # RSI is above 70 and we own shares, time to sell  
        if rsi[sid(8554)] > context.HIGH_RSI and current_position > 0:  
            order_target(stock, 0)  
            log.info('{0}: RSI is at {1}, selling {2} shares'.format(  
                stock.symbol, rsi[sid(8554)], current_position  
            ))  
        # RSI is below 30 and we don't have any shares, time to buy  
        elif rsi[sid(8554)] < context.LOW_RSI and current_position == 0:  
            # Use floor division to get a whole number of shares  
            target_shares = cash // data[stock].price  
            order_target(stock, target_shares)  
            log.info('{0}: RSI is at {1}, buying {2} shares.'.format(  
                stock.symbol, rsi[sid(8554)], target_shares  
            ))

    # record the current RSI values of each stock  
    record(spy_rsi=rsi[symbol('SPY')])
                         
                                 
  
There was a runtime error.

This is my code to select stocks in the pipeline that seems to work well. An example of how to rank the stocks in the pipeline by EPS growth, limit the list to no more than ten names, and allocate ten percent of the portfolio to each of them, without the RSI consideration, would really help me. I don't understand how to refer to the stocks in the pipeline when placing orders.

Clone Algorithm
13
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
# An algorithm that uses Pipeline to screen the ten $15+ stocks with highest EPS growth # among those with debt near zero, market cap above $5 billion, and profit margins above # 20%.

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar

def initialize(context):

    # Create and attach an empty Pipeline.
    pipe = Pipeline()
    attach_pipeline(pipe,'universe')
     
    # Get EPS growth.
    revenuegrowth = morningstar.earnings_ratios.diluted_eps_growth.latest
    pipe.add(revenuegrowth, 'revenuegrowth')
    
    # Get market cap.
    marketcap = morningstar.valuation.market_cap.latest
    pipe.add (marketcap, 'marketcap')
    
    # Get debt to equity ratio.
    debt = morningstar.operation_ratios.long_term_debt_equity_ratio.latest
    pipe.add (debt, 'debt')
    
    # Get price. 
    price = USEquityPricing.close.latest
    pipe.add(price, 'price')
    
    # Get profit margin.
    profitmargin = morningstar.operation_ratios.normalized_net_profit_margin.latest
    pipe.add (profitmargin, 'profitmargin')
    
    # Screen for min $5B market cap, 25 EPS growth, no debt, $15+, 20%+ profit margin companies.
    pipe.set_screen((marketcap > 5000000000) & (revenuegrowth > 0.25) & (debt < 0.05) & (price > 15) & (profitmargin > 0.20))
                
def before_trading_start(context, data):
    context.output = pipeline_output('universe') 
    universe = context.output.fillna(0)
    
    universe['sid'] = universe.index
    universe['symbol'] = universe.sid.apply(lambda x: x.symbol)
    universe = universe[universe.symbol.apply(lambda x: not x.endswith('_WI'))]
  
    log.info(context.output.head(10))                           
There was a runtime error.

Took a look and I was able to debug it. I changed up the handle_data function to a separate function, and scheduled it using schedule_function.

I also removed some universe functions that were sorting everything, but this first backtest just shows indexing using pandas.

It looks like you have a general understanding of how Quantopian works, but you might consider taking a look at the pipeline tutorial and pandas documentation for direction on indexing and efficient methodology. Pipeline also has Factor and Classifier classes that will allow you to rank different values against each other. There's a short summary in the API documentation about this also.

Clone Algorithm
67
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
# An algorithim that buys the ten $15+ stocks with highest EPS growth among those with 
# debt near zero, market cap above $5 billion, and profit margins above 20%.

import talib

from quantopian.algorithm import attach_pipeline, pipeline_output
from quantopian.pipeline import Pipeline
from quantopian.pipeline import CustomFactor
from quantopian.pipeline.data.builtin import USEquityPricing
from quantopian.pipeline.data import morningstar

def initialize(context):
    # From 'Practice RSI Example'
    context.stocks = symbols('SPY')  
    context.max_cash_per_stock = 100000.0 / len(context.stocks)  
    context.LOW_RSI = 30  
    context.HIGH_RSI = 70  
    # Create a variable to track the date change  
    context.date = None
    # End 'Practice RSI Example'

    # Create and attach an empty Pipeline.
    pipe = Pipeline()
    attach_pipeline(pipe,'universe')
     
    # Get EPS growth.
    revenuegrowth = morningstar.earnings_ratios.diluted_eps_growth.latest
    pipe.add(revenuegrowth, 'revenuegrowth')
    
    # Get market cap.
    marketcap = morningstar.valuation.market_cap.latest
    pipe.add (marketcap, 'marketcap')
    
    # Get debt to equity ratio.
    debt = morningstar.operation_ratios.long_term_debt_equity_ratio.latest
    pipe.add (debt, 'debt')
    
    # Get price. 
    price = USEquityPricing.close.latest
    pipe.add(price, 'price')
    
    # Get profit margin.
    profitmargin = morningstar.operation_ratios.normalized_net_profit_margin.latest
    pipe.add (profitmargin, 'profitmargin')
    
    # Screen for min $5B market cap, 25 EPS growth, no debt, $15+, 20%+ profit margin companies.
    pipe.set_screen((marketcap > 5000000000) & (revenuegrowth > 0.25) & (debt < 0.05) & (price > 15) & (profitmargin > 0.20))
    
    schedule_function(my_func,date_rules.every_day(),time_rules.market_open())
                
def before_trading_start(context, data):
    context.output = pipeline_output('universe') 
    context.universe = context.output.index
  
    log.info(context.output.head(10))                           
    
def my_func(context, data):  

    cash = context.portfolio.cash  
    # Load historical data for the stocks  
    prices = data.history(context.universe,'price', 15, '1d')
    
    # 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]  
    # Loop through our list of stocks 
    
    #Baffled by correct way to refer to the list of stocks created in the pipeline in this for loop.
    for stock in context.universe:
        
        current_position = context.portfolio.positions[stock].amount  
        # 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'.format(  
                stock.symbol, rsi[stock], current_position  
            ))  
        # RSI is below 30 and we don't have any shares, time to buy  
        elif rsi[stock] < context.LOW_RSI and current_position == 0:  
            # Use floor division to get a whole number of shares  
            target_shares = cash // data.current(stock,'price')  
            order_target(stock, target_shares)  
            log.info('{0}: RSI is at {1}, buying {2} shares.'.format(  
                stock.symbol, rsi[stock], target_shares  
            ))

    # record the current RSI values of each stock  
                         
                                 
  
There was a runtime error.

Thank you so much for your help sir! This gives me something to work with and build on. I'm going to study the resources you mentioned as well. Have a great day and keep up the great work! :-)