プライスアクション分析ツールキットの開発(第45回):MQL5で動的水準分析パネルを作成する
内容
はじめに
連載第40回では、統計学を用いて価格の振る舞いの裏にある論理を明らかにし、市場の平均値、最頻値、中央値がどの価格帯に集まりやすいかを検証しました。この分析を通じて、市場は見た目ほど混沌としておらず、価格は統計的に意味のある水準の周辺で回転し、間接的にオーダーフローへ影響を与えていることが分かりました。
前回の分析の目的は、こうした統計的な価格水準を特定し、価格がその水準に反応する頻度や反発する頻度を観察することでした。この分析により、「ある価格に統計的な重みがある場合、事前に指定した任意の水準に対して、市場が過去にどのように反応してきたかを定量的に測定できるのではないか」という、より深い問いが生まれました。
本記事では、このコンセプトをさらに一歩進め、任意の価格水準をその場でテストできる自動分析アシスタント「Price Level Testing EA」を紹介します。トレーダーが価格水準を指定すると、このEAは過去の数百〜数千本のローソク足を即座に分析し、その水準に対する価格の反応を客観的な形で提示します。この結果、過去にその水準で発生したタッチ、反発、ブレイクアウトの実証的パターンを明らかにする、「自分専用のプライスアクションラボ」のようなツールとして機能します。
統計的検証が重要な理由
チャートを目視で分析する際、ほとんどのトレーダーは直感的にラインを引きます。急激な反転ポイント、ローソク足のヒゲが集中した箇所、あるいは過去の高値といった繰り返し現れる水準を目で認識し、脳でそれをサポートかレジスタンスかと判断します。この直感的なスキルは価値がありますが、次の2つの落とし穴にも弱いのです。
- 直近バイアス:直近の値動きに過剰に重みを置き、長期的な頻度を無視してしまう
- 確証バイアス:水準が機能した場合は覚えていても、機能しなかった場合を忘れてしまう
バックテストなしに手作業で引いたラインは、あくまで意見に過ぎません。Price Level Testing EAが提供するのは、客観的な証拠です。視覚的な印象を測定可能なデータに変換します。
- この水準は実際にどのタイミングで障壁として機能したのか
- 価格はどのくらいの頻度でその水準を突破したのか
- 上から接近したのか、下から接近したのか、どちらが多かったのか
EAが解決する2つの核心的な問題
問題1:水準の強さを直感で判断してしまうこと
「ここは強いレジスタンス…だと思う。」
- 典型的なトレーダーのシナリオ
EURUSDが数週間の間に1.2000水準で2度反発したのを観察したとします。長い上ヒゲ、強い売り圧力、明確なパターン認識と、説得力があるように見えます。あなたは1.2000を主要なレジスタンスと判断し、次の取引計画を立てます。数週間後、価格が再び1.2000に向かって上昇し始めました。あなたは迷います。 「今回は持ちこたえるだろうか。1.2000は本当に強かったのか、それとも前回はたまたま価格が反転しただけなのか。」
記憶だけでは答えられません。なぜなら、記憶はほんの数例しか思い出せないからです。統計がなければ、過去にその水準がどのくらいの頻度でタッチされたか、あるいはブレイクされたかはわかりません。
EAが解決する方法
ダッシュボードに「1.2000」と入力して[Analyze]をクリックするだけです。数秒以内にEAは過去のデータをスキャンし、次の情報を報告します。- その水準付近で価格が反転した回数(タッチ数)
- 価格が明確に突破した回数(クリーンブレイクアウト数)
- その水準が過去にサポートとして機能したか、レジスタンスとして機能したかの傾向(最も重要)
これにより、目視の記憶や直感に頼る必要がなくなります。1.2000の統計的プロファイルが数値として示され、データに基づいた客観的な判断が可能になります。この情報をもとに、次の取引をより合理的に計画できるようになります。
問題2 – 市場方向性やブレイクアウトの信頼性を誤判断してしまうこと
「価格が水準を突破したけど、本物のブレイクアウト?それともただのノイズ?」
- よくある課題
XAUUSD(ゴールド)が1950.00付近で取引されているとします。勢いのあるローソク足がこの水準を上抜けると、トレーダーは興奮し、「強気のブレイクアウトだ」と飛びつきます。しかし、2時間後にローソク足が崩れ、価格は1950を下回り、ストップロスが次々にヒットします。これは本当のモメンタムだったのか、それとも金特有のボラティリティによる偽ブレイクアウトだったのか。
もし事前に1950の統計的な挙動を確認していれば、その答えはすでにわかっていたかもしれません。
EAが解決する方法
1950.00を入力して[Analyze]をクリックすると、EAは瞬時に過去データを解析し、次の情報を提供します。
- 1950を上抜けた強気ブレイクアウトのうち、どれだけが継続して上昇したか
- 偽ブレイクアウトで素早く反転した回数
- 1950が価格が集中しやすい水準として機能した回数(頻繁にタッチ)と、障壁として機能した回数(鋭く反発)
これらの指標をもとに、1950が価格を引き寄せやすいか、反発させやすいかを明確に把握できます。不確実性を数値化された期待値に変換することで、規律あるトレーダーやアルゴリズム取引システムにとって一貫して有益な、確率的洞察を得ることができます。
例:1.34244水準の手動分析(GBP/USD H1、2025年4月〜10月)
以下に示す期間において、Price Level Testing EAはGBP/USDのH1チャート上で1.34244という価格水準に対する複数回の相互作用を検出しました。価格は何度もこの水準に接近し、設定された許容範囲内でタッチしましたが、上方向への明確なブレイクアウトを達成することはできませんでした。いずれの試行も、その後は下方向への反転に終わっており、この水準が一貫して売り手によって防衛されていたことを示しています。
このように、決定的な突破を伴わない反復的なタッチが見られる場合、その期間において1.34244はサポートではなく、短期的なレジスタンスとして機能していたと解釈できます。

