研报复现:《光大证券·多因子系列报告之二十二:再论动量因子》

Posted by @Ian666 on May 26, 2019

用于因子策略回测效果检查

本期研报来自于光大证券金融工程的多因子系列,基于大类因子动量因子的讨论——《光大证券·多因子系列报告之二十二:再论动量因子》

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
'''
根据聚宽高频因子挖掘大赛比赛专用模板修改
初始资金:2000000
建议回测时间范围
每日调仓 一年 回测日期:20180720-20190720
每周调仓 三年 回测日期:20160720-20190720
每月调仓 五年 回测日期:20140720-20190720

股票池:中证500
每日持仓:数量固定为股票池的20只,持仓均为等权重持有
换仓时间:默认14:50
交易成本:不考虑滑点,印花税1‰,佣金2.5‱、最低5元
'''

# 导入函数库
from jqdata import *
import numpy as np
import pandas as pd
import jqfactor

################################################# 以下内容根据研究因子内容定义 ########################################################

# 定义因子
def calc_factor(context):
    '''
    用户自定义因子,要求返回一个 Series,index为股票code,value为因子值
    我们会买入「因子值最小」的20只,如果您想使用买入「因子值最大」的20只股票,只需将您的结果「乘以-1.0」即可,详见函数下方 return 部分
    '''
    # 获取股票池,g.stock_pool为因子挖掘的对象股票池,用户不可对此股票池进行二次筛选
    stocks = g.stock_pool
    # 获取当前时间
    now  =  context.current_dt
    # 获取数据
    df = get_price(stocks,end_date=context.previous_date,count=21,fields=['close'])['close'] 
    far = df.iloc[-1,:]/df.iloc[0,:] - 1
    
    ###### 中性化等数据处理模块,用户根据需要决定是否使用 ######
    # 中位数去极值
    # far = jqfactor.winsorize_med(far, scale=3, inclusive=True, inf2nan=True)
    # # 行业市值对数中性化
    far = jqfactor.neutralize(far, how=['market_cap'], date=g.d)
    # # zscore标准化
    # far = jqfactor.standardlize(far, inf2nan=True)
    # 去除 nan 值
    # far = far.dropna()
    
    return far
    #如想选择因子值最大的20只股票,请注释上方`return far`。使用下方的return:
    # return far * -1.0
    

# 开盘前运行函数
def before_market_open(context):
    '''
    盘后运行函数,可选实现
    '''
    pass

## 收盘后运行函数
def after_market_close(context):
    '''
    盘后运行函数,可选实现
    '''
    pass



################################################# 以下内容除设置运行周期,其他地方不用修改 ########################################################

# 初始化函数,设定基准等等
def initialize(context):
    # 设定500等权作为基准
    g.benchmark = '000982.XSHG'
    set_benchmark(g.benchmark)
    # 开启动态复权模式(真实价格)
    set_option('use_real_price', True)
    ### 股票相关设定 ###
    # 股票类每笔交易时的手续费
    set_order_cost(OrderCost(close_tax=0.001, open_commission=0.00025, close_commission=0.00025, min_commission=5),type='stock')
    # 滑点
    set_slippage(FixedSlippage(0.0))
    # 初始化因子设置
    factor_analysis_initialize(context)
    # 定义股票池
    set_stockpool(context)
    # 运行函数(reference_security为运行时间的参考标的;传入的标的只做种类区分,因此传入'000300.XSHG'或'510300.XSHG'是一样的)
    run_daily(set_stockpool, time='before_open', reference_security='000300.XSHG')
    run_daily(before_market_open, time='before_open', reference_security='000300.XSHG')
    
    #设置策略交易时间间隔
    #run_daily(trade, time='14:50', reference_security='000300.XSHG')
    run_weekly(trade,1, time='14:50', reference_security='000300.XSHG')
    #run_monthly(trade,1, time='14:50', reference_security='000300.XSHG')
    
    run_daily(after_market_close, time='after_close', reference_security='000300.XSHG')

# 定义股票池
def set_stockpool(context):
    # 获取股票池
    stocks = get_index_stocks(g.benchmark,context.previous_date)
    paused_series = get_price(stocks,end_date=context.current_dt,count=1,fields='paused')['paused'].iloc[0]
    # g.stock_pool 为因子挖掘的对象股票池,用户不可对此股票池进行二次筛选
    g.stock_pool =  paused_series[paused_series==False].index.tolist()

