English Deutsch
preview
MetaTrader 5のEMAクロスオーバーに基づくカスケード注文取引戦略

MetaTrader 5のEMAクロスオーバーに基づくカスケード注文取引戦略

MetaTrader 5トレーディング | 4 9月 2024, 09:36
32 0
Kikkih25
Kikkih25

はじめに 

この記事では、MetaTrader 5向けのMetaQuotes Language 5(MQL5)を使用し、EAにおけるカスケード注文取引戦略をデモンストレーションします。このMQL5 EAの記事では、移動平均クロスオーバーを取引戦略の基礎として活用し、MetaTrader 5プラットフォーム上で取引の自動選択を実現します。ポジションの初期化、調整、監視に不可欠な機能を組み込み、効果的な注文管理のためにTrade.mqhライブラリを利用します。

まず、あらかじめ設定された期間を持つ2つの指数移動平均(EMA)を手法の一部として使用します。この移動平均線がクロスすると、そのクロスの方向に基づいて売買シグナルが発生します。注文にはテイクプロフィットとストップロスが設定されており、市場の動向に合わせて動的に調整されます。

さらに、このスクリプトには新しいバーを識別するルーチンが含まれています。これにより、取引判断が完了したローソク足の形成に基づいて行われることが保証されます。また、利益目標達成時に現在のポジションを調整する機能も提供されています。

全体として、このEAは、MQL5を活用し、自動執行とテクニカル指標に基づいて、あらかじめ設定されたルールに従い取引を行うことで、システマティックな取引戦略を実践する方法を示しています。

この記事では、以下のトピックをカバーします。

  1. カスケード注文取引戦略の説明
  2. MQL5におけるEAの実装
  3. 結論


カスケード注文取引戦略の説明 

カスケード注文取引戦略とは、前の注文の結果や条件を基にして、次の注文を決定する手法を指します。この戦略は、市場の動向とあらかじめ設定されたルールに基づき、エントリやポジションサイズを管理し、最適化するために頻繁に使用されます。以下は、カスケード注文を使った取引戦略がどのように運用されるかを詳細に説明したものです。

カスケード注文取引戦略の主要な要素は以下の通りです。

  1. 連続発注:カスケード注文戦略では、事前に定めたイベントや条件に応じて、取引が連続的に開始されます。初回の注文は、例えば特定のテクニカル指標のシグナルに反応して発注されることが考えられます。
  2. 条件付き注文:将来の注文は、先行する取引結果や市場状況に基づいて発注されます。市場が有利な方向に動いた場合、ポジションを拡大するための追加注文がおこなわれます。
  3. スケーリング:カスケード戦略では、リスクをコントロールし、利益の最大化を目指してポジションを徐々に増やすことが多いです。一方、スケールアウトとは、利益目標が達成された時や市場が不利な方向に動いた際に、ポジションサイズを縮小する手法です。
  4. リスク管理:損失を最小限に抑えるためには、カスケード手法において効果的なリスク管理が不可欠です。これには、各注文に対してストップロスの閾値を設定するか、ポジションの変化に応じて動的に変更することが重要です。

利益確定:一定の条件が満たされた際に、利益を確保するための行動を取ります。取引の各段階で、注文には利益目標が設定されており、トレーダーは利益を確保しつつ、市場状況に応じてさらなる利益の可能性を追求します。

以下は、カスケード注文取引戦略をまとめたグラフです。

カスケード注文取引戦略


MQL5におけるEAの実装

まず、MQL5のTrade.mqhライブラリは、取引活動を容易にする強力かつ実用的なライブラリで、ポジションや注文のオープン、変更、削除のためのハイレベルなインターフェイスを提供します。Trade.mqhをインクルードすると、CTradeクラスにアクセスできるようになります。CTradeクラスは、取引活動の複雑な詳細の多くを簡素化してカプセル化し、コードの読み取り能力と維持能力を向上させます。

#include <Trade/Trade.mqh>
CTrade obj_Trade;

