引 言

上一篇推文《什麼是多因子量化選股模型?》主要介紹了多因子模型產生的理論背景、基本原理和實現步驟,而《【手把手教你】Python量化Fama-French三因子模型》則對國內A股市場的三因子模型進行了實證分析。多因子量化模型研究的對象主要是因子,因此單因子的回測和有效性檢驗是整個多因子模型的重要組成部分。本文結合Python開源包Alphalens,以A股市場真實場景數據,手把手教你對單因子進行量化回測。Alphalens是Quantopian公司(美帝最大的量化回測平台之一,國內幾個基本上都是仿他們家的)三大知名Python開源包之一,其他兩個分別是Zipline(策略回測,一直沒安裝成功)和Pyfolio(策略分析)。Alphalens主要提供因子收益分析、因子IC分析、因子換手分析和事件研究等回測框架,由於簡單易上手和科學穩定等優點,是量化分析師最常用的回測工具包之一。

數據預處理

數據預處理是使用Alphalens做單因子回測的最主要工作,包括獲因子數據,數據歸一化和異常值處理等,將原始數據整理成符合要求的格式後,後面的分析就變得很簡單,基本上都是一行代碼搞掂。本文以市盈率(PE)指標為例,使用tushare的每日指標介面(daily_basic)獲取A股市場3000多隻股票2011-2019年收盤價和市盈率數據,為大家展示如何使用alphalens做單因子的歷史回測。

#先引入後面可能用到的包(package)
import alphalens #使用pip安裝即可
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

#正常顯示畫圖時出現的中文和負號
from pylab import mpl
mpl.rcParams[font.sans-serif]=[SimHei]
mpl.rcParams[axes.unicode_minus]=False

#還是使用tushare獲取數據
import tushare as ts
token=輸入token
pro=ts.pro_api(token)

#獲取當前交易的股票代碼和名稱
def get_code():
df = pro.stock_basic(exchange=, list_status=L)
#剔除2017年以後上市的新股次新股
df=df[df[list_date].apply(int).values<20170101]
#剔除st股
df=df[-df[name].apply(lambda x:x.startswith(*ST))]
codes=df.ts_code.values
return codes

df=pro.daily_basic(ts_code=get_code()[0],start_date=20110101)
for code in get_code()[1:]:
df1=pro.daily_basic(ts_code=code,start_date=20110101)
df=pd.concat([df,df1])

df_new=df.loc[:,[ts_code,trade_date,close,pe_ttm]]
df_new.loc[:,trade_date]=pd.to_datetime(df_new.trade_date)

#設定雙重重索引的數據格式
df_new=df_new.set_index([trade_date,ts_code])
#根據第一索引排序
df_new=df_new.sort_index()

#查看數據前幾行
df_new.head()

其中,pe_ttm是動態市盈率,是本文重點考察的單因子,數據預處理的第一步是建立以日期、股票代碼的雙重索引,如上表所示。先來看下全市場收盤價和市盈率的描述性統計,市盈率有440萬個觀測值(刪除了市盈率為負的觀測值),均值為206,標準差高達12698,最大值為2653832,而75%分位數才77.3,可見均值受極端值影響很大,有必要對原始數據進行歸一化和縮尾處理。factor_new是處理後的因子數據。prices是收盤價數據(前復權),必須轉化為日期為索引,列名是相應股票代碼或名稱格式的數據形式。

df_new.describe().round(2)#對數據進行縮尾處理,並進行標準化
def winsor_data(data):
q=data.quantile([0.02,0.98])
data[data<q.iloc[0]]=q.iloc[0]
data[data>q.iloc[1]]=q.iloc[1]
return data
#數據標準化
def MaxMinNormal(data):
"""[0,1] normaliaztion"""
x = (data - data.min()) / (data.max() - data.min())
return x

factor=df_new[pe_ttm].groupby(trade_date).apply(winsor_data)

factor_new=factor.groupby(trade_date).apply(MaxMinNormal)
factor_new.hist(figsize=(12,6),bins=20)

prices.head()

alphalens庫所用到是函數名稱都非常長,其中數據預處理函數是get_clean_factor_and_forward_returns,要想了解函數的詳細參數可以輸入help(函數名),這裡不考慮分組(行業),其他參數均使用默認,factor_new為因子數據,prices為收盤價數據,quantiles=10表示將數據分成10個分位數進行考察,period是調倉周期,10,20,60,表示分布考察10、20、60日調倉情況。進行到這一步,表明數據清洗工作已完成,下面主要圍繞單因子的收益率、信息比率和換手率進行回測和分析。

data=alphalens.utils.get_clean_factor_and_forward_returns(factor_new,prices,
quantiles=10,periods=(10,20,60))
data.head()

收益率分析Returns Analysis

