Индекс относительной силы в python pandas
Я новичок в pandas. Каков наилучший способ расчета относительной силы в индикаторе RSI в pandas? До сих пор я получил следующее:
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)
Я делаю это правильно до сих пор? У меня возникают проблемы с разностной частью уравнения, где вы выделяете вычисления вверх и вниз
Ответы
Ответ 1
dUp= delta[delta > 0]
dDown= delta[delta < 0]
также вам нужно что-то вроде:
RolUp = RolUp.reindex_like(delta, method='ffill')
RolDown = RolDown.reindex_like(delta, method='ffill')
иначе RS = RolUp / RolDown
не будет делать то, что вы пожелаете
Изменить: кажется, что это более точный способ вычисления 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
Ответ 2
Важно отметить, что существуют различные способы определения RSI. Он обычно определяется, по крайней мере, двумя способами: с использованием простой скользящей средней (SMA), как указано выше, или с использованием экспоненциальной скользящей средней (EMA). Здесь фрагмент кода, который вычисляет оба определения RSI и отображает их для сравнения. Я отбрасываю первую строку, принимая разницу, поскольку по определению она всегда NaN.
Обратите внимание, что при использовании EMA нужно быть осторожным: поскольку он включает в себя память, возвращающуюся к началу данных, результат зависит от того, где вы начинаете! По этой причине обычно люди будут добавлять некоторые данные в начале, скажем 100 временных шагов, а затем отключить первые 100 значений RSI.
В приведенном ниже графике можно увидеть разницу между RSI, рассчитанной с использованием SMA и EMA: SMA имеет тенденцию быть более чувствительной. Обратите внимание, что RSI, основанный на EMA, имеет первое конечное значение на первом временном шаге (который является вторым временным шагом исходного периода из-за отбрасывания первой строки), тогда как RSI на основе SMA имеет свое первое конечное значение на 14-й шаг времени. Это связано с тем, что по умолчанию roll_mean() возвращает только конечное значение, когда для заполнения окна достаточно значений.
![A comparison of the RSI calculated using exponential or simple moving average]()
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()
Ответ 3
Мой ответ проверяется на данных образцов StockCharts.
[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
Ответ 4
У меня тоже был этот вопрос, и я работал по пути roll_apply, который взял Джев. Однако, когда я проверил свои результаты, они не совпали с коммерческими программами составления графиков акций, такими как StockCharts.com или thinkorswim. Поэтому я немного покопался и обнаружил, что когда Уэллс Уайлдер создал RSI, он использовал технику сглаживания, которая теперь называется сглаживанием Уайлдера. Для расчета средних прибылей и убытков в вышеупомянутых коммерческих услугах используется сглаживание Уайлдера, а не простая скользящая средняя.
Я новичок в Python (и Pandas), поэтому мне интересно, есть ли какой-нибудь блестящий способ реорганизовать цикл для ниже, чтобы сделать его быстрее. Может быть, кто-то еще может прокомментировать эту возможность.
Надеюсь, вы найдете это полезным.
Подробнее здесь.
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
Ответ 5
Вы можете использовать roll_apply в сочетании с подфункцией, чтобы сделать чистую функцию следующим образом:
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)
Ответ 6
# 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), где P - цена закрытия, а t - дата
Ответ 7
Вы можете значительно ускорить ответ билла, используя numba. 100 циклов ряда строк по 20 тысяч (обычная = 113 секунд, числовая = 0,28 секунды). Numba выделяется петлями и арифметикой.
import numpy as np
import numba as nb
@nb.jit(fastmath=True, nopython=True)
def calc_rsi( array, deltas, avg_gain, avg_loss, n ):
# Use Wilder smoothing method
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_gain = ((avg_gain * (n-1)) + up(d)) / n
avg_loss = ((avg_loss * (n-1)) + down(d)) / n
if avg_loss != 0:
rs = avg_gain / avg_loss
array[i] = 100 - (100 / (1 + rs))
else:
array[i] = 100
i += 1
return array
def get_rsi( array, n = 14 ):
deltas = np.append([0],np.diff(array))
avg_gain = np.sum(deltas[1:n+1].clip(min=0)) / n
avg_loss = -np.sum(deltas[1:n+1].clip(max=0)) / n
array = np.empty(deltas.shape[0])
array.fill(np.nan)
array = calc_rsi( array, deltas, avg_gain, avg_loss, n )
return array
rsi = get_rsi( array or series, 14 )
Ответ 8
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)