MT4で一目均衡表EAを作成|無料MQL4サンプルコード解説

ICHIMOKU1
EAサンプル・ノウハウ
記事内に商品プロモーションを含む場合があります
スポンサーリンク

はじめに

「一目均衡表を使ったトレードをEA化して自動売買したい!」という方向けに、この記事では MT4(MQL4)で動作する無料サンプルコード を紹介します。
初心者でもコピペで動かせるので、学習用や検証用に最適です。

一目均衡表は「相場の一目観測」を目的に開発された日本発のインジケーターで、トレンドの方向性や強さだけでなく、サポート・レジスタンスも把握できる強力な指標です。
この記事では「三役好転/三役逆転」の判定をEA化して、自動でエントリー・決済する方法を解説します。


📈 一目均衡表とは?

一目均衡表は、以下の5本の線で構成されるテクニカル指標です。

  • 転換線(短期の方向性)
  • 基準線(中期の方向性)
  • 先行スパン1(雲の上限)
  • 先行スパン2(雲の下限)
  • 遅行スパン(価格との位置関係)

特に有名なシグナルが「三役好転/三役逆転」です。

  • 三役好転(買いサイン)
    転換線 > 基準線、価格が雲の上、遅行スパンがローソク足の上にある
  • 三役逆転(売りサイン)
    転換線 < 基準線、価格が雲の下、遅行スパンがローソク足の下にある

一目均衡表の詳細

一目均衡表の詳細

◎5本の線の内容
①転換線 =(過去9日間の最高値+最安値)÷2
②基準線 =(過去26日間の最高値+最安値)÷2
③先行スパン1 =(転換線+基準線)÷2を26日将来に描画
④先行スパン2 =(過去52日間の最高値+最安値)÷2を26日将来に描画
⑤遅行スパン = 終値を26日過去にずらして描画

◎三役好転(三役逆転)
A.転換線が基準線を上抜けたとき
B.遅行スパンがローソク足を上抜けたとき
C.ローソク足が雲を上抜けたとき
※A~Cが全て一致した場合は三役好転で買いサイン
(三役逆転はこの逆バージョン)


EAの概要とポイント

  • MT4標準の「Ichimoku」インジケーターを iCustom() で呼び出し
  • 三役好転で買いエントリー、三役逆転で売りエントリー
  • 条件が崩れたら決済
  • ロット数・TP/SLはパラメータでカスタマイズ可能

エントリーロジック解説

  • 買いエントリー(ロング)
    転換線 > 基準線 + 価格が雲上 + 遅行スパンがローソク足上 → BUY
  • 売りエントリー(ショート)
    転換線 < 基準線 + 価格が雲下 + 遅行スパンがローソク足下 → SELL

📊 三役好転/逆転の判定表

判定条件三役好転(買いシグナル)三役逆転(売りシグナル)
① 転換線 vs 基準線転換線 > 基準線転換線 < 基準線
② 価格 vs 雲(先行スパン1・2)価格が 雲の上限より上価格が 雲の下限より下
③ 遅行スパン vs ローソク足遅行スパンが ローソク足の上遅行スパンが ローソク足の下

※「価格が雲の上」=ローソク足が 先行スパン1と先行スパン2で形成される雲の上限よりも上にある状態

👉 この3条件がすべて揃ったときに「三役好転(買い)」「三役逆転(売り)」と判定します。
EAでも、この条件を基準にエントリー判定を行っています。


別のエントリー方法

一目均衡表EAでは「雲抜け」や「転換線と遅行線の上抜け」だけを条件にするアレンジ、その他インジケータの組み合わせについては以下の記事も参考にしてください。
参考記事:
MT4で一目均衡表EAを改良する方法|エントリー条件をカスタマイズ
一目均衡表と移動平均線を使ったEA


⚠️ 注意点

  • 今回のロジックはトレンド相場で有効ですので、レンジ相場ではダマシが多発します
  • サンプルEAは単純化のためマジックナンバー管理なし(単独稼働推奨)
  • 新しいローソク足が形成された際に1回だけ処理を実行する設計です
  • パラメータ設定でTP/SLがあり機能しますが、決済処理がある関係上今回のロジックではほぼ未使用です

ダウンロード

EAファイルのダウンロードはこちら👇

📥 一目均衡表EA をダウンロード

📜 一目均衡表EAのサンプルコード解説

以下にMQL4サンプルコードを掲載します。
そのままコピーしてMT4(MetaEditor)に貼り付ければコンパイル可能で、動作確認も済んでいます。

