Índice de fuerza relativa en pandas python

Soy nuevo en pandas. ¿Cuál es la mejor manera de calcular la parte de fuerza relativa en el indicador RSI en pandas? Hasta ahora he conseguido lo siguiente:

from pylab import * import pandas as pd import numpy as np def Datapull(Stock): try: df = (pd.io.data.DataReader(Stock,'yahoo',start='01/01/2010')) return df print 'Retrieved', Stock time.sleep(5) except Exception, e: print 'Main Loop', str(e) def RSIfun(price, n=14): delta = price['Close'].diff() #----------- dUp= dDown= RolUp=pd.rolling_mean(dUp, n) RolDown=pd.rolling_mean(dDown, n).abs() RS = RolUp / RolDown rsi= 100.0 - (100.0 / (1.0 + RS)) return rsi Stock='AAPL' df=Datapull(Stock) RSIfun(df) 

¿Lo estoy haciendo correctamente hasta ahora? Tengo problemas con la parte de diferencia de la ecuación en la que se separan los cálculos ascendentes y descendentes

 dUp= delta[delta > 0] dDown= delta[delta < 0] 

También necesitas algo como:

 RolUp = RolUp.reindex_like(delta, method='ffill') RolDown = RolDown.reindex_like(delta, method='ffill') 

de lo contrario, RS = RolUp / RolDown no hará lo que usted desea

Editar: parece que esta es una forma más precisa de cálculo RS:

 # dUp= delta[delta > 0] # dDown= delta[delta < 0] # dUp = dUp.reindex_like(delta, fill_value=0) # dDown = dDown.reindex_like(delta, fill_value=0) dUp, dDown = delta.copy(), delta.copy() dUp[dUp < 0] = 0 dDown[dDown > 0] = 0 RolUp = pd.rolling_mean(dUp, n) RolDown = pd.rolling_mean(dDown, n).abs() RS = RolUp / RolDown 

Es importante tener en cuenta que hay varias formas de definir el RSI. Por lo general, se define de al menos dos formas: usando un promedio móvil simple (SMA) como se indica arriba, o usando un promedio móvil exponencial (EMA). Aquí hay un fragmento de código que calcula ambas definiciones de RSI y las grafica para compararlas. Estoy descartando la primera fila después de tomar la diferencia, ya que siempre es NaN por definición.

Tenga en cuenta que cuando use EMA, debe tener cuidado: ya que incluye una memoria que se remonta al principio de los datos, ¡el resultado depende de dónde comience! Por esta razón, normalmente las personas agregarán algunos datos al principio, digamos 100 pasos de tiempo, y luego cortarán los primeros 100 valores RSI.

En la gráfica a continuación, se puede ver la diferencia entre el RSI calculado utilizando SMA y EMA: el SMA tiende a ser más sensible. Tenga en cuenta que el RSI basado en EMA tiene su primer valor finito en el primer paso (que es el segundo paso del período original, debido a descartar la primera fila), mientras que el RSI basado en SMA tiene su primer valor finito en el Paso 14 de tiempo. Esto se debe a que, de forma predeterminada, rolling_mean () solo devuelve un valor finito una vez que hay suficientes valores para llenar la ventana.

Una comparación del RSI calculado utilizando un promedio móvil exponencial o simple

 import pandas import pandas.io.data import datetime import matplotlib.pyplot as plt # Window length for moving average window_length = 14 # Dates start = datetime.datetime(2010, 1, 1) end = datetime.datetime(2013, 1, 27) # Get data data = pandas.io.data.DataReader('AAPL', 'yahoo', start, end) # Get just the close close = data['Adj Close'] # Get the difference in price from previous step delta = close.diff() # Get rid of the first row, which is NaN since it did not have a previous # row to calculate the differences delta = delta[1:] # Make the positive gains (up) and negative gains (down) Series up, down = delta.copy(), delta.copy() up[up < 0] = 0 down[down > 0] = 0 # Calculate the EWMA roll_up1 = pandas.stats.moments.ewma(up, window_length) roll_down1 = pandas.stats.moments.ewma(down.abs(), window_length) # Calculate the RSI based on EWMA RS1 = roll_up1 / roll_down1 RSI1 = 100.0 - (100.0 / (1.0 + RS1)) # Calculate the SMA roll_up2 = pandas.rolling_mean(up, window_length) roll_down2 = pandas.rolling_mean(down.abs(), window_length) # Calculate the RSI based on SMA RS2 = roll_up2 / roll_down2 RSI2 = 100.0 - (100.0 / (1.0 + RS2)) # Compare graphically plt.figure() RSI1.plot() RSI2.plot() plt.legend(['RSI via EWMA', 'RSI via SMA']) plt.show() 

Mi respuesta se prueba en los datos de muestra de StockCharts.

[Información sobre el RSI de StockChart] [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 

Yo también tenía esta pregunta y estaba trabajando en el camino de enrollado que Jev tomó. Sin embargo, cuando probé mis resultados, no coincidían con los progtwigs comerciales de gráficos de acciones que utilizo, como StockCharts.com o thinkorswim. Así que hice algunas excavaciones y descubrí que cuando Welles Wilder creó el RSI, usó una técnica de suavizado que ahora se conoce como Wilder Smoothing. Los servicios comerciales anteriores utilizan Wilder Smoothing en lugar de un simple promedio móvil para calcular las ganancias y pérdidas promedio.

Soy nuevo en Python (y Pandas), así que me pregunto si hay alguna manera shiny de refactorizar el bucle for para hacerlo más rápido. Tal vez alguien más pueda comentar sobre esa posibilidad.

Espero que encuentres esto útil.

Más información aquí .

 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 

Puede utilizar rolling_apply en combinación con una subfunción para realizar una función limpia como esta:

 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) 
 def RSI(series): delta = series.diff() u = delta * 0 d = u.copy() i_pos = delta > 0 i_neg = delta < 0 u[i_pos] = delta[i_pos] d[i_neg] = delta[i_neg] rs = moments.ewma(u, span=27) / moments.ewma(d, span=27) return 100 - 100 / (1 + rs) 
 # 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) donde P es el precio de cierre y t es la fecha