一目均衡表の「雲(先行スパンA・先行スパンBに挟まれた帯)」

を抜けたらエントリーする、という手法は昔からよく使われますが、

CCIの±100超えのような「固定の数値ラインを超えたか」という単純な判定は使えません。

雲の上限・下限は先行スパンA・Bの計算結果によって毎回動き、

しかもどちらが上でどちらが下かも相場状況によって入れ替わります。

「雲を上抜けた」を正しく判定するには、毎回その足ごとの雲の位置を計算し直し、

かつ「元々雲の中や下にいた」状態から「今は雲の上にいる」への変化を確認する必要があります。

この記事では、価格が雲を上抜け・下抜けした確定足だけに矢印を表示するインジケーターを、

雲の上限・下限が毎回動くことを前提にした設計の考え方とあわせて解説します。

設計思想: 「固定ラインのクロス」と「動く帯のブレイク」は別問題

以前の記事(CCIの±100超え矢印インジケーター)では、閾値そのものが常に100・-100で固定だったため、

「今の値が閾値を超えていて、1本前は超えていなかった」という単純な比較でクロスを検知できました。

雲抜けの判定はこれより一段複雑です。

  • 雲の上限・下限は、先行スパンA・Bの値によって足ごとに変わる(固定値ではない)
  • 先行スパンAと先行スパンBの上下関係は、相場状況によって入れ替わる(雲が「ねじれる」)ため、単純に「先行スパンAを上限」と決め打ちできない
  • そのため、各足ごとに`MathMax()`・`MathMin()`で「その足の雲の上限・下限」を都度計算し直してから、価格との比較を行う必要がある

この「毎回の閾値そのものを計算し直す」という一手間が、CCIのような固定閾値のクロス判定と最も違う設計ポイントです。

iIchimoku関数で雲の上限・下限を取得する

double iIchimoku(
   string symbol,        //通貨ペア(NULLで現在のチャート)
   int    timeframe,     //時間足(0で現在のチャートの時間足)
   int    tenkan_sen,    //転換線の期間(標準9)
   int    kijun_sen,     //基準線の期間(標準26)
   int    senkou_span_b, //先行スパンBの期間(標準52)
   int    mode,          //取得する線の種類
   int    shift          //何本前の足を見るか
   );

雲を構成する2本の線は、mode引数に`MODE_SENKOUSPANA`(先行スパンA)・`MODE_SENKOUSPANB`(先行スパンB)を指定して取得します。

既存記事(iIchimoku関数の使い方)で解説した通り、先行スパンの未来方向へのシフトは関数の内部で計算済みの値が返るため、

shift引数に自分で26を足す必要はありません。

double spanA = iIchimoku(NULL, 0, TenkanSen, KijunSen, SenkouSpanB, MODE_SENKOUSPANA, i);
double spanB = iIchimoku(NULL, 0, TenkanSen, KijunSen, SenkouSpanB, MODE_SENKOUSPANB, i);

double cloudTop    = MathMax(spanA, spanB);//その足の雲の上限
double cloudBottom = MathMin(spanA, spanB);//その足の雲の下限

「ブレイクの瞬間」だけを検知する条件式

「今の終値が雲の上にある」だけを条件にすると、雲を抜けたあと何本もその状態が続く間ずっと矢印が出てしまいます。

CCI記事と同じく、1本前の足との比較を加えて「変化した瞬間」だけに絞り込みます。

ただし今回は閾値自体も1本前とは違う値になっている点に注意が必要です。

//上抜け: 1本前の終値は「1本前の雲の上限」以下だったが、今の終値は「今の雲の上限」を超えた
close[i] > cloudTop_i && close[i+1] <= cloudTop_prev

//下抜け: 1本前の終値は「1本前の雲の下限」以上だったが、今の終値は「今の雲の下限」を割った
close[i] < cloudBottom_i && close[i+1] >= cloudBottom_prev

比較対象の閾値(`cloudTop_i`と`cloudTop_prev`)がそれぞれの足ごとに別々の値になっている点が、

