English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
MetaTrader 5のマルチ通貨モードの実行

MetaTrader 5のマルチ通貨モードの実行

MetaTrader 5 | 14 10月 2015, 15:09
2 845 0
Konstantin Gruzdev
Konstantin Gruzdev

はじめに

現在、多くの開発されえたマルチ通貨トレーディングシステムやインジケーター、エキスパートアドバイザーがあります。にもかかわらず、開発者はマルチ通貨システムの特定の問題に直面し続けました。

MetaTrader 5クライアントターミナルとMQL5プログラミング言語のリリースとともに、完全なマルチ通貨モードやよりこうRか的なマルチ通貨システム、インジケーターを実現する機会を得ることができました。これらの新しい機会が、この記事のトピックです。


従来のアプローチの概要

従来のアプローチは、MQL4のstart()関数の代わりに備えられた、標準のOnTick()OnCalculate()関数を基盤にしたマルチ通貨システムの作成です。単純に、チャート上の新しいティックやバーの発生のたびに、(マルチ通貨システムの)すべての通貨ペアが分析や決定をリクエストされます。

このアプローチの問題点:

  1. システム全体がチャートのトレーディングシンボルにおける新たなティックに依存しているという点です。

    急速な市場において、チャートのシンボルにおけるティックが頻繁なものであれば、そこまで問題ではありません。しかし、動きの遅い市場であれば、夜間にティックが新たに入ることは少なく、1分に一度かそれ以下です。希少なティックごとのインターバル間にて、全マルチ通貨システムが「眠っている」状態となりますが、その他のシンボルでの変化は起こっているのです。

    この欠点は、もしshシウテムが大きいタイムフレームにて調整されているのであれば、あまり重要ではありません。しかし、より小さいタイムフレームではより大きい影響がうまれます。毎日、世界は変化の速度を増し、コンピューター多くの情報を処理できるようになり、結果的に、人々は秒間で仕事するようになりました。

  2. マルチ通貨システムにて使用される全シンボルでの履歴データの同期における複雑さ

    「MetaTrader 4では、バーが描かれ、そのバーにて少なくとも一つの価格の変化が発生しました。もし1分間に価格の変化が発生しなかった場合、1バーのギャップは、1分の間でチャート上に発生しました」"Free-of-Holes"チャートの始まりと言われます。

    そのようなチャートの作成のアプローチは、MetaTrader5にて維持されています。シンボルごとのチャート上での等しいバーの数は、時間により同期化されていることを意味しません。例えば、100番目のバーがシンボルごとで異なるオープン時間を持っています。マルチ通貨インジケーターの構築と再計算中に、すべてのバーがそれぞれのバーと一致するか確認することは重要です。

    これは、もしシステムが大きいタイムフレームにて調整されていれば、重要ではありません、期間の拡大により、バーの欠損の可能性は大きく減少するためです。ただ、注意してもしすぎることはありませんが。また人が何もしないとわかることはありません。

    現在の不完全なバーの同期時刻を個別にチェックする必要があります。新規バーがチャートにて現れた際、新規バーがその他のバーでも形成されたということを意味しません。従って、CopyXXXX()関数を使用した、他のシンボルでの新規バーの価格の調査は、間違いのコピーやシンボルの一つ前のバーの価格を取得するということにつながります。他のシンボルの新規バーは、その現在のバーよりずっと早く形成される可能性もあります。これは、状況の判断の正確さに影響を与えるかもしれません。

    この中間インジケーターバッファを使用したマルチ通貨インジケーターの作成 という記事は多かれ少なれ履歴データの同期化を解決する方法を紹介しています。

  3. データの同期化と関連して、その他の重要な点は、いくつかのトレーディングシンボルにおいてどのように履歴データの更新があったかを発見する方法です。

    例えば、シングル通貨インジケーターを構築する際は問題ありません。もしOnCalculate()関数の入力変数prev_calculatedが0であれば、インジケーターを再計算します。しかし、シンボルにおいて履歴の更新があり、現在のチャートでは更新がない場合はどうすれば良いのでしょうか?これは、いつでも発生し、マルチ通貨インジケーターを再計算する必要があります。この質問への答えは、とても関連しています。

これらの3つのインスタンスはマルチ通貨EAやインジケーターのコードが大きくなりすぎるほどのたくさんの問題点を引き起こすことがわかります。しかし、この問題のすべては解決されきっていません。


OnTimer関数という新しい希望

MQLプログラムの新たな能力である、Timerイベントと標準OnTimer()イベントハンドラの生成は、マルチ通貨システムの新しいタイプの出現への希望をもたらしました。これは一方で、現在マルチ通貨エキスパートアドバイザー・インジケーターがチャート上のシンボルごとのティックの受信から独立し、また、他方では、EAの動作を監視できるようになったためです。しかし、

