ストキャスティクスは%Kと%Dという2本の線を見て判断する指標です。

ただ、サブウィンドウを常に見ていなければ、

2本の線が交差した瞬間を見逃してしまいます。

この記事では、iStochastic()関数の使い方と、

%Kと%Dの値そのものではなく、

交差した瞬間だけをメインチャートに矢印で知らせるインジケーターの作り方を解説します。

この記事で分かること
・iStochastic()関数の書式と引数の意味
・%Kと%Dのクロスを検知する設計
・買われすぎ・売られすぎ領域だけに絞るフィルター
・MQL5版との違い

なぜ「クロスの瞬間」だけを検知する設計にするのか

まず、この設計を選ぶ理由を整理します。

%Kと%Dの位置関係だけでは判断に迷う

%Kが%Dより上か下かは、

サブウィンドウを見ればいつでも分かります。

しかし「いつ交差したか」は、

目で追い続けないと気づきにくいタイミングです。

既刊OsMA・Momentumクロス矢印記事との接続

既刊記事では、OsMAのゼロクロスや、

Momentumの基準線100クロスを矢印表示する設計を扱いました。

同じ「変化の検知」をストキャスティクスに応用します。

この記事で扱う範囲

この記事では、%Kと%Dが交差した瞬間だけをメインチャートに矢印で表示する、

カスタムインジケーターの作り方を中心に扱います。

iStochastic()の基本的な使い方

関数の書式と、各引数の意味を確認します。

関数の書式

double iStochastic(
   string           symbol,        // シンボル名
   int              timeframe,     // 時間枠
   int              Kperiod,       // %Kの計算期間
   int              Dperiod,       // %Dの計算期間(%Kの移動平均期間)
   int              slowing,       // スローイング(平滑化)期間
   int              method,        // 移動平均の種類(MODE_SMA等)
   int              price_field,   // 価格の比較方法(0または1)
   int              mode,          // 取得するライン(MODE_MAIN=0、MODE_SIGNAL=1)
   int              shift          // シフト(0が最新バー)
   );

modeにMODE_MAIN(0)を指定すると%Kの値、

MODE_SIGNAL(1)を指定すると%Dの値が返ります。

price_field(価格の比較方法)の選び方

price_fieldの意味
・0を指定 → 直近の終値を期間内の最高値・最安値と比較する方式
・1を指定 → 直近の終値を期間内の終値どうしで比較する方式
・MT4標準のストキャスティクスは0(最高値・最安値比較)が一般的

公式リファレンスには、

この2つの値に対応する定数名の記載が無かったため、

本記事では数値の0・1をそのまま使います。

methodとslowingの役割

methodは平均化の方式(単純移動平均等)、

slowingは%Kをさらに平滑化する期間です。

大きくするほど線が滑らかになり、クロスの頻度が減ります。

%Kと%Dのクロスを検知するロジック

「状態」ではなく「変化」を検知する考え方を実装に落とし込みます。

「状態」でなく「変化」を検知する考え方

既刊のMomentum・OsMA記事と同じく、

1本前の値と今回の値を比較し、

大小関係が入れ替わった瞬間だけを検知します。

1本前・今回の値を比較する実装

%Kから%Dを引いた差分を計算し、

前回と今回で符号が変わった瞬間をクロスと判定します。

同じ足でシグナルを連発させない工夫

符号が変わった最初の1本だけ矢印を描き、

変わらない間は描かないようにします。

実際に動くコード全体(ストキャスクロス矢印インジケーター)

%Kと%Dが交差した瞬間だけを矢印で表示するインジケーターです。

indicator_buffersとバッファの設計

上抜け用・下抜け用の2つのバッファを用意し、

メインチャート上に矢印を描画する設計にします。

コード全文

//+------------------------------------------------------------------+
//|                                  StochasticCrossArrowIndicator.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

input int  Kperiod       = 5;
input int  Dperiod       = 3;
input int  Slowing       = 3;
input int  PriceField    = 0;      // 0=Low/High基準、1=Close/Close基準
input bool FilterByZone  = false;  // trueなら買われすぎ・売られすぎ領域内のみ検知
input double OversoldLevel   = 20.0;
input double OverboughtLevel = 80.0;

double UpArrowBuffer[];
double DownArrowBuffer[];

