長期取引の最適化:包み足と流動性戦略
はじめに
本記事を執筆したのは、近年、多くのトレーダーが短期売買やスキャルピングのノイズや不確実性に翻弄され、その結果として口座資金を失うケースが増えているという問題意識からです。これは初心者だけでなく、経験豊富なベテラントレーダーにとっても無縁ではありません。
多くのトレーダーは短期的な値動きや小さなスイングに意識を奪われがちですが、価格は常に明確な意図やストーリー、そしてターゲットを持って、ある水準から次の水準へと推移しています。また、チャート上のすべての値動きは上位足から派生し、そこから下位足へと波及していきます。これがいわゆる「トップダウン分析」と呼ばれる理由です。上位足から下位足へと分析をおこない、上位足の重要な価格帯を基準にエントリーをおこなう方が、より効果的であるとされています。
高時間足に基づいて分析、執行、管理された取引は、一般的に精度が高く、ドローダウンも比較的少ない傾向があります。価格は上位足のシナリオに沿って力強く動くため、仮に一時的な含み損が発生しても、やがて上位足の流れに従って目標方向へ進み、ドローダウンから回復する可能性が高いのです。また、価格の変動はより強力であり、ドローダウン状態にある場合でも、価格はやがて上位足のシナリオに沿って推移し、ドローダウンから回復する可能性が高いことを意味します。
このEAは、短期的な値動きに翻弄されることなく、利確目標に到達するまで自分のトレンドの方向性(バイアス)を頻繁に変えずにポジションを保持できる、忍耐強い長期トレーダー向けに設計されています。同時に、短期トレーダーにとっても有用であり、上位足のバイアスやオーダーフローに沿った取引をおこなうことで、長期トレンドに逆らう取引を回避する助けとなります。
統計的にも、上位足のトレンドと同方向に取引をおこなう方が、逆張りよりも良好な結果をもたらす可能性が高いことが示されています。このEAは、その優位性を実践レベルで活用するためのツールとして設計されています。

上位足トレードの内省
本記事の主な目的は、多くの市場参加者、特に経験の浅い参加者や、長年市場に関わってきた参加者でさえ見落としがちな上位足の重要性を強調することにあります。この視点は、最終的に取引成績を大きく左右し得る決定的な要素になり得ます。
本質的に、価格は上位足における一つの重要水準から次の重要水準へと推移します。下位足で発生する値動きは、その過程で生じる結果的な現象に過ぎません。これは、多数派の認識とは逆です。一般的には、下位足が上位足の価格変動を形成し、エントリーは下位足から始まり、それが上位足の値動きを構成すると考えられがちです。
この観点に立てば、何をおこなうにしても、まず月足(MN)チャートに注目すべきです。そして観察をおこない、重要なエリアや注目すべきポイントに印を付けたうえで、順により下位の時間足へと落としていきます。これらの重要なエリアや注目ポイントは、用いる戦略によってさまざまな名称で呼ばれます。
あるトレーダーはそれらをオーダーブロックと捉え、あるトレーダーは支持線や抵抗線と見なし、またあるトレーダーは供給や需要ゾーンと呼び、さらには流動性の刈り取りと表現することもあります。しかし、これらすべての戦略や理論に共通している最も重要な点は、それらが非常に重要かつ有用な水準であり、強い価格反応を予測できる関心領域であるということです。そして、最も精度が高く、熟練したトレーダーが理想的な仕掛けの機会を探すのも、まさにそのような場所です。本記事が目指すのは、この現象を効果的に活用するエキスパートアドバイザー(EA)をどのように作成し、どのように運用するかを示すことにあります。

