小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

一步一步解讀MT4的例子EA

 灰暉 2010-11-28
一步一步解讀MT4的例子EA

關(guān)于什么是EA請(qǐng)看此文章(連接到http://www./html/c350/2010-02/1239235.htm

在MT4安裝后,默認(rèn)會(huì)給用戶(hù)提供幾個(gè)例子程序,這些程序?qū)τ谛聦W(xué)習(xí)EA開(kāi)發(fā)過(guò)程中有很大的幫助,下面我們就來(lái)對(duì)MACD Sample這個(gè)例子EA來(lái)做個(gè)解讀,來(lái)看看別人是如何開(kāi)發(fā)一個(gè)EA的。

首先是注釋?zhuān)贛QL語(yǔ)言中所有//的這一行就是注釋行,系統(tǒng)本身不會(huì)去執(zhí)行它,它只是用來(lái)解釋當(dāng)前代碼的含義的,我們?cè)诖a中加入這些注釋為了是讓我們能夠清楚的閱讀代碼的含義,在程序中加入詳細(xì)的注釋是一個(gè)很好的編程習(xí)慣,我們鼓勵(lì)大家多加入注釋。很多人覺(jué)得注釋這東西因?yàn)闆](méi)用在寫(xiě)代碼中覺(jué)得很麻煩而忽略它,但是即使是自己編寫(xiě)的程序如果不加注釋過(guò)幾天就會(huì)忘記意思,還要再一行一行地看這些代碼,所以注釋是非常重要的。

下面這些就是定義變量,我們發(fā)現(xiàn)前面加上了extern關(guān)鍵字,如果在定義變量的前面有這個(gè)詞說(shuō)明這個(gè)變量將會(huì)被作為EA運(yùn)行的參數(shù),舉個(gè)例子,比如我要編寫(xiě)一個(gè)EA,在使用過(guò)程中我想改變它的止盈和止損值,如果我程序都是事先編好的止盈止損,那么以后要改動(dòng)它必須要改代碼,這樣不僅麻煩也不靈活,如果我把這些信息作為EA運(yùn)行參數(shù),那么在EA運(yùn)行中就可以隨時(shí)調(diào)整它了。

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個(gè)變量并且都是當(dāng)作參數(shù),這里設(shè)定變量名稱(chēng)的時(shí)候盡量使用用戶(hù)可以理解的詞匯,在EA的參數(shù)設(shè)置里這些變量名就是參數(shù)的名字。值得注意的是EA里變量名稱(chēng)是可以用中文的。

int start()

start()函數(shù)是EA運(yùn)行的核心,MQL語(yǔ)言規(guī)定了幾個(gè)默認(rèn)函數(shù),其中EA第一次運(yùn)行時(shí)會(huì)調(diào)用init()函數(shù),在這個(gè)函數(shù)里我們可以放入一些需要初始化的信息,start()函數(shù)中放我們EA的核心代碼,每次一個(gè)TICK(換句話說(shuō)就是新報(bào)價(jià))來(lái)到后,系統(tǒng)會(huì)自動(dòng)調(diào)用start()函數(shù)。deinit()函數(shù)是當(dāng)EA關(guān)閉的時(shí)候調(diào)用的,這里放一些我們程序停止后需要“善后”的代碼。start()函數(shù)是必須要有的,其它兩個(gè)函數(shù)如果不需要可以不用寫(xiě)。

if(Bars<100)
{
        Print("bars less than 100");
        return(0);  
}

上面代碼的意思是如果當(dāng)前圖表中的k線少于100根將會(huì)在日志信息里輸出提示信息并且結(jié)束start()函數(shù)的執(zhí)行。return的意思是返回,如果在程序中判斷出有錯(cuò)誤,下面的代碼無(wú)法繼續(xù)執(zhí)行了,我們調(diào)用return()函數(shù)讓他退出start()函數(shù)的執(zhí)行。

if(TakeProfit<10)
{
        Print("TakeProfit less than 10");
        return(0);  // check TakeProfit
}

