您现在的位置: 比特财富网 >> 财经 >  >> 外匯
MT4編程之MACD EA詳解
外_匯_邦 WaiHuiBang.com

在MT4安裝後,默認會給用戶提供幾個例子程序,這些程序對於新學習EA開發過程中有很大的幫助,下面我們就來對MACD Sample這個例子EA來做個解讀,來看看別人是如何開發一個EA的。www.emoneybtc.com

首先是注釋,在MQL語言中所有//的這一行就是注釋行,系統本身不會去執行它,它只是用來解釋當前代碼的含義的,我們在代碼中加入這些注釋為了是讓我們能夠清楚的閱讀代碼的含義,在程序中加入詳細的注釋是一個很好的編程習慣,我們鼓勵大家多加入注釋。很多人覺得注釋這東西因為沒用在寫代碼中覺得很麻煩而忽略它,但是即使是自己編寫的程序如果不加注釋過幾天就會忘記意思,還要再一行一行地看這些代碼,所以注釋是非常重要的。

下面這些就是定義變量,我們發現前面加上了extern關鍵字,如果在定義變量的前面有這個詞說明這個變量將會被作為EA運行的參數,舉個例子,比如我要編寫一個EA,在使用過程中我想改變它的止盈和止損值,如果我程序都是事先編好的止盈止損,那麼以後要改動它必須要改代碼,這樣不僅麻煩也不靈活,如果我把這些信息作為EA運行參數,那麼在EA運行中就可以隨時調整它了。

extern double TakeProfit = 50;

extern double Lots = 0.1;

extern double TrailingStop = 30;

extern double MACDOpenLevel=3;

extern double MACDCloseLevel=2;

extern double MATrendPeriod=26;

上面定義了6個變量並且都是當作參數,這裡設定變量名稱的時候盡量使用用戶可以理解的詞匯,在EA的參數設置裡這些變量名就是參數的名字。值得注意的是EA裡變量名稱是可以用中文的。

int start()

start()函數是EA運行的核心,MQL語言規定了幾個默認函數,其中EA第一次運行時會調用init()函數,在這個函數裡我們可以放入一些需要初始化的信息,start()函數中放我們EA的核心代碼,每次一個TICK(換句話說就是新報價)來到後,系統會自動調用start()函數。deinit()函數是當EA關閉的時候調用的,這裡放一些我們程序停止後需要“善後”的代碼。start()函數是必須要有的,其它兩個函數如果不需要可以不用寫。

if(Bars<100)

{

        Print("bars less than 100");

        return(0);  

}

上面代碼的意思是如果當前圖表中的k線少於100根將會在日志信息裡輸出提示信息並且結束start()函數的執行。return的意思是返回,如果在程序中判斷出有錯誤,下面的代碼無法繼續執行了,我們調用return()函數讓他退出start()函數的執行。

if(TakeProfit<10)

{

        Print("TakeProfit less than 10");

        return(0);  // check TakeProfit

}

上面的代碼意思是如果參數裡的TakeProfit變量小於10也提示一條信息並結束執行,TakeProfit從字面的意思中我們可以知道是止盈的意思,有些平台會限制下單時的止盈點數不得小於某個點,如果小於某值會在下單時報錯,為了避免這種錯誤我們會限制參數中止盈的設定。

其實這裡可以調用MarketInfo()函數得到我們當前平台中允許的止盈止損最小值從而根據平台的不同自動計算出最小的止盈點數,詳細情況請參閱文檔MarketInfo()函數的描述。

MacdCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,0);

MacdPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_MAIN,1);

SignalCurrent=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,0);

SignalPrevious=iMACD(NULL,0,12,26,9,PRICE_CLOSE,MODE_SIGNAL,1);

MaCurrent=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,0);

MaPrevious=iMA(NULL,0,MATrendPeriod,0,MODE_EMA,PRICE_CLOSE,1);

以上語句是調用了MQL的一些內置指標函數,在MQL語言中,對於常用的指標如均線,MACD,KD等MQL已經提供給我們現成的函數,我們只要調用他即可得到指標的值(相見文檔技術指標部分:http://docs.mql4.com/cn/indicators)。

就上面的代碼,MacdCurrent的值是參數為12,26,9的MACD主線當前K線的值,MacdPrevious則是MacdCurrent前一根K線的值,SignalCurrent和SignalPrevious則是相同參數信號線的當前值和前一根值。

後兩個是調用均線指標函數,這裡的均線周期參數則是使用了EA的參數變量MATrendPeriod,這樣寫是個好習慣,把調用指標的參數放到EA參數裡,這樣可以隨時在運行中調整這些參數方便我們改變策略。MaCurrent和MaPrevious是得到26均線的當前K線值和前一根的值。

total=OrdersTotal();

if(total<1)

上面的代碼就是判斷我們當前是否有單子在做,他調用了OrdersTotal()函數,它可以計算當前賬戶中一共還沒有平倉的單子和掛單的個數,如果它小於1說明當前沒有任何單子,這種判斷方法只是一種簡單的判斷法,如果這個EA在運行過程中人為也去下單則EA永遠不會下單了,如果要更加精確的計算這個EA所下的單子數量還需要利用其他方法,這些技巧我們會在以後的文章中介紹。

if(AccountFreeMargin()<(1000*Lots))

{

        Print("We have no money. Free Margin = ", AccountFreeMargin());

        return(0);  

}    

上面的代碼是計算當前的剩余保證金是否小於1000,如果太少錢會不夠用,所以會輸出下當前的保證金還剩多少並退出。

if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious<SignalPrevious && MathAbs(MacdCurrent)>(MACDOpenLevel*Point) && MaCurrent>MaPrevious)

