Relative Strength Index in python pandas

前端 未结 12 1418
生来不讨喜
生来不讨喜 2020-12-07 17:29

I am new to pandas. What is the best way to calculate the relative strength part in the RSI indicator in pandas? So far I got the following:

from pylab impor         


        
相关标签:
12条回答
  • 2020-12-07 18:02

    You can use rolling_apply in combination with a subfunction to make a clean function like this:

    def rsi(price, n=14):
        ''' rsi indicator '''
        gain = (price-price.shift(1)).fillna(0) # calculate price gain with previous day, first row nan is filled with 0
    
        def rsiCalc(p):
            # subfunction for calculating rsi for one lookback period
            avgGain = p[p>0].sum()/n
            avgLoss = -p[p<0].sum()/n 
            rs = avgGain/avgLoss
            return 100 - 100/(1+rs)
    
        # run for all periods with rolling_apply
        return pd.rolling_apply(gain,n,rsiCalc) 
    
    0 讨论(0)
  • 2020-12-07 18:02
    rsi_Indictor(close,n_days):
        rsi_series = pd.DataFrame(close)
    
    
        # Change = close[i]-Change[i-1]
        rsi_series["Change"] = (rsi_series["Close"] - rsi_series["Close"].shift(1)).fillna(0)
    
        # Upword Movement
        rsi_series["Upword Movement"] = (rsi_series["Change"][rsi_series["Change"] >0])
        rsi_series["Upword Movement"] = rsi_series["Upword Movement"].fillna(0)
    
        # Downword Movement
        rsi_series["Downword Movement"] = (abs(rsi_series["Change"])[rsi_series["Change"] <0]).fillna(0)
        rsi_series["Downword Movement"] = rsi_series["Downword Movement"].fillna(0)
    
        #Average Upword Movement
        # For first Upword Movement Mean of first n elements.
        rsi_series["Average Upword Movement"] = 0.00
        rsi_series["Average Upword Movement"][n] = rsi_series["Upword Movement"][1:n+1].mean()
    
        # For Second onwords
        for i in range(n+1,len(rsi_series),1):
            #print(rsi_series["Average Upword Movement"][i-1],rsi_series["Upword Movement"][i])
            rsi_series["Average Upword Movement"][i] = (rsi_series["Average Upword Movement"][i-1]*(n-1)+rsi_series["Upword Movement"][i])/n
    
        #Average Downword Movement
        # For first Downword Movement Mean of first n elements.
        rsi_series["Average Downword Movement"] = 0.00
        rsi_series["Average Downword Movement"][n] = rsi_series["Downword Movement"][1:n+1].mean()
    
        # For Second onwords
        for i in range(n+1,len(rsi_series),1):
            #print(rsi_series["Average Downword Movement"][i-1],rsi_series["Downword Movement"][i])
            rsi_series["Average Downword Movement"][i] = (rsi_series["Average Downword Movement"][i-1]*(n-1)+rsi_series["Downword Movement"][i])/n
    
        #Relative Index
        rsi_series["Relative Strength"] = (rsi_series["Average Upword Movement"]/rsi_series["Average Downword Movement"]).fillna(0)
    
        #RSI
        rsi_series["RSI"] = 100 - 100/(rsi_series["Relative Strength"]+1)
        return rsi_series.round(2)     
    

    For More Information

    0 讨论(0)
  • 2020-12-07 18:02

    It is not really necessary to calculate the mean, because after they are divided, you only need to calculate the sum, so we can use Series.cumsum ...

    def rsi(serie, n):
    
        diff_serie = close.diff()
        cumsum_incr = diff_serie.where(lambda x: x.gt(0), 0).cumsum()
        cumsum_decr = diff_serie.where(lambda x: x.lt(0), 0).abs().cumsum()
        rs_serie = cumsum_incr.div(cumsum_decr)
        rsi = rs_serie.mul(100).div(rs_serie.add(1)).fillna(0)
    
        return rsi
    
    0 讨论(0)
  • 2020-12-07 18:05
    # Relative Strength Index
    # Avg(PriceUp)/(Avg(PriceUP)+Avg(PriceDown)*100
    # Where: PriceUp(t)=1*(Price(t)-Price(t-1)){Price(t)- Price(t-1)>0};
    #        PriceDown(t)=-1*(Price(t)-Price(t-1)){Price(t)- Price(t-1)<0};
    # Change the formula for your own requirement
    def rsi(values):
        up = values[values>0].mean()
        down = -1*values[values<0].mean()
        return 100 * up / (up + down)
    
    stock['RSI_6D'] = stock['Momentum_1D'].rolling(center=False,window=6).apply(rsi)
    stock['RSI_12D'] = stock['Momentum_1D'].rolling(center=False,window=12).apply(rsi)
    

    Momentum_1D = Pt - P(t-1) where P is closing price and t is date

    0 讨论(0)
  • 2020-12-07 18:08

    My answer is tested on StockCharts sample data.

    [StockChart RSI info][1]http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:relative_strength_index_rsi

    def RSI(series, period):
        delta = series.diff().dropna()
        u = delta * 0
        d = u.copy()
        u[delta > 0] = delta[delta > 0]
        d[delta < 0] = -delta[delta < 0]
        u[u.index[period-1]] = np.mean( u[:period] ) #first value is sum of avg gains
        u = u.drop(u.index[:(period-1)])
        d[d.index[period-1]] = np.mean( d[:period] ) #first value is sum of avg losses
        d = d.drop(d.index[:(period-1)])
        rs = pd.stats.moments.ewma(u, com=period-1, adjust=False) / \
             pd.stats.moments.ewma(d, com=period-1, adjust=False)
        return 100 - 100 / (1 + rs)
    
    
    #sample data from StockCharts
    data = pd.Series( [ 44.34, 44.09, 44.15, 43.61,
                        44.33, 44.83, 45.10, 45.42,
                        45.84, 46.08, 45.89, 46.03,
                        45.61, 46.28, 46.28, 46.00,
                        46.03, 46.41, 46.22, 45.64 ] )
    print RSI( data, 14 )
    
    #output
    14    70.464135
    15    66.249619
    16    66.480942
    17    69.346853
    18    66.294713
    19    57.915021
    
    0 讨论(0)
  • 2020-12-07 18:08

    I too had this question and was working down the rolling_apply path that Jev took. However, when I tested my results, they didn't match up against the commercial stock charting programs I use, such as StockCharts.com or thinkorswim. So I did some digging and discovered that when Welles Wilder created the RSI, he used a smoothing technique now referred to as Wilder Smoothing. The commercial services above use Wilder Smoothing rather than a simple moving average to calculate the average gains and losses.

    I'm new to Python (and Pandas), so I'm wondering if there's some brilliant way to refactor out the for loop below to make it faster. Maybe someone else can comment on that possibility.

    I hope you find this useful.

    More info here.

    def get_rsi_timeseries(prices, n=14):
        # RSI = 100 - (100 / (1 + RS))
        # where RS = (Wilder-smoothed n-period average of gains / Wilder-smoothed n-period average of -losses)
        # Note that losses above should be positive values
        # Wilder-smoothing = ((previous smoothed avg * (n-1)) + current value to average) / n
        # For the very first "previous smoothed avg" (aka the seed value), we start with a straight average.
        # Therefore, our first RSI value will be for the n+2nd period:
        #     0: first delta is nan
        #     1:
        #     ...
        #     n: lookback period for first Wilder smoothing seed value
        #     n+1: first RSI
    
        # First, calculate the gain or loss from one price to the next. The first value is nan so replace with 0.
        deltas = (prices-prices.shift(1)).fillna(0)
    
        # Calculate the straight average seed values.
        # The first delta is always zero, so we will use a slice of the first n deltas starting at 1,
        # and filter only deltas > 0 to get gains and deltas < 0 to get losses
        avg_of_gains = deltas[1:n+1][deltas > 0].sum() / n
        avg_of_losses = -deltas[1:n+1][deltas < 0].sum() / n
    
        # Set up pd.Series container for RSI values
        rsi_series = pd.Series(0.0, deltas.index)
    
        # Now calculate RSI using the Wilder smoothing method, starting with n+1 delta.
        up = lambda x: x if x > 0 else 0
        down = lambda x: -x if x < 0 else 0
        i = n+1
        for d in deltas[n+1:]:
            avg_of_gains = ((avg_of_gains * (n-1)) + up(d)) / n
            avg_of_losses = ((avg_of_losses * (n-1)) + down(d)) / n
            if avg_of_losses != 0:
                rs = avg_of_gains / avg_of_losses
                rsi_series[i] = 100 - (100 / (1 + rs))
            else:
                rsi_series[i] = 100
            i += 1
    
        return rsi_series
    
    0 讨论(0)
提交回复
热议问题