https://guorn.com/
果仁網(wǎng)~? ?大家不妨打開看看
這次主要想看看計算機在量化里面的應(yīng)用,然后白天自己補充補充
如下:
量化選股-多因子模型
總體分為基本面選股、市場行為選股模狭。基本面選股包括:多因子模型,風(fēng)格輪動模型衙传,行業(yè)輪動模型。市場行為選股包括:資金流選股厕九,動量反轉(zhuǎn)模型蓖捶,一致預(yù)期模型,趨勢追蹤模型和籌碼選股扁远。
今天要講的是多因子模型俊鱼。
多因子選股模型是廣泛應(yīng)用的一種方法。采用一系列的因子作為選股標(biāo)準(zhǔn)畅买,滿足則買入亭引,不滿足則賣出。不同的市場時期總有一些因子在發(fā)揮作用皮获,該模型相對來說比較穩(wěn)定焙蚓。
模型的優(yōu)點是可以綜合很多信息后給出一個選股結(jié)果。選取的因子不同以及如何綜合各個因子得到最終判斷的方法不同會產(chǎn)生不同的模型洒宝。一般來說购公,綜合因子的方法有打分法和回歸法兩種,打分法較為常見雁歌。
模型構(gòu)建實例
選取09-15年做樣本期宏浩,進行因子檢驗。
benchmark = 000001.XSHG
一.備選因子選取
根據(jù)市場經(jīng)驗和經(jīng)濟邏輯選取靠瞎。選擇更多和更有效的因子能增強模型信息捕獲能力比庄。 如一些基本面指標(biāo)(PB、PE乏盐、EPS佳窑、增長率),技術(shù)面指標(biāo)(動量父能、換手率神凑、波動),或其他指標(biāo)(預(yù)期收益增長、分析師一致預(yù)期變化溉委、宏觀經(jīng)濟變量)鹃唯。
結(jié)合JQ能提供的數(shù)據(jù),具體選取以下三個方面的因子:
(1)估值:賬面市值比(B/M)瓣喊、盈利收益率(EPS)坡慌、動態(tài)市盈(PEG)
(2)成長性:ROE、ROA藻三、主營毛利率(GP/R)洪橘、凈利率(P/R)
(3)資本結(jié)構(gòu):資產(chǎn)負(fù)債(L/A)、固定資產(chǎn)比例(FAP)趴酣、流通市值(CMV)
下面就上述10個因子的有效性進行驗證。
二.因子有效性檢驗
采用排序的方法檢驗備選因子的有效性坑夯。
對任一個因子岖寞,從第一個月月初計算市場每只股票該因子的大小,從小到大對樣本股票池排序柜蜈,平均分為n個組合仗谆,一直持有到月末。每月初用同樣的方法調(diào)整股票池淑履。運用一定樣本時期的數(shù)據(jù)來建立模型隶垮。
0.導(dǎo)入所需庫
In [1]:
import pandas as pdfrom pandas import Series, DataFrameimport numpy as npimport statsmodels.api as smimport scipy.stats as scsimport matplotlib.pyplot as plt
1.每月初取所有因子數(shù)值(以2015-01-01為例)
(1)估值:賬面市值比(B/M)、盈利收益率(EPS)秘噪、動態(tài)市盈(PEG)
(2)成長性:ROE狸吞、ROA、主營毛利率(GP/R)指煎、凈利率(P/R)
(3)資本結(jié)構(gòu):資產(chǎn)負(fù)債(L/A)蹋偏、固定資產(chǎn)比例(FAP)、流通市值(CMV)
In [2]:
factors = ['B/M','EPS','PEG','ROE','ROA','GP/R','P/R','L/A','FAP','CMV']#月初取出因子數(shù)值def get_factors(fdate,factors):? ? stock_set = get_index_stocks('000001.XSHG',fdate)? ? q = query(? ? ? ? valuation.code,? ? ? ? balance.total_owner_equities/valuation.market_cap/100000000,? ? ? ? income.basic_eps,? ? ? ? valuation.pe_ratio,? ? ? ? income.net_profit/balance.total_owner_equities,? ? ? ? income.net_profit/balance.total_assets,? ? ? ? income.total_profit/income.operating_revenue,? ? ? ? income.net_profit/income.operating_revenue,? ? ? ? balance.total_liability/balance.total_assets,? ? ? ? balance.fixed_assets/balance.total_assets,? ? ? ? valuation.circulating_market_cap? ? ? ? ).filter(? ? ? ? valuation.code.in_(stock_set),? ? ? ? valuation.circulating_market_cap? ? )? ? fdf = get_fundamentals(q, date=fdate)? ? fdf.index = fdf['code']? ? fdf.columns = ['code'] + factors? ? return fdf.iloc[:,-10:]fdf = get_factors('2015-01-01',factors)fdf.head()
Out[2]:
2.對每個因子按大小排序(以'B/M'為例)
In [3]:
score = fdf['B/M'].order()score.head()
Out[3]:
code600301.XSHG? -0.045989600444.XSHG? -0.029723600228.XSHG? -0.026231600217.XSHG? -0.026090600876.XSHG? -0.010862Name: B/M, dtype: float64
股票池中股票數(shù)目
In [4]:
len(score)
Out[4]:
966
3.按分值將股票池五等分構(gòu)造組合port1-5
In [5]:
startdate = '2015-01-01'enddate = '2015-02-01'nextdate = '2015-03-01'df = {}CMV = fdf['CMV']port1 = list(score.index)[: len(score)/5]port2 = list(score.index)[ len(score)/5: 2*len(score)/5]port3 = list(score.index)[ 2*len(score)/5: -2*len(score)/5]port4 = list(score.index)[ -2*len(score)/5: -len(score)/5]port5 = list(score.index)[ -len(score)/5: ]
Out[5]:
15066.599999999999
4.函數(shù)-計算組合月收益(按流通市值加權(quán))
In [6]:
defcaculate_port_monthly_return(port,startdate,enddate,nextdate,CMV):close1=get_price(port,startdate,enddate,'daily',['close'])close2=get_price(port,enddate,nextdate,'daily',['close'])weighted_m_return=((close2['close'].ix[0,:]/close1['close'].ix[0,:]-1)*CMV).sum()/(CMV.ix[port].sum())returnweighted_m_returncaculate_port_monthly_return(port1,'2015-01-01','2015-02-01','2015-03-01',fdf['CMV'])
Out[6]:
0.042660461430416276
5.函數(shù)-計算benchmark月收益
In [7]:
def caculate_benchmark_monthly_return(startdate,enddate,nextdate):? ? close1 = get_price(['000001.XSHG'],startdate,enddate,'daily',['close'])['close']? ? close2 = get_price(['000001.XSHG'],enddate, nextdate, 'daily',['close'])['close']? ? benchmark_return = (close2.ix[0,:]/close1.ix[0,:]-1).sum()? ? return benchmark_returncaculate_benchmark_monthly_return('2015-01-01','2015-02-01','2015-03-01')
Out[7]:
-0.06632375461831419
6.觀察5個組合在2015-01-01日構(gòu)建起一個月內(nèi)的收益情況
In [8]:
benchmark_return = caculate_benchmark_monthly_return(startdate,enddate,nextdate)df['port1'] =? caculate_port_monthly_return(port1,startdate,enddate,nextdate,CMV)df['port2'] = caculate_port_monthly_return(port2,startdate,enddate,nextdate,CMV)df['port3'] = caculate_port_monthly_return(port3,startdate,enddate,nextdate,CMV)df['port4'] = caculate_port_monthly_return(port4,startdate,enddate,nextdate,CMV)df['port5'] = caculate_port_monthly_return(port5,startdate,enddate,nextdate,CMV)print Series(df)print 'benchmark_return %s'%benchmark_return
Out[8]:
port1? ? 0.042660port2? -0.047200port3? ? 0.012783port4? -0.063027port5? -0.117817dtype: float64benchmark_return -0.0663237546183
7.構(gòu)建因子組合并計算每月?lián)Q倉時不同組合的月收益率
數(shù)據(jù)范圍:2009-2015共7年
得到結(jié)果monthly_return為panel數(shù)據(jù)至壤,儲存所有因子威始,在7×12個月內(nèi)5個組合及benchmark的月收益率
In [9]:
factors = ['B/M','EPS','PEG','ROE','ROA','GP/R','P/R','L/A','FAP','CMV']#因為研究模塊取fundmental數(shù)據(jù)默認(rèn)date為研究日期的前一天。所以要自備時間序列像街。按月取year = ['2009','2010','2011','2012','2013','2014','2015']month = ['01','02','03','04','05','06','07','08','09','10','11','12']result = {}for i in range(7*12):? ? startdate = year[i/12] + '-' + month[i%12] + '-01'? ? try:? ? ? ? enddate = year[(i+1)/12] + '-' + month[(i+1)%12] + '-01'? ? except IndexError:? ? ? ? enddate = '2016-01-01'? ? try:? ? ? ? nextdate = year[(i+2)/12] + '-' + month[(i+2)%12] + '-01'? ? except IndexError:? ? ? ? if enddate == '2016-01-01':? ? ? ? ? ? nextdate = '2016-02-01'? ? ? ? else:? ? ? ? ? ? nextdate = '2016-01-01'? ? print 'time %s'%startdate? ? fdf = get_factors(startdate,factors)? ? CMV = fdf['CMV']? ? #5個組合黎棠,10個因子? ? df = DataFrame(np.zeros(6*10).reshape(6,10),index = ['port1','port2','port3','port4','port5','benchmark'],columns = factors)? ? for fac in factors:? ? ? ? score = fdf[fac].order()? ? ? ? port1 = list(score.index)[: len(score)/5]? ? ? ? port2 = list(score.index)[ len(score)/5+1: 2*len(score)/5]? ? ? ? port3 = list(score.index)[ 2*len(score)/5+1: -2*len(score)/5]? ? ? ? port4 = list(score.index)[ -2*len(score)/5+1: -len(score)/5]? ? ? ? port5 = list(score.index)[ -len(score)/5+1: ]? ? ? ? df.ix['port1',fac] = caculate_port_monthly_return(port1,startdate,enddate,nextdate,CMV)? ? ? ? df.ix['port2',fac] = caculate_port_monthly_return(port2,startdate,enddate,nextdate,CMV)? ? ? ? df.ix['port3',fac] = caculate_port_monthly_return(port3,startdate,enddate,nextdate,CMV)? ? ? ? df.ix['port4',fac] = caculate_port_monthly_return(port4,startdate,enddate,nextdate,CMV)? ? ? ? df.ix['port5',fac] = caculate_port_monthly_return(port5,startdate,enddate,nextdate,CMV)? ? ? ? df.ix['benchmark',fac] = caculate_benchmark_monthly_return(startdate,enddate,nextdate)? ? ? ? print 'factor %s'%fac? ? result[i+1]=dfmonthly_return = pd.Panel(result)
8.取某個因子的5個組合收益情況('L/A'為例)
In [10]:
monthly_return[:,:,'L/A']
Out [10]:
In [11]:
(monthly_return[:,:,'L/A'].T+1).cumprod().tail()
Out [11]:
9.因子檢驗量化指標(biāo)
模型建立后,計算n個組合的年化復(fù)合收益镰绎、超額收益脓斩、不同市場情況下高收益組合跑贏benchmark和低收益組合跑輸benchmark的概率。
檢驗有效性的量化標(biāo)準(zhǔn):
(1)序列1-n的組合畴栖,年化復(fù)合收益應(yīng)滿足一定排序關(guān)系俭厚,即組合因子大小與收益具有較大相關(guān)關(guān)系。假定序列i的組合年化收益為Xi,則Xi與i的相關(guān)性絕對值A(chǔ)bs(Corr(Xi,i))>MinCorr驶臊。此處MinCorr為給定的最小相關(guān)閥值挪挤。
(2)序列1和n表示的兩個極端組合超額收益分別為AR1叼丑、ARn。MinARtop扛门、MinARbottom表示最小超額收益閥值鸠信。
if AR1 > ARn #因子越小,收益越大
則應(yīng)滿足AR1 > MinARtop >0 and ARn < MinARbottom < 0
if AR1 < ARn #因子越小论寨,收益越大
則應(yīng)滿足ARn > MinARtop >0 and AR1 < MinARbottom < 0
以上條件保證因子最大和最小的兩個組合星立,一個明顯跑贏市場,一個明顯跑輸市場葬凳。
(3) 在任何市場行情下绰垂,1和n兩個極端組合,都以較高概率跑贏or跑輸市場火焰。
以上三個條件劲装,可以選出過去一段時間有較好選股能力的因子。
In [12]:
total_return = {}annual_return = {}excess_return = {}win_prob = {}loss_prob = {}effect_test = {}MinCorr = 0.3Minbottom = -0.05Mintop = 0.05for fac in factors:? ? effect_test[fac] = {}? ? monthly = monthly_return[:,:,fac]? ? total_return[fac] = (monthly+1).T.cumprod().iloc[-1,:]-1? ? annual_return[fac] = (total_return[fac]+1)**(1./6)-1? ? excess_return[fac] = annual_return[fac]- annual_return[fac][-1]? ? #判斷因子有效性? ? #1.年化收益與組合序列的相關(guān)性 大于 閥值? ? effect_test[fac][1] = annual_return[fac][0:5].corr(Series([1,2,3,4,5],index = annual_return[fac][0:5].index))? ? #2.高收益組合跑贏概率? ? #因子小昌简,收益小占业,port1是輸家組合,port5是贏家組合? ? if total_return[fac][0] < total_return[fac][-2]:? ? ? ? loss_excess = monthly.iloc[0,:]-monthly.iloc[-1,:]? ? ? ? loss_prob[fac] = loss_excess[loss_excess<0].count()/float(len(loss_excess))? ? ? ? win_excess = monthly.iloc[-2,:]-monthly.iloc[-1,:]? ? ? ? win_prob[fac] = win_excess[win_excess>0].count()/float(len(win_excess))? ? ? ? ? ? ? ? effect_test[fac][3] = [win_prob[fac],loss_prob[fac]]? ? ? ? ? ? ? ? #超額收益? ? ? ? effect_test[fac][2] = [excess_return[fac][-2]*100,excess_return[fac][0]*100]? ? ? ? ? ? ? ? #因子小纯赎,收益大谦疾,port1是贏家組合,port5是輸家組合? ? else:? ? ? ? loss_excess = monthly.iloc[-2,:]-monthly.iloc[-1,:]? ? ? ? loss_prob[fac] = loss_excess[loss_excess<0].count()/float(len(loss_excess))? ? ? ? win_excess = monthly.iloc[0,:]-monthly.iloc[-1,:]? ? ? ? win_prob[fac] = win_excess[win_excess>0].count()/float(len(win_excess))? ? ? ? ? ? ? ? effect_test[fac][3] = [win_prob[fac],loss_prob[fac]]? ? ? ? ? ? ? ? #超額收益? ? ? ? effect_test[fac][2] = [excess_return[fac][0]*100,excess_return[fac][-2]*100]#effect_test[1]記錄因子相關(guān)性犬金,>0.5或<-0.5合格#effect_test[2]記錄【贏家組合超額收益念恍,輸家組合超額收益】#effect_test[3]記錄贏家組合跑贏概率和輸家組合跑輸概率⊥砬辏【>0.5,>0.4】合格(因?qū)嶋H情況樊诺,跑輸概率暫時不考慮)DataFrame(effect_test)
Out[12]:
檢驗結(jié)果,同時滿足上述三個條件的5個有效因子(粗體):
(1)估值:賬面市值比(B/M)音同、盈利收益率(EPS)词爬、動態(tài)市盈(PEG)
(2)成長性:ROE、ROA权均、主營毛利率(GP/R)顿膨、凈利率(P/R)
(3)資本結(jié)構(gòu):資產(chǎn)負(fù)債(L/A)、固定資產(chǎn)比例(FAP)叽赊、流通市值(CMV)
其中:CMV恋沃,F(xiàn)AP,PEG三個因子越小收益越大;B/M必指,P/R越大收益越大
(1)有效因子的總收益和年化收益
小市值妖孽D矣健!按CMV因子排序時,CMV小的組合總收益14.6倍梅割,年化58%霜第!總收益第二名是FAP的port2,達(dá)到2.71倍户辞。(這也是造成FAP組合收益相關(guān)性稍低的原因)
In [13]:
effective_factors = ['B/M','PEG','P/R','FAP','CMV']DataFrame(total_return).ix[:,effective_factors]
Out[13]:
In [14]:
DataFrame(annual_return).ix[:,effective_factors]
Out[14]:
(2)有效因子組合和benchmark收益率展示
In [15]:
def draw_return_picture(df):? ? plt.figure(figsize =(10,4))? ? plt.plot((df.T+1).cumprod().ix[:,0], label = 'port1')? ? plt.plot((df.T+1).cumprod().ix[:,1], label = 'port2')? ? plt.plot((df.T+1).cumprod().ix[:,2], label = 'port3')? ? plt.plot((df.T+1).cumprod().ix[:,3], label = 'port4')? ? plt.plot((df.T+1).cumprod().ix[:,4], label = 'port5')? ? plt.plot((df.T+1).cumprod().ix[:,5], label = 'benchmark')? ? plt.xlabel('return of factor %s'%fac)? ? plt.legend(loc=0)for fac in effective_factors:? ? draw_return_picture(monthly_return[:,:,fac])
Out [15]:
3.冗余因子的剔除
(僅給出思路泌类,此處因子較少不做這一步)
有些因子,因為內(nèi)在的邏輯比較相近等原因底燎,選出來的組合在個股構(gòu)成和收益等方面相關(guān)性較高刃榨。所以要對這些因子做冗余剔除,保留同類因子中收益最好双仍、區(qū)分度最高的因子枢希。具體步驟:
(1)對不同因子的n個組合打分。收益越大分值越大朱沃。分值達(dá)到好將分值賦給每月該組合內(nèi)的所有個股苞轿。
if AR1 > ARn #因子越小,收益越大
則組合i的分值為(n-i+1)
if AR1 < ARn #因子越小为流,收益越小
則組合i的分值為i
(2)按月計算個股不同因子得分的相關(guān)性矩陣呕屎。得到第t月個股的因子得分相關(guān)性矩陣Score_Corrt,u,v让簿。u,v為因子序號敬察。
(3)計算樣本期內(nèi)相關(guān)性矩陣的平均值。即樣本期共m個月尔当,加總矩陣后取1/m莲祸。
(4)設(shè)定得分相關(guān)性閥值MinScoreCorr。只保留與其他因子相關(guān)性較小的因子椭迎。
4.模型建立和選股
根據(jù)選好的有效因子锐帜,每月初對市場個股計算因子得分,按一定權(quán)重求得所有因子的平均分畜号。如遇因子當(dāng)月無取值時缴阎,按剩下的因子分值求加權(quán)平均。通過對個股的加權(quán)平均得分進行排序简软,選擇排名靠前的股票交易蛮拔。
以下代碼段等權(quán)重對因子分值求和,選出分值最高的股票進行交易痹升。
(1)模型構(gòu)建
In [16]:
def score_stock(fdate):? ? #CMV建炫,F(xiàn)AP,PEG三個因子越小收益越大,分值越大,應(yīng)降序排疼蛾;B/M肛跌,P/R越大收益越大應(yīng)順序排? ? effective_factors = {'B/M':True,'PEG':False,'P/R':True,'FAP':False,'CMV':False}? ? fdf = get_factors(fdate)? ? score = {}? ? for fac,value in effective_factors.items():? ? ? ? score[fac] = fdf[fac].rank(ascending = value,method = 'first')? ? print DataFrame(score).T.sum().order(ascending = False).head(5)? ? score_stock = list(DataFrame(score).T.sum().order(ascending = False).index)? ? return score_stock,fdf['CMV']def get_factors(fdate):? ? factors = ['B/M','PEG','P/R','FAP','CMV']? ? stock_set = get_index_stocks('000001.XSHG',fdate)? ? q = query(? ? ? ? valuation.code,? ? ? ? balance.total_owner_equities/valuation.market_cap/100000000,? ? ? ? valuation.pe_ratio,? ? ? ? income.net_profit/income.operating_revenue,? ? ? ? balance.fixed_assets/balance.total_assets,? ? ? ? valuation.circulating_market_cap? ? ? ? ).filter(? ? ? ? valuation.code.in_(stock_set)? ? )? ? fdf = get_fundamentals(q,date = fdate)? ? fdf.index = fdf['code']? ? fdf.columns = ['code'] + factors? ? return fdf.iloc[:,-5:][score_result,CMV] = score_stock('2016-01-01')
Out [16]:
code600382.XSHG? ? 4274600638.XSHG? ? 4224600291.XSHG? ? 4092600791.XSHG? ? 4078600284.XSHG? ? 4031dtype: float64
In [17]:
year = ['2009','2010','2011','2012','2013','2014','2015']month = ['01','02','03','04','05','06','07','08','09','10','11','12']factors = ['B/M','PEG','P/R','FAP','CMV']result = {}for i in range(7*12):? ? startdate = year[i/12] + '-' + month[i%12] + '-01'? ? try:? ? ? ? enddate = year[(i+1)/12] + '-' + month[(i+1)%12] + '-01'? ? except IndexError:? ? ? ? enddate = '2016-01-01'? ? try:? ? ? ? nextdate = year[(i+2)/12] + '-' + month[(i+2)%12] + '-01'? ? except IndexError:? ? ? ? if enddate == '2016-01-01':? ? ? ? ? ? nextdate = '2016-02-01'? ? ? ? else:? ? ? ? ? ? nextdate = '2016-01-01'? ? print 'time %s'%startdate? ? #綜合5個因子打分后,劃分幾個組合? ? df = DataFrame(np.zeros(7),index = ['Top20','port1','port2','port3','port4','port5','benchmark'])? ? [score,CMV] = score_stock(startdate)? ? port0 = score[:20]? ? port1 = score[: len(score)/5]? ? port2 = score[ len(score)/5+1: 2*len(score)/5]? ? port3 = score[ 2*len(score)/5+1: -2*len(score)/5]? ? port4 = score[ -2*len(score)/5+1: -len(score)/5]? ? port5 = score[ -len(score)/5+1: ]? ? print len(score)? ? df.ix['Top20'] = caculate_port_monthly_return(port1,startdate,enddate,nextdate,CMV)? ? df.ix['port1'] = caculate_port_monthly_return(port1,startdate,enddate,nextdate,CMV)? ? df.ix['port2'] = caculate_port_monthly_return(port2,startdate,enddate,nextdate,CMV)? ? df.ix['port3'] = caculate_port_monthly_return(port3,startdate,enddate,nextdate,CMV)? ? df.ix['port4'] = caculate_port_monthly_return(port4,startdate,enddate,nextdate,CMV)? ? df.ix['port5'] = caculate_port_monthly_return(port5,startdate,enddate,nextdate,CMV)? ? df.ix['benchmark'] = caculate_benchmark_monthly_return(startdate,enddate,nextdate)? ? result[i+1]=dfbacktest_results = pd.DataFrame(result)
(哈哈,此處結(jié)果下一次再公布~)
5.不足和改進
隨著模型使用人數(shù)的增加衍慎,有的因子會逐漸失效转唉,也可能出現(xiàn)一些新的因素需要加入到因子庫中。同時西饵,各因子的權(quán)重設(shè)計有進一步改進空間酝掩。模型本身需要做持續(xù)的再評價,并不斷改進來適應(yīng)市場的變化眷柔。