これは、以前のセクションのパラグラフ1での問題を解決し、いくつかの利点を提供します。しかし、NewTickイベントを受け取った時のように、Timerイベントの受信により変化を感知するためにすべての通貨ペアを調査する必要があります。時折、これは、頻繁に行われ、MQL5プログラムのリソースの使用をあげるものです。

パラグラフ2と3で特定された問題は、同じ解決すべき状態で依然残っています。これに加え、OnTimer()関数に見られる問題を解決する必要があります。例えば、週末のタイマーの初期化やでイニシャ来ゼーションの問題などです。

OnTimer()イベントハンドラの利点を軽視することなく、マルチ通貨モードの実現を可能ではないことを注意する必要があります。


OnChartEvent関数の新しい可能性

上記の標準関数の制限は、その狭い特別化によるものです:特定の事前に定義されたイベントを扱い、マルチ通貨システムへの対応は意図されていませんでした。

マルチ通貨システムの開発者への救済として、OnChartEvent()標準カスタムイベントハンドラがあります。これによりプログラマーは、独自のイベントを生成できるようになります。

例えば、現在のチャート上のシンボルにおいてのティックの取得のための関数を用いることができるようになります。適切なシンボルを持ったチャートに「スパイ」を送り込むのみで良いのです。

「スパイ」という単語は、以下のインジケーターを意味しています。

//+------------------------------------------------------------------+
//|                                                         iSpy.mq5 |
//|                                            Copyright 2010, Lizar |
//|                                               lizar-2010@mail.ru |
//+------------------------------------------------------------------+
#define VERSION         "1.00 Build 2 (26 Dec 2010)"

#property copyright   "Copyright 2010, Lizar"
#property link        "https://www.mql5.com/ru/users/Lizar"
#property version     VERSION
#property description "iSpy agent-indicator. If you want to get ticks, attach it to the chart"
#property indicator_chart_window

input long            chart_id=0;        // chart id
input ushort          custom_event_id=0; // event id

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,        // size of price[] array
                 const int prev_calculated,  // bars, calculated at the previous call
                 const int begin,            // starting index of data
                 const double& price[]       // array for the calculation
   )
  {
   double price_current=price[rates_total-1];

   //--- Initialization:
   if(prev_calculated==0) 
     { // Generate and send "Initialization" event
      EventChartCustom(chart_id,0,(long)_Period,price_current,_Symbol);
      return(rates_total);
     }
   
   // When the new tick, let's generate the "New tick" custom event
   // that can be processed by Expert Advisor or indicator
   EventChartCustom(chart_id,custom_event_id+1,(long)_Period,price_current,_Symbol);
   
   //--- return value of prev_calculated for next call
   return(rates_total);
  }

「スパイ」を望ましいチャート内に忍び込ませ、OnChartEvent()関数を用いて、EAやインジケーター内のメッセージを扱えるようにします。「スパイ」のメッセージを復号化するために、以下の方法でこの関数のパラメーターの意味を汲み取る必要があります。

  • id - イベントIDもし、id-CHARTEVENT_CUSTOM = 0の場合、その「スパイ」は、prev_calculated変数は、0であり、適切なアクションを取る必要があります。
  • lparam - この場合、スパイのいるチャートの期間
  • dparam - ティック価格標準として、これが最後のクローズ価格です。「スパイ」使用中は、これが列挙型ENUM_APPLIED_PRICEの値にセットされます。
  • sparam - イベントが受け取られたトレーディングシンボルの名前

いくつかの「スパイ」による同時の作業を示すために、(アーカイブにて使用可能な)EA exSpy.mq5を記述します。

//+------------------------------------------------------------------+
//|                                                        exSpy.mq5 |
//|                                            Copyright 2010, Lizar |
//|                            https://www.mql5.com/ru/users/Lizar |
//+------------------------------------------------------------------+
#define VERSION       "1.00 Build 1 (26 Dec 2010)"

#property copyright   "Copyright 2010, Lizar"
#property link        "https://www.mql5.com/ru/users/Lizar"
#property version     VERSION
#property description "The Expert Advisor shows the work of iSPY indicator"

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {   
   if(iCustom("GBPUSD",PERIOD_M1,"iSpy",ChartID(),0)==INVALID_HANDLE) 
      { Print("Error in setting of spy on GBPUSD"); return(true);}
   if(iCustom("EURUSD",PERIOD_M1,"iSpy",ChartID(),1)==INVALID_HANDLE) 
      { Print("Error in setting of spy on EURUSD"); return(true);}
   if(iCustom("USDJPY",PERIOD_M1,"iSpy",ChartID(),2)==INVALID_HANDLE) 
      { Print("Error in setting of spy on USDJPY"); return(true);}
      
   Print("Spys ok, waiting for events...");
   //---
   return(0);
  }
  