# 定义需要用到的全局变量
def factor_analysis_initialize(context):
    # g.weight_method 为加权方式, "avg"按平均加权
    g.weight_method = "avg"
    weight_method_model = {"avg": "平均加权"}
    # 持仓股票数量
    g.buy_num = 20
    # g.sell为卖出股票权重列表
    g.sell = pd.Series(dtype=float)
    # g.buy为买入股票权重列表
    g.buy = pd.Series(dtype=float)
    #g.ind为行业分类
    g.ind = 'jq_l1'
    # g.d 为获取昨天的时间点
    g.d = context.previous_date

# 对因子进行分析计算出每日买入或卖出的股票
def fac(context):
    # 获取因子值
    far = calc_factor(context)
    # 买入股票池
    try:
        buy = far.sort_values(ascending=True).index.tolist()[:g.buy_num]
    except:
        buy = far.order(ascending=True).index.tolist()[:g.buy_num]
    # 买卖股票权重
    if g.weight_method == "avg":
        buy_weight = pd.Series(1. / len(buy), index=buy)
    else:
        raise ValueError('invalid weight_method %s', weight_method)

    return buy_weight

#股票交易
def trade(context):
    # 计算买入卖出的股票和权重
    try:
        factor_analysis_initialize(context)
        g.buy = fac(context)
    except ValueError:
        if "Bin edges must be unique" in str(e):
            log.error("计算因子值过程出错!")
        else:
            raise
    
    for s in context.portfolio.positions.keys():
        if s not in g.buy.index:
            order_target_value(s, 0)
    

    long_cash = context.portfolio.total_value
    for s in g.buy.index:
        order_target_value(s, g.buy.loc[s] * 0.98 * long_cash)

# 买入股票
def buy(context):
    # 计算买入卖出的股票和权重
    try:
        factor_analysis_initialize(context)
        g.buy = fac(context)
    except ValueError:
        if "Bin edges must be unique" in str(e):
            log.error("计算因子值过程出错!")
        else:
            raise
    long_cash = context.portfolio.total_value
    for s in g.buy.index:
        order_target_value(s, g.buy.loc[s] * 0.98 * long_cash)

# 卖出股票
def sell(context):
    for s in context.portfolio.positions.keys():
        order_target_value(s, 0)
        

请先从下面内容开始

因子分析基础模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#导入需要的数据库
from jqfactor import *
from jqdata import *
import pandas as pd
import warnings  
warnings.filterwarnings('ignore') 

#获取日期列表
def get_tradeday_list(start,end,frequency=None,count=None):
    if count != None:
        df = get_price('000001.XSHG',end_date=end,count=count)
    else:
        df = get_price('000001.XSHG',start_date=start,end_date=end)
    if frequency == None or frequency =='day':
        return df.index
    else:
        df['year-month'] = [str(i)[0:7] for i in df.index]
        if frequency == 'month':
            return df.drop_duplicates('year-month').index
        elif frequency == 'quarter':
            df['month'] = [str(i)[5:7] for i in df.index]
            df = df[(df['month']=='01') | (df['month']=='04') | (df['month']=='07') | (df['month']=='10') ]
            return df.drop_duplicates('year-month').index
        elif frequency =='halfyear':
            df['month'] = [str(i)[5:7] for i in df.index]
            df = df[(df['month']=='01') | (df['month']=='06')]
            return df.drop_duplicates('year-month').index 

===初始化====

1
2
3
4
5
6
7
8
9
10
# 设置起止时间
start='2016-07-01'
end='2019-07-01'
# 设置调仓周期
periods=(5,10,20)
# 设置分层数量
quantiles=5
#获取日期列表
date_list = get_tradeday_list(start=start,end=end,count=None)#获取回测日期间的所有交易日
date_list
1
2
3
4
5
6
7
8
DatetimeIndex(['2016-07-01', '2016-07-04', '2016-07-05', '2016-07-06',
               '2016-07-07', '2016-07-08', '2016-07-11', '2016-07-12',
               '2016-07-13', '2016-07-14',
               ...
               '2019-06-18', '2019-06-19', '2019-06-20', '2019-06-21',
               '2019-06-24', '2019-06-25', '2019-06-26', '2019-06-27',
               '2019-06-28', '2019-07-01'],
              dtype='datetime64[ns]', length=730, freq=None)

