Why does the bar_count in data.history affect my RSI calculation using TA-Lib?

Good evening,

I noticed that my RSI calculation (and therefore my RSI EWMA calculation) are different depending on what I set the bar_count to when I grab historical pricing for a security. The start and end dates, and RSI window_length are kept the same in my comparison.

Can someone please explain to me why this is happening? Referring to the following article on the unstable period for a TA calculation enter link description here, it appears that regardless of the data used to calculate a technical indicator, 34 price bars are stripped off the price history in order to assure the same result is always calculated.

RSI value on July 19, 2016 for 30 days of price history = 41.36
RSI value on July 19, 2016 for 60 days of price history = 43.64
RSI value on July 19, 2016 for 90 days of price history = 43.69

Any help would be greatly appreciated.

Thanks,

Brian

571
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
"""
This algorithm calculates the Relative Strength Index (RSI) for one stock over
a specified window length. The mean and weighted mean (exponential moving average)
are calculated. The weighted mean is compared with the actual RSI value of the stock
to determine when a RSI crossover occurs.
"""

import numpy as np
import pandas as pd
import talib

# Setup our variables
def initialize(context):
context.stock = sid(18196) # stock that I want to backtest
context.LOW_RSI = 30
context.HIGH_RSI = 70

# Rebalance every day, 30 minutes after market open on Monday.
schedule_function(my_rebalance,
date_rules.every_day(),
time_rules.market_open(minutes=30))

# Record tracking variables at the end of each day.
schedule_function(my_record_vars,
date_rules.every_day(),
time_rules.market_close())

def my_rebalance(context, data):
# Window length
window = 9

# Load historical data for the stock (returns a Series)
hist = data.history(context.stock, 'price', 30, '1d')

'''
Why does the length of price history affect our RSI calculation?
'''

# Calculate RSI moving average
rsi = talib.RSI(hist, timeperiod=window) # returns a numpy array
context.rsi_current = rsi[-1] # Get most recent RSI of the stock
context.rsi_mean = np.nanmean(rsi)

# Calculate RSI EWMA
center_of_mass = (window - 1) / 2
context.rsi_ewma = pd.ewma(rsi, com=center_of_mass, ignore_na=True)[-1]

# Calculate rsi moving average crossover with weighted average
rsi_crossover = context.rsi_current - context.rsi_ewma

# Grab portfolio information
current_position = context.portfolio.positions[context.stock].amount
cash = context.portfolio.cash

# RSI > RSI_mean (long position)
if rsi_crossover > 0 and data.can_trade(context.stock):
target_shares = cash // data.current(context.stock, 'price')
order_target_percent(context.stock, 1)
log.info("Cash available: {}".format(cash))
log.info("{0}: RSI is at {1} and RSI mean at {2}, buying {3} shares".format(context.stock.symbol,                                                                                  context.rsi_current,                                                                                    context.rsi_ewma,                                                                                      target_shares))
# RSI < RSI_mean (short position)
elif rsi_crossover < 0 and data.can_trade(context.stock):
target_shares = cash // data.current(context.stock, 'price')
order_target_percent(context.stock, -1)
log.info("Cash available: {}".format(cash))
log.info("{0}: RSI is at {1} and RSI mean at {2}, selling {3} shares".format(context.stock.symbol,                                                                                  context.rsi_current,                                                                                    context.rsi_ewma,                                                                                      target_shares))

def my_record_vars(context, data):
"""
Plot variables at the end of each day.
"""

record(
stock_rsi=context.rsi_current,
stock_rsi_ewma=context.rsi_ewma,
)
There was a runtime error.
5 responses

This may be due to the EWMA code. EWMA will use all data points in the series, so providing the RSI variable, which is in itself a rolling set of RSIs at different time periods if I'm reading this correctly, will change the result of the EWMA computation. Does this make sense? I wouldn't think RSI[-1] would change.

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 Delaney,

I understand why the EWMA value changes since it is calculating the weighted average of the rolling set of RSIs based on the window length. However, the RSI[-1] value is changing which is concerning me since that value should be the same regardless of how much historical data I am using in the calculation (as long the historical data is longer than the window length).

If you run the code you will see what I'm talking about. Any further explanation would be great since I can not use this RSI calculation unless it appears to be correct.

I've cross-checked using the RSI function from TA-Lib in a separate script that pulls Yahoo Finance data and calculated the exact same RSI value as Yahoo Finance.

Any further help is much appreciated.

Thanks again,

Brian

@Brian, this difference in value as a result of window length is definitely something that shows up in TA-Lib functions. I have always found that if you give them a large enough window_length they usually calm down and converge to a single number. If you want to use TA-Lib functions on the platform, check out this notebook (https://www.quantopian.com/posts/ta-lib-for-pipeline) which contains some TA-Lib functions constructed as Pipeline factors.

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.

@Gil, the problem is not the window_length of the RSI talib function. The problem is that the RSI values change depending on how much historical data I am using. If I change the number of historical data points in the data.history function below, my RSI values are substantially different.

data.history(context.stock, 'price', **30**, '1d')

Like I said, writing a script outside of Quantopian that pulls Yahoo Finance data and calculates the RSIs are the values I am seeing on all other finance websites, irrespective of the start and end dates.

@Brian, window_length is the Pipeline equivalent of number of historical bars, I was thinking in Pipeline as opposed to data.history.

If you look at the TA-Lib docs, you'll see that they reference a particular formula that depends on 'n' -the number of data-points (http://www.fmlabs.com/reference/default.htm?url=RSI.htm is the link they give). This is why RSI changes when it is passed a different number of historical data-points. I would find out the conventions that other finance websites use for calculating RSI and match your data.history length to them.