Trade.mqhをインクルードした後、obj_Tradeとしてインスタンス化されたCTradeクラスにアクセスできます。取引のための多くの機能がCTradeクラスにカプセル化されていることは知っての通りです。以下はCTradeクラスが提供する主な機能の一部です。

  1.  注文を出す
  2.  注文の変更
  3.  注文の終了

次に、取引戦略の運用において非常に重要な役割を果たし、EAでさまざまな機能を担うグローバル変数について説明します。それぞれのグローバル変数とその役割について詳しく見ていきましょう。

  •  整数の変数

int handleMAFast;
int handleMASlow;

OnInit関数によって計算された低速平均指標と高速平均指標のハンドル(ID)が格納されます。これらの指標の現在値を取得するには、ハンドラがそれらのバッファにアクセスする必要があります。

  • 移動平均のためのdouble配列

double maSlow[],maFast[];

指標バッファから得られる高速平均と低速平均の値は、これらの配列に保持されます。分析や取引判断のために、指標の現在値と過去値を保存するために利用されます。

  • doubleテイクプロフィットおよびストップロス変数

double takeProfit = 0;
double stopLoss = 0;

取引操作のテイクプロフィット(TP)とストップロス(SL)のレベルは、現在この変数に格納されています。取引注文を出したり変更したりするために利用され、市場の状況に応じて更新されます。

  •  システム状態予約変数

bool isBuySystemInitiated = false;
bool isSellSystemInitiated = false;

これらの予約済みフラグは、売買取引システムの開始状態を監視します。不要な注文や重複注文を防止し、特定の基準(移動平均線のクロスなど)が満たされた場合にのみ注文が発注されるようにします。

  • 入力パラメータ

input int slPts = 300;
input int tpPts = 300;
input double lot = 0.01;
input int slPts_Min = 100;
input int fastPeriods = 10;
input int slowPeriods = 20;

これらの変数は入力パラメータとして機能し、コード自体を変更することなく、EAの動作を外部から設定できます。トレーダーはMetaTraderのインターフェイスを通じて、テイクプロフィット、ストップロス、ロットサイズ、短期および長期の移動平均期間などのパラメータを自由に調整できます。

変数の役割を説明した後、ティックや関数をまたいでアクセスする必要があるデータは、MQL5ではグローバル変数として格納されることが分かりました。これは、注文パラメータ、取引状況、指標の値、ユーザー定義の設定など、重要なデータを保存する役割を果たすからです。これらの変数は、取引戦略の実行やポジションの維持、市場の状況への対応に使用され、さまざまなEA機能がこれらの変数にアクセスし、必要に応じて変更を行います。

次に、コードの初期化部分を分解してみましょう。OnInit関数は、EAの初期設定をおこなうための役割を果たします。まず、iMA関数を使用して高速移動平均と低速移動平均のハンドルを作成し、それらが有効であるかを確認します。ハンドルが無効な場合、初期化は失敗します。次に、ArraySetAsSeriesを使用して、maFastとmaSlowの配列を時系列配列として設定します。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit(){
   
   handleMAFast = iMA(_Symbol,_Period,fastPeriods,0,MODE_EMA,PRICE_CLOSE);
   if (handleMAFast == INVALID_HANDLE){
      Print("UNABLE TO LOAD FAST MA, REVERTING NOW");
      return (INIT_FAILED);
   }
   
   handleMASlow = iMA(_Symbol,_Period,slowPeriods,0,MODE_EMA,PRICE_CLOSE);
   if (handleMASlow == INVALID_HANDLE){
      Print("UNABLE TO LOAD SLOW MA, REVERTING NOW");
      return (INIT_FAILED);
   }
   
   ArraySetAsSeries(maFast,true);
   ArraySetAsSeries(maSlow,true);
   
   return(INIT_SUCCEEDED);
}

そのあとで、初期化解除関数を見てみましょう。MQL5 EAシステム内では、この関数はEAが閉じられたり、チャートから削除されたときに呼び出されます。ここではタスクのクリーニングがおこなわれます。

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }

この例では、関数は空の状態であり、EAの初期化解除時には特に何も実行しないことを示しています。 

初期化解除の原因を指定する整数のパラメータreasonは、関数に渡されます。これにより、端末が閉じられた、EAがチャートから削除された、またはその他の理由で初期化解除が発生したことが示されます。

