实战之单因子回测框架
概述
之前我们在研究平台上所做的因子 IC 分析和因子收益率分析都属于因子的测试框架. 因为我们使用的第三方平台, 所以没有办法做一个比较完整的通用的测试系统. 但是目的是为了测试表现较好的, 所以本节我们来建立一个测试系统.
因子排名
统计完结果之后我们需要对上百个因子进行一次筛选.
构建打分依据:
- 因子平均收益 > 0.002
- IC > 0.02
- IR > 0.3
- 对于 3 项标准中的每一项进行打分, 每满足一项打分为 1, 然后每个因子看的多少分
单因子回测框架
当筛选出部分因子之后, 其实我们还要去观察它在回测过程当中的真实收益率情况. 所以要建立每个因子的回测框架, 主要对不同分为数上的股票收益进行统计. 也就是下面这张图:
代码实现
代码
# 建立单因子的回测框架
# 回测区间2020-01-01到2021-01-01
import numpy as np
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。
def init(context):
# 在context中保存全局变量
context.quantile = 5
scheduler.run_monthly(factor_rollback, tradingday=1)
def factor_rollback(context, bar_dict):
# 选出因子数据, 选出不同组的位置进行回测
q = query(
fundamentals.financial_indicator.earnings_per_share
)
fund = get_fundamentals(q)
# 转置
fund = fund.T
# 去极值, 标准化
fund["earnings_per_share"] = mad(fund["earnings_per_share"])
fund["earnings_per_share"] = stand(fund["earnings_per_share"])
# 求分位数是对于一列数据, df求不了
data = fund.iloc[:, 0]
# 按照分位去分成5组, 分别进行回测
if context.quantile == 1:
data = data[data <= data.quantile(0.2)]
elif context.quantile == 2:
data = data[(data > data.quantile(0.2)) & (data <= data.quantile(0.4))]
elif context.quantile == 3:
data = data[(data > data.quantile(0.4)) & (data <= data.quantile(0.6))]
elif context.quantile == 4:
data = data[(data > data.quantile(0.6)) & (data <= data.quantile(0.8))]
elif context.quantile == 5:
data = data[data > data.quantile(0.8)]
# 建立回测的股票池
context.stock_list = data.index
# ----------------卖出----------------
# 遍历股票池
for stock in context.portfolio.positions.keys():
# 判断是否还在股票池
if stock not in context.stock_list:
# 如果不在, 卖出
order_target_percent(stock, 0)
# ----------------买入-----------------
# 买入的百分比
weight = 1.0 / len(context.stock_list)
# 遍历股票池
for stock in context.stock_list:
# 等比例买入
order_target_percent(stock, weight)
# before_trading此函数会在每天策略交易开始前被调用,当天只会被调用一次
def before_trading(context):
pass
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
def handle_bar(context, bar_dict):
# 开始编写你的主要的算法逻辑
pass
def mad(factor):
"""3倍中位数去极值"""
# 求出因子值的中位数
median = np.median(factor)
# 求出因子值与中位数的差值, 进行绝对值
mad = np.median(abs(factor - median))
# 定义几倍的中位数上下限
high = median + (3 * 1.4826 * mad)
low = median - (3 * 1.4826 * mad)
# 替换上下限
factor = np.where(factor > high, high, factor)
factor = np.where(factor < low, low, factor)
return factor
def stand(factor):
"""数据标准化"""
mean = factor.mean()
std = factor.std()
return (factor - mean) / std