English Русский 中文 Español Deutsch Português
ユニバーサルEA:カスタムトレーリングストップ(その6)

ユニバーサルEA:カスタムトレーリングストップ(その6)

MetaTrader 5 | 8 8月 2016, 10:01
1 769 0
Vasiliy Sokolov
Vasiliy Sokolov

目次


イントロダクション

ユーザーが独自のCStrategyを作成できる取引エンジンを構成するクラスのセットです。この前のパートでは、エンジンに基づいて作成されたCStrategyの基本的な関数を拡張可能にするエンジンのモジュールを扱いました。しかし、これらのモジュールのほとんどはCStrategyクラスであるか、または、このクラスが直接動作するオブジェクトです。 

トレーリングストップのサポート:このパートでは、CStrategy取引エンジンの関数の新しい可能性を検討します。他のCStrategyモジュールとは異なり、トレーリングの停止アルゴリズムは取引エンジンとの関係で、externalです。これはCStrategyの関数に影響を与えることを意味します。この関数は、compositionと呼ばれる特別なプログラミング技術を使用して実装することができます。この技術は後述します。また、厳密なオブジェクト指向プログラミングの下、追加モジュールやクラスを使用して新しい関数を追加します。

 

関数の実装オプション

トレーリングストップは、アルゴリズムの一種であり、過剰損失からのポジションを保護するために特定の価格水準にストップロスオーダーを移動させることです。明らかに、ポジションのストップロスを管理するためのアルゴリズムは多く存在しています。トレーリングストップの管理アルゴリズムは、CStrategyクラス内の別のメソッドとして行うことができます。例えば、パラメータとして、現在のポジションを受信し、現在のストップロスオーダーを移動することができます。

class CStrategy
   {
public:
   double TrailingMode1(CPosition* pos);
   };

そして、後の関数に従って、ポジション管理はストラテジーで可能でしょう。

void CMovingAverage::SupportBuy(const MarketEvent &event,CPosition *pos)
  {
   double new_sl = TrailingMode1(pos);
   pos.StopLossValue(new_sl);
  }

トレーリングストップ関数が多くあるので、CStrategyクラス内に配置することは望ましくありません。トレーリングストップは、EAの基本的なアルゴリズムでexternalです。取引エンジン動作に必要な関数ではなく、取引プロセスを簡略化します。したがって、後の関数が欠如しても、トレーリングストップを使用しないCStrategyの関数に影響を与えるべきではありません。しかし、ストップ管理のアルゴリズムは、コードを複雑にするべきではありません。これが後のストップ関数を別々のクラスで取引ストラテジーに接続されているファイルに配置する必要がある理由です。

代わりに、CPositionのクラスのトレーリングの関数を実装することができます。この場合、トレーリングストップの動作は次のようになります。

void CMovingAverage::SupportBuy(const MarketEvent &event,CPosition *pos)
  {
   pos.TrailingMode1();
  }

しかし、これはCStrategyクラスからCPositionに問題を移すことになります。この場合、CPositionのクラスで、ポジション管理のアルゴリズムの数が非常に大きくなる可能性があります。  

また、トレーリングのアルゴリズムは、特定のパラメータの設定が必要です。例えば、クラシカルなトレーリングストップは、価格の値とストップロスのレベルとの間の距離を指定する必要があります。したがって、アルゴリズム自体に加えて、どこかにそのパラメータを格納する必要があります。CPositionやCStrategyなどのクラスでこのデータを保存する場合、多くの変数でこれらのクラスの内部変数を混乱させ、動作が複雑になります。

 

トレーリング関数の標準化。トレーリングクラス

非常に多くの場合、最も効果的な解決法は最もシンプルで実績のあるものです。トレーリングストップの場合も例外ではありません。トレーリングストップが保存されている特別なクラスであるとした場合、上記の問題のすべて解決されるだろう。独立したクラスとしてトレーリングストップを作成する場合、そのデータとメソッドは、データとCStrategyクラスやCPositionなどの他の重要なインフラストラクチャオブジェクトのメソッドと混同されることはありません。

このクラスを開発する場合、2つの問題を解く必要があります。

  1. トレーリングストップクラスの内部。その操作の標準化。
  2. CStrategyエンジンの他のモジュールとの相互作用。

