English
preview
初心者からエキスパートへ:サポートとレジスタンスの強度指標(SRSI)

初心者からエキスパートへ:サポートとレジスタンスの強度指標(SRSI)

MetaTrader 5 | 27 6月 2025, 07:49
26 6
Clemence Benjamin
Clemence Benjamin

内容


はじめに

市場は、過去の価格レベルを一貫して意識しながら動いています。多くのトレーダーは、MetaTrader 5のラインツールを使って、こうした重要な価格帯をチャートに手動で描くことから一日を始めます。しかし、この手作業では、顕著なレベルを見逃したり、その重要性を誤って判断したりする可能性があり、自動化されたソリューションの必要性が浮き彫りになります。

なぜ自動化が必要なのかと疑問に思う方もいるかもしれません。人間は、創造的で複雑なタスクや新しい状況への対応には優れていますが、一貫性を保ったり、大量のデータを処理したりするのは苦手です。2024年7月7日に発表されたMark Angelo D. Julian、Danilo B. Villarino、Kristine T. Soberanoによる論文「The Human Brain Versus Computer: Which is Smarter?」はこの点を明らかにしています。この研究では、人間が文脈を理解する能力に優れている一方で、処理速度、データの正確性、反復的な計算においてはコンピューターのほうが圧倒的に優れていることが示されています。この対比こそが、取引やデータ分析におけるアルゴリズム開発を継続する原動力となっています。


議論の概要

本日は、MQL5プログラミングを用いた問題解決手法を活用し、先述の課題に取り組んでいきます。この内容は初心者から上級者まで、すべてのレベルのトレーダーを対象としており、すべてのトレーダーにとって重要な概念を扱います。ご存じのとおり、MetaTrader 5は、本質的には価格データや分析ツール、過去情報が集約された巨大なリポジトリです。たとえば、ローソク足の系列は、始値・高値・安値・終値(OHLC)を表すバーで構成されており、移動平均線のような一般的なインジケーターもこれらの値から算出されます。仮に5,000本のローソク足を手動で確認することを想像してみてください。非常に手間がかかる上、ミスも起きやすい作業です。だからこそ、サポートとレジスタンスレベルの自動検出には大きな価値があります。

現在、市場には無料・有料を問わず、さまざまなツールがすでに存在していますが、今回はその中でも独自のアプローチに焦点を当てていきます。このセッションでは、完成品を紹介するだけではなく、MQL5で独自のソリューションを構築するために必要なプログラミング技術も共有していきます。以下は、今回開発する「サポートおよびレジスタンス強度インジケーター(SRSI)」の主な利点です。

  • 効率的なデータ処理:膨大な過去のローソク足データを分析し、重要な価格レベルを特定
  • 継続的な自動化:手動によるミスを減らし、常時自動で稼働
  • レベルの差別化:弱い・強いサポートおよびレジスタンスレベルを識別
  • 明確な視覚表示:重要な価格レベルをチャート上にわかりやすく表示
  • 多様な通知機能:ターミナル通知やプッシュ通知などの機能に対応

次のセクションでは、まずMetaTrader 5のチャートを使って、過去の価格データと手動で特定したサポート・レジスタンスレベルを収集します。この初期分析によって、現在の市場動向と過去のパターンとの関連性を明らかにします。続いて、カスタムインジケーターの開発プロセスに入り、コードを共有しながら、各行の内容を丁寧に解説していきます。これにより、MQL5を実践的に理解し、自分のアイデアをどのようにコードへと落とし込むかを学ぶことができます。

最後に、テスト工程とその結果を確認し、実用的なソリューションとプログラミングスキルの両方を習得していただける内容となっています。ぜひ、じっくり取り組んで、コーディングの旅を楽しんでください。


今日の市場の性質を示す証拠

私のMetaTrader 5プラットフォームは、Deriv.comのブローカーに接続されており、さまざまな取引ペアにアクセスできます。口座の種類によって、ボラティリティペア、為替ペア、株式ペアなど、幅広い銘柄を取引することが可能です。以下の画像には、取引可能な追加ペアの豊富な一覧が表示されています。今回の調査では、この中からいくつかのペアを選んで分析をおこないました。

