English Deutsch
preview
プライスアクション分析ツールキットの開発(第18回):クォーターズ理論の紹介(III) - Quarters Board

プライスアクション分析ツールキットの開発(第18回):クォーターズ理論の紹介(III) - Quarters Board

MetaTrader 5 |
95 0
Christian Benjamin
Christian Benjamin

内容


はじめに

クォーターズ理論の導入では、最初のコンポーネントであるQuarters Drawerスクリプトから始めました。このスクリプトは、チャート上にクォーターレベルを自動的に描画し、各水準の表示・非表示を制御するブール型の切り替え機能を備えています。

input bool   DrawLargeQuarters  = true;     // Draw intermediate large quarter lines.
input bool   DrawSmallQuarters  = false;    // Draw small quarter lines.
input bool   DrawOvershootAreas = true;     // Mark overshoot/undershoot areas for large quarter lines.

たとえば、DrawSmallQuartersをtrueに設定するとスモールクォーターが表示され、DrawLargeQuartersをfalseに設定するとラージークォーターラインが非表示になります。同じアプローチがオーバーシュートとアンダーシュートのレベルにも適用されます。この機能により、特定のレベルに集中でき、チャートをすっきりと見やすく保つことができます。すべてのレベルを表示したい場合は、すべてのトグルを有効にするだけでOKです。

設定を切り替えるたびに、いちいちコードに戻って変更するのが面倒だと感じたことはありませんか。この記事では、「Quarters Board」という強化ツールを紹介します。これは、ライブチャート上でボタンを押すだけでブール値のフラグ(true/false)を自動的に切り替えることができる便利なツールです。たとえば、DrawSmallQuartersフラグを変更するためにコードを編集する代わりに、チャート上で直接調整が可能になり、すべてのトレーダーにとって操作がさらにスムーズになります。ラージクォーターだけを表示したい場合も、ボタンを1回押すだけで簡単に切り替えられます。


概要

はじめに述べたように、このツールを使えば、ブールフラグを編集するためにコードに戻ることなく、チャート上で表示するレベルを切り替えることができます。Quarter Boardはエキスパートアドバイザー(EA)であり、[Large Quarters]、[Small Quarters]、[Overshoot/Undershoot]、[Trend Direction]の4つのボタンを備えています。各ボタンを押すことで、それぞれ対応するレベルの表示が切り替わります。レベルが有効になるとボタンのテキストは緑色に、無効になると赤色になります。

[Trend Direction]ボタンは、リアルタイムの市場インサイトを提供する追加機能です。ボタンを1回クリックするだけで、50期間の単純移動平均線(SMA)を計算し、それを現在の市場価格と比較することで、市場が上昇トレンドにあるのか、下降トレンドなのか、または横ばいなのかを素早く判断できます。このボタンも、アクティブ状態を示すために色が変わるようになっており、チャート上で市場トレンドをわかりやすく・使いやすく監視できる手段を提供します。 次のセクションで、このEAの機能の中核となるロジックについて見ていきましょう。


論理

このEAは、使いやすさと高い柔軟性の両立を目指して設計されています。設定項目によりカスタマイズが簡単におこなえ、インターフェイスはシンプルで整理されており、ボタンベースの操作によりスムーズなインタラクションが可能です。クォーターラインの追加・削除を自動で処理することで、チャートは常に整理され、重要な価格帯に集中しやすくなっています。さらに、リアルタイムのトレンド解説が加わることで、トレーダーは画面を散らかすことなく、市場の方向性を素早く把握できます。視覚的なツールと分析的なツールの両方が連携することで、このEAは取引判断をシンプルにしつつ、直感的かつ効率的な操作性を保っています。

グローバル設定と構造体

EAは、価格水準やチャート上の要素をどのように表示するかを決める主要なパラメータの定義から始まります。入力設定では、たとえば「主要な価格水準の間隔」や「各ラインに使用する色」などの値をトレーダーが自由にカスタマイズできます。これにより、コアロジックを変更せずにEAの外観や挙動を柔軟に調整することが可能です。コードには、ラージークォーターラインやトレンド解説の有効化といった特定機能のオン/オフを切り替えるためのグローバルなブール変数がいくつか含まれています。また、マクロを使ってチャート上のオブジェクトに一貫性のある名前を割り当てており、スクリプト全体で各要素を統一的に参照できるようにしています。これらの設定を一箇所にまとめて管理することで、パラメータの調整や不具合のトラブルシューティングが容易になり、コード全体を探し回る手間を省くことができます。
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/ja/users/lynnchris"
#property version   "1.0"
#property strict

