提起资本资产定价模型,大家可能都有学习过,那么本篇内容主要向大家讲述资本资产定价模型的实际应用,我们将其构建成量化策略,并在历史行情中回测。
import pandas as pd
import numpy as np
from scipy import stats
# 初始化函数,全局只运行一次
def init(context):
g.n = 20 #设置最大持仓数量为20只股票
g.longday = 60 #设置数据长度
run_monthly(handle_bar,date_rule=1)
#将handle_bar交易函数设置为定时运行:每个月第一个交易日
context.stock = []#储存上期的股票池
g.settock='399006.SZ'
set_benchmark(g.settock)
## 开盘时运行函数
def handle_bar(context, bar_dict):
#执行选股函数:CAPM(),并将结果导入,该股票列表是需要买入的个股。
needstock_list = CAPM()
#获取上期持仓个股
holdstock_list = list(context.stock)
#确定本期需要卖出的个股
sell_list = list(set(holdstock_list)-set(needstock_list))
#执行卖出操作,运用for循环,逐个操作。
for s in sell_list:
order_target(s,0)
#确定本期需要买入的个股,其余即为继续持仓的个股
buy_list=[]
for i in needstock_list:
if i in holdstock_list:
pass
else:
buy_list.append(i)
#确定可用资金,平分分配至需买入的个股
n=len(buy_list)
cash=context.portfolio.available_cash/n
#执行买入操作
for s in range(0,n,1):
stock=list(buy_list)[s]
order_target_percent(stock,0.1)
#操作完毕,将选股结果放到上期股票池储存变量中,以备下次使用。
context.stock = frozenset(needstock_list)
#=========选股函数===========
def CAPM():
date=get_last_datetime().strftime('%Y%m%d')
stock_list=stock(date)
ret=get_price(stock_list, None, date, '1d', ['quote_rate'], False, 'pre', g.longday, is_panel=1)['quote_rate']
ret=(ret/100-0.04/252)*100
ret_jz=get_price('000300.SH', None, date, '1d', ['quote_rate'], False, 'pre', g.longday, is_panel=1)['quote_rate']
ret['ret_jz']=(ret_jz/100-0.04/252)*100
#进行线性回归
y=list(ret['ret_jz'])
df=pd.DataFrame(columns=['alpha'])
for i in ret.columns:
x = list(ret[i])
beta, stockalpha, r_value, p_value, slope_std_error=stats.linregress(y, x)
df.loc[i]=stockalpha
df=pd.DataFrame(df).sort_values(by='alpha',ascending=True)
df['syboml']=df.index
df=df[df['syboml']!='ret_jz']
#获取股票的代码
needstock_list=[]
for s in range(0,g.n,1):
needstock_list.append(df.iloc[s]['syboml'])
return needstock_list
#===============以沪深300为股票池,除去ST和停牌=====
def stock(date):
stk=list(get_index_stocks(g.settock,date))
price=get_price(stk, None, date, '1d', ['is_paused', 'is_st'], False, None, 1, is_panel=1)
stopstk=price['is_paused'].iloc[-1]
ststk=price['is_st'].iloc[-1]
startstk=(stopstk[stopstk==0].index)
okstk=(ststk[ststk==0].index)
tradestk=list(set(startstk)&set(okstk))
return tradestk
第八篇:CAPM模型的应用
导语:提起资本资产定价模型,大家可能都有学习过,那么本篇内容主要向大家讲述资本资产定价模型的实际应用,我们将其构建成量化策略,并在历史行情中回测。
一、策略阐述
CAPM模型公式
夏普发现单个股票或者股票组合的预期回报率的公式如下:E[ri]=rf+β(E[rM]−rf)。
其中,rf是无风险回报率,β是证券的Beta系数,E[rM]是市场期望回报率,E[rM]−rf 是市场溢价。
超额收益
当一只股票的价格被正确定价的时候,它的风险溢价与市场组合的风险溢价是呈现完全的线性关系,也就是线性回归后应该得到一条斜率为β,截距为 rf 的拟合直线。
实际上,每只股票的收益率与市场组合的收益率进行回归的时候截距都不会等于rf,而这个偏差值α的计算公式为:α=(E[ri]−rf)−β(E[rM]−rf)
按照CAPM模型,当正确定价时,股票的α值应该为零,所有α值不为零的股票我们都可以认为被错误的定价了。被错误定价的股票可以分为两类
1.α < 0,此时股票的价格被低估了
2.α > 0,此时股票的价格被高估了
假设CAPM理论是成立的,这些错误定价的股票都会最终回到得到正确的定价,那么选股时应该买入α较低的股票。
CAPM模型实际应用
第一步:我们选取创业板指数成分股为股票池,由于创业板为风险较大板块,因此错误定价的发生概率和偏离度会更大。
第二步:获取股票池内个股与创业板指数的过去60个交易日的涨跌幅,进行线性回归,计算出每一个股票的alpha值。
第三步:按alpha从小到大排序,选取前10只股票作为持仓,持股一个月。
以下为策略实现的基本信息:
策略实现难度:3
实现过程中所需要用到的API函数,ps:通过SuperMind量化交易平台API文档快速掌握:
需要用到的API函数 | 功能 |
---|---|
handle_bar() | 定时运行函数,按交易日或按分钟运行 |
set_benchmark() | 设置基准指数 |
二、代码示意图
三、编写释义
本篇内容的关键点是将个股的alpha通过线性回归计算获取,以下是作者实现过程中的笔记,建议初学者到研究环境中使用,尤其是线性回归模板。
In [1]:
from scipy import stats
#===============以创业板为股票池,除去ST和停牌=====
def stock(date):
stk=list(get_index_stocks('399006.SZ',date))
price=get_price(stk, None, date, '1d', ['is_paused', 'is_st'], False, None, 1, is_panel=1)
stopstk=price['is_paused'].iloc[-1]
ststk=price['is_st'].iloc[-1]
startstk=(stopstk[stopstk==0].index)
okstk=(ststk[ststk==0].index)
tradestk=list(set(startstk)&set(okstk))
return tradestk
#=========选股函数===========
date='20180125'
stock_list=stock(date)
ret=get_price(stock_list, None, date, '1d', ['quote_rate'], False, 'pre', 60, is_panel=1)['quote_rate']
ret=(ret/100-0.04/252)*100
ret_jz=get_price('000300.SH', None, date, '1d', ['quote_rate'], False, 'pre', 60, is_panel=1)['quote_rate']
ret['ret_jz']=(ret_jz/100-0.04/252)*100
#进行线性回归
y=list(ret['ret_jz'])
df=pd.DataFrame(columns=['alpha'])
for i in ret.columns:
x = list(ret[i])
beta, stockalpha, r_value, p_value, slope_std_error=stats.linregress(y, x)
df.loc[i]=stockalpha
df=pd.DataFrame(df).sort_values(by='alpha',ascending=True)
df['syboml']=df.index
df[df['syboml']!='ret_jz']
df.head()
Out[1]:
alpha | syboml | |
---|---|---|
300216.SZ | -1.090606 | 300216.SZ |
300450.SZ | -0.871863 | 300450.SZ |
300115.SZ | -0.821309 | 300115.SZ |
300136.SZ | -0.676029 | 300136.SZ |
300077.SZ | -0.637057 | 300077.SZ |
四、最终结果
策略回测区间:2021.01.01-2022.12.31
回测资金:1000000
回测频率:日级
回测结果:红色曲线为策略收益率曲线,蓝色曲线为对应的基准指数收益率曲线
策略源代码:
In [ ]:
import pandas as pd
import numpy as np
from scipy import stats
# 初始化函数,全局只运行一次
def init(context):
g.n = 20 #设置最大持仓数量为20只股票
g.longday = 60 #设置数据长度
run_monthly(handle_bar,date_rule=1)
#将handle_bar交易函数设置为定时运行:每个月第一个交易日
context.stock = []#储存上期的股票池
g.settock='399006.SZ'
set_benchmark(g.settock)
## 开盘时运行函数
def handle_bar(context, bar_dict):
#执行选股函数:CAPM(),并将结果导入,该股票列表是需要买入的个股。
needstock_list = CAPM()
#获取上期持仓个股
holdstock_list = list(context.stock)
#确定本期需要卖出的个股
sell_list = list(set(holdstock_list)-set(needstock_list))
#执行卖出操作,运用for循环,逐个操作。
for s in sell_list:
order_target(s,0)
#确定本期需要买入的个股,其余即为继续持仓的个股
buy_list=[]
for i in needstock_list:
if i in holdstock_list:
pass
else:
buy_list.append(i)
#确定可用资金,平分分配至需买入的个股
n=len(buy_list)
cash=context.portfolio.available_cash/n
#执行买入操作
for s in range(0,n,1):
stock=list(buy_list)[s]
order_target_percent(stock,0.1)
#操作完毕,将选股结果放到上期股票池储存变量中,以备下次使用。
context.stock = frozenset(needstock_list)
#=========选股函数===========
def CAPM():
date=get_last_datetime().strftime('%Y%m%d')
stock_list=stock(date)
ret=get_price(stock_list, None, date, '1d', ['quote_rate'], False, 'pre', g.longday, is_panel=1)['quote_rate']
ret=(ret/100-0.04/252)*100
ret_jz=get_price('000300.SH', None, date, '1d', ['quote_rate'], False, 'pre', g.longday, is_panel=1)['quote_rate']
ret['ret_jz']=(ret_jz/100-0.04/252)*100
#进行线性回归
y=list(ret['ret_jz'])
df=pd.DataFrame(columns=['alpha'])
for i in ret.columns:
x = list(ret[i])
beta, stockalpha, r_value, p_value, slope_std_error=stats.linregress(y, x)
df.loc[i]=stockalpha
df=pd.DataFrame(df).sort_values(by='alpha',ascending=True)
df['syboml']=df.index
df=df[df['syboml']!='ret_jz']
#获取股票的代码
needstock_list=[]
for s in range(0,g.n,1):
needstock_list.append(df.iloc[s]['syboml'])
return needstock_list
#===============以沪深300为股票池,除去ST和停牌=====
def stock(date):
stk=list(get_index_stocks(g.settock,date))
price=get_price(stk, None, date, '1d', ['is_paused', 'is_st'], False, None, 1, is_panel=1)
stopstk=price['is_paused'].iloc[-1]
ststk=price['is_st'].iloc[-1]
startstk=(stopstk[stopstk==0].index)
okstk=(ststk[ststk==0].index)
tradestk=list(set(startstk)&set(okstk))
return tradestk
查看以上策略详细请 到 supermind量化交易官网查看:风险控制建模-CAPM模型的应用