ご自身のブローカーが提供しているペアを確認し、[気配値表示]リストに追加するには、キーボードでCTRL + Uを押すか、下の画像にある赤い丸いアイコンをクリックして[銘柄]ウィンドウを開いてください。追加したいペアをダブルクリックするだけで、自動的にリストに表示されます。

銘柄

DerivSVGMetaTrader 5銘柄

合成ペア

最初に分析を始めたのは、「ボラティリティ指数」に分類される合成ペアの一つ、Volatility 75 (1s) Indexです。週足で確認したところ、このペアは2020年ごろに導入され、当初は高値圏にありましたが、まもなく長期にわたる下落トレンドに入りました。この数週間続いた強い下降局面では、ショートポジションを取っていたトレーダーたちは大きな利益を得ていたことでしょう。しかし、私の主な関心は市場構造にあり、特に過去3年間の動向に注目しています。

このような持続的な下落トレンドにより、多くのトレーダーは「このまま下がり続ける」というトレンドフォロー型の思考に慣れてしまった可能性があります。しかし、以下の画像でも分かるように、市場の力学は変化しています。上位時間枠では、現在は値動きが荒く不規則なレンジ(保ち合い)相場が形成されており、同様の特徴は下位時間枠にも見られます。このような状況では、スイングトレードが非常に難しくなります。

こうした相場では、サポートとレジスタンスに基づくプライスアクションが、重要な取引機会を見極めるうえで不可欠です。以下の画像は、このような市場の振る舞いを視覚的に示しており、テクニカル分析における体系的なアプローチの重要性を再確認させてくれます。

Volatility 75(1s) index

Volatility 75 (1s) Index

株式ペア

米国テクノロジー株の週足チャートを分析しましたが、市場は上昇トレンドを描いており、その途中で周期的な調整が見られます。これらの調整局面では価格の動きが鈍化し、その後トレンドが再開されるまでの保ち合い段階が形成されることが多いです。上昇トレンドの市場では、調整局面が強力なサポートゾーンを築き、強気の勢いを後押しします。

このような上位時間枠では、下位時間枠の値動きに影響を与える正確なパターンを特定するのは難しい場合があります。しかし、さらに詳細に見ていくと、サポートとレジスタンスの概念は複数の時間枠にわたって有効であり、さまざまな市場パターンをより深く観察できることがわかります。

     米国テック100(週次)

米国テック100(週次)

外国為替ペア

EUR/USDの週足チャートを見ると、小さなインパルスの後に、長期間にわたる変動局面が続いていることが分かります。この動きは上位時間枠に限らず、下位時間枠にも見られます。ここでの重要なポイントは、相場がトレンドを形成するよりも、レンジで推移する時間が長いということです。以下の画像は、この一定のレンジ内での長期的な相場の動きを示す証拠となっています。

EURUSD(週次)

EURUSD(週次)

以上の検証から明らかなように、市場価格は上昇や下降のトレンドを形成しつつも、過去の価格水準に強く依存してテストや検証をおこなっています。特に保ち合い局面では、選択した時間枠に基づく水平な価格レベルが、価格が反応しやすい重要なエリアとなります。

しかしながら、すべての価格レベルが大きな値動きを引き起こすほど強力とは限りません。また、よく知られたサポートやレジスタンスレベルであっても、必ずしも価格が反応するとは限らないものの、強さが証明されている場合には、市場の動きに影響を与える可能性が高くなります。

次のセクションでは、アルゴリズム開発に入る前に、サポートとレジスタンスの基本的な考え方を簡単に振り返ります。


SRSI開発におけるMQL5の実装 

サポートとレジスタンスの定義

サポートとは、一般的に複数の価格レベルが集まる需要のゾーンを指し、買い手が介入して価格を押し上げる傾向があるエリアのことです。このエリアは市場の「底」となり、買い注文の蓄積がさらなる下落を防ぐ役割を果たします。

  • 実務的には、サポートは単一の価格点ではなく、過去の安値や複数の接点によって買い手の信頼が形成されたゾーンであることが多いです。

一方、レジスタンスは供給のゾーンであり、複数の価格レベルが集まる場所を示します。ここでは売り手が介入して価格を押し下げる傾向が強く、市場の「天井」として機能します。売り圧力が買い圧力を上回るため、価格の上昇が抑えられることが多いのです。サポートと同様に、レジスタンスも複数の高値や接点が売りの勢いを強めるため、正確な一点ではなくゾーンとして捉えられます。