これらの質問の1つ目を考えてみましょう。明らかに、任意のトレーリングストップは、パラメータのセットを持っています。したがって、このセットの標準化は不可能です。しかし、トレーリングアルゴリズムが変更するストップロスオーダー、つまり、ある1つの必須パラメータを持っています。このポジションは、すでに馴染みのあるクラスで表されます。また、トレーリングストップの各タイプは、ポジションのストップロス注文を修正されるメソッドを持つ必要があります。このメソッドはトレーリングアルゴリズムを起動する「ボタン」の一種なので、このメソッドの名前はトレーリングのすべてのタイプと同じでなければなりません。

CTrailingという特殊なベースクラスとして2つの識別を行いましょう。。これは、後述する目的は、現在のポジション、仮想Modifyメソッド、ストップロスが変更されることによって、仮想コピーのメソッドを設定するメソッドが含まれます。:

//+------------------------------------------------------------------+
//|                                                     Trailing.mqh |
//|                                 Copyright 2016, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#include <Object.mqh>
#include "..\PositionMT5.mqh"
#include "..\Logs.mqh"
class CPosition;
//+------------------------------------------------------------------+
//|トレーリングストップのクラス|
//+------------------------------------------------------------------+
class CTrailing : public CObject
  {
protected:
   CPosition         *m_position;     // トレーリングストップを修正したいポジション
   CLog              *Log;
public:
                      CTrailing(void);
   void               SetPosition(CPosition *position);
   CPosition         *GetPosition(void);
   virtual bool       Modify(void);
   virtual CTrailing* Copy(void);
  };
//+------------------------------------------------------------------+
//|コンストラクタ。|ログモジュールを受け取ります
//+------------------------------------------------------------------+
CTrailing::CTrailing(void)
  {
   Log=CLog::GetLog();
  }
//+------------------------------------------------------------------+
//|トレーリングストップメソッド|
//|派生トレーリングクラスでオーバーライド|
//+------------------------------------------------------------------+
bool CTrailing::Modify(void)
  {
   return false;
  }
//+------------------------------------------------------------------+
//||インスタンスのコピーを返します。
//+------------------------------------------------------------------+  
CTrailing* CTrailing::Copy(void)
{
   return new CTrailing();
}
//+------------------------------------------------------------------+
//|ポジションを設定し、ストップロスを変更する必要があります|
//+------------------------------------------------------------------+
void CTrailing::SetPosition(CPosition *position)
  {
   m_position=position;
  }
//+------------------------------------------------------------------+
//|ストップロスを変更する必要があるポジションを返します
//+------------------------------------------------------------------+
CPosition *CTrailing::GetPosition(void)
  {
   return m_position;
  }
//+------------------------------------------------------------------+


トレーリングストップは、このクラスから派生されます。このトレーリングのクラスは、ストップロスの移動アルゴリズムのパラメータが含まれていません。これは、クラス操作の柔軟性の達成に役立ちます。トレーリング関数が動作するための各種パラメータを必要とするという事実にもかかわらず、Modifyメソッドはそれらを受け入れません。すべてのパラメータは、特別なメソッドを使用して子トレーリングクラスで設定されます。よって、修正のコールの時間によって、必要なすべてのパラメータが得られます。

 

CStrategyの他のモジュールと相互作用

CTrailingクラスがありますが、これは取引エンジンの構造に含めるのに十分です。CPositionクラス内基底クラスを追加します。

class CPosition
  {
public:
   CTrailing* Trailing;    //トレーリングストップモジュール
  };

この配置は、直感的で自然です。ポジション自体によって制御されている場合は、ポジションを同一に制御することができます。

void CMovingAverage::SupportBuy(const MarketEvent &event,CPosition *pos)
  {
   pos.Trailing.Modify();
  }

標準化された修正メソッドによってこれも可能で、すなわち、ポジションを変更するために何をすべきか正確にわかっています。 

しかし、トレーリングストップのモジュールの統合はそれだけではありません。上記の例では、まだユーザのストラテジーのレベルでポジション管理が必要です。BuySupportとSellSupportメソッドをオーバーライドし、EAのロジック内の各ポジションを管理する必要があります。さらにポジション管理を簡単にするために、CStrategyクラスに直接トレーリングストップモジュールを追加します。

class CStrategy
  {
public:
   CTrailing* Trailing;   // すべてのポジションのトレーリングストップモジュール
  };

また、CStrategyのクラスに属する、追加のコールのサポートメソッドが必要になります。

