量化投資實戰(一)之KDJ交易策略

點贊、關注再看,養成良好習慣
Life is short, U need Python
初學量化投資實戰,[快來點我吧]

在這裏插入圖片描述

1. 前言

由於最近博主比較忙,所以有一段時間沒寫博文了;另外,量化投資基礎系列以及量化投資實戰系列是博主擅長和看重的欄目,故遲遲未與大家見面。由於前段時間學院和一個公司合作搭建量化投資虛擬仿真實驗中心,需要我提供搭建示例(思路)以及一些選股因子指標和擇時買賣因子指標的制定(提供用Python寫的指標因子代碼以及量化交易策略回測代碼等),由於是爲了教學服務,公司不建議做的那麼複雜(可能工作量太大吧),在擇時交易指標上就準備先做一個因子(選股因子還是有4-6個因子的,雖然也很少),於是博主就選擇了KDJ技術指標。接下來,博主就以KDJ交易策略作爲量化投資實戰系列的開篇之作展現給博友們(時間倉促,如若不對之處,請博友們留言指正,先謝謝大家了)!

2. KDJ指標概述

KDJ指標又叫隨機指標,是一種相當新穎、實用的技術分析指標,它起先用於期貨市場的分析,後被廣泛用於股市的中短期趨勢分析,是期貨和股票市場上最常用的技術分析工具。

隨機指標KDJ一般是用於股票分析的統計體系,根據統計學原理,通過一個特定的週期(常爲9日、9周等)內出現過的最高價、最低價及最後一個計算週期的收盤價及這三者之間的比例關係,來計算最後一個計算週期的未成熟隨機值RSV,然後根據平滑移動平均線的方法來計算K值、D值與J值,並繪成曲線圖來研判股票價格走勢。

3. KDJ指標原理

隨機指標KDJ是以最高價、最低價及收盤價爲基本數據進行計算,得出的K值、D值和J值分別在指標的座標上形成的一個點,連接無數個這樣的點位,就形成一個完整的、能反映價格波動趨勢的KDJ指標。它主要是利用價格波動的真實波幅來反映價格走勢的強弱和超買超賣現象,在價格尚未上升或下降之前發出買賣信號的一種技術工具。它在設計過程中主要是研究最高價、最低價和收盤價之間的關係,同時也融合了動量觀念、強弱指標和移動平均線的一些優點,因此,能夠比較迅速、快捷、直觀地研判行情。由於KDJ線本質上是一個隨機波動的觀念,故其對於掌握中短期行情走勢比較準確。

4. KDJ指標公式

(1)RSV(未成熟隨機指標)計算

在這裏插入圖片描述
其中,原始參數值 n=9n = 9

  • RSV的K線圖解釋
    在這裏插入圖片描述
  • RSV的Python代碼實現
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt


# 讀取標普500的指數數據
GSPC = pd.read_csv('GSPC.csv',index_col='Date')
GSPC = GSPC.iloc[:,1:]
GSPC.index = pd.to_datetime(GSPC.index)

# 提取收盤價、最高價、最低價數據
close = GSPC.Close
high = GSPC.High
low = GSPC.Low

# 獲取日期數據
date = close.index.to_series()
ndate = len(date)

# 定義初始變量最高價High,取值爲0
periodHigh = pd.Series(np.zeros(ndate-8),index=date.index[8:])
# 定義初始變量最低價Low,取值爲0
periodLow = pd.Series(np.zeros(ndate-8),index=date.index[8:])
# 定義初始變量RSV,取值爲0
RSV = pd.Series(np.zeros(ndate-8),index=date.index[8:])

# 計算RSV的值
for j in range(8,ndate):
    period = date[j-8:j+1]
    i = date[j]
    periodHigh[i] = high[period].max()
    periodLow[i] = low[period].min()
    RSV[i] = 100*(close[i]-periodLow[i])/(periodHigh[i]-periodLow[i])
    periodHigh.name = 'periodHigh'
    periodLow.name = 'periodLow'
    RSV.name = 'RSV'

# 繪製標普500指數收盤價曲線圖和RSV曲線圖
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']  