上面的代碼意思是如果參數(shù)里的TakeProfit變量小于10也提示一條信息并結(jié)束執(zhí)行,TakeProfit從字面的意思中我們可以知道是止盈的意思,有些平臺(tái)會(huì)限制下單時(shí)的止盈點(diǎn)數(shù)不得小于某個(gè)點(diǎn),如果小于某值會(huì)在下單時(shí)報(bào)錯(cuò),為了避免這種錯(cuò)誤我們會(huì)限制參數(shù)中止盈的設(shè)定。
其實(shí)這里可以調(diào)用MarketInfo()函數(shù)得到我們當(dāng)前平臺(tái)中允許的止盈止損最小值從而根據(jù)平臺(tái)的不同自動(dòng)計(jì)算出最小的止盈點(diǎn)數(shù),詳細(xì)情況請(qǐng)參閱文檔MarketInfo()函數(shù)的描述。

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);

以上語(yǔ)句是調(diào)用了MQL的一些內(nèi)置指標(biāo)函數(shù),在MQL語(yǔ)言中,對(duì)于常用的指標(biāo)如均線,MACD,KD等MQL已經(jīng)提供給我們現(xiàn)成的函數(shù),我們只要調(diào)用他即可得到指標(biāo)的值(相見(jiàn)文檔技術(shù)指標(biāo)部分:http://docs./cn/indicators)。
就上面的代碼,MacdCurrent的值是參數(shù)為12,26,9的MACD主線當(dāng)前K線的值,MacdPrevious則是MacdCurrent前一根K線的值,SignalCurrent和SignalPrevious則是相同參數(shù)信號(hào)線的當(dāng)前值和前一根值。
后兩個(gè)是調(diào)用均線指標(biāo)函數(shù),這里的均線周期參數(shù)則是使用了EA的參數(shù)變量MATrendPeriod,這樣寫(xiě)是個(gè)好習(xí)慣,把調(diào)用指標(biāo)的參數(shù)放到EA參數(shù)里,這樣可以隨時(shí)在運(yùn)行中調(diào)整這些參數(shù)方便我們改變策略。MaCurrent和MaPrevious是得到26均線的當(dāng)前K線值和前一根的值。

total=OrdersTotal();
if(total<1)

上面的代碼就是判斷我們當(dāng)前是否有單子在做,他調(diào)用了OrdersTotal()函數(shù),它可以計(jì)算當(dāng)前賬戶(hù)中一共還沒(méi)有平倉(cāng)的單子和掛單的個(gè)數(shù),如果它小于1說(shuō)明當(dāng)前沒(méi)有任何單子,這種判斷方法只是一種簡(jiǎn)單的判斷法,如果這個(gè)EA在運(yùn)行過(guò)程中人為也去下單則EA永遠(yuǎn)不會(huì)下單了,如果要更加精確的計(jì)算這個(gè)EA所下的單子數(shù)量還需要利用其他方法,這些技巧我們會(huì)在以后的文章中介紹。

if(AccountFreeMargin()<(1000*Lots))
{
        Print("We have no money. Free Margin = ", AccountFreeMargin());
        return(0);  
}

上面的代碼是計(jì)算當(dāng)前的剩余保證金是否小于1000,如果太少錢(qián)會(huì)不夠用,所以會(huì)輸出下當(dāng)前的保證金還剩多少并退出。

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);
}

上面這段就是多單開(kāi)倉(cāng)部分了,條件是這樣:如果當(dāng)前MACD主線在0軸以下,MACD“金叉”,MACD的主線不在0軸附近(這塊是EA的參數(shù)來(lái)指定0軸附近多少點(diǎn))并且還要當(dāng)前的均線是上升的。
這里最精彩的部分在于如何判斷MACD“金叉”,如何判斷MACD值不在0軸附近和均線目前是上升的還是下降的。
“金叉”的判斷是EA里用的比較多的,這里我們用了判斷大小的方法就能很容易的計(jì)算它,首先得到MACD兩根線當(dāng)前的值和上一根K線的MACD值,如果上一根K線的MACD主線大于信號(hào)線并且當(dāng)前的MACD主線小于信號(hào)線那么就相當(dāng)于這兩根線做了一個(gè)“交叉”,因此我們可以認(rèn)為MACD“金叉”了。從這里我們也能看出來(lái)用計(jì)算機(jī)的方法來(lái)解決我們?nèi)祟?lèi)所認(rèn)知的問(wèn)題靠的都是這種具體數(shù)值的計(jì)算,所以計(jì)算機(jī)還是比較“死板”的,如果兩根線“扭”在了一起那么用計(jì)算機(jī)程序很難判斷出來(lái),這些就是目前計(jì)算機(jī)程序的缺點(diǎn)。
 