一方、2025年9月30日から10月9日にかけては、市場は数セッションにわたり1.34244を上回る水準で推移し、この価格帯を一時的なサポートとして利用していました。 価格は上方からこの水準を何度もリテストし、当初は維持に成功しており、短期的な安定性が確認されていました。しかし、時間の経過とともに買い圧力は弱まり、最終的に1.34244を明確に下抜ける局面が訪れます。 ローソク足は水準下で確定し始め、その後は下方向への明確な継続的動きが確認されました。 この挙動は、サポートが崩壊し、役割が反転したことを示しています。その後に価格がこの水準を再び試した際、1.34244は新たなレジスタンスとして機能し、上昇を抑える天井となりました。
構造的な観点から見ると、これはいわゆる「サポートからレジスタンスへの転換」であり、モメンタムが売り手側へ移行したことを示す代表的なシグナルの一つです。 かつて下落を食い止めていた水準が、今度は上昇を抑える障壁となり、接近するたびに需要ではなく供給を引き寄せるようになります。
このような反転現象が、過去の月に見られたものと同様に異なる時点でも繰り返し観測される場合、それは特定の価格水準を中心に市場心理がどのように変化していくかを示しています。 こうした変化を手動で検証することで、タッチ回数やブレイクアウトを体系的に数値化することの重要性が明確になります。客観的なデータは、視覚的な分析が示唆する内容を裏付けてくれるのです。