//+------------------------------------------------------------------+
//|                                                  03_Ichimoku.mq4 |
//|                                Copyright © 2020-2025 ぷろぐらむFX |
//|                                             https://fx-prog.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2020-2025 ぷろぐらむFX"
#property link      "https://fx-prog.com/"
#property version   "1.00"
#property strict


input double Lots = 0.01;              //ロット
input int TP = 1000;                    //利確(pips)
input int SL = 1000;                    //損切り(pips)
//***【パラメータ設定↓】一目均衡表***//
//一目均衡表は個別設定無し
//***【パラメータ設定↑】一目均衡表***//

string Ea_Name = "Ichimoku";           //オーダーコメントに使用

double PipValue;                       //ブローカー桁数に対応した Point 補正
datetime prevtime;                     //ローソク足時間保持用
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){

   //デジットチェック
   if (Digits == 3 || Digits == 5){
      PipValue = Point * 10;   // 例: EURUSD 1.23456 → 1pip = 0.00010
   }else{
      PipValue = Point;        // 例: USDJPY 123.45 → 1pip = 0.01
   }

   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){

}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){

   int total = OrdersTotal();    //ポジショントータル数をセット  
   int ea_order_Type = -1; //0:OP_BUY  1:OP_SELL
   double ea_order_stop_price = 0; //ストップロスレート
   double ea_order_good_price = 0; //利確レート

   //新しい足ができた時だけやる
   if(Time[0] != prevtime){
      prevtime = Time[0];
   }else{
      return;
   }

   //ポジションがない場合はエントリー判定
   if(total == 0){

      bool openBuy  = false;    //買い新規注文判断
      bool openSell = false;    //売り新規注文判断
      
//***【新規注文判断↓】***//
      bool isBullIchimoku_S = false;
      bool isBearIchimoku_S = false;
      
      // 一目均衡表の値取得
      double Tenkansen   = iCustom(NULL,0,"Ichimoku",9,26,52,0,1);
      double Kijunsen    = iCustom(NULL,0,"Ichimoku",9,26,52,1,1);
      double SenkouSpanA = iCustom(NULL,0,"Ichimoku",9,26,52,2,1);
      double SenkouSpanB = iCustom(NULL,0,"Ichimoku",9,26,52,3,1);
      double ChikouSpan  = iCustom(NULL,0,"Ichimoku",9,26,52,4,26); // ←26本前の値
      
      double close1 = iClose(NULL,0,1);
      
      // △三役好転△
      if(Tenkansen > Kijunsen
         && close1 > MathMax(SenkouSpanA, SenkouSpanB)
         && ChikouSpan > iClose(NULL,0,26)){
         isBullIchimoku_S = true;
      }
      
      // ▼三役逆転▼
      else if(Tenkansen < Kijunsen
         && close1 < MathMin(SenkouSpanA, SenkouSpanB)
         && ChikouSpan < iClose(NULL,0,26)){
         isBearIchimoku_S = true;
      }


//***【新規注文判断↑】***//

      //参照するサンプルEAの買いエントリーフラグをセットしてください
      if(isBullIchimoku_S){
         openBuy =true;
         ea_order_Type = OP_BUY;
      //参照するサンプルEAの売りエントリーフラグをセットしてください      
      }else if(isBearIchimoku_S){
         openSell =true;
         ea_order_Type = OP_SELL;
      }

//***【TP/SL判断↓】***//
      if(openBuy){
         ea_order_stop_price = Ask - SL * PipValue;
         ea_order_good_price = Ask + TP * PipValue;
      }else if(openSell){
         ea_order_stop_price = Bid + SL * PipValue;  
         ea_order_good_price = Bid - TP * PipValue;   
      }
//***【TP/SL判断↑】***//

      if(ea_order_Type > -1){
         funcOrder_Send(ea_order_Type,ea_order_stop_price,ea_order_good_price,Lots,Ea_Name,777,0);
      }
      
   //ポジションがある場合は決済判定   
   }else{
   
      bool closeBuy  = false;    //買いポジション決済判断
      bool closeSell = false;    //売りポジション決済判断
      bool kekka = OrderSelect(0,SELECT_BY_POS,MODE_TRADES);

//***【決済注文判断↓】***//
      bool isBullIchimoku_C = false;
      bool isBearIchimoku_C = false;

      //一目均衡表の値取得
      double Tenkansen   = iCustom(NULL,0,"Ichimoku",9,26,52,0,1);
      double Kijunsen    = iCustom(NULL,0,"Ichimoku",9,26,52,1,1);
      double SenkouSpanA = iCustom(NULL,0,"Ichimoku",9,26,52,2,1);
      double SenkouSpanB = iCustom(NULL,0,"Ichimoku",9,26,52,3,1);
      double ChikouSpan  = iCustom(NULL,0,"Ichimoku",9,26,52,4,26);

      
      // BUYポジション → 転換線が基準線を下抜け、または価格が雲を割ったら決済
      if(OrderType() == OP_BUY){
         if(Tenkansen < Kijunsen || iClose(NULL,0,1) < MathMax(SenkouSpanA, SenkouSpanB)){
            isBullIchimoku_C = true;
         }
      }
      
      // SELLポジション → 転換線が基準線を上抜け、または価格が雲を上抜けたら決済
      else if(OrderType() == OP_SELL){
         if(Tenkansen > Kijunsen || iClose(NULL,0,1) > MathMin(SenkouSpanA, SenkouSpanB)){
            isBearIchimoku_C = true;
         }
      }

//***【決済注文判断↑】***//
   
      //参照するサンプルEAの買いポジション決済フラグをセットしてください
      if(isBullIchimoku_C){
         closeBuy =true;
         ea_order_Type = OP_BUY;
      //参照するサンプルEAの売りポジション決済フラグをセットしてください
      }else if(isBearIchimoku_C){
         closeSell =true;
         ea_order_Type = OP_SELL;
      }
      
      if(ea_order_Type > -1){
         funcOrder_CloseAll(ea_order_Type, -1, 0);
      }
      
   }

   return;
}


