MQL4初學-含教學 - 投資

Yedda avatar
By Yedda
at 2017-07-06T22:23

Table of Contents

HIHI大家好,我又再度出現了,很久沒發文前陣子都待在中國,

最近很多人發文有關MT4 EA的文章,看到了一些也想提供一些撰寫方式,

我自己本身不是IT出身,CODING在學MQL4之前幾乎沒學過,所以算是從0學起吧。

但過程我就不多加贅述了,我這篇文章將提供一般的策略如何撰寫,

讓你不用有求於人,也能輕鬆寫出自己的EA,至於大神們就可以直接跳過了,

若有錯誤還請多指教。

在本文開始前額外插個小話題:
10/1開始MATE QUOTE將停止更新MT4,並上調MT4對外匯商售價以及維護費,
並且相對調低MT5價格,試圖逼所有外匯商改用MT5,目前今年使用MT5券商,
已經增加百家,如果照這樣下去,MT5的使用將會越來越大,如果有懂IT的大人,
可以改用MQL5試試看了,我還在學覺得很困難。
另外MT5為人詬病的"不可對鎖"這件事情在新版本已經改善,將由外匯商自行決定
是否給投資人對鎖模式。

-------------------------本文開始-----------------------------
在MQL4編輯介面新開一個EA,甚麼都不選擇的情況下按下一步,
將會出現一個空白的EA編寫介面包含以下三個區塊:
Oninit(首次啟動EA執行內部程序"只執行一次")
OnDeinit(關閉EA時執行內部程序)
Ontick(價格"每次"跳動都會執行裡面的程序一次)

在這邊我會先給大家一個概念,建議將所有的程序都寫在這三個區塊以外,
有人可能會覺得神經病那這樣怎麼執行,且聽老納娓娓道來。
"所有的程序寫成"子函數"並在ONTICK中調用"
"所有的程序寫成"子函數"並在ONTICK中調用"
"所有的程序寫成"子函數"並在ONTICK中調用"
很重要說三次

解釋:有需要用到她的時候再把他叫出來,沒需要用到叫他滾邊睡。

曾經下載過網路上其他程式的人,不知道有沒有這樣的經驗,
兩支EA有的時候回測速度就是有一支比別支慢很多,明明同樣時間和歷史,
先忽略掉程序本身真的很複雜的部份,大約有70%的情況都是因為,
設計師把所有的程序全部放在ONTICK裡面,不管是不是立即要用到的,
這會導致電腦程序的執行非常緩慢,假設你的程序有500行,
也就是說價格每跳動一次你就要執行一次500行的程序,非常佔資源與時間,
所以謹記這點。

回到EA部分,一支EA裡面最關鍵的幾個要素是:
下單
平倉


我這次就以這兩個來做示範,基本上你想要直接複製走也可以,很多IT到最後都是這樣,
下單:
下單最重要的就是"條件",連接到剛剛的調用的概念,我會先做一個子函數出來,
void CheckForOpen()
{
if(這邊很多人會直接開始寫下單條件)//但我不會這麼做
//我會在外面再增加一個子函數
//bool buy_rule()
//bool sell_rule()


}

為什麼會這樣做呢?,當我在設定一個buyrule sell rule 當之後我的下單條件
有所更改,我不用一行一行去找,我只需要去更改這兩個子函數內的條件就可以了。

額外說:如果您要問bool是甚麼void是甚麼,可以去估狗 myeatrade的網站,
上面有完整的教科文。

輪到平倉部分,當然也是用同樣方式,在外面製作一個子函數來調用
void CheckForclose()
{
一樣在開始下單之前設定一個
bool buy_crule() //bool後面的字不一定要跟我一樣,我這只是方便我自己看
//你可以改成你自己想要的名子,中文也可以。
bool sell_crule() //同樣的
}
這邊得解釋一下平倉這件事情,在下單中因為你場上沒有任何單子,
再加上你的下單策略可能是不需要看場上單子的,
所以你不需要用到"選單子"這件事情,
但在平倉你必須先選擇到你要平的部位才能進行砍單。
所以你必須有這一段選單過程:
for(int i= OrdersTotal()-1; i>=0; i--)
{
if(!OrderSelect(i, SELECT_BY_POS))
{
if(OrderMagicNumber() == magic)(魔術碼)
提醒一下(IF裡面都是兩個==)
{
if(OrderSymbol()==symbol) (商品確認)
{
if(OrderType() == OP_SELL ) (確認方向)
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,White)
最後在ORDERCLOSE平倉,如果是BUY單就是Bid
如果是sell單就是Ask,這邊要小心常錯。
}
}
}
}
}