//---- Input parameters for drawing levels ----------------------------
input double MajorStep = 0.1000;   // Difference between major whole numbers

//---- Color settings ---------------------------------------------------
input color  MajorColor         = 0x2F4F4F; // Dark Slate Gray for major lines.
input color  LargeQuarterColor  = 0x8B0000; // Dark Red for large quarter lines.
input color  SmallQuarterColor  = 0x00008B; // Dark Blue for small quarter lines.
input color  OvershootColor     = clrRed;   // Red for overshoot/undershoot lines.

//---- Line styles and thickness settings -----------------------------
input ENUM_LINE_STYLE MajorLineStyle       = STYLE_SOLID;
input int    MajorLineWidth                 = 4;
input ENUM_LINE_STYLE LargeQuarterLineStyle  = STYLE_DOT;
input int    LargeQuarterLineWidth          = 3;
input ENUM_LINE_STYLE OvershootLineStyle     = STYLE_DASH;
input int    OvershootLineWidth             = 1;
input ENUM_LINE_STYLE SmallQuarterLineStyle  = STYLE_SOLID;
input int    SmallQuarterLineWidth          = 1;

//---- Panel and button settings --------------------------------------
input int PanelX       = 10;
input int PanelY       = 10;
input int PanelWidth   = 250;
input int ButtonHeight = 30;
input int ButtonSpacing= 5;

//---- Global toggle variables ----------------------------------------
bool g_DrawLargeQuarters   = true;
bool g_DrawSmallQuarters   = false;
bool g_DrawOvershootAreas  = true;
bool g_DrawTrendDirection  = false;

//---- Object names for panel and buttons -----------------------------
#define PANEL_NAME       "LevelsPanel"
#define BUTTON_LARGE     "btnLargeQuarters"
#define BUTTON_SMALL     "btnSmallQuarters"
#define BUTTON_OVERSHOOT "btnOvershoot"
#define BUTTON_TREND     "btnTrendDirection"
#define TREND_LABEL      "TrendDirectionLabel"

パネルおよびボタンの初期化

設定が完了すると、EAはユーザーインターフェイスの構築を開始します。すべてのボタンをまとめる背景パネルが作成され、整理されたレイアウトを提供します。このパネルは長方形のラベルオブジェクトを使って擬似的に表現されており、テキストプロパティを調整することでサイズを指定しています。ボタンはパネルを基準に配置され、適切な間隔と整列が保たれるように設計されています。

これらのボタンにより、トレーダーは、ラージークォーター、スモールクォーター、オーバーシュート領域、トレンド解説の表示などの機能を簡単に切り替えることができます。各ボタンには統一された幅と高さが設定されており、インターフェイス全体がすっきりとした印象になります。このように設定することで、ユーザーはシンプルなクリック操作で個別の要素をオン・オフでき、EAとのインタラクションが直感的かつ快適になります。統一されたレイアウトを維持することで、すべての操作が視覚的にわかりやすく、すぐにアクセスできるようになっています。

void CreatePanel()
  {
   if(ObjectCreate(0, PANEL_NAME, OBJ_RECTANGLE_LABEL, 0, 0, 0))
     {
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_XDISTANCE, PanelX);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_YDISTANCE, PanelY);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_COLOR, clrDarkGray);
      ObjectSetString(0, PANEL_NAME, OBJPROP_TEXT, "\n\n\n\n");
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_BORDER_TYPE, BORDER_RAISED);
     }
  }

ユーザーインタラクションの処理

ユーザーとのインタラクションはEAの重要な要素であり、イベント処理システムによって管理されています。スクリプトはチャート上のイベントを監視しており、特にボタンがクリックされたかどうかを確認します。ボタンが押されると、システムはそのボタンの名前に基づいてどの機能を実行するかを特定します。対象が特定されると、該当する機能がオンまたはオフに切り替えられます。たとえば、[Large Quarters]ボタンを押すと、その価格水準の表示・非表示が切り替わります。