この理解を踏まえると、サポートとレジスタンスを扱うことがぐっと簡単になります。以下の動画では、私が普段どのようにこれらのラインを引いているかを解説していますので、ぜひご覧ください。


アルゴリズム設計と実装

プログラムには、私が手動でサポートおよびレジスタンスのゾーンを特定しマーキングする方法を再現してもらう必要があります。動画を確認したうえで、主要なステップを以下にまとめました。

  1. 極値ポイントの特定:価格が方向転換する重要な高値(レジスタンス)または安値(サポート)を見つけます。
  2. 追加の検証ポイントの探索:極値ポイントと同じ価格、もしくはその近く(5 pips以内)にある価格レベルを探し、その重要性を裏付けます。
  3. 反発ゾーンの形成:極値ポイントと検証ポイントを含む矩形ゾーンを作成し、その周囲に適切な範囲を設けます。
  4. ゾーン寸法のカスタマイズ

  • 高さ:ゾーンの縦幅を(pips単位で)調整可能にします。
  • 幅:ゾーンの横幅(ローソク足の本数、右方向への範囲)を調整可能にします。

基本的に、プログラムはカスタマイズ可能な本数のローソク足をスキャンし、設定した条件を満たすポイントを特定して、適切な図形やライン、ラベルを描画します。また、プログラムの機能を制御するための入力オプションも用意します。アラート機能については、プッシュ通知とターミナル通知を実装し、カスタマイズ可能な4時間間隔で定期的に配信します。サポートおよびレジスタンスレベルは常時監視が必要な指標ではないため、この方法で過剰な通知を避けつつ、適切なタイミングで知らせることが可能です。以下に、コードの断片とともに詳細をステップごとに説明していきます。

MetaEditorを開いて新しいカスタムインジケーターを作成すると、基本的なテンプレートが提供されます。このテンプレートは、開発者が作業を開始するための白紙のキャンバスのようなものであり、ここにSRSIインジケーターを構築していきます。これは以下のようになります。

//+------------------------------------------------------------------+
//|                                                        _SRSI.mq5 |
//|                                   Copyright 2025, Metaquotes Ltd |
//|                                            https://www.mql5.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, Metaquotes Ltd"
#property link      "https://www.mql5.com/"
#property version   "1.00"
#property indicator_chart_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   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[])
  {
//---
   
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

これを基礎的なガイドとして活用し、すべての主要な機能が正しく実装されていることを確認します。今後の手順では、テンプレートを完成させ、新機能を統合し、それらの機能について詳しく解説していきます。理解を深めるために、ぜひ最後まで一緒に進めてください。

手順1:インジケーターのプロパティをカスタマイズする

まずは、MetaTrader 5の要件に沿った形でインジケーターのプロパティをカスタマイズし、個別の設定をおこないます。著作権情報やリンク先を自分の情報に更新し、開発中のミスを検出しやすくするための厳密なエラーチェック設定を追加します。インジケーターはメインチャートウィンドウに表示されるように設定します。また、MetaTrader 5では少なくとも1つのバッファを定義する必要があるため、描画にバッファデータではなくカスタムオブジェクト(ラインや矩形)を使用する本インジケーターでは、非表示のダミーバッファを1つ定義します。

#property copyright "Clemence Benjamin"
#property link      "https://www.mql5.com/ja/users/billionaire2024/seller"
#property version   "1.00"
#property strict          // Enforces stricter error checking
#property indicator_chart_window
#property indicator_buffers 1  // MT5 requires at least one buffer
#property indicator_plots 1    // Ties to the buffer (even if unused for plotting)

手順2:ユーザー入力の追加

次に、ユーザーが自由に設定を変更できる入力項目を追加し、インジケーターの柔軟性を高めます。具体的には、過去何本のバーを分析対象とするか、レベルの検証範囲(例:デフォルトは7 pips)、強いレベルと判断するために必要な最小テスト回数、そして強いレベルの周囲に表示する矩形ゾーンの表示・非表示を切り替えるオプションを設けます。これらの入力によって、コードを変更することなくユーザーがインジケーターの動作を調整できるようになります。

input int InpLookBack = 1000;        // Number of bars to analyze
input double InpTestProximity = 0.0007; // Price range for tests (e.g., 7 pips)
input int InpMinTests = 3;           // Minimum tests for strong levels
input bool InpShowRectangles = true; // Show zones as rectangles

手順3:ダミーバッファの作成

MetaTrader 5では、インジケーターはたとえ表示しなくても、少なくとも1つのバッファを持つ必要があります。そこで、グローバル配列を作成し、これをダミーバッファとして使用します。初期化時にこの配列をバッファスロットに割り当て、チャート上には表示されないよう設定します。これによりMetaTrader 5の要件を満たしつつ、カスタムのサポートおよびレジスタンスレベルの描画に集中できます。

double DummyBuffer[];

使用方法

int OnInit()
{
   SetIndexBuffer(0, DummyBuffer, INDICATOR_DATA);   // Bind buffer to index 0
   PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_NONE); // Hide it from the chart
   return(INIT_SUCCEEDED);
}