//+------------------------------------------------------------------+
//| The Standard event handler.                                      |
//| See MQL5 Reference for the details.                              |
//|                                                                  |
//| In this case it is used for decoding of spy messages, sent by    |
//| iSPY spy indicator                                               |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // event id:
                                     // if id-CHARTEVENT_CUSTOM=0-"initialization" event
                const long&   lparam, // chart period
                const double& dparam, // price
                const string& sparam  // symbol
               )
  {
   if(id>=CHARTEVENT_CUSTOM)      
     {
      Print(TimeToString(TimeCurrent(),TIME_SECONDS)," -> id=",
            id-CHARTEVENT_CUSTOM,":  ",sparam," ",
            EnumToString((ENUM_TIMEFRAMES)lparam)," price=",dparam);
     }
  }
//+------------------------------------------------------------------+

エキスパートアドバイザーのチャート上での開始

こちらがその結果です:

ログからご覧の通り、望ましいシンボルのすべてのティックを取得するとともに、もし履歴などで更新があれば、取得される「初期化」イベントも獲得しています。

中間結果を要約します:

  • 特定のシンボルのティックに依存しません。OnTick()OnCalculate()標準関数を使用した際に行ったものと同じようなものです。
  • OnTimer()関数を使用する際、厳格にタイムインタバールに制限されていません。
  • 変化を監視するためにループ内などですべてのシンボルをリクエストする必要はありません。シンボル上での変化があれば、それと一致するイベントを取得できます。イベントが発生したシンボルをイベントIdやsparam変数により特定できます。
  • それぞれのシンボルごとのサーバーで履歴の同期化を監視する問題を解決しました。
  • 追加のプログラムの指示に関する仕事が残っています。これはデータ処理の並列化に関連しています。
  • OnChartEvent()関数のパラメーター内で、追加の情報を取得します:期間、価格、シンボル名です。データの追加の取得の必要性がなくなり、EAやインジケーターのコードを単純化します。

この時点でMetaTrader 5 ターミナルやMQL5言語により、マルチ通貨モードを実現することができたため、この記事を簡単に要約することができます。しかし、依然これは「不完全な」実現ですそれゆえ、少し先へ進んでいきます。


マルチ通貨モードの実現

もしマルチ通貨システムの純粋な形での実現案を使用するなら、いくつかの困難に直面します。問題は、そのようなアプローチは「スパイ」が稼働するトレーディングシンボルのティックをすべて取得可能にする点です。

1秒で、急速な動きの市場はそれぞれのシンボルにいくつものティックが生まれています。これにより、イベント注文の「妨害」が生じます。Helpセクションからの警告がこちらにあります:

クライアントターミナルはイベントキューに発生しているイベントを追加します。なので、イベントは、次々に取得された順序に従って処理されていきます。NewTickイベントにおいては例外があります。もしキューがすでにそのようなイベントを取得しているか、そのイベントが処理されている最中である場合、その新しいNewTickイベントはエンキューされません。

イベントのキューはサイズに制限があります。新しいイベントの受信のため古いイベントは処理されずに除去されます。そのため、効果的なイベントハンドラを記述することが推奨されており、無限のループを使用することは推奨されていません。(Startイベントのためのスクリプトは例外です。)

キューのオーバーフローはマルチ通貨インジケーターかEAにおいての重要なイベントの損失につながります。これは一方の側からの観点です。他方で、すべてのシンボルにおいて必ずしもティックを必要としません。時折、すべてのタイムフレームにて「新規バー」イベントを取得する必要があります。もしくは、異なるタイムフレームで多く「新規バー」イベントごとで取得します。基本的に、「スパイ」は、そのような要求には適しておらず、その使用はあまり便利ではありません

より普遍的にしましょう。それにより、マルチ通貨EAやインジケーターのシンボルに基づきイベントを取得する方法についての質問に戻ってこなくていいようになります。このために、"MCM Control Panel" for Multicurrency Expert Advisors and Indicatorsの記述から、ENUM_CHART_EVENT_SYMBOLイベントサンプルとして選択しました:

enum ENUM_CHART_EVENT_SYMBOL
  {
   CHARTEVENT_INIT      =0,         // "Initialization" event
   CHARTEVENT_NO        =0,         // No events

   CHARTEVENT_NEWBAR_M1 =0x00000001, // "New bar" event on M1 chart
   CHARTEVENT_NEWBAR_M2 =0x00000002, // "New bar" event on M2 chart
   CHARTEVENT_NEWBAR_M3 =0x00000004, // "New bar" event on M3 chart
   CHARTEVENT_NEWBAR_M4 =0x00000008, // "New bar" event on M4 chart
   
   CHARTEVENT_NEWBAR_M5 =0x00000010, // "New bar" event on M5 chart
   CHARTEVENT_NEWBAR_M6 =0x00000020, // "New bar" event on M6 chart
   CHARTEVENT_NEWBAR_M10=0x00000040, // "New bar" event on M10 chart
   CHARTEVENT_NEWBAR_M12=0x00000080, // "New bar" event on M12 chart
   
   CHARTEVENT_NEWBAR_M15=0x00000100, // "New bar" event on M15 chart
   CHARTEVENT_NEWBAR_M20=0x00000200, // "New bar" event on M20 chart
   CHARTEVENT_NEWBAR_M30=0x00000400, // "New bar" event on M30 chart
   CHARTEVENT_NEWBAR_H1 =0x00000800, // "New bar" event on H1 chart
   
   CHARTEVENT_NEWBAR_H2 =0x00001000, // "New bar" event on H2 chart
   CHARTEVENT_NEWBAR_H3 =0x00002000, // "New bar" event on H3 chart
   CHARTEVENT_NEWBAR_H4 =0x00004000, // "New bar" event on H4 chart
   CHARTEVENT_NEWBAR_H6 =0x00008000, // "New bar" event on H6 chart
   
   CHARTEVENT_NEWBAR_H8 =0x00010000, // "New bar" event on H8 chart
   CHARTEVENT_NEWBAR_H12=0x00020000, // "New bar" event on H12 chart
   CHARTEVENT_NEWBAR_D1 =0x00040000, // "New bar" event on D1 chart
   CHARTEVENT_NEWBAR_W1 =0x00080000, // "New bar" event on W1 chart
     
   CHARTEVENT_NEWBAR_MN1=0x00100000, // "New bar" event on MN1 chart
   CHARTEVENT_TICK      =0x00200000, // "New tick" event
   
   CHARTEVENT_ALL       =0xFFFFFFFF, // All events
  };

実施は、この列挙型はカスタムチャートイベントのフラッグです。それはマルチ通貨モードで必要な最小のものです。もちろん、完全なものにできます。フラッグの組み合わせにより、「スパイ」から送信するイベントを決定します。

そのフラッグは「OR」演算子を使用し組み合わせることができます。例えば、CHARTEVENT_NEWBAR_M1 | CHARTEVENT_NEWBAR_H1の組み合わせは、「スパイ」の助けにより、「新規バー」イベントを分毎、一時間毎のタイムフレームから送ることを意味します。これらのフラッグは、スパイインジケーターの入力パラメータとなります。今後はそれを「エージェントインジケーター」として呼びます。

新規アイディアに伴いインジケーターは、このようになります。

//+------------------------------------------------------------------+
//|                                        Spy Control panel MCM.mq5 |
//|                                            Copyright 2010, Lizar |
//|                            https://www.mql5.com/ja/users/Lizar |
//+------------------------------------------------------------------+
#define VERSION       "1.00 Build 3 (26 Dec 2010)"

#property copyright   "Copyright 2010, Lizar"
#property link        "https://www.mql5.com/ja/users/Lizar"
#property version     VERSION
#property description "This is the MCM Control Panel agent-indicator."
#property description "Is launched on the required symbol on any time-frame"
#property description "and generates the custom NewBar event and/or NewTick"
#property description "for the chart which receives the event"

#property indicator_chart_window
  
input long                    chart_id;                 // identifier of the chart which receives the event
input ushort                  custom_event_id;          // event identifier  
input ENUM_CHART_EVENT_SYMBOL flag_event=CHARTEVENT_NO;// indicator, which determines the event type.