次に、新しいティック(価格変動)を受信するたびにトリガーされるOnTick関数について説明します。取引ロジックはこの関数内で実行されます。提供されたコードのOnTick関数では、移動平均のクロスオーバーに基づく取引戦略が適用されています。

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick(){
   
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),_Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),_Digits);
   
   if (CopyBuffer(handleMAFast,0,1,3,maFast) < 3){
      Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   if (CopyBuffer(handleMASlow,0,1,3,maSlow) < 3){
      Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   
   //if (IsNewBar()){Print("FAST MA DATA:");ArrayPrint(maFast,6);}
   
   if (PositionsTotal()==0){
      isBuySystemInitiated=false;isSellSystemInitiated=false;
   }
   
   if (PositionsTotal()==0 && IsNewBar()){
      if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]){
         Print("BUY SIGNAL");
         takeProfit = Ask+tpPts*_Point;
         stopLoss = Ask-slPts*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,stopLoss,0);
         isBuySystemInitiated = true;
      }
      else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]){
         Print("SELL SIGNAL");
         takeProfit = Bid-tpPts*_Point;
         stopLoss = Bid+slPts*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,stopLoss,0);
         isSellSystemInitiated = true;
      }
   }
   
   else {
      if (isBuySystemInitiated && Ask >= takeProfit){
         takeProfit = takeProfit+tpPts*_Point;
         stopLoss = Ask-slPts_Min*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,0);
         ModifyTrades(POSITION_TYPE_BUY,stopLoss);
      }
      else if (isSellSystemInitiated && Bid <= takeProfit){
         takeProfit = takeProfit-tpPts*_Point;
         stopLoss = Bid+slPts_Min*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,0);
         ModifyTrades(POSITION_TYPE_SELL,stopLoss);
      }
   }
}

OnTick関数を簡単に理解するための詳細な内訳は以下の通りです。

Ask値とBid値を取得する:この関数は、現在のAsk値とBid値を取得し、適切な小数点以下の桁数に丸めます。カスケード注文取引戦略では、異なる価格帯で注文をおこなう際に、十分な情報に基づいて判断するために、現在価格の取得とその正規化が不可欠です。したがって、カスケード注文取引戦略を実践するには、現在の市場価格を正確に把握することが重要です。この関数を呼び出すことで、MetaTraderで取引している銘柄の現在のAsk値とBid値を取得できます。この関数を呼び出すと、指定した銘柄(_Symbol)の現在のAsk値が取得できます。Ask値は資産を購入するための価格を示します。銘柄の現在のBid値は、この関数呼び出しによって取得されます。Bid値は資産を売却するための価格を示します。

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

正規化は、検索された価格が取引銘柄の要求精度を満たすことを保証します。浮動小数点演算の問題を回避することも、これに依存します。この関数呼び出しによって、値は指定された小数点以下の桁数(_Digits)に丸められます。Digitsは銘柄がサポートする小数点以下の桁数を表し、通常は銘柄に対して事前に定義されています。

移動平均バッファを複製する:この関数は、緩急両方の移動平均の最新の値を取得します。データが不足している場合、関数は終了し、エラーメッセージが表示されます。移動平均線は、カスケード注文取引戦略において、取引機会を見つけ、注文を出すタイミングを決定するために用いられます。戦略の信頼性を高めるためには、取引を開始する前に移動平均から十分なデータを取得しておくことが不可欠です。

if (CopyBuffer(handleMAFast,0,1,3,maFast) < 3){
      Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
      return;
   }
   if (CopyBuffer(handleMASlow,0,1,3,maSlow) < 3){
      Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
      return;
   }

この関数は、高速移動平均指標バッファからmaFast配列に情報を転送します。具体的には、高速移動平均指標のハンドル、バッファ番号(指標のメインラインでは通常0)、データをコピーする開始位置、コピーするデータの数、そしてコピーされたデータを保持する配列を指定します。関数は、コピーに成功した要素の数を返します。データの有効性を検証している間に、maFastがコピーした要素が3つ未満かどうかを判断します。要素が3つ未満の場合、データが不十分であることを示しており、信頼性の高い分析をサポートするには不足しています。この場合、関数はメッセージを表示し、早期に処理を終了します。低速移動平均についても、同様の理由でMASlowとmaSlowを使用して同じ検証が行われます。