CCIの「常に100」という固定値クロス判定との違いです。

矢印インジケーターのコード全体

確定足で雲を上抜け・下抜けした瞬間だけに矢印を表示する、実際にMetaEditorでコンパイルできるインジケーターです。

//+------------------------------------------------------------------+
//|                              IchimokuCloudBreakout.mq4            |
//|                     Copyright 2026, FX-EA System Project Creator |
//|                        https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link      "https://creator.fx-ea-system-project.com/"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 2
#property indicator_color1 DodgerBlue
#property indicator_color2 OrangeRed

input int TenkanSen   = 9;//転換線の期間
input int KijunSen    = 26;//基準線の期間
input int SenkouSpanB = 52;//先行スパンBの期間
input int ArrowGap    = 20;//高値・安値から矢印を離すpoint数

double UpArrow[];
double DownArrow[];
datetime lastAlertBarTime = 0;//直前にAlertを出した確定足の時刻(同じ足で連発しないためのガード)

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   SetIndexBuffer(0,UpArrow);
   SetIndexStyle(0,DRAW_ARROW,STYLE_SOLID,1);
   SetIndexArrow(0,233);
   SetIndexEmptyValue(0,EMPTY_VALUE);

   SetIndexBuffer(1,DownArrow);
   SetIndexStyle(1,DRAW_ARROW,STYLE_SOLID,1);
   SetIndexArrow(1,234);
   SetIndexEmptyValue(1,EMPTY_VALUE);

   IndicatorShortName("Ichimoku Cloud Breakout");
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                 const int prev_calculated,
                 const datetime &time[],
                 const double &open[],
                 const double &high[],
                 const double &low[],
                 const double &close[],
                 const long &tick_volume[],
                 const long &volume[],
                 const int &spread[])
  {
   int neededBars = SenkouSpanB + KijunSen + 3;
   if(rates_total < neededBars)
      return(0);

   ArraySetAsSeries(close,true);

   int limit=(prev_calculated==0) ? rates_total-2 : rates_total-prev_calculated+1;
   if(limit > rates_total-2)
      limit = rates_total-2;

   for(int i=limit;i>=1;i--)
     {
      UpArrow[i]=EMPTY_VALUE;
      DownArrow[i]=EMPTY_VALUE;

      double spanA_cur  = iIchimoku(NULL,0,TenkanSen,KijunSen,SenkouSpanB,MODE_SENKOUSPANA,i);
      double spanB_cur  = iIchimoku(NULL,0,TenkanSen,KijunSen,SenkouSpanB,MODE_SENKOUSPANB,i);
      double spanA_prev = iIchimoku(NULL,0,TenkanSen,KijunSen,SenkouSpanB,MODE_SENKOUSPANA,i+1);
      double spanB_prev = iIchimoku(NULL,0,TenkanSen,KijunSen,SenkouSpanB,MODE_SENKOUSPANB,i+1);

      double cloudTop_cur    = MathMax(spanA_cur, spanB_cur);
      double cloudBottom_cur = MathMin(spanA_cur, spanB_cur);
      double cloudTop_prev   = MathMax(spanA_prev, spanB_prev);
      double cloudBottom_prev= MathMin(spanA_prev, spanB_prev);

      //上抜け: 1本前は雲の上限以下、今は雲の上限を超えた
      if(close[i] > cloudTop_cur && close[i+1] <= cloudTop_prev)
         UpArrow[i]=low[i]-ArrowGap*Point;
      //下抜け: 1本前は雲の下限以上、今は雲の下限を割った
      else if(close[i] < cloudBottom_cur && close[i+1] >= cloudBottom_prev)
         DownArrow[i]=high[i]+ArrowGap*Point;
     }

   //形成中の足には表示しない
   UpArrow[0]=EMPTY_VALUE;
   DownArrow[0]=EMPTY_VALUE;

   //直近の確定足(shift=1)でブレイクが起きていればAlertで通知する(同じ足で連発しない)
   datetime barTime1 = iTime(NULL,0,1);
   if(barTime1 != lastAlertBarTime)
     {
      if(UpArrow[1] != EMPTY_VALUE)
        {
         Alert(Symbol()," ",Period(),"分足: 一目均衡表の雲を上抜けました (",TimeToString(barTime1,TIME_DATE|TIME_MINUTES),")");
         lastAlertBarTime = barTime1;
        }
      else if(DownArrow[1] != EMPTY_VALUE)
        {
         Alert(Symbol()," ",Period(),"分足: 一目均衡表の雲を下抜けました (",TimeToString(barTime1,TIME_DATE|TIME_MINUTES),")");
         lastAlertBarTime = barTime1;
        }
     }

   return(rates_total);
  }
