内容概要
- alpha因子与beta因子
- 多因子策略的理论基础
- 多因子策略流程
- 多因子策略的数据处理
alpha因子与beta因子
一个投资策略的收益率可以分解为两个部分
- 跟市场走向相关,相关度用beta系数表示。beta可以称作这个投资组合的系统风险
- beta得到相对容易
- beta就是有市场行情及时跟上,有风险时候及时躲避,通过水涨船高的方式获得收益
- 跟市场走向无关,属于超额回报的部分,相关度用alpha表示。
- alpha难得
- 就是精选个股,跑赢市场
- 跟市场走向相关,相关度用beta系数表示。beta可以称作这个投资组合的系统风险
股票量化交易策略
- 目标是获取alpha和beta收益
- 主要分为两种形式
- 趋势追踪:重点是择时,交易时机要研究好
- 多因子选股 :重点是选股,侧重于股票池的更新
多因子策略的理论基础
1.资本资产定价模型(CAPM)
- 单因子模型–市场因素
- y=kx+b
2.APT模型–套利定价理论
- 发现收益率不仅仅受市场因素的影响,不过不确定受什么其他因子的影响,以及有多少个因子
- y = w1x1 + w1x2 +…+w0
3.FF三因子模型
- 发现个收益受市场风险,市值风险和账面市值比风险三个因子的影响
- y = w1市场 + w2市值 +w3账面 +w0
4.FF五因子模型
- y = w1*x1 + w2x2 + …… + wnxn + w0
什么是alpha类型的选股?
- 获取alpha收益的选股策略
示例:
def init(context):
# 选择的股票数量
context.stock_num = 20
# before_trading此函数会在每天策略交易开始前被调用,当天只会被调用一次
def before_trading(context):
# 获取市值最小的股票
q = query(fundamentals.eod_derivative_indicator.market_cap).order_by(
fundamentals.eod_derivative_indicator.market_cap).limit(context.stock_num)
fund = get_fundamentals(q)
print(fund.T.index.values)
# 定义股票池,每个交易日更新
context.stocks = fund.T.index.values
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
def handle_bar(context, bar_dict):
# 每日调仓
# 卖出
for stock in context.portfolio.positions.keys():
if context.portfolio.positions[stock].quantity > 0:
if stock not in context.stocks:
order_target_percent(stock, 0)
# 买入
for stock in context.stocks:
order_target_percent(stock, 1.0/context.stock_num)
# after_trading函数会在每天交易结束后被调用,当天只会被调用一次
def after_trading(context):
pass
- 什么是因子?
- 影响收益率的指标或者方向
- 如何选择合适的因子
- 分析,验证
多因子策略流程
- 1.对因子的处理和探索
- 1)获取数据,准备数据,数据处理
- 去极值,标准化,中性化
- 2)单因子的有效分析
- 因子的IC分析
- 因子的收益分析
- 3)多因子的组合
- 多因子相关性分析
- 多因子的合并
- 4)确定因子的权重
- 打分法
- 回归法
- 1)获取数据,准备数据,数据处理
- 2.回测
- 排序方向
- 选股数量
- 调仓周期
多因子策略选股注意点
- 找到因子与收益率之间的关联性
- 分析使用研究平台,注意有些API和策略平台不一样
- panel类型
- series类型:有index的一维数组
- DataFrame类型:有index的二维数据,相当于series的容器
- panel类型:有index的三维数据,相当于DataFrame的容器
- 横截面数据
- 同一个时间点,不同的股票相同的特征的表现情况
- 序列数据
- 在不同时间点上收集到的数据,这类数据反映了某一事物,现象随着时间的变化状态或程度
多因子策略的数据处理
极值处理
- 把异常数据“拉回”到正常值
- 将异常数据以正常值范围的边界值进行替换
三种方式
- 分位数去极值
- 根据分位数确定边界值
- API:
from scipy.stas.mstats import winsorize
中位数去极值
- 先找到mad(每一个元素离中位数的距离)
- 计算madx1.482x3 确定左右边界值
- 代码:
# 1、找到MAD值 med = np.median(factor) distance = abs(factor - med) MAD = np.median(distance) # 2、求出MAD_e MAD_e = 1.4826 * MAD # 3、求出正常值范围的边界 up_scale = med + 3 * MAD_e down_scale = med - 3 * MAD_e
- 正态分布去极值
- 3σ原则
- 由于是以平均值作为中间值,收到异常值的影响较大,所以效果不好
- 分位数去极值
标准化处理
- 无量纲化,把数据处理到统一规格
代码:
from sklearn.preprocessin import StandardScaler transfer = StandardScaler() factor = transfer.fit_transform(factor)
市值中性处理
- 中性处理:排除掉关联指标之间的关联部分
- 使用多种指标来对股票池进行筛选,有时会因为其他因子的影响,而导致选出来的股票具有一些我们不希望看到的偏向,这个时候就需要进行中性处理
- 如,市净率会与市值有很高的相关性,这时如果我们使用未进行市值中性化的市净率,选股的交过会比较集中,这不是我们想要的,需要进行市值中性化处理。
- 怎么进行市值中性化呢?
- 线性回归
- 核心:将和市值相关性很高的因子去掉市值相关的部分,如策略是市盈率单因子,就计算出市盈率和市值相关的部分,然后减去
步骤:
- 1.用线性回归算法找到因子值和市值的线性关系模型
- 2.用线性关系模型预测得到市值相关部分
- 3.从因子值中减去市值相关部分
代码:
from sklearn.linear_model import LinearRegression x = factor["market_cap"].reshape(-1, 1) y = factor["pb_ratio"] # 线性回归预估器 estimator = LinearRegression() estimator.fit(x, y) y_predict = estimator.predict(x) pb_rdio = factor["pb_ratio"] - y_predict
示例:根据进行市值中性化之后的市净率因子值选出前20%的股票作为股票池
# 可以自己import我们平台支持的第三方python模块,比如pandas、numpy等。
# 导入线性回归算法预估器
import numpy as np
from sklearn.linear_model import LinearRegression
# 中位数去极值法
def med_method(factor):
# 1、找到MAD值
med = np.median(factor)
distance = abs(factor - med)
MAD = np.median(distance)
# 2、求出MAD_e
MAD_e = 1.4826 * MAD
# 3、求出正常值范围的边界
up_scale = med + 3 * MAD_e
down_scale = med - 3 * MAD_e
# 4、替换
factor = np.where(factor > up_scale, up_scale, factor)
factor = np.where(factor < down_scale, down_scale, factor)
return factor
# 标准化
# (x - mean) / std
def stand_method(factor):
mean = np.mean(factor)
std = np.std(factor)
factor = (factor - mean) / std
return factor
# 在这个方法中编写任何的初始化逻辑。context对象将会在你的算法策略的任何方法之间做传递。
def init(context):
# 选定股票范围
context.hs300 = index_components('000300.XSHG')
# 确定更新股票的周期
scheduler.run_monthly(select_stocks, tradingday=1)
def select_stocks(context, bar_dict):
# 获取财务数据当天的市值,以及市净率,pb_ratio
q = query(fundamentals.eod_derivative_indicator.market_cap,
fundamentals.eod_derivative_indicator.pb_ratio)
factor = get_fundamentals(q)
# 处理缺失值
factor = factor.dropna(axis=1)
# 因子处理:去极值,标准化,市值中性化
pb_ratio = treat_data(factor.T)
# 选股
context.stocks = pb_ratio[pb_ratio < pb_ratio.quantile(0.2)].index
def treat_data(factor):
# 对pb_ratio进行去极值和标准化
# 去极值
factor['pb_ratio'] = med_method(factor["pb_ratio"])
# 标准化
factor['pb_ratio'] = stand_method(factor["pb_ratio"])
# 3.对pb_ratio进行市值中性化
# 1)把市值设置为特征值,市净率设置为目标值
# 特征值
x = factor["market_cap"].reshape(-1,1)
# 目标值
y = factor["pb_ratio"]
# 2)预估器流程
estimator = LinearRegression()
estimator.fit(x,y)
y_predict = estimator.predict(x)
# 3)去掉市值相关部分
error = factor['pb_ratio'] - y_predict
return error
# before_trading此函数会在每天策略交易开始前被调用,当天只会被调用一次
def before_trading(context):
pass
# 你选择的证券的数据更新将会触发此段逻辑,例如日或分钟历史数据切片或者是实时数据切片更新
def handle_bar(context, bar_dict):
# 股票买卖,买股票市净率在前20%的股票,卖不这前20%的股票
# 买
for stock in context.stocks:
order_target_percent(stock, 1.0/20)
# 卖
for stock in context.portfolio.positions.keys():
if context.portfolio.positions[stock].quantity > 0:
if stock not in context.stocks:
order_target_percent(stock,0)
# after_trading函数会在每天交易结束后被调用,当天只会被调用一次
def after_trading(context):
pass