ユーザー体験をさらに向上させるために、ボタンの色は即座に更新され、視覚的なフィードバックが提供されます。たとえば、アクティブなボタンは緑色に、非アクティブなボタンは赤色のまま表示されるようになっています。このシステムにより、各機能が個別に動作し、他の機能との競合を防ぎながら、リアルタイムのユーザー操作に即応できるようになっています。イベント処理の構造を効率的に整備することで、EAは高速な市場環境でも安定性と使いやすさを保ちます。

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      if(sparam == BUTTON_LARGE)
        {
         g_DrawLargeQuarters = !g_DrawLargeQuarters;
         UpdateButtonColors();
         DrawQuarterLines();
        }
      else if(sparam == BUTTON_TREND)
        {
         g_DrawTrendDirection = !g_DrawTrendDirection;
         UpdateButtonColors();
         if(g_DrawTrendDirection)
            UpdateTrendComment();
         else
            DeleteTrendComment();
        }
      // Similar handling for other buttons...
     }
  }

クォーターラインの描画と削除

このEAの主要な機能の一つは、チャート上に価格水準をプロットすることです。処理は、まず現在の市場価格を取得し、主要な価格境界を計算するところから始まります。主要レベル(メジャーレベル)は常に表示されますが、ラージクォーター、スモールクォーター、オーバーシュートゾーンといった追加レベルは、それぞれのボタンが有効化されている場合にのみ表示されます。チャートを整理された状態に保つため、EAはまず既存のラインをすべて削除してから新しいラインを描画します。

これにより、重複や古いラインによる混乱を防止できます。各クォーターの分割方式には体系的な計算手順があり、価格水準が正しく整列するように設計されています。ある機能が無効化された場合、スクリプトは該当するラインを自動的に削除し、表示内容を常にユーザーの選択に合わせて更新します。このアプローチにより、チャートは常に整理され、ユーザーにとって最も関連性の高い情報のみを表示するようになります。

void DrawQuarterLines()
  {
   DeleteQuarterLines();
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   if(g_DrawLargeQuarters)
     {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
        {
         double level = lowerMajor + i * LQIncrement;
         DrawHorizontalLine("LargeQuarter_" + IntegerToString(i), level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);
         // Overshoot/Undershoot handling...
        }
     }
   // Additional code for small quarters...
  }

トレンド解説の表示

グラフィカルな要素に加え、このEAは市場トレンドに関するテキストによる分析情報もトレーダーに提示します。定義された期間に基づいて単純移動平均(SMA)を計算し、それを現在の価格と比較します。価格がSMAを上回っていれば上昇トレンド(強気)、下回っていれば下降トレンド(弱気)と判断されます。価格がSMA付近であまり動きがない場合は、レンジ(中立)として分類されます。この分析結果は、チャート上にテキストラベルとして表示され、他の要素と干渉しないように「Trend Direction」ボタンのすぐ下に配置されます。ラベルはリアルタイムで更新され、市場の動向に応じて常に最新のインサイトを提供します。この機能は、グラフィカルなクォーターライン表示に分析的な視点を加える補完的な役割を果たし、トレーダーがより情報に基づいた意思決定をおこなえるよう支援します。

void UpdateTrendComment()
  {
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double smaValue = 0.0;
   int handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE);
   if(handle != INVALID_HANDLE)
     {
      double buffer[];
      if(CopyBuffer(handle, 0, 1, 1, buffer) > 0)
         smaValue = buffer[0];
      IndicatorRelease(handle);
     }
   string trendComment = (currentPrice > smaValue) ? "Uptrend" :
                         (currentPrice < smaValue) ? "Downtrend" : "Sideways";
                         
   int trendLabelY = PanelY + 10 + 3 * (ButtonHeight + ButtonSpacing) + ButtonHeight + ButtonSpacing;
   if(ObjectFind(0, TREND_LABEL) == -1)
     {
      ObjectCreate(0, TREND_LABEL, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_XDISTANCE, PanelX + 10);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_YDISTANCE, trendLabelY);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_COLOR, clrWhite);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_FONTSIZE, 14);
     }
   ObjectSetString(0, TREND_LABEL, OBJPROP_TEXT, "Trend Direction: " + trendComment);
  }