//+------------------------------------------------------------------+
//||トレーディングを条件とするポジション管理ロジックを呼び出し
//|TRADE_WAITと等しくない|
//+------------------------------------------------------------------+
void CStrategy::CallSupport(const MarketEvent &event)
  {
   m_trade_state=m_state.GetTradeState();
   if(m_trade_state == TRADE_WAIT)return;
   SpyEnvironment();
   for(int i=ActivePositions.Total()-1; i>=0; i--)
     {
      CPosition *pos=ActivePositions.At(i);
      if(pos.ExpertMagic()!=m_expert_magic)continue;
      if(pos.Symbol()!=ExpertSymbol())continue;
      if(CheckPointer(Trailing)!=POINTER_INVALID)
        {
         if(CheckPointer(Trailing)==POINTER_INVALID)
            pos.Trailing=Trailing.Copy();
         pos.Trailing.Modify();
         if(!pos.IsActive())
            continue;
        }
      if(pos.Direction()==POSITION_TYPE_BUY)
         SupportBuy(event,pos);
      else
         SupportSell(event,pos);
      if(m_trade_state==TRADE_STOP && pos.IsActive())
         ExitByStopRegim(pos);
     }
  }

新しい特徴は、黄色で強調表示されます。これらは非常にシンプルです:トレーリングストップはデフォルトで配置されましたが、現在ポジションを持っていない場合、トレーリングは現在ポジションに配置され、そのストップロスオーダーは、トレーリングのロジックに従って変更されます。しかし、非常に重要な関数を取る必要があります。デフォルトのトレーリングストップのインスタンスはそれぞれのポジションではなく、デフォルのトレーリング自身に割り当てられています。この解決策は、トレーリングストップのロジック内部の混乱の回避に役立ちます。トレーリングストップの同じインスタンスが複数のポジションを管理していることを想像してみてください。一つのポジションの任意の変数を計算した場合、渡されたポジションが異なることになるので、次の呼び出し時に無効になります。この事実は、非常に奇妙なエラーを引き起こすことになります。この問題を回避するために、トレーリングストップの個々のインスタンスは、それぞれのポジションに割り当てられます。このインスタンスは、ポジションの保有中に変更されません。個々のトレーリングストップを割り当てるためには、デフォルトトレーリングストップをコピーする必要があります。CStrategyはデータと内部変数をコピーする必要がないので、コピーの手順はトレーリングのクラスによって行われます。これは、CTrailingクラスの仮想Copy()メソッドをオーバーライドして、、一般的なトレーリングクラスの形で自身の作成したコピーの参照を返す必要があります。CTrailingClassicの対処メソッドの実装の例は次のとおりです。

//+------------------------------------------------------------------+
//||インスタンスのコピーを返します。
//+------------------------------------------------------------------+  
CTrailing *CTrailingClassic::Copy(void)
  {
   CTrailingClassic *tral=new CTrailingClassic();
   tral.SetDiffExtremum(m_diff_extremum);
   tral.SetStepModify(m_step_modify);
   tral.SetPosition(m_position);
   return tral;
  }

このメソッドは現在のインスタンスに等しいパラメータを設定し、CTrailingClassic型のインスタンスを作成し、CTrailing型へのポインタの形でオブジェクトを返します。

カスタムトレーリングのクラスを開発する際に単純なルールを覚えておいてください: 

デフォルトでは、トレーリングストップを設定するために、CTrailingクラスのCopyメソッドをオーバーライドする必要があります。そうでなければ、CStrategyは自動的にポジションを保有して管理することができないでしょう。BuySupportとSellSupportメソッドでトレーリングストップを使用する場合、仮想のCopyメソッドをオーバーライドする必要はありません。

Copyメソッドをオーバーライドするとカスタムトレーリングストップの開発を複雑にしますが、共通データの処理エラーの防止、モジュールの動作ロジックがより安全になります。

CStrategyにロジックとして渡されたトレーリングストップを使ってポジションを管理しましょう。。CStrategyをリンクした場合、それは現在のEAに属すすべてのポジションのデフォルトトレーリングになります。よって、ポジションを管理するために、トレーリングに使用するCStrategyのBuySupportとSellSupportメソッドをオーバーライドすることは必要とされていません。ポジションが自動的にCStrategyで管理されます。

CallSupportコードで、ポジションがアクティブかどうかのチェックが続いていることに注意してください。ポジションはトレーリングストップの修正中に閉鎖された場合、検索サイクルはオーバーライドされたメソッドの呼び出しを中断し、次のポジションで検索を続けますが、問題ありません。この特徴は、興味深い結果になります。

ポジション管理アルゴリズムは、実際にはトレーリングストップ関数として使用することができます。ストップロスオーダーの変更は必要ありません。ポジション管理アルゴリズムは、一定の条件の下でポジションを閉じることができます。このアクションはCStrategyにとって、通常の処理となります。


