本文是對報(bào)告《20100210-華泰證券-數(shù)量化策略:大小盤輪動》、《20161218-中金公司-價(jià)量視角下的市值風(fēng)格輪動策略》部分內(nèi)容的復(fù)制,文章為個人理解,不保證正確性,請理性看待,歡迎指正。A股市場上存在著明顯的大小盤輪動的現(xiàn)象,一段時間大盤表現(xiàn)強(qiáng)勢,一段時間小盤表現(xiàn)強(qiáng)勢,所謂二八輪動。這種現(xiàn)象提供了構(gòu)建大小盤輪動策略的可能,目前常見的兩種構(gòu)建大小盤輪動策略的方式分別為 宏觀層面出發(fā),分析影響市場價(jià)格變動的政策、利率、GDP、供需數(shù)據(jù)等,以此構(gòu)建模型分析市場當(dāng)前的大小盤風(fēng)格; 技術(shù)角度出發(fā),通過量價(jià)數(shù)據(jù)構(gòu)建指標(biāo),分析市場當(dāng)前的大小盤風(fēng)格。
兩種方式各有優(yōu)劣,本文復(fù)制的兩篇報(bào)告均屬于第二種方式。 以交易時點(diǎn)劃分,可以將市場上的交易行為劃分為兩類:左側(cè)交易與右側(cè)交易。 左側(cè)交易:在價(jià)格即將達(dá)到某個支撐點(diǎn)時逆向進(jìn)入市場,做反轉(zhuǎn)。 右側(cè)交易:在價(jià)格走出趨勢之后進(jìn)入市場,做動量,也就是常說的追漲殺跌。 本文選取的兩種策略分別屬于這兩種策略,比較說明在同一指標(biāo)下,這兩種交易行為的優(yōu)劣,但不具有普遍性。 大盤指數(shù):HS300 小盤指數(shù):ZZ500 回測區(qū)間:2015年1月1日 - 2018年12月2日 數(shù)據(jù)來源:WIND 注:后臺回復(fù)“代碼”可獲取代碼文件和研報(bào) import pandas as pd import numpy as np from matplotlib import pyplot as plt from matplotlib.font_manager import FontProperties font = FontProperties(fname=r'c:\windows\fonts\simsun.ttc',size = 20) from WindPy import * w.start()
dateStart = date(2005,1,1) dateEnd = date(2018,12,2)
IndexClose = w.wsd('000300.SH,000905.SH', 'close', '{}'.format(dateStart), '{}'.format(dateEnd), '') Indexprice = pd.DataFrame(np.array(IndexClose.Data).T,columns=['hs300','ZZ500'],index = IndexClose.Times)
通過大小盤指數(shù)收盤價(jià)格構(gòu)造相對強(qiáng)弱指數(shù): 其中P1是中證500點(diǎn)位,P2是滬深300點(diǎn)位,回測區(qū)間內(nèi)的相對強(qiáng)弱指標(biāo)如圖所示 代碼(全文作圖代碼基本相同,之后不再列出)
Indexprice['P'] = np.log(Indexprice.ZZ500) - np.log(Indexprice.hs300) X = np.arange(Indexprice.shape[0]) xticklabel = Indexprice.index xticks = np.arange(0,Indexprice.shape[0]+1,np.int((Indexprice.shape[0]+1)/5))
plt.figure(figsize = [20,4]) SP = plt.axes() P1 = SP.plot(X,Indexprice.hs300,linewidth = 2,label = 'HS300',color = 'darkred') P2 = SP.plot(X,Indexprice.ZZ500,linewidth = 2,label = 'ZZ500',color = 'cornflowerblue') SP1 = SP.twinx() P3 = SP1.plot(X,Indexprice['P'],color = 'orange',linewidth = 2,label = u'相對強(qiáng)弱指數(shù)') SP.set_xticks(xticks) SP.set_xticklabels(xticklabel[xticks],size = 20) p = P1+P2+P3 lns = [l.get_label() for l in p]
plt.legend(p,lns,prop=font) plt.show()
相對強(qiáng)弱指標(biāo)的值大小沒有意義,并不是說大于0就傾向于小盤,小于0就傾向于大盤,兩個指數(shù)的點(diǎn)數(shù)之間數(shù)量上有差異,因此要關(guān)注指標(biāo)的變化趨勢。 指標(biāo)呈上升趨勢,說明當(dāng)前市場為小盤風(fēng)格,應(yīng)該投資小盤指數(shù),反之應(yīng)投資大盤指數(shù) 策略1為左側(cè)交易,首先計(jì)算指標(biāo)的MA10對數(shù)據(jù)進(jìn)行平滑,通過函數(shù)updownbound計(jì)算MA10的布林帶,若MA10上穿下軌,做多小盤股,若MA10下穿上軌,做多大盤。 布林帶定義 def updownbound(data,n,c): data['upbound'] = data['P'].rolling(window = n, center = False).mean() + c * data['P'].rolling(window = n, center = False).std() data['upbound'] = data['upbound'].shift(1) data['downbound'] = data['P'].rolling(window = n, center = False).mean() - c * data['P'].rolling(window = n, center = False).std() data['downbound'] = data['downbound'].shift(1) for i in range(2,n): data.loc[i,'upbound'] = data.loc[0:i - 1,'P'].mean() + c * data.loc[0:i - 1,'P'].std() data.loc[i,'downbound'] = data.loc[0:i - 1,'P'].mean() - c * data.loc[0:i - 1,'P'].std() data.loc[0,'upbound'] = 0 data.loc[0,'downbound'] = 0 data.loc[1,'upbound'] = data.loc[0,'P'] data.loc[1,'downbound'] = data.loc[0,'P'] return(data)
相對強(qiáng)弱指數(shù)、MA10及布林帶如下 策略規(guī)則 當(dāng) 10 日均線從下方上穿下軌,則做多小盤股,賣出大盤股,第二天開始算收益率。 當(dāng) 10 日均線從上方下穿上軌,則做空小盤股,做多大盤股,第二天開始算收益率。 其他的情形,不需要做什么操作,任何時候都是滿倉大盤股或者小盤股。
def strategy(data): data['flag_hs'] = 0 data['flag_zz'] = 0 data['ret_strategy'] = 0 data['ret_zz'] = data['ZZ500'].pct_change(1) data['ret_hs'] = data['hs300'].pct_change(1) data.loc[0,'ret_zz'] = 0 data.loc[0,'ret_hs'] = 0 for i in range(1,data.shape[0] - 1): # 上穿下軌,做多小盤,賣出大盤 if data.ma10[i - 1] < data.downbound[i - 1] and data.ma10[i] > data.downbound[i]: data.loc[i + 1 ,'flag_zz'] = 1 data.loc[i + 1 ,'flag_hs'] = 0 # data.loc[i + 1,'net_zz'] = data.loc[i ,'net_zz']*(1 + data.loc[i + 1,'ret_zz']) # data.loc[i + 1,'net_hs'] = data.loc[i ,'net_hs']*(1 - data.loc[i + 1,'ret_hs']) # 下穿上軌,做多大盤,賣出小盤 elif data.ma10[i - 1] > data.upbound[i - 1] and data.ma10[i] < data.upbound[i]: data.loc[i + 1 ,'flag_zz'] = 0 data.loc[i + 1 ,'flag_hs'] = 1 # data.loc[i + 1,'net_zz'] = data.loc[i ,'net_zz']*(1 - data.loc[i + 1,'ret_zz']) # data.loc[i + 1,'net_hs'] = data.loc[i ,'net_hs']*(1 + data.loc[i + 1,'ret_hs']) else: data.loc[i + 1 ,'flag_zz'] = data.loc[i ,'flag_zz'] data.loc[i + 1 ,'flag_hs'] = data.loc[i ,'flag_hs'] data.loc[data['flag_zz'] ==1,'ret_strategy'] = data.loc[data['flag_zz'] ==1,'ret_zz'] data.loc[data['flag_hs'] ==1,'ret_strategy'] = data.loc[data['flag_hs'] ==1,'ret_hs'] data['net_strategy_zz'] = (1 + data['flag_zz']*data['ret_zz']).cumprod() data['net_strategy_hs'] = (1 + data['flag_hs']*data['ret_hs']).cumprod() data['net_strategy'] = (1 + data['ret_strategy']).cumprod() return data
回測結(jié)果如下,藍(lán)色為策略收益,淺藍(lán)色為小盤指數(shù)的凈值,紅色為大盤指數(shù)的凈值,綠色為持倉情況,值為1表示持有的是大盤,值為2表示持有的是小盤。 策略凈值為4.96,整體來看,這種策略的優(yōu)勢僅在于交易次數(shù)很小,但基本沒有超額收益。 再從其他方面考察策略: 上圖為策略相對于大盤和小盤指數(shù)的表現(xiàn),可以看出策略在16年之前優(yōu)于大盤,而在整個區(qū)間內(nèi)與小盤指數(shù)基本持平。 分年統(tǒng)計(jì)來看,策略并沒有表現(xiàn)出持續(xù)優(yōu)于大盤指數(shù)或者優(yōu)于小盤指數(shù)。 整體來看,策略效果不盡人意。分析原因,主要在于市場在2008-2015年之間出現(xiàn)了長期的震蕩行情,16年之后至今也是震蕩下行,沒有出現(xiàn)明顯的趨勢性,因此很難觸發(fā)策略條件。 策略2采取趨勢突破的方法,創(chuàng)新高時買入小盤指數(shù),創(chuàng)新低時買入大盤指數(shù)。 報(bào)告中相對強(qiáng)弱指數(shù)定義如下 與前文定義的指標(biāo)相差一個常數(shù),對結(jié)果沒有影響,仍采用前文定義。
策略規(guī)則: 相對強(qiáng)弱指數(shù)創(chuàng)新N1日新高,持有小盤 相對強(qiáng)弱指數(shù)創(chuàng)N2日新低,持有大盤
def strategy1(data,N1,N2,fee_ratio = 0): data['flag_hs'] = 0 data['flag_zz'] = 0 data['ret_strategy'] = 0 data['buysell'] = 0 data['ret_zz'] = data['ZZ500'].pct_change(1).fillna(0) data['ret_hs'] = data['hs300'].pct_change(1).fillna(0) for i in range(max(N1,N2),data.shape[0] - 1): # 創(chuàng)新高,做多小盤 if data.P[i] >= np.max(data.P[i - N1:i]): data.loc[i + 1 ,'flag_zz'] = 1 data.loc[i + 1 ,'flag_hs'] = 0 # data.loc[i + 1,'net_zz'] = data.loc[i ,'net_zz']*(1 + data.loc[i + 1,'ret_zz']) # data.loc[i + 1,'net_hs'] = data.loc[i ,'net_hs']*(1 - data.loc[i + 1,'ret_hs']) # 創(chuàng)新低,做多大盤 elif data.P[i] <= np.min(data.P[i - N2:i]): data.loc[i + 1 ,'flag_zz'] = 0 data.loc[i + 1 ,'flag_hs'] = 1
# data.loc[i + 1,'net_zz'] = data.loc[i ,'net_zz']*(1 - data.loc[i + 1,'ret_zz']) # data.loc[i + 1,'net_hs'] = data.loc[i ,'net_hs']*(1 + data.loc[i + 1,'ret_hs']) else: data.loc[i + 1 ,'flag_zz'] = data.loc[i ,'flag_zz'] data.loc[i + 1 ,'flag_hs'] = data.loc[i ,'flag_hs'] data.loc[data['flag_zz'] ==1,'ret_strategy'] = data.loc[data['flag_zz'] ==1,'ret_zz'] data.loc[data['flag_hs'] ==1,'ret_strategy'] = data.loc[data['flag_hs'] ==1,'ret_hs']
data.loc[data['flag_hs'] != data.flag_hs.shift(1),'buysell'] = 1 data.loc[0,'buysell'] = 0 data['ret_strategy'] = data['ret_strategy'] - fee_ratio*data['buysell'] #data['net_strategy_zz'] = (1 + data['flag_zz']*data['ret_zz']).cumprod() #data['net_strategy_hs'] = (1 + data['flag_hs']*data['ret_hs']).cumprod() data['net_strategy'] = (1 + data['ret_strategy']).cumprod() return data
fee_ratio為手續(xù)費(fèi)率,設(shè)定為0,取N1 = 20,N2 = 20,回測結(jié)果如下
最優(yōu)參數(shù)下,策略凈值為7.52,從凈值曲線來看,明顯優(yōu)于策略1,有超額回報(bào),但交易次數(shù)增多,交易成本也會上升。 此外,今年以來策略出現(xiàn)明顯回撤,但整個市場都在下跌,可以通過策略與大小盤指數(shù)的相對強(qiáng)弱來說明策略相對于市場的表現(xiàn) 可以看出,策略2持續(xù)性優(yōu)于或持平大小盤指數(shù)。 分年統(tǒng)計(jì)表明,除了16,17年,策略相對于滬深300每年都有正收益。 總體來看,策略2明顯優(yōu)于策略1(但并不是說右側(cè)交易一定優(yōu)于左側(cè)交易,只是這一指標(biāo)下)。 中金報(bào)告中指數(shù),N1,N2處于15-25時,策略表現(xiàn)都很好。對N1,N2從5到30進(jìn)行遍歷,看看策略在不同參數(shù)下的表現(xiàn)情況。 橫縱軸分別為N1,N2,豎軸/顏色表示策略累計(jì)收益率,顏色越深表明策略累積收益率越大,從圖可以看出,最優(yōu)參數(shù)存在于平面左下區(qū)域,即N1,N2較小時。 取最優(yōu)參數(shù)N1 = 8,N2 = 10做回測結(jié)果如下 最優(yōu)參數(shù)下,凈值為12.78。 相對于市場走勢平穩(wěn),回測區(qū)間內(nèi)均持平或上升。 分年統(tǒng)計(jì)來看,除個別年份,每年對于大小盤指數(shù)都有明顯超額收益,表現(xiàn)很好。 1. 20100210-華泰證券-數(shù)量化策略:大小盤輪動 2. 20161218-中金公司-量化策略專題風(fēng)格輪動研究(1):價(jià)量視角下的市值風(fēng)格輪動策略
Python的愛好者社區(qū)歷史文章大合集: Python的愛好者社區(qū)歷史文章列表(每周追加更新一次)
|