第四章:经典量化策略集锦(第二篇:从“二八轮动”中学择时)

 导语:作为策略锦集第二篇,我们以沪深A 股市场出了名的“二八轮动”现象为基础,向大 


家介绍经典择时策略:二八轮动策略。 






一、策略阐述 






    在介绍二八轮动策略之前,我们首先来了解一下择时交易,择时交易是指利用某种方法 


来判断后市走势,如果判断是上涨,则买入持有;如果判断是下跌,则卖出清仓;如果判断 


是震荡,则进行高抛低吸,这样可以获得远远超越简单买入持有策略的收益率,所以择时交 


易是收益率最高的一种交易方式。通俗的讲,择时即为选择交易时机,投资者总是希望通过 


择时,在上涨前买入,在下跌前卖出。 


  


    “二八轮动”现象就是大小盘轮动现象,“二”代表数量占比20%左右的大盘权重股, 


 “八”代表数量占比80%左右的中小盘股票,二八轮动策略就是指在大盘股与小盘股中间不 


断切换,轮流持有,在大小盘都看跌的时候,则买入债券或者货币基金。二八轮动策略的本 


质是择时,从大小盘指数中选择最佳交易时机。 


     


    二八轮动是如何轮动的呢? 






    择时方法:对比当前交易日收盘数据与二十个交易日前的收盘数据,选择沪深300 指数 


和中证500 指数中涨幅较大的一个,于下一个交易日切换为持有该指数 ETF ,若两个指数均 


为下跌,则于下个交易日切换为空仓状态。调仓 日为每周第一个交易 日。 






    以下为策略实现的基本信息: 






    策略实现难度:1 


    实现过程中所需要用到的API 函数,ps:通过 MindGo 量化交易平台 API 文档快速掌握: 






需要用到的API 函数           功能 






run_weekly()          按周定时运行函数 






account.positions     获取账户持仓信息 






account.cash          获取账户当前资金 






history()             获取多只股票多属性的历史行情数据 




----------------------- Page 74-----------------------


二、代码示意图 






三、编写释义 






    本策略的编写难点在于根据信号值来调整持仓。以下是持仓调整逻辑梳理: 






    第一步:根据信号值,只可能会出现三种情况:分别是空仓、沪深300、中证500,其 


中空仓是两者信号值都小于 0,否则持仓为信号值大的那个。 






    第二步:以目标持仓为导向,根据当前持仓情况作出调仓操作: 






  目标持仓      当前持仓                 操作 






空仓      无持仓          无操作 






        有持仓          卖出持仓 






沪深300   无持仓          买入沪深300 






        沪深300        不操作 






        中证500        卖出中证500,随后买入沪深300 






中证500   无持仓          买入中证500 






        沪深300        卖出沪深300,买入中证500 






        中证500        无操作 




----------------------- Page 75-----------------------


四、最终结果 






策略回测区间:2014.01.01-2018.01.29 


回测资金:100000 


回测频率:日级 


回测结果:红色曲线为策略收益率曲线,蓝色曲线为对应的基准指数收益率曲线 






策略源代码: 






import pandas as pd  


import numpy as np  


#=============================初始化账户=============================== 






def initialize(account): 


    account.day = 20 #设置数据获取长度为 20 


    account.security = ['000300.SH','000905.SH']#设沪深300 指数,中证500 指数 


    account.ETF300 = '510300.OF' #沪深300ETF 基金 


    account.ETF500 = '510500.OF' # 中证500ETF 基金 


    run_weekly(trade,date_rule=1) 


#=============交易函数============ 


def trade(account,data): 


    #获取信号值 


    signal=get_signal(account,data) 


    hs300=signal[0] 


    zz500=signal[1] 


    #根据信号值,来调整至相应仓位 


    #空仓 


    if hs300 <= 0 and zz500 <= 0: 


        if len(account.positions) > 0: 


            for stock in list(account.positions): 


                order_target(stock, 0) 




----------------------- Page 76-----------------------


    #沪深300 


    elif hs300 > zz500: 


        if account.ETF500 in list(account.positions): 


            order_target(account.ETF500, 0) 


        if len(account.positions) < 1: 


            order_target_value(account.ETF300, account.cash) 


    # 中证500 


    elif hs300 < zz500: 


        if account.ETF300 in list(account.positions): 


            order_target(account.ETF300, 0) 


        if len(account.positions) < 1: 


            order_target_value(account.ETF500, account.cash) 






#======================信号获取函数===================================== 


def get_signal(account,data): 


    #获取沪深300 与中证500 过去 20  日的收盘价 


    close=history(account.security, ['close'], 20, '1d', False, 'pre', is_panel=1)['close'] 


    #计算涨跌幅 


    h=(close.iloc[-1]-close.iloc[0])/close.iloc[0] 


    h300=h['000300.SH'] 


    h500=h['000905.SH'] 


    return h300,h500 




----------------------- Page 77-----------------------
阅读更多

更多精彩内容