//★★★★★★★★★★★★★★★★★★★★ ここから下は共通関数 ★★★★★★★★★★★★★★★★★★★★
//+------------------------------------------------------------------+
//|【関数】新規注文関数
//|
//|【引数】 orderType:売買(0=BUY, 1=SELL)
//|【引数】 sl:損切り価格  tp:利確価格
//|【引数】 lots:取引ロット数
//|【引数】 orderComment:オーダーコメント
//|【引数】 magic:マジックNo
//|【引数】 maxSpreadPips: 許容スプレッド[Point] (0=制限なし)
//|
//|【戻値】true=成功 false=失敗
//+------------------------------------------------------------------+
bool funcOrder_Send(int orderType, double sl, double tp, double lots,
                    string orderComment, int magic, int maxSpreadPoints){
   int    ticket = -1;
   double price  = 0;
   color  clr    = clrNONE;
   double spread = 0;

   // 最大10回リトライ
   for(int retry=0; retry<10; retry++)
   {
      RefreshRates();
      
      // スプレッド取得(MT4表示と同じポイント単位)
      spread = MarketInfo(Symbol(), MODE_SPREAD);

      // スプレッドチェック(maxSpreadPoints=0 の場合はスキップ)
      if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
         Print("スプレッド拡大中(", spread,
               "ポイント) → 待機中 (リトライ=", retry+1, ")");
         Sleep(2000);
         continue;
      }

      // エントリー価格と色を決定
      if(orderType == OP_BUY){
         price = Ask;
         clr   = clrBlue;
      }else if(orderType == OP_SELL){
         price = Bid;
         clr   = clrRed;
      }

      ticket = OrderSend(Symbol(), orderType, lots, price,
                         20, sl, tp, orderComment, magic, 0, clr);

      if(ticket > 0){
         Print("新規注文成功! チケットNo=", ticket,
               " レート=", price, " Lots=", lots,
               " スプレッド=", spread, "ポイント");
         return true;
      }else{
         int err = GetLastError();
         Print("新規注文失敗 エラーNo=", err,
               " リトライ回数=", retry+1);
         Sleep(2000);
      }
   }

   return false;
}