以下は、移動平均線と価格データをプロットしたグラフです。プロットには、価格シリーズ、高速移動平均(10日EMA)、低速移動平均(20日EMA)が含まれます。

移動平均クロスオーバー

取引判断を下す前に、戦略は移動平均の過去データが一定量以上あることを確認します。これにより、より信頼性の高い、十分な情報に基づいた選択が可能になります。戦略は、十分なデータが揃っていることを確認することで、誤ったシグナルを発することや、不十分な情報に基づく取引のリスクを回避します。このスニペットは、取引前に実施する検証ステップを示しています。条件が満たされない場合、戦略は元の状態に戻り、そのティックでの取引や分析は行われません。

移動平均線は、カスケード注文取引戦略において、トレンドの方向と強さを評価するために使用されます。例えば、高速移動平均が低速移動平均を上回るまたは下回ると、異なる価格レベルでの注文が検討されます。

ポジションを確認する:買いと売りのシステム開始フラグは、未決済のポジションがない場合にリセットされます。カスケード注文取引戦略において取引の重複を防ぎ、取引システムの状態を効率的に管理するためには、未決済のポジションを確認することが不可欠です。この関数の仕組みの1つは、未決済のポジションがない場合に特定のフラグをリセットすることです。

//if (IsNewBar()){Print("FAST MA DATA:");ArrayPrint(maFast,6);}
   
   if (PositionsTotal()==0){
      isBuySystemInitiated=false;isSellSystemInitiated=false;
   }

この関数は、現在の取引口座における未決済ポジションの総数を返します。アクティブな取引があるかどうかを確認するのは有用です。例えば、「PositionTotal() == 0」の場合、この条件は全ポジションが0であるかどうかを判断し、現時点で取引がおこなわれていないことを示します。未決済のポジションがない場合、isBuySytemInitiatedおよびisSellSystemInitiatedフラグはfalseに設定されます。買いシステムの開始状況を示すフラグがリセットされます(_isBuySystemInitiated = false;)。売りシステムの開始状況を示すフラグがリセットされます(_isSellSystemInitiated = false;)。

このアプローチでは、定期的に未決済ポジションを確認し、開始フラグをリセットすることで、未決済ポジションがない場合にのみ新規取引が開始されるようにしています。これにより、リスクへの過剰な露出や矛盾した取引行動を引き起こす重複取引を避けることができます。isBuySystemInitiatedとisSellSystemInitiatedというフラグを利用して取引システムを管理します。これらのフラグは、現在のポジションがクローズされるまで、同じトレンド内で複数回の売買注文が開始されないようにします。こうした確認は、戦略の論理的な流れを維持するためにも役立ちます。このアプローチにより、新規注文は未決済のポジションがないときのみ強く発注されるようになり、市場の状況やトレンドに正確に反応できます。多数のポジションが同時に建てられるのを防ぐことで、より優れたリスク管理が実現されます。こうすることで、この戦略は、市場エクスポージャーを制限し、過剰なレバレッジのリスクを防ぐことができます。

 新しいバーの検出:移動平均線のクロスに基づき、新しいバー(ローソク足)が形成され、ポジションがない場合に売買シグナルを探します。取引戦略が複数回実行されるのを防ぐためには、新しいバーの出現を正確に検出することが重要です。バー内の不安定な価格変動と比較して、終了したバーのデータを取引の基準として使用することで、取引の精度が向上します。

if (PositionsTotal()==0 && IsNewBar()){
      if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]){
         Print("BUY SIGNAL");
         takeProfit = Ask+tpPts*_Point;
         stopLoss = Ask-slPts*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,stopLoss,0);
         isBuySystemInitiated = true;
      }
      else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]){
         Print("SELL SIGNAL");
         takeProfit = Bid-tpPts*_Point;
         stopLoss = Bid+slPts*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,stopLoss,0);
         isSellSystemInitiated = true;
      }
   }