直感から証拠へ
すべてのトレーダーは、価格が引き寄せられたり、反発したりするように見える水準に対して、自然と「感覚」を身につけていきます。経験を重ねることでそうした印象は洗練されていきますが、直感だけでは裏付けに欠ける場合も少なくありません。Price Level Testing EAは、その直感を形式知へと変換するためのツールです。 「この水準は重要そうだ」という感覚を、検証可能な定量データへと落とし込みます。
一見すると、このEAは驚くほど単純に見えます。価格水準を入力し、[Analyze]を押すだけで、直近の履歴を調べてくれます。しかし、その背後では、数百本に及ぶ過去のローソク足を対象に、価格がその水準とどのように相互作用してきたかを測定する、完全な分析フレームワークが稼働しています。処理は数秒で完了し、次のような具体的な結果が返されます。
- 価格が上下いずれの方向からタッチしたかに基づく、強気と弱気それぞれのタッチ回数
- 明確なブレイクアウトが発生した回数、すなわち価格が決定的に水準を突破した事例の数
- それらの事象に基づいて算出された、方向性の偏りを示す確率
- そして最終的に、その水準がサポート、レジスタンス、あるいはニュートラルのいずれとして機能してきたかを示す総合的なバイアス判定
これまでであれば、チャートを何度もスクロールし、主観的な判断を積み重ねなければ得られなかった情報が、今では自動かつ偏りのない形で処理されます。トレーダーの役割は、単に重要そうな水準を見つけることから、その水準が統計的に意味を持つかどうかを検証する段階へと進化します。
客観的なイベント分類
このEAでは、すべての「タッチ」および「ブレイクアウト」が、時間軸や銘柄に依存せず、一貫した基準で判定されるよう、明確なルールが採用されています。これにより、分析結果に主観や恣意性が入り込む余地を排除しています。
1. タッチの識別
タッチとは、価格が水準に近づき、到達はするものの、明確にその水準を越えて終値で抜けない、いわば「抑制されたテスト」を指します。ランダムな値動きやノイズを除外するために、EAはTouchPipsという許容幅を設定します。これは指定した価格水準の上下に対して、pips単位で定義される許容範囲です。あるローソク足において、
High ≥ Level − (TouchPips × pip) AND Low ≤ Level + (TouchPips × pip)
であれば、その足はタッチイベントとして記録されます。その後、終値の位置によって方向性が分類されます。
- 強気タッチ:ローソク足の終値が水準の上でクローズした場合。買い手がその水準をサポートとして防衛したことを示す。
- 弱気タッチ:ローソク足の終値が水準の下でクローズした場合。レジスタンスとして拒否されたことを示す。
この区別により、過去において市場のどちら側がその価格帯をより頻繁に尊重してきたかではなく、どちらの方向から反応してきたかを定量的に把握することが可能になります。
2. ブレイクアウトの判定
ブレイクアウトは、終値が定義されたマージンBreakPipsを超えて水準を抜けた場合にのみ確認されます。これにより、一時的なスパイクは除外されます。
強気ブレイクアウト:直前のローソク足が水準の下でクローズし、現在のローソク足が水準をBreakPips分以上上回って確定した場合。
PrevClose<LevelANDClose>Level+(BreakPips×pip) 弱気ブレイクアウト:直前のローソク足が水準の上でクローズし、現在のローソク足が水準をBreakPips分以上下回って確定した場合。
PrevClose>LevelANDClose<Level−(BreakPips×pip)
終値と閾値による変位を用いることで、瞬間的なボラティリティではなく、市場構造の変化を評価する実務的な分析手法を再現しています。
カウントから経験的確率へ
BarsToCheck内のすべてのローソク足が検査された後、EAは結果を以下の4つの生データとして集計します。
| イベント種別 | 強気 | 弱気 |
|---|---|---|
| タッチ | bull_touch | bear_touch |
| ブレイクアウト | bull_break | bear_break |
これらのカウントは、選択された過去データサンプルにおける出現頻度という、経験的確率へと変換されます。
経験的確率
- 強気タッチの確率
![]()
- 弱気タッチの確率
![]()
これらは予測値や理論値ではなく、選択された期間において市場が実際に示した行動を直接反映したものです。
最後に、全体的なバイアスが以下のように推定されます。
- 強気タッチおよび強気ブレイクアウトの確率がともに優勢な場合:その水準は主にサポート(強気)として機能してきた
- 弱気の指標が両方とも優勢な場合:その水準はレジスタンス(弱気)として機能してきた
- いずれの側も決定的でない場合:その水準はニュートラルと判断される
この解釈は、数値データの精密さと、古典的なサポート・レジスタンス分析の直感を融合させたものです。
MQL5での実装
1. メタデータとユーザー入力
まず、スクリプトの先頭でEAのメタデータを定義します。これには、EAの名称( Price Level Testing EA)、著作権情報、そして作者のMQL5プロフィールへのリンクが含まれます。これらの行はEAの機能そのものには影響しませんが、EAの識別や出所を明確にするために役立ちます。続いて、#propertyディレクティブを使用して、バージョン番号、著作権参照、そしてstrictコンパイルモードを設定します。strictモードを有効にすることで、厳密な型チェックが強制され、より安全で堅牢なコードを書くことが可能になります。
#property copyright "https://www.mql5.com/ja/users/lynnchris" #property version "1.0" #property strict input int BarsToCheck = 500; input double TouchPips = 10; input double BreakPips = 20; input color TextColor = clrYellow;
次に、EAの動作をユーザーがカスタマイズできるようにするための入力パラメータを定義します。ここでは、分析対象とする過去のローソク足の本数(BarsToCheck)、価格が水準にどれだけ近づけば「タッチ」と判定するか(TouchPips)、そしてその水準をどれだけ超えれば「ブレイクアウト」と見なすか(BreakPips)を指定します。また、出力テキストの色(TextColor)をユーザーが選択できるように設定します。これらの入力項目により、分析の柔軟性と制御性が確保され、異なる通貨ペア、時間足、あるいは取引戦略に応じてEAの挙動を調整することが可能となります。
2. UI定数とレイアウト構造の定義
次に、#defineディレクティブを用いて一連の定数を設定します。これらの定数は、後ほどチャート上に表示するユーザーインターフェース(UI)要素を管理し整理するために役立ちます。たとえば、テキスト入力フィールド用のEDIT_NAME、分析ボタン用のBTN_NAME、マーカー用のMARK_PREFIXといったように、各オブジェクトに固有の名前や接頭辞を与えることで、スクリプト全体を通じてそれらを容易に参照し、管理できるようになります。これは、UIオブジェクトを動的に削除したり更新したりする必要がある場合に特に有用です。
#define EDIT_NAME "UI_EDIT_LEVEL" #define BTN_NAME "UI_BTN_ANALYZE" #define BOX_NAME "UI_BOX" #define HDR_NAME "UI_HDR" #define INSTR_NAME "UI_INSTR" #define MARK_PREFIX "AN_" #define LINE_PREFIX "UI_LINE_" #define UI_CORNER CORNER_LEFT_UPPER int ui_base_x = 6; int ui_base_y = 18; int ui_row_spacing = 17; int ui_font_size = 9;
また、ui_base_xやui_base_yといったレイアウト関連の変数も定義し、UI要素を画面上のどの位置に配置するかを決定します。これは、すべてのUIコンポーネントを配置するための土台を作る作業と考えることができます。行間の間隔を制御するui_row_spacingや、フォントサイズを指定するui_font_sizeによって、UIの可読性や整列具合を細かく調整することができます。これらの定数とレイアウト設定を整えることで、見た目が整理され、実務での使用を想定した一貫性のあるインターフェースを構築する準備が整います。
3. OnInit()内でのユーザーインターフェース構築
UI構造の定義が完了したら、次にOnInit()関数へと進みます。OnInit()は、EAがチャートに最初に追加された際に実行される関数です。ここでは、ユーザーが操作することになるグラフィカル要素の作成を開始します。まず、ObjectCreate()を使用して編集可能なテキストフィールドを作成し、EDIT_NAME定数で定義された名前を付けます。その後、適切なサイズ、フォントサイズ、色を設定することで、機能的で視覚的にも使いやすいデザインに仕上げます。この入力ボックスは、ユーザーが分析したい価格水準を入力するためのものです。
SafeDeleteObj(EDIT_NAME); ObjectCreate(0, EDIT_NAME, OBJ_EDIT, 0, 0, 0); ObjectSetInteger(0, EDIT_NAME, OBJPROP_CORNER, UI_CORNER); ObjectSetInteger(0, EDIT_NAME, OBJPROP_XDISTANCE, ui_base_x); ObjectSetInteger(0, EDIT_NAME, OBJPROP_YDISTANCE, ui_base_y); ObjectSetInteger(0, EDIT_NAME, OBJPROP_XSIZE, 100); ObjectSetInteger(0, EDIT_NAME, OBJPROP_BGCOLOR, clrBlack); ObjectSetInteger(0, EDIT_NAME, OBJPROP_COLOR, clrLime); ObjectSetInteger(0, EDIT_NAME, OBJPROP_FONTSIZE, ui_font_size); ObjectSetString(0, EDIT_NAME, OBJPROP_TEXT, "1.2000");
次に、入力フィールドのすぐ隣に[Analyze]とラベルされたボタンを配置します。このボタンをクリックすると、分析が実行されます。レイアウト用の定数を使って慎重に位置を決め、入力フィールドと揃うように配置します。その後、「Press Analyze」とユーザーに操作を促すラベルをボタンの右側に追加します。最後に、ヘッダ用のラベルとして「Touch & Breakout Stats」というタイトルを表示し、インターフェース全体の文脈を示します。OnInit()が終了する時点で、シンプルでありながらユーザーが数クリックで分析を開始できるインタラクティブなUIが完成しています。
4. OnDeinit()によるクリーンアップ
インターフェースを設定した後は、クリーンアップの準備もおこないます。OnDeinit()関数は、EAをチャートから削除した場合やリロードした場合に実行されます。このステップでは、EAが作成したすべてのオブジェクトを削除し、チャートをきれいで整理された状態に保ちます。DeletePrefixObjects()を適切な接頭辞とともに呼び出すことで、分析中に動的に作成されたすべてのマーカーやラベルを削除します。
void OnDeinit(const int reason) { DeletePrefixObjects(MARK_PREFIX); DeletePrefixObjects(LINE_PREFIX); SafeDeleteObj(EDIT_NAME); SafeDeleteObj(BTN_NAME); SafeDeleteObj(BOX_NAME); SafeDeleteObj(HDR_NAME); SafeDeleteObj(INSTR_NAME); }
次に、SafeDeleteObj()を使用して、入力ボックス、ボタン、ヘッダ、操作ラベル、背景ボックスなどの静的なUI要素を個別に削除します。これにより、チャート上に不要なオブジェクトを残さないようにします。クリーンアップを適切におこなうことで、ユーザーがEAを再読み込みしたり削除したりする際に、他のツールやインジケーターに影響を与えるグラフィカルな残留物を心配せずに済むようになります。
5. OnChartEvent()でのユーザー操作への対応
UIが整い、クリーンアップの手順も準備できたら、次にユーザーがチャート上で操作したときのEAの反応を定義します。OnChartEvent()関数は、マウスクリックなどのイベントを監視します。具体的には、クリックされたオブジェクトの名前をBTN_NAMEと比較し、[Analyze]ボタンが押されたかどうかを確認します。
void OnChartEvent(const int id,const long &l,const double &d,const string &s) { if(id==CHARTEVENT_OBJECT_CLICK && s==BTN_NAME) { string textlevel = ObjectGetString(0, EDIT_NAME, OBJPROP_TEXT); double level = StringToDouble(textlevel); if(level <= 0) { Alert("Enter numeric level"); return; } DeletePrefixObjects(MARK_PREFIX); DeletePrefixObjects(LINE_PREFIX); RunAnalysis(level); } }
ボタンがクリックされると、まず入力フィールドからテキストの値を取得し、StringToDouble()を使って数値に変換します。その後、その値が0より大きいかどうかを検証します。値が無効な場合は、ユーザーに有効な数値の水準を入力するようアラートを表示します。値が有効であれば、DeletePrefixObjects()を使って以前のマーカーや分析結果をすべてクリアします。最後に、ユーザーが指定した水準を引数としてRunAnalysisを呼び出し、核心となる分析を開始します。このステップにより、ユーザーの入力を実際の処理に変換し、有意義なデータ可視化の準備が整います。
6. RunAnalysis()での分析準備
RunAnalysis()関数に入ったら、まず必要な変数と閾値の準備をおこないます。現在の銘柄の桁数に基づいてpipの値を計算し、これによって「タッチ」や「ブレイクアウト」と見なす正確な閾値を定義します。その後、利用可能な履歴内で安全に分析できるローソク足の数を確認し、解析可能な範囲を決定します。
double point = SymbolInfoDouble(_Symbol,SYMBOL_POINT); double pip = (SymbolInfoInteger(_Symbol,SYMBOL_DIGITS) > 3 ? 0.0001 : 0.01); double touch_th = TouchPips * pip; double break_th = BreakPips * pip;
また、4種類のイベントをカウントするためのカウンタも初期化します。具体的には、強気タッチ(価格が水準を下からタッチした場合)、弱気タッチ(上からタッチした場合)、強気ブレイクアウト(価格が水準を上抜けした場合)、弱気ブレイクアウト(価格が水準を下抜けした場合)の4種類です。これらのカウンタは、各ローソク足を順にスキャンする際にデータを蓄積し、指定された水準に対して価格が過去にどのように反応してきたかを把握するためのスナップショットを提供します。
7. 過去のローソク足のスキャンによるイベント検出
次に、過去の各ローソク足をスキャンしてタッチやブレイクアウトを検出する核心ループに入ります。各ローソク足について、高値、安値、終値、前回の終値、そして時間を取得します。その後、高値と安値がタッチの閾値内で水準と交差しているかを確認します。交差している場合はタッチとして分類し、終値に基づいてその方向を判定します。
for(int i=0; i<bars_to_check; i++) { double hi = iHigh(_Symbol,_Period,i); double lo = iLow(_Symbol,_Period,i); double cl = iClose(_Symbol,_Period,i); double prev = iClose(_Symbol,_Period,i+1); datetime t = iTime(_Symbol,_Period,i); if(hi >= level - touch_th && lo <= level + touch_th) { if(cl < level) bull_touch++, DrawMarker(MARK_PREFIX+"T_BU_"+string(i), t, level + 5*point, clrLime, 241); else if(cl > level) bear_touch++, DrawMarker(MARK_PREFIX+"T_BE_"+string(i), t, level - 5*point, clrRed, 242); } if(prev < level && cl > level + break_th) bull_break++, DrawMarker(MARK_PREFIX+"B_BU_"+string(i), t, cl + 10*point, clrLime, 217); if(prev > level && cl < level - break_th) bear_break++, DrawMarker(MARK_PREFIX+"B_BE_"+string(i), t, cl - 10*point, clrRed, 218); }
終値が水準の下にある場合、それは強気タッチとなり、カウンターを増加させるとともにDrawMarker()を呼び出してチャート上に緑の矢印を表示します。終値が水準の上にある場合は弱気タッチとなり、赤の矢印でマーキングします。ブレイクアウトについても同様の判定をおこないます。前回の終値が水準の下で、今回の終値がBreakPipsに基づき十分上回っている場合は強気ブレイクアウトです。逆の場合は弱気ブレイクアウトとなります。各ブレイクアウトもチャート上に視覚的にマーキングされ、パターンを一目で把握できるようにします。
8. 統計計算と市場バイアスの判定
すべてのローソク足をスキャンした後、タッチとブレイクアウトの合計を計算し、それぞれのカテゴリで強気と弱気の発生割合を算出します。これらの統計により、価格が水準に対して過去どのように反応してきたかを把握できます。また、イベントが存在しない場合でもエラーが発生しないよう、安全な除算を使用して計算します。
double tot_touch = (double)(bull_touch + bear_touch); double tot_break = (double)(bull_break + bear_break); double pBT = (tot_touch > 0.0 ? 100.0 * bull_touch / tot_touch : 0.0); double pRT = (tot_touch > 0.0 ? 100.0 * bear_touch / tot_touch : 0.0); double pBB = (tot_break > 0.0 ? 100.0 * bull_break / tot_break : 0.0); double pRB = (tot_break > 0.0 ? 100.0 * bear_break / tot_break : 0.0); string bias = "Neutral"; if(pBT > pRT && pBB > pRB) bias = "Support (Bullish)"; else if(pRT > pBT && pRB > pBB) bias = "Resistance (Bearish)";
強気または弱気の活動が優勢かどうかに基づき、全体的なバイアスを判定します。強気のタッチとブレイクアウトが優勢な場合は、その水準を「Support (Bullish)」とラベル付けします。弱気のイベントが優勢な場合は「Resistance (Bearish)」となります。どちらも明確に優勢でない場合は「Neutral」と分類します。これにより、トレーダーはその水準が市場で底(サポート)や天井(レジスタンス)として機能する可能性を迅速に判断できます。
9. 結果パネルの作成
統計が準備できたら、チャート上に結果を表示するためのサマリーパネルを作成します。文字列の配列を使用し、各要素がパネル内の1行を表します。このパネルには、銘柄名、時間足、テストした水準、タッチとブレイクアウトの回数、それぞれの割合、そして全体的なバイアスといった情報が含まれます。
ArrayResize(lines, 7); lines[0] = StringFormat("Symbol: %s TF: %s", _Symbol, EnumToString(_Period)); lines[1] = StringFormat("Level: %.*f Bars Checked: %d", (int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS), level, bars_to_check); lines[2] = " "; lines[3] = StringFormat("Touches ↑ %3d ↓ %3d P↑ %4.1f%% P↓ %4.1f%%", bull_touch, bear_touch, pBT, pRT); lines[4] = StringFormat("Breaks ↑ %3d ↓ %3d P↑ %4.1f%% P↓ %4.1f%%", bull_break, bear_break, pBB, pRB); lines[5] = " "; lines[6] = StringFormat("Overall Bias: %s", bias);
パネルのサイズを正しく設定するために、文字列の最大行長を計算します。これにより、テキストが背景ボックス内できれいに収まり、重なったり切れたりすることを防ぎます。コンテンツを動的に構築することで、パネルは柔軟性を保ち、異なる入力値や銘柄にも対応できるようになります。
10. チャート上への視覚的出力の描画
新しいパネルを描画する前に、既存の出力をすべて削除し、チャートを整理します。その後、分析結果の背景ボックスとして使用する矩形ラベルオブジェクトを作成します。サイズは前述の計算に基づき、入力UIの下に配置します。
ObjectCreate(0, BOX_NAME, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, BOX_NAME, OBJPROP_XDISTANCE, baseX - 6); ObjectSetInteger(0, BOX_NAME, OBJPROP_YDISTANCE, baseY - 8); ObjectSetInteger(0, BOX_NAME, OBJPROP_XSIZE, boxWidth + 12); ObjectSetInteger(0, BOX_NAME, OBJPROP_YSIZE, boxHeight + 12); ObjectSetInteger(0, BOX_NAME, OBJPROP_BGCOLOR, clrDarkSlateGray); for(int i=0; i<7; i++) { string nm = LINE_PREFIX + IntegerToString(i); ObjectCreate(0, nm, OBJ_LABEL, 0, 0, 0); ObjectSetString(0, nm, OBJPROP_TEXT, lines[i]); }
次に、結果行の配列をループ処理し、各行ごとに個別のラベルを作成します。最初の数行は白色でスタイルを設定し、ヘッダのように見えるようにします。残りの行はユーザーが指定したTextColorを使用します。各ラベルは慎重に配置され、縦に整列したきれいなパネルを作成します。この出力により、トレーダーはチャート上で分析の概要を一目で確認でき、使いやすさと意思決定の質が向上します。
11. ターミナルへのレポート出力
チャート上に結果を表示するだけでなく、Print()を使ってレポート全体をターミナルにも出力します。これにより、ユーザーはMetaTraderの[エキスパート]や[操作ログ]タブで分析を確認できます。また、恒久的なログとしても残るため、複数の水準を追跡したり、デバッグしたり、長期間にわたる分析に活用できます。視覚的出力とテキスト出力の両方を提供することで、ユーザーの好みに応じた確認が可能となり、情報が失われることも防ぎます。
string report = ""; for(int i=0; i<ArraySize(lines); i++) { report += lines[i]; if(i < ArraySize(lines)-1) report += "\n"; } Print(report);
12. DrawMarker()によるマーカー描画
このユーティリティ関数は、タッチやブレイクアウトを検出した際にチャート上に視覚的なマーカーを配置するために使用します。まず、同じ名前のマーカーが既に存在するかを確認し、重複を避けるために削除します。その後、指定された時間と価格に新しいOBJ_ARROWオブジェクトを作成し、適切な色と矢印コードでスタイルを設定します。
void DrawMarker(string name, datetime t, double price, color clr, int arrow) { if(ObjectFind(0, name) >= 0) ObjectDelete(0, name); ObjectCreate(0, name, OBJ_ARROW, 0, t, price); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_ARROWCODE, arrow); }
これらのマーカーは、価格が水準とどの位置で接触したかを示す視覚的な目印として機能します。これにより、トレーダーは統計データと実際の価格変動やローソク足を簡単に対応させることができ、分析結果を視覚的に強化する効果があります。
13. SafeDeleteObj()によるオブジェクトの安全な削除
このヘルパー関数は、指定された名前のチャートオブジェクトが存在するかを確認し、存在する場合に削除します。存在しないオブジェクトを削除しようとして発生するエラーを防ぎ、UIやマーカーの管理を安全におこなうことができます。この関数はEA全体で繰り返し使用され、古いオブジェクトを削除してから新しいオブジェクトを作成する際に活用されます。
void SafeDeleteObj(string name) { if(ObjectFind(0, name) >= 0) ObjectDelete(0, name); }
14. DeletePrefixObjects()による接頭辞単位のオブジェクト削除
最後に、DeletePrefixObjects()を使用して、共通の命名規則を持つオブジェクトのグループを削除します。これは、以前の分析で動的に作成されたマーカーやラベルを整理する際に特に有用です。チャート上のすべてのオブジェクトをループ処理し、特定のプレフィックスで始まるオブジェクトを特定することで、EAが作成したオブジェクトのみを削除し、他のチャート要素には影響を与えないようにします。これにより、操作の正確性が保たれ、関連のないオブジェクトの誤削除を防ぐことができます。
void DeletePrefixObjects(string prefix) { int total = ObjectsTotal(0); for(int i = total - 1; i >= 0; i--) { string nm = ObjectName(0, i); if(StringFind(nm, prefix) == 0) ObjectDelete(0, nm); } }
結果
このセクションでは、価格水準のテストとその結果の分析に焦点を当てます。 以下は、EAをMetaTrader 5のチャートにドラッグした後、任意の価格水準をテストする際の手順です。
1. 入力ボックスに正確な数値の価格を入力します。例:
- EURUSDの場合:1.2000
- ゴールドの場合:1950.25
- 指数の場合:80.50
チャートに表示されている小数点以下の桁数と同じ精度で入力することを必ず確認してください。
2. [Analyze]を押します。
- EAは設定された過去ローソク足数をスキャンし、その水準で発生したすべての歴史的なタッチおよびブレイクアウトをチャート上にマーキングします。また、ダッシュボードには行単位の統計として結果を表示します。
3. ダッシュボードで確認できる内容
- タッチの総数
- ブレイクアウトの総数
- 方向別の内訳(上昇/下降)
- 全体的な方向バイアス
チャート上には、タッチやブレイクアウトが発生した箇所に矢印マーカーが表示されます。これにより、選択した水準に対する価格の挙動を、統計的かつ視覚的に明確に把握できます。
- EURUSD H1のテスト