===原始计算因子数据===

  • 进行因子值函数定义

  • 循环日期获取因子值

股票价格的动量(Momentum) , 顾名思义代表的是股价在一定时间内延续前期走势的现象。 不过与海外长期的研究和经验相悖的是, 在 A 股市场, 我们发现股价的反转(Reverse) 效应要远强于动量效应, 且短期反转因子的历史收益非常出色。

但常用动量因子也存在单调性不佳, 多头收益不稳定的问题, 因此参考研报我们尝试从不同角度出发对动量因子进行改造, 寻找提升常用动量因子选股 效果和稳定性的方法。

在该多因子系列报告中, 曾给出过动量类因子的因子测试结论, 报告中测试的几个常用动量因子,也是我们经常接触到的基础动量因子,明细如下

下面我们将以统计周期为21天的动量因子为例进行探索演示

1
2
3
4
5
6
#定义要计算的动量因子
def factor_cal(pool,date):
    df = get_price(pool,end_date=date,count=21,fields=['close'])['close'] 
    far = df.iloc[-1,:]/df.iloc[0,:] - 1
    return far
factor_cal(['000001.XSHE','600000.XSHG'],'2019-07-12')
1
2
3
000001.XSHE    0.142395
600000.XSHG   -0.022901
dtype: float64
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#定义一个空的dataframe记录因子值
factor_df = pd.DataFrame()
#循环计算给定日期范围的因子值
mark = 1
for d in date_list:
    pool = get_index_stocks('000905.XSHG',date=d)
    far = factor_cal(pool,d)
    if mark == 1:
        factor_df = far
        mark = 0
    else:
        factor_df = pd.concat([far,factor_df],axis=1)