//+------------------------------------------------------------------+
//|【関数】全決済関数                                                 |
//|                                                                  |
//|【引数】 orderType : -1=すべて  0=BUYのみ  1=SELLのみ             |
//|【引数】 magic: 対象マジック番号 (-1=全マジック対象)               |
//|【引数】 maxSpreadPoints: 許容スプレッド[Point] (0=制限なし)       |
//|                                                                  |
//|【戻値】true=全成功 false=一部失敗あり                             |
//+------------------------------------------------------------------+
bool funcOrder_CloseAll(int orderType, int magic, int maxSpreadPoints){
   bool allSuccess = true;
   int totalOrders = OrdersTotal();
   double spread, closePrice, lots;
   int type, ticket;
   color  clr    = clrNONE;

   for(int i = totalOrders-1; i >= 0; i--)
   {
      //オーダーセレクト失敗でスキップ
      if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      
      // 同一シンボル以外はスキップ
      if(OrderSymbol() != Symbol()) continue;

      // マジック番号指定がある場合は一致しないものをスキップ
      if(magic != -1 && OrderMagicNumber() != magic) continue;

      type   = OrderType();
      ticket = OrderTicket();
      lots   = OrderLots();

      // orderType指定でフィルタ
      if(orderType == 0 && type != OP_BUY) continue;
      if(orderType == 1 && type != OP_SELL) continue;

      // 最大10回リトライ
      bool result = false;
      for(int retry=0; retry<10; retry++)
      {
         RefreshRates();

         // スプレッド取得
         spread = MarketInfo(Symbol(), MODE_SPREAD);

         if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
            Print("スプレッド拡大中(", spread,
                  "ポイント) → クローズ待機中 ticket=", ticket,
                  " リトライ=", retry+1);
            Sleep(2000);
            continue;
         }

         // クローズ価格決定
         if(type == OP_BUY){
            closePrice = Bid;
            clr   = clrBlue;
         }else if(type == OP_SELL){
            closePrice = Ask;
            clr   = clrRed;
         }

         result = OrderClose(ticket, lots, closePrice, 20, clr);

         if(result){
            Print("クローズ成功! チケットNo=", ticket,
                  " ロット=", lots, " クローズ価格=", closePrice,
                  " スプレッド=", spread, "ポイント");
            break;
         }else{
            int err = GetLastError();
            Print("クローズ失敗 ticket=", ticket,
                  " エラーNo=", err,
                  " リトライ=", retry+1);
            Sleep(2000);
         }
      }

      if(!result) allSuccess = false;
   }

   return allSuccess;
}

スポンサーリンク

iCustom() 関数の解説

一目均衡表の各ラインは MT4標準関数 iCustom() で取得します。

【例:転換線の取得】

double Tenkansen = iCustom(NULL,0,"Ichimoku",9,26,52,0,1);

引数の意味

  • 引数1:通貨ペア(NULLで現在のチャート)
  • 引数2:時間軸(0で現在の時間足)
  • 引数3〜5:転換線・基準線・先行スパンの期間設定(9, 26, 52)
  • 引数6:ライン番号(0=転換線, 1=基準線, 2=先行スパン1, 3=先行スパン2, 4=遅行スパン)
  • 引数7:シフト(1で直近の1本前、27で27本前など)

※iIchimoku() 関数でも同様の事ができますが、今回はあえてiCustomにチャレンジしています

遅行スパンの値は注意が必要

一目均衡表の値は簡単に取得できますが、例外として遅行スパンの値は現在の時間軸0~26個前のバーに値が入っていません。
27本前の値が最新となりますので、27本目の値を今回は見るようにしています。
以下のイメージを見ると確認できますが、遅行スパンが描かれていない部分の値は全て0となっています。
※iCustom(NULL,0,,”Ichimoku”,9,26,52,4,0~26)の値も履歴に出力
遅行スパンの値は注意が必要

一目均衡表の利用箇所

  • 66~91行目 … 新規注文処理で、三役好転/三役逆転をチェック
  • 127~151行目 … 決済処理で、三役好転/三役逆転の解消をチェック

一目均衡表を使った売買判定について

一目均衡表EAのトレードイメージ

本サンプルEAでは以下のようなロジックで売買を判定しています。

買いエントリー(ロング)の条件

  • 転換線が基準線を上回る
  • 現在価格が雲の上にある
  • 遅行スパンが、26本前のローソク足終値より上にある

👉 このEAでは「遅行スパンがローソク足より上」という本来の判定を簡易化し、26本前の終値を基準に比較する方法を採用しています。

売りエントリー(ショート)の条件

  • 転換線が基準線を下回る
  • 現在価格が雲の下にある
  • 遅行スパンが、26本前のローソク足終値より下にある

👉 こちらも同様に、26本前の終値を基準にした簡易判定を行っています。

買いポジション(ロング)の決済条件

  • 価格が雲の下限を下抜けたら決済
    👉 上昇トレンドが弱まり、相場がレンジや下落に転じる可能性があるためです。

売りポジション(ショート)の決済条件

  • 価格が雲の上限を上抜けたら決済
    👉 下落トレンドが崩れ、上昇に転じるサインとなるためです。
  • 利確損切設定
    • 決済処理で決済させたいため、どちらも1000pipsに初期設定しています
      ※パラメータ設定で自由に変更してください

新規注文・決済注文関数

本記事の一目均衡表 EAで使用している「新規注文、決済注文処理」は、当サイト共通のベースソースに含まれています。
EAを効率的に自作したい方は、以下の記事もあわせて参考にしてください。
👉 MT4 EAベースソースコード(無料配布・カスタマイズ容易)
👉 新規・変更・決済注文関数の詳しい解説はこちら