close1 = close['2015']
RSV1 = RSV['2015']
Cl_RSV = pd.DataFrame([close1,RSV1]).transpose()
Cl_RSV.plot(subplots=True,title='未成熟隨機指標RSV')

plt.show()

結果如圖所示:
在這裏插入圖片描述
從上可以歸納出一個規律,當市場處於連續上漲行期時,未成熟隨機指標 RSV 取值也逐漸增大,而且可能在較多日期中取值爲 100;當市場處於連續下跌行期時,RSV 取值可能在較多日期中取值爲0。當 RSV 連續多期取值 100 或者 0 時,RSV 則會出現所謂“鈍化”的現象,例如,當收盤價在上漲行情高位變化時,RSV 在一段時間內取值均爲 100,不隨收盤價的變化而波動,則失去了捕捉收盤價變化的作用。此外,從上圖中可以觀察到,RSV 值的波動幅度較大,也可能會造成“假信號”。其中一種可能狀況是,在上漲行期中收盤價上漲幅度稍微增大,則可能造成 RSV 取值過大,進而釋放出市場處於“超買”行期的“假信號”。

(2)K、D 指標計算

爲了解決 RSV 波動幅度較大的問題,引入 K 指標,它是對 RSV 值進行平滑得到的結果。
K 值由前一日的 K 值和當期 RSV 值經過一定權重調整後相加而得到,一般來說,K 值的計算爲:
在這裏插入圖片描述
在這裏插入圖片描述
其中,KtK_t爲第 ttKK 值,Kt1K_{t-1}爲第 t1t-1KK值,RSVt_t 表示第tt日的 RSV 值。
D 值由前一日的 D 值和當期 K 值經過一定權重調整後相加而得到,一般來說,D 值的計算爲:
在這裏插入圖片描述
在這裏插入圖片描述
其中,DtD_t爲第 t 日 D 值,Dt1D_{t-1}爲第 t-1 日 D 值,KtK_t 表示第 t 日的 K 值。

此外,在計算第1期的 K 值和 D 值時,如果沒有指定,則 K 值和 D 值默認取值爲50。在K值和D值的求解過程中,平滑權重 2/3 和 1/3 是較爲常用的權重,這兩個權重也可以根據股價走勢的特點進行適當修改。

K1K_1 = 50, D1D_1= 50,通過遞歸和迭代,可以推出K值是由未成熟隨機指標 RSV 通過指數移動平均而得到。同理,D 值是 K 值的指數移動平均數(Exponential Moving Average, EMA)。

  • Python計算 K 值和 D 值
# 在RSV基礎上增加前2期的數據=50
RSV1 = pd.Series([50,50],index=date[6:8]).append(RSV)
RSV1.name = 'RSV'

# 利用 RSV 值計算 K 值
KValue = pd.Series(0.0,index=RSV1.index)
KValue[0] = 50
for i in range(1,len(RSV1)):
    KValue[i] = 2/3*KValue[i-1]+RSV1[i]/3   
KValue.name = 'KValue'

# 利用 K 值計算 D 值
DValue = pd.Series(0.0,index=RSV1.index)
DValue[0] = 50
for i in range(1,len(RSV1)):
    DValue[i] = 2/3*DValue[i-1]+KValue[i]/3
DValue.name='DValue'

# 提取 K 值和 D 值
KValue = KValue[1:]
DValue = DValue[1:]


# 直觀展示 RSV、K 值和 D 值
import matplotlib.pyplot as plt

plt.figure(figsize=(10,6))

plt.subplot(211)
plt.title('2015年標準普爾500的收盤價')
plt.plot(close['2015'])

plt.subplot(212)
plt.title('2015年標準普爾500的RSV與KD線')
plt.plot(RSV['2015'])
plt.plot(KValue['2015'],linestyle='dashed')
plt.plot(DValue['2015'],linestyle='-.')

plt.subplots_adjust(hspace=0.4)  # 子圖間隔設置
plt.legend()
plt.show()

結果如圖所示:
在這裏插入圖片描述

(4)J 指標計算

J 指標是 KD 指標的輔助指標,進一步反映了 K 指標和 D 指標的偏離程度。第 t 日 J 值計算公式爲:
在這裏插入圖片描述
其中,JtJ_t 爲第 t 日 J 值,KtK_t 爲第 t 日 K 值,DtD_t 爲第 t 日 D 值。

  • Python計算 J 值