#将columns更改为可以日期标签
factor_df.columns = date_list
factor_df.head(3)
2016-07-01 00:00:00 2016-07-04 00:00:00 2016-07-05 00:00:00 2016-07-06 00:00:00 2016-07-07 00:00:00 2016-07-08 00:00:00 2016-07-11 00:00:00 2016-07-12 00:00:00 2016-07-13 00:00:00 2016-07-14 00:00:00 2016-07-15 00:00:00 2016-07-18 00:00:00 2016-07-19 00:00:00 2016-07-20 00:00:00 2016-07-21 00:00:00 2016-07-22 00:00:00 2016-07-25 00:00:00 2016-07-26 00:00:00 2016-07-27 00:00:00 2016-07-28 00:00:00 2016-07-29 00:00:00 2016-08-01 00:00:00 2016-08-02 00:00:00 2016-08-03 00:00:00 2016-08-04 00:00:00 2016-08-05 00:00:00 2016-08-08 00:00:00 2016-08-09 00:00:00 2016-08-10 00:00:00 2016-08-11 00:00:00 2016-08-12 00:00:00 2016-08-15 00:00:00 2016-08-16 00:00:00 2016-08-17 00:00:00 2016-08-18 00:00:00 2016-08-19 00:00:00 2016-08-22 00:00:00 2016-08-23 00:00:00 2016-08-24 00:00:00 2016-08-25 00:00:00 ... 2019-05-06 00:00:00 2019-05-07 00:00:00 2019-05-08 00:00:00 2019-05-09 00:00:00 2019-05-10 00:00:00 2019-05-13 00:00:00 2019-05-14 00:00:00 2019-05-15 00:00:00 2019-05-16 00:00:00 2019-05-17 00:00:00 2019-05-20 00:00:00 2019-05-21 00:00:00 2019-05-22 00:00:00 2019-05-23 00:00:00 2019-05-24 00:00:00 2019-05-27 00:00:00 2019-05-28 00:00:00 2019-05-29 00:00:00 2019-05-30 00:00:00 2019-05-31 00:00:00 2019-06-03 00:00:00 2019-06-04 00:00:00 2019-06-05 00:00:00 2019-06-06 00:00:00 2019-06-10 00:00:00 2019-06-11 00:00:00 2019-06-12 00:00:00 2019-06-13 00:00:00 2019-06-14 00:00:00 2019-06-17 00:00:00 2019-06-18 00:00:00 2019-06-19 00:00:00 2019-06-20 00:00:00 2019-06-21 00:00:00 2019-06-24 00:00:00 2019-06-25 00:00:00 2019-06-26 00:00:00 2019-06-27 00:00:00 2019-06-28 00:00:00 2019-07-01 00:00:00
000006.XSHE 0.050943 0.028302 0.018450 0.007326 -0.005396 0.048872 0.070881 0.033582 0.005525 0.013084 0.009276 -0.030576 -0.019856 0.000000 -0.005464 -0.037906 -0.024164 -0.029358 -0.043557 -0.014870 -0.100170 -0.098639 -0.084459 -0.085427 -0.113238 -0.146067 -0.171429 -0.171561 -0.162037 -0.183206 -0.184569 -0.151145 -0.171898 -0.182229 -0.187870 -0.192420 -0.214599 -0.208999 -0.203757 -0.202963 ... 0.121523 0.138235 0.116312 0.118741 0.153515 0.172805 0.155492 0.139403 0.135838 0.089744 0.059829 0.060734 0.097561 0.098694 0.080344 0.105036 0.052260 -0.018841 -0.032117 0.013353 0.008863 0.000000 0.027697 0.027941 0.034125 0.063253 0.050975 0.074924 0.056489 0.057229 0.090062 0.089231 0.092476 0.081633 0.044978 0.038864 0.044248 0.016200 0.007353 0.008982
000008.XSHE 0.021053 -0.015666 0.015915 0.000000 0.018667 0.054348 0.048649 0.005249 -0.018135 -0.026178 -0.038560 -0.064838 -0.049875 -0.038071 -0.045000 -0.074813 -0.061224 -0.048223 -0.062814 -0.047859 -0.112150 -0.088095 -0.158482 -0.149888 -0.198718 -0.210300 -0.206009 -0.197895 -0.180467 -0.204167 -0.186192 -0.150424 -0.166320 -0.184265 -0.175258 -0.188259 -0.190083 -0.205645 -0.189409 -0.179752 ... -0.065789 -0.065541 -0.082524 -0.088462 -0.070260 -0.102830 -0.088292 -0.083734 -0.084615 -0.103612 -0.099906 -0.035748 -0.073446 -0.068868 -0.054650 -0.071361 -0.103286 -0.089623 -0.089720 -0.064333 -0.080074 -0.035441 0.011788 0.031746 0.046324 0.042281 0.012634 0.007759 -0.074733 -0.108475 -0.100085 -0.111204 -0.071678 -0.046763 -0.130833 -0.122705 -0.069056 -0.066079 -0.060579 -0.072807
000009.XSHE 0.010395 -0.024641 -0.022312 0.000000 0.026971 0.021277 0.004132 0.010526 -0.038855 -0.006466 -0.004292 -0.048880 -0.008282 0.010638 0.004219 -0.037815 -0.032538 -0.033403 -0.058704 -0.040900 -0.064202 0.010373 -0.040856 -0.062136 -0.126812 -0.139194 -0.149385 -0.192177 -0.114130 -0.163964 -0.158845 -0.102377 -0.113761 -0.142336 -0.156584 -0.166375 -0.194056 -0.198997 -0.143847 -0.159794 ... NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN NaN

进行因子数据优化

  • 标准化
  • 风格中性化

根据研报的观点,动量(反转) 效应的成因是投资者认识出现偏差,对信息的解读不够及时充分。 也可以认为动量(反转) 效应是来自于投资者认知偏差或者说噪音交易行为。

由此可以推测, 散户集中程度或者说流动性因素是影响动量因子效果的一个重要变量。 因此, 我们会自然的联想到采用截面中性化的方法, 将衡量散户集中程度的流动性因素从原始动量因子中剥离。

因此,我们接下来对原始因子数据进行特定风格中性化处理

1
2
3
4
5
6
7
8
9
10
#数据清洗、包括去极值、标准化、中性化等,并加入y值
for date in date_list:
    #对数据进行处理、标准化、去极值、中性化
    #factor_df = winsorize_med(factor_df, scale=3, inclusive=True, inf2nan=True, axis=0) #中位数去极值处理
    se = standardlize(factor_df[date], inf2nan=True) #对每列做标准化处理
    se = neutralize(se, how=['liquidity'], date=date)#剔除原始因子值与流动性相关的部分
    factor_df[date] = se