手順4:データ構造の定義

データを整理して管理しやすくするために、列挙型と構造体を使用します。まず、レベルの種類(例:強いサポート、弱いレジスタンス)を分類する列挙型を定義し、わかりやすくします。価格レベルを表す構造体では、各レベルの価格、テスト回数、種類、識別された時間を格納します。さらに、強いレベルの周囲に形成されるゾーンを表すstructを用意し、その上下の価格帯や時間範囲を保持します。また、強いレベル、弱いレベル、ゾーンをそれぞれ格納するグローバル配列を設定し、最後にアラート送信時刻を管理する変数も用意します。

enum ENUM_LEVEL_TYPE {
   LEVEL_STRONG_SUPPORT,      // Strong support level
   LEVEL_STRONG_RESISTANCE,   // Strong resistance level
   LEVEL_WEAK_SUPPORT,        // Weak support level
   LEVEL_WEAK_RESISTANCE      // Weak resistance level
};

struct PriceLevel {
   double price;           // Price value of the level
   int test_count;         // Number of times price tested it
   ENUM_LEVEL_TYPE type;   // Strong or weak, support or resistance
   datetime time;          // Time the level was identified
};

struct Zone {
   double top;             // Top price of the zone
   double bottom;          // Bottom price of the zone
   datetime start_time;    // When the zone starts
   datetime end_time;      // When the zone ends (current time)
};

PriceLevel StrongLevels[];    // Array for strong levels
PriceLevel WeakLevels[];      // Array for weak levels
Zone Zones[];                 // Array for strong level zones
datetime LastAlertTime = 0;   // Tracks the last alert time

手順5:スイングポイントの検出

サポートおよびレジスタンスレベルは、しばしばスイングハイやスイングローの付近に形成されます。そこで、スイングハイを特定する関数を作成します。この関数では、あるバーの高値がその前後5本のバーの高値を超えているかどうかを確認し、ピークをマークします。同様に、スイングローを検出する関数では、あるバーの安値が前後5本のバーの安値より低いかどうかをチェックし、谷を示します。前後5本のバーを対象にすることで、これらのポイントが重要な転換点であることを保証します。

bool IsSwingHigh(int index, const double &high[])
{
   int window = 5;  // Check 5 bars on each side
   for (int i = 1; i <= window; i++) {
      if (index - i < 0 || index + i >= ArraySize(high)) return false; // Out of bounds
      if (high[index] <= high[index - i] || high[index] <= high[index + i]) return false; // Not a peak
   }
   return true;
}

bool IsSwingLow(int index, const double &low[])
{
   int window = 5;  // Check 5 bars on each side
   for (int i = 1; i <= window; i++) {
      if (index - i < 0 || index + i >= ArraySize(low)) return false; // Out of bounds
      if (low[index] >= low[index - i] || low[index] >= low[index + i]) return false; // Not a trough
   }
   return true;
}

手順6:価格テストのカウント

レベルの強さは、価格がそのレベルを何度テストしたかによって決まります。そこで、スイングポイントの後のバーを調べてテスト回数をカウントする関数を追加します。この関数は、各バーの高値または安値がレベルの定めた価格範囲内にあるかどうかをチェックし、該当するたびにカウンタを増やします。合計のテスト回数が、ユーザー設定の最小閾値を満たすかどうかで、そのレベルが強いか弱いかを判定します。

