溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何利用Python實(shí)現(xiàn)隨機(jī)相對(duì)強(qiáng)弱指數(shù)StochRSI

發(fā)布時(shí)間:2021-09-24 15:51:17 來源:億速云 閱讀:178 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要介紹如何利用Python實(shí)現(xiàn)隨機(jī)相對(duì)強(qiáng)弱指數(shù)StochRSI,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

隨機(jī)相對(duì)強(qiáng)弱指數(shù)簡稱為StochRSI,是一種技術(shù)分析指標(biāo),用于確定資產(chǎn)是否處于超買或超賣狀態(tài),也用于確定當(dāng)前市場的態(tài)勢(shì)。顧名思義,StochRSI是標(biāo)準(zhǔn)相對(duì)強(qiáng)弱指數(shù)(RSI)的衍生,因此被視為是一種能夠衡量指數(shù)的指數(shù)。它是一種振蕩器,在中心線的上方和下方波動(dòng)。

StochRSI最初是在1994年由Stanley KrollTushar Chande撰寫的題為《The NewTechnical Trader》的書中描述。它經(jīng)常被股票交易者使用。

一、StochRSI如何運(yùn)作?

通過應(yīng)用隨機(jī)振蕩器生成公式,從標(biāo)準(zhǔn)RSI生成StochRSI。其生成結(jié)果是單個(gè)數(shù)字評(píng)級(jí),圍繞中心線(0.5)在0-1的值域范圍內(nèi)上下擺動(dòng)。但是,StochRSI的修改版本將結(jié)果乘以100,因此該值是介于0和100之間而不是0和1之間。通常還會(huì)參考3天內(nèi)的簡單移動(dòng)平均線(SMA)以及StochRSI趨勢(shì),作為信號(hào)線,旨在降低虛假信號(hào)交易的風(fēng)險(xiǎn)。

標(biāo)準(zhǔn)隨機(jī)震蕩指數(shù)公式取決于資產(chǎn)的收盤價(jià)以及設(shè)定周期內(nèi)的最高價(jià)和最低價(jià)。但是,當(dāng)使用公式計(jì)算StochRSI時(shí),它直接使用RSI數(shù)據(jù)(不考慮價(jià)格)。

Stoch RSI = (Current RSI - Lowest RSI)/(Highest RSI - Lowest RSI)

與標(biāo)準(zhǔn)RSI一樣,StochRSI使用的最常見時(shí)間周期為14。StochRSI計(jì)算中涉及的14個(gè)周期基于圖表時(shí)間范圍。因此,每日?qǐng)D表會(huì)顯示過去14天(K線圖),每小時(shí)圖表會(huì)顯示過去14小時(shí)生成的StochRSI

周期可以設(shè)置為幾天、幾小時(shí)甚至幾分鐘,并且它們的使用方式也因交易者而異(根據(jù)他們的情況和策略而定)。還可以向上或向下調(diào)整周期數(shù),以確定長期或短期趨勢(shì)。將周期值設(shè)置為20,是StochRSI指標(biāo)一個(gè)相當(dāng)受歡迎的選擇。

如上所述,某些StochRSI圖表模式指定的范圍值為0到100而不是0到1。在這些圖表中,中心線為50而不是0.5。因此,通常在0.8處出現(xiàn)的超買信號(hào)將表示為80,而超賣信號(hào)表示為20而不是0.2。具有0-100設(shè)置的圖表可能看起來略有不同,但實(shí)際原理解釋是基本相同的。

二、如何使用StochRSI?

StochRSI指數(shù)如果出現(xiàn)在其范圍的上限和下限附近,此時(shí)的意義是最重大的。因此,該指標(biāo)的主要用途是確定潛在的買入和賣出點(diǎn),以及價(jià)格發(fā)生的逆轉(zhuǎn)。因此,0.2或以下的數(shù)值,會(huì)表明資產(chǎn)可能發(fā)生超賣,而0.8或以上的數(shù)值則表明該資產(chǎn)可能會(huì)發(fā)生超買。