長期トレンドの検出、週足、月足、日足のバイアス判断、および取引方向とナラティブの想定
MNチャートを開いた後、最初におこなうべきことは、前述した主要なポイント(反応エリア)に印を付けることです。これらは通常、過去数か月の高値や安値付近に位置しています。これらの主要な反応エリアは常に念頭に置く必要があります。というのも、価格は多くの場合ここで反応を示し、その月、あるいはその月の残り期間の値動きの方向性を決定づける可能性があるからです。
これは、月足において最も近い反応エリアであるため、いわば「狙いやすい目標」と言えます。もう一つの注目ポイントはフェアバリューギャップであり、これは利益確定水準として活用できます。さらに重要なエリアとして、チャート上に現れる相対的に等しい高値および安値が挙げられます。
注意深くチャートを観察していれば、これらのエリアにおいて、価格が到達した後に高値または安値を素早く刈り取り、その直後に包み足が素早く形成される場面に気付くはずです。この現象は、より下位の時間足で発生することもあり、必ずしも同一時間足で起こる必要はありません。重要なのは、その構造が有効に機能することです。たとえば、価格が前週安値を刈り取り、その直後に強い陽の包み足が反対方向へ大きく伸びる場合、それは長期的な取引機会を示唆している可能性があります。なぜなら、上位足においてはトレンドや方向性、ナラティブは容易には変化しないからです。
目標は、包み足が完成し確定するまで忍耐強く待つことです。そしてそれが有効であると確認できた時点で、長期の買いポジションに入ります。保有期間は数週間から数か月に及ぶ可能性があります。利益確定水準は、前月の高値、相対的に等しい高値、あるいは顕著な高値などになります。これらのエリアを基準として、月足の見通しやプロファイルを決定します。
また、この事象が発生しても、価格がまだ重要な利益確定エリアに到達していない場合は、トレンド転換を想定すべきではありません。下位足ではスイングや短期的な反転が発生することがありますが、長期的な見通しに大きな影響を与えるものではありません。トレンドの終焉や本格的な反転は、月足の対極に位置する主要水準、あるいは前述した主要エリアで発生します。売りの場合も同様に、流動性の刈り取りの後に包み足パターンが形成されます。この同じ理論は週足にも当てはまり、週足の見通しやナラティブを判断するために用いられます。
たとえば価格が前週の高値に到達し、勢いよくそれを刈り取った後、流動性を吸収した直後に日足(D1)または同一の週足(W1)上で陰の包み足が素早く形成され、確定した場合、これは週足時間軸における長期的な売りエントリーの確認となります。
他の時間足と同様に、利益確定ポイントをあらかじめ特定し、主な焦点は前週安値に置きます。もしそこが刈り取られても価格の減速が見られない場合、その水準は部分的な利益確定エリアと見なし、長期目標をフェアバリューギャップ、相対的に等しい安値、あるいは週足上の直近安値へと調整します。
この明確で特徴的な構造が最後に現れる時間足が日足(D1)です。日足は、下位足と上位足の中間に位置する橋渡し的な時間足として機能するため、極めて重要かつ基礎的な時間軸であると考えられます。日足のみを用いることで、数日から数時間にわたる短期的な取引の枠組みを構築することも可能です。
また、この時間足では短期スイングと長期スイングの両方を比較的容易に識別でき、さらにナラティブやトレンドの把握もおこないやすくなります。重要な時間足であるため、相対的に等しい高値および安値、過去の高値および安値、前日の高値および安値に注目すべきです。必要な情報の多くはこの時間足に集約されています。
価格はこの時間足において、相対的に等しい高値/安値や前日の高値/安値に向かって強く動き、そのエリアを刈り取ることがあります。前日の安値を例にすると、そこを刈り取った直後に陽の包み足が形成され、新たな日足上昇トレンドの開始を示唆します。この包み足は、下位足であるH4に現れる場合もあります。
このような現象が発生した場合、この時間足における中長期的トレンドの可能性を示唆します。利益確定目標は前日の高値、あるいは日足の直近高値や相対的に等しい高値となります。場合によっては、フェアバリューギャップが最も適切な決済または部分利確の機会を提供します。
さらに重要な点として、抵抗帯や支持帯も注視すべき重要エリアであり、供給/需要ゾーンやオーダーブロックも本質的には同一のパターンを異なる名称で表現しているに過ぎません。また、利益確定エリアは固定的なものではなく、市場環境や対象資産を取り巻く地政学的要因などによって変化する可能性があります。場合によっては、全体的なトレンド自体が変化することもあります。
そのため、このEAにおいては部分的な利益確定が有効に機能します。また、フェアバリューギャップなどの要素を活用することで損失の軽減や反転の予測にも対応できます。しかし、常に念頭に置くべきことは、これらすべての現象は主要水準においてのみ発生するという点です。それらの水準は、価格にとっていわばバス停のような存在なのです。

上位足の方向性、トレンド、ナラティブ
ここからは最後の、そして比較的理解しやすい部分です。主要水準や想定目標エリアを特定することは、正しい方向への第一歩に過ぎません。実務上の理由から、それらを手動でチャートにマーキングしておくことで、ノイズに惑わされることを防ぎ、現在有効なナラティブに明確に集中できるようになります。例えば月足(MN)において、前月安値を刈り取り、その後に陽の包み足が確定して買いが確認された場合、月足のプロファイル、バイアス、そしてナラティブは総じて強気であると判断できます。この状況下で売りをおこなうことは、月足トレンドに逆行する行為になります。
同様の構造は週足(W1)でも発生します。例えば、価格が前週高値を刈り取り、その後に陰の包み足が確定して下落が始まった場合、週足のナラティブ、バイアス、トレンドは売り方向であると解釈できます。この状況で買いを試みる場合、高い確率で損切りにかかる可能性があります。なぜなら、週足のナラティブに逆らうことになるからです。効率的に収益を上げる最もシンプルな方法は、週足および月足に従って取引をおこなうことです。これにより、大きな含み損や精神的負担、不必要な損切りを大幅に回避できます。
最後に日足(D1)です。直近安値/高値や前日高値/安値を刈り取り、その安値圏からH4またはD1で陽の包み足が形成された場合、それは日足における強気バイアスを示唆します。そのため、下位足での執行はこの方向性を前提としておこなうべきです。最後に最も重要なポイントとして、最適な成果を得るためには、複数の時間足、できれば月足、週足、日足のすべてが同一のバイアス、ナラティブ、トレンドで一致している局面を優先すべきです。W1、D1、MNが同じ方向性を示している場合、それは最も取り組みやすい局面の一つとなります。値動きは速く、押し目や含み損も比較的小さくなりやすい傾向があります。
次の章では、上位足分析(HTF分析)に基づき、週足、日足、月足のナラティブおよびバイアスを用いて長期的確信度を判断するEAの設計および設定方法について詳述します。