「PositionsTotal == 0」という条件は、ifブロック内の関数がポジションがないときだけ実行されることを確認します。これにより、取引が重複するのを防ぎ、新しい取引は古い取引の決済後にのみ開始されます。IsNewBar()関数は、最後の実行以降に新しいバーが形成されたかどうかを判定します。基本的に、開始時間が以前に記録されていた場合、このメソッドはtrueを返すはずです。

買いシグナルでは、直近のバーが強気のクロスオーバーを示すか、または高速移動平均線(MA)が低速移動平均線を上回ったかどうかを判断します。もしそうなら、テイクプロフィットとストップロスのレベルを計算し、「買いシグナル」を出します。その後、isBuySystemInitiatedフラグをtrueに設定し、obj_Trade.Buy()を使用して買い注文を出します。以下は、カスケード注文取引戦略のEMAクロスオーバー買いシグナルです。

買いシグナル (かいシグナル)

売りシグナルでは、直近のバーが弱気クロス、つまり高速移動平均線(MA)が低速移動平均線を下抜けたかどうかを判断します。この場合、テイクプロフィットとストップロスのレベルを計算し、「SELL SIGNAL」メッセージを出力します。その後、obj_Tradeを使用して売り注文を出します。isSellSystemInitiatedフラグは、Sell()によってTrueに設定されます。下記はカスケード注文のEMAクロスオーバー売りシグナルです。

売りシグナル

この戦略は、新しいバーが検出されたときにのみ取引ロジックを実行することで、1バーにつき1回の取引しか行われないようにします。これにより、同じバー内で複数の注文が発注される問題を回避し、過剰取引や取引手数料の増加を防ぐことができます。売買の意思決定には完成したバーのデータを使用するため、その選択が信頼できる情報に基づいていることが保証されます。バー内の価格変動はノイジーであり、誤った指標を生む可能性があるためです。取引システムの状態は、未決済ポジションの確認と新しいバーの検出を組み合わせることで効果的に管理され、戦略の論理的な進行を維持しながら、必要な場合にのみ新たな取引がおこなわれることが保証されます。 

買いまたは売り注文の実行: 高速移動平均が低速移動平均を上回ると、買い注文が出されます。一方、高速MAが低速MAを下回ると、売り注文が出されます。また、開始フラグを変更し、テイクプロフィットとストップロス(SL)を設定します。この注文における「カスケード」は、価格が最初の取引に有利に動くにつれて、徐々にポジションを構築するのに役立ちます。

else {
      if (isBuySystemInitiated && Ask >= takeProfit){
         takeProfit = takeProfit+tpPts*_Point;
         stopLoss = Ask-slPts_Min*_Point;
         obj_Trade.Buy(lot,_Symbol,Ask,0);
         ModifyTrades(POSITION_TYPE_BUY,stopLoss);
      }

買い注文のカスケードでは、戦略はテイクプロフィットレベルに達したかどうか、そして現在のAsk値がそのレベル以上であるかを判断します。この条件が満たされると、価格が現在の買いポジションに有利に動いたため、追加の買い注文がトリガーされたことになります。テイクプロフィットのレベルは、あらかじめ決められたポイント数だけ引き上げられ、カスケードに続く増分のために新しいグローバル変数が設定されます。ストップロスの設定変更により、新しい買い注文のリスクが適切にコントロールされ、ストップロスレベルが希望価格よりも低い新しいレベルに調整されます。追加の買い注文は、指定されたロットサイズで現在のAsk値に基づいて出されます。現在の取引の変更により、ポジション全体のリスクが管理され、既存の購入ポジションのストップロスが新しいストップロスレベルに更新されます。

逐次売り注文では、戦略に基づいて、現在のBid値がテイクプロフィットレベルを下回っているか、または販売システムが稼働しているかどうかが判断されます。この状況は、価格が現在の売りポジションに有利に動いたため、追加の売り注文がトリガーされたことを意味します。テイクプロフィットレベルは、事前に設定されたポイント数だけ下げられ、次のカスケード増分のための新しいゴールが設定されます。また、ストップロスを更新することで、新たに発生した売り注文のリスクを適切に管理し、ストップロスレベルは既存のBid値よりも高い新しいレベルに変更されます。指定されたロットサイズの追加の売り注文が現在のBid値で約定し、取引が更新されると、現在の売りポジションのストップロスも新しいレベルに調整されます。

現在のポジションを調整する:未決済のポジションがある状態で価格がテイクプロフィットの閾値に達した場合、追加の注文が発注され、ストップロスの額も適切に更新されます。これにより、利益の最大化とリスク管理が可能になります。

else if (isSellSystemInitiated && Bid <= takeProfit){
         takeProfit = takeProfit-tpPts*_Point;
         stopLoss = Bid+slPts_Min*_Point;
         obj_Trade.Sell(lot,_Symbol,Bid,0);
         ModifyTrades(POSITION_TYPE_SELL,stopLoss);
      }
   }
}

