Demo entry 6295770

my

   

Submitted by wang on Oct 22, 2016 at 06:56
Language: Python 3. Code size: 9.9 kB.

from CAL.PyCAL import Date
from CAL.PyCAL import Calendar
from CAL.PyCAL import BizDayConvention
from pandas import DataFrame
import numpy as np
import pandas as pd
import scipy as sp
import scipy.optimize as sco
from datetime import *

start = '2014-01-01'                       # 回测起始时间
end = '2016-05-15'                         # 回测结束时间
benchmark = 'HS300'                        # 策略参考标准
universe = set_universe('HS300')           # 证券池,HS300
capital_base = 1000000                     # 起始资金
freq = 'd'                                 # 策略类型,日间策略使用日线回测
refresh_rate = 1                           # 调仓频率,每天
weigh = 2                                  #控制仓位参数
yiRi = 0.05                           #T-1日相对于T-2日波动幅度,用于T日调仓[此为风控部分所需要要的波动率阈值]取反的话即是风险下限

global stock_history

#根据OperatingProfitRatio,InventoryTDays,PB,NonCurrentAssetsRatio四个因子选取股票,每月第一天重置一次#
def get_stockset(universe,date):
    p=DataAPI.MktStockFactorsOneDayGet(tradeDate=date,secID=universe,field=u"secID,OperatingProfitRatio,InventoryTDays,PB,NonCurrentAssetsRatio",pandas="1")
    effective_factors={'OperatingProfitRatio':True,'InventoryTDays':True,'PB':True,'NonCurrentAssetsRatio':True}
    p.index=p['secID']
    score={}

    #循环求得股票a在有效因子fac部分的得分
    for fac,value in effective_factors.items():
        score[fac]=p[fac].rank(ascending=value,method='first')
    #βi乘score,将得分按从大到小排序,得到前20只股票为首选组合
    buy_stock_set = list((DataFrame(score)*np.array([3,4,2,1])).T.sum().order(ascending = False).head(40).index)
    return buy_stock_set[:20]
#输出测试
#print(get_stockset(universe,'2016-08-01'))
# ['600663.XSHG', '600783.XSHG', '000623.XSHE', '002252.XSHE', '600666.XSHG', 
#  '601985.XSHG', '600867.XSHG', '600252.XSHG', '600177.XSHG', '600415.XSHG',
#  '600674.XSHG', '600895.XSHG', '300003.XSHE', '600196.XSHG', '300027.XSHE',
#  '300251.XSHE', '600900.XSHG', '600649.XSHG', '600519.XSHG', '600018.XSHG']

#获取股票池中股票的历史收盘价 以便使用#
def get_historical_closes(ticker, start_date, end_date):
    p = DataAPI.MktEqudGet(secID=ticker,beginDate=start_date,endDate=end_date,field=u"secID,tradeDate,closePrice",pandas="1") 
    p.rename(columns={'tradeDate': 'Date', 
                      'closePrice': 'Close'}, inplace=True)
    pivoted = p.pivot(index='Date', columns='secID')
    pivoted.columns = pivoted.columns.droplevel(0)
    return np.log(pivoted/pivoted.shift(1))


#择时系统的确定
#止损策略 需要时调用

#五日线、十日线
#传入参数为股票池,函数对股票池进行五日线十日线金叉死叉分析,返回是卖出或买入信号
def timing1(universe):
    #获取股票池中所有股票当日所有交易因子
    getData_current_date=DataAPI.MktStockFactorsOneDayGet(tradeDate=last_date,secID=account.universe,field=['secID','MA5','MA10','MA20','NetProfitGrowRate'],pandas="1")
    # print "today tech index",getData_current_date.head()
    getData_current_date.set_index('secID',inplace=True)

    #生成股票检查清单
    getData_current_date=getData_current_date[getData_current_date.NetProfitGrowRate>=1.0].dropna()
    getData_current_date=getData_current_date.sort(columns='NetProfitGrowRate',ascending=False)
    getData_current_date=getData_current_date.head(20)
    # print "today buy list", getData_current_date
    
    #获取上面股票清单中所有股票前一天所有交易因子
    getData_last_date=DataAPI.MktStockFactorsOneDayGet(tradeDate=lastT2Day,secID=list(getData_current_date.index),field=['secID','MA5','MA10','MA20','NetProfitGrowRate'],pandas="1")
    getData_last_date.set_index('secID',inplace=True)
    # print "yesterday tech index", getData_last_date.head()
    
    a=len(getData_current_date)
    b=len(getData_last_date)
    
    #生成买入股票清单
    for stock in list(getData_current_date.index):
        if sh_index_ma_down:
            # print "___down___"
            break
        elif a!=b:
            break        
        elif((getData_current_date['MA5'][stock]>getData_current_date['MA10'][stock])&(getData_last_date['MA5'][stock]<=getData_last_date['MA10'][stock])): 
            buylist.append(stock)
            return False    #均线金叉买入
            # print "buylist", buylist
        else: 
            pass
            # print "buy-wrong"
    # print "buylist",buylist 
    
    # print "check list", getData_current_date.index
    # print "in hand", account.valid_secpos
    
    #生成卖出股票清单    
    for stock in list(getData_current_date.index):
        if a!=b:
            break     
        elif((getData_current_date['MA5'][stock]<=getData_current_date['MA10'][stock])&(getData_last_date['MA5'][stock]>getData_last_date['MA10'][stock])): 
            selist.append(stock)
            return True     #均线死叉卖出
            # print "selist", selist
        else:
            pass
    #         print "sel-wrong"

