本文不是一篇介绍如何编写一个性能优异模型的文章,本文的初衷是以抛砖引玉的方式来探讨发展和创新程序化交易编程的思路、方式、方法.
人类所有的智慧和文明,来源于对历史的积累和创新.”温故而知新”,在期货交易中同样适用.交易的目的是盈利,每一次进场和出场,都是对未来行情发展的一种预测,只是这种预测不是来自迷信,而是以历史数据的概率统计和分析为基础,加上不断发展和创新的产物.有人在多头趋势中做多,那是因为历史概率告诉他,趋势大多具有惯性,不会马上结束;有人在相对高点做空,同样也是来自对历史数据概率分析,行情总是以波浪形式在阴阳转换中轮回发展.因此,概率统计和分析是交易的基础和灵魂.但概率在一定范围内不是固定不变的,它自身也在历史的长河中不断发展和变化.
综上所述,一个拟合历史的交易模型不一定是性能优良的模型,但一个不能拟合历史的模型肯定不是性能优良的模型.
光阴一去不复返,这是大家都知道的道理,它告戒我们要从我做起,从现在做起,今天的事情今天做,那么,在程序化交易的程序中,我们同样可以用下面这一条简单的语句告诉计算机这一哲理.
这样我们可以让计算机在IF(DATE=TODAY,…..)的控制下完成今天要做的任何事情,如只在今天(也就是图表的最后一天)统计/绘图甚至交易,当然也可以根据个人习惯有其他姊妹写法, 前提是天天向上.如:
程序化交易模型设计和调试过程中,难免发现这样那样的问题.发现问题是好事,但不能头痛医头,脚痛医脚,如果不对产生问题的原因做深入细致的分析,找出从根本上解决问题的办法,也许尽管问题暂时消失了,并不代表将来不发生同样的问题.下面我们以大家非常熟悉一个简单的均线穿透模型为例来分析其中可能出现的问题,以及解决方法.
这个模型在使用中很容易出现指令反复和消失的现象,这是我们发现的问题,那么我们现在来分析问题.在K线数据中,最常用的数据有开盘价、最高价、最低价、收盘价,他们有如下特征.
分析问题:从上表价格特征和均价公式可知,导致指令反复和消失的原因是引用了盘中可变的CLOSE.
解决问题:一个问题可能存在多种解决途径.下面列举几种常用的解决这个模型指令反复和消失的方法.
选择等待K线走完再发指令,即勾选文华软件界面上的等待K线走完选项.
不勾选等待K线走完,但将模型更改如下,用开盘价测试比较准确,模型执行会在开盘价附近成交,信号显示与指令同步,指令时效与上面等同.
MA1:=MA(CLOSE,N1);
MA2:=MA(CLOSE,N2);
REF(CROSS(MA1,MA2),1),BPK;
REF(CROSS(MA2,MA1),1),SPK;
上面两种方法虽然能解决问题,但同时也带来了与理想设计相比的延时现象,要达到理想效果,我们不妨以上穿为例来分析一下穿透的瞬态,从简单平均算法的原理及开平条件可以看出,穿透瞬态必然满足如下条件,CLOSE=HIGH并且MA1>=MA2,并且CLOSE为MA1和MA2共用,由于HIGH具有上增长不可逆特征,在这个瞬间我们用HIGH代替与之相等的CLOSE,就可以排除指令反复和消失现象.当然,这只是针对这个连续持仓的模型,如果是断续持仓的模型,则还需要考虑更多问题,在接下来的[信号竞争与仲裁]中会谈到.
根据MA原理可知,下面两行代码等价.
MA1:=MA(CLOSE,N1);
MA1:=(REF(MA(CLOSE,N1-1),1)*(N1-1)+CLOSE)/N1;
现在就可以用如下代码来表达原模型的思想并解决指令反复和消失现象.
MA1H:=(REF(MA(CLOSE,N1-1),1)*(N1-1)+HIGH)/N1;
MA2H:=(REF(MA(CLOSE,N2-1),1)*(N2-1)+HIGH)/N2;
MA1L:=(REF(MA(CLOSE,N1-1),1)*(N1-1)+LOW)/N1;
MA2L:=(REF(MA(CLOSE,N2-1),1)*(N2-1)+LOW)/N2;
CROSS(MA1H,MA2H),BPK;
CROSS(MA2L,MA1L),SPK;
发现规律和利用规律
通过对历史数据的统计和分析,前辈们已经总结了很多有价值的规律,如果善于观察,我们也许还能发现一些另外的不曾被重视的规律.
举个例子,在设计追踪止损模块时,按照追踪止损定义,设定获利阀值和回撤止损值都是固定的某一数值,在实际应用中,虽然有一定效果,但效果并不是特别理想,观察发现,这个止损的合理值与最近一段时期的振幅有很大关系,并且这种关联的表现近似为一个顶点在第一象限的二次函数图象.那么,假设D为最小止损值,X为振幅,Y为实际止损值,文华语言的函数关系式可如下表示.
Y:=MAX(D,-A*SQUARE(X)+B*X+D);
止损值肯定有一定的范围,所以必须先定义最小值D和最大值,这可以通过统计分析得出,同时还可以找到对应止损最大值的幅度,设这个已知幅度为F,由于函数曲线的顶点在第一象限,顶点值即最大止损值,将已知最大止损值设定为TOP,那么可以用下面方程组计算 出A和B.
-B/(2*A)=F; ①
(4*A*D-B²)/4A=TOP; ②
解上面方程组,求出A和B.的解.然后将A,B,D带入上面的函数表达式,就完成了Y(即止损值)的自适应变化.Y将在最小止损值D到最大止损值TOP这个范围内根据X的变化而变化,它实际上就是上面抛物线函数在第一象限的部分连续曲线段.
通过这个例子,我们将它应用到反手操作上,实际效果也不错.
信号竞争与仲裁
在编程过程中,编程逻辑相当重要,但并不是排除了所有单条语句或单个模块的逻辑错误,就代表整个模型不再有冲突,当有这种冲突发生时,我们称之为竞争.为方便说明问题,下面还是列举一个简单例子.
HIGH>REF(HHV(HIGH,4),1),BK;
LOW<REF(LLV(LOW,4),1),SK;
很显然,如果将上面两条语句的条件部分应用在持续持仓的系统中(只使用BPK和SPK),由于平台有自动过滤机制,不会有多大问题,但如果将它应用在不过滤系统或有混合指令的断续交易系统中,若在空仓状态下,当本周最高价大于前四周最高价且最低价小于前4周最低价,这时在同一周期内即做多又做空,形成了冲突,也就是我说的信号竞争,模型到底是多还是空呢?这就需要引入仲裁机制.对竞争进行仲裁,方法很多,可以利用趋势仲裁,也可以使用已经发生的某一状态或指标等来进行仲裁.在交易模型设计中,竞争是允许的,仲裁也不是必须的,但必须根据实际情况全面考虑各种因数,然后决定是否使用仲裁.
信号竞争与仲裁更多的被应用在对信号的分析和统计上.
验证
程序开发过程中和设计完成后,都要进行验证,验证的方法很多,既可以对单条语句或单个模块进行验证,也可以对整个模型进行验证.我们一般采用的有图形化验证,历史数据测试,K线复盘,实时模拟测试等等.经过这些初步验证,各方面性能指标达到满意后,还要进行一段时间的实盘验证.所有的验证过程中,都有可能发现新问题,只有在全部问题关闭后,才可以正式投入使用.