完全なEAコード

//+------------------------------------------------------------------+
//|                                             Quarters Board EA.mq5|
//|                                Copyright 2025, Christian Benjamin|
//|                           https://www.mql5.com/ja/users/lynnchris|
//+------------------------------------------------------------------+
#property copyright "Christian Benjamin"
#property link      "https://www.mql5.com/ja/users/lynnchris"
#property version   "1.0"
#property strict

//---- Input parameters for drawing levels ----------------------------
input double MajorStep = 0.1000;   // Difference between major whole numbers

//---- Color settings ---------------------------------------------------
input color  MajorColor         = 0x2F4F4F; // Dark Slate Gray for major lines.
input color  LargeQuarterColor  = 0x8B0000; // Dark Red for large quarter lines.
input color  SmallQuarterColor  = 0x00008B; // Dark Blue for small quarter lines.
input color  OvershootColor     = clrRed;   // Red for overshoot/undershoot lines.

//---- Line styles and thickness settings -----------------------------
input ENUM_LINE_STYLE MajorLineStyle       = STYLE_SOLID;
input int    MajorLineWidth                 = 4;
input ENUM_LINE_STYLE LargeQuarterLineStyle  = STYLE_DOT;
input int    LargeQuarterLineWidth          = 3;
input ENUM_LINE_STYLE OvershootLineStyle     = STYLE_DASH;
input int    OvershootLineWidth             = 1;
input ENUM_LINE_STYLE SmallQuarterLineStyle  = STYLE_SOLID;
input int    SmallQuarterLineWidth          = 1;

//---- Panel and button settings --------------------------------------
input int PanelX       = 10;
input int PanelY       = 10;
input int PanelWidth   = 250;
input int ButtonHeight = 30;
input int ButtonSpacing= 5;

//---- Global toggle variables ----------------------------------------
bool g_DrawLargeQuarters   = true;
bool g_DrawSmallQuarters   = false;
bool g_DrawOvershootAreas  = true;
bool g_DrawTrendDirection  = false;

//---- Object names for panel and buttons -----------------------------
#define PANEL_NAME       "LevelsPanel"
#define BUTTON_LARGE     "btnLargeQuarters"
#define BUTTON_SMALL     "btnSmallQuarters"
#define BUTTON_OVERSHOOT "btnOvershoot"
#define BUTTON_TREND     "btnTrendDirection"
#define TREND_LABEL      "TrendDirectionLabel"

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
// Create panel background and buttons
   CreatePanel();
   CreateButtons();
// Draw quarter lines initially
   DrawQuarterLines();
// If trend commentary is toggled on, update it
   if(g_DrawTrendDirection)
      UpdateTrendComment();
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
// Delete panel, buttons, quarter lines, and trend commentary
   ObjectDelete(0, PANEL_NAME);
   ObjectDelete(0, BUTTON_LARGE);
   ObjectDelete(0, BUTTON_SMALL);
   ObjectDelete(0, BUTTON_OVERSHOOT);
   ObjectDelete(0, BUTTON_TREND);
   DeleteQuarterLines();
   DeleteTrendComment();
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Redraw quarter lines on every tick
   DrawQuarterLines();
// Update trend commentary if enabled
   if(g_DrawTrendDirection)
      UpdateTrendComment();
  }
//+------------------------------------------------------------------+
//| Chart event function to catch button clicks                      |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
   if(id == CHARTEVENT_OBJECT_CLICK)
     {
      if(sparam == BUTTON_LARGE)
        {
         g_DrawLargeQuarters = !g_DrawLargeQuarters;
         UpdateButtonColors();
         DrawQuarterLines();
        }
      else
         if(sparam == BUTTON_SMALL)
           {
            g_DrawSmallQuarters = !g_DrawSmallQuarters;
            UpdateButtonColors();
            DrawQuarterLines();
           }
         else
            if(sparam == BUTTON_OVERSHOOT)
              {
               g_DrawOvershootAreas = !g_DrawOvershootAreas;
               UpdateButtonColors();
               DrawQuarterLines();
              }
            else
               if(sparam == BUTTON_TREND)
                 {
                  g_DrawTrendDirection = !g_DrawTrendDirection;
                  UpdateButtonColors();
                  if(g_DrawTrendDirection)
                     UpdateTrendComment();
                  else
                     DeleteTrendComment();
                 }
     }
  }
