流動性狩りの最適化:流動性狩りと市場構造転換の違いを見極める
はじめに
本記事は、市場構造転換と流動性狩りの違いを判断することが難しく、その結果、いずれかが発生した際にどのようなトレードアクションを取るべきか判断に迷っているトレーダーを対象としています。私自身のこれまでの経験や、多くのトレーダーを見てきた中で、非常に多くのトレーダーが、市場構造転換や流動性狩りを活用する際に、経験やスキルの不足から誤った判断を下していることに気付きました。有効な流動性狩り(Liquidity Grab)や市場構造転換(Market Structure Shifts)を見極めるだけの知識や技術が十分でないため、誤ったシグナルを選択してしまい、その結果、短期間で損失やドローダウンにつながるケースが少なくありません。そして、そのことが「流動性狩りや市場構造転換という考え方は機能しない」といった根拠のない噂や議論を生み出す要因にもなっています。
本記事が大きな恩恵をもたらすもう一つの対象は、これらの概念についてある程度のスキルや経験を持ちながらも、結果にばらつきがあるトレーダーです。このようなトレーダーは、トレードセットアップの選択がうまくいくこともあれば、大きく失敗することもあります。本記事では、流動性狩りと市場構造転換の重要な違いを詳しく解説することで、読者の知識をさらに強化し、両者を混同することによって生じる損失を軽減することを目指します。また、流動性狩りと市場構造転換はいずれも、適切に活用すれば非常に有効で利益につながる手法であることを明確に示します。さらに、有効な市場構造転換または流動性狩りを識別する際に確認すべきチェックポイントについても説明します。トレーダーはこれらのチェックポイントを素早く参照することで、自身のトレード判断を確認でき、冷静さを保ちながら、衝動的なトレードや実行の迷いによる硬直化を避けることができるようになります。
私自身もトレーダーとして、ICTコンセプトを用いてトレードを行う初心者および中級者の多くが、この課題に直面していることを理解しています。実際のところ、すべてのトレーダーは、そのトレードキャリアのどこかの時点で、ほぼ同じ、あるいは非常によく似た課題に直面します。しかし、それぞれのトレーダーを分けるものは、その課題への対処方法、反応、そして事前の備え方です。その違いがトレード結果の差となって表れ、その差は、スキル、経験、冷静さ、意思決定能力、トレード技術がほぼ同等であるトレーダー同士であっても、非常に大きなものになることが証明されています。また、この課題は他のトレード手法では、例えば「ブレイクアウト」といった異なる名称で呼ばれている場合もあります。そのため、本記事はICTコンセプトを用いるトレーダーだけでなく、そのようなトレーダーにとっても有益な内容となります。
本記事では、流動性狩りを最適に識別し活用する方法を学びたいトレーダー向けに特別に設計されたEAについて詳しく解説します。流動性狩りは、トレンドと市場のシナリオが明確に定まっている状況において、トレンド方向へのトレードを行う際に優れたエントリー機会を提供することが多く、トレンドに逆らったトレードを避けるうえでも有効です。また、このEAは、市場構造転換も識別できるよう設計されています。市場構造転換は、トレンドの終盤や上位時間足における大きな反転局面など、市場の特定の重要なポイントで発生するため、本EAは流動性狩りと市場構造転換のいずれであるかを適切に識別し、それぞれが発生した際に適切なタイミングで実行できるよう最適化されています。これにより、実際には市場構造転換が発生しているにもかかわらず流動性狩りとしてトレードしてしまったり、逆に単なる流動性狩りであるにもかかわらず市場構造転換としてトレードしてしまったりすることを防ぐことができます。
このEAは、デイトレーダーや短期トレーダーにとっても非常に重要です。なぜなら、その日に最も発生する可能性が高いトレンド方向への値動きに沿ったトレードを支援することで、勝率の向上につながるためです。流動性狩りは、多くの通貨ペアでほぼ毎日のように発生し、同じ通貨ペアでも週に複数回発生することが少なくないためです。
定義:インバランス、市場構造転換、流動性狩り
この章では、本記事で使用・活用する主な用語や概念について定義と説明を行います。本記事をご覧になるすべての方がこれらの概念に精通しているとは限らず、中には初めて耳にする方もいらっしゃると思います。そのため、できるだけ多くの読者に理解していただけるよう、基本的な内容から説明していきます。
1. インバランス/非効率性
インバランス(非効率性)は、価格がいずれかの方向へ急速に動くことで形成されます。これは主に機関投資家による強い買い圧力または売り圧力を示しています。簡単に言えば、このような強い売買圧力が発生すると、市場参加者が平等に注文を出したり約定させたりする機会が失われることがあります。例えば、強い上昇によって価格が勢いよく高値方向へ動いた強気のインバランスでは、売り手は十分な時間や機会を得られずに取り残されます。一方、強い下落によって価格が勢いよく安値方向へ動いた弱気のインバランスでは、買い手は十分な時間や機会を得られません。このように、価格が一方向へ拡大した後、その反対方向への価格移動が存在しない価格帯は、アンバランス(不均衡)な価格帯と呼ばれます。
この現象は、塗装工の作業に例えると最も分かりやすく説明できます。塗装工が壁を塗るとき、均一に仕上げるためには反対方向にも同じように筆を入れる必要があります。この論理は価格にも当てはまります。たとえば、1.3010から1.3030まで強気のローソク足が勢いよく上昇し、その価格帯を突破した場合、本来であれば弱気のローソク足もその価格帯を通過することで価格のバランスが取られます。しかし、その動きが起こらなければ、その価格帯はインバランスとなります。多くの場合、価格は最終的にこのポイントに戻ってきます。この現象は、どの時間足でも発生する可能性があります。