單因子的收益率分析主要圍繞10、20、60日(可自己設定)調倉周期,將因子數據從小到大排列,分為10個分位數進行回測,一行代碼便可實現,但函數名稱實在太冗長了。第一張表報告了不同調倉期的alpha、beta、高分位(top quantile)和低分位(bottom quantile)的收益情況。柱狀圖清晰地顯示出該因子(市盈率)隨著分位的提高收益由正轉負,可見市盈率因子與股票收益存在一定的反向關係,即市盈率越小,未來收益越高,與理論和直覺基本一致。小提琴圖是多收益率的分布,60日調倉的收益更加集中,方差更小,收益率更加可信。 由於對因子進行了歸一化化處理,因此可以以因子值為權重構建一個全市場的股票組合進行回測。對於cumulative return by quantile的評價標準是累計收益率是否發散,越發散越好,說明因子的區分度越高,60天調倉期出現了明顯的發散。好的信號:波動小,在某一個方向的佔比處於絕對地位,如大部分的Top minus bottom都是正的。

alphalens.tears.create_returns_tear_sheet(data)

信息分析 Information analysis

信息分析說白了是考察IC和IR指標。IC全稱為Information Coefficient, 即信息係數,代表因子預測股票收益的能力。其原理是通過計算全部股票在調倉周期期初排名和調倉周期期末收益排名的線性相關度(correlation)。 不難理解,IC絕對值越大的因子,選股能力越強。IC的值在[-1,1]區間內,最大值為1,表示該因子100%準確,對應的是排名分最高的股票,選出來的股票在下個調倉周期中,漲幅最大;相反,如果IC為-1,則代表排名最高的股票,在下個調倉周期中,漲幅最大,是一個完全反向指標,也是非常有意義的,使用的時候反向操作即可。一般而言,當IC的絕對值<0.05時,說明該因子對於的股票沒有任何預測能力或較差,當IC絕對值>0.05時,因子選股能力有一定的意義,當IC大於0.5時因子穩定獲取超額收益能力較強。

IR全稱是Information Ratio,等於IC的多周期均值/IC的標準差,或等於超額收益均值/超額收益標準差,代表因子獲取穩定Alpha的能力。 整個回測時段由多個調倉期組成,每一個周期都會計算出一根不同的IC值,IR等於多個調倉周期的IC均值除以IC的標準差。因此IR兼顧了因子的選股能力和因子選股能力的穩定性,IR值越大越好。

information analysis表給出了每個調倉周期下,IC的均值、方差以及t統計量,還有偏度、峰度以及年化的IR。因子信息分析好的評判標準是:IC的均值較高,方差小,而t統計量大(一般大於2)或p-value小(一般小於5%)。從結果上看,PE因子的IC均值都比較小,看來不是很理想的選股因子偏度和峰度主要考察和正態分布的偏離程度,主要用於分析小概率事件的影響。

alphalens.tears.create_information_tear_sheet(data)

Q-Q plot圖是查看樣本分布與正態分布的對比情況,如果滿足正態分布,Q-Q圖上的點應該在y=x上。雖然有些IC的取值挺大的,但是尾部比較大,均值大是由於極度的尖峰和右偏造成的。還需具體考察IC的分布來決定一個因子的預測能力是不是可靠。

熱力圖提供了不同時間段因子的預測能力表現,有利於進行因子的情景分析。通過熱力圖我們可以輕易識別哪些時間段IC值比較好,哪些時間段IC比較差,有沒有突發的情況,然後可以對此進行情景分析。

ic=alphalens.performance.mean_information_coefficient(data,by_time=1y)

from pyecharts import Bar
attr=ic.index.strftime(%Y)
v1=list(ic[10D].round(2))
v2=list(ic[20D].round(2))
v3=list(ic[60D].round(2))
bar=Bar(IC均值:2006-2019)
bar.add(10D,attr,v1)
bar.add(20D,attr,v2)
bar.add(60D,attr,v3)
bar

因子換手率 Turnover analysis

實際交易是有手續費的,因子對單因子的回測還需要考慮換手率的影響,換手率越高說明交易次數越多,可能產生的手續費越高。如果一個因子,今天給一個股票打了很高的分,明天就打很低的分,這將導致對該股頻繁的買賣,從而造成很高的手續費。所以,因子的換手率分析也是很重要的一個部分。

還有一個角度可以查看因子造成的換手率高低,就是因子的自相關性。如果因子的自相關性低,那麼就一會兒高,一會兒低,往往會造成很大的換手率。而因子的自相關性高,就不會有這樣的問題。因子的截面換手率越低,因子的自相關性越高

alphalens.tears.create_turnover_tear_sheet(data)

結 語

本文以動態市盈率作為選股因子,旨在為大家展示如何利用alphalens進行單因子的歷史回測,沒有考慮行業或市值大小的分組因素影響,實戰應用到量化因子篩選時還需考慮更多因素和細節的處理,包括調倉周期和分位數確定等,本文僅提供一個因子量化回測的一般分析框架,不構成任何投資建議。關於alphalens的詳細使用教程可參看其官網或東北證券金融工程研報《Alphalens使用教程》,公眾號後台回復「Alphalens 」即可下載。


推薦閱讀:
相关文章