//+------------------------------------------------------------------+
//| Create panel background                                          |
//+------------------------------------------------------------------+
void CreatePanel()
  {
   if(ObjectCreate(0, PANEL_NAME, OBJ_RECTANGLE_LABEL, 0, 0, 0))
     {
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_XDISTANCE, PanelX);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_YDISTANCE, PanelY);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_COLOR, clrDarkGray);
      // Simulate a larger panel using newlines in the text.
      string panelText = "\n\n\n\n";
      ObjectSetString(0, PANEL_NAME, OBJPROP_TEXT, panelText);
      ObjectSetInteger(0, PANEL_NAME, OBJPROP_BORDER_TYPE, BORDER_RAISED);
     }
  }
//+------------------------------------------------------------------+
//| Create buttons on the panel                                      |
//+------------------------------------------------------------------+
void CreateButtons()
  {
   int x = PanelX + 10;
   int y = PanelY + 10;
   int btnWidth = PanelWidth - 20;
// Button for Large Quarters
   if(!ObjectCreate(0, BUTTON_LARGE, OBJ_BUTTON, 0, 0, 0))
      Print("Failed to create button ", BUTTON_LARGE);
   else
     {
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_XSIZE, btnWidth);
      ObjectSetInteger(0, BUTTON_LARGE, OBJPROP_YSIZE, ButtonHeight);
      ObjectSetString(0, BUTTON_LARGE, OBJPROP_TEXT, "Large Quarters");
     }
// Button for Smaller Quarters
   y += ButtonHeight + ButtonSpacing;
   if(!ObjectCreate(0, BUTTON_SMALL, OBJ_BUTTON, 0, 0, 0))
      Print("Failed to create button ", BUTTON_SMALL);
   else
     {
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_XSIZE, btnWidth);
      ObjectSetInteger(0, BUTTON_SMALL, OBJPROP_YSIZE, ButtonHeight);
      ObjectSetString(0, BUTTON_SMALL, OBJPROP_TEXT, "Smaller Quarters");
     }
// Button for Overshoot/Undershoot
   y += ButtonHeight + ButtonSpacing;
   if(!ObjectCreate(0, BUTTON_OVERSHOOT, OBJ_BUTTON, 0, 0, 0))
      Print("Failed to create button ", BUTTON_OVERSHOOT);
   else
     {
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_XSIZE, btnWidth);
      ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_YSIZE, ButtonHeight);
      ObjectSetString(0, BUTTON_OVERSHOOT, OBJPROP_TEXT, "Overshoot/Undershoot");
     }
// Button for Trend Direction
   y += ButtonHeight + ButtonSpacing;
   if(!ObjectCreate(0, BUTTON_TREND, OBJ_BUTTON, 0, 0, 0))
      Print("Failed to create button ", BUTTON_TREND);
   else
     {
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_XDISTANCE, x);
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_YDISTANCE, y);
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_XSIZE, btnWidth);
      ObjectSetInteger(0, BUTTON_TREND, OBJPROP_YSIZE, ButtonHeight);
      ObjectSetString(0, BUTTON_TREND, OBJPROP_TEXT, "Trend Direction");
     }
   UpdateButtonColors();
  }
//+------------------------------------------------------------------+
//| Update button colors based on toggle state                       |
//+------------------------------------------------------------------+
void UpdateButtonColors()
  {
   color onColor  = clrGreen;
   color offColor = clrRed;
   ObjectSetInteger(0, BUTTON_LARGE,     OBJPROP_COLOR, g_DrawLargeQuarters  ? onColor : offColor);
   ObjectSetInteger(0, BUTTON_SMALL,     OBJPROP_COLOR, g_DrawSmallQuarters  ? onColor : offColor);
   ObjectSetInteger(0, BUTTON_OVERSHOOT, OBJPROP_COLOR, g_DrawOvershootAreas ? onColor : offColor);
   ObjectSetInteger(0, BUTTON_TREND,     OBJPROP_COLOR, g_DrawTrendDirection ? onColor : offColor);
  }
