English Русский 中文 Español Deutsch Português
ユニバーサルEA:シグナルの標準メタトレーダーモジュールとの統合(その7)

ユニバーサルEA:シグナルの標準メタトレーダーモジュールとの統合(その7)

MetaTrader 5 | 11 8月 2016, 15:06
1 451 0
Vasiliy Sokolov
Vasiliy Sokolov

目次


イントロダクション

戦略アルゴリズムを作成している - 以前の記事では、効率的でシンプルな取引アルゴリズムになるメカニズムについて議論しました。このプロジェクトは6ヶ月以上進化し続けています。この間、新しいモジュールは、トレーディング業務の技術的な執行の観点から、取引プロセスをより効率的かつ安全にするため、CStrategyに追加されました。しかし、エンジンはまだ重要な関数を欠いていました。CStrategyは、オブジェクト指向のアプリケーションであるという事実にもかかわらず、"自分自身を"取り残しました。オブジェクト指向のアプローチは、コードのオープン性とモジュール性を仮定しています。実際には、コードベースは、共通の一般的なクラスに基づくべきです。特に、取引モデルとシグナル生成モデルに関して強く言えます。戦略取引ロジックは、標準CTrade取引モジュールに基づいていますが、CStrategyにおけるシグナルのデータベースとそれほど良いものではありません。簡単に言えば、CStrategyは、売買シグナルを生成する任意のモジュールが含まれていませんでした。以前のバージョンでは、必要なシグナルが標準MT5パッケージで利用可能であったとしても、EAのロジックを再書き込みしなければなりませんでした。したがって、標準的なMT5のシグナルのデータベースを操作するための戦略メカニズムの新しいバージョンに追加することを決めました。この記事では、標準的なシグナルモジュールとCStrategyを統合するために、排他的に既製のアルゴリズムを使用して、どのように独自の戦略を作成するかを紹介します。

 

戦略ジェネレータで使用するクラスの概要

標準のMT5パッケージに含まれる様々なクラスのセットは、MQLウィザードを使用して、自動化戦略を生成するために使用されます。MQL5\Includeサブフォルダにmqhファイルを含めるようにクラスが用意されています。これらのクラス(またはモジュール)は、いくつかのカテゴリーに分けることができます。以下がカテゴリーです。

  • データを整理するための基本クラス(CObject, CArrayDouble, CArrayObjなど)。取引のための他のモジュールは、これらのクラスに基づいて構築されています。
  • インジケータバッファ(CDoubleBuffer, CIndicatorBuffer)にアクセスするためのクラス。それぞれ、インジケータを操作するために使用されています。
  • インジケータクラスと共通のCSeriesクラスに基づいた時系列クラス。
  • 基本的なCBaseExpertとCExpertはそれから派生しました。すべての補助モジュールはCBaseExpertに基づいています。 - 例えば、資産の計算、ストップ制御モジュールのモジュールなど。CExpertは、すべてのカスタムEAの基礎となっています。
  • CErtBaseに基づいたCExpertSignalのシグナルモジュール。シグナルのモジュールは、取引売買シグナルを生成します。シグナルに基づいたインジケータのクラスを使用します。
  • CExpertTradeの取引モジュール。CTradeクラスに基づいて、トレード操作の実行へのアクセスを提供しています。

以下の図は、戦略の自動生成の過程で使用されるクラスの一般的なスキームを示しています。

 

図1。戦略ジェネレーターの標準クラスの継承

図は、いくつかの派生クラスの基本的な表示。このスキームは、CIndicatorsから継承されたすべてのインジケータを備えていません。資金の管理およびシグナルモジュールは、スキームに含まれていません。その代わり、基本的な関係が内包されています。特色グループの一つは、シグナルクラスCExpertSignalとその子クラスです。図1において、そのグループは緑色の点線で強調表示されています。

垂直リンクに加えて、クラスが水平リンクの複雑なシステムを形成します。例えば、シグナルモジュールは、順番にインジケータバッファを使用し、インジケータのクラスを使用します。セットは、お互いのパートです。これらのモジュールは、EAを行うには何を持っているかどうか明らかでないが、例えば、資金管理モジュールは、(少なくともCExpertBaseのレベルで)同じ時間取引のEAです。

原則として、複雑な初期化チェインは、これらのクラスのオブジェクトを作成するために必要とされます。たとえば、CSignalMacdなどのシグナルオブジェクトを作成するために、シグナルを初期化し、そのインジケータだけでなく、シグナルの動作に必要な時系列を(CPriceSeriesの子クラス)を初期化する必要があります。オブジェクトは複雑なオブジェクトで初期化することができるので、(時系列等の)初期化を必要とします。このように、初期化の問題がイブラリの中で最も複雑なパートの1つです。

それでは、次の例を分析してみましょう。このクラスの対応するオブジェクトの作成時に、そのクラス内CMacdSignalモジュールを初期化する必要があるとします。次のようにシグナルモジュールの初期化コードは次のようになります。

