[心得] 一条鞭法程式化教学

楼主: stasis (流雨风雪)   2014-05-19 00:14:44
图文版:http://stasistw.blogspot.tw/2014/05/blog-post_18.html
法意在答辩书中宣称我不熟悉程式交易,只好写这篇自娱娱人一下 XD
在开始这个话题之前,我们要先了解什么是时间序列,以及如何对时间序列作分析。所谓
时间序列(Time Series),就是指以时间先后顺序出现的观测值集合,像是气象预报研究
中,某一地区的每天气温与气压的数据;或者医学领域中,病人在不同时刻的心跳与体温
变化;以台股来说,证交所每天收盘后提供的发行量加权股价指数历史资料,就是一种典
型的时间序列资料。
有了历史资料之后,我们就可以对这些数字做进一步的分析,发掘蕴藏在这些资料之中的
模式(Pattern)。为了方便观察和理解,我们可以把这些数据图像化,像是下图就是某位
女性每日的体温变化图,可以发现排卵前体温较低,排卵后体温较高,因此有些人会借由
体温推估排卵时间,并在前后几天禁止行房以达到避孕的效果 (至于准不准就是另外一回
事了)。
同样的方式运用到台股上就是我们熟知的线图:
[图]
从上图我们可以大致知道从2006到2013年的台湾股市涨跌,以及成交量的变化。假设在看
了这几年的历史走势之后,希望未来如果出现像2008和2009的大涨大跌走势时,自己可以
赚到钱的话,应该怎么做呢?我之前提供过一个很简单的方法:一条鞭法,即指数站上60
日平均线(Moving average, MA)做多,跌破就空手或放空,加上MA之后的线图会长这样:
[图]
有了方法之后,我们要如何评估成效呢?最直观的方法就是目视计算,假设在操作时,只
要指数收盘价跌破60MA,就在隔日开盘时放空,那么回到2008年5月的话,会发生什么事
呢?
[图]
5/26的收盘价8707.83,跌破了当时的60MA,即8740.79(绿色向下箭头处),因此要在隔日
5/27的开盘价放空,即8779.34(绿色向右箭头)。
但5/27的收盘价8778.39,又超过了60MA(8723.72,红色向上箭头),所以在5/28的开盘价
8826.94做多(红色向右箭头)。
不幸的是5/28的收盘价8665.73又再度跌破60MA(8753.60,第二个绿色向下箭头),故在
5/29的开盘价放空(8773.81,第二个绿色向下箭头)。
接下来就出运了,2008年指数再也没碰过季线,空单可以沿路抱到2009年的1/5收盘价
4698.31,突破60MA(4596.76,右侧红色向上箭头),并在1/6开盘价转多4719.54为止(右
侧红色向右箭头)。
[图]
接下来我们可以计算在没有杠杆的状况下,这三笔交易的粗略报酬率:
1. (8779.34-8826.94)/8740.79 = -0.54%
2. (8773.81-8826.94)/8826.94 = -0.60%
3. (8773.81-4719.54)/8773.81 = 46.20%
当然这边都只是模拟,实际交易时若加入手续费等交易成本和买卖造成的滑价,绩效势必
会更差;如果用ETF等工具还需考虑除权息所造成的指数下滑;用期货则要评估期货现货
间的价差,以及换月时的差价。
问题来了,取样时间短的话,自己计算还可行,如果取样时间拉长,像一条鞭法如果回测
近40年,交易次数可是高达500多笔,要是像上面这样自己计算的话会累死,而且加减乘
除之间还很容易算错,这时候这些交易软件的回测功能就派上用场了。
[图]
市面上的同性质软件很多,像是tradestation、HTS、奇狐、Multichart、wealthlab,甚
至国内也有人开发过一套叫做土狼的交易软件,这些交易软件大部分都有许多默认的函式
库,通常也有许多默认范例可以供新手参考。这边以奇狐为例说明一条鞭法怎么程式化:
[图]
下面这段就是一条鞭法的程式码:
ENTERLONG: CROSS(MA(CLOSE,SHORT),MA(CLOSE,LONG));
EXITLONG: CROSS(MA(CLOSE,LONG),MA(CLOSE,SHORT));
ENTERSHORT: CROSS(MA(CLOSE,LONG),MA(CLOSE,SHORT));
EXITSHORT: CROSS(MA(CLOSE,SHORT),MA(CLOSE,LONG));
不要看都是英文字很难懂,这边让我简单说明一下这些函式:
ENTERLONG: 发出买进讯号,顾名思义,EXITLONG就是多头平仓。
ENTERSHORT: 放空讯号,同理可知EXITSHORT就是空头平仓。
CROSS(A,B): 交叉,例如CROSS(A,B)的意思就是,若前一笔资料A<B,下一笔A>B时就代表
状况成立。
MA(X,Y): X代表要用开高低收哪种值做计算,上面是使用收盘价,即CLOSE;Y则是均线的
参数,在这个程式中我使用了两个数值(LONG,SHORT),分别代表长短两条均线要取的参
数。
有了这些概念之后,就可以开始“翻译”这些程式码了:
像“ENTERLONG: CROSS(MA(CLOSE,SHORT),MA(CLOSE,LONG));”和“EXITSHORT:
CROSS(MA(CLOSE,SHORT),MA(CLOSE,LONG));”这两行程式码,翻成中文就是:当短期均线
向上突破长期均线时,空头平仓且多头进场。
同理可知,另外两行的意思就是:当短期均线向下跌破长期均线时,空头进场且多头平仓