# 計算J值:J = 3K-2D
JValue = 3*KValue - 2*DValue
JValue.name = 'JValue'

5. KDJ指標簡要分析

不再多說了,直接上代碼分析吧!

# 繪製 KDJ 指標曲線圖
import matplotlib
matplotlib.rcParams['axes.unicode_minus']=False   # 負號顯示

import matplotlib.pyplot as plt
plt.figure(figsize=(10,8))

plt.subplot(211)
plt.title('2015年標準普爾500的收盤價')
plt.plot(close['2015'])

plt.subplot(212)
plt.title('2015年標準普爾500的RSV與KDJ線')
plt.plot(RSV['2015'])
plt.plot(KValue['2015'],linestyle='dashed')
plt.plot(DValue['2015'],linestyle='-.')
plt.plot(JValue['2015'],linestyle='--')

plt.subplots_adjust(hspace=0.4)     # 子圖間隔設置
plt.legend(loc='upper left')
plt.show()

結果如圖所示:
在這裏插入圖片描述
KDJ 指標的四種線圖與收盤價曲線走勢大致相同,在 KDJ 指標的四種線圖中,RSV線的波動幅度較大,K 線與 D 線的走勢很類似,J 線與 K 線、D 線走勢相比波動略大。在四種指標的取值上,RSV、K 值和 D 值的取值範圍都在 0~100 之間;而 J 值的取值可以超過 100,也可以低於0,例如,從 J 線圖中可以看出J值的取值範圍爲 -20~120。

6. KDJ指標交易策略

【1】在 KDJ 指標的取值上,K 值與 D 值的取值範圍是 0~100。

  • 依據K值與D值可以劃分出超買、超賣區,一般而言,K值或者D值取值在80以上爲超買區;K值或者D值取值在20以下爲超賣區。

【2】對於J 值,當J值大於 100,可以視爲超買區,當J值小於 0,視爲超賣區。

【3】此外,在 K 線、D 線的交叉情況也可以釋放出買入、賣出信號。

  • 當K線由下向上穿過 D 線時,即出現所謂“黃金交叉”現象,隱含股票價格上漲的動量較大,釋放出買入信號;當 K 線由上向下穿過 D 線時,出現“死亡交叉”現象,股票有下跌的趨勢,釋放出賣出信號。

7. KDJ 指標交易實測

【1】KD 指標交易策略

將 KDJ 指標運用於標普500中,通過 K 線、D 線分別捕捉超買點和超賣點,構造交易策略函數,計算 KD 指標交易策略的收益率,再對 KD 指標交易策略進行評價。

  • 計算 KD 指標釋放的買賣信號
# K、D值捕捉超買、超賣信號
# K值大於85,超買,signal=-1
# K值小於20,超賣,signal=1
# D值大於80,超買,signal=-1
# D值小於20,超賣,signal=1

KSignal = KValue.apply(lambda x: -1 if x>85 else 1 if x<20 else 0)
DSignal = DValue.apply(lambda x: -1 if x>80 else 1 if x<20 else 0)

KDSignal = KSignal + DSignal
KDSignal.name = 'KDSignal'

KDSignal[KDSignal>=1] == 1
KDSignal[KDSignal<=-1] == -1
  • 定義交易策略函數
# 定義交易策略函數
def trade(signal,price):
    ret = ((price-price.shift(1))/price.shift(1))[1:]
    ret.name = 'ret'
    signal = signal.shift(1)[1:]
    tradeRet = ret * signal + 0
    tradeRet.name = 'tradeRet'
    Returns = pd.merge(pd.DataFrame(ret),pd.DataFrame(tradeRet),left_index=True,
                       right_index=True).dropna()
    return(Returns)

KDtrade = trade(KDSignal,close)
KDtrade.rename(columns={'ret':'Ret','tradeRet':'KDtradeRet'},inplace=True)
  • KD 指標交易策略回測及評價
import ffn       # 事先安裝:pip install ffn   

