请看第5行,这是我们计算MACD信号线的方式。WealthScript的MACDSeries函式只是计算到ema12 – ema26的地步。如果要信号线我们便要将MACD再使用EMA(平滑系数)计算9天均值。WealthScript提供EMASeries函式来方便我们计算。查表得知: EMASeries( Series: integer; Period: integer ): integer; 我们可以写成 MACDSignal := EMASeries(MACDSeries(#Close),9); 或 MACDSignal := EMASeries(MACD1,9); 都可以成立。 接下来重点来啦!我们要把这两条线的数据相减得到MACD里的那个柱状图(MACD – MACD Signal)。嗯那就是直接抓MACD1来减MACDSignal?错!!!在WealthScript系列性数据(Series)是不能让你这样玩的!它有专属的四则运算专用函式,查表分别是: AddSeries( Series1: integer; Series2: integer ): integer; 加法 SubtractSeries( Series1: integer; Series2: integer ): integer; 减法 MultiplySeries( Series1: integer; Series2: integer ): integer; 乘法 DivideSeries( Series1: integer; Series2: integer ): integer; 除法 注意这四个函式专用于系列变量对系列变量运算。比如你想把所有的收盘价都乘以10那就不能用这些函式,你可以查表找一些后面加上Value的函式如: MultiplySeriesValue( Series: integer; Value: float ): integer; 这个函式就是系列变量对一般数值的运算。所以我们的第6行呼叫了系列数减法函式来得到我们要的MACD – MACD Signal系列数值。其他几行各位应该不会再有问题吧?没问题就按「GO」验收成果啰!
Wealth-Lab 特区【7】 写自己的指标「上」 几篇文章下来,我想大家已经对这个积木玩的不亦乐乎了。不过总觉得虽然吃了斯斯还是有些地方感觉痒痒的,因为这些积木都是Wealth-Lab提供的基本款,如果自己也能做些想要的积木形状岂不痛快哉?今天、我们就动手自己来做做看吧! 无论是使用T.S 2000i的EasyLanguage或是Wealth-Lab 的WealthScript,我们撰写指标都是从最基本的函式(Function)开始的;而每一个函式都只能回应(Return)单一数据结果。就如KD就要两个函式完成,一个完成%K的计算而另一个完成%D的计算;没有例外! 其次,Wealth-Lab开发环境提供许多精灵(Wizard)协助我们完成许多工作,其实这方面是比T.S 2000i的开发环境强很多的,如果你能细心去体会的话。这些精灵包括许多现成的样板支持减少程序书写的共享部份,与聪明的提供实时程序参考支持让你几乎可以不用伤脑筋翻书就可以完成程序开发。我想起前一阵子台湾引进在世界市场占有率很高的TomTom导航系统时,这个在世界享高知名度的软件被台湾用户批评的一无是处;终其原因是因为台湾使用者长时间习惯了本地的PaPaGo系统「积习难改」罢了!对我而言;我是一个从SuperChart时代就玩起的人,到末代的T.S 2000i你说我们对Omega谁的感情深?我并不建议交易工作的工具选择上也跟追求新指标一样,终究滚动的石头不生青苔。但是如果你想选择Wealth-Lab使用的人或想了解的人,开阔的心胸是非常重要的。 今天我们又要向Wealth-Lab的核心向前挺进一步!我们要写自己的指标!目标就是把我们自己的指标完成并列在左边的指标选用区里头。我们就拿KD来做范例吧;因为我还是习惯用那个单一参数的KD指标。首先我们就是呼叫上头说的精灵来帮我们完成!
新建立指标对话框(New Indicator),空白部份填入我们的指标名称。我们这次要建立的是KD指标,所以一共有两条线必须被显示出来。先完成我们的%K或称快线的部份,命名为「StochFast」(StochK已经被Wealth-Lab用走啦),完毕按下「OK」!
再来、这是设定指标参数的对话框(Indicator Parameters)。我们在第一格里有两个选项「Series与Period」,比如我们今天设计的是RSI,就可能先要设定Series使用#Close。但是今天我们只要天数参数来计算,所以我们选择「Period」。在数据形态(DataType)上选择整数。没问题按下增加参数图示「+ Add Parameter」
你会发现刚才设定的参数跑到下方的框框去啰!代表这个参数已经被记录了。如果你需要一个以上的参数就重复上一个步骤,如果设定有错误的话简单,你就点选那个要除之而后快的参数再单击「× Delete Parameter」。没问题一样按OK到下一步。
这就是精灵丢出来的样板!基本上来说如果你没需要做太复杂的计算,只要在绿色的{ Calculate your indicator value here }下方直接打入你要的表达式,然后改value := 计算结果;这样就可以完成一个指标了,够简单了吧?如果现在我说这节下课的话你有没有想要杀我的冲动? 当然你不会就这样放我走,我也不会让你这样轻松下课!还没让你头昏脑涨的话你别想溜!现在我们来解说这个样板吧!首先我们看到一个奇怪的东东,为什么精灵一次给我们两个函式呢? function StochFastSeries( Period: Integer ): integer; function StochFast( Bar: integer; Period: Integer ): float; 虽然我们是在建立一个新指标,但其实我们真正做的还是建立函式,所以我们看到了Function。跟EasyLanguage一样函式是系统之基础,建立函式而非直接建立提供显示的指针,方便我们在其他地方如交易系统上也可以顺利呼叫使用。在WealthScript中我们一次建立两个同性质的函式为了方便在不同场合或需求使用。这两个函式在名称的差别在一个多了系列(Series),这是包裹计算一次计算完我们的KD快线然后丢到另一个系列变量储存。而另外一个则是方便我们计算个别数据,你可以给它指定的那一天(Bar)与计算天数(Period)然后它会给你那天的KD快线数据(Return float)。大多数情况我们几乎不必理会下方的函式,很少有机会动到它,不过我们还是来了解它到底在干啥好事? function StochFast( Bar: integer; Period: Integer ): float; begin Result := GetSeriesValue( Bar, StochFastSeries( Period ) ); end; 其实整个函式就只有一条使用了GetSeriesValue函式。查表: GetSeriesValue( Bar: integer; Series: integer ): float; 它的功能就是从一个系列变量中取回指定位置的变量内容。所以我们可以用这个函式取得某一天的KD快线数据;在此我们取得的对像就是我们上头第一个函式StochFast的内容。GetSeriesValue的相对函式就是SetSeriesValue,把数据丢到系列变量的指定位置上,在上头的函式我们会利用到。 现在看到我们的函式主体,StochFastSeries部份。 function StochFastSeries( Period: Integer ): integer; Begin End; 这部份构成我们的主体,括符内的Period:Integer就是我们精灵一开头时我们设定的外部输入整数变量,这里代表设定KD的计算天数。所有的函式表达式将被规范在Begin跟End的范围。3到5行是一连串的使用变量宣告,这些大家应该不会有问题吧? 第7行sName := 'StochFast(' + IntToStr( Period ) + ')'; 这是一个字符串的计算式,它的结果会是sName等于StochFast(9)。这里又碰到一个陌生的字符串处理函式「IntToStr」,望文生义它是一个「Integer to String」整数转换为字符串的函式。我们不能把不同性质的东西拿来相互计算,Period在这里是个数字我们必须先把它转换成字符串才能拿来跟其他字符串在一起。查表: IntToStr( Value: integer ): string; 当然也有把字符串变成整数的StrToInt;或者是FloatToStr把带小数点的数字转换为字符串的函式。 第8行Result := FindNamedSeries( sName ); 使用了FindNameSeries函式查表: FindNamedSeries( SeriesName: string ): integer; 这个函式将询问系统是否有StochFast(9)名称的系列变量已经被建立使用?如果有将响应0,没有为-1。 第9行与第10为if Result >= 0 then Exit; 如果FindNameSeries响应为0或大于0(非-1)代表这个名称已经被使用,Exit将直接中断函式执行,以下所有的表达式都不会再被执行,直接拍屁屁走人。 第11行Result := CreateNamedSeries( sName ); 排除掉可能的名称冲突之后可以顺利的宣告并建立我们的StochFast(9)系列变量。我们使用CreateNameSeries函式来建立查表: CreateNamedSeries( SeriesName: string ): integer; CreateNameSeries将会建立一个空白的系列变量供我们放置KD的快线数据使用。另外有一个CreatSeries函式也是可以建立系列变量,两者唯一差别就在是否有对该变量命名。 12行的for循环: for Bar := Period to BarCount() - 1 do Begin End; 这段for循环将会一天一天的带着我们计算KD快线。给for的变量为Bar范围落在参数天数开始到最后一天。这里有些要说明的是BarCount是一个函式,它会响应所有的数据天数;问题在它老兄为什么要减1呢?故事是这样的啦!我们在计算机的世界里第一笔不是我们习惯的1而是从0起算的,所以第一天或第一笔的数据是存在内存的第0笔,而最近或最后一笔就自然是BarCount -1啦。所以我们的Period如果下的是第9天,事实上我们是从第10天的数据开始计算的。 第14行{ Calculate your indicator value here } ,我们之前有提过这是精灵建议我们从这里开始写我们的表达式的批注。 第15行Value := 0; 这里的Value将是我们最终的运算结果,将它填入换掉0。这个Value就如我们在EasyLanguage写函式最终也要Return回一个数值一样,在EasyLanguage我们如果函式名称为Function ABC,最后我们一定会写上 ABC = XXX; 道理是一样的。这里我们使用Value这个变量先来暂放结果。 第16行 SetSeriesValue( Bar, Result, Value ); 呼叫SetSeriesValue函式把结果的Value变量丢入我们的指定位置(Bar)置放。查表: SetSeriesValue( Bar: integer; Series: integer; Value: float ); 我们之前有提过它的亲戚相对的GetSeriesValue函式。 好啦!今天假日兼手酸了!就先谈完精灵的样板部份休息啰~
Wealth-Lab 特区【8】 写自己的指标「下」 这几天大家应该把样板搞清楚了吧?如果还不是,请不要继续读下去;不然你会更痛苦。但是一旦你弄清楚了,那么我增加的程序代码你就不会觉得看起来很累了。我们StochFast函式部份完成后如下:
KD的计算公式请自己去查书,我已经写的会做恶梦了!饶了我吧!我在第5行多加了一些浮点变量,这都是以下计算会用到的。增加的程序代码我依精灵的建议全部写在它标示的绿色指示位置以下,也就是在主要的for循环里头。 第15行 if Bar = Period then TodayK := 50; 利用 if then 判断式,我们给第一天的%K数据设定为50。由于 if 判断后我们只要执行一件工作,所以不必使用 begin ~ end; 来包含,但是16行的 if 之后必须做一堆计算,所以必须使用 begin ~ end; 来标示范围。 第16行 if Bar > Period then 当进行到大于设定天数以后的日子那时我们便要进行18行到22行间的算式,以求得%K。 第18行 HighP := Highest(Bar, #High, Period); 我们呼叫WealthScript内部函式Highest来求得设定天数内价格范围的最高价;查表: Highest( Bar: integer; Series: integer; Period: integer ): float; Highest函式回传一个浮点数,代入的参数为以Bar为准往前Period天或个数的Series系列数的最高数据。所以你如果给它#Close,它回的是几天内最高的收盘价。在此我们要的是指定天数内最高的每日高价 Highest #High。 第19行 LowP := Lowest(Bar, #Low, Period); 我们使用Highest的相对函式Lowest来求得最低的低价。Lowest 使用方式与参数设定同于Highest。 第20行 CloseP := GetSeriesValue(Bar, #Close); 得到今日的收盘。 第21行 Stoch := (CloseP - LowP) / (HighP - LowP) * 100; 这是计算不成熟随机值(RSV)。 第22行 TodayK := (Stoch / 3) + (LastK *2 / 3); 钝化RSV后我们便可求得今天的%K。至此、我们已经完成主要的运算得到本日的%K。 第24行 LastK := TodayK; 我们将今天的%K复制一份到LastK变量位置,这个LastK是记录前一天的%D。当我们程序进入到下一个 for 循环时,它就变成前一天的%K了。 第25行 Value := TodayK; 把样板的 Value := 0; 改成我们要回传的数据。当然你要是把这行去掉,直接把第26行改成SetSeriesValue( Bar, Result, TodayK );结果是相同的。到这里计算%K的函式就完成啰!没问题的话就把它存档:
WealthScript所有的程序代码都放到这个地方管理。你会看到很多分类如不同形态的交易方式的交易程序;其中Indicators目录就是存放指针函式的地方。未来你如果有需要的时候,找到你要修改的指标然后右键单击,选择选单里的「Open」就可以再把它叫出来编辑了。
基本上这个StochSlow的%D是直接在StochFast加上几行程序代码完成的,因为%D就是再钝化一次的%K值。本来这个%D应该可以用精简一点的算法完成的,就是直接呼叫StochFast 得到我们的%K。 图打出来后应该会像这样子!这样的KD我看起来比较顺眼。函式与指标的设计就到此,下次我们要往前推进到程序交易的设计部份。