#第二个择时信号,传入参数为股票的历史日线数据和止损点数值
#返回卖出信号为True,不作操作为False
def timing2(hist,bench):
    security_returns = (hist[len(hist)-1]-hist[0])/hist[0]
    #如果五日内没有回到买入价格,则置flag为1便于下面操作
    for stock in range(hist, 5):
        count++
        if stock >= hist[0]:
            break
    
    if count = 5 :
        flag = 1

    if security_returns < bench and flag = 1:
        return True
    else:
        return False

#第三个择时信号
#True为买入信号
def timing3(hist, bench, callback):
    security_returns = -(hist[len(hist)-1]-hist[0])/hist[0]

    #如果股价回调了10%,则置flag为1便于操作
    if hist[len(hist)-2]-hist[1])/hist[1] = -0.1:
        flag = 1

    if security_returns > bench and flag = 1:
        return True
    else:
        return False      
#择时系统到此结束

#风险控制
###风险控制部分开始##

#传入参数为股票池,函数求出股票池的波动率
#风险控制部分直接在主函数中重新编写逻辑,此处不再做相关处理
def risk_up(universe)
    pass
    
#股票池组合优化,最小化标准差或最大化夏普比#
def statistics(weights):
    global stock_history
    weights = np.array(weights)
    port_returns = np.sum(stock_history.mean()*weights)*252
    port_variance = np.sqrt(np.dot(weights.T, np.dot(stock_history.cov()*252,weights)))
    return np.array([port_returns, port_variance, port_returns/port_variance])

#最小化夏普比的负数#
def min_sharpe(weights):
    return -statistics(weights)[2]
#最小化标准差#
def min_variance(weights):
    return statistics(weights)[1]
def port_weight(stockpool):
    n=len(stockpool)
    weights_gus=n*[1./n]
    #约束条件#
    cons = ({'type':'eq', 'fun':lambda x: np.sum(x)-1})
    #边界条件:每个股票的权重必须在0~1之间#
    bnds = tuple((0,1) for x in range(n))
    #开始优化,最小化风险or最大化夏普率#
    optv = sco.minimize(min_variance,weights_gus,method = 'SLSQP', bounds = bnds, constraints = cons)
    #log.info("portweights")
    #log.info(optv['x'].round(3))
    return optv['x'].round(3)
    #opts = sco.minimize(min_sharpe, weights_gus, method = 'SLSQP', bounds = bnds, constraints = cons)
    #log.info(opts['x'].round(3))
    #return opts['x'].round(3)


# 初始化虚拟账户状态
def initialize(account):                   
    account.flag=1
    account.stockpool=[]
    account.stock_history=DataFrame({})
    account.portweights=[]

def handle_data(account):     # 每个交易日的买入卖出指令
    
    #此处调用上面的择时系统
    #止损策略#
    hist=[]
    hist=DataAPI.MktIdxdGet(indexID=u"000001.ZICN",beginDate=account.current_date-timedelta(days=5),endDate=account.current_date,field=u"PrecloseIndex",pandas="1")['preCloseIndex']
    if timing2(hist,-0.05) or timing1(universe):#达到任意一个条件即发出买入或卖出信号
        for i in account.stockpool:
            order_to(i,0)
        #log.info("sell all for stoploss")
        return

    #买入股票
    if !timing1(universe) or timing3(hist, 0.2, 0.1):
        for i in account.stockpool:
            order(i,0);
    #每月第一天更新股票池,并卖出股票池外的股票#
    date=account.current_date
    dayspan=timedelta(days=30)
    if date.day<5 :
        if account.flag==1:
            stockpool=get_stockset(account.universe,date)
            for i in account.stockpool:
                if i not in stockpool:
                    order_to(i,0)
            account.stockpool=stockpool
            #log.info("stockpool")
            #log.info(account.stockpool)
            account.flag=0
    elif date.day>24:
        account.flag=1
        for i in account.stockpool:
            order_to(i,0)
        return

    #获取股票池中股票的历史收盘价,用于计算方差,夏普比等#
    global stock_history
    stock_history=DataFrame({})
    stock_history=get_historical_closes(account.stockpool,date-dayspan,date).dropna()

    #获取优化后的资产组合比例#
    account.portweights=port_weight(account.stockpool)


    #风险控制
    hits2 = account.get_attribute_history('closePrice',2)
    if account.t==0:        
        for stock in account.universe:#初始化股票数量和仓位标志的字典
            account.amount[stock] = 0  #单个个股仓位控制
            account.percent[stock] = 0  #单个个股仓位控制
        
        account.t = 1  

    for stock in account.universe:
        #单次买卖股票的数量,每次卖出5万单只股票
        amount = int(account.referencePortfolioValue / len(account.universe) / account.referencePrice[stock] / weigh)
        #风险控制判断
        #大于风险上限对波动率最低的五支股票加仓,对波动率最大的三支股票减仓
        if hist[stock][-1]/hist[stock][-2] - 1 >= yiRi  and stock in account.valid_secpos :
            if account.amount[stock] >= amount:
                account.amount[stock + 3] = account.amount[stock + 3] - amount
                account.amount[stock - 5] = account.amount[stock - 5] + amount
                order(stock,-amount)  
            else :
                order_to(stock,0)
                account.amount[stock] = 0
            account.percent[stock] = account.amount[stock]*account.referencePrice[stock]/account.referencePortfolioValue

        #小于风险上限调整波动率最高的五支股票,各股都加仓    
        elif hist[stock][-1]/hist[stock][-2] - 1 < -yiRi :
            if account.cash >= account.referencePrice[stock] * amount :
                order(stock,amount)   
                account.amount[stock] = account.amount[stock] + amount      
            account.percent[stock] = account.amount[stock]*account.referencePrice[stock]/account.referencePortfolioValue

    #下单#
    for i in range(20):
        order_pct_to(account.stockpool[i],account.portweights[i])
        

This snippet took 0.02 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).