2. 市場構造転換
市場構造転換とは、価格変化において、それまで一方向へ推移していた市場構造が別の方向へ転換する現象を指します。たとえば、価格が上昇トレンドにあり、高値と安値を切り上げ(Higher High、Higher Low)ながら推移していたとします。その後、価格が直近のHigher Lowを勢いよく下抜け、そのまま下落を続け、Lower LowとLower Highを形成し始めた場合、市場構造は強気から弱気へ転換したことになります。市場構造が有効であるためには、このような市場構造のブレイクと、それに伴う勢いと力強さを伴った価格変化が必要です。
また、市場構造転換が高い確率で機能し、単なるダマシの構造転換、Judas Swing、あるいは流動性狩りではないと判断するためには、価格が高い関心を集める価格帯、すなわち私たちが一般に「流動性」と呼ぶポイントから動き出している必要があります。特に、流動性狩りの後に発生する市場構造転換は、成功確率が非常に高いセットアップとなります。さらに、この現象はM1からMNまで、あらゆる時間足で発生します。

3.流動性狩り
流動性とは、機関投資家が以前に保有したロングまたはショートポジションを決済するため、あるいは新たなポジションを構築するための候補となる、高い関心を集める価格帯を指します。これらの価格帯が重要視される理由は、多くの個人トレーダーがストップロスを配置したり、ブレイクアウトを狙ってエントリーしたりするポイントであるためです。その結果、機関投資家が自身の注文を執行するために十分な流動性が供給されます。そのため、このような価格帯は流動性と呼ばれます。買いストップ注文、売りストップ注文、ストップロス注文が次々と執行されることで、新たに生まれた流動性を利用して機関投資家も自身の注文を執行します。この現象が「流動性狩り」と呼ばれる理由です。
このような流動性が集まりやすい価格帯は、ダブルボトム、ダブルトップ、ほぼ等しい高値や安値(Equal Highs/Equal Lows)、あるいは前日・前週・前月の高値・安値などによって特徴付けられます。これらの価格帯では常に流動性が形成されており、価格変動が大きく、市場の反応も強く現れます。そのため、優れたトレードエントリーの機会を数多く提供してくれます。

流動性狩りと市場構造転換がどのように発生するかの考察
このコンセプトを効果的に活用するための最も重要な最初のステップの一つは、トレンドの方向性と市場のシナリオを判断することです。本記事では、この点について重点的に解説します。これは本コンセプトを成功させるうえで非常に重要なステップであり、市場をどのように分析し、現在どのようなシナリオが展開されているのかを判断するための基礎となります。言い換えれば、現在のトレンドやシナリオを把握できなければ、このコンセプト全体は機能しません。
本記事およびエキスパートアドバイザー(EA)は、流動性狩りの後におこなうトレードをトレンドの方向と一致させることを支援し、トレンドに逆らった短期トレードを避けられるようにします。これにより、経験の浅いトレーダーでもトレードを実行する際の自信と判断力を高めることができ、最終的には、現在のトレンドとシナリオに沿った流動性狩りの後だけでトレードを行うべきであることを自然に理解できるようになります。そして、トレンドとシナリオの方向を判断するという課題を克服できれば、残る作業は、流動性狩りや市場構造転換の後に現れる適切なトレードセットアップを見つけることだけになります。
トレーダーが利益を上げる優れたトレード判断を行うためには、特にデイトレードや長期トレードにおいて、自身のポジションをトレンドの方向性と強さに対してどのように位置付けるかが極めて重要です。統計的にも、トレンドに逆らったトレードは短期的な値動きしか得られないことが繰り返し示されています。そのような値動きの多くは、大きなトレンド方向への動きが始まる前の単なる押し目や戻りに過ぎません。そのため、十分な注意を払わなければ大きな損失を抱えることになり、損切りを行わなければ、トレンド相場では価格が数日、場合によっては数週間にわたって一方向へ動き続けることもあるため、最終的には口座資金を失う結果になりかねません。
一方で、トレンドの強さと方向に沿ってエントリーしたトレードは、たとえエントリーポイントがあまり良くなかったとしても比較的許容されやすく、トレーダーが辛抱強く全体のトレンドが反転や流動性狩りの後に再開するのを待つことができれば、数百ドル、場合によっては数千ドルもの追加利益につながることもあります。
また、トレンド方向に基づいて分析、実行、管理された取引は、単に精度が高いだけでなく、より迅速に結果へ到達する傾向があります。さらにドローダウンも比較的小さく抑えられ、価格は目標水準へより速く到達しやすくなります。加えて、価格のスイングはより強力であるため、仮に一時的に含み損を抱えた場合でも、最終的にはトレンドの方向と強さに従って価格が再び動き、ドローダウンから回復する可能性が高くなります。
シナリオとトレンドを判断する最も効果的な方法は、主に週足(W1)と日足(D1)といった上位時間足を確認することです。EAが最初におこなう処理(これは手動でもおこなえます)は、単純移動平均線(SMA)と指数平滑移動平均線(EMA)を利用し、市場がトレンド相場なのか、それともレンジ相場なのかを明確に把握することです。トレンド相場は、より安全で質の高いトレード機会を提供します。トレンド相場は、9期間単純移動平均線が21期間移動平均線より上または下に位置し、なおかつ明確な上昇または下降の並びを形成している場合に判断できます。次に重要なのは、この2つの上位時間足における価格変化を確認し、価格がどこへ向かおうとしているのかを分析することです。これらの手順によって、現在のトレンドが強気なのか弱気なのかを比較的容易に判断することができます。
トレンドが確認され、価格がレンジ相場ではないことも確認できたら、次のステップは現在のシナリオ、すなわち価格が何を目指して動いているのかを把握することです。価格は常に、流動性、PDアレイ(PD Arrays)、またはインバランスのいずれかを目指して動いており、多くの場合、一つの流動性ポイントから次の流動性ポイントへ向かって推移します。ここで本EAの最も重要な役割が現れます。この点はぜひ覚えておいてください。前日の安値、前週の安値、前月の安値、あるいはEqual Lowsのような主要な流動性ポイントの流動性が取り込まれた場合、売りのシナリオはその目的を達成したと考えられるため、その地点では市場構造転換が発生する可能性を想定し始めます。この市場構造転換は、H1/H4/M15といったやや下位の時間足で発生する場合があり、それが新たな買いのシナリオの始まりとなります。つまり、次の流動性ポイントへ向かう買いが始まるということです。
本EAは、このような考え方に基づいて市場構造転換を追跡・予測し、トレードをおこないます。一方、流動性狩りを利用したトレードは、次のようなシンプルな方法で実行されます。現在のシナリオが明確に判断できたら、M15、M5、M1といった下位時間足へ分析対象を移します。これらの時間足はデイトレードに非常に適しており、ほぼ毎日のようにトレードセットアップを提供してくれます。
価格は基本的に次のような流れで動きます。まず、主要市場の取引時間帯という「時間」の要素によって値動きが形成されます。例えば、シナリオが強気であれば、直近安値でJudas Swingや流動性狩りが発生することがあります。流動性狩りとダマシのブレイクアウトが完了すると、価格はその価格帯から勢いよく離れていきます。この力強く素早い値動きは、それが実際に流動性狩りであったことを示す有力な判断材料となります。また、このような値動きの過程でインバランスが形成されることもあり、そのインバランスは新たなポジションへエントリーするための判断材料として利用できます。インバランスの出現は、流動性狩りが発生したことを示す非常に有力なシグナルでもあります。
要するに、本EAは、それぞれの状況が発生するたびにその内容を識別・評価し、その場で実際に何が起きているのかを判断したうえで、それが流動性狩りなのか、それとも市場構造転換なのかを判定します。そして、どちらのシナリオであるかを判断した後、それぞれのシナリオに対応したルールに従ってトレードを実行します。