//+------------------------------------------------------------------+
//| Delete quarter lines                                             |
//+------------------------------------------------------------------+
void DeleteQuarterLines()
  {
   ObjectDelete(0, "MajorLower");
   ObjectDelete(0, "MajorUpper");
   for(int i = 1; i < 4; i++)
     {
      ObjectDelete(0, "LargeQuarter_" + IntegerToString(i));
      ObjectDelete(0, "Overshoot_" + IntegerToString(i) + "_up");
      ObjectDelete(0, "Undershoot_" + IntegerToString(i) + "_down");
     }
   for(int seg = 0; seg < 10; seg++)
     {
      for(int j = 1; j < 4; j++)
        {
         ObjectDelete(0, "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j));
        }
     }
  }
//+------------------------------------------------------------------+
//| Delete trend commentary                                          |
//+------------------------------------------------------------------+
void DeleteTrendComment()
  {
   ObjectDelete(0, TREND_LABEL);
  }
//+------------------------------------------------------------------+
//| Update trend commentary                                          |
//+------------------------------------------------------------------+
void UpdateTrendComment()
  {
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(currentPrice == 0)
      return;
   double smaValue = 0.0;
   double buffer[];
   int handle = iMA(_Symbol, PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE);
   if(handle != INVALID_HANDLE)
     {
      if(CopyBuffer(handle, 0, 1, 1, buffer) > 0)
         smaValue = buffer[0];
      IndicatorRelease(handle);
     }
   string trendComment;
   if(currentPrice > smaValue)
      trendComment = "Uptrend";
   else
      if(currentPrice < smaValue)
         trendComment = "Downtrend";
      else
         trendComment = "Sideways";

// Calculate the position for the commentary label below the Trend Direction button
   int trendButtonY = PanelY + 10 + 3 * (ButtonHeight + ButtonSpacing);
   int trendLabelY = trendButtonY + ButtonHeight + ButtonSpacing;
   int trendLabelX = PanelX + 10;

   if(ObjectFind(0, TREND_LABEL) == -1)
     {
      ObjectCreate(0, TREND_LABEL, OBJ_LABEL, 0, 0, 0);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_CORNER, CORNER_LEFT_UPPER);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_XDISTANCE, trendLabelX);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_YDISTANCE, trendLabelY);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_COLOR, clrWhite);
      ObjectSetInteger(0, TREND_LABEL, OBJPROP_FONTSIZE, 14);
     }
   string txt = "Trend Direction: " + trendComment;
   ObjectSetString(0, TREND_LABEL, OBJPROP_TEXT, txt);
  }
//+------------------------------------------------------------------+
//| Draw horizontal line utility                                     |
//+------------------------------------------------------------------+
void DrawHorizontalLine(string name, double price, color lineColor, int width, ENUM_LINE_STYLE style)
  {
   if(ObjectFind(0, name) != -1)
      ObjectDelete(0, name);
   if(!ObjectCreate(0, name, OBJ_HLINE, 0, 0, price))
     {
      Print("Failed to create line: ", name);
      return;
     }
   ObjectSetInteger(0, name, OBJPROP_COLOR, lineColor);
   ObjectSetInteger(0, name, OBJPROP_STYLE, style);
   ObjectSetInteger(0, name, OBJPROP_WIDTH, width);
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, true);
  }