MqlDateTime time, prev_time;

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate (const int rates_total,       // size of the price[] array
                 const int prev_calculated, // bars processed at the previous call
                 const int begin,           // where the data begins
                 const double& price[]      // calculations array
   )
  {  
   double price_current=price[rates_total-1];

   TimeCurrent(time);
   
   if(prev_calculated==0)
     {
      EventCustom(CHARTEVENT_INIT,price_current);
      prev_time=time; 
      return(rates_total);
     }
   
//--- new tick
   if((flag_event & CHARTEVENT_TICK)!=0) EventCustom(CHARTEVENT_TICK,price_current);       

//--- check change time
   if(time.min==prev_time.min && 
      time.hour==prev_time.hour && 
      time.day==prev_time.day &&
      time.mon==prev_time.mon) return(rates_total);

//--- new minute
   if((flag_event & CHARTEVENT_NEWBAR_M1)!=0) EventCustom(CHARTEVENT_NEWBAR_M1,price_current);     
   if(time.min%2 ==0 && (flag_event & CHARTEVENT_NEWBAR_M2)!=0)  EventCustom(CHARTEVENT_NEWBAR_M2,price_current);
   if(time.min%3 ==0 && (flag_event & CHARTEVENT_NEWBAR_M3)!=0)  EventCustom(CHARTEVENT_NEWBAR_M3,price_current); 
   if(time.min%4 ==0 && (flag_event & CHARTEVENT_NEWBAR_M4)!=0)  EventCustom(CHARTEVENT_NEWBAR_M4,price_current);      
   if(time.min%5 ==0 && (flag_event & CHARTEVENT_NEWBAR_M5)!=0)  EventCustom(CHARTEVENT_NEWBAR_M5,price_current);     
   if(time.min%6 ==0 && (flag_event & CHARTEVENT_NEWBAR_M6)!=0)  EventCustom(CHARTEVENT_NEWBAR_M6,price_current);     
   if(time.min%10==0 && (flag_event & CHARTEVENT_NEWBAR_M10)!=0) EventCustom(CHARTEVENT_NEWBAR_M10,price_current);      
   if(time.min%12==0 && (flag_event & CHARTEVENT_NEWBAR_M12)!=0) EventCustom(CHARTEVENT_NEWBAR_M12,price_current);      
   if(time.min%15==0 && (flag_event & CHARTEVENT_NEWBAR_M15)!=0) EventCustom(CHARTEVENT_NEWBAR_M15,price_current);      
   if(time.min%20==0 && (flag_event & CHARTEVENT_NEWBAR_M20)!=0) EventCustom(CHARTEVENT_NEWBAR_M20,price_current);      
   if(time.min%30==0 && (flag_event & CHARTEVENT_NEWBAR_M30)!=0) EventCustom(CHARTEVENT_NEWBAR_M30,price_current);      
   if(time.min!=0) {prev_time=time; return(rates_total);}
//--- new hour
   if((flag_event & CHARTEVENT_NEWBAR_H1)!=0) EventCustom(CHARTEVENT_NEWBAR_H1,price_current);
   if(time.hour%2 ==0 && (flag_event & CHARTEVENT_NEWBAR_H2)!=0)  EventCustom(CHARTEVENT_NEWBAR_H2,price_current);
   if(time.hour%3 ==0 && (flag_event & CHARTEVENT_NEWBAR_H3)!=0)  EventCustom(CHARTEVENT_NEWBAR_H3,price_current);      
   if(time.hour%4 ==0 && (flag_event & CHARTEVENT_NEWBAR_H4)!=0)  EventCustom(CHARTEVENT_NEWBAR_H4,price_current);      
   if(time.hour%6 ==0 && (flag_event & CHARTEVENT_NEWBAR_H6)!=0)  EventCustom(CHARTEVENT_NEWBAR_H6,price_current);      
   if(time.hour%8 ==0 && (flag_event & CHARTEVENT_NEWBAR_H8)!=0)  EventCustom(CHARTEVENT_NEWBAR_H8,price_current);      
   if(time.hour%12==0 && (flag_event & CHARTEVENT_NEWBAR_H12)!=0) EventCustom(CHARTEVENT_NEWBAR_H12,price_current);      
   if(time.hour!=0) {prev_time=time; return(rates_total);}
//--- new day
   if((flag_event & CHARTEVENT_NEWBAR_D1)!=0) EventCustom(CHARTEVENT_NEWBAR_D1,price_current);      
//--- new week
   if(time.day_of_week==1 && (flag_event & CHARTEVENT_NEWBAR_W1)!=0) EventCustom(CHARTEVENT_NEWBAR_W1,price_current);      
//--- new month
   if(time.day==1 && (flag_event & CHARTEVENT_NEWBAR_MN1)!=0) EventCustom(CHARTEVENT_NEWBAR_MN1,price_current);      
   prev_time=time;
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

void EventCustom(ENUM_CHART_EVENT_SYMBOL event,double price)
  {
   EventChartCustom(chart_id,custom_event_id,(long)event,price,_Symbol);
   return;
  } 

このインジケーターは、名付けていなかったMCM Control panelの一部であり、付属物は、更新されたバージョンです。(「Spy Control panel MCM.mq5」をみてください。)しかし、これはパネルから個別に使うことができないというわけではありません。

このエージェントインジケーターは、カスタムユーザーイベントを生成し、これらのイベントの処理のためにOnChartEvent()関数を用い、チャートの受信場所へ送ります。この関数の入力パラメーターは、以下のように解釈されます:

  • id -イベントID
  • lparam - パネルから取得されるイベントインジケーターENUM_CHART_EVENT_SYMBOL と一致するインジケーターです
  • dparam - 特定のタイムフレームにおけるティック価格やオープン価格
  • sparam - イベントの発生するトレーディングシンボルの名前

EAのでもは、以前のバージョンよりも複雑に見えます。(完全なバージョンはアーカイブ上にあります。)

//+------------------------------------------------------------------+
//|                                      exSpy Control panel MCM.mq5 |
//|                                            Copyright 2010, Lizar |
//|                            https://www.mql5.com/ja/users/Lizar |
//+------------------------------------------------------------------+
#define VERSION       "1.00 Build 1 (28 Dec 2010)"

#property copyright   "Copyright 2010, Lizar"
#property link        "https://www.mql5.com/ja/users/Lizar"
#property version     VERSION
#property description "The EA demonstrates the work of the MCM Spy Control panel"

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {   
   if(iCustom("GBPUSD",PERIOD_M1,"Spy Control panel MCM",ChartID(),0,
             CHARTEVENT_NEWBAR_M1|CHARTEVENT_NEWBAR_M5)==INVALID_HANDLE) 
      { Print("Error in setting of spy on GBPUSD"); return(true);}
   if(iCustom("EURUSD",PERIOD_M1,"Spy Control panel MCM",ChartID(),1,
             CHARTEVENT_NEWBAR_M2)==INVALID_HANDLE) 
      { Print("Error in setting of spy on EURUSD"); return(true);}
   if(iCustom("USDJPY",PERIOD_M1,"Spy Control panel MCM",ChartID(),2,
             CHARTEVENT_NEWBAR_M6)==INVALID_HANDLE) 
      { Print("Error in setting of spy on USDJPY"); return(true);}
      
   Print("Spys ok, waiting for events...");
   //---
   return(0);
  }
  
//+------------------------------------------------------------------+
//| The Standard event handler.                                      |
//| See MQL5 Reference for the details.                              |
//|                                                                  |
//| In this case it is used for decoding of spy messages, sent by    |
//| iSPY Control panel MCM indicator.                                |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,           // event identifier
                  const long&   lparam, // the event flag.
                                       // event flag is a bit mask of ENUM_CHART_EVENT_SYMBOL enumeration.
                  const double& dparam, // price
                  const string& sparam  // symbol 
                 )
  {
   if(id>=CHARTEVENT_CUSTOM)      
     {
      Print(TimeToString(TimeCurrent(),TIME_SECONDS)," -> id=",id-CHARTEVENT_CUSTOM,
           ":  ",sparam," ",EnumToString((ENUM_CHART_EVENT_SYMBOL)lparam)," price=",dparam);
     }
  }