#进行转置,调整为分析可用的格式
factor_df = factor_df.T
factor_df.head()
000006.XSHE 000008.XSHE 000009.XSHE 000012.XSHE 000021.XSHE 000025.XSHE 000027.XSHE 000028.XSHE 000030.XSHE 000031.XSHE 000039.XSHE 000049.XSHE 000050.XSHE 000060.XSHE 000061.XSHE 000062.XSHE 000066.XSHE 000078.XSHE 000088.XSHE 000089.XSHE 000090.XSHE 000099.XSHE 000156.XSHE 000158.XSHE 000301.XSHE 000400.XSHE 000401.XSHE 000417.XSHE 000418.XSHE 000426.XSHE 000488.XSHE 000501.XSHE 000513.XSHE 000517.XSHE 000519.XSHE 000528.XSHE 000536.XSHE 000537.XSHE 000541.XSHE 000543.XSHE ... 603169.XSHG 603188.XSHG 603198.XSHG 603225.XSHG 603228.XSHG 603233.XSHG 603328.XSHG 603355.XSHG 603369.XSHG 603377.XSHG 603444.XSHG 603486.XSHG 603501.XSHG 603515.XSHG 603517.XSHG 603528.XSHG 603555.XSHG 603556.XSHG 603567.XSHG 603568.XSHG 603569.XSHG 603589.XSHG 603650.XSHG 603658.XSHG 603659.XSHG 603698.XSHG 603699.XSHG 603712.XSHG 603766.XSHG 603799.XSHG 603806.XSHG 603816.XSHG 603866.XSHG 603868.XSHG 603877.XSHG 603883.XSHG 603885.XSHG 603888.XSHG 603899.XSHG 603939.XSHG
2016-07-01 0.116279 -0.230939 -0.307165 -0.018065 -1.115277 -0.499227 0.232659 -0.346900 NaN 0.389321 0.668226 NaN NaN -0.652505 -0.651069 -0.937019 0.396109 -1.316769 NaN 0.703391 0.010869 NaN -1.094827 -0.483434 0.537527 -0.068281 0.746313 NaN NaN 0.537537 -0.392134 0.041164 0.888780 NaN -0.476111 0.022197 -0.153983 -0.448221 -0.196065 -0.029184 ... NaN NaN 1.036071 NaN NaN NaN 0.215926 0.173149 1.773804 -1.312008 NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.237745 NaN NaN NaN NaN NaN NaN NaN NaN -0.025671 NaN 0.632709 NaN 0.346798 -0.040118 NaN 0.128373 0.359723 NaN NaN 1.315883
2016-07-04 0.231738 -0.280201 -0.303062 -0.054342 -0.708107 -0.221434 0.410154 -0.384254 NaN 0.312459 0.584113 NaN NaN -0.682699 -0.757832 -1.067445 0.567712 -1.425293 NaN 0.421777 0.139029 NaN -0.910318 -0.872446 0.751647 0.068043 0.191558 NaN NaN 0.781548 -0.224895 0.127288 0.943820 NaN 0.083240 -0.075114 -0.934088 -0.378330 -0.062909 0.267830 ... NaN NaN 1.074967 NaN NaN NaN 0.288378 0.627841 1.260432 -1.129653 NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.391451 NaN NaN NaN NaN NaN NaN NaN NaN -0.219668 NaN 0.930923 NaN 0.998194 0.677699 NaN 0.143252 0.843557 NaN NaN 1.788913
2016-07-05 0.035329 0.031336 -0.389137 0.010385 -0.971491 -0.465154 0.334051 -0.545740 NaN 0.111782 0.568943 NaN NaN -0.143460 -0.339332 -1.027743 -0.403524 -1.595908 NaN 0.354445 0.175401 NaN -0.776015 -0.617827 0.937806 -0.076594 -0.094896 NaN NaN 1.046214 -0.245540 -0.034545 0.371119 NaN 0.308446 -0.106853 -1.002989 -0.551899 -0.055793 -0.113595 ... NaN NaN 1.324256 NaN NaN NaN 0.344898 0.317328 1.051565 -1.186974 NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.581834 NaN NaN NaN NaN NaN NaN NaN NaN -0.096823 NaN 0.731554 NaN 0.763084 0.362635 NaN -0.243363 0.714846 NaN NaN 1.708468
2016-07-06 -0.023627 -0.110300 -0.071705 0.118002 -0.776730 -0.069136 0.290735 -0.816949 NaN 0.059781 0.512792 NaN NaN -0.005006 -0.069321 -1.039786 -0.592182 -1.734341 NaN 0.263885 0.197672 NaN -0.648460 -0.622340 0.743690 -0.223395 0.732000 NaN NaN 1.132459 -0.027701 -0.034763 0.321193 NaN 0.837059 -0.021498 -0.937775 -0.567653 -0.151441 0.174682 ... NaN NaN 0.464886 NaN NaN NaN 0.035668 0.071702 0.982961 -1.789795 NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.735023 NaN NaN NaN NaN NaN NaN NaN NaN 0.045010 NaN 0.693245 NaN 0.929924 0.280750 NaN -0.573270 0.507304 NaN NaN 1.721318
2016-07-07 -0.195936 0.129881 0.289773 -0.142384 -0.822338 -0.166412 0.453323 -1.004299 NaN 0.030255 0.593486 NaN NaN 0.160475 -0.035896 -0.951212 -0.548201 -2.091365 NaN 0.275797 0.195717 NaN -0.249111 -0.351283 0.738504 0.026681 0.614991 NaN NaN 1.676250 -0.080624 -0.075823 -0.322200 NaN 0.777190 0.059828 -1.196252 -0.510519 -0.217232 0.269244 ... NaN NaN 0.502855 NaN NaN NaN -0.116687 0.143196 0.821851 -1.334644 NaN NaN NaN NaN NaN NaN NaN NaN NaN 1.621746 NaN NaN NaN NaN NaN NaN NaN NaN 0.032007 NaN 0.401600 NaN 0.681191 0.167255 NaN -1.033837 0.613974 NaN NaN 0.615488