0軸附近這種判斷方法這里利用了一點(diǎn)數(shù)學(xué)方面的知識(shí),不過(guò)不用擔(dān)心都是很簡(jiǎn)單的算法。把MACD值做絕對(duì)值運(yùn)算然后判斷是否大于指定的值,因?yàn)镸ACD會(huì)是負(fù)值做絕對(duì)值運(yùn)算后直接判斷是否大于設(shè)定的值就行了,這塊相當(dāng)于是簡(jiǎn)化了判斷語(yǔ)句的條件。
均線的上升和下降判斷和“金叉”的算法差不多,得到當(dāng)前均線值和前一根線的均線值,如果前一根均線值小于當(dāng)前值那么就說(shuō)明均線是上升的。

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);

這段代碼就是空單的進(jìn)場(chǎng)條件,和上面的正相反。值得說(shuō)明是這兩個(gè)下單代碼中會(huì)遇到下單失敗的情況,因?yàn)楫?dāng)用OrderSend()函數(shù)下單后會(huì)返回一個(gè)大于0的整數(shù)訂單號(hào)數(shù)值,利用這一點(diǎn)就可以很容易的知道下單是否成功了。

下面的代碼是平倉(cāng)和移動(dòng)止損部分,這段代碼比較難懂,但是卻是非常重要的部分,因?yàn)樵诰帉?xiě)EA中這些操作會(huì)經(jīng)常遇到,讓我們來(lái)一點(diǎn)一點(diǎn)的拆解開(kāi)來(lái)理解下它們的含義。

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

當(dāng)前存在的訂單中我們要判斷是否到達(dá)平倉(cāng)的條件,所以第一步我們首先要對(duì)所有在下的單子進(jìn)行一次遍歷,一個(gè)一個(gè)的去判斷它們是否達(dá)到平倉(cāng)條件。
此代碼中利用了一個(gè)循環(huán)語(yǔ)句從第一單開(kāi)始一單一單的循環(huán),這里值得注意的是所有單子都是按照下單的先后順序存放的,第一張單子的編號(hào)是0而不是1,這是編程語(yǔ)言中一般都采取的方法,我們?cè)诰帉?xiě)程序的時(shí)候一定要注意它的值要從0開(kāi)始。

OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);

上面是選擇訂單操作,當(dāng)循環(huán)一次訂單后,必須調(diào)用OrderSelect()函數(shù)來(lái)鎖定這一訂單,這樣下面的操作才可以正常運(yùn)行。這里最容易出錯(cuò)的地方是函數(shù)的第二個(gè)參數(shù)如果查一下文檔我們會(huì)發(fā)現(xiàn)它有兩個(gè)選項(xiàng):SELECT_BY_POS和SELECT_BY_TICKET。第一種方式是根據(jù)訂單的位置進(jìn)行選定操作,這個(gè)例子中就是使用了這種方式,第二種方式是根據(jù)訂單號(hào)來(lái)進(jìn)行選定操作,因?yàn)槲覀儾⒉恢浪袉巫拥挠唵翁?hào)是多少所以我們只能使用第一種方式來(lái)選擇訂單,剛才說(shuō)過(guò)訂單是按照下單的先后順序來(lái)存放的,因此如果是第一個(gè)單子那么就是0,如果是第二個(gè)單子就是1,最后一個(gè)單子是總單子數(shù)減一。

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

上面的代碼段又運(yùn)用了一個(gè)小技巧,它首先調(diào)用了OrderType()函數(shù)來(lái)得到所選定的訂單是多單還是空單,但是我們查下這個(gè)函數(shù)的定義(http://docs./cn/constants/trading)發(fā)現(xiàn)多單的值是0,空單的值是1,那么如果OrderType()函數(shù)小于等于空單的值那么相當(dāng)于在判斷當(dāng)前訂單是否是非掛單。
第二個(gè)條件是判斷當(dāng)前單子的貨幣對(duì)是否和當(dāng)前圖表相同,這個(gè)判斷是為了防止我們處理訂單過(guò)程中誤操作了其他不是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
        }

