English Deutsch
preview
MQL5でボリンジャーバンド取引戦略を実装する:ステップごとのガイド

MQL5でボリンジャーバンド取引戦略を実装する:ステップごとのガイド

MetaTrader 5トレーディング | 9 10月 2024, 14:03
45 0
Kikkih25
Kikkih25

はじめに

金融取引のダイナミックな世界では、テクニカル指標の活用が大きな影響を与える可能性があります。その中でも、ボリンジャーバンドは、価格のボラティリティやトレンドの強さを基にエントリおよびエグジットポイントを決定するための効果的なテクニックです。本記事では、MetaTrader 5のMQL5プログラミング言語を用いて、ボリンジャーバンドを活用した取引選択の自動化について解説します。

このステップごとのチュートリアルに従うことで、トレーダーは、特定の市場条件に基づき売買注文を実行するエキスパートアドバイザー(EA)を構築することができます。ボリンジャーバンドの設定方法、取引ポジションの管理、注文の実行およびエラー管理といった重要なトピックもすべて網羅されています。このチュートリアルは、開発経験やアルゴリズム取引の知識がどの程度であっても、トレーダーが取引手法を設計し、改善するための確かな基礎を提供します。

本記事では、以下のトピックについて取り上げます。

  1. ボリンジャーバンド戦略の定義
  2. ボリンジャーバンド戦略の説明
  3. MQL5によるステップごとの実装
  4. 結論


ボリンジャーバンド戦略の定義

ボリンジャーバンド戦略は、移動平均を中心にプロットされた複数のバンドを利用して、取引機会を判断するテクニカル分析手法です。戦略は、下部バンド(中央値バンドから標準偏差の倍数を引いたもの)、上部バンド(中央値バンドに標準偏差の倍数を加えたもの)、そして中央値バンド(単純移動平均)という3つのバンドで構成されます。トレーダーは、価格がこれらのバンドとどのように相互作用するかを基に、買われすぎや売られすぎの状況を判断し、売買シグナルを特定するほか、価格のブレイクアウトや反転を予測することができます。


ボリンジャーバンド戦略の説明 

ボリンジャーバンド戦略は、トレーダーが市場のボラティリティを評価し、取引のチャンスを見つけるために使用する代表的なテクニカル分析ツールです。この戦略はジョン・ボリンジャーによって考案され、3つの主要な要素で構成されています。

  1. 中央値バンド(SMA):一定期間の資産の終値を基に計算される単純移動平均(SMA)です。このバンドは、指定期間中の平均価格を示し、全体の基準点として機能します。
  2. 上部バンド:標準偏差をSMAに加えることで算出され、中央値バンドの上に位置します。これは価格レンジの上限を示し、買われ過ぎや価格変動が大きいことを示唆します。計算式は次の通りです:[{Upper Band} = {Middle Band} + {Standard Deviation} {Band Deviation&}]
  3. 下部バンド:SMAから標準偏差を差し引くことで計算され、中央値バンドの下に表示されます。これは価格レンジの下限を示し、ボラティリティの低下や売られ過ぎの可能性を示唆します。計算式は次の通りです:[{Lower Band} = {Middle Band}  - {Standard Deviation}] 

戦略の主要な側面

価格の動きとバンドの相互作用:価格が下部バンドに接近または接触すると、売られすぎと判断されることが多く、逆に上部バンドに接近または接触すると、買われすぎとみなされます。トレーダーはこの価格とバンドの相互作用を利用して、売買シグナルの発生を見極めることができます。

  • バンドスクイーズ:ボリンジャーバンドの重要な概念のひとつに「バンドスクイーズ」があります。これは、バンドが収縮して互いに接近・収束する現象で、低ボラティリティの兆候です。この状況は、大きな値動きやブレイクアウトの前触れであることが多いため、トレーダーはスクイーズ発生時に取引の機会を見逃さないよう注視しています。



  • トレンドの確認:ボリンジャーバンドは、他の指標と組み合わせることでトレンドの確認に役立ちます。例えば、強い上昇トレンドは、価格が十分な出来高を伴って上側のバンドを上抜けることで確認でき、逆に下降トレンドは、価格が下側のバンドを下抜けることで確認されます。                                       

戦略の適用

