单因子 & 多因子策略(基于JoinQuant)

一份朴实的声明。。。

1. 基于joinquant,大部分代码是原作者所写,俺只是改写、补充。。。
2. 源码见:https://www.joinquant.com/post/775

3. 基于因子打分,不是因子回归
思路:单因子打分,分值赋权个股形成单因子组合,再等权加权单因子组合,变为多因子策略
----------------------------------------------------------------------------------------

 
  
## 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))
### step5:Smart Beta指数的编制 #把一个三维的panel按因子降维,即对因子求平均,使因子这一维度消失掉 # 也即将因子类子指数等权加权,编制成指数 columns= ['port1','port2','port3','port4','port5','benchmark'] avg_data= DataFrame(np.zeros(85*6).reshape(85,6),columns= ['port1','port2','port3','port4','port5','benchmark']) for i in columns: avg_data[i]=pd.DataFrame((monthly_return[:,i,:]).mean()) #(monthly_return[:,2,:]).mean() #avg_data avg_total_return=(avg_data+1).cumprod().iloc[-1,:]-1 avg_annual_return= (avg_total_return+1)**(1./6)-1 avg_excess_return= avg_annual_return*0.7- avg_annual_return[-1] avg_annual_volatility=avg_data.std() avg_information_ratio=avg_excess_return/avg_annual_volatility avg_sharpe=(avg_annual_return-0.04)/avg_annual_volatility avg_drawdown=avg_data.min() avg_win_excess = avg_data.T.iloc[5,:]*0.7-avg_data.T.iloc[-1,:] avg_win_prob=avg_win_excess[avg_win_excess>0].count()/float(len(avg_win_excess)) avg_win_prob plt.figure(figsize =(8,4)) plt.plot((avg_data+1).cumprod().ix[:,0], 'r',label = '%s'%fac ,alpha=0.5) plt.plot((monthly.ix[-1,:].T+1).cumprod(), 'blue',label = '沪深300指数',alpha=0.5) plt.xlabel('净值曲线') plt.legend(loc='upper left',ncol=2)


你可能感兴趣的:(Python,Quantitative,Strategy)