上のアニメーションは、Price Level Testing EAのフル機能を示しています。このデモでは、特定の価格水準がEAのオンチャートUIの入力欄に手動で入力されています。[Analyze]ボタンを押すと、システムは即座に水準テストのルーチンを開始します。瞬時に、選択した水準を過去データに対して評価し、結果をダッシュボードに自動表示します。同時に、チャートには各タッチ(価格が水準付近で反応した箇所)やブレイクアウト(決定的に水準を抜けた箇所)を示す矢印マーカーが動的に描画されます。これにより、統計上の各イベントを価格動作と直接照合することが可能です。
分析結果を見ると、この水準はニュートラルと分類されています。これは、テスト対象となったローソク足のサンプルにおいて、価格が強気と弱気の反応を均等に示したことを意味します。実務的には、観測期間中にこの水準が一貫してサポートまたはレジスタンスとして機能していなかったことを示しています。ニュートラルであること自体も有益な情報となり、過去に買い圧力と売り圧力がほぼ拮抗していた価格水準であることを示唆しています。
結論
Price Level Testing EAは、視覚的な直感と定量的な検証のギャップを埋めるツールであり、水準認識という「技」のプロセスを、実証的なテストに裏付けられた手法へと変換します。
これまでトレーダーがチャート上の印象だけに頼っていたところを、このツールは以下の機能でサポートします。
- 水準がサポートまたはレジスタンスとして機能した頻度を客観的に測定できること
- タッチやブレイクアウトをpipsベースの閾値で一貫して検証でき、解釈による偏りを排除できること
- 実際の市場挙動を表す経験的確率を提供できること
- イベントがいつどこで発生したかを正確に確認できる透明な視覚的記録が得られること
強気と弱気のタッチ、確認済みブレイクアウトの割合、方向バイアスなど、具体的な統計データを収集することで、EAは過去の価格動作を実践に活用可能な証拠に変換します。トレーダーは構造を単に観察するのではなく、定量的に把握できるようになります。このEAから得られる主要な洞察は、シンプルでありながらも非常に示唆に富んでいます。
過去の挙動は情報を持つ
過去に繰り返し価格が反応した水準は、市場構造において重要な意味を持つことを示しています。これを視覚的に捉えるだけでなく数値的に理解することで、より賢明な意思決定が可能になります。具体的には、トレード計画への自信向上、より効率的なバックテスト、客観的データを自動または裁量的なフレームワークに組み込む機会などが得られます。さらに、即時利用にとどまらず、このツールは新たな研究の道を開きます。出力結果を複数の銘柄や時間足で集計することで、水準の信頼性、市場のレジーム変化を研究したり、機械学習モデルに事実に基づく特徴量として組み込むことも可能です。
最終的に、Price Level Testing EAは単なる利便性のためのツールではなく、方法論的な転換をもたらします。トレーダーは経験則や直感に頼るだけでなく、データに基づいた市場構造の解釈へと進むことができるようになります。仮説は検証可能で、結果は再現可能となり、直感は証拠によって補強され、置き換えられるのではなく支えられるのです。
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/19842
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
MQL5入門(第23回):オープニングレンジブレイクアウト戦略の自動化
MQL5入門(第22回):5-0ハーモニックパターンを用いたエキスパートアドバイザーの構築
MQL5における二変量コピュラ(第1回):依存関係モデリングのための正規コピュラおよびtコピュラの実装
機械学習の限界を克服する(第5回):時系列交差検証の簡単な概要
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索