//+------------------------------------------------------------------+
Copy

任意: Alertで通知も出す

矢印だけだとチャートを開いている間しか気づけないため、上のコードでは直近の確定足(shift=1)でブレイクが起きた場合に`Alert()`も呼んでいます。

ループの中ではなく`OnCalculate()`の最後で1回だけ、

かつ`lastAlertBarTime`というグローバル変数で「最後に通知した確定足の時刻」

を記録し、同じ足に対して何度もアラートが出ないようにガードしている点がポイントです。

この判定を入れないと、同じ足を再計算するたびに(新しいティックが来るたびに)Alertが繰り返し表示されてしまいます。

MetaEditorでの実行手順

  1. MT4のMetaEditorで「ファイル」→「新規作成」→「カスタムインディケータ」を選ぶ
  2. 「IchimokuCloudBreakout」という名前で作成し、テンプレートの中身をすべて削除してコード全体を貼り付ける
  3. F7キーでコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
  4. チャートへ適用し、MT4標準の一目均衡表インジケーターも同時に表示する
  5. 雲を実際に上抜け・下抜けしている確定足の位置と、矢印の表示位置が一致するか目視で確認する

この矢印を売買サインと断定しない

雲抜けは「三役好転」のような複合条件の一部として使われることが多く、

雲抜け単体で反転や継続のどちらかを保証するものではありません。

雲が薄い(先行スパンA・Bの差が小さい)局面では、抜けたと思ってもすぐに雲の中へ戻る「だまし」

も起こりやすくなります。

このインジケーターの役割は「雲抜けという状態変化を見落とさないこと」

であり、EA化する場合は、雲の厚み・上位足の方向・損切り・ポジション重複防止といった条件を別途追加してください。

矢印が出ない・多すぎるとき

  • 出ない: `neededBars`(先行スパンBの期間+基準線の期間+3本)より過去のヒストリーデータが読み込まれているか。表示直後は雲の計算に必要な本数が揃っておらず、しばらく待つか履歴データをダウンロードし直す必要がある
  • 矢印がMT4標準の一目均衡表の雲と噛み合わない: このインジケーターのTenkanSen・KijunSen・SenkouSpanBの値が、チャートに表示している標準一目均衡表のパラメーターと一致しているか確認する
  • 多すぎる: 雲が薄い(先行スパンA・Bがほぼ同水準)相場では、小さな値動きでも上抜け・下抜けを繰り返しやすい。必要に応じて、雲の厚み(`MathAbs(spanA-spanB)`)が一定以上のときだけ矢印を出すフィルターを追加する
  • 最新足に出ない: 意図的に確定足のみを判定している(0番目は形成中の足のため対象外)

まとめ

一目均衡表の雲抜けを検知するには、CCIの±100のような固定閾値のクロス判定と違い、

雲の上限・下限そのものが足ごとに変わることを前提にした設計が必要です。

先行スパンA・Bを`MathMax()`・`MathMin()`でその都度比較して雲の上限・下限を求め、

1本前の足の雲との比較で「状態」ではなく「変化した瞬間」だけを矢印で表示することで、

雲の中に居座っている間の矢印連発を防げます。

関連記事