//+------------------------------------------------------------------+
//|CSignalMACDシグナルモジュールの初期化|
//+------------------------------------------------------------------+
CStrategyMACD::CStrategyMACD(void)
{
   CSymbolInfo* info = new CSymbolInfo();                // 戦略の取引シンボルを表すオブジェクトを作成します戦略の取引シンボルを表すオブジェクトを初期化します
   info.Name(Symbol());                                  // 戦略の取引シンボルを表すオブジェクトを初期化します
   m_signal_ma.Init(info, Period(), 10);                 //取引シンボルと時間枠でモジュールの初期化
   m_signal_ma.InitIndicators(GetPointer(m_indicators)); // m_indicatorsの空のリストに基づいて、モジュールに必要な指標を作成します
   m_signal_ma.EveryTick(true);                          // テストモード
   m_signal_ma.Magic(ExpertMagic());                     //マジックナンバー
   m_signal_ma.PatternsUsage(8);                         //パターンマスク
   m_open.Create(Symbol(), Period());                    // 始値の時系列の初期化
   m_high.Create(Symbol(), Period());                    // 高値の時系列の初期化
   m_low.Create(Symbol(), Period());                     // 安値の時系列の初期化
   m_close.Create(Symbol(), Period());                   // 終値の時系列の初期化
   m_signal_ma.SetPriceSeries(GetPointer(m_open),        // オブジェクトによるモジュールの初期化
                              GetPointer(m_high),
                              GetPointer(m_low),
                              GetPointer(m_close));
}

初期化の問題は、自動化された戦略ジェネレータのユーザに関連しないことに留意すべきです。初期化のチェーン全体は、すべてのユーザーが行う必要があり、戦略・ジェネレータに自動的に作成されます。この状況は、独自のソリューションを作成するクラスのセットを使用する人ごとに異なっています。この場合には、全体の初期化チェーンを実行するのに必要です。

 

シグナルモジュールの概要、パターンの概念

既に述べたように、シグナルモジュールは、CExpertBaseの代わりに、共通CExpertSignalクラスに基づいています。シグナルの各標準モジュールは、実際には1つ以上を検索する関数を持つクラスである。(パターン - 売買の瞬間を決定する特別な論理条件。)たとえば、短期移動平均が逆さまからゆっくりと1を超えた場合、それは買いパターンを形成します。各インジケータは、売買のための条件を形成することができます。簡単な例では、MACDのインジケータです。両方のインジケータとヒストグラムのシグナル線の単純な交差はシグナルとして解釈することができます。これらの取引の条件の両方が異なるパターンを表します。エントリーは、これらのイベントの複数の発生時に可能です。売買のパターンが異なっており、通常は反対の状態を表していることに留意することが重要です。自動化された戦略の観点から、シグナルは、共通のインジケータを有する1つ以上のパターンのプロセッサです。例えば、MACDに基づくシグナルは、市場にいくつかのパターンの存在を検出することができます。MACD基づくシグナルの標準モジュールは、5つの買いパターンと5つの売りパターンが含まれています。

  • 逆転 - オシレーターが上がる(買い)または下がる(売り)
  • メインとシグナル線の交点
  • ゼロレベルを横切る
  • ダイバージェンス
  • ダブルダイバージェンス

パターンの詳細な説明は、ターミナルヘルプファイルで利用可能なので、ここで詳細は説明しません。他のシグナルモジュールは、異なるパターン、およびそれらの異なる数を含みます。一般的に、すべてのシグナルが3つの買いパターンと3つの売りパターンが含まれています。シグナルは(これが使用されるパターンのマスクを格納する整数変数のビットフィールドの長さである)、最大32パターンのを含めることができます。

シグナルはパターンを識別することができ、それはまた、整数として、いくつかの特徴を与えることができます。強く、大きなシグナル:この数は、シグナル強度を示すことが期待されます。xは、パターンのインジケータであるメソッドの特別なグループPattern_x(int値)を用いて、パターンのそれぞれに対するシグナル強度を設定することができます。例えば、以下はシグナル構成コードに書き込まれます。

//+------------------------------------------------------------------+
//|CSignalMACDシグナルモジュールの初期化|
//+------------------------------------------------------------------+
CStrategyMACD::CStrategyMACD(void)
{
   m_signal_ma.Pattern_0(0);
   m_signal_ma.Pattern_1(0);
   m_signal_ma.Pattern_2(0);
   m_signal_ma.Pattern_3(100);
   m_signal_ma.Pattern_4(0);
   m_signal_ma.Pattern_5(0);
}

ダイバージェンスが形成されている場合、CSignalMacdシグナルモジュールは、オシレーターの最初の谷が以前のものよりも浅くなっているパターンです。他のすべてのパターンはスキップされます。

取引は、2つの独立したメソッドのLongConditionとShortConditionによって返されます。前者は買いを返し、後者は売りを返します。どのような関数かを理解するために、それらの内部を見てみましょう。LongConditionの条件は以下のとおりです。

//+------------------------------------------------------------------+
//|価格が成長するインジケータ。 |
//+------------------------------------------------------------------+
int CSignalMACD::LongCondition(void)
  {
   int result=0;
   int idx   =StartIndex();
//---メインラインの方向を確認します
   double diff = DiffMain(idx);
   if(diff>0.0)
     {
      //---メインラインは上向きに、価格の上昇を確認します
      if(IS_PATTERN_USAGE(0))
         result=m_pattern_0;      //シグナルの確認0
      //---パターン1が使用される場合、、メインラインの逆が検索されます
      if(IS_PATTERN_USAGE(1) && DiffMain(idx+1)<0.0)
         result=m_pattern_1;      //シグナルナンバー1
      //---パターン2が使用される場合、シグナルとメインラインのクロスオーバーを検索
      if(IS_PATTERN_USAGE(2) && State(idx)>0.0 && State(idx+1)<0.0)
         result=m_pattern_2;      //シグナルナンバー2
      //---パターン3が使用される場合、ゼロレベルのメインラインのクロスオーバーを検索 
      if(IS_PATTERN_USAGE(3) && Main(idx)>0.0 && Main(idx+1)<0.0)
         result=m_pattern_3;      // シグナルナンバー3
      //---パターン4,5が使用され、メインラインがゼロレベル以下であり、上昇している場合、ダイバージェンスが検索 
      if((IS_PATTERN_USAGE(4) || IS_PATTERN_USAGE(5)) && Main(idx)<0.0)
        {
         //---オシレーターの状態の拡張分析 
         ExtState(idx);
         //---パターン4が使用される場合、ダイバージェンスシグナルが期待されています 
         if(IS_PATTERN_USAGE(4) && CompareMaps(1,1)) // 0000 0001b
            result=m_pattern_4;   // シグナルナンバー4
         //---パターン5を使用する場合、ダブルダイバージェンスシグナルが期待されます 
         if(IS_PATTERN_USAGE(5) && CompareMaps(0x11,2)) // 0001 0001b
            return(m_pattern_5);  //シグナルナンバー5
        }
     }
//---結果を返します
   return(result);
  }

 このメソッドは、パターン検出マクロ IS_PATTERN_USAGEと連携して動作します。