isBuySystemInitiatedと呼ばれるブール値のフラグは、購入システムが開始されたかどうかを示し、isSellSystemInitiatedというブール値のフラグは、売りシステムが開始されたかどうかを示します。これには、Ask値、現在のBid値、テイクプロフィット額、テイクプロフィット基準値を変更するために必要なEDポイント数、ストップロスのレベル、ストップロス調整の最小ポイント、取引のロットサイズ、買い注文を出す機能、売り注文を出す機能、既存のポジションのストップロスを変更できる機能が含まれます。

UTシステムが開始されているかどうか、および現時点での希望価格がテイクプロフィット基準値に達しているか、または超えているかを確認します。テイクプロフィットレベルを所定のポイント数だけ上昇させることで、戦略は既存のテイクプロフィット目標よりも高い新たな目標を設定し、さらなる利益を追求します。ストップロスを提示価格よりも低い新しい価格に設定し、前回の利益の一部を固定することでリスク管理を強化します。提示価格での追加買い注文が完了すると、指定ロットの2回目の買い注文が約定します。最初の取引で価格が有利に動いた場合、ポジションが徐々に増加します。現在の買いポジションのストップロスをすべて更新し、新しいストップロス額を反映させることで、買いポジションに関連するリスクを効果的に管理します。

次に、売却メカニズムが開始されたかどうか、Bid値がテイクプロフィット閾値に達したか、またはそれを下回ったかを確認します。テイクプロフィットレベルを一定のポイント数だけ引き下げることで、新たな利益目標は既存のレベルよりも低く設定されます。ストップロスを更新すると、ストップロスの位置がBid値よりも高い新しいレベルに移動します。これにより、前回の利益の一部を固定し、リスク管理を強化することができます。指定ロットサイズの追加売り注文を現在のBid値で出し、価格が最初の取引に有利に動くと、ポジションを徐々に増加させます。すべての売りポジションのストップロスを更新し、新しいストップロス額を反映させることで、売りポジションに関連するリスクを効果的に管理します。

市場が最初の取引に有利にシフトするにつれて、戦略は徐々に取引ポジションを増やしていきます。これにより、トレーダーは過度のリスクを負うことなくポジションを拡大し、重要なトレンドから利益を得ることができます。この戦略は、新規注文および未決済ポジションにおけるストップロスレベルの変更を通じて、リスクを効果的に管理します。市場が下落した場合には、利益を維持し損失を抑えるのに役立ちます。相場がカスケード戦略に適した方向に進むたびに、新たなテイクプロフィットレベルが設定され、利益を最大化することができます。これにより、将来の成長の可能性を確保しつつ、収益の段階的な固定化を実現します。

それでは、MQL5 EAのコードにある2つのユーティリティ関数を見てみましょう。IsNewBarとModifyTradesです。これらのルーチンは、OnTick関数で提供されるコア取引ロジックをサポートするために必要な補助的な操作を実行します。

まずはIsNewBar関数から始めます。この関数は、チャートに新しいバー(ローソク足)が形成されたかどうかを確認します。これにより、新規取引の開始などの特定のアクションがバーごとに一度だけ実行されることが保証されます。

//+------------------------------------------------------------------+

