【MT4】MQL4でEAを作るベースとなるソースコードの公開

※本ページはプロモーションが含まれています

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)

スリッページは低くしすぎるとエラーになる

スリッページは低くしすぎると、取引所側からエラーが返ってきます。これについては、こちらの記事にまとめました。

あわせて読みたい
【MQL4】OrderCloseでエラーコード138が返ってくる原因と解決方法 いやー、MQL4は仕様どおりに作っても、取引所が絡んだエラーが多いです。 OrderCloseの関数でも同じでした。エラーコード138が必ず返ってくる。 色々調べて試して、よう...

利益値幅、損切り値幅も低くしすぎるとエラーになる

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

あわせて読みたい
MQL4でOrderSendエラーコード130 invalid stopsの解決策 バックテストでは正常に稼働するけど、リアル口座ではOrderSend時に、エラーコード130(Invalid Stops)が出てしまう。かなりあれこれ調べまくって、なんとかある程度は解...

売買はオリジナル関数を用意

売買時に簡潔に書きたかったので、売買時は直接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後のエラー処理について

エラーが取引所から返ってきた際のリトライ処理は以下のブログの処理を参考にさせて頂きました。それを改造した感じ。

あわせて読みたい
OrderModify | MT4でEA自作しちゃお~ 当サイトはMetaQuotes Software社のMT4(メタトレーダー4)で、EA(自動売買)やカスタムインジケータを作成したいけど・・・ まず何をやったらいいのか分からずスタート地点で...

オーダーのクローズ

オーダーのクローズもオリジナル関数を用意しました。基本はOrg_LongやOrg_Short関数で利益や損切りタイミングまで待ちますが、クローズタイミングを自分でしっかり決める場合は以下を使ってます。

引数はマジックナンバー。

//ロングのエントリーをクローズ
ClosePositions_BUY(MAGIC);

//ショートのエントリーをクローズ
ClosePositions_SELL(MAGIC);

 

売買の基本ルーチンは以上です。

まとめ

あとは、OnTick()で、エントリータイミングをどう書くかですね。この中で、ボリンジャーバンドみたり、各種テクニカルの数値を見て、エントリータイミングを判断する感じです。

矢野テック
矢野テック

まだまだ研究中

 

ブログランキングに参加してます。この記事が少しでもお役に立ちましたら、応援ポチっとお願いします。

にほんブログ村 為替ブログ システムトレード 自作EA派へ
にほんブログ村

お友達にMT4インジケータープレゼント中

機械学習使った日々の予測結果や、細かい試行錯誤の結果はLINEで公開しています。パスワード付き記事もこちらから。

また、今ならお友達には矢野テック自作のMT4用のインジケーターをプレゼント中です。

友だち追加

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

プログラマー。FXのMT4を使った自動売買EA作成やBOT作成などが趣味。2016年から元本10万円をどこまで増やせるか挑戦中。一旦は10万⇒700万⇒2017暴落 20万。ガチホからFXトレードに変更。 現在1000万円。その過程やノウハウは無料メール講座にまとめました。1か月で学べます。→無料メール講座

ご質問はコメント欄からお願いします

コメント一覧 (4件)

コメントする

目次