Reputation: 221
I would like to calculate RSI 14 in line with the tradingview chart.
According to there wiki this should be the solution: https://www.tradingview.com/wiki/Talk:Relative_Strength_Index_(RSI)
I implemented this is in a object called RSI: Calling within object RSI:
self.df['rsi1'] = self.calculate_RSI_method_1(self.df, period=self.period)
Implementation of the code the calculation:
def calculate_RSI_method_1(self, ohlc: pd.DataFrame, period: int = 14) -> pd.Series:
delta = ohlc["close"].diff()
ohlc['up'] = delta.copy()
ohlc['down'] = delta.copy()
ohlc['up'] = pd.to_numeric(ohlc['up'])
ohlc['down'] = pd.to_numeric(ohlc['down'])
ohlc['up'][ohlc['up'] < 0] = 0
ohlc['down'][ohlc['down'] > 0] = 0
# This one below is not correct, but why?
ohlc['_gain'] = ohlc['up'].ewm(com=(period - 1), min_periods=period).mean()
ohlc['_loss'] = ohlc['down'].abs().ewm(com=(period - 1), min_periods=period).mean()
ohlc['RS`'] = ohlc['_gain']/ohlc['_loss']
ohlc['rsi'] = pd.Series(100 - (100 / (1 + ohlc['RS`'])))
self.currentvalue = round(self.df['rsi'].iloc[-1], 8)
print (self.currentvalue)
self.exportspreadsheetfordebugging(ohlc, 'calculate_RSI_method_1', self.symbol)
I tested several other solution like e.g but non return a good value:
https://github.com/peerchemist/finta https://gist.github.com/jmoz/1f93b264650376131ed65875782df386
Therefore I created a unittest based on : https://school.stockcharts.com/doku.php?id=technical_indicators:relative_strength_index_rsi
I created an input file: (See excel image below) and a output file: (See excel image below)
Running the unittest (unittest code not included here) should result in but is only checking the last value.
if result == 37.77295211:
log.info("Unit test 001 - PASSED")
return True
else:
log.error("Unit test 001 - NOT PASSED")
return False
But again I cannot pass the test. I checked all values by help with excel.
So now i'm a little bit lost.
If I'm following this question: Calculate RSI indicator from pandas DataFrame? But this will not give any value in the gain.
Upvotes: 5
Views: 11270
Reputation: 63
Tradingview RSI is based on Relative Moving Average. In Tradingview Relative Moving Average, aka ta.rma
defined as,
pine_rma(src, length) =>
alpha = 1/length
sum = 0.0
sum := na(sum[1]) ? ta.sma(src, length) : alpha * src + (1 - alpha) * nz(sum[1])
note that when calculating sum for the first value of the given dataset, the previous value becomes NaN because there are no data available beyond that. So the ta.rma function calculates Simple Moving Average only for that instance, but from second data point onwards, there is a value available at sum[1]
position.
So make sure to provide at least 100 datapoints to get a RSI value too close to the value given in Tradingview.
import numpy as np
import pandas as pd
from pandas import DataFrame, Series
from pandas import DataFrame, Series, isna
#tradingview ta.rma function
def rma(dataframe: DataFrame, length: int = 14):
alpha = 1.0 / length
series = dataframe['close']
for i in range(1, series.size):
if not isna(series[i - 1]):
series.iloc[i] = (series[i] * alpha) + (1 - alpha) * (series[i - 1])
else:
series.iloc[i]=(series[i]/length)
return series
#tradingview ta.sma function
def sma(dataframe: DataFrame, length: int = 14):
series = dataframe['close']
sum=0
for i in range(1, series.size):
sum = sum+(series.iloc[i]/length)
return sum
#tradingview ta.rsi function
def rsi_tradingview(ohlc: pd.DataFrame, period: int = 14, round_rsi: bool = False):
delta =ohlc['close'].diff()
delta=delta.fillna(0)
up = delta.copy()
up[up < 0] = 0
up1=pd.DataFrame(up)
up2=pd.Series(rma(up1,14))
down = delta.copy()
down[down > 0] = 0
down *= -1
down1=pd.DataFrame(down)
down2=pd.Series(rma(down1,14))
rsi = np.where(up2 == 0, 0, np.where(down2 == 0, 100, 100 - (100 / (1 + (up2 / down2)))))
return np.round(rsi, 2) if round_rsi else rsi
Here it tested providing 100 closing prices from BTCUSDT.P from BINANCE at 5min interval
array=[37027.4, 37055.4, 37051.9, 37032.5, 37018.9, 36991.6, 37010.0, 37025.7, 37015.1, 37015.6, 36996.0, 37024.7, 37034.5, 37016.9, 37011.6, 37007.0, 36981.9, 36967.5, 36969.2, 36956.4, 36949.6, 36970.0, 36969.8, 36991.6, 37012.0, 36995.7, 36998.1, 36981.5, 36957.0, 36882.1, 36918.7, 36900.2, 36885.6, 36849.4, 36842.4, 36807.0, 36766.5, 36797.5, 36838.3, 36807.7, 36784.1, 36763.9, 36739.0, 36737.8, 36795.6, 36808.0, 36849.8, 36866.1, 36938.0, 36946.6, 36952.6, 36964.0, 36938.6, 36868.0, 36897.4, 36851.1, 36863.9, 36918.0, 36878.9, 36853.0, 36849.8, 36866.9, 36855.8, 36905.4, 36897.4, 36892.4, 36920.3, 36871.9, 36863.0, 36820.1, 36777.0, 36703.8, 36744.7, 36722.0, 36812.2, 36801.5, 36783.9, 36740.3, 36779.6, 36777.6, 36788.4, 36754.0, 36774.4, 36755.1, 36835.6, 36893.2, 36871.7, 36909.5, 36902.9, 36910.8, 36963.0, 37015.0, 37045.0, 36965.1, 36911.1, 36932.3, 36914.9, 36867.1, 36891.5]
df=pd.DataFrame()
df["close"]=pd.DataFrame(array)
print(rsi_tradingview(df,14))
This is the result it gives
50.71
Upvotes: 2
Reputation: 365
Here is a Python implementation of the current RSI indicator version in TradingView:
https://github.com/lukaszbinden/rsi_tradingview/blob/main/rsi.py
Upvotes: 7
Reputation: 71
I had same issue in calculating RSI and the result was different from TradingView, I have found RSI Step 2 formula described in InvestoPedia and I changed the code as below:
N = 14
close_price0 = float(klines[0][4])
gain_avg0 = loss_avg0 = close_price0
for kline in klines[1:]:
close_price = float(kline[4])
if close_price > close_price0:
gain = close_price - close_price0
loss = 0
else:
gain = 0
loss = close_price0 - close_price
close_price0 = close_price
gain_avg = (gain_avg0 * (N - 1) + gain) / N
loss_avg = (loss_avg0 * (N - 1) + loss) / N
rsi = 100 - 100 / (1 + gain_avg / loss_avg)
gain_avg0 = gain_avg
loss_avg0 = loss_avg
N is the number of period for calculating RSI (by default = 14) the code is put in a loop to calculate all RSI values for a series.
Upvotes: 5
Reputation: 221
For those who are experience the same.
My raw data contained ticks where the volume is zero. Filtering this OLHCV rows will directly give the good results.
Upvotes: 2