ボリンジャーバンド戦略を活用することで、トレーダーは価格水準を参考にし、十分な情報に基づいた意思決定をおこなうことができます。典型的な戦略としては、反発を期待して下部バンドに触れたり、下抜けたりした際に買い、プルバックを見込んで上部バンドに触れたり、上抜けたりした際に売ることが挙げられます。この戦略は、ボラティリティの急上昇やトレンドの反転の可能性を見抜くのにも役立ちます。


MQL5によるステップごとの実装 

まず、取引操作の設定から始めます。発注と注文管理は、MQL5でボリンジャーバンド戦略を実装するために処理しなければならない取引操作です。これらの操作は、MQL5言語に組み込まれた取引ライブラリによってより簡単になります。取引ライブラリの初期設定と、主要な取引ロジックをどのようにサポートするかについて説明しましょう。

#include<Trade\Trade.mqh> // Include the trade library

取引ライブラリが提供する関数を利用するには、CTradeクラスのインスタンスを構築しなければなりません。

CTrade trade; // Create an instance of the CTrade class  

取引ライブラリを追加し、CTradeオブジェクトを初期化することで、注文の開始、終了、変更などの取引操作にそのメソッドを使用することができます。CTradeオブジェクトは複数の取引方法を提供します。私たちのボリンジャーバンドEAでは、onTick関数で指定された取引状況によって売買注文を開始するためにこれを利用しています。取引オブジェクトは、買い注文と売り注文を出すために使用されます。価格がボリンジャーバンドの下部バンドを下回ると、EAによって買い注文が出されます。

この構成により、取引活動を効果的に監督し、強力な取引ロジックの構築に集中することができます。トレーダーは、{CTrade{注文を出すためのメソッド}}の使い方を学ぶことで、EAが市場の状況に反応し、取引を実行する方法を改善することができます。

次に、取引戦略をカスタマイズすることによって入力を設定します。MQL5のinput宣言とconst宣言によって、トレーダーは取引戦略のさまざまな側面を修正し、設定することができます。市場の状態や取引の好みによって、これらの入力を変更することができます。これらのパラメータの重要性と、ボリンジャーバンド取引法がこれらのパラメータによってどのような影響を受けるかについて説明しましょう。

変数の入力は、コードに変更を加えることなく、MetaTrader端末から変更できます。inputキーワードはそれらを宣言するために使われます。ボリンジャーバンドEAは以下の入力パラメータを使用します。

 // Input parameters for the Bollinger Bands strategy
 input int BandPeriod = 30;
 input double BandDeviation = 2.0;
 input double LotSize = 0.2;
 input int Slippage = 3;
 const double StopLoss = 70;
 const double TakeProfit = 140;

BandPeriodは、ボリンジャーバンドの計算で使用する期間の数です。時間が短いほど価格変動に対するバンドの感度が高まる一方、期間が長いとバンドが平滑化され、売買シグナルが減少する可能性があります。市場のボラティリティや取引プランのニーズに応じて、これを変更します。

BandDeviationは、移動平均から乖離した標準偏差をカウントして、上下のバンドを決定します。より広く、より触れにくいバンドは、より大きな乖離をもたらし、売買シグナルを弱める可能性があります。ダイバージェンスが小さいほど、ndsは狭くなり、シグナルの頻度は高くなります。この値を調整することで、価格変更に対するバンドの責任を調整します。

LotSizeはインパクトのための資産額。各取引の出来高を確定します。ロットサイズを大きくすることで収益が増加しますが、口座の大きさやリスク許容度に応じて変更されます。

Slippageは、得点の順位に影響を与える際に許される最大のスリッページのことです。注文が意図された価格に近い価格で満たされるようにアシストし、注文間のわずかな価格変動を考慮します。市場の状態と資産の流動性に基づいて調整します。

定数は、コンパイル時に設定され、実行時には変更できない値です。これらの定義にはconstキーワードを使用します。

const double StopLoss = 70;           
const double TakeProfit = 140;   

StopLossは、エントリレベルのpriImpactStopLossからのポイントごとの分離です。もし市場が指定したポイントだけ不利に動いたら、取引を終了することで損失を抑えることができます。市場のボラティリティとご自分のリスク管理ガイドラインに基づいて、この数値を決定すべきです。

TakeProfitは、entImpactactoとテイクプロフィットレベルのポイントごとの差です。市場が好転したときに取引を終了することで、収益を維持します。カスタマイズのポイントはいくつかある。希望する利益水準と市場の状況に応じて調整します。