MQL5におけるHTF Engulfing King EAによる上位足取引の自動化
この戦略を自動化し、説明して実装するために、以下を作成しました。
- 上位足のトレンドおよび流動性刈り取り後の取引エントリーポイントを解析する上位時間軸EAで、トレーリングストップと単純移動平均(SMA)も組み込んでいます。
意思決定プロセス
このEAの意思決定(流動性の検知、包み足の検知、取引実行)は、次のロジックに基づいています。
HTF Engulfing King EAのソースコード
このEAは、上位足チャート(D1、W1、MN)から長期取引シグナルを検出します。流動性刈り取り直後に形成される包み足を取引エントリーのトリガーとして解釈します。また、単純移動平均(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市場での誤ブレイクを減らすようになっています。
//+------------------------------------------------------------------+ //| FlexibleMultiTFEngulfingEA.mq5 | //| Expert Advisor for MetaTrader 5 | //| Description: Trades based on H1/H4/D1 highs/lows purges, waits | //| for engulfing candles on H1 or M15, with flexible execution. | //+------------------------------------------------------------------+ #property copyright "Eugene Mmene" #property link "https://EMcapital.com" #property version "1.06" //--- Input Parameters input double LotSize = 0.1; // Lot size for trades input int LookbackBars = 3; // Number of bars to check for highs/lows input double StopLossPips = 150.0; // Stop loss in pips (adjusted for GBPUSD/GBPJPY) input double TakeProfitPips = 600.0; // Take profit in pips (adjusted for GBPUSD/GBPJPY) input double TrailingStopPips = 100.0;// Trailing stop in pips input double EngulfingMinBodyRatio = 0.3; // Min body ratio for engulfing candle input ENUM_TIMEFRAMES TradeTimeframe = PERIOD_H1; // Primary timeframe for trading input ENUM_TIMEFRAMES ConfirmationTimeframe = PERIOD_M15; // Lower timeframe for engulfing input int MaxCandlesPostPurge = 3; // Max H1 candles to wait for engulfing input double VolumeThreshold = 1.0; // 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の特定市場環境に適応した堅牢な動作が可能となり、金などのよりボラティリティの高い資産とは異なり、比較的安定した取引が可能になります。
int OnInit() { if(TradeTimeframe != PE RIOD_H1 && TradeTimeframe != PERIOD_H4 && TradeTimeframe != PERIOD_D1) { Print("Invalid trade timeframe. Use H1, H4, or D1."); return(INIT_PARAMETERS_INCORRECT); } if(ConfirmationTimeframe != PERIOD_M15 && ConfirmationTimeframe != PERIOD_M30) { Print("Invalid confirmation timeframe. Use M15 or M30."); 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); } lastHighH1 = 0; lastLowH1 = 0; lastHighH4 = 0; lastLowH4 = 0; lastHighD1 = 0; lastLowD1 = 0; lastCandleTime = 0; tradePlaced = false; 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でコンパイルし、チャートに添付します。GBPUSD、EURUSD/GBPJPY H1 (2025)を1% のリスクでバックテストします。
戦略テスト
HTF Engulfing King EAの戦略テスト
この戦略は、トレンドへの適応が比較的早く、流動性刈り取りのコンセプトと高ボラティリティを利用できるため、多くの通貨ペアで効果的です。これらの特徴は、短期取引(デイトレード)だけでなく長期取引にも有効です。今回はEURUSDとGBPUSDを対象に、2025年1月1日から2025年10月27日までのH1(60分足)チャートでテストをおこないます。以下は、この戦略で選択したパラメータです。
EURUSD

GBP/USD


ストラテジーテスターの結果
ストラテジーテスターでテストを実施した結果、HTF包み足キングEAの動作、分析、及びパフォーマンスは以下の通りです。
HTF Engulfing King EAのストラテジーテスター結果
残高/資本グラフ:
EURUSD

GBP/USD

バックテスト結果:
EURUSD 
GBP/USD

まとめ
本記事では、MetaTrader 5用のEAを紹介しました。このEAは、包み足と流動性刈り取りを活用したプライスアクションを組み合わせ、GBPUSDやEURUSDにおける長期的で高確率の取引セットアップを特定し、同じプライスアクションを用いて利食いや損切りのポイントを設定できるよう設計されています。このEAは、長期ポジション取引およびトレンドフォロー戦略において、可能な長期エントリーポイントやトレンド変化を捉える上で非常に価値が高く、画期的な概念です。
EURUSD、GBPUSD、GBPJPYでテストをおこなった結果、上位足での長期取引エントリーポイントを効率的かつ適切に検出できることが確認されました。しかし、エントリーポイントの検出は全体の一部に過ぎません。最近刈り取られた流動性から勢いのある包み足が形成されない場合、その地点はEAが有効な取引シナリオとして認識せず、価格が急騰しても取引は実行されません。これらの包み足は、ボラティリティの高い相場で取引精度と質を向上させる確認シグナルとして機能します。
EAを実装する際は、下記の入力パラメータを設定することで望ましい結果を得られます。EAは、トレーダーが選択した上位足(D1~MN)をスキャンして取引エントリーポイントを特定し、トレンド、単純移動平均(SMA)、およびATRに基づいたトレーリングストップと連動するよう設計されています。興味のあるトレーダーは、任意の資産や通貨ペアでデモ口座を使ってバックテストをおこなうことが推奨されますが、特にEURUSDとGBPUSDで最適に機能します。EAの主目的は、上位足における高確率セットアップを活用した長期ポジション取引を最適化し、リスク管理をトレーリングストップで組み込むことです。
また、ユーザーには、定期的にパフォーマンスログを確認し、目標や資産クラス、リスク許容度に応じて設定や入力パラメータを調整することを推奨します。免責条項:このEAを使用する方は、まずデモ口座でテストし、この長期ポジション取引手法を習得してから、ライブ資金での取引に臨むようにしてください。
結論
本記事の主なポイントと強調点は、トレーダーが日々の取引で直面する問題を明確に説明し、解決策を提示することにあります。たとえば、週足、月足、日足のナラティブやオーダーフローに逆らった取引、下位足のノイズに迷いトレンドや実際の値動きがどこで発生するのか判断できずに分析麻痺に陥ること、そして長期ポジション取引において「いつ」「どこで」意思決定を下すべきかといった問題です。記事では、EAがこれらの制約を解決し、取引プロセスをより簡単にし、流動性刈り取りと包み足戦略を活用して分析、理解、確認、さらには自動取引の実行まで可能にする方法を明確に示しています。
多くの専門家、初心者トレーダー、さらには中級者トレーダーでさえ、長期間ポジション取引の複雑な世界をうまくナビゲートできず、この手法にフラストレーションを感じることがあります。それは、相場の動きを十分に理解できなかったり、価格がどのように常に動き、馴染みのあるパターンや移動平均を使って短期的に実際に利益を生むクラシックな取引や実行をおこなっているのかを見極める目を持っていないためです。これは長期取引やポジショントレーダーに比べて頻繁に発生します。あるいは、たとえEAのエントリーに基づいて取引を実行しなくても、トレーダーは自身の取引アイデア、ポジション、セットアップ、さらにはこの記事で共有したトレンドや方向性を検証することができます。そして、UT BOTがシグナル生成において非常に重要な役割を果たすことに気づき、興味深く感じるでしょう。
この長期ポジション取引用のEAをMQL5で自動化することで、感情的バイアス、分析麻痺、自己不信を減らし、この長期ポジション取引戦略に基づく取引アイデアの一貫した実行が可能になります。さらに、このEAは短期取引やスキャルピングにも応用でき、日足、週足、月足のナラティブに従って自身の取引を検証することができます。
記事で参照されているすべてのコードは以下に添付されています。次の表では、この記事に付随するすべてのソースコードファイルについて説明します。
| ファイル名 | 説明 |
|---|---|
| HTF Engulfing King EA.mq5 | HTF Engulfing King EAの完全なソースコード |
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/19756
警告: これらの資料についてのすべての権利はMetaQuotes Ltd.が保有しています。これらの資料の全部または一部の複製や再プリントは禁じられています。
この記事はサイトのユーザーによって執筆されたものであり、著者の個人的な見解を反映しています。MetaQuotes Ltdは、提示された情報の正確性や、記載されているソリューション、戦略、または推奨事項の使用によって生じたいかなる結果についても責任を負いません。
MQL5での取引戦略の自動化(第38回):傾斜角フィルタ付き隠れRSIダイバージェンス取引
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
MetaTrader 5機械学習の設計図(第5回):逐次ブートストラップ - ラベルのバイアス除去とリターンの向上
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索