🔧 パラメータとカスタマイズ

今回のパラメータ設定は以下の通りです:

  • 取引ロット数(例:0.01 = 1,000通貨)
  • 利確幅(pips)
  • 損切幅(pips)
一目均衡表EAのパラメータ設定画像
スポンサーリンク

EAバックテストレポート

USDJPY(M15, 2024/08〜2025/08, 初期証拠金100万円, FXTFヒストリカル)での結果:

通貨ペア・時間足PF勝率最大DD取引回数備考
USDJPY M151.2331%0.52%349回勝率は低いが、損小利大のトレードができている
一目均衡表EAのバックテストレポート

まとめ

一目均衡表EAは、相場の総合的な状態を見ながら 「強いトレンドだけに乗る」 ロジックを実現できます。

  • 三役好転/逆転でシンプルに売買可能
  • 雲抜け・クロス判定などアレンジ次第で応用幅大
  • パラメータ変更でデイトレ・スイング両方に対応

まずはサンプルコードを動かしてバックテストし、条件やフィルタを追加して自分好みのEAに育てていきましょう。

🛠️ EAを効率的にカスタマイズしたい方へ
▶ 【MT4 EAベースソース】を無料公開中!初心者でもすぐに使えます。


✅ 他にも多数のEAサンプルを公開中!

今回紹介した内容以外にも、当サイトではさまざまな
FX自動売買EAのサンプルコードを提供しています。

自分に合った戦略のEAを見つけたい方は、ぜひチェックしてみてください。


📊 【2025年最新】FX自動売買EAランキングも公開中!

当サイトの「どのEA(インジ)が実際に勝っているのか?」を知りたい方はこちら👇
PF(プロフィットファクター)や勝率で徹底比較した最新ランキングから、あなたに最適なEA(インジ)を見つけましょう。


EA開発初心者向けに、今後も実践的なMQL4関数を紹介していきます。
気になる機能やロジックがあれば、ぜひ他の記事もあわせてご覧ください!

コメント

  1. 新さんのアイコン より:

    いつもお世話になっております。
    コンパイルしたところ、88行目にエラーが発生しているとの事でコンパイルできない状態です。

    エラーメッセージは、
    「’OrderKekka’ – undeclared identifier」
    となります。

    何が原因なのでしょうか?

    • りょう りょう より:

      #property strictを宣言していると発生する感じでした。
      OrderKekkaが宣言されていませんっていうエラーメッセージですが、別のif文内で宣言しているので、#property strictを宣言してないとコンパイル時にエラーになりませんでした。
      『bool OrderKekka』をif文の外で宣言してあげると問題は解消されます!

  2. 新さんのアイコン より:

    ありがとうございます。
    コンパイルできました!

  3. うま太郎さんのアイコン うま太郎 より:

    一目均衡表を使用して裁量トレードしています。
    私のトレードルールは簡単なので、EA を使おうと思って勉強しているのですが、実際にコード乗ってるの少ないので助かります。
    ちなみに、一目均衡表の先行スパンと指数移動平均のゴールデンクロスでトレードするEAを作ろうとしているのですが、難易度高いのでしょうか?

    • りょう りょう より:

      うま太郎さん

      一目均衡表の先行スパンと指数移動平均のゴールデンクロスでトレードするEAですが、iMA()関数で指数移動平均線の値を取得して比較するだけなので難易度は高くないですよ。

  4. ひろさんのアイコン ひろ より:

    質問失礼します
    一目均衡表のデータ取得の際
    遅行スパンのシフトを27にされてますが
    元々26本前にシフトされているのが現在値ではないでしょうか?
    26本前に表示されてるところから27本シフトさせると、現在値から53本前となりませんか?
    なので遅行スパンの呼び出す値はシフト1じゃないでしょうか?

    • りょう りょう より:

      ひろさん

      ご質問ありがとうございます。
      ソースコードの51行目の事でしょうか?
      確かにこの部分は少し複雑なのですが、遅行スパンの値自体がシフト27(厳密には26)からしか入っていません。一目均衡表をチャート表示したらわかりますが、最新チャートから26個前までは遅行スパンが描かれていないので値が取れないのは必然です。
      ※わかりずらいので記事(ソースコードの下)にイメージを追加しました

      追加したイメージでも分かりますが、27本前の値は151.930付近53本前の値は151.220付近なので27本前の値(遅行スパンの最新値付近)を取得出来ている事がわかります。

      もしご質問の趣旨と違う事を回答してしまっている場合は、お手数ですがお伝え頂ければ再度回答いたします。

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