int CountLevelTests(double price, int start_index, const double &high[], const double &low[])
{
   int tests = 0;
   for (int i = start_index + 1; i < ArraySize(high); i++) {
      if (MathAbs(high[i] - price) <= InpTestProximity || MathAbs(low[i] - price) <= InpTestProximity) {
         tests++;
      }
   }
   return tests;
}

手順7:レベルの処理

それぞれのスイングポイントを専用の関数でレベルとして処理します。この関数では、価格、テスト回数、時間、タイプ(強い/弱い、サポート/レジスタンス)を記録します。スイングハイかスイングローか、そしてテスト回数が閾値を満たしているかに基づいて分類されます。強いレベルの場合は、そのレベルの周囲に価格範囲を持つゾーンも定義します。処理が終わったレベルは、後で使うために強いレベル用または弱いレベル用の配列に格納されます。

void ProcessLevel(int index, double price, bool is_high, const double &high[], const double &low[], const datetime &time[])
{
   PriceLevel level;
   level.price = price;
   level.test_count = CountLevelTests(price, index, high, low);
   level.time = time[index];
   
   if (is_high) {
      level.type = (level.test_count >= InpMinTests) ? LEVEL_STRONG_RESISTANCE : LEVEL_WEAK_RESISTANCE;
   } else {
      level.type = (level.test_count >= InpMinTests) ? LEVEL_STRONG_SUPPORT : LEVEL_WEAK_SUPPORT;
   }
   
   if (level.test_count >= InpMinTests) {
      ArrayResize(StrongLevels, ArraySize(StrongLevels) + 1);
      StrongLevels[ArraySize(StrongLevels) - 1] = level;
      Zone zone;
      zone.start_time = time[index];
      zone.end_time = TimeCurrent();
      zone.top = price + InpTestProximity;
      zone.bottom = price - InpTestProximity;
      ArrayResize(Zones, ArraySize(Zones) + 1);
      Zones[ArraySize(Zones) - 1] = zone;
   } else {
      ArrayResize(WeakLevels, ArraySize(WeakLevels) + 1);
      WeakLevels[ArraySize(WeakLevels) - 1] = level;
   }
}

手順8:チャートへの描画

レベルを表示するために、2つの描画関数を使います。1つ目は、強いレベルを描画します。ゾーン表示が有効な場合はグレーの矩形で囲み、ラインはサポートなら青、レジスタンスなら赤の実線で引きます。ラベルには「SS」(強いサポート)または「SR」(強いレジスタンス)を表示します。2つ目は、弱いレベルを描画します。ラインはサポートが薄い青、レジスタンスがピンクの破線で描き、ラベルは「WS」(弱いサポート)または「WR」(弱いレジスタンス)です。それぞれのオブジェクトには、識別と管理を容易にするため、時刻に基づくユニークな名前を付けています。

void RenderZone(const Zone &zone, const PriceLevel &level)
{
   string name = "Zone_" + TimeToString(zone.start_time);
   if (InpShowRectangles) {
      ObjectCreate(0, name, OBJ_RECTANGLE, 0, zone.start_time, zone.top, zone.end_time, zone.bottom);
      ObjectSetInteger(0, name, OBJPROP_COLOR, clrLightGray);
      ObjectSetInteger(0, name, OBJPROP_FILL, true);
   }
   
   string line_name = "Line_" + TimeToString(level.time);
   ObjectCreate(0, line_name, OBJ_HLINE, 0, 0, level.price);
   ObjectSetInteger(0, line_name, OBJPROP_COLOR, (level.type == LEVEL_STRONG_SUPPORT) ? clrBlue : clrRed);
   ObjectSetString(0, line_name, OBJPROP_TEXT, (level.type == LEVEL_STRONG_SUPPORT) ? "SS" : "SR");
}

void RenderWeakLine(const PriceLevel &level)
{
   string name = "WeakLine_" + TimeToString(level.time);
   ObjectCreate(0, name, OBJ_HLINE, 0, 0, level.price);
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
   ObjectSetInteger(0, name, OBJPROP_COLOR, (level.type == LEVEL_WEAK_SUPPORT) ? clrLightBlue : clrPink);
   ObjectSetString(0, name, OBJPROP_TEXT, (level.type == LEVEL_WEAK_SUPPORT) ? "WS" : "WR");
}