bool IsNewBar(){
   static int prevBars = 0;
   int currBars = iBars(_Symbol,_Period);
   if (prevBars==currBars) return (false);
   prevBars = currBars;
   return (true);
}

直前のティックからのバー数は、static変数prevBarsに格納されます。staticキーワードにより、変数の値は関数呼び出し間で保持されます。Bar count**:currBarsは現在のバーのカウントを取得します。比較**:新しいバーが生成されておらず、prevBarsとcurrBarsが等しい場合、この関数はfalseを返します。一致しない場合は、新しいバーが生成されていることを示し、関数は、prevBarsをcurrBarsに更新した後にtrueを返します。 

それでは、ModifiyTrades関数に移りましょう。この関数は、指定されたポジションタイプに基づいて、アクティブポジションのストップロス(SL)レベルを調整します。

void ModifyTrades(ENUM_POSITION_TYPE posType, double sl){
   for (int i=0; i<=PositionsTotal(); i++){
      ulong ticket = PositionGetTicket(i);
      if (ticket > 0){
         if (PositionSelectByTicket(ticket)){
            ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
            if (type==posType){
               obj_Trade.PositionModify(ticket,sl,0);
            }
         }
      }
   }
}

この関数では以下をおこないます。

  1. ポジションをループする:positionsTotal()を使用して、すべてのポジションを検索します。
  2. チケットを取得する:index{i}のチケット番号の場所を返します。
  3. チケットを確認する:チケット番号が本物(0以上)であることを確認します。
  4. ポジションを選択する:PositionSelectByTicketを使用してポジションを選択します。
  5.  **ポジションタイプを確認する**:指定されたposTypeがポジションタイプと一致するかどうかを確認します。
  6. ** ポジションを変更する:ポジションタイプの一致を変更するには、PositionModifyを使用します。

カスケード注文取引戦略の全コードは以下の通りです。

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

#include <Trade/Trade.mqh>
CTrade obj_Trade;

int handleMAFast;
int handleMASlow;
double maSlow[], maFast[];

double takeProfit = 0;
double stopLoss = 0;
bool isBuySystemInitiated = false;
bool isSellSystemInitiated = false;

input int slPts = 300;
input int tpPts = 300;
input double lot = 0.01;
input int slPts_Min = 100;
input int fastPeriods = 10;
input int slowPeriods = 20;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit() {
    handleMAFast = iMA(_Symbol, _Period, fastPeriods, 0, MODE_EMA, PRICE_CLOSE);
    if (handleMAFast == INVALID_HANDLE) {
        Print("UNABLE TO LOAD FAST MA, REVERTING NOW");
        return (INIT_FAILED);
    }

    handleMASlow = iMA(_Symbol, _Period, slowPeriods, 0, MODE_EMA, PRICE_CLOSE);
    if (handleMASlow == INVALID_HANDLE) {
        Print("UNABLE TO LOAD SLOW MA, REVERTING NOW");
        return (INIT_FAILED);
    }

    ArraySetAsSeries(maFast, true);
    ArraySetAsSeries(maSlow, true);

    return (INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) {
    // Cleanup code if necessary
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick() {
    double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
    double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);

    if (CopyBuffer(handleMAFast, 0, 1, 3, maFast) < 3) {
        Print("NO ENOUGH DATA FROM FAST MA FOR ANALYSIS, REVERTING NOW");
        return;
    }
    if (CopyBuffer(handleMASlow, 0, 1, 3, maSlow) < 3) {
        Print("NO ENOUGH DATA FROM SLOW MA FOR ANALYSIS, REVERTING NOW");
        return;
    }

    if (PositionsTotal() == 0) {
        isBuySystemInitiated = false;
        isSellSystemInitiated = false;
    }

    if (PositionsTotal() == 0 && IsNewBar()) {
        if (maFast[0] > maSlow[0] && maFast[1] < maSlow[1]) {
            Print("BUY SIGNAL");
            takeProfit = Ask + tpPts * _Point;
            stopLoss = Ask - slPts * _Point;
            obj_Trade.Buy(lot, _Symbol, Ask, stopLoss, 0);
            isBuySystemInitiated = true;
        } else if (maFast[0] < maSlow[0] && maFast[1] > maSlow[1]) {
            Print("SELL SIGNAL");
            takeProfit = Bid - tpPts * _Point;
            stopLoss = Bid + slPts * _Point;
            obj_Trade.Sell(lot, _Symbol, Bid, stopLoss, 0);
            isSellSystemInitiated = true;
        }
    } else {
        if (isBuySystemInitiated && Ask >= takeProfit) {
            takeProfit = takeProfit + tpPts * _Point;
            stopLoss = Ask - slPts_Min * _Point;
            obj_Trade.Buy(lot, _Symbol, Ask, 0);
            ModifyTrades(POSITION_TYPE_BUY, stopLoss);
        } else if (isSellSystemInitiated && Bid <= takeProfit) {
            takeProfit = takeProfit - tpPts * _Point;
            stopLoss = Bid + slPts_Min * _Point;
            obj_Trade.Sell(lot, _Symbol, Bid, 0);
            ModifyTrades(POSITION_TYPE_SELL, stopLoss);
        }
    }
}

    static int prevBars = 0;
    int currBars = iBars(_Symbol, _Period);
    if (prevBars == currBars) return (false);
    prevBars = currBars;
    return (true);
}

