MQL4初學-含教學 - 投資
By Yedda
at 2017-07-06T22:23
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,如果有比較深入的想了解,
可以把問題來信,我看我有沒有辦法解決,如果無法就說抱歉了,
下次文章:馬丁寫法。
--
最近很多人發文有關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
By Ida
at 2017-07-07T09:31
at 2017-07-07T09:31
By Aaliyah
at 2017-07-11T07:37
at 2017-07-11T07:37
By Rebecca
at 2017-07-14T06:59
at 2017-07-14T06:59
By Elizabeth
at 2017-07-16T17:53
at 2017-07-16T17:53
By Carolina Franco
at 2017-07-17T17:26
at 2017-07-17T17:26
By Audriana
at 2017-07-19T03:22
at 2017-07-19T03:22
By Jack
at 2017-07-20T16:31
at 2017-07-20T16:31
By Jacky
at 2017-07-23T11:08
at 2017-07-23T11:08
By Madame
at 2017-07-24T15:07
at 2017-07-24T15:07
By Agatha
at 2017-07-25T04:13
at 2017-07-25T04:13
By Susan
at 2017-07-30T02:30
at 2017-07-30T02:30
By Kama
at 2017-07-30T16:40
at 2017-07-30T16:40
By Zenobia
at 2017-07-31T11:40
at 2017-07-31T11:40
By Steve
at 2017-08-03T06:39
at 2017-08-03T06:39
By Hamiltion
at 2017-08-04T02:00
at 2017-08-04T02:00
Related Posts
2017/07/06(四)盤勢數據
By Xanthe
at 2017-07-06T08:02
at 2017-07-06T08:02
( 月配 ) 封閉型全球總回報基金 - CGO
By Zanna
at 2017-07-05T14:18
at 2017-07-05T14:18
定期定額海外證券操作方法?
By Ethan
at 2017-07-05T12:48
at 2017-07-05T12:48
2017/07/05(三)盤勢數據
By Mia
at 2017-07-05T08:40
at 2017-07-05T08:40
外匯保證金IB操作問題
By Emma
at 2017-07-04T10:33
at 2017-07-04T10:33