若我把LONG设定为60,SHORT设定为1,那么条件就会变成:当收盘价(1MA)向上突破60MA
时,空头平仓且多头进场;当收盘价(1MA)向下跌破60MA时,空头平仓且多头进场。
把条件拿来回测之后,软件就会自动计算出绩效报表,如下图(底色淡绿色是改windows设
定,据说可以让眼睛比较不会疲劳):
[图]
这边的报酬率甚至没有使用杠杆,看起来超漂亮的吧!
我们也可以去检视逐笔交易,像是刚刚提到的三笔交易,跑出来就会像这样:
[图]
要提醒大家的是,看起来很漂亮的回测结果,绝大部分只是假象,因为作弊的手法非常多
(像是万恶的this bar,这也是新手写程式时最容易犯的错之一),如果无法得知原始程
式码自己验证检视,那么小心为上。
像是上面的回测,如同之前所提到,并没有考虑交易成本、除权息等问题,若尽量用保守
的方式估计,年报酬大概会低个10%左右。
如果觉得用收盘价很容易被假讯号骗,一直进进出出,那么刚刚设定的参数SHORT就可以
派上用场了,以下是当短均线参数分别设定为1和5时的讯号:
[图]
可以看到震荡区域的交易笔数明显减少,代价就是交易讯号比较迟钝,若出现连续上涨或
下跌,进出场的位置会比原本糟糕很多。
同样的交易法则,如果换成MultiChart的语法,应该会变成下面这样(//部分为注解):
//参数的宣告,一样是短(1)长(60)两个MA,价格采用的是close,即收盘价
inputs:Price(close),M_Short(1),M_long(60);
//设定变量,var1为短期均线,var2为长期均线
vars:var1(0),var2(0);
var1=Average(Price,M_Short);
var2=Average(Price,M_long);
//如果没有部位(marketposition=0),且短均突破(Crosses)长均,
就在下一笔市价买进(buy next bar at market),
("buy")是方便有多系统时不会混淆各系统的在仓部位,例如有三个独立系统时,
可以将交易讯号分别设定为buy 1,buy 2,buy 3,同理也可以设定来加减码用。
if marketposition=0 and var1 Crosses Above var2 then begin
buy("buy") next bar at market;
end;
//如果有多头部位(marketposition>0),且短均跌破长均,就在下一笔市价平仓
if marketposition>0 and var1 Crosses Under var2 then begin
sell("EXIT_buy") next bar at market;
end;
//如果没有部位,且短均跌破长均,就在下一笔市价放空
if marketposition=0 and var1 Crosses Under var2 then begin
sellshort("sell") next bar at market;
end;
//如果有空头部位(marketposition<0),且短均突破长均,就在下一笔市价平仓
if marketposition<0 and var1 Crosses Above var2 then begin
buytocover("EXIT_sell") next bar at market;
end;
延伸阅读:法意教你伊利安星球答辩法
http://stasistw.blogspot.tw/2014/05/blog-post.html

Links booklink

Contact Us: admin [ a t ] ucptt.com