//---市場のパターンが使用されているかどうかを確認します
#define IS_PATTERN_USAGE(p)          ((m_patterns_usage&(((int)1)<<p))!=0)

パターンが使用され、対応する条件が満たされた場合、次に、Pattern_xを介してユーザによって定義され、対応するパターンの重みに等しくなります。しかし、複数のパターンを使用している場合、チェックが割り込み演算子を持っていないため、どれが引き金となったか見つけることができません。この場合、最後の決定されたパターンの重みに等しくなります。

使用するパターンの数は、特別なビットマスクで与えられるべきです。たとえば、パターンナンバー3を使用する場合、32ビット変数の4番目のビットは、4桁目の第3パターンに使用されるように、パターンのインデックス作成は、(1と同じである必要があり)ゼロのパターンに使用されます。10進バイナリで数千を変換する場合、8を得ます。つまり、PatternsUsage上のメソッドに渡す必要がある数です。パターンを組み合わせることができます。1100:たとえば、ナンバー2のパターンとパターンナンバー3を使用するために、第一に等しくなる三桁のビットフィールドを作成する必要があります。10進形式で同じ値が12です。

 

シグナルのモジュール。最初の使用

これで、シグナルの係数を使用して起動するのに十分です。CStrategyに基づいて実験してみましょう。この目的のために、特別な実験的クラス、CSignalSamplesの戦略を作成します。

//+------------------------------------------------------------------+
//|                                                EventListener.mqh |
//|           Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia |
//|                                https://www.mql5.com/ja/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link      "https://www.mql5.com/ja/users/c-4"
#include <Strategy\Strategy.mqh>
#include <Expert\Signal\SignalMACD.mqh>
//+------------------------------------------------------------------+
//|この戦略は、イベントを受信し、端末に表示します。|
//+------------------------------------------------------------------+
class CSignalSamples : public CStrategy
{
private:
   CSignalMACD       m_signal_macd;
   CSymbolInfo       m_info;
   CiOpen            m_open;
   CiHigh            m_high;
   CiLow             m_low;
   CiClose           m_close;
   CIndicators       m_indicators;
public:
                     CSignalSamples(void);
   virtual void      OnEvent(const MarketEvent& event);                     
};
//+------------------------------------------------------------------+
//|CSignalMACDシグナルモジュールの初期化|
//+------------------------------------------------------------------+
CSignalSamples::CSignalSamples(void)
{
   m_signal_macd.Pattern_0(0);
   m_signal_macd.Pattern_1(0);
   m_signal_macd.Pattern_2(0);
   m_signal_macd.Pattern_3(100);
   m_signal_macd.Pattern_4(0);
   m_signal_macd.Pattern_5(0);
   m_info.Name(Symbol());                                  // 戦略の取引シンボルを表すオブジェクトを初期化します
   m_signal_macd.Init(GetPointer(m_info), Period(), 10);   // 取引シンボルと時間枠でモジュールの初期化
   m_signal_macd.InitIndicators(GetPointer(m_indicators)); // 指標指標の空のリストに基づいて、モジュールに必要な指標を作成します
   m_signal_macd.EveryTick(true);                          // テストモード
   m_signal_macd.Magic(ExpertMagic());                     //マジックナンバー
   m_signal_macd.PatternsUsage(8);                         //パターンマスク
   m_open.Create(Symbol(), Period());                      //始値の初期化
   m_high.Create(Symbol(), Period());                      //高値の初期化
   m_low.Create(Symbol(), Period());                       //安値の初期化
   m_close.Create(Symbol(), Period());                     //終値の初期化
   m_signal_macd.SetPriceSeries(GetPointer(m_open),        //オブジェクトによるモジュールの初期化
                              GetPointer(m_high),
                              GetPointer(m_low),
                              GetPointer(m_close));
                              
}
//+------------------------------------------------------------------+
//|買い。 |
//+------------------------------------------------------------------+
void CSignalSamples::OnEvent(const MarketEvent &event)
{
   if(event.type != MARKET_EVENT_BAR_OPEN)
      return;
   m_indicators.Refresh();
   m_signal_macd.SetDirection();
   int power_sell = m_signal_macd.ShortCondition();
   int power_buy = m_signal_macd.LongCondition();
   if(power_buy != 0 || power_sell != 0)
      printf("PowerSell: " + (string)power_sell + " PowerBuy: " + (string)power_buy);
}
//+------------------------------------------------------------------+