{

        ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,0,Ask+TakeProfit*Point,"macd sample",16384,0,Green);

        if(ticket>0)

        {

      if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("BUY order opened : ",OrderOpenPrice());

        }

        else Print("Error opening BUY order : ",GetLastError()); 

        return(0); 

}

上面這段就是多單開倉部分了,條件是這樣:如果當前MACD主線在0軸以下,MACD“金叉”,MACD的主線不在0軸附近(這塊是EA的參數來指定0軸附近多少點)並且還要當前的均線是上升的。

這裡最精彩的部分在於如何判斷MACD“金叉”,如何判斷MACD值不在0軸附近和均線目前是上升的還是下降的。

“金叉”的判斷是EA裡用的比較多的,這裡我們用了判斷大小的方法就能很容易的計算它,首先得到MACD兩根線當前的值和上一根K線的MACD值,如果上一根K線的MACD主線大於信號線並且當前的MACD主線小於信號線那麼就相當於這兩根線做了一個“交叉”,因此我們可以認為MACD“金叉”了。從這裡我們也能看出來用計算機的方法來解決我們人類所認知的問題靠的都是這種具體數值的計算,所以計算機還是比較“死板”的,如果兩根線“扭”在了一起那麼用計算機程序很難判斷出來,這些就是目前計算機程序的缺點。

0軸附近這種判斷方法這裡利用了一點數學方面的知識,不過不用擔心都是很簡單的算法。把MACD值做絕對值運算然後判斷是否大於指定的值,因為MACD會是負值做絕對值運算後直接判斷是否大於設定的值就行了,這塊相當於是簡化了判斷語句的條件。

均線的上升和下降判斷和“金叉”的算法差不多,得到當前均線值和前一根線的均線值,如果前一根均線值小於當前值那麼就說明均線是上升的。

if(MacdCurrent>0&&MacdCurrent<SignalCurrent&&MacdPrevious>SignalPrevious&& MacdCurrent>(MACDOpenLevel*Point) && MaCurrent<MaPrevious)

{

        ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,0,Bid-TakeProfit*Point,"macd sample",16384,0,Red);

        if(ticket>0)

        {

        if(OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) Print("SELL order opened : ",OrderOpenPrice());

        }

        else

                Print("Error opening SELL order : ",GetLastError()); 

        return(0);

這段代碼就是空單的進場條件,和上面的正相反。值得說明是這兩個下單代碼中會遇到下單失敗的情況,因為當用OrderSend()函數下單後會返回一個大於0的整數訂單號數值,利用這一點就可以很容易的知道下單是否成功了。

下面的代碼是平倉和移動止損部分,這段代碼比較難懂,但是卻是非常重要的部分,因為在編寫EA中這些操作會經常遇到,讓我們來一點一點的拆解開來理解下它們的含義。

for(cnt=0; cnt<total; cnt++)

當前存在的訂單中我們要判斷是否到達平倉的條件,所以第一步我們首先要對所有在下的單子進行一次遍歷,一個一個的去判斷它們是否達到平倉條件。

此代碼中利用了一個循環語句從第一單開始一單一單的循環,這裡值得注意的是所有單子都是按照下單的先後順序存放的,第一張單子的編號是0而不是1,這是編程語言中一般都采取的方法,我們在編寫程序的時候一定要注意它的值要從0開始。

OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);

上面是選擇訂單操作,當循環一次訂單後,必須調用OrderSelect()函數來鎖定這一訂單,這樣下面的操作才可以正常運行。這裡最容易出錯的地方是函數的第二個參數如果查一下文檔我們會發現它有兩個選項:SELECT_BY_POS和SELECT_BY_TICKET。第一種方式是根據訂單的位置進行選定操作,這個例子中就是使用了這種方式,第二種方式是根據訂單號來進行選定操作,因為我們並不知道所有單子的訂單號是多少所以我們只能使用第一種方式來選擇訂單,剛才說過訂單是按照下單的先後順序來存放的,因此如果是第一個單子那麼就是0,如果是第二個單子就是1,最後一個單子是總單子數減一。

if(OrderType()<=OP_SELL &&   // check for opened position 

        OrderSymbol()==Symbol())  // check for symbol