exSpy Control panel MCMの動作結果::

ご覧の通り、すべての必要なイベントを規則的に取得しています。

もう一度中間結果を要約しましょう:

  • エージェントインジケーターの新バージョンのおかげで、すべての業績を維持することができました。
  • マルチ通貨MQLプログラムから、「新規ティック」、「新規バー」、「初期化」などを含め、すくなくとも23のイベントを明記できています。
  • EAインジケーターからのさらなる動作は、アンロードのためエージェントに渡されます。

MetaTrader 5.でのマルチ通貨モードの実行はそこまで難しくないことがわかりました。

さらにいくつかの点に焦点を当てたいと思います。

第一. マルチ通貨EA・インジケーターのために「エージェント」により生成されるイベントはすべて外部のものです。これとの接続において、「EA・インジケーターから直接エージェントを稼働させるべきか」という質問が生じます。答えは「NO」です。

第二. OnChartEvent()関数では、トレーディングシンボル名である、パラメーターsparamによりどのシンボルにイベントが取得されたかわかるため、イベントIDが空白であるようでした。従って、その他の目的のために使用できるのでしょうか?答えは「できます」。

そのような議論は、マルチ通貨エキスパートアドバイザーとインジケーターのための「MCM Control Panel」.の出現を導き出しました。ターミナルとEA/インジケーター間の「中間層」のようなものです。 これは、マルチ通貨環境の設定においてより多くの利益と柔軟性を提供します。

  • そのパネルは、個別のインジケーターとしてチャート上にインストールされ、パネルと合致するマルチ通貨インジケーターを割り当てます。
  • そのパネルは、インジケーターとEAをコンポーネントとして含みます。それに伴い更新していきます。
  • 「イベント」メニューを使用し、トレーディングや分析のために「Market Watch」からそのシンボルを開始/停止させることができます。OnChartEvent()関数では、シンボルのシリアル数を"Market Watch"ウィンドウ内でイベントIDにより特定することができません。
  • 「Market Watch」にて選択した期間やシンボルにおいて、ティックや「新規バー」イベントによりトレーディングモードを設定することができます。これらはすべてメニューを使用し、行います。
  • すべての設定を止めたり、EAやインジケーターのプロパティウィンドウに行かずとも変更できます。
  • すべてはマルチ通貨インジケータやEAの作成においての創造性を制限しません。さらに、コードにパネルの結果を統合しません。エージェントインジケーターの管理はコントロールパネル内に実現されます。
  • マルチ通貨システムの構造はよりシンプルです。


USDドルインデックスにおけるマルチ通貨インジケーターRSI

上記のメソッドの利点を経験するために、USDx ドルインデックスのためMCM Control Panelを使用し、RSIインジケーターのマルチ通貨バリアントの実行を提案します。

