MT4のEA作りの書籍はたくさん出ていたり、ネットで検索するとサンプルのソースコードはたくさん見つかるのですが、バックテストではなく、実トレードで実行するとどうも動かない事が多い。
そこで、僕自身が、MT4のEA作りであれこれ実践して、実際に動いた売買部分だけのベースソースコードを公開したいと思います。
売買のMQL4のベースソース
僕が実際にベースで使ってるソースです。これに、あれこれ条件加えたりしてます。
#property copyright "Copyright 2020,Yano"
#property link "https://www.fx-doremi.com/"
#property version "1.00"
#property strict
#include <stdlib.mqh>
#define MAGIC 20200609
extern double Lots = 0.02; //ロット
extern int Slippage = 30; //スリッページ
extern double Profitrate = 20; //Take Profit 値幅(pips)
extern double SLrate = 20; //Stop Loss 損切り(pips)
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//---
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
//売買の処理はここで書く
//ロングの際の書き方
//Org_Long(Lots,Slippage,SLrate,Profitrate,MAGIC);
//ショートの際の書き方
//Org_Long(Lots,Slippage,SLrate,Profitrate,MAGIC);
}
//+------------------------------------------------------------------+
//| ロング
//| OP_BUYのエントリー。リトライあり
//| 引数: my_lot = ロット
//| my_slipage = スリッページ
//| my_sl = 損切り
//| my_tp = 利益
//+------------------------------------------------------------------+
void Org_Long(double my_lot,int my_slipage , double my_sl, double my_tp, int my_magic){
//ticket no
int ticket_no=0;
int errorcode=0; // エラーコード
double losscut_normalize=0;
double profit_normalize=0;
double losscut_rate=0;
double profit_rate=0;
// ロスカット価格
losscut_rate = Ask - ( 10 * Point() * my_sl);
// 決済価格
profit_rate = Ask + ( 10 * Point() * my_tp);
//正規化
losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));
profit_normalize = NormalizeDouble(profit_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));
//ロングエントリー処理
ticket_no = OrderSend(Symbol(),OP_BUY,my_lot,Ask,my_slipage,losscut_normalize,profit_normalize,"Buy order",my_magic,0,clrBlue);
printf("OrderSend OP_BUY , price=%f , sl=%f , tp=%f",Ask,losscut_normalize,profit_normalize);
if(ticket_no < 0){
errorcode = GetLastError(); // エラーコード取得
printf("Send Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode));
//再設定
losscut_rate = Ask - ( 10 * Point() * my_sl);
profit_rate = Ask + ( 10 * Point() * my_tp);
losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));
profit_normalize = NormalizeDouble(profit_normalize,int(MarketInfo(Symbol(),MODE_DIGITS)));
//オーダー送信と同時に損切り、利益設定エラー対策
ticket_no = OrderSend(Symbol(),OP_BUY,my_lot,Ask,my_slipage,0,0,"Buy order",my_magic,0,clrBlue);
printf("Resend OrderSend OP_BUY , price=%f , sl=%f , tp=%f",Ask,losscut_normalize,profit_normalize);
//オーダー修正
LimitStop_Set(ticket_no,OP_BUY,clrBlue);
}else {
printf("Send Done. Ticket NO = %d",ticket_no);
}
}
//+------------------------------------------------------------------+
//| ショート
//| OP_SELLのエントリー。リトライあり
//| 引数: my_lot = ロット
//| my_slipage = スリッページ
//| my_sl = 損切り
//| my_tp = 利益
//+------------------------------------------------------------------+
void Org_Short(double my_lot,int my_slipage , double my_sl, double my_tp, int my_magic){
//ticket no
int ticket_no=0;
int errorcode=0; // エラーコード
double losscut_normalize=0;
double profit_normalize=0;
double losscut_rate=0;
double profit_rate=0;
// ロスカット価格
losscut_rate = Bid + ( 10 * Point() * my_sl);
// 決済価格
profit_rate = Bid - ( 10 * Point() * my_tp);
//正規化
losscut_normalize = NormalizeDouble(losscut_rate,Digits());
profit_normalize = NormalizeDouble(profit_rate,Digits());
//shortエントリー処理
ticket_no = OrderSend(Symbol(),OP_SELL,my_lot,Bid,my_slipage,losscut_normalize,profit_normalize,"Sell order",my_magic,0,clrRed);
printf("OrderSend OP_SELL , price=%f , sl=%f , tp=%f",Bid,losscut_normalize,profit_normalize);
//エラー?
if(ticket_no < 0){
errorcode = GetLastError(); // エラーコード取得
printf("Send Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode));
// 再設定
losscut_rate = Bid + ( 10 * Point() * my_sl);
profit_rate = Bid - ( 10 * Point() * my_tp);
losscut_normalize = NormalizeDouble(losscut_rate,int(MarketInfo(Symbol(),MODE_DIGITS)));
profit_normalize = NormalizeDouble(profit_normalize,int(MarketInfo(Symbol(),MODE_DIGITS)));
//オーダー送信と同時に損切り、利益設定エラー対策
ticket_no = OrderSend(Symbol(),OP_SELL,my_lot,Bid,my_slipage,0,0,"Sell order",my_magic,0,clrRed);
printf("Resend sOrderSend OP_SELL , price=%f , sl=%f , tp=%f",Bid,losscut_normalize,profit_normalize);
//オーダー修正
LimitStop_Set(ticket_no,OP_SELL,clrRed);
}else {
printf("Send Done. Ticket NO = %d",ticket_no);
}
}
//+------------------------------------------------------------------+
//| エントリー中のポジションのリミット・ストップを変更
//| 引数 int in_ticket_no = Ticket no
//| double my_sl = Stopp Loss
//| double my_tp = Take Profit
//+------------------------------------------------------------------+
//
void LimitStop_Set( int in_ticket_no, int buysell_type , color mycolor) {
int modify_resend_num; // 変更試行回数
bool modify_ret; // 変更判定
int errorcode;
bool selbool;
double limit_rate,stop_rate;
int my_ticket_no;
// オーダー中のチケット選択(チケットNo指定)
selbool = OrderSelect(in_ticket_no, SELECT_BY_TICKET);
if (buysell_type == OP_BUY){
limit_rate = OrderOpenPrice() + ( 10 * Point() * Profitrate);
stop_rate = OrderOpenPrice() - ( 10 * Point() * SLrate);
}else{
limit_rate = OrderOpenPrice() - ( 10 * Point() * Profitrate);
stop_rate = OrderOpenPrice() + ( 10 * Point() * SLrate);
}
limit_rate = NormalizeDouble(limit_rate , Digits() ); // リミット価格 を正規化
stop_rate = NormalizeDouble(stop_rate , Digits() ); // ストップロス価格を正規化
my_ticket_no = OrderTicket();
for( modify_resend_num = 0; modify_resend_num < 30; modify_resend_num++ ) {
modify_ret = OrderModify(
my_ticket_no, // チケットNo
OrderOpenPrice(), // 注文価格
stop_rate, // ストップロス価格
limit_rate, // リミット価格
OrderExpiration(), // 有効期限
mycolor // 色
);
printf("OrderModify ticket_no:%d , sl=%f , tp=%f",my_ticket_no , stop_rate,limit_rate);
if ( modify_ret == false ) { // 注文変更拒否
Sleep(300); // 300msec待ち
errorcode = GetLastError(); // エラーコード取得
printf( "[%d]Modify Error! error_code:%d ,detail:%s ",
modify_resend_num+1, errorcode , ErrorDescription(errorcode));
} else { // 決済注文約定
Print("Done. Ticket NO=",in_ticket_no);
break;
}
}
}
//+------------------------------------------------------------------+
//| ポジション決済 |
//+------------------------------------------------------------------+
void ClosePositions_BUY(int my_magic){
int i;
int my_ticket_no;
double my_lots;
double my_price = NormalizeDouble(Ask,int(MarketInfo(Symbol(),MODE_DIGITS)));
bool chk;
int errorcode;
for(i=0;i<OrdersTotal();i++){
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false){
break;
}
if(OrderMagicNumber() != my_magic || OrderSymbol() != Symbol()){
continue;
}
my_ticket_no = OrderTicket();
my_lots = OrderLots();
//買いポジションのチェック
if(OrderType() == OP_BUY){
chk = OrderClose(my_ticket_no,my_lots,my_price,Slippage,White);
printf("OrderClose ret=%d , ticket_no=%d , lots=%f , BUY price=%f",chk,my_ticket_no,my_lots,my_price);
if(chk == False){
errorcode = GetLastError(); // エラーコード取得
printf("OrderClose Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode));
}else{
printf("OrderClose Done!");
}
break;
}
// ループを抜ける
break;
}
}
void ClosePositions_SELL(int my_magic){
int i;
int my_ticket_no;
double my_lots;
double my_price = NormalizeDouble(Ask,int(MarketInfo(Symbol(),MODE_DIGITS)));
bool chk;
int errorcode;
for(i=0;i<OrdersTotal();i++){
if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES) == false){
break;
}
if(OrderMagicNumber() != my_magic || OrderSymbol() != Symbol()){
continue;
}
my_ticket_no = OrderTicket();
my_lots = OrderLots();
//売りポジションのチェック
if(OrderType() == OP_SELL){
chk = OrderClose(my_ticket_no,my_lots,my_price,Slippage,White);
printf("OrderClose ret=%d , ticket_no=%d , lots=%f , SELL price=%f",chk,my_ticket_no,my_lots,my_price);
if(chk == False){
errorcode = GetLastError(); // エラーコード取得
printf("OrderClose Error! error_code:%d , detail:%s ",errorcode , ErrorDescription(errorcode));
}else{
printf("OrderClose Done!");
}
break;
}
// ループを抜ける
break;
}
}
解説
ロット、スリッページ、利益、損切りをパラメータで設定にするため、extern宣言。
MT4はポイント計算なのですが、利益や損切りは分かりやすくpipsで設定出来るようにしました。(実際はOrg_Long、Org_Short関数内でポイントをpips換算してます)
extern double Lots = 0.02; //ロット extern int Slippage = 30; //スリッページ extern double Profitrate = 20; //Take Profit 利益(pips) extern double SLrate = 20; //Stop Loss 損切り(pips)
スリッページは低くしすぎるとエラーになる
スリッページは低くしすぎると、取引所側からエラーが返ってきます。これについては、こちらの記事にまとめました。