トレーリングストップの実用。トレーリングストップの例

さて、基本的なCStrategyエンジンについて触れました。トレーリングストップを実装することができます。クラシカルなトレーリングストップのアルゴリズムから始めましょう。その動作は非常に簡単です。トレーリングストップは、新しいの高値と安値で、ポジションのストップロスオーダーを移動します。価格が戻った場合でも、ストップロスは同じレベルのままです。このように、ストップロスは一定の距離の価格以下で引きずられます。この距離は、対応するパラメータにより定義されます。

また、トレーリングストップは、1つ以上のパラメータを持っています。これはオプションです。ストップロスがあまりにも頻繁に変更するのを回避するために、制限します:前のレベルから新しいストップロスレベルの最小の差は等しくなければならない StepModifyポイント。StepModifyの値は、別のパラメータで設定されます。このパラメータは、FORTSの取引に重要です。FORTSの取引ルールによると、取引所はいわゆる"非効率的な取引"に追加料金を請求します。実際の取引がある一方でストップロスの多くの変更がある場合 - 為替トレーダーに追加料金が必要になります。よって、今回のアルゴリズムは、アカウントにこの関数を取る必要があります。

最初のトレーリングストップのコードです。これは、トレーリングのクラスに基づいて、Modifyメソッドをオーバーライドされます。  

//+------------------------------------------------------------------+
//|                                              TrailingClassic.mqh |
//|                                 Copyright 2016, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#include "Trailing.mqh"
//+------------------------------------------------------------------+
//|パラメータのリストで停止 トレーリングの統合|
//|EA|
//+------------------------------------------------------------------+
#ifdef SHOW_TRAILING_CLASSIC_PARAMS
input double PointsModify=0.00200;
input double StepModify=0.00005;
#endif
//+------------------------------------------------------------------+
//|クラシカルなトレーリングストップ|
//+------------------------------------------------------------------+
class CTrailingClassic : public CTrailing
  {
private:
   double            m_diff_extremum;  // ポイント単位での極値からストップロスまでの距離
   double            m_step_modify;    //ストップロスを修正する最小単位
   double            FindExtremum(CPosition *pos);
public:
                     CTrailingClassic(void);
   void              SetDiffExtremum(double points);
   double            GetDiffExtremum(void);
   void              SetStepModify(double points_step);
   double            GetStepModify(void);
   virtual bool      Modify(void);
   virtual CTrailing *Copy(void);
  };
//+------------------------------------------------------------------+
//|コンストラクタ。|デフォルトのパラメータを初期化します
//+------------------------------------------------------------------+
CTrailingClassic::CTrailingClassic(void) : m_diff_extremum(0.0),
                                           m_step_modify(0.0)
  {
#ifdef SHOW_TRAILING_CLASSIC_PARAMS
   m_diff_extremum=PointsModify;
   m_step_modify=StepModify;
#endif
  }
//+------------------------------------------------------------------+
//||インスタンスのコピーを返します。
//+------------------------------------------------------------------+  
CTrailing *CTrailingClassic::Copy(void)
  {
   CTrailingClassic *tral=new CTrailingClassic();
   tral.SetDiffExtremum(m_diff_extremum);
   tral.SetStepModify(m_step_modify);
   tral.SetPosition(m_position);
   return tral;
  }
//+------------------------------------------------------------------+
//||極値からポイント数を設定します。
//+------------------------------------------------------------------+
void CTrailingClassic::SetDiffExtremum(double points)
  {
   m_diff_extremum=points;
  }
//+------------------------------------------------------------------+
//||最小限の変更の値を設定します
//+------------------------------------------------------------------+
void CTrailingClassic::SetStepModify(double points_step)
  {
   m_step_modify=points_step;
  }
//+------------------------------------------------------------------+
//||極値からポイント数を返します。
//+------------------------------------------------------------------+
double CTrailingClassic::GetDiffExtremum(void)
  {
   return m_diff_extremum;
  }
//+------------------------------------------------------------------+
//||最小限の変更の値を返します。
//+------------------------------------------------------------------+
double CTrailingClassic::GetStepModify(void)
  {
   return m_step_modify;
  }
