导语:作为策略锦集第二篇,我们以沪深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-----------------------