トレーダーは、入力パラメータと定数パラメータを設定することで、ボリンジャーバンド取引手法を自分の取引スタイルや市場の状態に合わせて調整することができます。パラメータを変更することで、EAのパフォーマンスを微調整し、取引目的に合わせることができます。取引パフォーマンスを最大化し、リスクを効率的に管理するためには、これらの要因を理解し、それらがどのように戦略に影響するかを理解することが不可欠です。

その後、整数変数を見てみましょう。スクリプト全体を通して、このハンドルは、表示を参照し、対話するために必要です。

int Bb_Handle; // Handle for the Bollinger Bands indicator

このハンドルは、MQL5のボリンジャーバンド指標を扱う上で欠かせないものです。指標データとリソースの管理を合理化することで、取引戦略を円滑かつ効果的に実行できることを保証します。

このチュートリアルでは、ボリンジャーバンドを取引ロジックとするEAのOnInit関数について説明します。EAが再初期化されたとき、またはチャートにアタッチされたとき、OnInit関数が一度だけ呼び出されます。この関数は、指標に必要なハンドルを作成し、開始パラメータを設定します。

EAでは、OnInit関数の前に、使用される、あるいは使用されない入力パラメータをいくつか定義しています。これらのパラメータには、期間、ボリンジャーバンドの偏差、ロットサイズ、スリッページ、ストップが含まれます。

ボリンジャーバンド指標のハンドルを作成することは、OnInit関数の主要な責任です。これはiBands関数を使っておこないます。

int OnInit()
  {
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE);

ここでは、指定したパラメータでボリンジャーバンド指標を作成し、ハンドルをBb_Handleに代入しようとしています。

ハンドルの作成が成功したかどうかを確認することは非常に重要です。ハンドルが無効な場合、この問題を適切に管理するための指示がなされていないため、EAはINIT_FAILEDを返し、エラーメッセージを表示すべきです。

if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator");
      return(INIT_FAILED);
     }

OnInit関数は、指標ハンドルが有効であれば、初期化手順が正常に終了したことを示すためにINIT_SUCCEEDEDを返すべきです。

return(INIT_SUCCEEDED);
  }

すべてのステップを組み合わせると、OnInit関数は以下のようになります。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Create the Bollinger Bands indicator handle
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE); 
    { 
    if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator"); 
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }

OnInit関数は、EAを構成する要素を設定するために不可欠です。アルゴリズムは、ボリンジャーバンド指標のハンドルを確立し、あらゆるリスクを管理することで、取引ロジックを実行する準備が整っていることを確認します。

次に、OnDeinit関数を見てみましょう。この関数は、基本的な取引ロジックであるアルゴリズム取引にとって非常に重要です。EAがリソースをクリーンアップすることで、問題を回避し、取引を安定させることができます。EAがチャートから削除されるか、プラットフォームが閉じられると、OnDeinit関数がトリガーされます。その責任は、EAの操作中に割り当てられた指標ハンドルのようなリソースを解放することです。これにより、プラットフォームのパフォーマンスがメモリーリークや永続プロセスによって影響を受けないことが保証されます。

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release the Bollinger Bands indicator hande
   IndicatorRelease(Bb_Handle);
  }

ボリンジャーバンド指標のハンドルのリリースは、EAのOnDeinit関数の主な責任です。IndicatorRelease関数が使用されます。

次に、EAの心臓部であるOnTick関数に移ります。現在のチャート銘柄の価格更新が新しいティックを受信するたびにトリガーされます。相場状況に対するEAの反応を制御する基本的な取引ロジックは、この関数に含まれています。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
    double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;
    
     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];
     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
     
     // Buy signal: price is below the lower band and no open positions 
    if(price < lower && ! IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
      // Sell signal: price is above the upper band no open positions
      else if(price > upper && ! IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

理解しやすいように、OnTick関数の詳細な内訳を以下に示します。

ボリンジャーバンドの値の定義と取得:ボリンジャーバンドの現在値を取得するのが最初の作業です。CopyBuffer関数はこの目的のために利用され、指標値を配列にコピーします。

double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;

バンド値を変数に割り当てる:配列の値は、参照しやすいように変数に代入されます。

     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];

現在の売値と買値を取得する:ここで取引をおこなうには、現在の売値と買値が必要です。

     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);