上面的代碼段又運用了一個小技巧,它首先調用了OrderType()函數來得到所選定的訂單是多單還是空單,但是我們查下這個函數的定義(http://docs.mql4.com/cn/constants/trading)發現多單的值是0,空單的值是1,那麼如果OrderType()函數小於等於空單的值那麼相當於在判斷當前訂單是否是非掛單。

第二個條件是判斷當前單子的貨幣對是否和當前圖表相同,這個判斷是為了防止我們處理訂單過程中誤操作了其他不是EA所下的單子。

if(OrderType()==OP_BUY)   // long position is opened

{

        // should it be closed?

        if(MacdCurrent>0 && MacdCurrent<SignalCurrent && MacdPrevious>SignalPrevious && MacdCurrent>(MACDCloseLevel*Point))

        {

                OrderClose(OrderTicket(),OrderLots(),Bid,3,Violet); // close position

                return(0); // exit

        }

多單的平倉部分代碼,這裡其實就是去掉均線條件的空單下單信號,平倉操作中一定要注意在平倉完成後必須終止這個遍歷訂單的循環,因為平倉後會打亂所有單子的順序,造成誤操作其他訂單。

我們在這裡舉個例子就能明白為什麼要這麼做:比如當前有三個單子沒有平倉,按照順序排列序號是0、1、2,如果第二個單子平倉後第三個單子序號就會提前,這樣當下一輪循環執行到OrderSelect()函數後會因為沒有這個編號而出現錯誤。

if(TrailingStop>0)  

{                 

        if(Bid-OrderOpenPrice()>Point*TrailingStop)

        {

                if(OrderStopLoss()<Bid-Point*TrailingStop)

                {

                     OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);

                     return(0);

                }

        }

}     

這段代碼就是多單的移動止損部分,當參數TrailingStop大於0的時候EA就開啟了移動止損功能(默認設定是30,也就是說默認情況下是開啟移動止損的),我們就用我們這個例子EA的默認參數30點來說明,當單子的盈利大於30點並且單子的止損點和當前價位相差30點以上時,修改訂單的止損到當前價格以下30點位置。

我們在上面的程序裡屢次發現作者使用Point變量來計算點位,這個變量是MT4運行環境中自動設定的值,它在MQL語言中叫做預定義變量(關於預定義變量可以參考這裡:http://docs.mql4.com/cn/predefined/variables),Point告訴我們當前貨幣對的價格最小點值是多少,舉個例子:歐元對美元的價格總是X.XXXX這種形式,它的Point值就是0.0001,當我們想設定當價格大於30點這種情況時,我們只要用30乘以Point就可以計算這個貨幣對的實際30點值。不過Point常量在很多平台中不能正確的來實現它本身的功能了,原因是很多平台已經改為小數點後5位,這樣Point值變成了0.00001,我們直接用他來乘以點位得到是卻是實際點位的十分之一,這樣會在EA的運行中出現致命的邏輯錯誤。因此如果是5位的平台,需要在那些點位的值上乘以10來修正這個問題。關於Point的完美解決方法我們將在後續的文章中繼續討論。

以上就是MT4例子EA的解讀,這個程序雖然比較復雜但是它卻是一個很好的例子,裡面涉及到了我們在寫EA程序過程中常用到的一些功能,對於初學EA程序的人來說幫助很大,我們也可以修改這個程序的開倉、平倉部分直接變成我們自己的邏輯。

外_匯_邦 WaiHuiBang.com
  • 期貨一手黃金需要准備多少

        在實際交易中,期貨公司可能會收到10%~12%的保證金,即便如此,投資者實際交易一手黃金期貨的保證金也在500

  • 識別變盤前六點征兆看盤技巧

    市場發生變盤前,總會呈現出一些預兆性的市場特征:  一、指數在某一狹小區域內保持橫盤震蕩整理的走勢,處於上下兩難、漲跌空間均有限的境地中;二

  • 原油期貨跌為負會倒虧嗎

    為什麼5月原油期貨會跌成負值?|原油期貨   原標題:為什麼5月原油期貨會跌成負值? 來源:證券時報網 周一(4月20日

  • 2019白金信用卡神卡有哪些?

    最佳答案: 2019年白金信用卡神卡推薦:1、農行樂絢白金信用卡有銀聯和萬事達兩種卡組織,小白金信用

  • 網上領券買東西安全嗎?

    最佳答案: 如果是從希財省錢購這樣的正規平台領取優惠券,那麼買到的東西是安全的,和直接在淘寶、京東、

  風險提示:比特財富網的各種信息資料僅供參考,不構成任何投資建議,不對任何交易提供任何擔保,亦不構成任何邀約,不作為任何法律文件,投資人據此進行投資交易而產生的後果請自行承擔,本網站不承擔任何責任,理財有風險,投資需謹慎。
比特財富網 版權所有 © www.emoneybtc.com