## step1:导入所需的库
import pandas as pdfrom pandas
import Series, DataFrame
import numpy as npimport statsmodels.api as sm
import scipy.stats as scs
import matplotlib.pyplot as plt
## step2:三个函数
# 函数1:获取因子
factors = ['B/M','EPS','PEG','ROE','ROA','GP/R','P/R','L/A','FAP','CMV']
#月初取出因子数值
def get_factors(fdate,factors):
stock_set = get_index_stocks('000001.XSHG',fdate)
q = query( valuation.code, balance.total_owner_equities/valuation.market_cap/100000000, income.basic_eps, valuation.pe_ratio, income.net_profit/balance.total_owner_equities, income.net_profit/balance.total_assets, income.total_profit/income.operating_revenue, income.net_profit/income.operating_revenue, balance.total_liability/balance.total_assets, balance.fixed_assets/balance.total_assets, valuation.circulating_market_cap ).filter( valuation.code.in_(stock_set), valuation.circulating_market_cap )
fdf = get_fundamentals(q, date=fdate)
fdf.index = fdf['code']
fdf.columns = ['code'] + factors
return fdf.iloc[:,-10:]
# 函数2和3:计算因子及benchmark的月收益
def caculate_port_monthly_return(port,startdate,enddate,nextdate,CMV):
close1 = get_price(port, startdate, enddate, 'daily', ['close']) #面板数据
close2 = get_price(port, enddate, nextdate, 'daily',['close']) #面板数据
weighted_m_return = ((close2['close'].ix[0,:]/close1['close'].ix[0,:]-1)).mean() #等权加权
return weighted_m_return
def caculate_benchmark_monthly_return(startdate,enddate,nextdate):
close1 = get_price(['000300.XSHG'],startdate,enddate,'daily',['close'])['close']
close2 = get_price(['000300.XSHG'],enddate, nextdate, 'daily',['close'])['close']
benchmark_return = (close2.ix[0,:]/close1.ix[0,:]-1).sum()
print close1
return benchmark_return
## step3:核心策略
factors = ['B/M','EPS','PEG','ROE','ROA','GP/R','P/R','L/A','FAP','CMV']#因为研究模块取fundmental数据默认date为研究日期的前一天。所以要自备时间序列。按月取
year = ['2011','2012','2013','2014','2015','2016','2017']
month = ['01','02','03','04','05','06','07','08','09','10','11','12']
result = {}
for i in range(7*12):
startdate = year[i/12] + '-' + month[i%12] + '-01'
try:
enddate = year[(i+1)/12] + '-' + month[(i+1)%12] + '-01'
except IndexError:
enddate = '2018-01-01'
try:
nextdate = year[(i+2)/12] + '-' + month[(i+2)%12] + '-01'
except IndexError:
if enddate == '2018-01-01':
nextdate = '2018-02-01'
else:
nextdate = '2018-01-01'
#print 'time %s'%startdate
fdf = get_factors(startdate,factors)
CMV = fdf['CMV'] #5个组合,10个因子
df = DataFrame(np.zeros(6*10).reshape(6,10),index = ['port1','port2','port3','port4','port5','benchmark'],columns = factors)
for fac in factors:
score = fdf[fac].order()
port1 = list(score.index)[: len(score)/5]
port2 = list(score.index)[ len(score)/5+1: 2*len(score)/5]
port3 = list(score.index)[ 2*len(score)/5+1: -2*len(score)/5]
port4 = list(score.index)[ -2*len(score)/5+1: -len(score)/5]
port5 = list(score.index)[ -len(score)/5+1: ]
df.ix['port1',fac] = caculate_port_monthly_return(port1,startdate,enddate,nextdate,CMV)
df.ix['port2',fac] = caculate_port_monthly_return(port2,startdate,enddate,nextdate,CMV)
df.ix['port3',fac] = caculate_port_monthly_return(port3,startdate,enddate,nextdate,CMV)
df.ix['port4',fac] = caculate_port_monthly_return(port4,startdate,enddate,nextdate,CMV)
df.ix['port5',fac] = caculate_port_monthly_return(port5,startdate,enddate,nextdate,CMV)
df.ix['benchmark',fac] = caculate_benchmark_monthly_return(startdate,enddate,nextdate)
#print 'factor %s'%fac
result[i+1]=dfmonthly_return = pd.Panel(result)
## step4:模型评价
total_return = {}
annual_return = {}
excess_return = {}
annual_volatility={}
sharpe={}
information_ratio={}
win_prob = {}
drawdown={}
tr={}
for fac in factors:
monthly = monthly_return[:,:,fac]
total_return[fac] = (monthly+1).T.cumprod().iloc[-1,:]-1
annual_return[fac] = (total_return[fac]+1)**(1./6)-1
excess_return[fac] = annual_return[fac]*0.7- annual_return[fac][-1]
annual_volatility[fac]=monthly.T.std()
sharpe[fac]=(annual_return[fac]-0.04)/annual_volatility[fac]
information_ratio[fac]=(annual_return[fac]-annual_return[fac][-1])/annual_volatility[fac]
drawdown[fac]=monthly.T.min()
win_excess = monthly.iloc[0,:]*0.7-monthly.iloc[-1,:]
win_prob[fac]=win_excess[win_excess>0].count()/float(len(win_excess))