此外,更接近中心線的數(shù)值也可以為交易者提供有關(guān)市場趨勢(shì)的信息。例如,當(dāng)中心線作為支撐線并且StochRSI線穩(wěn)定移動(dòng)到0.5以上時(shí),尤其是數(shù)值趨近于0.8,則可能表明其繼續(xù)看漲或呈上升趨勢(shì)。同樣,當(dāng)數(shù)值始終低于0.5,趨近于0.2時(shí),則表明下跌或呈下降趨勢(shì)趨勢(shì)。

我們將通過 Python 中的回測來介紹 RSI StochRSI 這兩種方法。

三、基于均值回歸的StochRSI 策略

最常見的 StochRSI 策略基于均值回歸。與 RSI 一樣,StochRSI 通常使用 80 來表示做空的超買水平,使用 20 來表示要買入的超賣水平。此外,14 天的回顧和平滑期很常見。出于我們的目的,我們將堅(jiān)持使用這些標(biāo)準(zhǔn)值。

現(xiàn)在編寫代碼,讓我們?cè)?Python 中導(dǎo)入一些標(biāo)準(zhǔn)包。

import numpy as np  
import pandas as pd  
import matplotlib.pyplot as plt  
import yfinance as yf

接下來,我們將構(gòu)建一個(gè)函數(shù)來計(jì)算我們的指標(biāo)。我們將其稱為 calcStochRSI(),它將依靠一些函數(shù)來計(jì)算 RSI 和隨機(jī)振蕩器,以獲得我們選擇的指標(biāo)。

def calcRSI(data, P=14):  
  # Calculate gains and losses  
  data['diff_close'] = data['Close'] - data['Close'].shift(1)  
  data['gain'] = np.where(data['diff_close']>0,  
    data['diff_close'], 0)  
  data['loss'] = np.where(data['diff_close']<0,   
    np.abs(data['diff_close']), 0)  
  # Get initial values  
  data[['init_avg_gain', 'init_avg_loss']] = data[  
    ['gain', 'loss']].rolling(P)   
  # Calculate smoothed avg gains and losses for all t > P  
  avg_gain = np.zeros(len(data))  
  avg_loss = np.zeros(len(data)) 
  for i, _row in enumerate(data.iterrows()):  
    row = _row[1]  
    if i < P - 1:  
      last_row = row.copy()  
      continue  
    elif i == P-1:  
      avg_gain[i] += row['init_avg_gain']  
      avg_loss[i] += row['init_avg_loss']  
    else:  
      avg_gain[i] += ((P - 1) * avg_gain[i] +  
            row['gain']) / P  
      avg_loss[i] += ((P - 1) * avg_loss[i] +  
            row['loss']) / P          
    last_row = row.copy()  
  data['avg_gain'] = avg_gain  
  data['avg_loss'] = avg_loss  
  # Calculate RS and RSI  
  data['RS'] = data['avg_gain'] / data['avg_loss']  
  data['RSI'] = 100 - 100 / (1 + data['RS'])  
  return data  
def calcStochOscillator(data):  
  data['low_N'] = data['RSI'].rolling(N).min()  
  data['high_N'] = data['RSI'].rolling(N).max()  
  data['StochRSI'] = 100 * (data['RSI'] - data['low_N']) / \  
    (data['high_N'] - data['low_N'])  
  return data  
def calcStochRSI(data, P=14, N=14):  
  data = calcRSI(data)  
  data = calcStochOscillator(data)  
  return data  
