本文选择优矿平台介绍单因子测试流程,优矿是一个量化投资研究平台。大家可以免费注册使用。
1.市场中性策略
- 市场中性alpha策略是一类收益与市场涨跌无关,致力于获取绝对收益的低风险量化投资策略
- 其主要通过同时持有股票多头和期货空头,获取多头组合超越期货所对应基准指数的收益
2.单因子分析流程
- 策略的核心在于找到如上图一样能够稳健跑赢基准指数的多头组合
- 寻找组合的核心在于找到驱使股票获得超额收益的因子
- 本篇从单因子角度详细讲解研究步骤与细节
2.1 寻找单因子
- 符合经济、金融投资逻辑
- 数据来源:基本面、行情、分析师预期、大数据分析。。。
- 作为例子:以市盈率PE为例
2.2 构建因子
- 公式:PE = 每股价格/每股收益,将上式同时乘以总股本数就是,PE = 总市值/净利润
- 合理性:总市值是日度变化数据,净利润则是季度数据,为了对比的一致性以及结合企业经营的实际情况,一般采用TTM值(Trailing twelve months)TTM算法说明 – 对一般公司而言,每年会发布四次财务报表(一季报、半年报、三季报、年报) – 假设现在公布了该年的半年报,报表显示半年的净利润为A,那么首先要将半年报数据折算成年报数据,是否直接用2*A作为全年的净利润呢? – TTM(Trailing Twelve Months)采用过去12个月的完整数据来计算年度财报数据 – 假设我们同时知道去年的年报和半年报,净利润分别为B和C,那么最新的净利润(TTM)= A + B – C
- 投资理念:由于我们假定是低估值会获得超额收益,所以将因子调整为 EP = 净利润/总市值,这样因子值越大就代表越高的持仓权重
# 优矿里提供了400多个因子数据,将诸如TTM类似的标准化算法工程化,可利用DataAPI直接获取
pe = DataAPI.MktStockFactorsOneDayGet(secID=set_universe(‘HS300’),tradeDate=u”20160922″,field=u”secID,tradeDate,PE”,pandas=”1″).set_index(‘secID’)
pe.head()
# pe.plot(figsize=(14,5))
- 构建好EP因子之后并非直接可用,还需要将其转化为实际可用的信号(signal)
- 常见的因子处理:去极值winsorize、中性化neutralize、标准化standardize去极值winsorize:调整明显不合理的极值中性化neutralize:调整不同行业之间的差异,季节调整标准化standardize:去量纲、多因子可加性
- 通过上述处理过的因子,得到的信号分布更平滑、更合理
2.3 回测分析
- 回测区间:2010年1月1日~2016年9月1日,基准为沪深300,中证800成分股,策略每20天换仓一次
- 因子选取:市盈率PE
- 因子处理:用到了去极值(winsorize)、标准化(standardize)处理
- 组合构建:整体分位+风格中性权重
import pandas as pd
import numpy as np
start = ‘2019-01-01’
end = ‘2021-09-01’
benchmark = ‘HS300’ # 策略参考标准
universe = DynamicUniverse(‘HS300’) + DynamicUniverse(‘ZZ500’)
capital_base = 10000000 # 起始资金
freq = ‘d’ # 策略类型,’d’表示日间策略使用日线回测,’m’表示日内策略使用分钟线回测
refresh_rate = Monthly(1) # 调仓频率
accounts = {
‘fantasy_account’: AccountConfig(account_type=’security’, capital_base=10000000)
}
def initialize(context): # 初始化虚拟账户状态
pass
def handle_data(context): # 每个交易日的买入卖出指令
universe = context.get_universe()
yesterday =
context.previous_date.strftime(‘%Y-%m-%d’) # 向前移动一个工作日
data = context.history(universe, [‘PE’], time_range=1, style=’tas’)
data = data[yesterday]
factor = data[‘PE’].dropna()
factor = pd.Series(winsorize(factor, win_type=’QuantileDraw’, pvalue=0.05)) # 去极值
factor = 1.0 / factor
factor = factor.replace([np.inf, -np.inf], 0.0)
signal = standardize(dict(factor)) # 标准化
# 组合构建
wts = simple_long_only(signal, yesterday)
# 交易部分
account = context.get_account(‘fantasy_account’)
current_position = account.get_positions(exclude_halt=True)
target_position = wts.keys()
# 卖出当前持有,但目标持仓没有的部分
for stock in set(current_position).difference(target_position):
account.order_to(stock, 0)
# 根据目标持仓权重,逐一委托下单
for stock in target_position:
account.order_pct_to(stock, wts[stock])

回测结果
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/68831
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!