MQL5におけるLiquidity Grab EAによるトレード判断の自動化
この戦略を自動化し、その動作を示し、実装するために、私は以下を作成しました。
- トレンドと市場のシナリオを分析し、流動性掃除の発生後にのみ、トレンドおよびシナリオの方向に沿ったトレードエントリーを実行するLiquidity Purge EAです。このEAには、トレーリングストップロス機能と移動平均線を組み込み、トレンドの検出を支援するようにしています。
意思決定プロセス
このEAは、トレンドの検出、流動性の検出、価格変化の判定、およびトレードの実行について、以下のロジックに基づいて意思決定を行います。
Liquidity Grab EAのソースコード
このEAは、全体のトレンド方向および市場のシナリオと一致する可能性のあるトレードシグナルを検出し、流動性掃除(Liquidity Purge)が発生した後にのみトレードセットアップを待機します。これにより、トレンドに逆らったポジションや、流動性掃除を伴わないポジションを回避します。また、指数平滑移動平均線(EMA)と単純移動平均線(SMA)を利用して市場全体のトレンド方向を判断し、それに基づいてトレードを実行します。さらに、トレーリングストップロスのロジックを適用し、価格が有利な方向へ推移した際にストップロス水準を調整して利益を保護するとともに、資金を守ります。加えて、1回のトレードあたり1%のリスクに制限するリスク管理機能も備えています。
入力パラメータ:取引設定のカスタマイズこのEAの入力パラメータにより、GBPJPY、GBPUSD、EURUSDの取引に合わせてコアコードを変更せずにEAの挙動を調整できます。LotSizeは0.1に設定されており、GBPペアの中程度のボラティリティ(1日100〜300 pips)を考慮した保守的なサイズです。LookbackBarsは3で、H1、H4、D1における直近高値/安値を特定する期間を定義し、応答性と信頼性のバランスを取る設計になっています。StopLossPipsは150、TakeProfitPipsは600に設定されており、GBPJPY、GBPUSD、EURUSDの典型的な値幅に合わせ、リスクリワード比1:4で流動性刈り取り後の強いトレンドを活用できるようになっています。TrailingStopPipsは100で、GBPJPYの急激な値動き中でも利益を確保します。EngulfingMinBodyRatioは0.3に設定されており、包み足の実体が前のローソク足に対して十分な大きさであることを確認し、弱いシグナルをフィルタリングします。
TradeTimeframeはH1、ConfirmationTimeframeはM15で、流動性刈り取りの検知および迅速なエントリー確認を可能にしています。MaxCandlesPostPurgeは3で、流動性刈り取り後の包み足シグナル検出の時間窓を制限し、遅すぎるエントリーを避けます。VolumeThresholdは1.0で、流動性確認のために出来高のスパイクを条件とし、GBPUSDのニュース相場で重要な役割を果たします。UseTrendFilterがtrueに設定され、SMAPeriodは50で、50期間のSMAを使用してより大きなトレンドに沿った取引をおこない、乱高下するGBP市場での誤ブレイクを減らすようになっています。
//+-------------------------------------------------------------------------------+ //| Liquidity GrabEA.mq5 | //| Expert Advisor for MetaTrader 5 | //| Description:Trades based on liquidity grabs and market structure shifts, waits| //| for trade set ups after liquidity grab, with flexible execution. | //+-------------------------------------------------------------------------------+ #property copyright "Eugene Mmene" #property link "https://www.EMcapital.com" #property version "1.10" //--- Input parameters input double LotSize = 0.05; // Lot size for trades input int LookbackBars = 1; // Number of bars to check for highs/lows input double StopLossPips = 20.0; // Stop loss in pips (adjusted for GOLD#) input double TakeProfitPips = 60.0; // Take profit in pips (adjusted for GOLD#) input double TrailingStopPips = 30.0; // Trailing stop in pips input double BreakevenPips = 20.0; // Move to BE after 30 pips profit input double EngulfingMinBodyRatio = 0.5; // Min body ratio for engulfing candle input ENUM_TIMEFRAMES TradeTimeframe = PERIOD_M15; // Primary timeframe for trading input ENUM_TIMEFRAMES ConfirmationTimeframe = PERIOD_M5; // Lower timeframe for engulfing input ENUM_TIMEFRAMES TrendTimeframe = PERIOD_H1; // Trend from H1 SMA input int MaxCandlesPostPurge = 5; // Max H1 candles to wait for engulfing input double VolumeThreshold = 1.2; // Volume multiplier for liquidity confirmation input bool UseTrendFilter = true; // Use SMA trend filter input int SMAPeriod = 50; // SMA period for trend filter
OnInit関数:堅牢な取引のためのセットアップと検証
OnInit関数は、EAがチャートに読み込まれた際に一度だけ実行され、GBPUSD、GBPJPY、EURUSDの取引に適した設定をおこないます。この関数はTradeTimeframe(H1、H4、D1)とConfirmationTimeframe(M15、M30)が戦略の多時間軸アプローチ構成と整合しているかを検証し、無効な入力は拒否してエラー発生を防ぎます。さらに、SymbolInfoDoubleを使用して通貨ペアごとの契約サイズを取得します。これはGBPペアでの正確なポジションサイズ計算に不可欠で、たとえばGBPJPYはJPYのスケールによりpip値が小さいため特に重要です。
また、高値と安値を保持するグローバル変数(lastHighH1、lastLowH1など)、ローソク足の時間、取引状況などは0またはfalseに初期化され、EAの状態をリセットします。契約サイズのチェックにより、EAは正しいロットサイズを計算できるようになり、特にGBPJPYのpip値の特性上、特に重要です。初期化が正常に完了すると、使用する時間足と契約サイズがログに出力され、取引準備が整ったことが確認できます。このセットアップにより、EAはEURUSD、GBPUSD、GBPJPYの特定市場環境に適応した堅牢な動作が可能となり、ゴールドのように値幅がより大きい銘柄とは異なり、EURUSD/GBPUSD/GBPJPYの特性に合わせた設計です。
int OnInit() { if(TradeTimeframe != PERIOD_M15 && TradeTimeframe != PERIOD_M30) { Print("Invalid trade timeframe. Use M15 or M30."); return(INIT_PARAMETERS_INCORRECT); } if(ConfirmationTimeframe != PERIOD_M5 && ConfirmationTimeframe != PERIOD_M15) { Print("Invalid confirmation timeframe. Use M5 or M15."); return(INIT_PARAMETERS_INCORRECT); } contractSize = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_CONTRACT_SIZE); if(contractSize == 0) { Print("Failed to get contract size for ", _Symbol); return(INIT_PARAMETERS_INCORRECT); } lastHigh = 0; lastLow = 0; lastCandleTime = 0; purgeDetected = false; lastPurgeTime = 0; Print("EA Initialized on ", EnumToString(TradeTimeframe), ", Confirmation TF: ", EnumToString(ConfirmationTimeframe), ", Contract Size: ", contractSize); return(INIT_SUCCEEDED); }
IsNewCandle関数:新規ローソク足でのトリガーロジック
IsNewCandle関数は、主要取引時間足(デフォルトはH1)で新しいローソク足が形成されたかを確認します。具体的には、現在のローソク足のタイムスタンプ(iTime)と最後に記録されたローソク足時間(lastCandleTime)を比較します。新しいローソク足が検出された場合、lastCandleTimeが更新され、関数はtrueを返します。これにより、OnTick内のメイン取引ロジックが実行されます。これにより、EAはH1足ごとに一度だけ取引条件を評価することができ、GBPUSDやGBPJPYでのボラティリティの高いローソク足内の値動きによる不要な処理負荷や重複チェックを防ぐことができます。新しいローソク足に焦点を当てることで、流動性刈り取りの検出や包み足パターンの判定に必要な完全なローソク足データに基づいた戦略を正確に実行でき、トレンド主導のGBPペア市場で重要な値動きを捉えることが可能です。この関数は軽量でありながら、EAの効率性と精度を維持するために不可欠です。
bool IsNewCandle() { datetime currentCandleTime = iTime(_Symbol, TradeTimeframe, 0); if(currentCandleTime != lastCandleTime) { lastCandleTime = currentCandleTime; return true; } return false; }
UpdateHighsLows関数:流動性刈り取りレベルの監視
UpdateHighsLows関数は、H1、H4、D1の各時間足において、過去LookbackBars(デフォルト3本)の最高値と最安値を追跡し、それらをグローバル変数(lastHighH1、lastLowH1など)に格納します。CopyRatesを用いて過去の価格データを取得し、ArraySetAsSeriesにより最新のローソク足が配列のインデックス0に来るよう設定されます。時間軸ごとに、最初のローソク足の高値/安値を初期値とし、ルックバック期間を順に確認することで極値を更新します。
この関数は、流動性刈り取りの検出において極めて重要です。たとえば、現在のH1足が過去の高値を上抜ける、または安値を下抜ける場合、それはEURUSD、GBPUSD、GBPJPYにおけるトレンド転換や継続の可能性を示唆します。多時間軸アプローチにより、GBPJPYのボラティリティの高い値動きで発生するストップ狩りなど、重要な流動性刈り取りを逃さず捉えることができます。また、CopyRatesの読み込みに失敗した場合はエラーログに記録され、EAの堅牢性が確保されます。この関数は、GBPペアの重要サポート/レジスタンスに敏感な特性を考慮した、流動性刈り取りに基づくエントリーロジックの基盤を形成します。
void UpdateHighsLows() { // H1 MqlRates ratesH1[]; ArraySetAsSeries(ratesH1, true); if(CopyRates(_Symbol, PERIOD_H1, 1, LookbackBars, ratesH1) >= LookbackBars) { lastHighH1 = ratesH1[0].high; lastLowH1 = ratesH1[0].low; for(int i = 1; i < LookbackBars; i++) { if(ratesH1[i].high > lastHighH1) lastHighH1 = ratesH1[i].high; if(ratesH1[i].low < lastLowH1) lastLowH1 = ratesH1[i].low; } } else Print("Failed to load H1 rates"); // H4 MqlRates ratesH4[]; ArraySetAsSeries(ratesH4, true); if(CopyRates(_Symbol, PERIOD_H4, 1, LookbackBars, ratesH4) >= LookbackBars) { lastHighH4 = ratesH4[0].high; lastLowH4 = ratesH4[0].low; for(int i = 1; i < LookbackBars; i++) { if(ratesH4[i].high > lastHighH4) lastHighH4 = ratesH4[i].high; if(ratesH4[i].low < lastLowH4) lastLowH4 = ratesH4[i].low; } } else Print("Failed to load H4 rates"); // D1 MqlRates ratesD1[]; ArraySetAsSeries(ratesD1, true); if(CopyRates(_Symbol, PERIOD_D1, 1, LookbackBars, ratesD1) >= LookbackBars) { lastHighD1 = ratesD1[0].high; lastLowD1 = ratesD1[0].low; for(int i = 1; i < LookbackBars; i++) { if(ratesD1[i].high > lastHighD1) lastHighD1 = ratesD1[i].high; if(ratesD1[i].low < lastLowD1) lastLowD1 = ratesD1[i].low; } } else Print("Failed to load D1 rates"); }
IsVolumeSpike関数:取引流動性の検証
IsVolumeSpike関数は、取引セットアップが有効かを確認するために、現在のローソク足のティックボリュームが、過去LookbackBars(デフォルト3本)の平均ボリュームをVolumeThreshold(デフォルト1.0)倍以上かどうかをチェックします。CopyRatesを使用して取引時間足(H1)の直近ローソク足データを取得し、有効なローソク足(ボリュームが1以上のローソク足)を対象に平均ボリュームを計算します。有効なローソク足が存在しない場合はチェックをスキップし、デバッグ用に警告をログに出力します。
EURUSD、GBPUSD、GBPJPYにおいては、高い取引量はニュース後のブレイクアウトや流動性刈り取りなどの重要な値動きに伴うことが多いため、このフィルタは流動性刈り取りの有効性を確認するうえで非常に重要です。関数は現在のボリュームと平均ボリュームをログに出力することで透明性を確保します。ボリューム確認をおこなうことで、EAは流動性の低いセットアップによる誤ったシグナルを避け、GBPペア、特にトレンド主導の市場であるGBPJPYにおける取引の精度と収益性を高めます。
bool IsVolumeSpike(long currentVolume) { double avgVolume = 0; MqlRates rates[]; ArraySetAsSeries(rates, true); if(CopyRates(_Symbol, TradeTimeframe, 1, LookbackBars, rates) < LookbackBars) { Print("Failed to load rates for volume check"); return true; } int validBars = 0; for(int i = 0; i < LookbackBars; i++) { if(rates[i].tick_volume > 1) { avgVolume += rates[i].tick_volume; validBars++; } } if(validBars == 0) { Print("Warning: No valid volume data. Average volume is 0. Bypassing volume check."); return true; } avgVolume /= validBars; Print("Current volume: ", currentVolume, ", Average volume: ", avgVolume, ", Valid bars: ", validBars); return currentVolume >= VolumeThreshold * avgVolume; }
IsBullishTrend関数:トレンドの整合性の確認
IsBullishTrend関数は、取引時間足(H1)における50期間の単純移動平均(SMA)を用いて、市場のトレンド方向を判定します。iMAでSMAハンドルを作成し、CopyBufferで最新のSMA値を取得した後、現在の終値(iClose)と比較します。価格がSMAより上にある場合、関数はtrueを返し、強気トレンドであることを示します。それ以外の場合は、弱気または中立のトレンドと判断されます。
UseTrendFilterが有効(デフォルトtrue)の場合、この関数は買い取引を強気条件下でのみ、売りを弱気条件下でのみ実行するよう制御します。これにより、EURUSD、GBPUSD、GBPJPYがロンドン/ニューヨーク時間帯に持続的トレンドに従う傾向に沿った取引が可能になります。SMAデータ取得の失敗はエラーログに記録され、信頼性が確保されます。このフィルタは、GBPペア市場における乱高下時の誤ブレイクを減らし、流動性刈り取り後の取引に先立って広い市場環境を確認することで、より安全で精度の高い取引を支援します。
bool IsBullishTrend() { double sma[]; ArraySetAsSeries(sma, true); int smaHandle = iMA(_Symbol, TradeTimeframe, SMAPeriod, 0, MODE_SMA, PRICE_CLOSE); if(CopyBuffer(smaHandle, 0, 0, 1, sma) < 1) { Print("Failed to load SMA data"); return false; } double currentPrice = iClose(_Symbol, TradeTimeframe, 0); Print("Current price: ", currentPrice, ", SMA: ", sma[0]); return currentPrice > sma[0]; }
IsBullishEngulfingおよびIsBearishEngulfing関数:反転シグナルの確認
これらの関数は、流動性刈り取り後のエントリーを確認するための重要な反転パターンである、陽および陰の包み足を検出します。IsBullishEngulfingは、現在のローソク足が陽線(終値 > 始値)、直前のローソク足が陰線(終値 < 始値)であり、現在のローソク足が前のローソク足を包み込む(始値 ≤ 前の終値、終値 ≥ 前の始値)条件を満たすかどうかをチェックします。さらに、現在のローソク足の実体が前のローソク足の実体のEngulfingMinBodyRatio(0.3)以上であることを確認します。IsBearishEngulfingはこの逆のロジックを適用し、弱気のセットアップを判定します。EURUSD、GBPUSD、GBPJPYにおいては、M15やH1の流動性刈り取り後の包み足は、重要水準での流動性刈り取り後に特に強い反転やトレンド継続のシグナルとなることが多いです。
実体比率のチェックにより、GBPペアのボラティリティが高い時間帯における弱いパターンを除外し、信頼性の高いシグナルを抽出します。これらの関数は、直近3本のH1足およびM15足に適用され、どちらの時間足でもシグナルを捉える柔軟性を提供し、GBP市場のダイナミクスに対するEAの応答性を高めます。
bool IsBullishEngulfing(MqlRates ¤t, MqlRates &previous) { double currentBody = MathAbs(current.close - current.open); double prevBody = MathAbs(previous.close - previous.open); if(current.close > current.open && previous.close < previous.open && current.open <= previous.close && current.close >= previous.open && currentBody >= EngulfingMinBodyRatio * prevBody) { return true; } return false; } bool IsBearishEngulfing(MqlRates ¤t, MqlRates &previous) { double currentBody = MathAbs(current.close - current.open); double prevBody = MathAbs(previous.close - previous.open); if(current.close < current.open && previous.close > previous.open && current.open >= previous.close && current.close <= previous.open && currentBody >= EngulfingMinBodyRatio * prevBody) { return true; } return false; }
PlaceTrade関数:成行注文の実行(SL/TP使用)
PlaceTrade関数は、有効なシグナル(流動性刈り取り + 包み足 + ボリューム + トレンド)が確認された際に、買いまたは売りの注文を実行します。この関数では、MqlTradeRequestを作成し、通貨ペア、固定のLotSize(0.1)、注文種別(買い/売り)、およびエントリープライスを設定します。ストップロスは150 pips、テイクプロフィットは600 pipsに設定されており、EURUSD、GBPUSD、GBPJPYのポイント値(_Point * 100)に合わせてpipスケーリングを考慮しています。ORDER_FILLING_IOC (Immediate or Cancel)により、GBPJPYのような急速な値動きが発生する市場でも迅速な約定が保証されます。
注文が成功した場合、取引内容がログに記録され、tradePlacedがtrueに設定され、同一シグナルでの重複エントリーを防ぎます。また、purgeDetectedはリセットされ、同じ流動性刈り取りで再エントリーされるのを防ぎます。注文が失敗した場合は、デバッグ用にエラーコードがログに出力されます。この関数により、あらかじめ定義されたリスクパラメータに基づく正確な取引が可能となり、GBPペアのトレンドフォロー市場における高確率セットアップを狙った収益性の最適化が可能になります。
void PlaceTrade(ENUM_ORDER_TYPE orderType, double price) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_DEAL; request.symbol = _Symbol; request.volume = LotSize; request.type = orderType; request.price = price; request.sl = (orderType == ORDER_TYPE_BUY) ? price - StopLossPips * _Point * 100 : price + StopLossPips * _Point * 100; request.tp = (orderType == ORDER_TYPE_BUY) ? price + TakeProfitPips * _Point * 100 : price - TakeProfitPips * _Point * 100; request.type_filling = ORDER_FILLING_IOC; if(OrderSend(request, result)) { Print("Trade placed successfully: ", orderType == ORDER_TYPE_BUY ? "BUY" : "SELL", " at ", price, " SL: ", request.sl, " TP: ", request.tp); tradePlaced = true; purgeDetected = false; // Reset purge after trade } else { Print("Trade failed: ", result.retcode); } }
ManageTrailingStop関数:トレーリングストップによる利益保護
ManageTrailingStop関数は、価格が有利に動いた際に、保有ポジションのストップロスを動的に調整して利益を確保します。まず、PositionSelectを使用して指定された通貨ペアのポジションが存在するかを確認します。買いポジションの場合、現在のBid価格からTrailingStopPips (100 pips)を引いた位置に新しいストップロスを計算し、GBPUSD、EURUSD、GBPJPYのポイント値に合わせて調整します。新しいストップロスは、現在のストップロスよりも高く、かつ建値より上の場合のみ適用され、損益分岐点または利益を確保できるようにします。売りポジションの場合は、現在のアスク価格より上にストップロスを設定し、現在のストップロスより低い場合(または未設定の場合)かつ建値より下の場合に適用されます。
ストップロスの更新にはMqlTradeRequestとTRADE_ACTION_SLTPを使用し、テイクプロフィットは保持されます。このトレーリング機能は、GBPJPYのようなボラティリティの高い相場で非常に重要で、大きな値動きを捉えつつ利益を守ることが可能です。更新に失敗した場合はエラーログに記録され、透明性が確保されます。この関数により、GBPペアのトレンド主導市場で利益を失うリスクを低減し、収益性を向上させることができます。
void ManageTrailingStop() { if(!PositionSelect(_Symbol)) return; double currentPrice = (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol, SYMBOL_BID) : SymbolInfoDouble(_Symbol, SYMBOL_ASK); double openPrice = PositionGetDouble(POSITION_PRICE_OPEN); double currentSL = PositionGetDouble(POSITION_SL); double newSL = 0; if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { newSL = currentPrice - TrailingStopPips * _Point * 100; if(newSL > currentSL && newSL > openPrice) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_SLTP; request.position = PositionGetInteger(POSITION_TICKET); request.symbol = _Symbol; request.sl = newSL; request.tp = PositionGetDouble(POSITION_TP); if(OrderSend(request, result)) Print("Trailing stop updated for BUY: ", newSL); else Print("Failed to update trailing stop: ", result.retcode); } } else // POSITION_TYPE_SELL { newSL = currentPrice + TrailingStopPips * _Point * 100; if((newSL < currentSL || currentSL == 0) && newSL < openPrice) { MqlTradeRequest request = {}; MqlTradeResult result = {}; request.action = TRADE_ACTION_SLTP; request.position = PositionGetInteger(POSITION_TICKET); request.symbol = _Symbol; request.sl = newSL; request.tp = PositionGetDouble(POSITION_TP); if(OrderSend(request, result)) Print("Trailing stop updated for SELL: ", newSL); else Print("Failed to update trailing stop: ", result.retcode); } } }
OnTick関数:流動性刈り取りと包み足に基づく取引のコアロジック
OnTick関数はEAの主要な意思決定ハブであり、すべての価格ティックで実行されますが、IsNewCandleによって新しいH1ローソク足のタイミングでのみ処理されます。ポジションが開かれていない場合はtradePlacedをリセットし、1回の流動性刈り取りサイクルにつき1回だけ取引がおこなわれるようにします。保有ポジションに対してはManageTrailingStopでトレーリングストップが管理されます。H1足およびM15足のデータをCopyRatesで読み込み、現在のH1足を過去の高値/安値(UpdateHighsLowsで更新)と比較して流動性刈り取りを検出します。具体的には、H1/H4/D1の高値を上抜ける、あるいは安値を下抜ける場合に流動性刈り取りが発生したと判断します。この現象はEURUSD、GBPUSD、GBPJPYでの主要取引セッション中によく見られます。刈り取りが検出されるとpurgeDetectedがセットされ、lastPurgeTimeが3本分のH1ローソク足のウィンドウを追跡します。
ボリュームはIsVolumeSpikeで確認され、トレンドはIsBullishTrendでチェックされます(有効な場合)。包み足パターンはH1およびM15の両方で判定され、柔軟な確認が可能です。高値刈り取り後にH1またはM15で陽の包み足が形成され、ボリュームが高く、トレンドが強気であれば買い取引が発動されます。一方、安値刈り取り後に陰の包み足が形成され、ボリュームが高く、トレンドが弱気であれば売りが実行されます。詳細なログ出力によりデバッグの透明性が確保されます。このロジックは、多時間軸での流動性刈り取りと堅牢な確認シグナルを組み合わせることで、GBPペアのトレンドフォロー型市場における高確率取引を実現し、収益性の最適化を可能にしています。
void OnTick() { // Check if a new candle has formed on the trade timeframe if(!IsNewCandle()) return; // Reset tradePlaced if no open positions if(!PositionSelect(_Symbol)) tradePlaced = false; // Manage trailing stop for open positions ManageTrailingStop(); // Get current and previous candle data for trade timeframe MqlRates ratesH1[]; ArraySetAsSeries(ratesH1, true); if(CopyRates(_Symbol, TradeTimeframe, 0, 4, ratesH1) < 4) { Print("Failed to load H1 rates data"); return; } // Get candle data for confirmation timeframe (M15) MqlRates ratesM15[]; ArraySetAsSeries(ratesM15, true); if(CopyRates(_Symbol, ConfirmationTimeframe, 0, 4, ratesM15) < 4) { Print("Failed to load M15 rates data"); return; } // Current H1 candle (index 0) double currentOpenH1 = ratesH1[0].open; double currentCloseH1 = ratesH1[0].close; double currentHighH1 = ratesH1[0].high; double currentLowH1 = ratesH1[0].low; long currentVolumeH1 = ratesH1[0].tick_volume; datetime currentTimeH1 = ratesH1[0].time; // Update highs and lows for all timeframes UpdateHighsLows(); // Check for purge (liquidity sweep) on any timeframe bool highPurgedH1 = (currentHighH1 > lastHighH1 && lastHighH1 > 0); bool highPurgedH4 = (currentHighH1 > lastHighH4 && lastHighH4 > 0); bool highPurgedD1 = (currentHighH1 > lastHighD1 && lastHighD1 > 0); bool lowPurgedH1 = (currentLowH1 < lastLowH1 && lastLowH1 > 0); bool lowPurgedH4 = (currentLowH1 < lastLowH4 && lastLowH4 > 0); bool lowPurgedD1 = (currentLowH1 < lastLowD1 && lastLowD1 > 0); bool highPurged = highPurgedH1 || highPurgedH4 || highPurgedD1; bool lowPurged = lowPurgedH1 || lowPurgedH4 || lowPurgedD1; // Update purge status if(highPurged || lowPurged) { purgeDetected = true; lastPurgeTime = currentTimeH1; highPurge = highPurged; } // Check if within the post-purge window bool withinPurgeWindow = false; if(purgeDetected) { int candlesSincePurge = iBarShift(_Symbol, TradeTimeframe, lastPurgeTime, true); withinPurgeWindow = candlesSincePurge <= MaxCandlesPostPurge; if(!withinPurgeWindow) { purgeDetected = false; // Reset if window expires Print("Purge window expired: ", candlesSincePurge, " candles since last purge"); } } // Check volume for liquidity confirmation bool volumeConfirmed = IsVolumeSpike(currentVolumeH1); if(currentVolumeH1 <= 1) { Print("Warning: Tick volume is ", currentVolumeH1, ". Possible data issue. Bypassing volume check."); volumeConfirmed = true; } // Check trend with SMA bool isBullishTrend = UseTrendFilter ? IsBullishTrend() : true; // Check for engulfing candles on H1 (current + previous 2 candles) bool bullishEngulfingH1 = false, bearishEngulfingH1 = false; for(int i = 0; i < 3; i++) { if(IsBullishEngulfing(ratesH1[i], ratesH1[i+1])) bullishEngulfingH1 = true; if(IsBearishEngulfing(ratesH1[i], ratesH1[i+1])) bearishEngulfingH1 = true; } // Check for engulfing candles on M15 (current + previous 2 candles) bool bullishEngulfingM15 = false, bearishEngulfingM15 = false; for(int i = 0; i < 3; i++) { if(IsBullishEngulfing(ratesM15[i], ratesM15[i+1])) bullishEngulfingM15 = true; if(IsBearishEngulfing(ratesM15[i], ratesM15[i+1])) bearishEngulfingM15 = true; } // Trade logic if(purgeDetected && withinPurgeWindow && !tradePlaced) { if(highPurge && (bullishEngulfingH1 || bullishEngulfingM15) && volumeConfirmed && isBullishTrend) { Print("Buy signal: High purged, bullish engulfing on ", bullishEngulfingH1 ? "H1" : "M15", ", volume confirmed, bullish trend"); PlaceTrade(ORDER_TYPE_BUY, currentCloseH1); } else if(!highPurge && (bearishEngulfingH1 || bearishEngulfingM15) && volumeConfirmed && !isBullishTrend) { Print("Sell signal: Low purged, bearish engulfing on ", bearishEngulfingH1 ? "H1" : "M15", ", volume confirmed, bearish trend"); PlaceTrade(ORDER_TYPE_SELL, currentCloseH1); } } }
インストールとバックテスト:MetaEditorでコンパイルし、チャートに添付します。GBPJPY、H1(2025年11月~2026年2月)を1% のリスクでバックテストします。
戦略テスト
Liquidity Grab EAの戦略テスト
この戦略は、そのコアロジックおよびトレンドフォロー型取引およびシナリオフォローへの高い適応性により、多くの通貨ペア、場合によってはほぼすべての通貨ペアにおいて有効に機能します。本戦略では、エントリーセットアップとして流動性パージの概念を採用しており、高ボラティリティ環境を活用する設計となっています。これらは多くの取引戦略において重要かつ有利な要素です。今回、この戦略はGBPJPYを対象に、2025年1月1日から2026年2月8日までの期間、60分足(H1)チャートで検証を行います。以下に、この戦略で使用するパラメータを示します。
GBPJPY


ストラテジーテスターの結果
ストラテジーテスターで検証をおこなった結果、このEAがどのように機能し、市場をどのように分析し、どのようなパフォーマンスを示すかが明らかになりました。
Liquidity Grab EAのストラテジーテスター結果
残高/エクイティグラフ
GBPJPY

バックテスト結果:
GBPJPY
まとめ
本記事では、トレンドフォローに特化したMetaTrader 5用EAについて解説しました。このEAは、流動性狩りと市場構造転換を適切に区別し、検出した状況に応じて最適に活用できるよう設計されています。また、トレード管理とリスク管理の手法も組み込まれており、高い確率のトレードセットアップをGBPJPYで検出・実行するとともに、同じトレード管理およびリスク管理のプロトコルを用いて適切な決済ポイントも判断できるようになっています。これにより、リスクやエクスポージャー、さらには人的ミスを体系的に低減することを目的としています。
このEAは、非常にシンプルでありながら強力なトレードEAの一つです。トレンドフォローの概念と流動性掃除を活用して、有望なエントリーポイントやトレンド転換を捉えます。堅牢で柔軟性の高いリスク・取引管理ロジックにより、ドローダウンや取引の損失を最小化しながら、EAが最適なパフォーマンスを発揮できるよう設計されています。
このEAをGBPJPYでテストし、任意の時間足で効率的にエントリを検出できることを確認しました。しかし、エントリの検出はあくまで一部であり、EA内部には最適なエントリ検証ロジックが組み込まれており、特定の条件を満たした場合のみ取引が実行されます。取引が検証されて実行されると、取引およびリスク管理ロジックが即座に適用され、決済時まで適切な管理がおこなわれます。
このEA戦略を実装するには、下記の入力パラメータを設定することで望ましい結果を得られます。このEAは、トレーダーが選択した時間足(M15からD1まで)において、流動性、流動性掃除、およびトレードエントリーの可能性をスキャンするよう設計されています。また、検出されたエントリーポイントがトレンド方向、移動平均線、およびトレーリングストップロスに用いるATRと整合していることを確認します。興味のあるトレーダーは、まずデモ口座でGBPJPYを用いてこのEAのバックテストをおこなうべきです。GBPJPY向けに設計されており、最適なパフォーマンスを発揮しますが、GBPUSD、EURUSD、GOLDにも適用可能です。
このEAの主な目的は、流動性一掃後のトレードに特化し、市場のシナリオに従ったトレードを、高度なトレードロジックによって最適化することです。また、トレーダーが選択する時間足に応じて出現する高確率のトレードセットアップに対応するとともに、実装されたトレーリングストップによるリスク管理機能を組み込むことも目的としています。
また、ユーザーには、定期的にパフォーマンスログを確認し、目標や資産クラス、リスク許容度に応じて設定や入力パラメータを調整することを推奨します。免責条項:本EAを使用する場合は、まずデモ口座で十分に検証し、流動性掃除の概念と本記事で紹介したトレード手法を十分に習得してから実際の資金で運用してください。継続的に利益を上げられることを確認したうえで、ライブ口座での取引へ移行することを推奨します。
結論
本記事では、トレーダーが市場のシナリオ、流動性エリア、流動性掃除、トレードエントリー、リスク管理、トレード管理、そしてドローダウンの回避において直面する主な課題を取り上げました。また、これらのプロセスを簡素化し、収益性を高め、高確率のトレードのみを実行できるようにするEAの設計方法についても説明しました。さらに、流動性掃除後に発生するトレードセットアップを利用し、市場のシナリオに従ってトレードを行い、トレンドに逆らうトレードアイデアやセットアップを避けることが、収益性の向上に大きく貢献することについても詳しく解説しました。
多くのトレーダーは、流動性や流動性掃除というトレードの概念が、自身のトレードパフォーマンスにどれほど大きな好影響を与え得るかを十分に理解していません。しかし、これらを適切なリスク管理およびトレード管理と組み合わせることで、その効果は非常に大きなものとなり、平均的なトレーダーと優れたトレーダーを分ける重要な要素となります。本記事で提案するEAは、規律を維持する支援をおこない、トレーダーが自分の取引アイデアやポジションサイズ、セットアップを検証できるようにします。EAのエントリを直接使用しなくても、管理と検証が可能です。
自動化されたMQL5 EAは以下を提供します。
- 取引対象資産において流動性掃除後に発生するセットアップに基づく、高確率のトレード
- ニュース時のボラティリティから保護するため、ニュース前後の取引をブロック
- 確認済みシグナルと検証済みエントリーロジックに基づくエントリー、および動的なストップロス(SL)とテイクプロフィット(TP)
- 適応型リスク管理(連敗時のロット削減、連勝時のロット増加)
- 継続的な戦略最適化のための取引ログ記録
- まず市場のシナリオを特定し、その後、市場構造転換なのか流動性掃除なのかといったセットアップの種類を判別するロジック
- 感情による意思決定の排除
- 自動取引管理(SL、TP、部分決済)
これらの機能を組み合わせることで、高確率のトレードを一貫して実行し、最適なリスク管理を実現できます。その結果、収益性の高いトレードを行える可能性が向上し、トレーダーのパフォーマンス改善につながります。
記事で参照されているすべてのコードは以下に添付されています。次の表では、この記事に付随するすべてのソースコードファイルについて説明します。
| ファイル名 | 説明 |
|---|---|
| Liquidity Grab EA.mq5 | Liquidity Grab EAの完全なソースコードを含むファイル |
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/21212
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
MQL5取引ツール(第18回):向き制御対応の角丸吹き出し
取引規律をコードに組み込む(第1回):MQL5でライブトレードに構造的な規律を実装する
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
MQL5取引ツール(第17回):ベクトルベースの角丸長方形と三角形を探る
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索
今回はモデレーターが書式を修正しました。今後はコードの書式を適切に整えてください。書式が不適切なコードを含む投稿は削除される場合があります。
新バージョンをありがとう;でも、ファイル内のコードが記事内のものと「同じ」かどうか、本当に確認しましたか!
(例えば、私は以下が見つかりませんでした
..
..
…など
が見つかりませんでしたが、コードには次のようなものが含まれています(これらはあなたの古い記事「Trending King **」からのものですが、2026年2月16日時点ではh1/h4/D1も含まれています;;; コードについて本当に混乱しています!!!):
新しいバージョンをありがとう。でも、ファイル内のコードは記事にあるものと本当に同じですか!
(例えば、私は見つけられませんでした
..
..
.. など
しかし、コードには次のようなものがあります(これらはあなたの以前の記事『Trending King **』からのものですが、2026年2月16日時点ではh1/h4/D1も含まれています;;; コードについて本当に混乱しています!!!):
こんにちは。はい、表示されているコードとファイル内のコードは同じです