Fama-French三因子火锅策略
import statsmodels.api as sm
from statsmodels import regression
import numpy as np
import pandas as pd
import time
from datetime import date
from jqdata import *
'''
================================================================================
总体回测前
================================================================================
'''
def initialize(context):
set_params()
set_variables()
set_backtest()
def set_params():
g.tc=15
g.yb=63
g.N=15
g.NoF=3
def set_variables():
g.t=0
g.rf=0.04
g.if_trade=False
today=date.today()
a=get_all_trade_days()
g.ATD=['']*len(a)
for i in range(0,len(a)):
g.ATD[i]=a[i].isoformat()
if today<=a[i]:
break
g.ATD=g.ATD[:i]
def set_backtest():
set_option('use_real_price', True)
log.set_level('order', 'error')
set_slippage(FixedSlippage(0))
'''
================================================================================
每天开盘前
================================================================================
'''
def before_trading_start(context):
if g.t%g.tc==0:
g.if_trade=True
set_slip_fee(context)
g.all_stocks = set_feasible_stocks(get_index_stocks('000300.XSHG'),g.yb,context)
g.t+=1
def set_slip_fee(context):
set_slippage(FixedSlippage(0))
dt=context.current_dt
log.info(type(context.current_dt))
if dt>datetime.datetime(2013,1, 1):
set_commission(PerTrade(buy_cost=0.0003, sell_cost=0.0013, min_cost=5))
elif dt>datetime.datetime(2011,1, 1):
set_commission(PerTrade(buy_cost=0.001, sell_cost=0.002, min_cost=5))
elif dt>datetime.datetime(2009,1, 1):
set_commission(PerTrade(buy_cost=0.002, sell_cost=0.003, min_cost=5))
else:
set_commission(PerTrade(buy_cost=0.003, sell_cost=0.004, min_cost=5))
def set_feasible_stocks(stock_list,days,context):
suspened_info_df = get_price(list(stock_list), start_date=context.current_dt, end_date=context.current_dt, frequency='daily', fields='paused')['paused'].T
unsuspened_index = suspened_info_df.iloc[:,0]<1
unsuspened_stocks = suspened_info_df[unsuspened_index].index
feasible_stocks=[]
current_data=get_current_data()
for stock in unsuspened_stocks:
if sum(attribute_history(stock, days, unit='1d',fields=('paused'),skip_paused=False))[0]==0:
feasible_stocks.append(stock)
return feasible_stocks
'''
================================================================================
每天交易时
================================================================================
'''
def handle_data(context, data):
if g.if_trade==True:
todayStr=str(context.current_dt)[0:10]
ais=FF(g.all_stocks,getDay(todayStr,-g.yb),getDay(todayStr,-1),g.rf)
g.everyStock=context.portfolio.portfolio_value/g.N
try:
stock_sort=ais.sort('score')['code']
except AttributeError:
stock_sort=ais.sort_values('score')['code']
order_stock_sell(context,data,stock_sort)
order_stock_buy(context,data,stock_sort)
g.if_trade=False
def order_stock_sell(context,data,stock_sort):
for stock in context.portfolio.positions:
if stock not in stock_sort[:g.N]:
stock_sell = stock
order_target_value(stock_sell, 0)
def order_stock_buy(context,data,stock_sort):
for stock in stock_sort:
stock_buy = stock
order_target_value(stock_buy, g.everyStock)
def FF (stocks,begin,end,rf):
LoS=len(stocks)
q = query(
valuation.code,
valuation.market_cap,
(balance.total_owner_equities/valuation.market_cap/100000000.0).label("BTM"),
indicator.roe,
balance.total_assets.label("Inv")
).filter(
valuation.code.in_(stocks)
)
df = get_fundamentals(q,begin)
ldf=get_fundamentals(q,getDay(begin,-252))
if len(ldf)==0:
ldf=df
df["Inv"]=np.log(df["Inv"]/ldf["Inv"])
try:
S=df.sort('market_cap')['code'][:LoS/3]
B=df.sort('market_cap')['code'][LoS-LoS/3:]
L=df.sort('BTM')['code'][:LoS/3]
H=df.sort('BTM')['code'][LoS-LoS/3:]
W=df.sort('roe')['code'][:LoS/3]
R=df.sort('roe')['code'][LoS-LoS/3:]
C=df.sort('Inv')['code'][:LoS/3]
A=df.sort('Inv')['code'][LoS-LoS/3:]
except AttributeError:
S=df.sort_values('market_cap')['code'][:int(LoS/3)]
B=df.sort_values('market_cap')['code'][LoS-int(LoS/3):]
L=df.sort_values('BTM')['code'][:int(LoS/3)]
H=df.sort_values('BTM')['code'][LoS-int(LoS/3):]
W=df.sort_values('roe')['code'][:int(LoS/3)]
R=df.sort_values('roe')['code'][LoS-int(LoS/3):]
C=df.sort_values('Inv')['code'][:int(LoS/3)]
A=df.sort_values('Inv')['code'][LoS-int(LoS/3):]
df2 = get_price(stocks,begin,end,'1d')
df3=df2['close'][:]
df4=np.diff(np.log(df3),axis=0)+0*df3[1:]
SMB=sum(df4[S].T)/len(S)-sum(df4[B].T)/len(B)
HMI=sum(df4[H].T)/len(H)-sum(df4[L].T)/len(L)
RMW=sum(df4[R].T)/len(R)-sum(df4[W].T)/len(W)
CMA=sum(df4[C].T)/len(C)-sum(df4[A].T)/len(A)
dp=get_price('000300.XSHG',begin,end,'1d')['close']
RM=diff(np.log(dp))-rf/252
X=pd.DataFrame({"RM":RM,"SMB":SMB,"HMI":HMI,"RMW":RMW,"CMA":CMA})
factor_flag=["RM","SMB","HMI","RMW","CMA"][:g.NoF]
print (factor_flag)
X=X[factor_flag]
t_scores=[0.0]*LoS
for i in range(LoS):
t_stock=stocks[i]
sample=pd.DataFrame()
t_r=linreg(X,df4[t_stock]-rf/252,len(factor_flag))
t_scores[i]=t_r[0]
scores=pd.DataFrame({'code':stocks,'score':t_scores})
return scores
def linreg(X,Y,columns=3):
X=sm.add_constant(array(X))
Y=array(Y)
if len(Y)>1:
results = regression.linear_model.OLS(Y, X).fit()
return results.params
else:
return [float("nan")]*(columns+1)
def getDay(precent,dt):
for i in range(0,len(g.ATD)):
if precent<=g.ATD[i]:
t_temp = i
if t_temp+dt>=0:
return g.ATD[t_temp+dt]
else:
t= datetime.datetime.strptime(g.ATD[0],'%Y-%m-%d')+datetime.timedelta(days = dt)
t_str=datetime.datetime.strftime(t,'%Y-%m-%d')
return t_str
'''
================================================================================
每天收盘后
================================================================================
'''
def after_trading_end(context):
return