ボリンジャーバンドに基づく取引ロジック:tBuy条件の価格は取引ロジックの基礎となります。

  • 買い条件:未決済ポジションがなく、価格が下部バンドより下にある場合に買い注文を出します。 
   // Buy signal: price is below the lower band and no open positions 
    if(price < lower && ! IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
  • 売リ条件:未決済のポジションがなく、価格が上部バンドを超えている場合に売り注文を出します。
 // Sell signal: price is above the upper band no open positions
      else if(price > upper && ! IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

私たちのボリンジャーバンド取引戦略では、真の操作はOnTick関数で行われます。ボリンジャーバンドの値を注意深く取得し、それに基づいて売買判断をおこなうことで、信頼性の高い自動売買戦略を開発することができます。この関数のあらゆる側面が、より効率的なデバッグと改善を促進し、私たちのEAがさまざまな市場シナリオにおいて最高の効率で動作することを保証します。

メインのOnTick関数に加え、私たちのエキスパートアドバイザーは、ポジションを管理し、利益確定、損切りレベルを決定し、シームレスな取引操作を保証するためのサポート関数に依存しています。サポート関数は、取引戦略の回復力と有効性を維持するために不可欠です。ステップごとにボリンジャーバンドEAで利用されているサポート関数について説明します。

最初のサポート関数は、ポジションを確認します。isPositionOpen関数は、指定された銘柄にこの時点でポジションがあったかどうかを判定します。これは、EAが同じ銘柄に対して同時に複数のポジションを建てないようにするために必要です。

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }

isPositionOpen関数のチェックのステップごとの内訳を以下に示します。

  • すべてのポジションをループします。 
for(int i = 0;  i< PositionsTotal(); i++)
    }

利用可能なポジションの総数を表示します。インデックスを使用してすべてのポジションを反復処理します。

  • インデックスによるポジションの選択:  
if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       

この関数は、インデックスiの位置を選択します。PositionGetString を使用して選択位置の銘柄を取得します。

  • 銘柄をチェックし、mの場合再び実行します。
if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     

ポジションの銘柄と入力銘柄を比較します。一致した場合はtrueを返します。

  • 一致しない場合はfalseを返します。
return false;
    }

すべてのポジションをループした後、銘柄のポジションが特定されない場合はfalseを返します。

EAの2番目のサポート関数は、銘柄のすべてのポジションをクローズします。CloseAllPositions関数は、指定された銘柄について、すべてのポジションをクローズします。リスク管理や戦略の修正に役立ちます。

//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        

銘柄ポジションをクローズするためのステップを以下に示します。

  • すべてのポジションを逆ループします。
for(int i = 0;  i< PositionsTotal(); i++)    

ループした後、スタート地点に戻ります。ポジションクローズがインデックスの順序を変更しないことを保証します。

  • インデックスとチェック銘柄でポジションを選択します。

   if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol

ポジションを選択し、入力銘柄と銘柄が一致するかどうかを判断します。

  • ポジションチケットとタイプを取得します。

      ulong ticket = PositionGetInteger(POSITION_TICKET);

ポジションのチケット番号を取得します。

  • 買いまたは売りのポジションをクローズします。

if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
        trade.Sell(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
  else if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
        trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");

買いポジションを売りで決済し、売りポジションを売りで決済し、売りポジションを買いで決済します。今現在の売値と買値を利用します。

  • 注文を処理するために一時停止します。
      // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }

次のスロットに進む前に、注文が処理されたことを確認するために少し間を置きます。

次は最後のサポート関数です。ストップロスとテイクプロフィットのレベルを計算します。ストップロス(SL)とテイクプロフィット(TP)のレベルは、現在の価格と取引の買い/売りステータスを使用して、CalculateSLTP機能によって決定されます。

//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

ストップロスとテイクプロフィットのレベルを計算するためのステップごとの内訳を以下に示します。

  • 関数のパラメータを定義します。

void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)

sl:ストップロスレベル。

tp:テイクプロフィットの閾値を示します。

price:現行価格。isBuy:取引が買い(true)か売り(false)かを示すブール値。買う際にSLとTPを決定します。

if(isBuy)
  {
    sl = price - StopLoss * _Point;
    tp = price + TakeProfit * _Point;
  }

StopLoss:現在の利食いから定義されたストップロス(ポイント)を差し引きます。

