心血来潮上优矿玩一下量化策略。技术分析中最简单的就是移动平均线(英语:Moving Average,MA)。移动平均线常用线有5天、10天、30天、60天、120天和240天的指标。其中,5天和10天的短期移动平均线,是短线操作的参照指标,称做日均线指标;30天和60天的是中期均线指标,称做季均线指标;120天、240天的是长期均线指标,称做年均线指标。均线是最基础的动量指标,一般短期均线上穿长期均线意味着近期买盘较强势可以作为买入信号俗称“金叉”;反之短期均线由上向下穿破长期均线意味着近期卖盘较强势可以作为卖出信号俗称“死叉”。
我以中国平安601318.XSHG为例,做一个简单的双均线策略:当5日均线上穿60日均线,买入;当5日均线下穿60日均线,卖出。回测时间是2012-12-1以来的5年。年化收益率31.4%,超额回报阿尔法Alpha居然高达22.3%,夏普比率1.06,最大回撤19.0%,换手率14.23%。看来我发现了一个致富秘笈,分分钟就要变成白富美人生赢家实现财务自由了?冷静冷静!让我再好好分析一下。
1、怎么判断这是一个好策略呢?
阿尔法就是绝对回报和按照由贝塔系数计算的预期回报之间的差额,越高越好。夏普比率描述的每承受一单位的总风险(收益波动率),会产生多少超过无风险利率的报酬,越高越好。最大回撤比较简单,就是从高点到低点的下跌幅度,肯定是越低越好。但往往阿尔法和夏普比率高的,最大回撤也比较高。考虑到一般人的心理承受能力,最大回撤最好不超过30%。我是以沪深300指数作为基准,在这个策略下可以说个股明显跑赢大盘。
2、这个策略不就是追涨杀跌吗?
从某种意义上可以这么说。但是短期均线和中期均线的关系,比起每日的涨跌还是更有趋势性。与其说是追涨杀跌,不如说是顺势而为。
3、如果用5日均线和120日均线策略可以吗?
大家可以试一下短期均线和长期均线/中期均线和长期均线的关系。比较而言,利用短期均线和长期均线的话,最大回撤过高,有时候高达50%以上,一般人肯定承受不了。中期均线和长期均线的阿尔法相对也没有那么高。当然这可能和个股的属性有关系,也许你能找到最适合某只个股的双均线策略。我测试了一下中国平安的各种组合,发现5-60日均线是最佳策略。
4、这个策略如此有效和选股有关系吗?
除了中国平安,我还测试了中小板和创业板的一些股票。比如乐视网300104.XSHE,回测后阿尔法高达46.8%,但最大回撤61.6%,换手率5.42%。看了一下回测详情,最后一次买入股票是2017-01-23,最后一次卖出股票是2017-02-07,距离停牌还有两个多月。所以,如果坚持按照这个策略执行,大方向是不会错的。最大的问题就在最大回撤上,估计很多人都会倒在黎明前。
最后贴一下策略代码,不懂编程也没关系,改几个日期数字自己玩一下。开心就好:)
start = '2012-12-01' # 回测开始时间
end = '2017-12-01' # 回测结束时间
secID = '601318.XSHG' # 中国平安
benchmark = 'HS300' # 策略对标标的
universe = [secID] # 证券池,支持股票和基金
capital_base = 100000 # 起始资金
freq = 'd' # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测
refresh_rate = 1 # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟
period1 = 5
period2 = 60
commission = Commission(buycost=0.0002, sellcost=0.0002, unit='perValue')
max_history_window = 1000 #设定调取历史价格区间最大为1000个交易日
def initialize(account): # 初始化虚拟账户状态
pass
def handle_data(account): # 每个交易日的买入卖出指令
hist1 = account.get_attribute_history('closePrice', period1) #获取过去5个交易日的收盘价
hist2 = account.get_attribute_history('closePrice', period2) #获取过去60个交易日的收盘价
for s in account.universe:
MA5 = hist1[s].mean() #计算过去5个交易日及过去60个交易日的均价
MA60 = hist2[s].mean()
if MA5 > MA60 and s not in account.security_position: #“金叉”时买入
amount = int(account.cash / account.referencePrice[s] / 100) * 100
order(s, amount)
elif MA5 < MA60 and s in account.security_position: #“死叉”时卖出
order_to(s, 0)