まず、いくつかの特別な機能を紹介します。しばしばDollar Indexを分析をしようとしますが、インデックスの読み込みのインジケーターを数えます。これは、通貨ペアインデックスからのすべてのシンボルがそれぞれで貢献するため、すべて正しいわけではありません。それゆえ、例えば、インデックス計算の公式に類似する公式を用い、ドルインデックスのためのRSIを計算してみましょう。

まずは、固有の通貨ペアのRSIを計算し、その後、係数の重みを考慮するインデックスのためのRSIを読み込みます。

そのリーダーは、マルチ通貨システムで使用されるシンボルの履歴データの同期に問題があることを読み込みます。(「従来のアプローチの外観」セクションのパラグラフ2をみてください。)

この問題は、RSI同期バッファー (SynchronizedBufferRSI.mqh file)を構築するためのクラス関数を使用し、インジケーター内にて解決されました。そのクラスのすべてのコードを提供することはむだなので、以下に関連する部分にみ載せています。

まずは、パブリック修飾子のついたクラス内にてインジケーターバッファーが定義されています。

public:
   double   buffer[];   // indicator buffer

Second, the indicator initialization is done using the class method:

//--- Initialization methods:
bool Init(int n,string symbol,int rsi_count,int rsi_period);

そして3番目に、それぞれのバーにつき、インジケーターバッファーの値が現在のタイムフレームとクラスのリフレッシュメソッドを用いて同期化されます。

//+------------------------------------------------------------------+
//| The method of receiving/updating indicator data for one bar      |
//| of the indicator buffer.                                         |
//| INPUT:  bar   - bar number                                       |
//| OUTPUT: no.                                                      |
//| REMARK: no.                                                      |
//+------------------------------------------------------------------+
void CSynchronizedBufferRSI::Refresh(int bar=0)
  {
   buffer[bar]=EMPTY_VALUE; // Initialization of the bar of the indicator buffer.
     
   //--- Inquire the time of the bar for the current graph:
   datetime time[1];      
   if(CopyTime(_Symbol,_Period,bar,1,time)!=1) return; // In case of an error, we wait for the next tick/bar...

   //--- Request the value of the indicator for the symbol for the time,
   //--- consistent with that of the bar of the current graph:
   double value[1];
   if(CopyBuffer(m_handle,0,time[0],time[0],value)!=1) return; // In case of an error, wait for the next tick/bar...

   buffer[bar]=value[0];
   return;
  }

以下の記事.にて紹介されているように、インジケーターバッファーの完全な同期化に関しては、「穴」のない分毎のタイムグレームを使用する必要があります。しかし、インジケーターバッファーの同期化のメソッドのために、現在のグラフのタイムフレームを選択しました。インジケーターディスプレイはそこで発生するためです。

私の経験から言うと、小さい期間では、もし、そのシンボルが現在のグラフのものと異なる場合、いかなるタイムシリーズやインジケーターバッファーにおいて、そのような同期化のメソッドを使用することは合理的です。

そのグラフは、これがなぜやるべきかを示しています:

より大きなタイムフレームにおいては、これはあまり見受けられません。

そして最後に、インジケーターにて使用される ユーザーのイベントハンドラのコードが以下になります。

//+------------------------------------------------------------------+
//| The Standard event handler.                                      |
//| See MQL5 Reference for the details.                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // event identifier or position symbol in the "Market Match"+CHARTEVENT_CUSTOM  
                const long& lparam,   // event indicator
                const double& dparam, // price
                const string& sparam  // symbol
                )
  {
   int custom_id=id-CHARTEVENT_CUSTOM-1;
   
   if(custom_id>=0)      
     {
      if(lparam!=CHARTEVENT_NEWBAR_NO)
        { 
         //--- Recalculation of the last uncompleted bar:
         if(EventToPeriod(lparam)==_Period && sparam==_Symbol)
           { // Recalculation of the indicator, if a new bar on the current chart
            iRSIUSDx_Ind[0]=EMPTY_VALUE;
            //--- Updating the value of the RSI for all of the currency pairs for the new bar
            for(int i=0;i<symbol_total;i++) buffer[i].Refresh();
            iRSIUSDx(symbol_total);   // calculation of the current incomplete bar RSI for the index
            return;
           }
         
         buffer[custom_id].Refresh(); // The value of RSI for the custom_id of the currency pair for the current bar
         iRSIUSDx(symbol_total);      // calculation of the RSI for the current(uncompleted) bar RSIx
         return;
        }
      else 
        { 
         //--- Recalculation of the indicator for the "Initialization" event 
         buffer[custom_id].RefreshBuffer();     // Update of the RSI buffer for the custom_id of the currency pair
         Init_iRSIUSDx(symbol_total,calculate); // Update of the RSI buffer for the index
         return;
        }
     }
  }

