第十三節 指標編寫

我們的交易信號都是來自對K線的分析。有些人把這些分析過程量化了,於是就成了指標。就用途來說,指標一般分為趨勢類指標、震盪類指標以及成交量指標。所謂趨勢類指標,顧名思義就是用於判斷趨勢的一類指標,比如均線、布林帶等;震盪類指標就是用於做震盪市場,高空低多的一類指標,比如RSI、KDJ等;成交量一類的指標用於多空方向的強弱,比如金錢流向、成交量等。雖然分了這幾類,實際上有些指標是可以相互用的,比如布林帶也可以用於做震盪,MACD也可以用於做趨勢。

MT4裡面有很多指標已經集成進去了,我們可以直接用,但是我們開發交易策略的時候總是要編寫一些裡面沒有的指標,比如做對沖的時候寫一個雙貨幣乖離度指標。

指標編寫函數

我們打開編輯器,新建一個自定義指標,如圖:

然後我們選擇獨立窗口指標,如果不選獨立窗口的話指標就會繪製在主圖上。

新建的指標如下圖,第一個紅框中表示的是指標採用的是獨立窗口,如果我們在前面新建的過程中選擇了獨立窗口指標那麼就會有這句代碼,如果要把指標改成主窗口指標,可以把這句改成#property indicator_chart_window。第二個紅框是初始化函數,只在指標加載的時候運行一次,這個和EA的初始化是一樣的。第三個紅框就是指標計算的函數了。

可以看到指標計算函數里面有十個參數,這十個參數不需要我們輸入,系統自動幫我們引用好了,我們可以直接使用。下面說一下這幾個參數的意義:

第一個參數是圖表裡面K線的總數;

第二個參數是已經計算完了的K線的個數,剛加載的時候是0;

第三到第十個參數分別是時間數組、開盤價數組、最高價數組、最低價數組、收盤價數組、 tick成交量數組、成交量數組以及點差數組,以上的數組我們都可以直接使用。

均線指標編寫

講了這麼多,估計大家還是有點迷糊,不知道怎麼使用,那麼接下來我們編寫一個簡單移動均線(SMA)試一下。

首先對均線的一些參數進行設置,代碼如下:

 #property strict #property indicator_chart_window #property indicator_buffers 1 #property indicator_plots 1 double MA[]; input int peri=10; int OnInit() { string name="SMA("+(string)peri+")"; SetIndexBuffer(0,MA,INDICATOR_DATA); SetIndexStyle(0,DRAW_LINE,STYLE_SOLID,1,clrBlue); IndicatorShortName(name); return(INIT_SUCCEEDED); }

對於畫線,需要1個緩衝區以及1個數據區,所以我們把indicator_buffers和indicator_plots都設置成了1,對於畫不同的對象(比如說話柱狀圖),各種對象需要的緩衝區和數據區個數都不一樣,參考下表:

可以看到,如果我要畫一根K線的話那就需要4個緩衝區,實際上緩衝區的數量取決於使用到的數據的類別數,K線有開、高、低、收四個數據,所以需要4個緩衝區。數據區的話就比較容易了,有多少個對象就需要有多少個數據區。

那麼接下來我們聲明了一個名字叫MA的數組,以及創建了一個可以接收外部輸入的變量,名字叫peri,這個變量用來存放輸入的均線的計算週期數,默認為10 .

接下來就是初始化函數OnInit()函數了,在這個函數當中我們首先聲明了一個name變量用來儲存均線的名稱,然後我們用SetIndexBuffer函數將數組MA[]和編號為0的指標數據綁定了,也就是說MA[]這個數組裡面的值,以後就用來繪製編號為0的指標了,MA[0]是多少,那麼當前這個指標的數值就是多少,MA[1]是多少那麼上一根K線的這個指標數值就是多少。關於指標的編號,第一個指標線的編號為0,往後順延,當然我們可以將任意的數組跟裡面的任意編號的指標線綁定,前提是不能超過緩衝區的數量。

然後我們設置了編號為0的指標的樣式,指標用線條繪製,線條樣式為實線,線寬為1,顏色為藍色,完成以上步驟後結束初始化過程。

接下來我們就要用OnCalculate函數來計算指標的值了,這個過程我們只要把MA[]這個數組填充好了就可以畫出所有K線的指標線。所以其實最關鍵的就是如何填充MA[]數組罷了。

這裡我們計算每個K線SMA的值,然後賦值給對應的MA數組裡面的組員即可,代碼如下:

 ……… int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int i; int j; double maadd=0; if(rates_total<peri) { return(0); } ArrayResize(MA,rates_total); if(prev_calculated==0) { for(i=0;i<=rates_total-peri;i++) { maadd=0; for(j=i;j<=i+peri-1;j++) { maadd=maadd+close[j]; } MA[i]=maadd/peri; } } else { maadd=0; for(j=0;j<=peri-1;j++) { maadd=maadd+close[j]; } MA[i]=maadd/peri; } return(rates_total); }

以上代碼中我們首先定義了用於循環的變量i和j,然後定義了一個用於累加的中間變量maadd。如果當前圖表總的K線根數rates_total小於我們輸入的周期peri的話,那麼我們知道這個移動平均線是沒辦法計算的,所以我們直接返回0,結束;否則的話就繼續指標的運算。

如果已經計算過的K線根數為0,也就是說剛加載指標的時候,指標一次都沒有計算過,那麼我們就要對所有的K線對應的指標進行計算。過程很簡單,我們從當前K線(編號為0)到編號為rates_total-peri做一個循環來逐個計算出每根K線的SMA值,這里為什麼是rates_total-peri呢,因為在這個編號後的K線由於數量小於週期,那麼就無法計算了。

對於編號為i的k線,它的SMA的值應該是包括這根K線在內的前peri根K線收盤價的平均值,那麼我們再做一個循環把這些K線的收盤價相加賦值給maadd,再將maadd除以peri就可以得出第i根K線的SMA值了。

我們加載一下指標,如下圖所示,可以看到圖表中多了一條藍色的均線,我們的代碼運行正確。要注意的是我們的指標只有一個輸入的參數那就是周期,其實均線的指標遠遠不止這麼簡單,其採用的價格以及計算方式不同,均線也是不一樣的,比如EMA和SMA就完全不一樣,這裡僅僅作為一個示例。

其他對像類型

我們可以將指標用不同的對象來表示,實際上就是在對應的時間和價格上畫一個對象。比如說我們把線條改成×號,代碼如下:

 #property strict #property indicator_chart_window #property indicator_buffers 1 #property indicator_plots 1 double MA[]; input int peri=10; int OnInit() { string name="SMA("+(string)peri+")"; SetIndexBuffer(0,MA,INDICATOR_DATA); SetIndexStyle(0,3,1,clrRed); IndicatorShortName(name); return(INIT_SUCCEEDED); } ……

運行之後的結果如下圖:

可以看到我們通過SetIndexStyle函數把線條改成了×號。所以我們看到的光滑的均線,實際上是由一個一個點連接起來的,它不是連續的。

這節課我們打下了一個指標編寫的基礎,那麼下節課我們試著去編寫一個對沖的指標來看一下鼎鼎大名的三角對沖策略是不是真的可以做到,下節課見。