
プライスアクション分析ツールキットの開発(第7回):Signal Pulse EA
内容
はじめに
この記事では、MQL5で「Signal Pulse EA」と呼ばれるエキスパートアドバイザー(EA)を開発する方法を紹介します。このEAは、3つの異なる時間枠にわたって、ボリンジャーバンドとストキャスティクスを組み合わせて売買シグナルを検出します。複数の時間枠にまたがるシグナルを確認することで、取引エントリー前に信頼性を高め、トレーダーがより的確な判断を下せるよう支援することが目的です。Signal Pulse EAでは、ボリンジャーバンド(BB)、ストキャスティクス、複数の時間枠を統合してシグナルを生成しています。私たちの目標は、トレーダーの判断を惑わせる誤ったシグナルを最小限に抑え、これらの要素を組み合わせることで、取シグナルの精度を高めることです。以下に、シグナル生成における各要素の役割と重要性を表形式でまとめました。
- 複数の時間枠
利点 | 詳細 |
---|---|
リスク管理 | 複数の時間枠を用いることで、EAは異なる視点から市場を分析でき、誤ったシグナルの影響を軽減し、リスク管理を強化できます。 |
シグナルへの信頼性 | 時間枠ごとにシグナルを確認することで、取引方向への確信が高まり、弱いまたは偽のシグナルによるエントリーを回避できます。 |
多様化 | 複数の時間枠を分析することで、市場の多角的な見方が可能となり、変化する相場環境に柔軟に対応できます。 |
- ストキャスティクス
利点 | 詳細 |
---|---|
買われ過ぎ/売られ過ぎの判断 | ストキャスティクスは、買われ過ぎや売られ過ぎの状態を特定し、市場の反転ポイントを示す手がかりになります。 |
シグナル確認ツール | ボリンジャーバンドのシグナルに対する確認手段として機能し、BB単独での判断による誤ったエントリーを防ぎます。 |
誤シグナルのフィルタリング | 特にボラティリティの高い状況下で、BBから発生する誤シグナルをフィルタリングする役割を果たします。 |
- ボリンジャーバンド
利点 | 詳細 |
---|---|
ボラティリティの可視化 | 市場のボラティリティを視覚的に示すことで、EAは市場の状況や取引機会を把握しやすくなります。 |
支持/抵抗レベル | ボリンジャーバンドは動的な支持・抵抗として機能し、エントリーおよびイグジットポイントの判断に活用されます。 |
トレンドの確認 | バンドの幅の変化によってトレンドの有無を判断でき、戦略の方向性を補強します。 |
複数の時間枠、ストキャスティクス、ボリンジャーバンド(BB)の相互作用は、EAにおける取引シグナルの信頼性向上とリスク管理強化に大きく貢献します。各時間枠での分析により、BBとストキャスティクスという異なる性質を持つインジケーターの合流点が確認されたときのみ、EAは取引を検討します。このような多次元的なアプローチにより、シグナルの信頼性が高まり、誤った取引のリスクが低減されます。その結果、EAによって生成されるシグナルの精度と信頼性が向上し、トレーダーはより自信を持って取引判断をおこなえるようになります。
戦略の理解
「Signal Pulse」スクリプトは、ボリンジャーバンドとストキャスティクスの整合性に基づき、3つの時間枠(M15、M30、H1)で取引シグナルを生成します。各シグナルの条件は以下のとおりです。
買いシグナル
- ボリンジャーバンドの条件:価格がM15、M30、H1のすべての時間枠でボリンジャーバンドの下限に接触していること。
- ストキャスティクスの条件:すべての時間枠において、ストキャスティクスが売られすぎの状態(一般的に20未満)を示していること。
- 確認要件:上記の2つの条件が、M15、M30、H1のすべての時間枠で同時に満たされていること。
図1:買いの条件
売りシグナル
- ボリンジャーバンドの条件:価格がM15、M30、H1のすべての時間枠でボリンジャーバンドの上限に接触していること。
- ストキャスティクスの条件:すべての時間枠において、ストキャスティクスが買われすぎの状態(一般的に80超)を示していること。
- 確認要件:上記の2つの条件が、M15、M30、H1のすべての時間枠で同時に満たされていること。
図2:売りの条件
このプロセスを下の図で可視化してみましょう。
図3:シグナル生成プロセス
MQL5コード
//+------------------------------------------------------------------+ //| Signal Pulse EA.mq5 | //| Copyright 2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2025, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" // Input parameters input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1; // H1 timeframe input int BB_Period = 20; // Bollinger Bands period input double BB_Deviation = 2.0; // Bollinger Bands deviation input int K_Period = 14; // Stochastic %K period input int D_Period = 3; // Stochastic %D period input int Slowing = 3; // Stochastic slowing input double SignalOffset = 10.0; // Offset in points for signal arrow input int TestBars = 10; // Number of bars after signal to test win condition input double MinArrowDistance = 5.0; // Minimum distance in points between arrows to avoid overlapping // Signal tracking structure struct SignalInfo { datetime time; double price; bool isBuySignal; }; // Arrays to store signal information datetime signalTimes[]; double signalPrices[]; bool signalBuySignals[]; //+------------------------------------------------------------------+ //| Retrieve Bollinger Band Levels | //+------------------------------------------------------------------+ bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle) { int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE); if(handle == INVALID_HANDLE) { Print("Error creating iBands for timeframe: ", timeframe); return false; } double upperBand[], middleBand[], lowerBand[]; if(!CopyBuffer(handle, 1, 0, 1, upperBand) || !CopyBuffer(handle, 0, 0, 1, middleBand) || !CopyBuffer(handle, 2, 0, 1, lowerBand)) { Print("Error copying iBands buffer for timeframe: ", timeframe); IndicatorRelease(handle); return false; } upper = upperBand[0]; middle = middleBand[0]; lower = lowerBand[0]; IndicatorRelease(handle); return true; } //+------------------------------------------------------------------+ //| Retrieve Stochastic Levels | //+------------------------------------------------------------------+ bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value) { int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE); if(handle == INVALID_HANDLE) { Print("Error creating iStochastic for timeframe: ", timeframe); return false; } double kBuffer[], dBuffer[]; if(!CopyBuffer(handle, 0, 0, 1, kBuffer) || // %K line !CopyBuffer(handle, 1, 0, 1, dBuffer)) // %D line { Print("Error copying iStochastic buffer for timeframe: ", timeframe); IndicatorRelease(handle); return false; } k_value = kBuffer[0]; d_value = dBuffer[0]; IndicatorRelease(handle); return true; } //+------------------------------------------------------------------+ //| Check and Generate Signal | //+------------------------------------------------------------------+ void CheckAndGenerateSignal() { double upper1, lower1, middle1, close1; double upper2, lower2, middle2, close2; double upper3, lower3, middle3, close3; double k1, d1, k2, d2, k3, d3; if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) || !GetBollingerBands(Timeframe2, upper2, lower2, middle2) || !GetBollingerBands(Timeframe3, upper3, lower3, middle3)) { Print("Error retrieving Bollinger Bands data."); return; } if(!GetStochastic(Timeframe1, k1, d1) || !GetStochastic(Timeframe2, k2, d2) || !GetStochastic(Timeframe3, k3, d3)) { Print("Error retrieving Stochastic data."); return; } // Retrieve the close prices close1 = iClose(Symbol(), Timeframe1, 0); close2 = iClose(Symbol(), Timeframe2, 0); close3 = iClose(Symbol(), Timeframe3, 0); bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) && (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) && (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition // Check if an arrow already exists in the same region before placing a new one if(buySignal && !ArrowExists(close1)) { Print("Buy signal detected on all timeframes with Stochastic confirmation!"); string arrowName = "BuySignal" + IntegerToString(TimeCurrent()); ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241); ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2); // Store signal data ArrayResize(signalTimes, ArraySize(signalTimes) + 1); ArrayResize(signalPrices, ArraySize(signalPrices) + 1); ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1); signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent(); signalPrices[ArraySize(signalPrices) - 1] = close1; signalBuySignals[ArraySize(signalBuySignals) - 1] = true; } if(sellSignal && !ArrowExists(close1)) { Print("Sell signal detected on all timeframes with Stochastic confirmation!"); string arrowName = "SellSignal" + IntegerToString(TimeCurrent()); ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242); ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2); // Store signal data ArrayResize(signalTimes, ArraySize(signalTimes) + 1); ArrayResize(signalPrices, ArraySize(signalPrices) + 1); ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1); signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent(); signalPrices[ArraySize(signalPrices) - 1] = close1; signalBuySignals[ArraySize(signalBuySignals) - 1] = false; } } //+------------------------------------------------------------------+ //| Check if an arrow already exists within the MinArrowDistance | //+------------------------------------------------------------------+ bool ArrowExists(double price) { for(int i = 0; i < ArraySize(signalPrices); i++) { if(MathAbs(signalPrices[i] - price) <= MinArrowDistance) { return true; // Arrow exists in the same price region } } return false; // No arrow exists in the same region } //+------------------------------------------------------------------+ //| OnTick Event | //+------------------------------------------------------------------+ void OnTick() { CheckAndGenerateSignal(); } //+------------------------------------------------------------------+ //| OnDeinit Function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Clean up the objects long chart_id = 0; for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--) { string name = ObjectName(chart_id, i); if(StringFind(name, "Signal") != -1) { ObjectDelete(chart_id, name); } } Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized."); } //+------------------------------------------------------------------+
コードの分解
このセクションでは、「Signal Pulse EA」の構成要素、動作メカニズム、そしてその機能の背後にあるロジックについて、ステップバイステップで詳しく解説していきます。このセクションでは、「Signal Pulse EA」の構成要素、動作メカニズム、そしてその機能の背後にあるロジックについて、ステップバイステップで詳しく解説していきます。- ヘッダー、プロパティ、入力パラメータ
EAの冒頭では、基本的なメタデータを記載したヘッダーが含まれています。ここには、EAの名称、著作権情報、そして開発元に関するリンクなどが記載されています。しかし、トレーダーにとって特に重要なのは入力パラメータです。これらのカスタマイズ可能な設定により、EAの挙動を自分の取引スタイルに合わせて柔軟に調整することができます。
//+------------------------------------------------------------------+ //| Signal Pulse EA.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Christian Benjamin" #property link "https://www.mql5.com/ja/users/lynnchris" #property version "1.00" // Input parameters input ENUM_TIMEFRAMES Timeframe1 = PERIOD_M15; // M15 timeframe input ENUM_TIMEFRAMES Timeframe2 = PERIOD_M30; // M30 timeframe input ENUM_TIMEFRAMES Timeframe3 = PERIOD_H1; // H1 timeframe input int BB_Period = 20; // Bollinger Bands period input double BB_Deviation = 2.0; // Bollinger Bands deviation input int K_Period = 14; // Stochastic %K period input int D_Period = 3; // Stochastic %D period input int Slowing = 3; // Stochastic slowing input double SignalOffset = 10.0; // Offset in points for signal arrow input int TestBars = 10; // Number of bars after signal to test win condition input double MinArrowDistance = 5.0; // Minimum distance in points between arrows to avoid overlappingこの部分では、異なる時間枠(M15、M30、H1)を指定しており、複数の期間にわたる価格の動きを分析できるようになっています。また、ボリンジャーバンドの期間や偏差といったパラメータ、ストキャスティクスの%Kおよび%Dの期間なども設定しています。さらに、チャート上に買い・売りシグナルを表示するための矢印に関する視覚的な設定も含まれており、重なり合う矢印を回避することで視認性を高めるためのパラメータも用意されています。
- シグナルトラッキングと構造体
次に、取引シグナルの管理において重要な役割を果たすSignalInfo構造体を定義します。この構造体には、シグナルが発生した時刻、そのときの価格、シグナルが買いか売りかといった情報が格納されます。また、これらの情報を動的に保持するために、配列を用いて記録・追跡できるように設定しています。
// Signal tracking structure struct SignalInfo { datetime time; double price; bool isBuySignal; }; // Arrays to store signal information datetime signalTimes[]; double signalPrices[]; bool signalBuySignals[];signalTimes、signalPrices、signalBuySignalsといった配列を使用することで、EAが生成した取引シグナルの記録を明確に保持できます。これにより、複数のシグナルを扱う際にも混乱を防ぎ、効率的に管理することが可能になります。
- インジケーター取得関数
次に、インジケーターの値を取得するための関数について詳しく説明します。ここでは、特にボリンジャーバンドとストキャスティクスの値を取得するために使用される関数に注目します。
//+------------------------------------------------------------------+ //| Retrieve Bollinger Band Levels | //+------------------------------------------------------------------+ bool GetBollingerBands(ENUM_TIMEFRAMES timeframe, double &upper, double &lower, double &middle) { int handle = iBands(Symbol(), timeframe, BB_Period, 0, BB_Deviation, PRICE_CLOSE); if(handle == INVALID_HANDLE) { Print("Error creating iBands for timeframe: ", timeframe); return false; } double upperBand[], middleBand[], lowerBand[]; if(!CopyBuffer(handle, 1, 0, 1, upperBand) || !CopyBuffer(handle, 0, 0, 1, middleBand) || !CopyBuffer(handle, 2, 0, 1, lowerBand)) { Print("Error copying iBands buffer for timeframe: ", timeframe); IndicatorRelease(handle); return false; } upper = upperBand[0]; middle = middleBand[0]; lower = lowerBand[0]; IndicatorRelease(handle); return true; } //+------------------------------------------------------------------+ //| Retrieve Stochastic Levels | //+------------------------------------------------------------------+ bool GetStochastic(ENUM_TIMEFRAMES timeframe, double &k_value, double &d_value) { int handle = iStochastic(Symbol(), timeframe, K_Period, D_Period, Slowing, MODE_SMA, STO_CLOSECLOSE); if(handle == INVALID_HANDLE) { Print("Error creating iStochastic for timeframe: ", timeframe); return false; } double kBuffer[], dBuffer[]; if(!CopyBuffer(handle, 0, 0, 1, kBuffer) || // %K line !CopyBuffer(handle, 1, 0, 1, dBuffer)) { // %D line Print("Error copying iStochastic buffer for timeframe: ", timeframe); IndicatorRelease(handle); return false; } k_value = kBuffer[0]; d_value = dBuffer[0]; IndicatorRelease(handle); return true; }最初の関数であるGetBollingerBandsは、指定された時間枠におけるボリンジャーバンドの上限・中央・下限レベルを取得します。この関数では、まずインジケーターのハンドルを作成し、その作成が成功したかどうかを確認します。すべてが正常であれば、バンドの値を配列にコピーし、後で取引ロジックに使用できるようにします。同様に、GetStochastic関数では、ストキャスティクスの%Kおよび%Dの値を取得します。この関数も同様に、エラーチェックとデータコピーの処理をおこない、常に正確なデータに基づいて意思決定ができるようになっています。
- シグナルのチェックと生成
インジケーターの準備が整ったところで、EAの中核となるロジックを含むCheckAndGenerateSignal関数に移ります。この関数では、前述のインジケーター取得関数を呼び出し、指定されたすべての時間枠におけるボリンジャーバンドとストキャスティクスのデータを取得します。加えて、それぞれの時間枠の最新の終値も取得します。
この関数では、市場の現在の状況に基づいて買いシグナルまたは売りシグナルをチェックします。買いシグナルは、終値がボリンジャーバンドの下限を下回り、かつストキャスティクスの値が5未満(売られすぎ)である場合に発生します。反対に、売りシグナルは、終値が上限バンドを上回り、ストキャスティクスの値が95超(買われすぎ)であるときに発生します。
//+------------------------------------------------------------------+ //| Check and Generate Signal | //+------------------------------------------------------------------+ void CheckAndGenerateSignal() { double upper1, lower1, middle1, close1; double upper2, lower2, middle2, close2; double upper3, lower3, middle3, close3; double k1, d1, k2, d2, k3, d3; if(!GetBollingerBands(Timeframe1, upper1, lower1, middle1) || !GetBollingerBands(Timeframe2, upper2, lower2, middle2) || !GetBollingerBands(Timeframe3, upper3, lower3, middle3)) { Print("Error retrieving Bollinger Bands data."); return; } if(!GetStochastic(Timeframe1, k1, d1) || !GetStochastic(Timeframe2, k2, d2) || !GetStochastic(Timeframe3, k3, d3)) { Print("Error retrieving Stochastic data."); return; } // Retrieve the close prices close1 = iClose(Symbol(), Timeframe1, 0); close2 = iClose(Symbol(), Timeframe2, 0); close3 = iClose(Symbol(), Timeframe3, 0); bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) && (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) && (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition // Check if an arrow already exists in the same region before placing a new one if(buySignal && !ArrowExists(close1)) { Print("Buy signal detected on all timeframes with Stochastic confirmation!"); string arrowName = "BuySignal" + IntegerToString(TimeCurrent()); ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 241); ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrGreen); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2); // Store signal data ArrayResize(signalTimes, ArraySize(signalTimes) + 1); ArrayResize(signalPrices, ArraySize(signalPrices) + 1); ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1); signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent(); signalPrices[ArraySize(signalPrices) - 1] = close1; signalBuySignals[ArraySize(signalBuySignals) - 1] = true; } if(sellSignal && !ArrowExists(close1)) { Print("Sell signal detected on all timeframes with Stochastic confirmation!"); string arrowName = "SellSignal" + IntegerToString(TimeCurrent()); ObjectCreate(0, arrowName, OBJ_ARROW, 0, TimeCurrent(), close1); ObjectSetInteger(0, arrowName, OBJPROP_ARROWCODE, 242); ObjectSetInteger(0, arrowName, OBJPROP_COLOR, clrRed); ObjectSetInteger(0, arrowName, OBJPROP_WIDTH, 2); // Store signal data ArrayResize(signalTimes, ArraySize(signalTimes) + 1); ArrayResize(signalPrices, ArraySize(signalPrices) + 1); ArrayResize(signalBuySignals, ArraySize(signalBuySignals) + 1); signalTimes[ArraySize(signalTimes) - 1] = TimeCurrent(); signalPrices[ArraySize(signalPrices) - 1] = close1; signalBuySignals[ArraySize(signalBuySignals) - 1] = false; } }
さらに、チャート上にシグナルを示す矢印を配置する前に、関数はArrowExistsを呼び出して既存の矢印が重複していないかを確認します。問題がなければ、適切な矢印を描画し、シグナルに関する情報を前述の配列に保存します。
- 矢印存在チェック
チャートを整然と保つために、ArrowExists関数は現在のシグナル価格付近に既存の矢印がないかどうかをチェックする重要な役割を果たします。これにより、複数の矢印が重なって混乱を招くのを防ぎます。具体的には、新しいシグナル価格をsignalPrices配列に格納された価格と比較し、既存の矢印が十分に近い場合は新しい矢印の作成をスキップするかどうかを判断します。
//+------------------------------------------------------------------+ //| Check if an arrow already exists within the MinArrowDistance | //+------------------------------------------------------------------+ bool ArrowExists(double price) { for(int i = 0; i < ArraySize(signalPrices); i++) { if(MathAbs(signalPrices[i] - price) <= MinArrowDistance) { return true; // Arrow exists in the same price region } } return false; // No arrow exists in the same region }
- OnTick関数とOnDeinit関数
最後に、OnTick関数とOnDeinit関数について説明します。OnTick関数は、新しいマーケットティックが発生するたびに呼び出され、EAが常に最新の状態で反応できるようにします。この関数は、最新データに基づいて取引シグナルを再評価するために、CheckAndGenerateSignal関数を呼び出します。
一方、OnDeinit関数は、EAが削除されたり端末が閉じられたりする際に呼び出されます。この関数の役割は、EAによって作成されたグラフィカルオブジェクト(特に売買シグナルを示す矢印)を削除し、チャートを整理された状態に保つことです。
//+------------------------------------------------------------------+ //| OnTick Event | //+------------------------------------------------------------------+ void OnTick() { CheckAndGenerateSignal(); } //+------------------------------------------------------------------+ //| OnDeinit Function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // Clean up the objects long chart_id = 0; for(int i = ObjectsTotal(chart_id) - 1; i >= 0; i--) { string name = ObjectName(chart_id, i); if(StringFind(name, "Signal") != -1) { ObjectDelete(chart_id, name); } } Print("Multitimeframe Bollinger-Stochastic Analyzer deinitialized."); }
また、Signal Pulse EAでは、ストキャスティクスの閾値レベルを調整し、最も信頼性の高いシグナルのみが生成されるようにしています。これらの調整は、市場が極端な状態(買いシグナルの場合は売られ過ぎ、売りシグナルの場合は買われ過ぎ)にあることを確認してから取引をおこなうことに重点を置いています。
- 売られ過ぎ状態:買いシグナル
bool buySignal = (close1 <= lower1 && close2 <= lower2 && close3 <= lower3) && (k1 < 5 && k2 < 5 && k3 < 5); // Oversold condition
買いシグナルの場合、価格は3つの時間枠(M15、M30、H1)すべてでボリンジャーバンドの下限以下である必要があり、これは強い下落圧力を示しています。さらに、ストキャスティクスの%K値は3つの時間枠すべてで5未満でなければなりません。この値は極端な売られ過ぎの状態を示しており、市場が上昇に転じる可能性が非常に高いことを意味します。より厳しい閾値の「5未満」に設定することで、EAは反転の確率が著しく高いシグナルのみを考慮するようにしています。
- 買われ過ぎ状態:売りシグナル
bool sellSignal = (close1 >= upper1 && close2 >= upper2 && close3 >= upper3) && (k1 > 95 && k2 > 95 && k3 > 95); // Overbought condition
売りシグナルの場合、価格は3つの時間枠すべてでボリンジャーバンドの上限以上である必要があり、これは強い上昇モメンタムがありながら、まもなく反転する可能性を示しています。さらに、ストキャスティクスの%K値はすべての時間枠で95を超えている必要があり、これは極端な買われ過ぎの状態を示し、市場が弱気に転じる可能性が高いことを意味します。この厳しい条件により、EAは中程度の価格変動やレンジ相場での誤った売りシグナルを回避します。
テストと結果
- 履歴データを使ったバックテスト
1.履歴データを読み込む
バックテストを開始するには、対象となる銘柄および時間枠に対応した高品質なティックレベルの履歴データを読み込むことが必要です。このデータはEAのパフォーマンス評価の基盤となるため、正確で信頼できるものでなければなりません。データに誤りや不整合があると、EAの性能評価に誤った結論をもたらす可能性があります。
データを読み込んだ後は、MetaTraderのストラテジーテスターにて必要なパラメータを設定します。設定項目は以下の通りです。2.テストパラメータを設定する
- Symbol:取引対象となる通貨ペアや資産を選択します。
- Period:EAで使用している時間枠と同じものを設定します(例:M15、M30、H1)。
- Spread:取引コストをリアルにシミュレートするため、現実的な値または固定スプレッドを設定します。
- Optimization:ボリンジャーバンドの期間やストキャスティクスの閾値など、入力パラメータを調整して最適なパフォーマンスを探ります。
3.結果を評価するテストパラメータを設定したら、出力されたメトリックを分析します。
- 収益性:EAの純利益やプロフィットファクターから全体の収益性を評価します。
- リスク:最大ドローダウンを確認し、EAのリスク許容度を把握します。
- 勝率と取引頻度:勝ちトレードの割合や取引回数を分析し、異なる市場環境でのEAの動きを理解します。
以下に示すテスト結果をご覧ください。
図4:テスト結果1
図5:テスト結果2
上の図はEAのパフォーマンステストを示しています。GIFでは、検出されたすべてのシグナルのログ記録を確認できます。要件を満たす結果が得られるまで、入力パラメータ、時間枠、ストキャスティクスのレベルを変更してさらにテストをおこなうことが可能です。
結論
この記事では、ボリンジャーバンドとストキャスティクスのインジケーターを組み合わせ、M15、M30、H1の複数時間枠で取引シグナルを生成する「Signal Pulse」EAを開発しました。複数の時間枠で買われ過ぎ・売られ過ぎの状態が一致する場合のみシグナルを検出することで、成功確率を高めています。さまざまな市場環境における徹底的なバックテストが不可欠です。今後の改良点としては、トレンド方向のフィルター追加、高度なリスク管理機能、異なる市場タイプに応じたシグナルロジックの洗練などが考えられます。トレーダーの皆さんには、包括的な取引戦略の一環として、ご自身の戦略やテクニックと組み合わせて「Signal Pulse」を活用されることをおすすめします。
日付 | ツール名 | 詳細 | バージョン | アップデート | 備考 |
---|---|---|---|---|---|
01/10/24 | ChartProjector | 前日のプライスアクションをゴースト効果でオーバーレイするスクリプト | 1.0 | 初回リリース | Lynnchris Tool Chestの最初のツール |
18/11/24 | Analytical Comment | 前日の情報を表形式で提供し、市場の将来の方向性を予測する | 1.0 | 初回リリース | Lynnchris Tool Chestの2番目のツール |
27/11/24 | Analytics Master | 2時間ごとに市場指標を定期的に更新する | 1.01 | v.2 | Lynnchris Tool Chestの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 |
09/01/2025 | Signal Pulse | 多時間枠分析ツール | 1.0 | 初回リリース | ツール番号7 |
MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/16861





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索