在CAPM模型的基础上,再向大家讲述Fama-French的三因子模型,并构建策略,实际应用于A股市场。
import pandas as pd
import numpy as np
from sklearn import linear_model
# 初始化函数,全局只运行一次
def init(context):
g.bstk = '399006.SZ' #设置指数
set_benchmark(g.bstk)#设置基准指数
g.day = 0 #记录运行天数
g.tradeday = 20 #调仓频率
g.stock = [] #储存上期的股票池
g.trade = False #是否调仓的开关
g.longday = 252 #样本长度
g.stocknum = 20 #持仓数量
pass
#每日开盘前9:00被调用一次,用于储存自定义参数、全局变量,执行盘前选股等
def before_trading(context):
#判断是否调仓
if g.day%g.tradeday==0:
g.trade=True
else:
g.trade=False
g.day=g.day+1
## 开盘时运行函数
def handle_bar(context, bar_dict):
if g.trade==True:
#获取选股结果
needstock_list = alpha_FF()
#获取上期持仓个股
holdstock_list = list(g.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_value(stock,cash)
#操作完毕,将选股结果放到上期股票池储存变量中,以备下次使用。
g.stock = frozenset(needstock_list)
else:
pass
#=================获取股票池==================================
def stock(yestoday,today): #要的是过去交易日的股票池,但换仓日不应该停牌
stk2=list(get_index_stocks(g.bstk,yestoday))#过去的
stk=list(get_index_stocks(g.bstk,today))#换仓日的
#获取换仓日的股票再换仓日的ST和停牌情况
price=get_price(stk, None, today, '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)&set(stk2))#符合不停牌非ST和过去交易日的沪深300成分股
return tradestk
#==========================获取当天交易日的前N个交易日的日期
def tradeday(today,n):
daylist=list(get_all_trade_days().strftime('%Y%m%d'))
calnum = daylist.index(today)#获取今日日期在整个月历中的序
lasttrade=daylist[calnum-n]#去前N个序的交易日
return lasttrade
#==========================alpha计算函数=========================
def alpha_FF():
today=get_last_datetime().strftime('%Y%m%d')#获取当天日期 格式YMD
#获取前N个交易日的日期
ldate=tradeday(today,g.longday)
stock_list = stock(ldate,today) #获取交易股票列表
stock_num = int(len(stock_list)*0.2)
#查询市值、所有者权益数据
q = query(valuation.symbol,valuation.market_cap,balance.total_equity).filter(valuation.symbol.in_(stock_list),)
basic = get_fundamentals(q, date = ldate)
basic['B/M']= basic['balance_total_equity']/basic['valuation_market_cap']
ret=get_price(stock_list, None, today, '1d', ['quote_rate'], False, 'pre', g.longday, is_panel=1)['quote_rate']
ret=ret/100
ret_jz=get_price(g.bstk, None, today, '1d', ['quote_rate'], False, 'pre', g.longday, is_panel=1)['quote_rate']
ret_jz=ret_jz/100-0.04/252
df=pd.DataFrame()
df['Rm']=ret_jz
basic.index=basic['valuation_symbol']
del basic['balance_total_equity']
for i in ['valuation_market_cap','B/M']:
basic = pd.DataFrame(basic).sort_values(by =i, ascending=False)
stockmax=list(basic.iloc[:stock_num]['valuation_symbol'])
stockmin=list(basic.iloc[-stock_num:]['valuation_symbol'])
df[i]=np.mean(ret[stockmin].T)-np.mean(ret[stockmax].T)
ret=ret-0.04/252
df.columns=['RM','SMB','HML']
clf = linear_model.LinearRegression()
#数据无法获取导致的,处理后的nan使其为0
ret.iloc[:] = ret.iloc[:].fillna(0)
df.iloc[:] = df.iloc[:].fillna(0)
#对三因子进行线性回归
x_list=['RM','SMB','HML']
df2=pd.DataFrame(index=['alpha'])
for i in ret.columns:
y = ret[i].values
x = df[x_list].values
clf.fit(x,y)
df2[i]=clf.coef_[0]
df2=df2.T
df2 = pd.DataFrame(df2).sort_values(by ='alpha', ascending=True)
#获取股票的代码
needstock_list=[]
for s in range(0,g.stocknum,1):
needstock_list.append(list(df2.index)[s])
return needstock_list