注意!!! 需要将处理好的factor_df格式设置为:

factor_df是dataframe格式 index 为日期 columns 是股票名称 将满足如上格式内容的df传入下面的效果模板即可

因子效果检查

在调整了因子数据格式之后,接下来的部分,我们将利用聚宽的因子分析模板,对计算好的因子进行收益分析。

我们将通过如下三个方面进行因子效果检查

1.IC信息比率

2.分组收益

3.换手率

在收益分析中, 分位数的平均收益, 第一分位数的因子值最小, 第五分位数的因子值最大。

分位数收益: 表示持仓5、10、20天后,各分位数可以获得的平均收益。

1
2
#使用获取的因子值进行单因子分析
far = analyze_factor(factor=factor_df, start_date=date_list[0], end_date=date_list[-1], weight_method='avg', industry='jq_l1', quantiles=quantiles, periods=periods,max_loss=0.3)

IC分析

1
2
# 打印信息比率(IC)相关表
far.plot_information_table(group_adjust=False, method='rank')
1
IC 分析
period_5 period_10 period_20
IC Mean 0.015 0.022 0.027
IC Std. 0.095 0.104 0.115
IR 0.153 0.213 0.236
t-stat(IC) 4.141 5.742 6.372
p-value(IC) 0.000 0.000 0.000
IC Skew 1.382 2.254 3.426
IC Kurtosis 6.463 12.271 21.551

IC分析:

以上展示了该因子的IC分析数据,通常来讲,我们主要观察的两个指标是IC值与IR值。

从分析结果我们看到,在持仓5天、10天、20天的分组中,持仓20天收益IC均值最大,IR信息比率最高,但是IC值不到0.03,说明该因子效果也有待提升。

分组收益

1
2
# 画各分位数平均收益图
far.plot_quantile_returns_bar(by_group=False, demeaned=0, group_adjust=False)

分组收益分析:

从五分组平均收益来看,基本上是有较为明显的分组效果,随着因子值1-5组从小到大的过程,分组跌幅也从大到小的变化。

从不同持仓周期看,持仓20天(绿色柱子)收益递增关系看起来更稳定一些

换手率分析