手順9:アラートの送信

強いレベルに関するアラートをユーザーに過剰に送らないように、専用の関数を設けます。この関数は、前回のアラート送信から1時間以上経過しているか、そして強いレベルが存在するかを確認します。条件を満たした場合、最新の強いレベルの種類、価格、現在の価格を含むメッセージを作成し、表示します。また、アラート送信時間を更新して、頻繁な通知を防ぎます。

void SendPeriodicAlert(double current_price)
{
   if (TimeCurrent() - LastAlertTime < 3600) return; // Wait 1 hour between alerts
   if (ArraySize(StrongLevels) == 0) return;         // No strong levels, no alert
   
   PriceLevel latest = StrongLevels[ArraySize(StrongLevels) - 1];
   string message = "SRZones Alert: Strong " + 
                    ((latest.type == LEVEL_STRONG_SUPPORT) ? "Support" : "Resistance") + 
                    " at " + DoubleToString(latest.price, 5) + 
                    ", Current Price: " + DoubleToString(current_price, 5);
   Alert(message);
   LastAlertTime = TimeCurrent();
}

手順10:古い描画オブジェクトの削除

チャートを見やすく保つために、古いオブジェクトを削除する関数を追加します。この関数は、以前に描画したゾーン、強いレベルのライン、弱いレベルのラインを、それぞれの名前の接頭辞を使って一括削除します。この処理は、毎回インジケーターの全再計算が始まる前に実行され、最新のレベルでチャート表示を更新します。

void ClearDisplayObjects()
{
   ObjectsDeleteAll(0, "Zone_");       // Delete all zones
   ObjectsDeleteAll(0, "Line_");       // Delete strong lines
   ObjectsDeleteAll(0, "WeakLine_");   // Delete weak lines
}

手順11:OnCalculateでロジックを実行する

最後に、すべての処理をメインの計算関数でまとめます。起動時および新しいバーが形成されるたびに、古いオブジェクトを削除し、配列をリセットします。ユーザーが設定した遡及期間に基づき、スイング検出に十分なデータがある開始位置を決定します。その後、バーをループ処理し、スイングハイとスイングローを特定し、レベルとして処理して保存します。続いて、強いレベルと弱いレベルをすべて描画し、アラートのチェックをおこないます。この関数は、処理したバーの数をMetaTrader 5に返します。

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[])
{
   if (prev_calculated == 0 || rates_total > prev_calculated) { // Full recalc on start or new bar
      ClearDisplayObjects();
      ArrayResize(StrongLevels, 0);
      ArrayResize(WeakLevels, 0);
      ArrayResize(Zones, 0);
      
      int start = MathMax(5, rates_total - InpLookBack); // Start within lookback period
      for (int i = start; i < rates_total - 5; i++) {    // Leave room for swing checks
         if (IsSwingHigh(i, high)) ProcessLevel(i, high[i], true, high, low, time);
         if (IsSwingLow(i, low)) ProcessLevel(i, low[i], false, high, low, time);
      }
      
      for (int i = 0; i < ArraySize(StrongLevels); i++) {
         RenderZone(Zones[i], StrongLevels[i]);
      }
      for (int i = 0; i < ArraySize(WeakLevels); i++) {
         RenderWeakLine(WeakLevels[i]);
      }
      
      SendPeriodicAlert(close[rates_total - 1]);
   }
   return(rates_total); // Tell MT5 how many bars were processed
}

すべてのパーツを組み合わせ、さまざまな問題を解決した結果、最終製品を無事にコンパイルできました。完成したプログラムは本稿の最後に添付しています。次のセクションでは、テストの経験を共有し、結論として総括をおこないます。


テストと結果 

最初の手順として、インジケーターを起動し、EURUSDを基準にデフォルト設定のままチャートに追加しました。他の通貨ペアでは、特にpips値の調整が必要になる場合があり、正しく表示させるために初期設定を変更することがあります。たとえば、Volatility 75 (1s) Indexでテストした際には、pips設定を70に調整するまでゾーンが表示されませんでした。