def calcReturns(df):  
  # Helper function to avoid repeating too much code  
  df['returns'] = df['Close'] / df['Close'].shift(1)  
  df['log_returns'] = np.log(df['returns'])  
  df['strat_returns'] = df['position'].shift(1) * df['returns']  
  df['strat_log_returns'] = df['position'].shift(1) * df['log_returns']  
  df['cum_returns'] = np.exp(df['log_returns'].cumsum()) - 1  
  df['strat_cum_returns'] = np.exp(df['strat_log_returns'].cumsum()) - 1  
  df['peak'] = df['cum_returns'].cummax()  
  df['strat_peak'] = df['strat_cum_returns'].cummax()  
  return df

有了這些功能,我們只需要為我們的策略構(gòu)建邏輯就可以了。還要注意,我們有一個(gè)名為 calcReturns 的輔助函數(shù),我們可以快速將其應(yīng)用于回測的結(jié)果以從中獲取所有返回值。

這意味著回歸模型將在 StochRSI 高于 80 時(shí)做空或賣出,并在低于 20 時(shí)買入。

def StochRSIReversionStrategy(data, P=14, N=14, short_level=80,   
  buy_level=20, shorts=True):  
  '''Buys when the StochRSI is oversold and sells when it's overbought'''  
  df = calcStochRSI(data, P, N)  
  df['position'] = np  
  df['position'] = np.where(df['StochRSI']<buy_level, 1, df['position'])  
  if shorts:  
    df['position'] = np.where(df['StochRSI']>short_level, -1, df['position'])  
  else:  
    df['position'] = np.where(df['StochRSI']>short_level, 0, df['position'])  
  df['position'] = df['position'].ffill()  
  return calcReturns(df)  
table = pd.read_html('https://en.wikipedia.org/wiki/List_of_S%26P_500_companies')  
df = table[0]  
syms = df['Symbol']  
# Sample symbols  
# ticker = np.random.choice(syms.values)  
ticker = "BSX"  
print(f"Ticker Symbol: {ticker}")  
start = '2000-01-01'  
end = '2020-12-31'  
# Get Data  
yfyfObj = yf.Ticker(ticker)  
data = yfObj.history(startstart=start, endend=end)  
data.drop(['Open', 'High', 'Low', 'Volume', 'Dividends',   
    'Stock Splits'], inplace=True, axis=1)  
# Run test  
df_rev = StochRSIReversionStrategy(data.copy())  
# Plot results  
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']  
fig, ax = plt.subplots(2, figsize=(12, 8))  
ax[0].plot(df_rev['strat_cum_returns']*100, label='Mean Reversion')  
ax[0].plot(df_rev['cum_returns']*100, label='Buy and Hold')  
ax[0].set_ylabel('Returns (%)')  
ax[0].set_title('Cumulative Returns for Mean Reversion and' +  
                f' Buy and Hold Strategies for {ticker}')  
ax[0].legend(bbox_to_anchor=[1, 0.6])  
ax[1].plot(df_rev['StochRSI'], label='StochRSI', linewidth=0.5)  
ax[1].plot(df_rev['RSI'], label='RSI', linewidth=1)  
ax[1].axhline(80, label='Over Bought', color=colors[1], linestyle=':')  
ax[1].axhline(20, label='Over Sold', color=colors[2], linestyle=':')  
ax[1].axhline(50, label='Centerline', color='k', linestyle=':')  
ax[1].set_ylabel('Stochastic RSI')  
ax[1].set_xlabel('Date')  
ax[1].set_title(f'Stochastic RSI for {ticker}')  
ax[1].legend(bbox_to_anchor=[1, 0.75])  
plt.tight_layout()  
plt.show()

如何利用Python實(shí)現(xiàn)隨機(jī)相對(duì)強(qiáng)弱指數(shù)StochRSI

在我們研究的 21 年期間,均值回歸策略擊敗了Boston Scientific(BSX)的買入和持有策略,回報(bào)率為 28 倍,而后者為 2 倍。