多單的平倉(cāng)部分代碼,這里其實(shí)就是去掉均線條件的空單下單信號(hào),平倉(cāng)操作中一定要注意在平倉(cāng)完成后必須終止這個(gè)遍歷訂單的循環(huán),因?yàn)槠絺}(cāng)后會(huì)打亂所有單子的順序,造成誤操作其他訂單。
我們?cè)谶@里舉個(gè)例子就能明白為什么要這么做:比如當(dāng)前有三個(gè)單子沒(méi)有平倉(cāng),按照順序排列序號(hào)是0、1、2,如果第二個(gè)單子平倉(cāng)后第三個(gè)單子序號(hào)就會(huì)提前,這樣當(dāng)下一輪循環(huán)執(zhí)行到OrderSelect()函數(shù)后會(huì)因?yàn)闆](méi)有這個(gè)編號(hào)而出現(xiàn)錯(cuò)誤。

if(TrailingStop>0)  
{                 
        if(Bid-OrderOpenPrice()>Point*TrailingStop)
        {
                if(OrderStopLoss()<Bid-Point*TrailingStop)
                {
                        OrderModify(OrderTicket(),OrderOpenPrice(),Bid-Point*TrailingStop,OrderTakeProfit(),0,Green);
                        return(0);
                }
        }
}

這段代碼就是多單的移動(dòng)止損部分,當(dāng)參數(shù)TrailingStop大于0的時(shí)候EA就開(kāi)啟了移動(dòng)止損功能(默認(rèn)設(shè)定是30,也就是說(shuō)默認(rèn)情況下是開(kāi)啟移動(dòng)止損的),我們就用我們這個(gè)例子EA的默認(rèn)參數(shù)30點(diǎn)來(lái)說(shuō)明,當(dāng)單子的盈利大于30點(diǎn)并且單子的止損點(diǎn)和當(dāng)前價(jià)位相差30點(diǎn)以上時(shí),修改訂單的止損到當(dāng)前價(jià)格以下30點(diǎn)位置。
我們?cè)谏厦娴某绦蚶飳掖伟l(fā)現(xiàn)作者使用Point變量來(lái)計(jì)算點(diǎn)位,這個(gè)變量是MT4運(yùn)行環(huán)境中自動(dòng)設(shè)定的值,它在MQL語(yǔ)言中叫做預(yù)定義變量(關(guān)于預(yù)定義變量可以參考這里:http://docs./cn/predefined/variables),Point告訴我們當(dāng)前貨幣對(duì)的價(jià)格最小點(diǎn)值是多少,舉個(gè)例子:歐元對(duì)美元的價(jià)格總是X.XXXX這種形式,它的Point值就是0.0001,當(dāng)我們想設(shè)定當(dāng)價(jià)格大于30點(diǎn)這種情況時(shí),我們只要用30乘以Point就可以計(jì)算這個(gè)貨幣對(duì)的實(shí)際30點(diǎn)值。不過(guò)Point常量在很多平臺(tái)中不能正確的來(lái)實(shí)現(xiàn)它本身的功能了,原因是很多平臺(tái)已經(jīng)改為小數(shù)點(diǎn)后5位,這樣Point值變成了0.00001,我們直接用他來(lái)乘以點(diǎn)位得到是卻是實(shí)際點(diǎn)位的十分之一,這樣會(huì)在EA的運(yùn)行中出現(xiàn)致命的邏輯錯(cuò)誤。因此如果是5位的平臺(tái),需要在那些點(diǎn)位的值上乘以10來(lái)修正這個(gè)問(wèn)題。關(guān)于Point的完美解決方法我們將在后續(xù)的文章中繼續(xù)討論。

以上就是MT4例子EA的解讀,這個(gè)程序雖然比較復(fù)雜但是它卻是一個(gè)很好的例子,里面涉及到了我們?cè)趯?xiě)EA程序過(guò)程中常用到的一些功能,對(duì)于初學(xué)EA程序的人來(lái)說(shuō)幫助很大,我們也可以修改這個(gè)程序的開(kāi)倉(cāng)、平倉(cāng)部分直接變成我們自己的邏輯。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多