最初の段階では、以下の画像のように矩形の幅が比較的小さく、サイズを広げるカスタマイズが必要でした。この調整をおこなった結果は次の画像に示しています。すべての設定は問題なく反映され、チャート上で明確な変化が確認できました。また、すべてのラベルも見やすく表示されており、必要に応じて非表示にすることも可能です。

SRSIをチャートに追加する

チャートにサポートおよびレジスタンス強度インジケーター(SRSI)を追加する

SRSIのカスタマイズ

SRSIの設定をカスタマイズする

インジケーターを初めて起動すると、現在のサポートまたはレジスタンスレベルとともに現在価格を表示するアラートが送信されます。これにより、ユーザーは今後の供給・需要ゾーンを予測しやすくなります。以下は、アラートの詳細を示したエキスパートアドバイザー(EA)ログです。

2025.03.10 07:44:42.548 _SRSI (EURUSD,M15)      Alert: Key Level: SR at 1.08715 | Current Price: 1.09021
2025.03.10 07:54:04.239 _SRSI (EURUSD,M15)      Alert: Key Level: SR at 1.08715 | Current Price: 1.09033
2025.03.10 07:55:04.965 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09044
2025.03.10 09:25:13.506 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09210
2025.03.10 11:26:46.761 _SRSI (EURUSD,M5)       Alert: Key Level: SR at 1.09013 | Current Price: 1.09192

また、設定にはプッシュ通知を有効にするオプションが用意されており、ターミナル通知はデフォルトで有効になっています。アラートが発生すると、アラートウィンドウが自動的にターミナル画面に表示されます。

アラート

ターミナルアラートウィンドウ:SRSIインジケーターの動作


結論 

今回のディスカッションの目的は、エラーのないインジケーターの開発という形で無事に達成されました。テスト結果からも、設計目標はしっかりと満たされ、期待通りの機能が実現されています。サポートラインとレジスタンスラインを数クリックで簡単に引くことができ、アルゴリズムが自動でその信頼性を判別してくれるようになりました。動画でもご覧いただいたように、手動でレベルを引く作業は非常に時間がかかりますが、アルゴリズムを使えばティックごとに瞬時にレベルが計算されます。このプロセスを通じて、インジケーター開発におけるMQL5の貴重な知見を得ることができました。今後もインジケーターのパフォーマンスを時間をかけて検証していく必要がありますが、より高度な開発者であれば、本ツールをさらに洗練・拡張するさまざまな方法があるはずです。

今回の実装では、よりプロフェッショナルで整然としたコードを書くため、構造体を導入しました。ただし、改善の余地は常にありますし、皆さん自身のアイデアや工夫でこのツールをさらに強化できるはずです。ぜひ自由に改良し、試してみてください。また、ご意見やご感想があれば、コメント欄でお知らせいただけると嬉しいです。

このディスカッションが皆さんにとって有益であったことを願っています。それでは、また次回お会いしましょう。開発者仲間の皆さん、コーディングを楽しんでください。そして、皆さんの取引が成功しますように。


添付ファイル(SRSIソースファイル) 

ファイル 説明
_SRSI.mq5 調整可能な長方形のゾーンを動的に描画し、強いサポート(SS)・レジスタンス(SR)を明確にラベル付けするサポートおよびレジスタンス強度インジケーター。さらに、より見やすくするために、弱いサポート(WS)・レジスタンス(WR)レベルを示す破線をプロットします。

目次に戻る

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/17450

添付されたファイル |
_SRSI.mq5 (29.97 KB)
最後のコメント | ディスカッションに移動 (6)
Clemence Benjamin
Clemence Benjamin | 20 3月 2025 において 18:13
Darz #:
あなたの記事がとても好きで、FXペアで試してみましたが、うまくいっているようです。US30のような指数はどうですか?どのような設定がお勧めですか?私はテキストの近接性を0.035に設定してみましたが、結果はおかしいようです。
こんにちは、@Darz です。ご回答ありがとうございます!
USテックや他の合成ペアでは、ピップ値が高いため、より高いプロキシミティ値が必要であることに気づきました。私は、US Techにレジスタンスゾーンが出現し始める前に、この値を10に 設定する必要がありました。
特定のペアに最適な設定を見つけるまで、この値を試してみることをお勧めします。

ありがとうございました!