1
2
# 打印换手率表
far.plot_turnover_table()
1
换手率分析
period_10 period_20 period_5
Quantile 1 Mean Turnover 0.572 0.791 0.408
Quantile 2 Mean Turnover 0.723 0.799 0.631
Quantile 3 Mean Turnover 0.734 0.774 0.657
Quantile 4 Mean Turnover 0.724 0.801 0.626
Quantile 5 Mean Turnover 0.543 0.781 0.377
period_5 period_10 period_20
Mean Factor Rank Autocorrelation 0.695 0.434 -0.035

换手率分析:

因子的换手率是在不同的时间周期下, 观察因子个分位中个股的进出情况。 计算方法举例: 某因子第一分位持有的股票数量为30支, 5天后有一只发生变动, 换手率为:

1/30 *100% = 3.33%

对于10日、20日的换手率,在每日都会对比当日1、5分位数的成分股与10日、20日前该分位数的成分股的变化进行计算。

从该分析结果我们看到,5、10、20不同持仓周期,5日换手率最低,20日换手率最高,1-5分组无明显区别

因子效果检查综述

结论:

通过以上IC分析、分组收益检查、换手率分析,我们初步对该示例因子有了一定了解

该因子有一定的收益预测能力,但是不够显著,最好的IC均值为0.027,不到0.03,存在分组效果,换手率在与因子统计周期一致是换手率最高,因子效果有待进一步优化提升

因子分析信息全览¶

具体说明可参考:

https://www.joinquant.com/help/api/help?name=factor#%E5%9B%A0%E5%AD%90%E5%88%86%E6%9E%90%E7%BB%93%E6%9E%9C

在收益分析中, 分位数的平均收益, 各分位数的累积收益, 以及分位数的多空组合收益三方面观察因子的表现。 第一分位数的因子值最小, 第五分位数的因子值最大。

分位数收益: 表示持仓5、10、20天后,各分位数可以获得的平均收益。

分位数的累积收益: 表示各分位数持仓收益的累计值。

多空组合收益: 做多五分位(因子值最大), 做空一分位(因子值最小)的投资组合的收益。

1
2
#调用因子分析方法,进行因子信息全览
far.create_full_tear_sheet(demeaned=False, group_adjust=False, by_group=False, turnover_periods=None, avgretplot=(5, 15), std_bar=False)
1
分位数统计
min max mean std count count %
factor_quantile
1 -8.279978 -0.500532 -1.176277 0.583761 72161 20.039267
2 -0.817781 -0.098838 -0.451522 0.132272 71930 19.975118
3 -0.457317 0.318954 -0.081340 0.124523 71936 19.976784
4 -0.095478 0.908593 0.330095 0.166710 71930 19.975118
5 0.306781 13.933795 1.392986 0.944940 72141 20.033713
1
2
3
-------------------------

收益分析
period_5 period_10 period_20
Ann. alpha 0.026 0.031 0.031
beta -0.018 -0.028 -0.012
Mean Period Wise Return Top Quantile (bps) 0.300 -0.117 -0.306
Mean Period Wise Return Bottom Quantile (bps) -2.163 -2.534 -2.431
Mean Period Wise Spread (bps) 2.571 2.557 2.167
1
2
3
-------------------------

IC 分析
period_5 period_10 period_20
IC Mean 0.015 0.022 0.027
IC Std. 0.095 0.104 0.115
IR 0.153 0.213 0.236
t-stat(IC) 4.141 5.742 6.372
p-value(IC) 0.000 0.000 0.000
IC Skew 1.382 2.254 3.426
IC Kurtosis 6.463 12.271 21.551
1
2
3
-------------------------

换手率分析
period_10 period_20 period_5
Quantile 1 Mean Turnover 0.572 0.791 0.408
Quantile 2 Mean Turnover 0.723 0.799 0.631
Quantile 3 Mean Turnover 0.734 0.774 0.657
Quantile 4 Mean Turnover 0.724 0.801 0.626
Quantile 5 Mean Turnover 0.543 0.781 0.377
period_5 period_10 period_20
Mean Factor Rank Autocorrelation 0.695 0.434 -0.035
1
-------------------------    <img src='http://i.caigoubao.cc/627139/bgpc/20190526/output_29_43.png'/>

错误提醒: factor_df = pd.concat([far,factor_df],axis=1) 应为 factor_df = pd.concat([factor_df,far],axis=1)

本文采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议(CC BY-NC-ND 4.0)进行许可,转载请注明出处,请勿用于任何商业用途采用。

☛决定关注我了吗☚