# 構造回測函數
def backtest(ret,tradeRet):
    def performance(x):
        winpct=len(x[x>0])/len(x[x!=0])
        annRet=(1+x).cumprod()[-1]**(245/len(x))-1
        sharpe=ffn.calc_risk_return_ratio(x)
        maxDD=ffn.calc_max_drawdown((1+x).cumprod())
        perfo=pd.Series([winpct,annRet,sharpe,maxDD],index=['win rate','annualized                          return','sharpe ratio','maximum drawdown'])
        return(perfo)
    BuyAndHold=performance(ret)
    Trade=performance(tradeRet)
    return(pd.DataFrame({ret.name:BuyAndHold,tradeRet.name:Trade}))

# 對KD交易策略進行回測
import matplotlib.pyplot as plt
plt.figure(figsize=(10,6))

cumRets1=(1+KDtrade).cumprod()

plt.plot(cumRets1.Ret,label='Ret')
plt.plot(cumRets1.KDtradeRet,'--',label='KDtradeRet')

plt.title('KD指標交易策略績效表現')
plt.legend()
plt.show()

結果如圖所示:
在這裏插入圖片描述
漢代散文家桓寬曾提出:“明者因時而變,知者隨事而制”。在金融市場投資實戰中,更是如此。對比上圖可以看出,KD 指標在2014年上半年績效表現優秀,但在2014年下半年和2015年表現較差。在實際運用 KD 指標時,除了謹記指標有一定的適用情境以外,更要因時制宜,才能趨利避害。

【2】KDJ 指標交易策略

J 線綜合了 K 線和 D 線的信息,對於市場超買、超賣行情的判斷也有一定的作用。J 值取值範圍不侷限於0~100之間,但 J 值低於 0 或者高於 100 出現的時機不多,當 J 值低於 0 時或者高於100 時,預示着市場多空雙方的力量可能會出現一些微妙的變化,該指標往往會有較高的可靠程度。接下來,在 KD 指標的基礎上,加入 J 指標交易策略,修改買賣點交易信號,並進行交易後測。

# J值捕捉超買、超賣信號
# J值大於100,超買,signal=-1
# J值小於0  ,超賣,signal= 1

KSignal = KValue.apply(lambda x: -1 if x>85 else 1 if x<20 else 0)
DSignal = DValue.apply(lambda x: -1 if x>80 else 1 if x<20 else 0)
JSignal = JValue.apply(lambda x: -1 if x>100 else 1 if x<0 else 0)

KDJSignal = KSignal + DSignal + JSignal
KDJSignal = KDJSignal.apply(lambda x: 1 if x>=2 else -1 if x<=-2 else 0)

KDJtrade = trade(KDJSignal,close)
KDJtrade.rename(columns={'ret':'Ret','tradeRet':'KDJtradeRet'},inplace=True)
backtest(KDJtrade.Ret,KDJtrade.KDJtradeRet)

KDJCumRet = (1+KDJtrade).cumprod()

# 對KDJ交易策略進行回測
import matplotlib.pyplot as plt
plt.figure(figsize=(10,6))

plt.plot(KDJCumRet.Ret,label='Ret')
plt.plot(KDJCumRet.KDJtradeRet,'--',label='KDJtradeRet')

plt.title('KDJ指標交易策略績效表現')
plt.legend(loc='upper left')
plt.show()

結果如圖所示:
在這裏插入圖片描述
從上圖可以看出,KDJ 指標和KD指標交易策差別並沒體現出來(有待進一步探討及設置新的投資策略)。其實,如果仔細觀察2014年10月10日之前的績效,反而KD指標交易策略比KDJ指標交易策略要好的(當然這與對應策略買賣點的策略值的設置有關,感興趣的博友不妨編個程序遍歷跑一下,看看能不能選到最有的策略值)!

8. 展望

下一步,博主將繼續探討KDJ指標的其它交易策略(其他買賣策略值的選取以及KDJ策略的‘金叉’和‘死叉’等策略),敬請期待中!

參考資料:
  • 蔡立耑. 量化投資以Python爲工具[M]. 北京:電子工業出版社,2017.
數據下載
  • 請在留言區留下您的郵箱(其實任何其他標的的數據都可以替代)!

  • 寫作不易,切勿白剽
  • 博友們的點贊關注就是對博主堅持寫作的最大鼓勵
  • 持續更新,未完待續…
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章