//+------------------------------------------------------------------+
//||古典のロジックに従って、変更されたトレーリングストップ
//||トレーリングストップ
//+------------------------------------------------------------------+
bool CTrailingClassic::Modify(void)
  {

   if(CheckPointer(m_position)==POINTER_INVALID)
     {
      string text="Invalid position for current trailing-stop. Set position with 'SetPosition' method";
      CMessage *msg=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
      Log.AddMessage(msg);
      return false;
     }
   if(m_diff_extremum<=0.0)
     {
      string text="Set points trailing-stop with 'SetDiffExtremum' method";
      CMessage *msg=new CMessage(MESSAGE_WARNING,__FUNCTION__,text);
      Log.AddMessage(msg);
      return false;
     }
   double extremum=FindExtremum(m_position);
   if(extremum == 0.0)return false;
   double n_sl = 0.0;
   if(m_position.Direction()==POSITION_TYPE_BUY)
      n_sl=extremum-m_diff_extremum;
   else
      n_sl=extremum+m_diff_extremum;
   if(n_sl!=m_position.StopLossValue())
      return m_position.StopLossValue(n_sl);
   return false;
  }
//+------------------------------------------------------------------+
//||極端な価格を返します。
//| ポジション。|ロングポジションの場合、それは戻ります
//|価格に達した。短いもののために - だった最低価格|
//|達しました。|
//+------------------------------------------------------------------+
double CTrailingClassic::FindExtremum(CPosition *pos)
  {
   double prices[];
   if(pos.Direction()==POSITION_TYPE_BUY)
     {
      if(CopyHigh(pos.Symbol(),PERIOD_M1,pos.TimeOpen(),TimeCurrent(),prices)>1)
         return prices[ArrayMaximum(prices)];
     }
   else
     {
      if(CopyLow(pos.Symbol(),PERIOD_M1,pos.TimeOpen(),TimeCurrent(),prices)>1)
         return prices[ArrayMinimum(prices)];
     }
   return 0.0;
  }
//+------------------------------------------------------------------+


このクラスの基本的なコードは、ModifyとFindExtremumメソッドにあります。EAは、価格の高値または安値をメソッドを使用して履歴から(ポジションタイプによって異なります)を検索します。これにより、CStrategyの再起動後、またはそのアイドル時間が経過した後、ストップロスが正しく計算されます。

トレーリングストップのクラスは、SHOW_TRAILING_CLASSIC_PARAMSと入力変数「入力」の形で追加のプログラミング構造が含まれています。 "トレーリングにパラメータを追加」セクションの後半でこれらの構成について説明します。

 

トレーリングストップを追加するCImpluse

前回の記事"ユニバーサルEA:注文を保留とサポートをヘッジの使用"でCImpulseCStrategyを導入しました。そのシンプルな取引ストラテジーは、シャープな値動き中のエントリに基づいています。提案のストラテジーは、移動平均に基づいて、ポジション管理を適用します。バーが移動平均を下回ったとき、ロングポジションを閉じます。バーが移動平均の上に開いたとき、ショートポジションを閉じます。ロジックのコードは次のとおりです。