//+------------------------------------------------------------------+
//| Draw quarter lines based on toggle settings                      |
//+------------------------------------------------------------------+
void DrawQuarterLines()
  {
   DeleteQuarterLines();
   double currentPrice = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   if(currentPrice == 0)
      return;
   double lowerMajor = MathFloor(currentPrice / MajorStep) * MajorStep;
   double upperMajor = lowerMajor + MajorStep;
   DrawHorizontalLine("MajorLower", lowerMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   DrawHorizontalLine("MajorUpper", upperMajor, MajorColor, MajorLineWidth, MajorLineStyle);
   if(g_DrawLargeQuarters)
     {
      double LQIncrement = MajorStep / 4.0;
      for(int i = 1; i < 4; i++)
        {
         double level = lowerMajor + i * LQIncrement;
         string objName = "LargeQuarter_" + IntegerToString(i);
         DrawHorizontalLine(objName, level, LargeQuarterColor, LargeQuarterLineWidth, LargeQuarterLineStyle);
         if(g_DrawOvershootAreas)
           {
            double smallQuarter = MajorStep / 40.0;
            DrawHorizontalLine("Overshoot_" + IntegerToString(i) + "_up", level + smallQuarter, OvershootColor, OvershootLineWidth, OvershootLineStyle);
            DrawHorizontalLine("Undershoot_" + IntegerToString(i) + "_down", level - smallQuarter, OvershootColor, OvershootLineWidth, OvershootLineStyle);
           }
        }
     }
   if(g_DrawSmallQuarters)
     {
      double segStep = MajorStep / 10.0;
      double smallQuarter = segStep / 4.0;
      for(int seg = 0; seg < 10; seg++)
        {
         double segStart = lowerMajor + seg * segStep;
         for(int j = 1; j < 4; j++)
           {
            double level = segStart + j * smallQuarter;
            string objName = "SmallQuarter_" + IntegerToString(seg) + "_" + IntegerToString(j);
            DrawHorizontalLine(objName, level, SmallQuarterColor, SmallQuarterLineWidth, SmallQuarterLineStyle);
           }
        }
     }
  }
//+------------------------------------------------------------------+


結果

このセクションでは、EAの動作結果とパフォーマンスを確認します。下のGIF図では、EAがどのように機能するかを視覚的に示しています。EAをEURUSDのチャートにドラッグすると、ボタン付きのパネルが表示されます。初期状態では、[Larger Quarter]ボタンと[Overshoot/Undershoot]ボタンは緑色のテキストで表示されており、これはこれらの機能が無効(非表示)であることを意味します。一方で、[Smaller Quarters]ボタンと[Trend Direction]ボタンは赤色のテキストとなっており、これらの機能が有効(表示中)であることを示しています。 各ボタンをクリックすることで、それに対応するレベルがチャートに表示されたり、非表示になったりするのが確認できます。特に注目すべき点は、[Trend Direction]ボタンを有効化すると、トレンド解説が[Uptrend]に更新され、現在の市場状況を正確に反映している点です。

Quarters Board

下図は、EAのテスト結果を視覚的にわかりやすく示した図です。チャート上には、青色の実線で描かれたラージクォーターのレベルと、赤色の点線で示されたオーバーシュート/アンダーシュートのレベルが表示されており、これらのレベルが有効化されていることが確認できます。これは、チャート上のラインと対応するボタンのテキスト色の両方から判断できます。さらに、トレンド方向の解説もチャート上に表示されており、この機能もアクティブであることがわかります。一方、[Small Quarters]ボタンは赤色で表示されており、これはそのレベルが無効(非表示)であることを示しています。



結論

この記事では、チャート上の必要なレベルをワンクリックでオン/オフできるパネル付きボタンの作成を目指して解説を進めてきましたが、その目的は無事に達成されました。これは、トレーダーのニーズに応じてクォーターレベルを柔軟に扱うための、さらなる一歩と言えるでしょう。この機能強化により、よりユーザーフレンドリーなインターフェイスが実現されました。たとえば、あるときはラージクォーターだけに集中したい場面があり、また別のときはすべてのレベルを表示したいという状況もあるでしょう。そのどちらにも簡単に対応できるようになっています。さらに、本ツールにはトレンド方向の分析機能も搭載されており、現在の価格に基づいた市場の実際の動向を把握する手助けとなります。

日付 ツール名  説明 バージョン  アップデート  備考
01/10/24 ChartProjector 前日のプライスアクションをゴースト効果でオーバーレイするスクリプト 1.0 初回リリース ツール番号1
18/11/24 Analytical Comment 前日の情報を表形式で提供し、市場の将来の方向性を予測する 1.0 初回リリース ツール番号2
27/11/24 Analytics Master 2時間ごとに市場指標を定期的に更新  1.01 v.2 ツール番号3
02/12/24 Analytics Forecaster  Telegram統合により、2時間ごとに市場指標を定期的に更新 1.1 v.3 ツール番号4
09/12/24 Volatility Navigator ボリンジャーバンド、RSI、ATR指標を使用して市場の状況を分析するEA 1.0 初回リリース ツール番号5
19/12/24 Mean Reversion Signal Reaper  平均回帰戦略を用いて市場を分析し、シグナルを提供する  1.0  初回リリース  ツール番号6 
9/01/25  Signal Pulse  多時間枠分析ツール 1.0  初回リリース  ツール番号7 
17/01/25  Metrics Board  分析用のボタン付きパネル  1.0  初回リリース ツール番号8 
21/01/25 External Flow 外部ライブラリによる分析 1.0  初回リリース ツール番号9 
27/01/25 VWAP 出来高加重平均価格   1.3  初回リリース  ツール番号10 
02/02/25  Heikin Ashi  トレンドの平滑化と反転シグナルの識別  1.0  初回リリース  ツール番号11
04/02/25  FibVWAP  Python分析によるシグナル生成  1.0  初回リリース  ツール番号12
14/02/25  RSI DIVERGENCE  プライスアクションとRSIのダイバージェンス  1.0  初回リリース  ツール番号13 
17/02/25  Parabolic Stop and Reverse (PSAR)  PSAR戦略の自動化 1.0 初回リリース  ツール番号14
20/02/25  Quarters Drawerスクリプト チャートにクォーターレベルを描く  1.0  初回リリース  ツール番号15 
27/02/25  Intrusion Detector 価格がクォーターレベルに達したときに検出して警告する 1.0   初回リリース ツール番号16 
27/02/25  TrendLoom Tool  多時間枠分析パネル 1.0 初回リリース ツール番号17
11/03/25  Quarters Board  クォーターレベルを有効または無効にするボタン付きのパネル  1.0  初回リリース ツール番号18

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

添付されたファイル |
Quarters_Board.mq5 (14.84 KB)
データサイエンスとML(第35回):MQL5でのNumPy活用術 - 少ないコードで複雑なアルゴリズムを構築する技法 データサイエンスとML(第35回):MQL5でのNumPy活用術 - 少ないコードで複雑なアルゴリズムを構築する技法
NumPyライブラリは、Pythonプログラミング言語においてほぼすべての機械学習アルゴリズムの中核を支えています。本記事では、高度なモデルやアルゴリズムの構築を支援するために、複雑なコードをまとめたモジュールを実装していきます。
ダーバスボックスブレイクアウト戦略における高度な機械学習技術の探究 ダーバスボックスブレイクアウト戦略における高度な機械学習技術の探究
ニコラス・ダーバスによって考案された「ダーバスボックスブレイクアウト戦略」は、株価が一定の「ボックス」レンジを上抜けたときに強い上昇モメンタムが示唆されることから、買いシグナルを見極めるためのテクニカル取引手法です。本記事では、この戦略コンセプトを例として用い、機械学習の3つの高度な技術を探っていきます。それは、取引をフィルタリングするのではなくシグナルを生成するために機械学習モデルを使用すること、離散的ではなく連続的なシグナルを用いること、異なる時間枠で学習されたモデルを使って取引を確認すること、の3点です。
MQL5での取引戦略の自動化(第12回):Mitigation Order Blocks (MOB)戦略の実装 MQL5での取引戦略の自動化(第12回):Mitigation Order Blocks (MOB)戦略の実装
本記事では、スマートマネー取引向けにオーダーブロックの自動検出をおこなうMQL5取引システムを構築します。戦略のルールを明確にし、そのロジックをMQL5で実装し、さらに取引を効果的に執行するためにリスク管理も統合します。最後に、システムのパフォーマンスを評価するためにバックテストをおこない、最適な結果を得るための改良を加えます。
知っておくべきMQL5ウィザードのテクニック(第57回):移動平均とストキャスティクスを用いた教師あり学習 知っておくべきMQL5ウィザードのテクニック(第57回):移動平均とストキャスティクスを用いた教師あり学習
移動平均線やストキャスティクスは非常に一般的なテクニカル指標ですが、その「遅行性」のために一部のトレーダーから敬遠されがちです。この3部構成のミニシリーズでは、機械学習の3つの主要なアプローチを軸に、この偏見が本当に正当なものなのか、それとも実はこれらの指標に優位性が隠れているのかを検証していきます。検証には、ウィザードで組み立てられたエキスパートアドバイザー(EA)を用います。