int OnInit()
  {
   SetIndexBuffer(0, UpArrowBuffer);
   SetIndexStyle(0, DRAW_ARROW, STYLE_SOLID, 2, clrDodgerBlue);
   SetIndexArrow(0, 233);

   SetIndexBuffer(1, DownArrowBuffer);
   SetIndexStyle(1, DRAW_ARROW, STYLE_SOLID, 2, clrOrangeRed);
   SetIndexArrow(1, 234);

   return(INIT_SUCCEEDED);
  }

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 start = (prev_calculated > 0) ? prev_calculated - 1 : 1;

   for(int i = start; i < rates_total; i++)
     {
      int shift = rates_total - 1 - i;

      double kNow  = iStochastic(NULL, 0, Kperiod, Dperiod, Slowing, MODE_SMA, PriceField, MODE_MAIN, shift);
      double dNow  = iStochastic(NULL, 0, Kperiod, Dperiod, Slowing, MODE_SMA, PriceField, MODE_SIGNAL, shift);
      double kPrev = iStochastic(NULL, 0, Kperiod, Dperiod, Slowing, MODE_SMA, PriceField, MODE_MAIN, shift + 1);
      double dPrev = iStochastic(NULL, 0, Kperiod, Dperiod, Slowing, MODE_SMA, PriceField, MODE_SIGNAL, shift + 1);

      UpArrowBuffer[i]   = EMPTY_VALUE;
      DownArrowBuffer[i] = EMPTY_VALUE;

      bool crossUp   = (kPrev <= dPrev && kNow > dNow);
      bool crossDown = (kPrev >= dPrev && kNow < dNow);

      if(FilterByZone)
        {
         if(crossUp && kNow > OversoldLevel)
            crossUp = false;
         if(crossDown && kNow < OverboughtLevel)
            crossDown = false;
        }

      if(crossUp)
        {
         UpArrowBuffer[i] = low[i] - 10 * _Point;
        }
      else if(crossDown)
        {
         DownArrowBuffer[i] = high[i] + 10 * _Point;
        }
     }

   return(rates_total);
  }

MetaEditorでのコンパイル・適用手順

MetaEditorでファイルを保存してコンパイルし、

エラーが0件であることを確認したうえで、

チャートにドラッグ&ドロップして適用します。

精度を上げる応用(買われすぎ・売られすぎ領域だけに絞る)

チャタリングを減らす応用の工夫を紹介します。

領域内クロスだけ検知するフィルターの考え方

20以下での上抜け、80以上での下抜けだけに絞ると誤検知を減らせます。

FilterByZoneパラメータの使い方

コード全文のFilterByZoneをtrueにすると、

領域外のクロスを矢印表示から除外します。

フィルターを強めるとシグナル数が減るトレードオフ

注意
・フィルターを有効にするとシグナル数が大きく減る
・トレンドが強い相場では領域内クロスがほとんど出ないことがある
・用途(逆張り狙いか順張り狙いか)に応じてON/OFFを選ぶ

よくある注意点

実装時につまずきやすい点をまとめます。

price_fieldを変えると結果が変わる

price_fieldを0から1に変えると、

同じ期間設定でも%K・%Dの値が変わります。

バックテストと実運用で設定をそろえてください。

Slowingを大きくするとシグナルが遅れる

Slowingを大きくするほど線が滑らかになりますが、

クロスの検知自体も遅れて発生するようになります。

単独で使わず環境認識と組み合わせる

強いトレンド中はクロスが連続発生し、誤検知が増えやすい点に注意してください。

よくある質問

ストキャスティクスのクロス表示について、よくある疑問に回答します。

%Kと%Dどちらが先に動く線ですか?

%Kが先に動き、%Dは%Kを平滑化した線のため、

%Kが%Dを追いかける形で交差が発生します。

サブウィンドウで数値も見たいです

本記事のコードは矢印だけを表示する設計です。

数値も見たい場合は、

標準のStochasticを別途サブウィンドウに追加してください。

MQL5版も同じ考え方で作れますか?

MQL5のiStochastic()はハンドルを返す方式に変わります。

CopyBufferでMAIN_LINE・SIGNAL_LINEを取得する設計です。

本記事ではMQL4版のみを扱い、MQL5版は今後の候補とします。

【MQL4】ストキャスティクスの%Kと%Dがクロスした瞬間だけ矢印表示するインジケーターの作り方について解説してみた:まとめ

ストキャスティクスは%Kと%Dの位置関係で判断する指標ですが、

サブウィンドウを見続けなければ交差のタイミングを見逃してしまいます。

交差した瞬間だけを矢印で表示することで、

一目でタイミングを把握できるようになります。

買われすぎ・売られすぎ領域に絞るフィルターと組み合わせれば、

さらに誤検知を減らせます。

単独でのエントリー判断は誤検知が増えやすいため、

環境認識や他の指標と組み合わせて使うことをおすすめします。

関連記事