在第二個(gè)圖中顯示了 StochRSI 和一些關(guān)鍵指標(biāo)。我還添加了 RSI 以與更不穩(wěn)定的 StochRSI 進(jìn)行比較。這導(dǎo)致交易頻繁,如果您的賬戶較小且交易成本相對(duì)較高,這可能會(huì)嚴(yán)重影響您的實(shí)際回報(bào)。我們只是在一個(gè)工具上運(yùn)行它,所以最終進(jìn)行了 443 筆交易,或者每 12 天交易一次,這看起來并不多。但是,如果我們要使用該指標(biāo)管理適當(dāng)?shù)墓ぞ呓M合并頻繁進(jìn)行交易,我們每天可能會(huì)進(jìn)出多筆交易,交易成本會(huì)變得很高。

# Get trades  
diff = df_rev['position'].diff().dropna()  
trade_idx = diff.index[np.where(diff!=0)]  
fig, ax = plt.subplots(figsize=(12, 8))  
ax.plot(df_rev['Close'], linewidth=1, label=f'{ticker}')  
ax.scatter(trade_idx, df_rev[trade_idx]['Close'], c=colors[1],   
           marker='^', label='Trade')  
ax.set_ylabel('Price')  
ax.set_title(f'{ticker} Price Chart and Trades for' +  
             'StochRSI Mean Reversion Strategy')  
ax.legend()  
plt.show()

如何利用Python實(shí)現(xiàn)隨機(jī)相對(duì)強(qiáng)弱指數(shù)StochRSI

要查看整體策略的一些關(guān)鍵指標(biāo),讓我們看看使用以下 getStratStats 函數(shù)。

def getStratStats(log_returns: pd.Series, risk_free_rate: float = 0.02):  
  stats = {}  
  # Total Returns  
  stats['tot_returns'] = np.exp(log_returns.sum()) - 1  
  # Mean Annual Returns  
  stats['annual_returns'] = np.exp(log_returns.mean() * 252) - 1  
  # Annual Volatility  
  stats['annual_volatility'] = log_returns * np.sqrt(252)  
  # Sortino Ratio  
  annualized_downside = log_returns.loc[log_returns<0].std() * np.sqrt(252)  
  stats['sortino_ratio'] = (stats['annual_returns'] - risk_free_rate) \  
    / annualized_downside  
  # Sharpe Ratio  
  stats['sharpe_ratio'] = (stats['annual_returns'] - risk_free_rate) \  
    / stats['annual_volatility']  
  # Max Drawdown  
  cum_returns = log_returns.cumsum() - 1  
  peak = cum_returns.cummax()  
  drawdown = peak - cum_returns  
  stats['max_drawdown'] = drawdown.max()  
  # Max Drawdown Duration  
  strat_dd = drawdown[drawdown==0]  
  strat_ddstrat_dd_diff = strat_dd.index[1:] - strat_dd.index[:-1]  
  strat_dd_days = strat_dd_diff.map(lambda x: x.days)  
  strat_dd_days = np.hstack([strat_dd_days,   
      (drawdown.index[-1] - strat_dd.index[-1]).days])  
  stats['max_drawdown_duration'] = strat_dd_days.max()  
  return stats  
rev_stats = getStratStats(df_rev['strat_log_returns'])  
bh_stats = getStratStats(df_rev['log_returns'])  
pd.concat([pd.DataFrame(rev_stats, index=['Mean Reversion']),  
           pd.DataFrame(bh_stats, index=['Buy and Hold'])])

如何利用Python實(shí)現(xiàn)隨機(jī)相對(duì)強(qiáng)弱指數(shù)StochRSI

在這里,我們看到該策略的回報(bào)率為 28 倍,而基礎(chǔ)資產(chǎn)的年度波動(dòng)率大致相同。此外,根據(jù) Sortino Sharpe Ratios 衡量,我們有更好的風(fēng)險(xiǎn)調(diào)整回報(bào)。