//+------------------------------------------------------------------+
//||移動平均に基づいたロングポジションを管理
//+------------------------------------------------------------------+
void CImpulse::SupportBuy(const MarketEvent &event,CPosition *pos)
{
   if(!IsTrackEvents(event))return;
   ENUM_ACCOUNT_MARGIN_MODE mode = (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
   if(mode != ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
   {
      double target = Bid() - Bid()*(m_percent/100.0);
      if(target < Moving.OutValue(0))
         pos.StopLossValue(target);
      else
         pos.StopLossValue(0.0);
   }
   if(Bid() < Moving.OutValue(0))
      pos.CloseAtMarket();
}
//+------------------------------------------------------------------+
//||移動平均に基づいたショートポジションを管理
//+------------------------------------------------------------------+
void CImpulse::SupportSell(const MarketEvent &event,CPosition *pos)
{
   if(!IsTrackEvents(event))return;
   ENUM_ACCOUNT_MARGIN_MODE mode = (ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
   if(mode != ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
   {
      double target = Ask() + Ask()*(m_percent/100.0);
      if(target > Moving.OutValue(0))
         pos.StopLossValue(target);
      else
         pos.StopLossValue(0.0);
   }
   if(Ask() > Moving.OutValue(0))
      pos.CloseAtMarket();
}

ポジション管理のルールの代わりに、クラシカルなトレーリングストップ・ロジックを使用して、単純化してみましょう。ストラテジーのコードからメソッドを削除し、コンストラクタ内の関数をデフォルトとして、クラシカルなトレーリングストップを追加します。CImpulseTrailingAuto:CStrategyの名前を変更してみましょう:

//+------------------------------------------------------------------+
//|初期化とトレーリングストップの設定|
//|起動時に|
//+------------------------------------------------------------------+
CImpulseTrailing::CImpulseTrailing(void)
{
   CTrailingClassic* classic = new CTrailingClassic();
   classic.SetDiffExtremum(0.00100);
   Trailing = classic;
}

今、新しいロジックでは、極端な価格から0.00100点の距離にあるトレーリングストップに基づいています。

自動トレーリングストップの完全なソースコードは、ImpleseTrailingAuto.mqhで利用可能です。

 

EAの設定にトレーリングのパラメータを追加

作成したトレーリングストップの操作メソッドは非常に便利です。しかし、カスタムストラテジーの中にトレーリングストップのパラメータを設定する必要があります。手続きを簡素化する必要があります。例えば、EAの設定にトレーリングストップのパラメータを追加します。問題はトレーリングストップを使用しない場合、パラメータは曖昧さを引き起こす可能性があるということです。この問題を回避するために、条件付きコンパイルを使用することができます。クラシカルなトレーリングストップのモジュールに条件付きコンパイルのマクロSHOW_TRAILING_CLASSIC_PARAMSを追加してみましょう。:

//+------------------------------------------------------------------+
//|                                              TrailingClassic.mqh |
//|                                 Copyright 2016, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#include "Trailing.mqh"
//+------------------------------------------------------------------+
//|パラメータのリストで停止 トレーリングの統合|
//|EA|
//+------------------------------------------------------------------+
#ifdef SHOW_TRAILING_CLASSIC_PARAMS
input double PointsModify = 0.00100;
input double StepModify =   0.00005;
#endif
//+------------------------------------------------------------------+
//|クラシカルなトレーリングストップ|
//+------------------------------------------------------------------+
class CTrailingClassic : public CTrailing
  {
   ...
public:
                     CTrailingClassic(void);
   ...
  };
//+------------------------------------------------------------------+
//|コンストラクタ。|デフォルトのパラメータを初期化します
//+------------------------------------------------------------------+
CTrailingClassic::CTrailingClassic(void) : m_diff_extremum(0.0),
                                           m_step_modify(0.0)
  {
   #ifdef SHOW_TRAILING_CLASSIC_PARAMS
   m_diff_extremum = PointsModify;
   m_step_modify = StepModify;
   #endif
  }

SHOW_TRAILING_CLASSIC_PARAMSマクロが定義されている場合、トレーリングのパラメータは、コンパイル時にEAに統合されます。


図1。動的にリンクされたパラメータPointsModifyとSepModify

SHOW_TRAILING_CLASSIC_PARAMSマクロがコメント化されているか、それが利用できない場合には、トレーリングは、EAのパラメータから消えます:


図2。トレーリングストップのパラメータの無効化

SHOW_TRAILING_CLASSIC_PARAMSマクロは、EAの設定にトレーリングにパラメータを追加し、パラメータが作成時に自動的に追加されるようにCTrailingClassicを設定します。マクロを作成するとき、既にEAの設定画面を介してユーザによって入力されたパラメータが含まれています。 

 

移動平均のトレーリングストップ

この記事の前のパートでは、CImpulseCStrategyは、価格が移動平均の上または下にあれば、そのポジションを閉じました。移動平均は、CIndMovingAverageインジケータクラスで提示されました。CIndMovingAverageクラスは、トレーリングストップクラスと非常によく似ています。移動平均の値を計算し、指標パラメータの柔軟な構成が可能になります。トレーリングストップとの唯一の違いは、ポジション管理のアルゴリズムが存在しないことです。CIndMovingAverageクラスは、Modify()メソッドを持っていません。一方、CTrailingクラスは、必要なすべてのメソッドが含まれ、移動平均を操作するためのアルゴリズムを持っています。移動平均に基づいたトレーリングストップ:合成メソッドによれば、これらのクラスのそれぞれの長所を組み合わせて、トレーリングストップの新しいタイプを作成することができます。アルゴリズムは非常に簡単です:移動平均に等しいストップロスのレベルを設定します。また、Modifyメソッドにチェックを追加してみましょう:現在の価格が購入時以下である場合、ポジションは市場価格で閉じる必要があります。クラス全体は、以下で利用可能です:

//+------------------------------------------------------------------+
//|                                               TrailingMoving.mqh |
//|                                 Copyright 2016, Vasiliy Sokolov. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link      "http://www.mql5.com"
#include "Trailing.mqh"
#include "..\Indicators\MovingAverage.mqh"

//+------------------------------------------------------------------+
//|移動平均に基づいたトレーリングストップ。|ストップロスを設定します。
//|MAレベルに等しいポジション|
//+------------------------------------------------------------------+
class CTrailingMoving : public CTrailing
{
public:
   virtual bool       Modify(void);
   CIndMovingAverage* Moving;
   virtual CTrailing* Copy(void);
};
//+------------------------------------------------------------------+
//|| MAレベルに等しいポジションのストップロスを設定します。
//+------------------------------------------------------------------+
bool CTrailingMoving::Modify(void)
{
   if(CheckPointer(Moving) == POINTER_INVALID)
      return false;
   double value = Moving.OutValue(1);
   if(m_position.Direction() == POSITION_TYPE_BUY &&
      value > m_position.CurrentPrice())
      m_position.CloseAtMarket();
   else if(m_position.Direction() == POSITION_TYPE_SELL &&
      value < m_position.CurrentPrice())
      m_position.CloseAtMarket();
   else if(m_position.StopLossValue() != value)
      return m_position.StopLossValue(value);
   return false;
}
//+------------------------------------------------------------------+
//|| CTrailingMovingインスタンスの正確なコピーを返します。
//+------------------------------------------------------------------+
CTrailing* CTrailingMoving::Copy(void)
{
   CTrailingMoving* mov = new CTrailingMoving();
   mov.Moving = Moving;
   return mov;
}

Modify関数は、ストップレベルでの移動平均レベルを比較します。レベルが等しくない場合、関数は新たなストップを置きます。常にバーは形成過程であるため、完了したバーの移動平均値が、使用されています。また、移動平均インジケータはポインタとして宣言されていることに注意してください。この特徴は、ユーザーがこのトレーリングストップにCIndMovingAverageの任意のオブジェクトを接続することができます。 

ストラテジーテスターで動作をテストしてみましょう。その動作を示すビデオは、次のとおりです。

 

 

個々のポジションのトレーリングストップ

ストップ操作でトレーリングのメカニズムを分析しました。統一された仮想Modifyメソッドを使用することにより、CStrategyの取引エンジンは自動的に各ポジションのトレーリングストップを設定し、その計算アルゴリズムを呼び出すことができます。通常はこれで十分ですが、いくつかのケースでは個別にそれぞれのポジションを管理する必要があるかもしれません。それは別のポジションに別の型のトレーリングタイプを適用する必要があるかもしれないことを意味します。このようなトレーリング関数が、取引エンジン側に実装することができないので、CStrategyの内部に実装する必要があります。これはBuySupportとSellSupportメソッドをオーバーライドすることによって行うことができます。また、この場合、CStrategyのコンストラクタで行ったメソッドのストップを初期化する必要はありません。

CImpulseCStrategyのロングポジションが移動平均に基づいて、トレーリングストップを使用して管理されるべきであるとします。クラシカルなトレーリングストップは、ショート・ポジションに適用されます。トレーリングのこれらのタイプの両方は、先に記載されています。BuySupportとSellSupportメソッドを以下のメソッドをオーバーライドしてみましょう:

//+------------------------------------------------------------------+
//||移動平均に基づいたロングポジションを管理
//+------------------------------------------------------------------+
void CImpulseTrailing::SupportBuy(const MarketEvent &event,CPosition *pos)
{
   if(!IsTrackEvents(event))
      return;
   if(pos.Trailing == NULL)
   {
      CTrailingMoving* trailing = new CTrailingMoving();
      trailing.Moving = GetPointer(this.Moving);
      pos.Trailing = trailing;
   }
   pos.Trailing.Modify();
}
//+------------------------------------------------------------------+
//||移動平均に基づいたショートポジションを管理
//+------------------------------------------------------------------+
void CImpulseTrailing::SupportSell(const MarketEvent &event,CPosition *pos)
{
   if(!IsTrackEvents(event))
      return;
   if(pos.Trailing == NULL)
   {
      CTrailingClassic* trailing = new CTrailingClassic();
      trailing.SetDiffExtremum(0.00100);
      pos.Trailing = trailing;
   } 
   pos.Trailing.Modify();
}

移動平均に基づいて、CIndMovingAverageクラスがパラメータとして設定されています。このクラスは、移動オブジェクトとしてCStrategyで利用可能です。このコードでは、ストップロスのレベルを計算するために使用するオブジェクトを指示しています。 

SupportSellメソッドは、新しいポジションに適用され、このトレーリングストップはパラメータの独自のセットを有します。トレーリングは0.00100ピップのチャンネルを形成して使用しています。 

各ポジションタイプのCStrategyのコードはImpulseTrailingManual.mqhファイルで利用可能です。

 

最新バージョンの修正リスト

CStrategy取引エンジンは、この記事の最初のパート以来、大幅に変更されました。新しい関数や取引の可能性を広げるモジュールを追加しました。また、様々な変更したバージョンは、最初の出版以降にリリースされました。この変更は、CStrategyの旧バージョンとの互換性がなかったので、取引エンジンを変更する必要がありました。これらの修正と拡張は避けられないエラーの出現を引き起こしました。このセクションでは、取引エンジンの最新バージョンのバグ修正をします。

  • 取引ストラテジーのパネルは、プロジェクトに含まれています。以前のバージョンのバグのため、互換性の問題で無効とされました。コンパイラの修正の後、パネルは再び追加されましたが、正常に動作しませんでした。取引エンジンの第6パートでは、パネルの動作が完全に復元されています。
  • 取引パネルにはエラーが含まれていました:SellOnlyを表示する代わりに、BuyOnlyが2回表示されていました。このバグは修正されています。
  • 以前のバージョンでは、パネル上の取引モードを変更すると、CStrategyの実際の取引モードが変更されることはありませんでした。このバグは、第6パートで修正されています。
  • 新しい動作は、モード変更のプロセスに追加されます。SellOnlyモードでは、すべてのポジションが閉鎖され、さらにCStrategyに属するすべての保留中の注文が削除されます。同じことがBuyOnlyに適用されています。すべての保留中の注文がキャンセルされます。「停止」モードを選択すると、両方向のすべての保留中の注文も削除されます。

実行中に見つかったバグを報告してください。検出されたバグは修正されます。 


結論

新しい関数は、記事の第1パートで取引エンジンに追加されました。トレーリングをサポートしています。各トレーリングストップはストップロスのレベルを変更し、Modifyメソッドが含まれているクラスです。また、トレーリングを設定するパラメータが含まれています。トレーリングストップは、2つのメソッドで使用することができます。

  • ストラテジーやオートパイロットモードの取引エンジンで実現できるトレーリングのストップ操作を有効にすることができます。。後者の場合、デフォルトで自動的にポジションに適用されます。カスタムストラテジー側からの制御は、この場合には必要ありません。 
  • カスタムストラテジー側でストップを管理 この場合、カスタムストラテジーはトレーリングストップ関数を使用して、独自のポジションを管理します。このモードでは、複雑な制御ロジックを実装でき - 異なるポジションごとに異なる学習アルゴリズムを使用しています。
各トレーリングストップでは、管理するポジションに関する完全な情報が含まれています。また、ポジションの変更メソッドは、任意の時点でポジションを閉じることができます。このメソッドは、トレーリングアルゴリズムの高い柔軟性をもたらします。形式的に、任意のポジションの制御アルゴリズムは、トレーリングストップアルゴリズムとして作用することができます。たとえば、ストップロスのレベルを変更するので、このアルゴリズムは、テイクプロフィットのレベルを変更することができます。取引エンジンがまだ正常に動作している間、このような変化は、取引ロジックを壊しません。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/2411

添付されたファイル |
実際ティックでの取引ストラテジーのテスト 実際ティックでの取引ストラテジーのテスト
この記事では、簡単な取引ストラテジーを3つのモード(履歴からの記録ティックを使用した『リアルティックに基づいた全てのティック』、『1分足OHLC』、『全ティック』)でテストします。
エリック・ナイマンの『チャネル』インディケータ エリック・ナイマンの『チャネル』インディケータ
この記事では、エリック・L・ナイマン氏の著書『トレーダーの小百科事典』を元に『チャネル』インディケータの作成について述べていきます。このインディケータは、指定した期間で計算したベアとブルの値に基づき、トレンドの方向を表示します。この記事では、サンプルコードと共にインディケータの計算と構築の原理を説明し、インディケータをベースにエキスパートアドバイザを作成し、外部パラメータの最適化について述べていきます。
ユニバーサルEA:シグナルの標準メタトレーダーモジュールとの統合(その7) ユニバーサルEA:シグナルの標準メタトレーダーモジュールとの統合(その7)
このパートでは、シグナルモジュールとCStrategyエンジンの統合の可能性が、メタトレーダーの標準ライブラリにあることについて記述します。この記事では、カスタム戦略を作成するメソッドと同様に、シグナルの操作メソッドについて説明します。
MQL5でのエラー処理とロギング MQL5でのエラー処理とロギング
この記事では、ソフトウェアにおける一般的なエラー処理の問題について述べていきます。また、ロギングについて言及し、MQL5のツールによるデータロガーの実装例をデモンストレーションします。