利益値幅、損切り値幅も低くしすぎるとエラーになる
利益や損切りについても同様です。以下の記事に書きましたが、XMだと4pips以上は設定しないとエラーになります(それでもエラーになる場合は+1〜+2くらいにすると動くと思います)。

売買はオリジナル関数を用意
売買時に簡潔に書きたかったので、売買時は直接OrderSendを書かずに、オリジナル関数内で処理しました。この中で、小数点の桁合わせや、エラー時のリトライなど、あれこれやってます。
ロング(買い)
使い方はめちゃ簡単にしました。引数に必要な情報を入れるだけ。
//引数1:Lots = ロット //引数2:Slippage = スリッページ //引数3:SLrate = 損切り(pips) //引数4:Profitrate = 利益(pips) //引数5:MAGIC = マジックナンバー Org_Long(Lots,Slippage,SLrate,Profitrate,MAGIC);
ショート(売り)
//引数1:Lots = ロット //引数2:Slippage = スリッページ //引数3:SLrate = 損切り(pips) //引数4:Profitrate = 利益(pips) //引数5:MAGIC = マジックナンバー Org_Short(Lots,Slippage,SLrate,Profitrate,MAGIC);
OrderSend後のエラー処理について
エラーが取引所から返ってきた際のリトライ処理は以下のブログの処理を参考にさせて頂きました。それを改造した感じ。
オーダーのクローズ
オーダーのクローズもオリジナル関数を用意しました。基本はOrg_LongやOrg_Short関数で利益や損切りタイミングまで待ちますが、クローズタイミングを自分でしっかり決める場合は以下を使ってます。
引数はマジックナンバー。
//ロングのエントリーをクローズ ClosePositions_BUY(MAGIC); //ショートのエントリーをクローズ ClosePositions_SELL(MAGIC);
売買の基本ルーチンは以上です。
まとめ
あとは、OnTick()で、エントリータイミングをどう書くかですね。この中で、ボリンジャーバンドみたり、各種テクニカルの数値を見て、エントリータイミングを判断する感じです。

まだまだ研究中








ご質問はコメント欄からお願いします
コメント一覧 (4件)
【MT4】MQL4でEAを作るベースとなるソースコードの公開はどんなEAですか。
コメントありがとうございます。このページに公開している売買のベースコードだけです。
46 Org_Long?
Yes.Org_Long is a wrapper function. Look at line 58