可能有人注意到我的for迴圈中是使用i--而非mql4範例中的i++
主要是因為電腦程序的第一個數位都是從0開始,如果你今天是多張單子策略,
他平倉完第一張(在程序編號上是0),前面的單字會往前補,也就是原本編號1的單子
會變成編號0,但這時候for迴圈會開始執行編號1的單子,這樣一直循環下去,
導致你的倉位會有些部位沒平倉到,為了解決這個問題,
最好的方式就是我從最後一張來,一路遞減,這樣甚麼煩惱都沒有。

回到Ontick上我們要調用這兩個勢必也有些條件,這個條件其實就不用像剛剛那個
再額外設置一個子函數了,直接寫在Ontick裡即可。
void OnTick()
{
if(CalculateCurrentOrders()==0) //計算場上部位數量的子函數等下附上
CheckForOpen();
if(CalculateCurrentOrders()>=1)
CheckForClose();
//---
}
/*如果if條件式下沒有{大括號},則程式只會執行條件式下一句,
所以如果有多行要執行,請加{}並左右對稱。

本來我還想提到追蹤止損部分,但是因為感冒打得有點累了所以下次再提吧,
最後送給大家一個簡易版的程式碼,可以直接複製過去的,並附上註解。


int MAGICMA = 378354385;
extern int 停利 =2900;
extern int 停損 =50;
extern int 追蹤止損距離 = 500;
extern int 均線數值 = 288;
extern double Lots = 0.1;
int bars = 1;
//+--------------------------買單條件--------------------------------+
bool buy_rule()
{
double ma=iMA(NULL,0,均線數值,0,MODE_SMA,PRICE_CLOSE,0);
if(Open[0]>ma)
return (true);
else
return(false);
}
//+--------------------------賣單條件--------------------------------+
bool sell_rule()
{
double ma=iMA(NULL,0,均線數值,0,MODE_SMA,PRICE_CLOSE,0);
if(Open[0]<ma)
return (true);
else
return(false);
}

bool buy_crule()
{
double ma=iMA(NULL,0,均線數值,0,MODE_SMA,PRICE_CLOSE,0);
if(Open[0]<ma)
return (true);
else
return(false);
}
//+--------------------------賣單條件--------------------------------+
bool sell_crule()
{
double ma=iMA(NULL,0,均線數值,0,MODE_SMA,PRICE_CLOSE,0);
if(Open[0]>ma)
return (true);
else
return(false);
}
//+--------------------------平倉子涵數--------------------------------+

void CheckForClose()
{
double ma=iMA(NULL,0,均線數值,0,MODE_SMA,PRICE_CLOSE,0);
for(int i=0;i<OrdersTotal();i++)
{
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
if(OrderMagicNumber()==MAGICMA || OrderSymbol()==Symbol())
if(OrderType()==OP_BUY && buy_crule()==True)
{
OrderClose(OrderTicket(),OrderLots(),Bid,3,White) ;
}
if(OrderType()==OP_SELL && sell_crule() == True)
{
OrderClose(OrderTicket(),OrderLots(),Ask,3,White);
}

}
}
//+--------------------------開新部位--------------------------------+
void CheckForOpen()
{
double ticket;
if(buy_rule()==true && bars!=Bars)
{
ticket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,Bid-停損*Point,Ask+停
利*Point,"",MAGICMA,0,Blue);
bars=Bars;
}

if(sell_rule()==true && bars!=Bars)
{
ticket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,Ask+停損*Point,Bid-停
利*Point,"",MAGICMA,0,Red);
bars=Bars;
}
}
int OnInit()
{
bars=Bars;
return(INIT_SUCCEEDED);
}
//+--------------------------計算部位數量--------------------------------+
int CalculateCurrentOrders()
{
int orders = 0;
for(int i=0;i<OrdersTotal();i++)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
continue;
if(OrderSymbol()!=Symbol() || OrderMagicNumber()!=MAGICMA)
continue;
orders++;
}
return(orders);
}
//關閉EA時所執行之程序
void OnDeinit(const int reason)
{
}
//+--------------------------移動停損--------------------------------+
void modify()
{
double Ma =iMA(NULL,0,均線數值,0,MODE_SMA,PRICE_CLOSE,0);
for(int i=0;i<OrdersTotal();i++)
{
if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
continue;
if(OrderType()==OP_BUY)
{
if(OrderMagicNumber() == MAGICMA )
{
if(追蹤止損距離>0 )
{
if(Bid-OrderOpenPrice()>Point*追蹤止損距離)
{
OrderModify(OrderTicket(),OrderOpenPrice(),Bid-追蹤止
損距離*Point,OrderTakeProfit(),0,Green);
}
}
}
}
if(OrderType()==OP_SELL)
{
if(追蹤止損距離>0 )
{
if((OrderOpenPrice()-Ask)>(Point*追蹤止損距離))
{
OrderModify(OrderTicket(),OrderOpenPrice(),Ask+追蹤止
損距離*Point,OrderTakeProfit(),0,Red);
return;

}
}
}
}
}
//+--------------------------價格跳動執行一次
--------------------------------+
void OnTick()
{
if(CalculateCurrentOrders()<1)
CheckForOpen();
if(CalculateCurrentOrders()>=1)
modify();
CheckForClose() ;
}


/*關於程序中的Bars這邊做個說明,Bars在mql4中定義為當前這根k棒,
/*而我自己在設定一個自定義變數bars,在開倉時用到,
/*當bars != Bars 代表著當前這根k棒跟之前紀錄的那一根不同了,
/*在ordersend之後 bars=Bars 代表著我這根k棒下過單了,避免重複開單,
/*每更新一根k棒才會下單。


這只是一個很簡易的模組版本ea,如果有比較深入的想了解,
可以把問題來信,我看我有沒有辦法解決,如果無法就說抱歉了,
下次文章:馬丁寫法。

--

All Comments

Ida avatar
By Ida
at 2017-07-07T09:31
子涵數的涵 寫錯 應該是函
Aaliyah avatar
By Aaliyah
at 2017-07-11T07:37
認真推
Rebecca avatar
By Rebecca
at 2017-07-14T06:59
推..
Elizabeth avatar
By Elizabeth
at 2017-07-16T17:53
感謝撰文分享
Carolina Franco avatar
By Carolina Franco
at 2017-07-17T17:26
推認真
Audriana avatar
By Audriana
at 2017-07-19T03:22
Jack avatar
By Jack
at 2017-07-20T16:31
推!
Jacky avatar
By Jacky
at 2017-07-23T11:08
Madame avatar
By Madame
at 2017-07-24T15:07
Agatha avatar
By Agatha
at 2017-07-25T04:13
推一下,謝分享
Susan avatar
By Susan
at 2017-07-30T02:30
推,對新手很有幫助,感謝
Kama avatar
By Kama
at 2017-07-30T16:40
函數、函式即可,不需要【子】
Zenobia avatar
By Zenobia
at 2017-07-31T11:40
推 超專業
Steve avatar
By Steve
at 2017-08-03T06:39
推推
Hamiltion avatar
By Hamiltion
at 2017-08-04T02:00
感謝分享

2017/07/06(四)盤勢數據

Xanthe avatar
By Xanthe
at 2017-07-06T08:02
============================== 02:00 USD 美聯儲FOMC公佈6月政策會議紀要 04:30 USD 美國至6月30日當週API原油庫存 15:15 CHF 瑞士6月CPI月率 19:30 USD 美國6月挑戰者企業裁員人數 19:30 EUR 歐洲央行公佈貨幣政 ...

( 月配 ) 封閉型全球總回報基金 - CGO

Zanna avatar
By Zanna
at 2017-07-05T14:18
圖文網誌版 http://ufshanno.pixnet.net/blog/post/65458300 ------------------------------------------------ ( 文章僅為商品經驗,並無任何投資建議 ) 我是一個金流投資者 對於金流的設定,希望能夠像薪 ...

定期定額海外證券操作方法?

Ethan avatar
By Ethan
at 2017-07-05T12:48
各位先進好 小妹最近開始研究指數型的基金投資 想要詢問各位的經驗和建議 我目前的狀況是手上有一筆定存想要轉ETF 未來希望能夠將每月或每季的存款定期投入 所以有兩種,一種是目前已經存到的比較大筆的錢和未來每月存下來的小筆金額 想請問各位建議怎麼操作比較好 如果我一次把金額轉入海外證券 是一大筆直接馬上投入 ...

2017/07/05(三)盤勢數據

Mia avatar
By Mia
at 2017-07-05T08:40
============================ 09:45 CNY 中國6月財新服務業PMI貌似真數據 15:00 EUR 歐洲央行非貨幣政策會議 15:50 EUR 法國6月服務業PMI終值 15:55 EUR 德國6月服務業PMI終值 16:00 EUR 歐元區6月服務業PMI終值 ...

外匯保證金IB操作問題

Emma avatar
By Emma
at 2017-07-04T10:33
昨天第一次使用IB下單就遇到問題(idealpro) 我買賣UJ 在IB裡面是以日幣做盈虧的追蹤 想請問有沒有人知道是否可以在系統中轉換成用美金計價顯示 另外就是平倉以後IB是否可以像其他平台將盈虧直接換算成我的基礎貨幣美金,而不是另 開個新的日幣的帳戶 不好意思 新手問題還請鞭小力一點 - ...