在 2020 年的新冠疫情中,我們確實(shí)看到了均值回歸策略的潛在問題之一。該策略的總回報(bào)大幅下降,因?yàn)樵摬呗缘亩ㄎ皇窍蛏匣貧w,但市場繼續(xù)低迷,該模型只是保持不變 . 它恢復(fù)了其中的一部分,但在這次測試中從未達(dá)到過疫情之前的高點(diǎn)。正確使用止損有助于限制這些巨大的損失,并有可能增加整體回報(bào)。

四、StochRSI 和動(dòng)量策略

我們之前提到的另一個(gè)基本策略是使用 StochRSI 作為動(dòng)量指標(biāo)。當(dāng)指標(biāo)穿過中心線時(shí),我們會(huì)根據(jù)其方向買入或做空股票。

def StochRSIMomentumStrategy(data, P=14, N=14,  
  centerline=50, shorts=True):  
  '''  
  Buys when the StochRSI moves above the centerline,   
  sells when it moves below  
  '''  
  df = calcStochRSI(data, P) 
  df['position'] = np.nan  
  df['position'] = np.where(df['StochRSI']>50, 1, df['position'])  
  if shorts: 
     df['position'] = np.where(df['StochRSI']<50, -1, df['position'])  
  else:  
    df['position'] = np.where(df['StochRSI']<50, 0, df['position'])  
  df['position'] = df['position'].ffill()  
  return calcReturns(df)

運(yùn)行我們的回測:

# Run test  
df_mom = StochRSIMomentumStrategy(data.copy())  
# Plot results  
colors = plt.rcParams['axes.prop_cycle'].by_key()['color']  
fig, ax = plt.subplots(2, figsize=(12, 8))  
ax[0].plot(df_mom['strat_cum_returns']*100, label='Momentum')  
ax[0].plot(df_mom['cum_returns']*100, label='Buy and Hold')  
ax[0].set_ylabel('Returns (%)')  
ax[0].set_title('Cumulative Returns for Momentum and' +  
                f' Buy and Hold Strategies for {ticker}')  
ax[0].legend(bbox_to_anchor=[1, 0.6])  
ax[1].plot(df_mom['StochRSI'], label='StochRSI', linewidth=0.5)  
ax[1].plot(df_mom['RSI'], label='RSI', linewidth=1)  
ax[1].axhline(50, label='Centerline', color='k', linestyle=':')  
ax[1].set_ylabel('Stochastic RSI')  
ax[1].set_xlabel('Date')  
ax[1].set_title(f'Stochastic RSI for {ticker}')  
ax[1].legend(bbox_to_anchor=[1, 0.75])  
plt.tight_layout()  
plt.show()

如何利用Python實(shí)現(xiàn)隨機(jī)相對(duì)強(qiáng)弱指數(shù)StochRSI

在這種情況下,我們的動(dòng)量策略表現(xiàn)非常糟糕,在我們假設(shè)的時(shí)間段內(nèi)幾乎損失了我們所有的初始投資。

查看我們策略的統(tǒng)計(jì)數(shù)據(jù),該模型的唯一優(yōu)勢(shì)是比買入并持有方法的回撤時(shí)間略短。

mom_stats = getStratStats(df_mom['strat_log_returns'])  
bh_stats = getStratStats(df_mom['log_returns'])  
pd.concat([pd.DataFrame(mom_stats, index=['Momentum']),  
           pd.DataFrame(rev_stats, index=['Mean Reversion']),  
           pd.DataFrame(bh_stats, index=['Buy and Hold'])])

這并不意味著StochRSI 不適合此類應(yīng)用。一次糟糕的回測并不意味著該策略毫無價(jià)值。相反,一個(gè)很好的回測并不意味著你有一些你應(yīng)該立即開始交易的東西。我們需要與其他指標(biāo)結(jié)合使用以改善結(jié)果。

以上是“如何利用Python實(shí)現(xiàn)隨機(jī)相對(duì)強(qiáng)弱指數(shù)StochRSI”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI