多因子系列(一):实现一个小目标,从单因子出发!

一、概述

单因子模型最早由威廉·夏普提出。单因子模型的基本思路是:证券收益只受一个因素影响。市场模型便是这种模型的典型例子。

如果我们观察证券市场,就会发现,当市场股价指数上涨时,大部分股票价格也同时上涨;反之亦然。这说明,各种证券对一个因子,即市场股价指数的变化具有联动的反应。

二、模型公式

其中F是共同因子的预测值,beta为证券i对因子的灵敏度。

三、实现一个小策略

取上证50的股票作为股票池,手动选择一个因子,对股票按因子的数值大小进行排序,买入排序在前面的股票,每一周进行调仓。

# coding=utf-8
from __future__ import print_function, absolute_import
from gm.api import *
from gm.enum import OrderSide_Sell, OrderType_Market
import numpy as np
import pandas as pd
'''
股票池:上证50中的50支股票
选择股票池中BP因子数值排名前五的股票,
每个月进行调仓,排名前五的股票若没有持仓则买入,有持仓则继续持仓
'''
# 策略中必须有init方法
def init(context):
    context.index = 'SHSE.000016'
    context.num = 5  # 调仓时用到,委托排名前五的股票
    schedule(schedule_func=algo_1, date_rule='1w', time_rule='09:31:00')

def algo_1(context):
    now = context.now
    # 获取上证50成分股
    symbols = get_history_constituents(index='SHSE.000016',
                                       start_date=now,
                                       end_date=now)[0].get('constituents').keys()
    # 获取当前日期上证50构成的成分股,并提取其因子数据
    DF = get_fundamentals_n(table='trading_derivative_indicator',
                            symbols=symbols,
                            end_date=now,
                            count=1,
                            fields='PB',
                            df=True)
    # 计算账面市值比,为P/B的倒数
    DF['PB'] = (DF['PB'] ** -1)
    # 根据因子数据对股票进行排序
    df = DF.sort_values(['PB'], ascending=False)
    target_list = df['symbol'].values[:context.num]
    
    # 指定持仓
    # 获取现有所有持仓
    pos_all = context.account().positions()
    #对于持仓的标的,若不在所筛选出来的股票池中,则平掉该标的
    for i in pos_all:
        if i['symbol'] not in target_list:
            order_volume(symbol=i['symbol'], volume=i['available'], side=OrderSide_Sell, order_type=OrderType_Market, position_effect=PositionEffect_Open)
            print("平掉不在标的的股票:",i['symbol'],"数量为",i['available'])


    for symbol in target_list:
        pos = context.account().position(symbol=symbol,side = PositionSide_Long)
        #若目标标的不在持仓中,则开仓
        if not pos:
            order_target_percent(symbol=symbol, percent=1/context.num,
                                position_side=PositionSide_Long, order_type=OrderType_Market)
            print("市价买进股票:",symbol)


if __name__ == '__main__':
    run(strategy_id='xxxxxxxxxxx',
        filename='main.py',
        mode=MODE_BACKTEST,
        token='xxxxxxxxxxxxxx',
        backtest_start_time='2020-11-01 08:00:00',
        backtest_end_time='2021-11-20 16:00:00',
        backtest_adjust=ADJUST_PREV,
        backtest_initial_cash=10000000,
        backtest_commission_ratio=0.0001,
        backtest_slippage_ratio=0.0001)

四、单因子测试

这里我们常使用以下三种方法:分组回测、信息系数评价、回归测试。以下内容将讲解这三种方法的内容,其中会给出信息系数评价和回归测试的代码,分组回测测试就请读者们完善啦~

1、分组回测:

回测方法—分位数

对股票按因子大小排序,将股票池均分为N个组合,或者对每个行业内进行均分。

个股权重一般选择等权,行业间权重一般与基准(例如沪深300)的行业配比相同,此时的组合为行业中性。

通过分组累计收益图,就可以简单的知道因子是否和收益率有着单调递增或递减的关系。

2、信息系数评价 :

信息系数(Information Coefficient,简称IC ),表示所选股票的因子值与股票下期收益率的截面相关系数,通过IC值可以判断因子值对下期收益率的预测能力。

IC值能够很好地反映因子的预测能力,IC越高,就表明该因子在该期对股票收益的预测能力越强。 通常IC大于3%或者小于-3%,则认为因子比较有效。

常见的IC有两种,一是Normal IC (类比皮尔森相关系数概念),另一个是Rank IC (类比斯皮尔曼相关系数) 。

  • Normal IC:即某时点某因子在全部股票的暴露值与其下期回报的截面相关系数。

  • Rank IC:某时点某因子在全部股票暴露值排名与其下期回报排名的截面相关系数。

比如我们需要计算当前时间的因子Normal IC值,其代码如下:

import datetime
#获取当前日期和时间
now_time = datetime.datetime.now()
#格式化
now_time=now_time.strftime('%Y-%m-%d')
# 获取上证50成分股
symbols = get_history_constituents(index='SHSE.000016',
                                   start_date=now_time,
                                   end_date=now_time)[0].get('constituents').keys()

# 获取当前日期上证50构成的成分股,并提取其因子数据
DF = get_fundamentals_n(table='trading_derivative_indicator',
                        symbols=symbols,
                        end_date=now_time,
                        count=1,
                        fields='PB',
                        df=True)
# 计算账面市值比,为P/B的倒数
#2021.8.25的因子暴露值
yz=DF['PB']
#2021.8.25的股票收益,8.25的股票收益-8.24的收盘价/8.24的收盘价
a=[]
for i in DF['symbol']:    
    history_n_data = history_n(symbol=str(""+i+""), frequency='1d', count=2, end_time='2021-10-25', fields='close', adjust=ADJUST_PREV, df=True)
    a.append((history_n_data['close'][1]-history_n_data['close'][0])/history_n_data['close'][0])
np.corrcoef(a,yz) 
#得到结果如下:
#array([[1.        , 0.17563877],
#       [0.17563877, 1.        ]])

IR 信息比率:

IR信息比率是IC的均值除以标准差,也就是IC值在回测时间段内的信息比率。可以评估因子的Alpha超额收益获取能力,并且是更稳定的获取能力。

 鉴于IC的重要性,在多因子的因子加权中常采用因子最近N个月(默认为12)的IC均值加权,通常结果会优于等权法。

IC_IR评价:

1)Rank IC值序列均值一因子显著性;

2)Rank IC值序列标准差一因子稳定性;

3)IC_IR(Rank IC值序列均值与标准差的比值)一因子有效性;

4)Rank IC值序列大于零的占比一因子作用方向是否稳定。

主要方法的代码如下:

# 计算一组数据的IC绝对值均值、正向比例、均值/标准差
def ics_return(l):

    # 信息系数绝对值均值
    a = [abs(i) for i in l]
    avr_ic = sum(a) / len(l)

    # 信息比例
    b = np.array(l)
    if b.std() != 0:
        ir = b.mean() / b.std()
    else:
        ir = 0

    # 正向比例
    c = [i for i in l if i > 0]
    pr = len(c) / len(l)
    return avr_ic, ir, pr

3、回归测试:

具体做法是将第T期的因子暴露度向量与T+1期的股票收益向量进行线性回归,所得到的回归系数即为因子在T期的因子收益率,同时还能得到该因子收益率在本期回归中的显著度水平t值。

一般t值绝对值要大于2时因子比较有效。

在某截面期上的个股的因子暴露度(Factor Exposure)即指当前时刻个股在该因子上的因子值。

计算方法:

回归因子评价:

1)t值序列绝对值均值-因子显著性的重要判据;

2)t值序列绝对值大于2的占比-判断因子的显著性是否稳定;

3)t值序列均值一与a.结合,能判断因子t值正负方向是否稳定;

4)因子收益率序列均值-判断因子收益率的大小。

# 线性回归方程系数t检验值
def t_value(x, y):
    x2 = sum((x - np.mean(x)) ** 2)
    xy = sum((x - np.mean(y)) * (y - np.mean(y)))

    #回归参数的最小二乘估计
    beta1 = xy / x2
    beta0 = np.mean(y) - beta1 * np.mean(x)
    #输出线性回归方程
    # print('y=',beta0,'+',beta1,'*x')

    #方差
    sigma2 = sum((y - beta0 - beta1 * x) ** 2) / len(x)
    #标准差
    sigma = np.sqrt(sigma2)
    #求t值
    t = beta1 * np.sqrt(x2) / sigma
    return t

以上便是今天的所有内容,如有不足之处,还请多多包涵~欢迎大家在下方留言交流,也欢迎大家通过掘金社区分享个人的量化心得!后续我们将会陆续推出其余的系列文章,敬请期待~

声明:本内容首发至掘金量化公众号,仅供学习、交流、演示之用,不构成任何投资建议!如需转载原创文章请联系掘金小Q(myquant2018)

  • 1
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值