CStrategyの最新バージョンは、新しいイベントの OnEventが発生するたびに呼び出されるメソッドで表されます。よく知られたメソッドのBuyInit、SellInit、BuySupport、SellSupportとは異なり、 OnEventは取引戦略モードと取引スケジュール関係なく、呼ばれます。したがって、OnEventのイベントモデルを維持しながら、イベントのストリームにアクセスすることができます。OnEventを、特定の売買に関連しない一般的な計算やアクションに使用することは非常に便利です。

このコードのほとんどは、売買シグナルモジュールの初期化に専念しています。CSignalMACD:例として、MACDインジケータに基づいてモジュールを使用していました。パターン3は、モジュールで使用されています。重り100は、このモジュールに割り当てられ、8の値が適切なパターンに使用されます。この戦略を実行するため、戦略ローダーまたはmq5モジュールを用意する必要があります。コンテンツ:

//+------------------------------------------------------------------+
//|                                                       Agent.mq5  |
//|           Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia |
//|                                https://www.mql5.com/ja/users/c-4 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, Vasiliy Sokolov."
#property link      "https://www.mql5.com/ja/users/c-4"
#property version   "1.00"
#include <Strategy\StrategiesList.mqh>
#include <Strategy\Samples\SignalSamples.mqh>
CStrategyList Manager;
//+------------------------------------------------------------------+
//|エキスパート初期化関数|
//+------------------------------------------------------------------+
int OnInit() 
{
   CSignalSamples* signal = new CSignalSamples();
   signal.ExpertMagic(2918);
   signal.ExpertName("MQL Signal Samples");
   signal.Timeframe(Period());
   if(!Manager.AddStrategy(signal))
      delete signal;
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//|EAティック関数|
//+------------------------------------------------------------------+
void OnTick()
{
  Manager.OnTick();
}
//+------------------------------------------------------------------+
//|OnChartEvent関数|
//+------------------------------------------------------------------+
void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
   Manager.OnChartEvent(id, lparam, dparam, sparam);
}

これは、OnInit関数の初期化、およびOnTickのハンドラで構成されています。ストラテジーテスターのビジュアルモードで実行した後は、受信したシグナルに関する通知が表示されます。

2016.06.20 16:34:31.697 tester agent shutdown finished
2016.06.20 16:34:31.642 shutdown tester machine
2016.06.20 16:34:31.599 tester agent shutdown started
2016.06.20 16:34:31.381 log file "Z:\MetaTrader 5\Tester\Agent-127.0.0.1-3000\logs\20160620.log" written
2016.06.20 16:34:31.381 325 Mb memory used including 28 Mb of history data, 64 Mb of tick data
2016.06.20 16:34:31.381 EURUSD,M1: 51350 ticks (12935 bars) generated in 0:00:00.780 (total bars in history 476937, total time 0:00:00.843)
2016.06.20 16:34:31.376 final balance 100000.00 USD
2016.06.20 16:34:31.373 2016.04.14 22:12:00   PowerSell: 100 PowerBuy: 0
2016.06.20 16:34:31.373 2016.04.14 22:01:00   PowerSell: 0 PowerBuy: 100
2016.06.20 16:34:31.373 2016.04.14 21:24:00   PowerSell: 100 PowerBuy: 0
2016.06.20 16:34:31.373 2016.04.14 20:54:00   PowerSell: 0 PowerBuy: 100
2016.06.20 16:34:31.373 2016.04.14 20:50:00   PowerSell: 100 PowerBuy: 0
2016.06.20 16:34:31.373 2016.04.14 20:18:00   PowerSell: 0 PowerBuy: 100
2016.06.20 16:34:31.373 2016.04.14 20:14:00   PowerSell: 100 PowerBuy: 0
2016.06.20 16:34:31.373 2016.04.14 20:13:00   PowerSell: 100 PowerBuy: 0
2016.06.20 16:34:31.373 2016.04.14 20:07:00   PowerSell: 0 PowerBuy: 100
2016.06.20 16:34:31.372 2016.04.14 19:48:00   PowerSell: 100 PowerBuy: 0
2016.06.20 16:34:31.372 2016.04.14 18:48:00   PowerSell: 0 PowerBuy: 100
...
...

この通知は、要求されたシグナルが正常に受信されたことを示しています。

 

CSignalMACDに基づいて、最初の戦略を書きます。