TakeProfit:定義されたテイクプロフィット(ポイント)を現在のCalculate SLと売り取引のTPに足します。

else
  {
    sl = price + StopLoss * _Point;
    tp = price - TakeProfit * _Point;
  }
}

StopLoss:現在のテイクプロフィットを指定されたストップロス(ポイント)だけ増やします。

TakeProfit:現在の価格から指定したTakeProfit(ポイント)を引きます。

このサポート関数の完全なコードは以下の通りです。

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }
//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        
//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

EAの基本的なロジックをサポート関数を使って管理し、整理しています。これは、EAがスムーズに動作し、ポジションが正確に管理され、ボリンジャーバンド取引戦略におけるリスク管理レベルがコンピュータで管理されていることを確認するものです。これらのサポート関数を理解し適用することで、MQL5取引アルゴリズムの信頼性と効率を向上させることができます。

記事の全コードは以下の通りです。

//+------------------------------------------------------------------+
//|                                               BollingerBands.mq5 |
//|                                  Copyright 2024, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

 #include<Trade\Trade.mqh> // Include the trade library
 CTrade trade; // Create an instance of the CTrade class  

 // Input parameters for the Bollinger Bands strategy
 input int BandPeriod = 30;
 input double BandDeviation = 2.0;
 input double LotSize = 0.2;
 input int Slippage = 3;
 const double StopLoss = 70;
 const double TakeProfit = 140;
 
 int Bb_Handle; // Handle for the Bollinger Bands indicator 

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   // Create the Bollinger Bands indicator handle
   Bb_Handle = iBands(_Symbol, _Period, BandPeriod, BandDeviation, 0, PRICE_CLOSE); 
    { 
    if(Bb_Handle == INVALID_HANDLE)
     {
      Print("Error creating Bollinger Bands indicator"); 
      return(INIT_FAILED);
     }
   return(INIT_SUCCEEDED);
  }
 
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   // Release the Bollinger Bands indicator hande
   IndicatorRelease(Bb_Handle);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
    double upperBand[], lowerBand[], middleBand[];
   
    // Copy the Bollinger Bands values into arrays
    if(CopyBuffer(Bb_Handle, 0, 0, 1, upperBand) <= 0||
      (CopyBuffer(Bb_Handle, 1, 0, 1, middleBand) <= 0||
      (CopyBuffer(Bb_Handle, 2, 0, 1, lowerBand) <= 0||
   {
     Print("Error copying band values");
     return;
    
     double upper = upperBand[0];
     double lower = lowerBand[0];
     double middle = middleBand[0];
     double price = Close[0];
     double Ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
     double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
     
     // Buy signal: price is below the lower band and no open positions 
    if(price < lower && ! IsPositionOpen(_symbol))
      {
       double sl, tp;
       CalculateSLTP(sl, tp, price, true);
      if(trade.Buy(LotSize, _symbol, Ask, sl, tp, "Buy Order"))
        Print("Buy order opened at price: ", price);
      else
      { 
       Print("Error opening BUY order:", trade.ResultRetcode());
     }
      // Sell signal: price is above the upper band no open positions
      else if(price > upper && ! IsPositionOpen(_symbol))
       {
        double sl, tp;
        CalculateSLTP(sl, tp, price, false);
       if(trade.Sell(LotSize, _Symbol, Bid, sl, tp, "Sell Order"));
         Print("Sell order opened at price:", Price);
      else
         print("Error opening SELL order:", trade.ResultRetcode())
    }
  }

//+------------------------------------------------------------------+
//| Check if there's an open position for a symbol                   |
//+------------------------------------------------------------------+
   
   bool IsPositionOpen(string symbol)
   }
    for(int i = 0;  i< PositionsTotal(); i++)
    }
     if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
       return true;
     {
      return false;
    }
//+------------------------------------------------------------------+
//|Close all positions for a symbol                                  |
//+------------------------------------------------------------------+
   void CloseAllPositions(string symbol)
  {
   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
    if(PositionSelectByIndex(i) && PositionGetString(POSITION_SYMBOL) == symbol)
     {
      ulong ticket = PositionGetInteger(POSITION_TICKET);
    if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
         trade.sell(LotSize, symbol, symbolInfoDouble(symbol, SYMBOL_BID), Slippage, 0, "Close Buy");
     {
     if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL)
          trade.Buy(LotSize, symbol, SymbolInfoDouble(symbol, SYMBOL_ASK), Slippage, 0, "Close Sell");
          // Wait for order to be processed before continuing
            Sleep(1000);
           }
          }
         }
        
//+------------------------------------------------------------------+
//| Calculate Stop Loss and Take Profit levels                       |
//+------------------------------------------------------------------+
   void CalculateSLTP(double &sl, double &tp, double price, bool isBuy)
   {
    if(isBuy)
     {
      sl = price - StopLoss *_Point;
      tp = price + TakeProfit *_Point;
     }
     else 
      {
       sl = price + StopLoss *_Point;
       tp = price - TakeProfit *_Point;
      }
     }

お疲れ様です。これで、取引シグナルを生成するためのスマートマネー取引コンセプトシステム、ボリンジャーバンド取引戦略を作成しました。


バックテスト結果

ストラテジーテスターでテストした結果は以下の通りです。

グラフ

結果


2016年から2019年にかけて、この戦略は1425件の取引を実行し、857件が利益を持って決済されました。これは、損失となった取引よりも20.28%多い結果です。           

使用されているパラメータはデフォルトであるため、トレーダーは自分の取引システムに合わせて調整することができます。以下は、使用されたパラメータです。

テストに使用した設定は以下の通りです。


結論

この記事では、MQL5でボリンジャーバンド取引戦略を自動化するための基本的なステップを解説しました。戦略の基本的な定義や説明をおこない、MQL5での具体的な実装方法を示しました。トレーダーは、この記事で紹介した知識を活用して、最終的により良い結果を得るために最適化可能な、より高度なボリンジャーバンド戦略を開発できるでしょう。

免責条項:本記事のコードは教育目的に限られており、投資に関する専門的なアドバイスとして扱うべきではありません。ご自身の取引スタイルに合わせたシステムの構築や最適化を行う際は、慎重に知識を活用してください。

この記事が、より最適化されたボリンジャーバンド戦略を構築するための足がかりとなれば幸いです。この記事で使用した例に必要なファイルも添付していますので、コードを研究し、ご自身の戦略に適用して最良の結果を目指してください。

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

添付されたファイル |
BollingerBands.mq5 (5.15 KB)
古典的な戦略をPythonで再構築する(第3回):高値更新と安値更新の予測 古典的な戦略をPythonで再構築する(第3回):高値更新と安値更新の予測
本連載では、古典的な取引戦略を実証的に分析し、AIを用いてそれらの改善が可能かどうかを検証します。本日の議論では、線形判別分析モデルを用いて高値更新と安値更新の予測に挑戦します。
MQL5とデータ処理パッケージの統合(第1回):高度なデータ分析と統計処理 MQL5とデータ処理パッケージの統合(第1回):高度なデータ分析と統計処理
統合により、MQL5から生の財務データをJupyter Labのようなデータ処理パッケージにインポートし、統計テストを含む高度な分析をおこなうシームレスなワークフローが実現します。
データサイエンスと機械学習(第28回):AIを使ってEURUSDの複数の先物を予測する データサイエンスと機械学習(第28回):AIを使ってEURUSDの複数の先物を予測する
多くの人工知能モデルでは単一の将来値を予測することが一般的ですが、この記事では、機械学習モデルを用いて複数の将来値を予測するという強力な手法について掘り下げていきます。このアプローチは「多段階予測」として知られ、明日の終値だけでなく、明後日以降の値も予測することが可能です。多段階予測をマスターすることで、トレーダーやデータサイエンティストはより深い洞察を得ることができ、情報に基づいた意思決定を行うことで予測能力と戦略立案を大幅に強化することができます。
独自のLLMをEAに統合する(第5部):LLM(I)による取引戦略の開発とテスト-微調整 独自のLLMをEAに統合する(第5部):LLM(I)による取引戦略の開発とテスト-微調整
今日の人工知能の急速な発展に伴い、言語モデル(LLM)は人工知能の重要な部分となっています。私たちは、強力なLLMをアルゴリズム取引に統合する方法を考える必要があります。ほとんどの人にとって、これらの強力なモデルをニーズに応じて微調整(ファインチューニング)し、ローカルに展開して、アルゴリズム取引に適用することは困難です。本連載では、この目標を達成するために段階的なアプローチをとっていきます。