コードの特別な機能

  • 現在のタイムフレームと同期するインジケーターバッファーRSIを計算するためのクラスインスタンスへのポインターを含む配列の参照のためのイベントIDの使用このアプローチは、大いにコードの構造を簡潔にします。
  • 「初期化」イベントは、取得させた通貨ペアのためのインジケーターバッファーRSIの再計算に使用されます。以前述べた通り、これにより履歴を更新する際にインジケーターを同期することができます。
  • 「新規」イベントは、現在のグラフの新規バーのためのインジケーターバッファーRSIの同期化に使用されます。
  • 「新規ティック」イベントは、すべての通貨ペアから使用され、最後の不完全なバーでのインジケーターを更新します。さらに、バーの再計算は「新規ティック」が受け取られるペアのためだけに行われます。

USDxドルインデックスのためのRSIインジケータのコードをすべて調査し終えれば、これがどのように動くか明確になります。

インストールの特徴:

  • マルチ通貨エキスパートアドバイザーのための「MCM Control Panel」 とインジケーターをダウンロードし、「iControl panel MCM.mq5」と「Spy Control panel MCM.mq5」ファイルをコンパイルしてください。
  • 「Market Match」ウィンドウにて、以下のシンボルを明記してください。
    1. EURUSD
    2. USDJPY
    3. GBPUSD
    4. USDCAD
    5. USDSEK
    6. USDCHF
    これは、適切なチェックをインジケーターに行っていなかったため必要です。また、これらのリストは、正確なインジケーターの計算に必要です。
  • iRSIUSDx.zipアーカイブをMQL5フォルダーに展開してください。/MQL5/Indicators/iRSIUSDx/フォルダーのiRSIUSDx.exを、EURUSDにM1ピリオドにて貼り付けてください。
  • 「Control panel MCM」パネルの「イベント」メニューにある6つすべてのシンボルに、「新規ティック」イベントを設定してください。詳細はこちらです。上の図と類似したものが得られると思います。
  • 追加として、EURUSDシンボルに関して、分チャートに「新規バー」イベントを設定してください。そのインジケーター内にて、このイベントは、新しいバーが現在のタイムフレームにて現れた際の同期化のために使用されます。
  • こちらで紹介されているように、もしより多くの視覚的な例が欲しければ、ドルインデックスを設定してください。


結論

MetaTrader 5のマルチ通貨モードの実現は、MT5やMQL5言語が問題を解決する上での利点を示します。困難の多くを今まで引き起こしてきたものが手に入れることができます。

明らかにこれは、この方向での動きの始まりでしかありません。もちろん、データの同期化やマルチ通貨モードの管理などにおいてより良い方法が見つかるだろうと思いますが、今の所の便利なツールをすべて紹介できたことを願います。

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

添付されたファイル |
irsiusdx_en.zip (7.54 KB)
Connecting NeuroSolutions Neuronets Connecting NeuroSolutions Neuronets
ニューロネットの作成に加え、NeuroSolutions ソフトウェアスウィートによりそれらを DLLとしてエクスポートすることが可能となります。本稿では、ニューロネット作成とDLL生成とそれを MetaTrader 5でのトレーディングのためExpert Advisor に連携する手順について述べています。
MQL5 ウィザード:オープンポジションのトレーリングモジュール作成方法 MQL5 ウィザード:オープンポジションのトレーリングモジュール作成方法
MQL5ウィザードのトレーディング戦略ジェネレータはトレーディングの考え方を検証することをひじょうに簡素化します。本稿では、MQL5 ウィザードでトレーディング戦略を書く方法、ジェネレータを、価格がポジション方向に行くときストップロスを無損失ゼロレベルへ移動させることでトレーディングの際減益ドローダウンを守ることのできるオープンポジションを管理する独自のクラスと連携させる方法について述べます。MQL5 ウィザード用に作成されたクラスのストラクチャおよび記述フォーマットについても述べます。
移動ミニマックス法:テクニカル分析用新インディケータと MQL5への実装実装 移動ミニマックス法:テクニカル分析用新インディケータと MQL5への実装実装
本稿ではZ.G.Silagadze氏による論文 'Moving Mini-max: a new indicator for technical analysis'を基にした移動ミニマックス インディケータの実装手順について述べます。このインディケータの考え方は、G. Gamov 氏のα 崩壊で提案される量子トンネル現象を基にしています。
価格変動の速度と傾向に基づくトレードアイディア 価格変動の速度と傾向に基づくトレードアイディア
この記事では、価格変動の速度と傾向に基づいたトレードアイディアについて紹介しています。検証する戦略の持続性を明らかにする目的で、取引エキスパートアドバイザのテストとして、MQL4言語でトレードアイディアの形式化が行われます。また、チェックや研究、最適化をすることによって、記事に書かれている例の最も良いパラメータが明確になります。