<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          用 Python 實(shí)現(xiàn) RSI 指標(biāo)線與股價(jià)的頂背離、底背離

          共 16324字,需瀏覽 33分鐘

           ·

          2021-09-15 00:34

          當(dāng)價(jià)格和您的指標(biāo)向相反方向移動(dòng)時(shí),就會(huì)出現(xiàn)背離。例如,您使用 RSI 進(jìn)行交易,它上次在 80 處達(dá)到峰值,現(xiàn)在在 70 處達(dá)到峰值。當(dāng) RSI 達(dá)到 80 時(shí),您交易的標(biāo)的證券價(jià)格為 14 美元,現(xiàn)在達(dá)到新的峰值 18 美元。這是一個(gè)背離。

          由于峰值的趨勢,交易者將價(jià)格稱為“更高的高點(diǎn)”,將 RSI 稱為“更低的高點(diǎn)”。技術(shù)交易者通過視覺跟蹤但很難復(fù)制,因?yàn)椴⒉豢偸乔宄烤故鞘裁丛炀土恕胺逯怠?。我們提供了一種算法來檢測交易的波峰和波谷,我們將在下面深入探討構(gòu)建 RSI 背離策略的細(xì)節(jié)時(shí)加以利用。

          作為入場信號的背離

          背離通常被稱為“看跌”或“看漲”。看跌背離就像我們在上面的例子中看到的那樣。我們有一個(gè)動(dòng)量指標(biāo)在價(jià)格之前減弱,這給了我們一個(gè)做空的點(diǎn)。看漲背離是我們的動(dòng)量指標(biāo)出現(xiàn)較高的低點(diǎn),但價(jià)格較低的低點(diǎn)。

          根據(jù)這種解釋,背離是領(lǐng)先指標(biāo)——背離發(fā)生在價(jià)格行為確認(rèn)之前。在實(shí)踐中,實(shí)現(xiàn)這一點(diǎn)更具挑戰(zhàn)性,因?yàn)槟鷷?huì)發(fā)現(xiàn)自己正在尋找價(jià)格和指標(biāo)的峰值,并且直到經(jīng)過一段時(shí)間后才能確認(rèn)該值是峰值,因此您可以查看該值是否下降。

          無論如何,讓我們用一些代碼來說明這是如何工作的!

          檢測背離

          第一步將需要導(dǎo)入幾個(gè)包。

          import numpy as npimport pandas as pdimport matplotlib.pyplot as pltimport yfinance as yffrom scipy.signal import argrelextremafrom collections import deque

          argrelextrema 用于檢測 SciPy 信號處理庫中的峰值,而 deque 就像一個(gè)固定長度的列表,如果超過它的長度,它將刪除最舊的條目并保留新條目。我們將使用第一個(gè)來發(fā)現(xiàn)數(shù)據(jù)中的極值,然后循環(huán)遍歷它們并保留高于先前條目的點(diǎn)。

          為了找出極值,我們需要傳遞一個(gè)名為 order 的參數(shù)。這定義了我們實(shí)際需要在峰的兩側(cè)有多少個(gè)點(diǎn)來標(biāo)記峰。因此,當(dāng) order=5 時(shí),我們需要一些東西成為左右 5 個(gè)數(shù)據(jù)點(diǎn)內(nèi)的最高點(diǎn)。我們提供的另一個(gè)參數(shù)是 K,它只是一個(gè)整數(shù),用于確定我們想要識別多少個(gè)連續(xù)峰值以確定更高的高點(diǎn)趨勢。

          下面給出了完整的、更高的檢測功能。

          def getHigherHighs(data: np.array, order=5, K=2):  '''  Finds consecutive higher highs in price pattern.  Must not be exceeded within the number of periods indicated by the width   parameter for the value to be confirmed.  K determines how many consecutive highs need to be higher.  '''  # Get highs  high_idx = argrelextrema(data, np.greater, order=order)[0]  highs = data[high_idx]  # Ensure consecutive highs are higher than previous highs  extrema = []  ex_deque = deque(maxlen=K)  for i, idx in enumerate(high_idx):    if i == 0:      ex_deque.append(idx)      continue    if highs[i] < highs[i-1]:      ex_deque.clear()
          ex_deque.append(idx) if len(ex_deque) == K: extrema.append(ex_deque.copy())
          return extrema

          這將返回包含峰值索引的雙端隊(duì)列列表。為了獲得用于識別背離的所有相關(guān)組合,我們需要四個(gè)這樣的函數(shù),一個(gè)用于更高的高點(diǎn)(上圖)、更低的低點(diǎn)、更低的高點(diǎn)和更高的低點(diǎn)。它們中的每一個(gè)的邏輯都是相同的,我們只是在第 9 行將 np.greater 更改為 np.less 并在第 18 行更改不等號以獲得我們想要的行為。

          我們需要一些數(shù)據(jù),因此我們將從 Yahoo! 使用 yfinance 包的金融 API。我將使用埃克森美孚 (XOM),因?yàn)樗谶^去幾十年中經(jīng)歷了相當(dāng)多的繁榮和蕭條。

          start = '2011-01-01'end = '2011-07-31'
          ticker = 'XOM'yfObj = yf.Ticker(ticker)data = yfObj.history(start=start, end=end)# Drop unused columnsdata.drop(['Open', 'High', 'Low', 'Volume', 'Dividends', 'Stock Splits'], axis=1, inplace=True)

          現(xiàn)在我們可以計(jì)算所有的極值并繪制結(jié)果。

          from matplotlib.lines import Line2D # For legend
          price = data['Close'].valuesdates = data.index
          # Get higher highs, lower lows, etc.order = 5hh = getHigherHighs(price, order)lh = getLowerHighs(price, order)ll = getLowerLows(price, order)hl = getHigherLows(price, order)
          # Get confirmation indiceshh_idx = np.array([i[1] + order for i in hh])lh_idx = np.array([i[1] + order for i in lh])ll_idx = np.array([i[1] + order for i in ll])hl_idx = np.array([i[1] + order for i in hl])
          # Plot resultscolors = plt.rcParams['axes.prop_cycle'].by_key()['color']
          plt.figure(figsize=(12, 8))plt.plot(data['Close'])plt.scatter(dates[hh_idx], price[hh_idx-order], marker='^', c=colors[1])plt.scatter(dates[lh_idx], price[lh_idx-order], marker='v', c=colors[2])plt.scatter(dates[ll_idx], price[ll_idx-order], marker='v', c=colors[3])plt.scatter(dates[hl_idx], price[hl_idx-order], marker='^', c=colors[4])_ = [plt.plot(dates[i], price[i], c=colors[1]) for i in hh]_ = [plt.plot(dates[i], price[i], c=colors[2]) for i in lh]_ = [plt.plot(dates[i], price[i], c=colors[3]) for i in ll]_ = [plt.plot(dates[i], price[i], c=colors[4]) for i in hl]
          plt.xlabel('Date')plt.ylabel('Price ($)')plt.title(f'Potential Divergence Points for {ticker} Closing Price')legend_elements = [ Line2D([0], [0], color=colors[0], label='Close'), Line2D([0], [0], color=colors[1], label='Higher Highs'), Line2D([0], [0], color='w', marker='^', markersize=10, markerfacecolor=colors[1], label='Higher High Confirmation'), Line2D([0], [0], color=colors[2], label='Higher Lows'), Line2D([0], [0], color='w', marker='^', markersize=10, markerfacecolor=colors[2], label='Higher Lows Confirmation'), Line2D([0], [0], color=colors[3], label='Lower Lows'), Line2D([0], [0], color='w', marker='v', markersize=10, markerfacecolor=colors[3], label='Lower Lows Confirmation'), Line2D([0], [0], color=colors[4], label='Lower Highs'), Line2D([0], [0], color='w', marker='^', markersize=10, markerfacecolor=colors[4], label='Lower Highs Confirmation')]plt.legend(handles=legend_elements, bbox_to_anchor=(1, 0.65))plt.show()


          在這個(gè)圖中,我們提取了所有潛在的分歧點(diǎn),并將高點(diǎn)和低點(diǎn)映射到價(jià)格。另外,請注意我為每個(gè)峰值繪制了確認(rèn)點(diǎn)。我們不知道峰值是否真的是峰值,直到我們給它幾天(在這種情況下為 5 天)看看價(jià)格接下來會(huì)發(fā)生什么。

          價(jià)格圖表只是背離所需的一半,我們還需要應(yīng)用一個(gè)指標(biāo)。借鑒考夫曼出色的交易系統(tǒng)和方法,我們應(yīng)該使用某種動(dòng)量指標(biāo)。我們將繼續(xù)應(yīng)用 RSI,盡管 MACD、隨機(jī)指標(biāo)等也適用。

          RSI 的峰值和谷值

          RSI 最常被解釋為當(dāng)該值高于中心線 (RSI=50) 時(shí)表現(xiàn)出上升勢頭,而當(dāng)它低于中心線時(shí)表現(xiàn)出下降勢頭。如果我們有一系列高于 50 的較小峰值,則可能表明動(dòng)能減弱,而低于 50 的一系列不斷增加的谷可能表明我們可以交易的動(dòng)能增加。

          我們的下一步是計(jì)算 RSI,然后應(yīng)用與上述相同的技術(shù)來提取相關(guān)的極值。

          def calcRSI(data, P=14):  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)  data[['init_avg_gain', 'init_avg_loss']] = data[    ['gain', 'loss']].rolling(P).mean()  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-1] + row['gain']) / P      avg_loss[i] += ((P - 1) * avg_loss[i-1] + row['loss']) / P
          last_row = row.copy()
          data['avg_gain'] = avg_gain data['avg_loss'] = avg_loss data['RS'] = data['avg_gain'] / data['avg_loss'] data['RSI'] = 100 - 100 / (1 + data['RS']) return data

          有了該功能,我們可以將 RSI 及其相關(guān)列添加到我們的數(shù)據(jù)框中:

          data = calcRSI(data.copy())# Get values to mark RSI highs/lows and plotrsi_hh = getHigherHighs(rsi, order)rsi_lh = getLowerHighs(rsi, order)rsi_ll = getLowerLows(rsi, order)rsi_hl = getHigherLows(rsi, order)

          我們將遵循與上述相同的格式來繪制我們的結(jié)果:

          fig, ax = plt.subplots(2, figsize=(20, 12), sharex=True)ax[0].plot(data['Close'])ax[0].scatter(dates[hh_idx], price[hh_idx-order],               marker='^', c=colors[1])ax[0].scatter(dates[lh_idx], price[lh_idx-order],              marker='v', c=colors[2])ax[0].scatter(dates[hl_idx], price[hl_idx-order],              marker='^', c=colors[3])ax[0].scatter(dates[ll_idx], price[ll_idx-order],              marker='v', c=colors[4])_ = [ax[0].plot(dates[i], price[i], c=colors[1]) for i in hh]_ = [ax[0].plot(dates[i], price[i], c=colors[2]) for i in lh]_ = [ax[0].plot(dates[i], price[i], c=colors[3]) for i in hl]_ = [ax[0].plot(dates[i], price[i], c=colors[4]) for i in ll]
          ax[0].set_ylabel('Price ($)')ax[0].set_title(f'Price and Potential Divergence Points for {ticker}')ax[0].legend(handles=legend_elements)
          ax[1].plot(data['RSI'])ax[1].scatter(dates[rsi_hh_idx], rsi[rsi_hh_idx-order], marker='^', c=colors[1])ax[1].scatter(dates[rsi_lh_idx], rsi[rsi_lh_idx-order], marker='v', c=colors[2])ax[1].scatter(dates[rsi_hl_idx], rsi[rsi_hl_idx-order], marker='^', c=colors[3])ax[1].scatter(dates[rsi_ll_idx], rsi[rsi_ll_idx-order], marker='v', c=colors[4])_ = [ax[1].plot(dates[i], rsi[i], c=colors[1]) for i in rsi_hh]_ = [ax[1].plot(dates[i], rsi[i], c=colors[2]) for i in rsi_lh]_ = [ax[1].plot(dates[i], rsi[i], c=colors[3]) for i in rsi_hl]_ = [ax[1].plot(dates[i], rsi[i], c=colors[4]) for i in rsi_ll]
          ax[1].set_ylabel('RSI')ax[1].set_title(f'RSI and Potential Divergence Points for {ticker}')ax[1].set_xlabel('Date')
          plt.tight_layout()plt.show()


          這只是一個(gè)短暫的 7 個(gè)月窗口,因此我們可以清楚地看到價(jià)格和 RSI 的走勢,因此只有一個(gè)背離可見。我們在 RSI 圖表(橙色,向上的三角形)上看到 6 月中旬在價(jià)格圖表(藍(lán)色,向下的三角形)中一系列較低的低點(diǎn)中間確認(rèn)更高的低點(diǎn)。我們不權(quán)衡圖表,所以讓我們把一個(gè)算法放在一起來測試這個(gè) RSI 背離模型。

          建立 RSI 發(fā)散模型

          到目前為止,我們有一些通用規(guī)則來識別我們有背離的情況,但我們?nèi)匀恍枰M(jìn)入和退出規(guī)則。首先,我們可以求助于 Kaufmann 出色的交易系統(tǒng)和方法,在那里他列出了一個(gè)示例策略,其中包含以下規(guī)則:

          如果指標(biāo)高于目標(biāo)水平(例如 RSI = 50),則在確定背離時(shí)輸入頭寸。如果指標(biāo)背離消失,則退出。如果我們在價(jià)格創(chuàng)出更高的高點(diǎn)而 RSI 創(chuàng)出更低的高點(diǎn)時(shí)做空,那么我們的 RSI 會(huì)移動(dòng)到更高的高點(diǎn),那么我們就出局了。一旦指標(biāo)達(dá)到目標(biāo)水平就退出。允許背離轉(zhuǎn)換為趨勢位置。為此,我們使用單獨(dú)的趨勢指標(biāo)(例如 EMA 交叉),如果趨勢與背離方向相同,我們將持有頭寸。如果背離消失但趨勢繼續(xù),我們持有,并僅在趨勢消失時(shí)退出。我們將根據(jù) Kaufmann 規(guī)則構(gòu)建兩種模型,一種僅交易背離(規(guī)則 1-3),另一種具有背離加趨勢(所有 4 條規(guī)則)。當(dāng)然,您可以根據(jù)自己的需要隨意修改這些,并自己嘗試各種方法。

          接下來,我將構(gòu)建一些輔助函數(shù)來標(biāo)記我們的峰值。第一組將修改我們的 getHigherHighs 函數(shù)組的輸出。這些是為上述可視化而構(gòu)建的,但我們只需要為我們的模型提取趨勢的確認(rèn)點(diǎn)。另請注意,由于我們正在向索引添加順序,因此我們可能會(huì)獲得會(huì)引發(fā)索引錯(cuò)誤的確認(rèn)點(diǎn),因此我們會(huì)刪除任何大于我們擁有的數(shù)據(jù)點(diǎn)數(shù)量的索引。

          四個(gè)函數(shù)如下:

          def getHHIndex(data: np.array, order=5, K=2):  extrema = getHigherHighs(data, order, K)  idx = np.array([i[-1] + order for i in extrema])  return idx[np.where(idx<len(data))]
          def getLHIndex(data: np.array, order=5, K=2): extrema = getLowerHighs(data, order, K) idx = np.array([i[-1] + order for i in extrema]) return idx[np.where(idx<len(data))]
          def getLLIndex(data: np.array, order=5, K=2): extrema = getLowerLows(data, order, K) idx = np.array([i[-1] + order for i in extrema]) return idx[np.where(idx<len(data))]
          def getHLIndex(data: np.array, order=5, K=2): extrema = getHigherLows(data, order, K) idx = np.array([i[-1] + order for i in extrema]) return idx[np.where(idx<len(data))]

          為了減少重寫代碼,我將引入一個(gè)名為 getPeaks 的函數(shù),它獲取我們的數(shù)據(jù)幀并將我們的高點(diǎn)和低點(diǎn)的輸出編碼為列向量。它將使用我們上面定義的四個(gè)函數(shù),并從我們觸及更高高點(diǎn)到 Close_highs 列分配值 1。如果我們的高點(diǎn)在確認(rèn)較低的高點(diǎn)后呈下降趨勢,那么我們在同一列中用 -1 標(biāo)記。它會(huì)為低點(diǎn)做同樣的事情。記住哪些值為 1 哪些值為 -1 很重要,因此如果趨勢正在增加(更高的高點(diǎn)或更高的低點(diǎn)),我將其設(shè)為 1,如果趨勢正在下降(更低的高點(diǎn)或更低的低點(diǎn)),我將其設(shè)為 1 )。

          def getPeaks(data, key='Close', order=5, K=2):  vals = data[key].values  hh_idx = getHHIndex(vals, order, K)  lh_idx = getLHIndex(vals, order, K)  ll_idx = getLLIndex(vals, order, K)  hl_idx = getHLIndex(vals, order, K)
          data[f'{key}_highs'] = np.nan data[f'{key}_highs'][hh_idx] = 1 data[f'{key}_highs'][lh_idx] = -1 data[f'{key}_highs'] = data[f'{key}_highs'].ffill().fillna(0) data[f'{key}_lows'] = np.nan data[f'{key}_lows'][ll_idx] = 1 data[f'{key}_lows'][hl_idx] = -1 data[f'{key}_lows'] = data[f'{key}_highs'].ffill().fillna(0) return data

          最后,我們可以制定我們的戰(zhàn)略。在這里,我們只是遵循上面列出的前 3 條規(guī)則。

          def RSIDivergenceStrategy(data, P=14, order=5, K=2):  '''  Go long/short on price and RSI divergence.  - Long if price to lower low and RSI to higher low with RSI < 50  - Short if price to higher high and RSI to lower high with RSI > 50  Sell if divergence disappears.  Sell if the RSI crosses the centerline.  '''  data = getPeaks(data, key='Close', order=order, K=K)  data = calcRSI(data, P=P)  data = getPeaks(data, key='RSI', order=order, K=K)
          position = np.zeros(data.shape[0]) # position[:] = np.nan for i, (t, row) in enumerate(data.iterrows()): if np.isnan(row['RSI']): continue # If no position is on if position[i-1] == 0: # Buy if indicator to higher low and price to lower low if row['Close_lows'] == -1 and row['RSI_lows'] == 1: if row['RSI'] < 50: position[i] = 1 entry_rsi = row['RSI'].copy()
          # Short if price to higher high and indicator to lower high elif row['Close_highs'] == 1 and row['RSI_highs'] == -1: if row['RSI'] > 50: position[i] = -1 entry_rsi = row['RSI'].copy()
          # If current position is long elif position[i-1] == 1: if row['RSI'] < 50 and row['RSI'] < entry_rsi: position[i] = 1
          # If current position is short elif position[i-1] == -1: if row['RSI'] < 50 and row['RSI'] > entry_rsi: position[i] = -1
          data['position'] = position return calcReturns(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

          關(guān)于退出條件需要注意的一件事,我們要等待趨勢的變化。我沒有等待 5 天來確認(rèn) RSI 的峰值,而是添加了一個(gè)條件,即如果 RSI 跌破我們的多頭倉位的入場 RSI 或高于我們的空頭倉位的入場 RSI,我們應(yīng)該退出。這是有效的,因?yàn)槿绻覀冊?RSI 的較低高點(diǎn)做空,那么如果情況逆轉(zhuǎn),我們將退出。如果 RSI 收于我們的入場 RSI 上方,那么要么成為更高的高點(diǎn),從而打破我們的趨勢,要么更高的高點(diǎn)仍將到來。設(shè)置這個(gè)條件只會(huì)讓我們更快地退出交易。

          好了,解釋夠了,讓我們用 2000-2020 年的數(shù)據(jù)測試一下。

          start = '2000-01-01'end = '2020-12-31'data = yfObj.history(start=start, end=end)# Drop unused columnsdata.drop(['Open', 'High', 'Low', 'Volume', 'Dividends',   'Stock Splits'], axis=1, inplace=True)
          df_div = RSIDivergenceStrategy(data.copy())
          plt.figure(figsize=(12, 8))plt.plot(df_div['cum_returns'] * 100, label='Buy-and-Hold')plt.plot(df_div['strat_cum_returns'] * 100, label='RSI Divergence')plt.xlabel('Date')plt.ylabel('Returns (%)')plt.title(f'Buy-and-Hold and RSI Divergence Returns for {ticker}')plt.legend()plt.show()
          df_stats = pd.DataFrame(getStratStats(df_div['log_returns']), index=['Buy and Hold'])df_stats = pd.concat([df_stats, pd.DataFrame(getStratStats(df_div['strat_log_returns']), index=['Divergence'])])
          df_stats


          最后,背離策略的表現(xiàn)優(yōu)于買入并持有的策略(忽略??松梨谥Ц兜墓上ⅲ?。它的波動(dòng)性較小,跌幅較小,但在 2004 年至 2020 年期間表現(xiàn)不佳。換句話說,在 2020 年突破之前,你會(huì)等待 16 年,而這種策略看起來像是對底層證券的虧損。這種策略可能在其他地方更有效或適合多元化的投資組合,但至少在這種情況下, 純 RSI 背離策略看起來不太好。

          RSI 背離和趨勢

          對于下一個(gè)模型,讓我們采用 Kaufman 的建議并應(yīng)用趨勢轉(zhuǎn)換。為此,我們將選擇 EMA 交叉。因此,該模型將像我們上面看到的背離模型一樣進(jìn)行交易,但會(huì)檢查我們的 EMA 交叉所指示的趨勢。如果我們做多且 EMA1 > EMA2,我們將保持該頭寸。

          EMA 計(jì)算代碼和策略如下:

          def _calcEMA(P, last_ema, N):  return (P - last_ema) * (2 / (N + 1)) + last_ema
          def calcEMA(data, N): # Initialize series data['SMA_' + str(N)] = data['Close'].rolling(N).mean() ema = np.zeros(len(data)) for i, _row in enumerate(data.iterrows()): row = _row[1] if i < N: ema[i] += row['SMA_' + str(N)] else: ema[i] += _calcEMA(row['Close'], ema[i-1], N) data['EMA_' + str(N)] = ema.copy() return data
          def RSIDivergenceWithTrendStrategy(data, P=14, order=5, K=2, EMA1=50, EMA2=200): ''' Go long/short on price and RSI divergence. - Long if price to lower low and RSI to higher low with RSI < 50 - Short if price to higher high and RSI to lower high with RSI > 50 Sell if divergence disappears or if the RSI crosses the centerline, unless there is a trend in the same direction. ''' data = getPeaks(data, key='Close', order=order, K=K) data = calcRSI(data, P=P) data = getPeaks(data, key='RSI', order=order, K=K) data = calcEMA(data, EMA1) data = calcEMA(data, EMA2)
          position = np.zeros(data.shape[0]) # position[:] = np.nan for i, (t, row) in enumerate(data.iterrows()): if np.isnan(row['RSI']): continue # If no position is on if position[i-1] == 0: # Buy if indicator to higher high and price to lower high if row['Close_lows'] == -1 and row['RSI_lows'] == 1: if row['RSI'] < 50: position[i] = 1 entry_rsi = row['RSI'].copy()
          # Short if price to higher high and indicator to lower high elif row['Close_highs'] == 1 and row['RSI_highs'] == -1: if row['RSI'] > 50: position[i] = -1 entry_rsi = row['RSI'].copy()
          # If current position is long elif position[i-1] == 1: if row['RSI'] < 50 and row['RSI'] < entry_rsi: position[i] = 1 elif row[f'EMA_{EMA1}'] > row[f'EMA_{EMA2}']: position[i] = 1
          # If current position is short elif position[i-1] == -1: if row['RSI'] < 50 and row['RSI'] > entry_rsi: position[i] = -1 elif row[f'EMA_{EMA1}'] < row[f'EMA_{EMA2}']: position[i] = -1
          data['position'] = position return calcReturns(data)

          在我們的數(shù)據(jù)上運(yùn)行這個(gè)模型,我們得到:

          plt.figure(figsize=(12, 8))plt.plot(df_trend['cum_returns'] * 100, label=f'Buy-and-Hold')plt.plot(df_trend['strat_cum_returns'] * 100, label='RSI Div + Trend')plt.xlabel('Date')plt.ylabel('Returns (%)')plt.title(f'Buy-and-Hold and Divergence with Trend Returns for {ticker}')plt.legend()plt.show()
          df_trend = RSIDivergenceWithTrendStrategy(data.copy())df_stats = pd.concat([df_stats, pd.DataFrame(getStratStats(df_trend['strat_log_returns']), index=['Div + Trend'])])df_stats


          添加我們的趨勢指標(biāo)大大增加了我們的回報(bào)。它以較低的波動(dòng)性(盡管比 RSI 背離策略更多)和較高的風(fēng)險(xiǎn)調(diào)整回報(bào)。最大回撤小于底層證券經(jīng)歷的最大回撤,而且持續(xù)時(shí)間更短。

          你準(zhǔn)備好交易了嗎?

          我們研究了兩種 RSI 背離策略的編碼和交易,一種很好,另一種則不然。這是否意味著您應(yīng)該出去用 EMA 交叉交易 RSI 背離?

          在這里給你一些關(guān)于這些指標(biāo)的想法和解釋。這些快速的回測很有用,因?yàn)槟梢粤私馊绾螠y試想法,并且可以在各種證券和市場上進(jìn)行測試以開始縮小選擇范圍。也許更嚴(yán)格的測試表明 RSI 背離是您系統(tǒng)中真正有價(jià)值的部分,而趨勢模型是一個(gè)異常值。除非你測試它,否則你永遠(yuǎn)不會(huì)知道!


          掃描本文最下方二維碼獲取全部完整源碼和Jupyter Notebook 文件打包下載。

          長按掃碼獲取完整源碼



          瀏覽 54
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  91人人操人人 | 性一交一乱一A片久久99蜜桃 | 18女人黄色毛片 | 伊人日产无码中文久久久 | 一区二区无码在线播放入口 |