Anil Varma
Anil Varma | 21 3月 2025 において 08:53
Clemence Benjamin #:
こんにちは、@Darzさん。お返事ありがとう!
USテックや他の合成ペアでは、ピップ値が高いため、より高いプロキシミティ値が必要であることに気づきました。USテックにレジスタンスゾーンが出現し始める前に、私はそれを10に 設定しなければなりませんでした。
特定のペアに最適な設定を見つけるまで、この値を試してみることをお勧めします。

ありがとうございました!


こんにちは

私はあなたの記事を見ています。知識の共有と拡散に感謝します。

私は以下のように21Period ATR multipleを試してみました:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1))); // (n*getATR(index) replaced for ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1))); // (n*getATR(index) は ...InpMinWeakDistance に置き換わった;

これで、EURUSDとXAUSDの両ペアのSRZonesを、1.08000から3000.00というかなり異なる値で取得することができました。

さらに少し微調整することで、あなたの記事の読者に役立つかもしれません。そうすれば、インジケータの設定はほとんどのシンボルに対して普遍的なものになるでしょう。

Clemence Benjamin
Clemence Benjamin | 25 3月 2025 において 22:09
Anil Varma #:

ハローフレンド

あなたの記事はとても参考になります。知識を分かち合い、広めてくれてありがとう。

私は21Period ATR multipleを以下のように試してみました:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1))); // (n*getATR(index) replaced for ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1)); // (n*getATR(index) replaced for ...InpMinWeakDistance;

これで、EURUSDとXAUSDの両ペアのSRZonesを、1.08000から3000.00というかなり異なる値で取得することができました。

さらに少し微調整することで、あなたの記事の読者に役立つかもしれません。そうすれば、インジケータの設定はほとんどのシンボルに対して普遍的なものになるでしょう。

こんにちは、親友のアニル・ヴァルマ です。

このユニークな方法を教えてくれてありがとう!ぜひ試してみます。

Evgeny Fedorenko
Evgeny Fedorenko | 9 6月 2025 において 14:44
Anil Varma #:

ハローフレンド

あなたの記事はとても参考になります。知識を分かち合い、広めてくれてありがとう。

21PeriodのATRマルチプルを試してみました:

gTestProximity = (MathMax((75/_Digits),0.10*getATR(rates_total - 1))); // (n*getATR(index) replaced for ...InpTextProximity;

gMinDistance = (MathMax((150/_Digits),0.20*getATR(rates_total - 1)); // (n*getATR(index) replaced for ...InpMinWeakDistance;

これで、EURUSDとXAUSDの両ペアのSRZonesを、1.08000から3000.00というかなり異なる値で取得することができました。

さらに少し微調整することで、あなたの記事の読者に役立つかもしれません。そうすれば、インジケータの設定はほとんどのシンボルに対して普遍的なものになるでしょう。


ATRインジケータのバージョンを教えていただけますか?
Anil Varma
Anil Varma | 18 6月 2025 において 10:25
Evgeny Fedorenko #:

ATRインジケータのバージョンを教えてください。

こんにちは

実は、クオンツ・ファイナンシャル・モデリングのコースに注意を移していたのです。

クレマンス・ベンジャミンの インジケーターのコードに、私の投稿で提案した微調整を加えてみただけです。

お役に立てれば幸いです。

MQL5における予測および分類評価のためのリサンプリング手法 MQL5における予測および分類評価のためのリサンプリング手法
本記事では、1つのデータセットを訓練(学習)用と検証用の両方として使用するモデル評価手法について、理論と実装の両面から検討します。
最適化におけるカスタム基準への新しいアプローチ(第1回):活性化関数の例 最適化におけるカスタム基準への新しいアプローチ(第1回):活性化関数の例
これは、カスタム基準に関する数学的考察をおこなう連載記事の第1回目です。特に、ニューラルネットワークで使用される非線形関数、実装用のMQL5コード、さらにターゲットオフセットや補正オフセットの活用に焦点を当てています。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
受信者動作特性曲線の紹介 受信者動作特性曲線の紹介
ROC曲線は、分類器の性能を評価するために使用されるグラフ表現です。ROC曲線は比較的単純に見えますが、実際に使用する際には、よくある誤解や陥りやすい落とし穴があります。この記事の目的は、分類器の性能評価を理解しようとする実務者に向けて、ROC曲線を紹介することです。