FX自動売買(EA)の作り方MQL4

【コピペ可】MQL4を使ったFX自動売買ツール(EA)の作り方

※アフィリエイト広告を利用しています

広告

基本的なナンピンマーチンEAの設計概要は以下のように非常にシンプルです。

  • Inputの設定
  • ループ処理
    • ポジションの確認
    • 新規エントリー注文
    • 追加エントリー(ナンピン)注文
    • ポジションクローズ注文

この記事の内容をコピペしていけば、最もシンプルなナンピンマーチンEAを作成することが可能です。

初心者向けになるべくコードの意味まで丁寧に解説するように心がけていますので、初心者の方も是非EA作成にチャレンジしてみてください。

また、最後にこの記事で紹介したコードをまとめた.mq4ファイルをダウンロード可能にしております。順番にコピペしていってもコンパイルが上手くいかない場合や、一つずつコピペしていくのが大変な方はご活用ください。

    広告

    EAのロジック概要

    ここで作成するEAのロジックは、複雑な条件は可能な限り省いて簡略化しています。

    初期lot 0.01lot
    エントリー 稼働時間内であればすぐに新規ポジションを取る
    ナンピン幅 最低価格変動0.01に対して、価格幅2.00
    マーチン倍率 マーチンゲール法(倍率1.5倍)
    利確目標 1ポジション当たり143円
    稼働時間 取引時間帯はフル稼働
    強制クローズ なし(翌日にポジションを持ち越す)

    Inputの設定

    主にEAのロジックを決定する部分です。またMT4で動かす時に外部からインプットして設定出来る部分でもあります。

    input double first_lot = 0.01;//初期ロット
    input double nanpin_range = 200;//ナンピン幅
    input double profit_target = 143;//利益目標
    input int magic_number = 10001; //マジックナンバー
    static int ticket_number;//チケットナンバー
    double slippage = 10;//スリッページ

    初期ロット(first_lot)

    1番目のポジションを取得する時のロット数の設定です。最小は0.01ですので、ひとまず0.01に設定しておきます。

    ナンピン幅(nanpin_range)

    1番目のポジションの後、どれくらい価格が動いたら次のポジションを取りに行くかという価格幅の設定です。200と設定すると、GOLDの場合、2.00の価格幅を意味します。(厳密には、この後に *Pointという形で単位を決めにいきます。)

    利益目標(profit_target)

    利益目標を金額で設定します。ここでは単位は円で、143円という設定です。1ポジションあたり143円の含み益が発生したら、クローズ注文を行うようなロジックです。

    マジックナンバー(magic_number)

    どんなEAにも存在する識別番号のようなものです。他のEAと同時に動かすようなことがなければ、どんな数値でも構いません。ロジックには関係ありません。ここでは適当に10001と設定しています。

    チケットナンバー(ticket_number)

    MT4の場合、各注文にチケットナンバー(注文番号のようなもの)が付きます。これを入れておく箱程度にお考えください。ロジックには関係ありません。

    スリッページ(slippage)

    MT4では、注文時にスリッページの許容範囲が設定可能です。ただし、業者によっては設定しても無効になるようです。XMTradingもその一つで、注文時にスリッページの許容範囲を設定しても無効になります。ただし、以下の公式の説明の通り、スリッページはほとんど発生しません。

    スリッページは発生しますか?
    当社で取引される場合、スリッページはほとんど発生しません。しかし、特に重要な経済ニュースの発表時などは、市場価格の急騰または急落により、お客様の注文はリクエストされたものと異なるレートで執行される場合があります。

    www.xmtrading.com

    ここでは適当に10と設定しておきます。

    ループ処理

    初期設定が終わり、ここからループ処理に入ります。

    void OnTick()

    void OnTick()
     {

    これはイベント関数と呼ばれるものの一つで、EAが新しいtickを受信した時に発生します。

    もう少しわかりやすく言い換えると、価格が変動する度に繰り返し行う処理ということです。

    従って、主要なロジックはほとんどこの中に記載していきます。

    これ以降はしばらく、void OnTick()の中に記載していく内容になります。

    変数の定義

    まずは、ループ処理内で使う変数の定義です。

    int cnt;
    int current_buy_position;//最新のbuyポジション
    int current_sell_position;//最新のsellポジション
    int buy_position;//buyポジション数
    int sell_position;//sellポジション数
    double buy_profit;//buyポジションの含み損益
    double sell_profit;//sellポジションの含み損益

    current_buy_position、current_sell_position

    current_buy_positionは、最新のbuyポジションを記録しておく変数です。例えば、buyポジションを3つ持っている状況であれば、3つ目のbuyポジションを意味します。current_sell_positionも同様です。

    buy_position、sell_position

    buy_positionは、buyポジションの数を意味します。buyポジション数をいくつ持っているかを判定する際に使用します。sell_positionも同様です。

    buy_profit、sell_profit

    buy_profitは、buyポジションの合計含み損益を意味します。buyポジション数を複数持っている場合は、複数ポジションの含み損益を通算した数値になります。クローズ注文を行うかどうか判定する際に使用します。sell_profitも同様です。

    ポジションの確認

    ここでは、ポジションを確認する処理を行います。

    具体的には、buyポジションとsellポジションをそれぞれいくつ持っているか、最新のポジションの番号(cnt)を取得しておき、次の注文の際に使用します。

    buy_position=0;//buyポジション数の初期化
    sell_position=0;//sellポジション数の初期化
    current_buy_position=-1;//最新buyポジションの初期化
    current_sell_position=-1;//最新sellポジションの初期化
    
    for(cnt=0;cnt<OrdersTotal();cnt++)//ポジションの確認
    {
      if(OrderSelect(cnt,SELECT_BY_POS)==false)continue;
      if(OrderMagicNumber()!=magic_number)continue;
      if(OrderType()==OP_BUY)
      {
        current_buy_position=cnt;
        buy_position+=1;
        buy_profit=buy_profit+OrderProfit();
      };//buyポジションの確認
    
      if(OrderType()==OP_SELL)
      {
        current_sell_position=cnt;
        sell_position+=1;
        sell_profit=sell_profit+OrderProfit();
      };//sellポジションの確認
    
    }

    簡単に中身を解説しておくと、全てのポジションを順番に確認していき、

    buyポジションだったら、

    • current_buy_positionにポジション番号(cnt)を記録しておく。
    • buy_positionを1つ増やす。
    • buy_profitにそのポジションのprofitを加える。

    sellポジションだったら、

    • current_sell_positionにポジション番号(cnt)を記録しておく。
    • sell_positionを1つ増やす。
    • sell_profitにそのポジションのprofitを加える。

        というような処理を行なっています。

        新規エントリー注文

        続いて、新規エントリー注文です。エントリー条件はシンプルに、「ポジションを持っていなかったら」という条件のみです。

        if(buy_position==0)//buyポジションを持っていない場合
        {
          ticket_number=OrderSend(
                                  Symbol(), //通貨ペア
                                  OP_BUY,  //buy:OP_BUY, sell:OP_SELL
                                  first_lot, //ロット数
                                  Ask, //注文価格
                                  slippage, //スリッページ
                                  0,  //決済逆指値
                                  0,  //決済指値
                                  "first_buy",  //注文コメント
                                  magic_number,  //マジックナンバー
                                  0,  //注文の有効期限
                                  Blue  //矢印の色
                                  );
        }
        if(sell_position==0)//sellポジションを持っていない場合
        {
          ticket_number=OrderSend(
                                  Symbol(), //通貨ペア
                                  OP_SELL,  //buy:OP_BUY, sell:OP_SELL
                                  first_lot, //ロット数
                                  Bid, //注文価格
                                  slippage, //スリッページ
                                  0,  //決済逆指値
                                  0,  //決済指値
                                  "first_sell",  //注文コメント
                                  magic_number,  //マジックナンバー
                                  0,  //注文の有効期限
                                  Red  //矢印の色
                                  );
        }

        ここは、OrderSend関数というのをそのまま使っているだけです。

        OP_BUY、OP_SELLというのはそれぞれ成行注文を表します。注文価格のAsk、Bidというのはその時の価格です。

        つまり、buyあるいはsellのそれぞれのポジションを持っていなかったら、その時の価格ですぐに成行注文を行う(成行注文でも価格を指定して注文を行います。)、そのロット数は最初の Inputで設定したfirst_lot(初期ロット)ということです。

        注文コメントは、MT4で注文を確認する際に表示されるものです。設定しなくても問題ありませんが、今回は”first_buy”や”first_sell”というように設定しておきます。

        矢印というのは、MT4のチャートで取引履歴が表示されますが、その矢印の色を指定するものです。ここでは、buyは青(Blue)、sellは赤(Red)としておきます。こちらも指定しなくても特に問題はありません。

        追加エントリー(ナンピン)注文

        そして、肝心のナンピン注文の設定です。

        とは言っても特に難しいことはしておらず、新規エントリー注文との違いは、

        • ナンピン幅の条件を満たした場合にのみ注文を行うこと
        • ロット数を前回のロット数の1.5倍にしていること

          の2つくらいです。

          if(buy_position>0) //buyポジションを1つ以上持っている場合
          {
           OrderSelect(current_buy_position,SELECT_BY_POS); //最新のbuyポジションを選択
           if(Ask<(OrderOpenPrice()-nanpin_range*Point)) //現在価格がナンピン幅に達しているか
           {
             ticket_number=OrderSend(
                                     Symbol(), //通貨ペア
                                     OP_BUY,  //buy:OP_BUY, sell:OP_SELL
                                     round(OrderLots()*1.5*100)/100, //ロット数
                                     Ask, //注文価格
                                     slippage, //スリッページ
                                     0,  //決済逆指値
                                     0,  //決済指値
                                     "nanpin_buy",  //注文コメント
                                     magic_number,  //マジックナンバー
                                     0,  //注文の有効期限
                                     Blue  //矢印の色
                                     );
            }
          
          if(sell_position>0) //sellポジションを1つ以上持っている場合
          {
            OrderSelect(current_sell_position,SELECT_BY_POS); //最新のsellポジションを選択
            if(Bid>(OrderOpenPrice()+nanpin_range*Point)) //現在価格がナンピン幅に達しているか
            { 
              ticket_number=OrderSend(
                                     Symbol(), //通貨ペア
                                     OP_SELL,  //buy:OP_BUY, sell:OP_SELL
                                     round(OrderLots()*1.5*100)/100, //ロット数
                                     Bid, //注文価格
                                     slippage, //スリッページ
                                     0,  //決済逆指値
                                     0,  //決済指値
                                     "nanpin_sell",  //注文コメント
                                     magic_number,  //マジックナンバー
                                     0,  //注文の有効期限
                                     Red  //矢印の色
                                     );  
          
            }

          最新のbuyポジションを選択

          OrderSelect(current_buy_position,SELECT_BY_POS); //最新のbuyポジションを選択

          OrderSelect関数というものを使用して、最新のポジションの情報を取得します。

          例えば、

          • ロット数:0.01、価格:1742.21のbuyポジション
          • ロット数:0.02、価格:1740.21のbuyポジション

            という2つのbuyポジションを持っていたとします。その場合、最新のポジションというのは後から取得した2つ目のポジションを表します。ここでは、current_buy_positionというポジションの確認の際に取得した番号(cnt)を使用しています。

            現在価格がナンピン幅に達しているか

            if(Ask<(OrderOpenPrice()-nanpin_range*Point)) //現在価格がナンピン幅に達しているか

            OrderOpenPrice関数を使用して、選択している最新ポジションの価格を取得します。先ほどの例で言うと、1740.21という価格を取得するわけです。

            nanpin_rangeは、Inputで設定したナンピン幅200です。Pointは、通貨ペア(取引対象)毎に定まる最小単位です。XMTradingのGOLDの場合は、0.01を意味します。

            つまりこのif文は、

            「現在価格(Ask)が、1740.21 – 200 × 0.01 = 1738.21を下回っていたら」

            という条件になります。

            ポジションクローズ注文

            最後に、ポジションクローズ注文です。

            以下のように、非常にシンプルですが、ここでは後で別途定めるbuyClose関数とsellClose関数というものを使用しています。

            if(buy_position>0&&buy_profit>profit_target*buy_position)
            {
              buyClose(Green);//すべてbuyポジションを決済
            }
            
            if(sell_position>0&&sell_profit>profit_target*sell_position)
            {
              sellClose(Yellow);//すべてsellポジションを決済
            }

            ポジションクローズ条件

            buyポジションのクローズ注文を行う条件は、以下の2つを同時に満たした場合です。

            • buyポジションを1つ以上持っている
            • buyポジションの含み益合計が、利益目標×buyポジション数を上回っている

              これを上記算式で表現しています。具体的には、例えばbuyポジション数が3だった場合、利益目標(profit_target)は143円と設定していたので、143円の3倍である429円を、buyポジションの含み益合計が上回った場合に、buyポジションのクローズ注文を行います。

              ポジションを決済する関数

              以下は、「void OnTick()」の外で別途定義しておきます。オリジナルの関数を定義しておいて、先ほどのポジションクローズ注文のところで呼び出します。

              buyClose関数

              持っているbuyポジションを全てクローズしていく関数です。

              マジックナンバーが同じもの、かつ、buyポジションだけを全てクローズします。

              //buyポジションを決済する関数
              void buyClose(color clr)
              {
                 int i;
                 for(i=OrdersTotal()-1;i>=0;i--)
                 {
                    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)
                       continue;
                    if(OrderSymbol()!=Symbol()||OrderMagicNumber()!=magic_number)
                       continue;
                    if(OrderType()==OP_BUY)
                       OrderClose(OrderTicket(),OrderLots(),Bid,NormalizeDouble(slippage,0),clr);
                 }
              }

              sellClose関数

              持っているsellポジションを全てクローズしていく関数です。

              マジックナンバーが同じもの、かつ、sellポジションだけを全てクローズします。

              //sellポジションを決済する関数
              void sellClose(color clr)
              {
                 int i;
                 for(i=OrdersTotal()-1;i>=0;i--)
                 {
                    if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false)
                       continue;
                    if(OrderSymbol()!=Symbol()||OrderMagicNumber()!=magic_number)
                       continue;
                    if(OrderType()==OP_SELL)
                       OrderClose(OrderTicket(),OrderLots(),Ask,NormalizeDouble(slippage,0),clr);
                 }
              }

              まとめ

              以上、これまで見てきたものを組み合わせるだけで、基本的なナンピンマーチンEAは完成です。

              いかがでしたでしょうか。思ったよりシンプルな構造ということがよくわかったかと思います。

              .mq4ファイルのダウンロード

              今回ご紹介したコードをまとめたものは以下からダウンロード可能です。

              基本的にはそのままコンパイルすれば使用可能かと思いますが、動作や収益の保証等は一切いたしかねますので、利用者ご自身のご判断でご使用ください。

              EAの動かし方、パラメーター設定等

              実際に動かす方法、パラメーター設定等は以下の記事を参考にしてください。

              取引時間制限、強制クローズ機能を追加

              ここで作成したEAをさらに機能拡張していく記事はこちらです。

              MQL5で作るナンピンマーチンEA

              MQL5でナンピンマーチンEAを作成する方法もご紹介しています。この記事で紹介したナンピンマーチンEAと全く同じロジックです。

              EAのバックテスト方法

              以下の記事では、作成したFX自動売買ツール(bot/EA)を、Google Colabを使ってPythonでバックテストを行う方法を紹介しています。botやEAの作成に正確なバックテストは不可欠ですので、是非こちらもご覧ください。

              Pythonで作るFX自動売買ツール(bot)

              PythonでFX自動売買ツール(bot)を作成する方法もご紹介しています。

              こちらも、この記事で紹介したナンピンマーチンEAと全く同じロジックで作成していますので、是非見比べてみてください。

              キャッシュバック口座の開設

              作成したEAを利用して実際に運用する際は、通常の口座開設ではなく、キャッシュバック口座を開設するのがおすすめです。以下の記事で、キャッシュバックサイト経由で海外FX口座を開設する際のメリットとデメリットをまとめていますのでご覧ください。

              各利用者にとってリアル口座をどのように開設するのが最適かを考える参考になると思います。

              ChatGPTと作るFX自動売買ツール(EA)

              プログラミングも出来るチャット型AI(ChatGPT)と協力して同様のEAを作成してみた記事はこちらです。

              タイトルとURLをコピーしました