CSignalMACDシグナルモジュールに基づいて、関数を書きましょう。使用する第一のパターンは、オシレーターとシグナル線の交点のパターンです。ドキュメントを使ってみましょう。MQL5 Reference -> Standard Library -> Trading Strategy Classes -> Modules of Trade Signals -> Signals of the Oscillator MACDを開いてください。第二のパターン「メインとシグナルのクロスオーバー」を検索します。次のとおりです。

    • 買い:「メインとシグナルのクロスオーバー" - メインラインがバーと以前の1のシグナル線の下のシグナル線上にある

    • 図2。オシレーターは、下から上にシグナル線を横切ります

    • 売り:"メインとシグナルのクロスオーバー" - メインラインと以前の1のシグナル線の上のシグナル線を下回る。

    図3。オシレーターは、上から下へのシグナル線を越えます

    これに対応するパターンの数を定義する必要があります。CSignalMACDクラスのヘッダを支援します。

    //+------------------------------------------------------------------+
    //|クラスCCSignalMACD。 |
    //|目的:トレードシグナルに基づくジェネレーターのクラス|
    //|「平均ダイバージェンスオシレーター。|
    //|CExpertSignalクラスから派生。 |
    //+------------------------------------------------------------------+
    class CSignalMACD : public CExpertSignal
      {
    protected:
       CiMACD            m_MACD;           //オシレーターオブジェクト
       //---調整パラメータ
       int               m_period_fast;    // オシレータパラメータ「高速EMAの期間」 
       int               m_period_slow;    // オシレータパラメータ「スローEMAの期間」 
       int               m_period_signal;  // 平均期間の差" 
       ENUM_APPLIED_PRICE m_applied;       //価格方式 
       //---市場モデルの「重み」(0-100)
       int               m_pattern_0;      // パターン0 指定の方向にオシレーターが動く
       int               m_pattern_1;      // パターン1 指定の方向の逆にオシレーターが動く
       int               m_pattern_2;      // パターン2 メインとシグナルのクロスオーバー
       int               m_pattern_3;      // パターン3 メインの0ラインクロス
       int               m_pattern_4;      // パターン4 オシレーターと価格のダイバージェンス
       int               m_pattern_5;      // パターン5 ダブルダイバージェンス
       //---変数
       double            m_extr_osc[10];   // オシレーターの極値の配列 
       double            m_extr_pr[10];    // 適切な極値の配列
       int               m_extr_pos[10];   // 極値シフト配列 (足) 
       uint              m_extr_map;       // オシレーターの極値、価格のビットマップ 
    ...
      }
    
    

    コード内のコメントから、パターンの種類は2であることがわかります。

    パターンの番号を適切に設定する必要があります。まず、混乱を避けるために、他のパターンを使用しません。このため、(バイナリ形式で100)4に等しいパターンマスクを設定します。1つのパターンのみを使用しようとしているので、シグナル強度を(パターンの強度を設定しないように)知る必要はありません - どちらかのシグナルがあり、または全くシグナルがありません。新しいバーのオープンにシグナルをチェックするので、偽のフラグを適切なシグナル方式EveryTickで呼び出すことによって、このことを示す必要があります。設定は戦略コンストラクタで実装する必要があります。その後、取引ロジックのプログラムに進みます。InitBuy、SupportBuy、InitSell、SupportSellをオーバーライドしてみましょう。接頭辞は戦略がシグナルの標準モジュールに基づいていることを示しています。:COnSignalMACDに名前を付けましょう。戦略コードを以下に示します。

    //+------------------------------------------------------------------+
    //|                                                EventListener.mqh |
    //|           Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia |
    //|                                https://www.mql5.com/ja/users/c-4 |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2016, Vasiliy Sokolov."
    #property link      "https://www.mql5.com/ja/users/c-4"
    #include <Strategy\Strategy.mqh>
    #include <Expert\Signal\SignalMACD.mqh>
    //+------------------------------------------------------------------+
    //|この戦略は、イベントを受信し、端末に表示します。|
    //+------------------------------------------------------------------+
    class COnSignalMACD : public CStrategy
    {
    private:
       CSignalMACD       m_signal_macd;
       CSymbolInfo       m_info;
       CiOpen            m_open;
       CiHigh            m_high;
       CiLow             m_low;
       CiClose           m_close;
       CIndicators       m_indicators;
    public:
                         COnSignalMACD(void);
       virtual void      InitBuy(const MarketEvent &event);
       virtual void      InitSell(const MarketEvent &event);
       virtual void      SupportBuy(const MarketEvent& event, CPosition* pos);
       virtual void      SupportSell(const MarketEvent& event, CPosition* pos);
    };
    //+------------------------------------------------------------------+
    //|CSignalMACDシグナルモジュールの初期化|
    //+------------------------------------------------------------------+
    COnSignalMACD::COnSignalMACD(void)
    {
       m_info.Name(Symbol());                                  // 戦略の取引シンボルを表すオブジェクトを初期化します
       m_signal_macd.Init(GetPointer(m_info), Period(), 10);   // 取引シンボルと時間枠でモジュールの初期化
       m_signal_macd.InitIndicators(GetPointer(m_indicators)); // 指標の空のリストに基づいたシグナルモジュールの評価に必要な指標
       m_signal_macd.EveryTick(false);                         // テストモード
       m_signal_macd.Magic(ExpertMagic());                     //マジックナンバー
       m_signal_macd.PatternsUsage(4);                         // パターンマスク
       m_open.Create(Symbol(), Period());                      //始値の初期化
       m_high.Create(Symbol(), Period());                      //高値の初期化
       m_low.Create(Symbol(), Period());                       //安値の初期化
       m_close.Create(Symbol(), Period());                     //終値の初期化
       m_signal_macd.SetPriceSeries(GetPointer(m_open),        //オブジェクトによるモジュールの初期化
                                  GetPointer(m_high),
                                  GetPointer(m_low),
                                  GetPointer(m_close));
    }
    //+------------------------------------------------------------------+
    //|買い。 |
    //+------------------------------------------------------------------+
    void COnSignalMACD::InitBuy(const MarketEvent &event)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       m_indicators.Refresh();
       m_signal_macd.SetDirection();
       int power_buy = m_signal_macd.LongCondition();
       if(power_buy != 0)
          Trade.Buy(1.0);
    }
    //+------------------------------------------------------------------+
    //||買いの終わり
    //+------------------------------------------------------------------+
    void COnSignalMACD::SupportBuy(const MarketEvent &event, CPosition* pos)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       m_indicators.Refresh();
       m_signal_macd.SetDirection();
       int power_sell = m_signal_macd.ShortCondition();
       //printf("Power sell: " + (string)power_sell);
       if(power_sell != 0)
          pos.CloseAtMarket();
    }
    //+------------------------------------------------------------------+
    //| 売り。 |
    //+------------------------------------------------------------------+
    void COnSignalMACD::InitSell(const MarketEvent &event)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       m_indicators.Refresh();
       m_signal_macd.SetDirection();
       int power_sell = m_signal_macd.ShortCondition();
       if(power_sell != 0)
          Trade.Sell(1.0);
    }
    //+------------------------------------------------------------------+
    //||買いの終わり
    //+------------------------------------------------------------------+
    void COnSignalMACD::SupportSell(const MarketEvent &event, CPosition* pos)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       m_indicators.Refresh();
       m_signal_macd.SetDirection();
       int power_buy = m_signal_macd.LongCondition();
       if(power_buy != 0)
          pos.CloseAtMarket();
    }
    //+------------------------------------------------------------------+
    
    
    

    ロングとショートは記載されたシグナルに基づいて開かれます。既存のポジションを逆のシグナルで閉じられます。ロングポジションを開くための条件がある場合、以前に開かれたショート・ポジションは閉じます。

    取引結果はストラテジーテスターで見ることができます。ヒストリーの一部は次の図で紹介されています。

     

    図4。MACDヒストグラムの交差とシグナル線で取引

    テストモードに応じて、シグナルは前のバーに受信された時に取引が開かれます。図は、MACDヒストグラムとシグナル線の交差点以下のバーでロングまたはショート開かれ、前のポジションが閉じていることを示しています。

     

    シグナルのアダプタ

    シグナルで作業を開始する前に、設定する必要があります。シグナルに渡す前に設定する必要があります。異なるシグナルがさまざまなオブジェクトを必要とします。例えば、他のシグナルを使用すると、いくつかのシグナルは基本的な時系列の仕様を必要とします。ユーザはシグナルの内部システムを知っている必要があり、その適正な動作に必要とされるので、ユーザレベルでのシグナルの使用を複雑にします。

    これらの困難を避けるために、アダプタクラスを導入します。このクラスは、 CSignalAdapterと呼ばれ、戦略プロジェクトの共通のディレクトリに配置されています。このアダプターは、シンプルなインターフェースです。シグナルを生成し、売買パターン形成のフラグを受け取ることができます。シグナルを作成するために、特別なメソッドでシグナルアダプターCreateSignalにシグナルパラメータを渡す必要があります。シグナルパラメータは、 MqlSignalParams構造体に含まれています。この構造体の定義は次のとおりです。

    //+--------------------------------------------------------------------+
    //|シグナルパラメータ|
    //+--------------------------------------------------------------------+
    struct MqlSignalParams
    {
    public:
       string            symbol;           // シンボル
       ENUM_TIMEFRAMES   period;           // チャート期間
       ENUM_SIGNAL_TYPE  signal_type;      // シグナルタイプ
       int               index_pattern;    //パターンインデックス
       int               magic;            // EAマジックナンバー
       double            point;            // ポイントナンバー
       bool              every_tick;       // "Every tick"テストモード
       void operator=(MqlSignalParams& params);
    };
    //+--------------------------------------------------------------------+
    //|文字列を使用するため、コピーオペレーターが試用されます。|
    //+--------------------------------------------------------------------+
    void MqlSignalParams::operator=(MqlSignalParams& params)
    {
       symbol = params.symbol;
       period = params.period;
       signal_type = params.signal_type;
       usage_pattern = params.usage_pattern;
       magic = params.magic;
       point = params.point;
       every_tick = params.every_tick;
    }
    
    

    この構造体は、次のシグナル特性を定義する基本的なタイプが含まれています。

    • シンボル;
    • 時間枠;
    • シグナルタイプ。
    • EAマジックナンバー。
    • "すべてのティック」のテストモードを示すフラグ。
    • 価格フィルタ
    • 使用するシグナルパターン。

    ここでindex_patternのいくつかの詳細があります。モジュールのシグナルとは異なり、それはパターンマスクを受け入れ、いずれかのインジケータを受信します。このように、すべてのシグナルアダプタは、選択したシグナルのいずれかのパターンを使用することができます。インデックスパターンの値が1から31以内でなければならず、使用されるシグナルのパターンの数と同じでなければなりません。

    それは文字列型を使用しているため、基本的なパラメータに加えて、構造体にはコピー演算子が含まれています。これが、自動的に別の構造体をコピーできない理由です。適切な構造体が必要なパラメータを決定し、ユーザーはCSignalAdapter:: CreateSignalメソッドを呼び出すことができ、それに応答して、このメソッドから作成されたシグナルのインスタンスを受け取ります。受信されたインスタンスは、さらに対応するシグナルの関数を取るように構成することができます。

    以下のリストは、CSignalAdapterアダプタを使用してCSignalMACDシグナルを構成するメソッドを示しています。

    //+------------------------------------------------------------------+
    //|                                                EventListener.mqh |
    //|           Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia |
    //|                                https://www.mql5.com/ja/users/c-4 |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2016, Vasiliy Sokolov."
    #property link      "https://www.mql5.com/ja/users/c-4"
    #include <Strategy\Strategy.mqh>
    #include <Strategy\SignalAdapter.mqh>
    
    //+------------------------------------------------------------------+
    //|この戦略は、イベントを受信し、端末に表示します。|
    //+------------------------------------------------------------------+
    class CAdapterMACD : public CStrategy
    {
    private:
       CSignalAdapter    m_signal;
       MqlSignalParams   m_params;
    public:
                         CAdapterMACD(void);
       virtual void      InitBuy(const MarketEvent &event);
       virtual void      InitSell(const MarketEvent &event);
       virtual void      SupportBuy(const MarketEvent& event, CPosition* pos);
       virtual void      SupportSell(const MarketEvent& event, CPosition* pos);
    };
    //+------------------------------------------------------------------+
    //||アダプタの設定
    //+------------------------------------------------------------------+
    CAdapterMACD::CAdapterMACD(void)
    {
       m_params.symbol = Symbol();
       m_params.period = Period();
       m_params.every_tick = false;
       m_params.signal_type = SIGNAL_MACD;
       m_params.magic = 1234;
       m_params.point = 1.0;
       m_params.usage_pattern = 2;
       CSignalMACD* macd = m_signal.CreateSignal(m_params);
       macd.PeriodFast(15);
       macd.PeriodSlow(32);
       macd.PeriodSignal(6);
    }
    
    

    パラメータは、アダプタを設定する必要があります。しかし、EAの最初のバージョンとは異なり、すべてのパラメータは些細です。時系列やインジケータなどの他の複雑なオブジェクトを、監視する必要はありません。これはすべてのアダプタによって行われます。それが大幅にシグナルでの作業を簡素化する理由です。  

    シグナルを作成した後、MACDインジケーター(15、32、6)の期間を設定することで、構成し続けていることに注意してください。CreateSignalメソッドで、対応するオブジェクトを返したので、これは簡単です。

    シグナルが正しく設定されたら、それを使用して起動することができます。シンプルなメソッドBuySignalとShortSignalは、この目的のために使用します。戦略クラスは次のとおりです。

    //+------------------------------------------------------------------+
    //|買い。 |
    //+------------------------------------------------------------------+
    void CAdapterMACD::InitBuy(const MarketEvent &event)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       if(m_signal.LongSignal())
          Trade.Buy(1.0);
    }
    //+------------------------------------------------------------------+
    //||買いの終わり
    //+------------------------------------------------------------------+
    void CAdapterMACD::SupportBuy(const MarketEvent &event, CPosition* pos)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       if(m_signal.ShortSignal())
          pos.CloseAtMarket();
    }
    //+------------------------------------------------------------------+
    //|売り|
    //+------------------------------------------------------------------+
    void CAdapterMACD::InitSell(const MarketEvent &event)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       if(m_signal.ShortSignal())
          Trade.Sell(1.0);
    }
    //+------------------------------------------------------------------+
    //||買いの終わり
    //+------------------------------------------------------------------+
    void CAdapterMACD::SupportSell(const MarketEvent &event, CPosition* pos)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       if(m_signal.LongSignal())
          pos.CloseAtMarket();
    }
    
    

    上記のロジックでは、前の例と同じように:MACDヒストグラムとそのシグナル線の交点でロングとショートを開きます。しかし、コードはより短くなります。シグナルコードの最初のバージョンとは異なり、現在のシグナルの方向を毎回定義・更新する必要がありません。戦略コードに補助オブジェクトを追加する必要があります。これらのアクションは、アダプタによって実行されます。

     

    取引戦略のコードで複数のシグナルを合成

    市場のエントリーと決済のための異なるパターン、さらには異なるシグナルを使用することはできるでしょうか?答えはYesです。シグナルシステムへの完全なアクセス権を持っているので、複数のパターンを使用することができます。パターンの混乱を避けるために、シグナルアダプタを使用する唯一のパターンを設定します。しかし、そのアダプタの数に制限はありません。この場合、すべてのパターンが1つのシグナルに基づいている場合であっても、別個のアダプタとシグナルによって表されます。もちろん、リソースの面で、標準ライブラリで利用可能なものよりわずかに効率的なメソッドですが、利点があります。

    別のエントリーと決済のシグナルを受信することができる戦略の例を書いてみましょう。戦略は、エントリーの買われ過ぎと売られ過ぎの領域に基づいて、RSIインジケータのパターンを使用します。第二のパターン - ビルウィリアムズによって提案されたアクセラレータオシレータ(AC)は、決済に使用します。ここではより詳細な戦略のルールがあります。

    買い買われ過ぎの場合 - オシレーターが上向きになり、その値は過剰なレベルにあります(デフォルト値は30です)。

     

    図5。ロングポジションのエントリー条件 

     

    売り: 売られ過ぎの場合 - オシレーターは下向きになって、その値は(デフォルト値は70です)売られ過ぎのレベルにあります。

     

    図 6。ショートポジションのエントリー条件

    買いの決済: ACインジケータの値が0以上である、かつ、前の2つのバーで立ち下がります。


    図 7。ロングポジションの終了条件 

    売り決済: ACインジケータの値が0以下であり、かつ、前の2つのバーで成長します:

     

    図 8。ショート・ポジションの終了条件

    ロングポジションの決済は、ACシグナルのパターンに基づいて行われます。

    このロジックは、以下で利用可能です:

    //+------------------------------------------------------------------+
    //|                                                EventListener.mqh |
    //|           Copyright 2016, Vasiliy Sokolov, St-Petersburg, Russia |
    //|                                https://www.mql5.com/ja/users/c-4 |
    //+------------------------------------------------------------------+
    #property copyright "Copyright 2016, Vasiliy Sokolov."
    #property link      "https://www.mql5.com/ru/users/c-4"
    #include <Strategy\Strategy.mqh>
    #include <Strategy\SignalAdapter.mqh>
    input int RSI_Period = 14; // RSI 期間
    //+------------------------------------------------------------------+
    //|この戦略は、イベントを受信し、端末に表示します。|
    //+------------------------------------------------------------------+
    class COnSignal_RSI_AC : public CStrategy
    {
    private:
       CSignalAdapter    m_adapter_rsi;
       CSignalAdapter    m_adapter_ac;
    public:
                         COnSignal_RSI_AC(void);
       virtual void      InitBuy(const MarketEvent &event);
       virtual void      InitSell(const MarketEvent &event);
       virtual void      SupportBuy(const MarketEvent& event, CPosition* pos);
       virtual void      SupportSell(const MarketEvent& event, CPosition* pos);
    };
    //+------------------------------------------------------------------+
    //|CSignalMACDシグナルモジュールの初期化|
    //+------------------------------------------------------------------+
    COnSignal_RSI_AC::COnSignal_RSI_AC(void)
    {
       MqlSignalParams params;
       params.every_tick = false;
       params.magic = 32910;
       params.point = 10.0;
       params.symbol = Symbol();
       params.period = Period();
       params.usage_pattern = 2;
       params.signal_type = SIGNAL_AC;
       CSignalAC* ac = m_adapter_ac.CreateSignal(params);
       params.usage_pattern = 1;
       params.magic = 32911;
       params.signal_type = SIGNAL_RSI;
       CSignalRSI* rsi = m_adapter_rsi.CreateSignal(params);
       rsi.PeriodRSI(RSI_Period);
    }
    //+------------------------------------------------------------------+
    //|買い。 |
    //+------------------------------------------------------------------+
    void COnSignal_RSI_AC::InitBuy(const MarketEvent &event)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       if(positions.open_buy > 0)
          return;
       if(m_adapter_rsi.LongSignal())
          Trade.Buy(1.0);
    }
    //+------------------------------------------------------------------+
    //||買いの終わり
    //+------------------------------------------------------------------+
    void COnSignal_RSI_AC::SupportBuy(const MarketEvent &event, CPosition* pos)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       if(m_adapter_ac.ShortSignal())
          pos.CloseAtMarket();
    }
    //+------------------------------------------------------------------+
    //| 売り。 |
    //+------------------------------------------------------------------+
    void COnSignal_RSI_AC::InitSell(const MarketEvent &event)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       if(positions.open_sell > 0)
          return;
       if(m_adapter_rsi.ShortSignal())
          Trade.Sell(1.0);
    }
    //+------------------------------------------------------------------+
    //||買いの終わり
    //+------------------------------------------------------------------+
    void COnSignal_RSI_AC::SupportSell(const MarketEvent &event, CPosition* pos)
    {
       if(event.type != MARKET_EVENT_BAR_OPEN)
          return;
       if(m_adapter_ac.LongSignal())
          pos.CloseAtMarket();
    }
    //+------------------------------------------------------------------+
    
    
    

    EAを使用すると、RSIの期間を指定することを可能にする外部パラメータがあります。これは、シグナルに直接アクセスして戦略コンストラクタで行われます。

    戦略の演算結果が下記の表に示されています:

     

    図 8。戦略結果 

    RSIとAC - グラフから分かるように、EAは2つのインジケータを使用します。RSIが上昇、または買わと売られ過ぎの領域の内側に落下し始めたときにEAがエントリーします。これらの領域は赤丸で囲まれています。ACインジケータが同じ色の3ラインを形成する場合、EAは決済します。買いポジション決済の場合、ラインは赤でなければならず、ゼロレベルを超えていなければなりません。売りポジション決済の場合、ラインは緑色でなければならず、ゼロレベルより下でなければなりません。このような瞬間は、青色のボックスに表示されています。

    このグラフは、EAのロジックが正しく処理されることを示しています。このEAの取引ルールは非自明です。しかし、戦略自体は長くはありません。コードの再利用のメリットです。

     

    結論

    戦略取引エンジンにシグナルの標準ライブラリを統合するメソッドを考えました。この統合により、CStrategyは標準的なシグナルのパターンに基づいて、カスタム戦略を作成するための非常に便利なツールになります。また、自動化されたメタトレーダーの戦略ジェネレータ用に書かれた、任意のシグナルが自動的に戦略取引エンジンで利用可能になります。

    大幅に開発時間を節約することができ、標準的な売買シグナルを使用しています。すでにシグナルの標準モジュールで利用可能である場合、独自のインジケータやパターン検出アルゴリズムを記述する必要はありません。ダイバージェンスやダブルダイバージェンスなどの複雑なパターンの定義は、既製のソリューションによって行われ、開発プロセスの複雑さを軽減します。

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

    添付されたファイル |
    ビル・ウィリアムズのシステムに基づく取引システムモジュール ビル・ウィリアムズのシステムに基づく取引システムモジュール
    この記事では、ビル・ウィリアムズの取引システムや、このシステムパターンをチャート上で発見しマーキングする為に開発されたMQL5モジュールの使用方法、見つけたパターンでの自動売買の原則、また様々な取引銘柄でのテスト結果を公開しています。
    実際ティックでの取引ストラテジーのテスト 実際ティックでの取引ストラテジーのテスト
    この記事では、簡単な取引ストラテジーを3つのモード(履歴からの記録ティックを使用した『リアルティックに基づいた全てのティック』、『1分足OHLC』、『全ティック』)でテストします。
    エキスパートアドバイザとインディケータに素早く制御パネルを追加する方法 エキスパートアドバイザとインディケータに素早く制御パネルを追加する方法
    自分のエキスパートアドバイザやインディケータに便利な制御パネルを追加したいけど、何をどうしたら良いかわかりませんか?この記事では、貴方のMQL4/MQL5プログラムに入力パラメータを持つダイアログパネルを『取り付ける方法』をステップバイステップでご紹介します。
    ユニバーサルEA:カスタムトレーリングストップ(その6) ユニバーサルEA:カスタムトレーリングストップ(その6)
    The sixth part of the article about the universal Expert Advisor describes the use of the trailing stop feature. The article will guide you through how to create a custom trailing stop module using unified rules, as well as how to add it to the trading engine so that it would automatically manage positions.