//+------------------------------------------------------------------+
//| ModifyTrades Function                                            |
//+------------------------------------------------------------------+

void ModifyTrades(ENUM_POSITION_TYPE posType, double sl) {
    for (int i = 0; i <= PositionsTotal(); i++) {
        ulong ticket = PositionGetTicket(i);
        if (ticket > 0) {
            if (PositionSelectByTicket(ticket)) {
                ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
                if (type == posType) {
                    obj_Trade.PositionModify(ticket, sl, 0);
                }
            }
        }
    }
}


結論

最後に、このMQL5 EAは、移動平均クロスオーバー取引戦略の優れた実例です。この記事では、Trade.mqhライブラリを活用して注文管理を効率化し、テイクプロフィットとストップロスのダイナミックな設定を導入することで、取引の自動化を実現していました。

このEAの特筆すべき特徴は以下の通りです。

  • 初期化と管理:クロスオーバーに基づく売買シグナルは体系的に管理され、移動平均の初期化が効率的におこなわれます。
  • リスク管理:テイクプロフィットとストップロスの設定を用いてリスクを抑え、ユーザーが設定した範囲内でリターンを確保します。
  • モジュール性と柔軟性:入力パラメータやグローバル変数を活用して、様々な市場状況や取引の好みに応じてカスタマイズと適応が可能です。

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

データサイエンスと機械学習(第26回):時系列予測における究極の戦い - LSTM対GRUニューラルネットワーク データサイエンスと機械学習(第26回):時系列予測における究極の戦い - LSTM対GRUニューラルネットワーク
前回の記事では、データの長期的な依存関係をうまく捉えられないにもかかわらず、利益を上げる戦略を構築できる単純RNNについて説明しました。この記事では、LSTM (Long-Short Term Memory)とGRU (Gated Recurrent Unit)の両方について説明します。この2つは、単純RNNの欠点を克服し、それを凌駕するために紹介されました。
Candlestick Trend Constraintモデルの構築(第6回):オールインワン統合 Candlestick Trend Constraintモデルの構築(第6回):オールインワン統合
一つの大きな課題は、異なる機能を持つ同じプログラムを、同じ通貨ペアに対して複数のチャートウィンドウで実行し、管理することです。この問題を解決するには、複数の機能を一つのメインプログラムに統合する方法を検討する必要があります。さらに、プログラムの設定を操作ログに出力する方法や、成功したシグナルのブロードキャストをチャートインターフェイス上に表示する方法についても解説します。連載が進むにつれ、この記事でさらに詳しい情報を提供していきます。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
初心者のためのMQL5によるSP500取引戦略 初心者のためのMQL5によるSP500取引戦略
MQL5を活用してS&P500指数を正確に予測する方法をご紹介します。古典的なテクニカル分析とアルゴリズム、そして長年の経験に裏打ちされた原理を組み合わせることで、安定性を高め、確かな市場洞察力を得られます。