DoEasyライブラリの時系列(第44部): 指標バッファオブジェクトのコレクションクラス

Artyom Trishkin | 7 10月, 2020

内容


概念

第39部から、カスタム指標を作成するためのライブラリの使用を検討し始めました。現在までにあるのは、時系列オブジェクトとそのコレクション、および指標バッファオブジェクト(基本抽象バッファとそれに基づく指標バッファ)です。
この記事では、単一のプログラムで任意の量(最大512)のバッファを高速に作成し、データを簡単に取得してアクセスできるようにするための指標バッファのコレクションの開発を開始します。

時系列コレクション — バッファコレクションのリンクを使用すると、任意の複数銘柄および複数期間指標を作成できますが、これは、次回の記事から行うつもりです。本稿では、9つの描画スタイルのいずれかを使用して任意の数のバッファを作成するための指標バッファのコレクションを開発およびテストします。現在、指標に描画されるバッファの最大数は512を超えることはできません。これは、多数のチャートを含む複雑な指標を作成するのに十分すぎるはずです。開発された機能は、このような多数のグラフィカル構造の作成と保守を簡素化することで、プロセス全体を、作成順に描画スタイルと番号、またはコレクション内のバッファインデックスによって作成されたバッファにアクセスするだけに減らします。


データの準備とバッファオブジェクトの改善

前回の記事では、基本抽象バッファの子孫である「指標バッファ」オブジェクトを作成しました。指標バッファとして割り当てられたdouble配列にアクセスしたり、そこからデータを読み取ったりするための補助メソッドを追加してみましょう。
既存の基本的な抽象バッファメソッドで十分ですが、描画スタイルのみに固有の子孫オブジェクトでカスタムメソッドを作成すると、ステータス(描画スタイル)でバッファにアクセスするときに、double配列に簡単にアクセスできるようになり、カスタム指標を作成する際の柔軟性を高めます。

新しいライブラリメッセージを追加しましょう。新しいメッセージインデックスを\MQL5\Include\DoEasy\Datas.mqhに追加します。

   MSG_LIB_SYS_FAILED_COLORS_ARRAY_RESIZE,            // Failed to change the color array size
   MSG_LIB_SYS_FAILED_ADD_BUFFER,                     // Failed to add buffer object to the list
   MSG_LIB_SYS_FAILED_CREATE_BUFFER_OBJ,              // Failed to create \"Indicator buffer\" object
   
   MSG_LIB_TEXT_YES,                                  // Yes

...

   MSG_LIB_TEXT_BUFFER_TEXT_INVALID_PROPERTY_BUFF,    // Invalid number of indicator buffers (#property indicator_buffers)
   MSG_LIB_TEXT_BUFFER_TEXT_MAX_BUFFERS_REACHED,      // Reached maximum possible number of indicator buffers

   MSG_LIB_TEXT_BUFFER_TEXT_STATUS_NONE,              // No drawing

また、新しく追加したインデックスに対応するテキストも追加します。

   {"Не удалось изменить размер массива цветов","Failed to resize color array"},
   {"Не удалось добавить объект-буфер в список","Failed to add buffer object to list"},
   {"Не удалось создать объект \"Индикаторный буфер\"","Failed to create object \"Indicator buffer\""},

   {"Да","Yes"},

...

   {"Неправильно указано количество буферов индикатора (#property indicator_buffers)","Number of indicator buffers incorrect (#property indicator_buffers)"},
   {"Достигнуто максимально возможное количество индикаторных буферов","Maximum number of indicator buffers reached"},
   
   {"Нет отрисовки","No drawing"},

指標は最大512個のバッファを使用できます。
\MQL5\Include\DoEasy\Defines.mqhにそれを指定するマクロ置換を追加します。

//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
//--- Describe the function with the error line number
#define DFUN_ERR_LINE                  (__FUNCTION__+(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian" ? ", Page " : ", Line ")+(string)__LINE__+": ")
#define DFUN                           (__FUNCTION__+": ")        // "Function description"
#define COUNTRY_LANG                   ("Russian")                // Country language
#define END_TIME                       (D'31.12.3000 23:59:59')   // End date for account history data requests
#define TIMER_FREQUENCY                (16)                       // Minimal frequency of the library timer in milliseconds
#define TOTAL_TRY                      (5)                        // Default number of trading attempts
#define IND_COLORS_TOTAL               (64)                       // Maximum possible number of indicator buffer colors
#define IND_BUFFERS_MAX                (512)                      // Maximum possible number of indicator buffers
//--- Standard sounds

もちろん、「512」の値を使用することもできますが、開発者がいつかこの値を増やした場合、すべてのファイルでこの値を検索してこの値への参照がある場合新しい値に修正する必要がないため、マクロ置換の方が便利です。代わりに、マクロ置換値を変更するだけで済みます。

検索と並べ替えに不要であると以前に識別されたプロパティで、バッファオブジェクトを検索して選択する必要があります。

並べ替えに適用されないすべてのプロパティは、常にプロパティ列挙リストの最後に配置されます。また、並び替え時に未使用のプロパティの数を指定するマクロ置換が有効になります。プロパティを並べ替え可能として設定するには、プロパティ列挙リストの最後から、現在並べ替えが許可されているプロパティの近くにプロパティを移動し、並べ替えで未使用のプロパティの新しい数を指定する必要があります。
もちろん、可能な並び替え基準の列挙を新しいプロパティ(並び替えに使用できるプロパティ)で補足する必要もあります。並び替え基準列挙リストで新しく追加されたプロパティの場所は、プロパティ列挙リストでのこれらのプロパティの場所と一致する必要があります。これらのプロパティを並び替えで使用できるようにしています。

紛らわしいように聞こえますが、実際にはすべてが単純です。\MQL5\Include\DoEasy\Defines.mqhを開いて、必要な変更を加えます。

以前は、整数バッファオブジェクトのプロパティが次の順序で配置されていました。

//+------------------------------------------------------------------+
//| Buffer integer properties                                        |
//+------------------------------------------------------------------+
enum ENUM_BUFFER_PROP_INTEGER
  {
   BUFFER_PROP_INDEX_PLOT = 0,                              // Plotted buffer serial number
   BUFFER_PROP_STATUS,                                      // Buffer status (by drawing style) from the ENUM_BUFFER_STATUS enumeration
   BUFFER_PROP_TYPE,                                        // Buffer type (from the ENUM_BUFFER_TYPE enumeration)
   BUFFER_PROP_TIMEFRAME,                                   // Buffer period data (timeframe)
   BUFFER_PROP_ACTIVE,                                      // Buffer usage flag
   BUFFER_PROP_DRAW_TYPE,                                   // Graphical construction type (from the ENUM_DRAW_TYPE enumeration)
   BUFFER_PROP_ARROW_CODE,                                  // Arrow code for DRAW_ARROW style
   BUFFER_PROP_ARROW_SHIFT,                                 // The vertical shift of the arrows for DRAW_ARROW style
   BUFFER_PROP_LINE_STYLE,                                  // Line style
   BUFFER_PROP_LINE_WIDTH,                                  // Line width
   BUFFER_PROP_DRAW_BEGIN,                                  // The number of initial bars that are not drawn and values in DataWindow
   BUFFER_PROP_SHOW_DATA,                                   // Flag of displaying construction values in DataWindow
   BUFFER_PROP_SHIFT,                                       // Indicator graphical construction shift by time axis in bars
   BUFFER_PROP_COLOR_INDEXES,                               // Number of colors
   BUFFER_PROP_COLOR,                                       // Drawing color
   BUFFER_PROP_NUM_DATAS,                                   // Number of data buffers
   BUFFER_PROP_INDEX_BASE,                                  // Basic data buffer index
   BUFFER_PROP_INDEX_COLOR,                                 // Color buffer index
   BUFFER_PROP_INDEX_NEXT,                                  // Index of the free array to be assigned as the next indicator buffer
  }; 
#define BUFFER_PROP_INTEGER_TOTAL (19)                      // Total number of integer bar properties
#define BUFFER_PROP_INTEGER_SKIP  (6)                       // Number of buffer properties not used in sorting
//+------------------------------------------------------------------+

ここでは、2つのプロパティを並び替え可能にします。これには、それらをもっと上に動かし並べ替えに使用されないプロパティの数を6 から2に変更します。

//+------------------------------------------------------------------+
//| Buffer integer properties                                        |
//+------------------------------------------------------------------+
enum ENUM_BUFFER_PROP_INTEGER
  {
   BUFFER_PROP_INDEX_PLOT = 0,                              // Plotted buffer serial number
   BUFFER_PROP_STATUS,                                      // Buffer status (by drawing style) from the ENUM_BUFFER_STATUS enumeration
   BUFFER_PROP_TYPE,                                        // Buffer type (from the ENUM_BUFFER_TYPE enumeration)
   BUFFER_PROP_TIMEFRAME,                                   // Buffer period data (timeframe)
   BUFFER_PROP_ACTIVE,                                      // Buffer usage flag
   BUFFER_PROP_DRAW_TYPE,                                   // Graphical construction type (from the ENUM_DRAW_TYPE enumeration)
   BUFFER_PROP_ARROW_CODE,                                  // Arrow code for DRAW_ARROW style
   BUFFER_PROP_ARROW_SHIFT,                                 // The vertical shift of the arrows for DRAW_ARROW style
   BUFFER_PROP_LINE_STYLE,                                  // Line style
   BUFFER_PROP_LINE_WIDTH,                                  // Line width
   BUFFER_PROP_DRAW_BEGIN,                                  // The number of initial bars that are not drawn and values in DataWindow
   BUFFER_PROP_SHOW_DATA,                                   // Flag of displaying construction values in DataWindow
   BUFFER_PROP_SHIFT,                                       // Indicator graphical construction shift by time axis in bars
   BUFFER_PROP_COLOR_INDEXES,                               // Number of colors
   BUFFER_PROP_COLOR,                                       // Drawing color
   BUFFER_PROP_INDEX_BASE,                                  // Basic data buffer index
   BUFFER_PROP_INDEX_NEXT,                                  // Index of the free array to be assigned as the next indicator buffer
   BUFFER_PROP_NUM_DATAS,                                   // Number of data buffers
   BUFFER_PROP_INDEX_COLOR,                                 // Color buffer index
  }; 
#define BUFFER_PROP_INTEGER_TOTAL (19)                      // Total number of integer bar properties
#define BUFFER_PROP_INTEGER_SKIP  (2)                       // Number of buffer properties not used in sorting
//+------------------------------------------------------------------+

ここでは、リストの最後にある2つのプロパティのみが並べ替えに参加しないことを指定しました。
これらの新しいプロパティを並べ替え基準に追加しましょう

//+------------------------------------------------------------------+
//| Possible buffer sorting criteria                                 |
//+------------------------------------------------------------------+
#define FIRST_BUFFER_DBL_PROP          (BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_INTEGER_SKIP)
#define FIRST_BUFFER_STR_PROP          (BUFFER_PROP_INTEGER_TOTAL-BUFFER_PROP_INTEGER_SKIP+BUFFER_PROP_DOUBLE_TOTAL-BUFFER_PROP_DOUBLE_SKIP)
enum ENUM_SORT_BUFFER_MODE
  {
//--- Sort by integer properties
   SORT_BY_BUFFER_INDEX_PLOT = 0,                           // Sort by the plotted buffer serial number
   SORT_BY_BUFFER_STATUS,                                   // Sort by buffer drawing style (status) from the ENUM_BUFFER_STATUS enumeration
   SORT_BY_BUFFER_TYPE,                                     // Sort by buffer type (from the ENUM_BUFFER_TYPE enumeration)
   SORT_BY_BUFFER_TIMEFRAME,                                // Sort by the buffer data period (timeframe)
   SORT_BY_BUFFER_ACTIVE,                                   // Sort by the buffer usage flag
   SORT_BY_BUFFER_DRAW_TYPE,                                // Sort by graphical construction type (from the ENUM_DRAW_TYPE enumeration)
   SORT_BY_BUFFER_ARROW_CODE,                               // Sort by the arrow code for DRAW_ARROW style
   SORT_BY_BUFFER_ARROW_SHIFT,                              // Sort by the vertical shift of the arrows for DRAW_ARROW style
   SORT_BY_BUFFER_LINE_STYLE,                               // Sort by the line style
   SORT_BY_BUFFER_LINE_WIDTH,                               // Sort by the line width
   SORT_BY_BUFFER_DRAW_BEGIN,                               // Sort by the number of initial bars that are not drawn and values in DataWindow
   SORT_BY_BUFFER_SHOW_DATA,                                // Sort by the flag of displaying construction values in DataWindow
   SORT_BY_BUFFER_SHIFT,                                    // Sort by the indicator graphical construction shift by time axis in bars
   SORT_BY_BUFFER_COLOR_INDEXES,                            // Sort by a number of attempts
   SORT_BY_BUFFER_COLOR,                                    // Sort by the drawing color
   SORT_BY_BUFFER_INDEX_BASE,                               // Sort by the basic data buffer index
   SORT_BY_BUFFER_INDEX_NEXT,                               // Sort by the index of the free array to be assigned as the next indicator buffer
//--- Sort by real properties
   SORT_BY_BUFFER_EMPTY_VALUE = FIRST_BUFFER_DBL_PROP,      // Sort by the empty value for plotting where nothing will be drawn
//--- Sort by string properties
   SORT_BY_BUFFER_SYMBOL = FIRST_BUFFER_STR_PROP,           // Sort by the buffer symbol
   SORT_BY_BUFFER_LABEL,                                    // Sort by the name of the graphical indicator series displayed in DataWindow
  };
//+------------------------------------------------------------------+

ご覧のとおり、並べ替え基準の列挙リストでのそれらの場所は、列挙での整数プロパティの場所と一致しています。プロパティの並べ替えの順序は、オブジェクトプロパティの列挙のプロパティの順序と一致する必要があるため、基準の列挙は必須の条件です。これについては、第3部で説明しました。

ここでは、バッファオブジェクトをプロパティで並べ替えることについて説明しているので、バッファオブジェクトをプロパティで検索するためのツールを準備します。コレクションに格納されているすべてのライブラリオブジェクトにこのような機能をすでに導入しました。それでは、バッファオブジェクトも検索するメソッドを書いてみましょう。

\MQL5\Include\DoEasy\Services\Select.mqhを開いてバッファクラスファイルをインクルードします

//+------------------------------------------------------------------+
//|                                                       Select.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include <Arrays\ArrayObj.mqh>
#include "..\Objects\Orders\Order.mqh"
#include "..\Objects\Events\Event.mqh"
#include "..\Objects\Accounts\Account.mqh"
#include "..\Objects\Symbols\Symbol.mqh"
#include "..\Objects\PendRequest\PendRequest.mqh"
#include "..\Objects\Series\SeriesDE.mqh"
#include "..\Objects\Indicators\Buffer.mqh"
//+------------------------------------------------------------------+

クラス本体の一番下(時系列バーの操作メソッドを宣言するブロックの後)に、指標バッファの操作メソッドを宣言するブロックを追加します。

//+------------------------------------------------------------------+
//| Methods of working with timeseries bars                          |
//+------------------------------------------------------------------+
   //--- Return the list of bars with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion
   static CArrayObj *ByBarProperty(CArrayObj *list_source,ENUM_BAR_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByBarProperty(CArrayObj *list_source,ENUM_BAR_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByBarProperty(CArrayObj *list_source,ENUM_BAR_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode);
   //--- Return the bar index in the list with the maximum value of the order's (1) integer, (2) real and (3) string properties
   static int        FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_INTEGER property);
   static int        FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_DOUBLE property);
   static int        FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_STRING property);
   //--- Return the bar index in the list with the minimum value of the order's (1) integer, (2) real and (3) string properties
   static int        FindBarMin(CArrayObj *list_source,ENUM_BAR_PROP_INTEGER property);
   static int        FindBarMin(CArrayObj *list_source,ENUM_BAR_PROP_DOUBLE property);
   static int        FindBarMin(CArrayObj *list_source,ENUM_BAR_PROP_STRING property);
//+------------------------------------------------------------------+
//| Methods of working with indicator buffers                        |
//+------------------------------------------------------------------+
   //--- Return the list of buffers with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion
   static CArrayObj *ByBufferProperty(CArrayObj *list_source,ENUM_BUFFER_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByBufferProperty(CArrayObj *list_source,ENUM_BUFFER_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode);
   static CArrayObj *ByBufferProperty(CArrayObj *list_source,ENUM_BUFFER_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode);
   //--- Return the buffer index in the list with the maximum value of the order's (1) integer, (2) real and (3) string properties
   static int        FindBufferMax(CArrayObj *list_source,ENUM_BUFFER_PROP_INTEGER property);
   static int        FindBufferMax(CArrayObj *list_source,ENUM_BUFFER_PROP_DOUBLE property);
   static int        FindBufferMax(CArrayObj *list_source,ENUM_BUFFER_PROP_STRING property);
   //--- Return the buffer index in the list with the minimum value of the order's (1) integer, (2) real and (3) string properties
   static int        FindBufferMin(CArrayObj *list_source,ENUM_BUFFER_PROP_INTEGER property);
   static int        FindBufferMin(CArrayObj *list_source,ENUM_BUFFER_PROP_DOUBLE property);
   static int        FindBufferMin(CArrayObj *list_source,ENUM_BUFFER_PROP_STRING property);
//---
  };
//+------------------------------------------------------------------+

ファイルの最後に、クラス本体で宣言されているすべてのメソッドを追加します。

//+------------------------------------------------------------------+
//| Methods of working with buffer lists                             |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Return the list of buffers with one integer                      |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByBufferProperty(CArrayObj *list_source,ENUM_BUFFER_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   int total=list_source.Total();
   for(int i=0; i<total; i++)
     {
      CBuffer *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      long obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the list of buffers with one real                         |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByBufferProperty(CArrayObj *list_source,ENUM_BUFFER_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   for(int i=0; i<list_source.Total(); i++)
     {
      CBuffer *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      double obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the list of buffers with one string                       |
//| property meeting the specified criterion                         |
//+------------------------------------------------------------------+
CArrayObj *CSelect::ByBufferProperty(CArrayObj *list_source,ENUM_BUFFER_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode)
  {
   if(list_source==NULL) return NULL;
   CArrayObj *list=new CArrayObj();
   if(list==NULL) return NULL;
   list.FreeMode(false);
   ListStorage.Add(list);
   for(int i=0; i<list_source.Total(); i++)
     {
      CBuffer *obj=list_source.At(i);
      if(!obj.SupportProperty(property)) continue;
      string obj_prop=obj.GetProperty(property);
      if(CompareValues(obj_prop,value,mode)) list.Add(obj);
     }
   return list;
  }
//+------------------------------------------------------------------+
//| Return the buffer index in the list                              |
//| with the maximum integer property value                          |
//+------------------------------------------------------------------+
int CSelect::FindBufferMax(CArrayObj *list_source,ENUM_BUFFER_PROP_INTEGER property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CBuffer *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CBuffer *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      long obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the buffer index in the list                              |
//| with the maximum real property value                             |
//+------------------------------------------------------------------+
int CSelect::FindBufferMax(CArrayObj *list_source,ENUM_BUFFER_PROP_DOUBLE property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CBuffer *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CBuffer *obj=list_source.At(i);
      double obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      double obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the buffer index in the list                              |
//| with the maximum string property value                           |
//+------------------------------------------------------------------+
int CSelect::FindBufferMax(CArrayObj *list_source,ENUM_BUFFER_PROP_STRING property)
  {
   if(list_source==NULL) return WRONG_VALUE;
   int index=0;
   CBuffer *max_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CBuffer *obj=list_source.At(i);
      string obj1_prop=obj.GetProperty(property);
      max_obj=list_source.At(index);
      string obj2_prop=max_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,MORE)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the buffer index in the list                              |
//| with the minimum integer property value                          |
//+------------------------------------------------------------------+
int CSelect::FindBufferMin(CArrayObj* list_source,ENUM_BUFFER_PROP_INTEGER property)
  {
   int index=0;
   CBuffer *min_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CBuffer *obj=list_source.At(i);
      long obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      long obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the buffer index in the list                              |
//| with the minimum real property value                             |
//+------------------------------------------------------------------+
int CSelect::FindBufferMin(CArrayObj* list_source,ENUM_BUFFER_PROP_DOUBLE property)
  {
   int index=0;
   CBuffer *min_obj=NULL;
   int total=list_source.Total();
   if(total== 0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CBuffer *obj=list_source.At(i);
      double obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      double obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+
//| Return the buffer index in the list                              |
//| with the minimum string property value                           |
//+------------------------------------------------------------------+
int CSelect::FindBufferMin(CArrayObj* list_source,ENUM_BUFFER_PROP_STRING property)
  {
   int index=0;
   CBuffer *min_obj=NULL;
   int total=list_source.Total();
   if(total==0) return WRONG_VALUE;
   for(int i=1; i<total; i++)
     {
      CBuffer *obj=list_source.At(i);
      string obj1_prop=obj.GetProperty(property);
      min_obj=list_source.At(index);
      string obj2_prop=min_obj.GetProperty(property);
      if(CompareValues(obj1_prop,obj2_prop,LESS)) index=i;
     }
   return index;
  }
//+------------------------------------------------------------------+

CSelectクラスについては第3部で詳しく説明しました。

抽象バッファとその子孫のクラスを少し改善してみましょう。

バッファオブジェクトのプロパティによる検索と並べ替えを実行するため、 CSelectクラスファイルを抽象バッファクラスファイル( \MQL5\Include\DoEasy\Objects\Indicators\Buffer.mqh)にインクルードしましょう。

//+------------------------------------------------------------------+
//|                                                       Buffer.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
#property strict    // Necessary for mql4
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "..\..\Services\Select.mqh"
#include "..\..\Objects\BaseObj.mqh"
//+------------------------------------------------------------------+

これで、CSelectクラスがCBufferクラスとそのすべての子孫に表示されます。

クラスのpublicセクションに、バッファオブジェクトのカスタム名を設定するメソッドを記述します。

public:
//--- Set buffer's (1) integer, (2) real and (3) string properties
   void              SetProperty(ENUM_BUFFER_PROP_INTEGER property,long value)   { this.m_long_prop[property]=value;                                        }
   void              SetProperty(ENUM_BUFFER_PROP_DOUBLE property,double value)  { this.m_double_prop[this.IndexProp(property)]=value;                      }
   void              SetProperty(ENUM_BUFFER_PROP_STRING property,string value)  { this.m_string_prop[this.IndexProp(property)]=value;                      }
//--- Return (1) integer, (2) real and (3) string buffer properties from the properties array
   long              GetProperty(ENUM_BUFFER_PROP_INTEGER property)        const { return this.m_long_prop[property];                                       }
   double            GetProperty(ENUM_BUFFER_PROP_DOUBLE property)         const { return this.m_double_prop[this.IndexProp(property)];                     }
   string            GetProperty(ENUM_BUFFER_PROP_STRING property)         const { return this.m_string_prop[this.IndexProp(property)];                     }
//--- Get description of buffer's (1) integer, (2) real and (3) string properties
   string            GetPropertyDescription(ENUM_BUFFER_PROP_INTEGER property);
   string            GetPropertyDescription(ENUM_BUFFER_PROP_DOUBLE property);
   string            GetPropertyDescription(ENUM_BUFFER_PROP_STRING property);
//--- Return the flag of the buffer supporting the property
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_INTEGER property)          { return true;       }
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_DOUBLE property)           { return true;       }
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_STRING property)           { return true;       }

//--- Compare CBuffer objects by all possible properties (for sorting the lists by a specified buffer object property)
   virtual int       Compare(const CObject *node,const int mode=0) const;
//--- Compare CBuffer objects by all properties (to search for equal buffer objects)
   bool              IsEqual(CBuffer* compared_obj) const;
                     
//--- Set the buffer name
   void              SetName(const string name)                                  { this.m_name=name;  }

//--- Default constructor
                     CBuffer(void){;}
protected:

バッファにカスタム名を設定すると、コレクションリストでの後続の検索用にバッファに名前を付けることができます。

指定された時系列インデックスからバッファ値を返すメソッドと、指定された時系列インデックスのバッファに割り当てられた色を返すメソッドがあります。ただし、指定された時系列インデックス内のバッファに設定されたカラーのインデックスを返すメソッドはありません。実際、バッファ自体にはカラー値を設定していません。代わりに、カラーインデックス(指定された時系列位置に線を描画するために使用される色のシリアル番号(カラーバッファに割り当てられたもののうち)を指定する値)を設定します。

これを修正しましょう。指定された時系列位置のバッファに設定されたカラーインデックスを返すさらに別のメソッドを宣言し、指定された時系列位置のバッファカラーを返すメソッドの名前をGetColorBufferValue()からGetColorBufferValueColor()に変更します。

//--- Return the size of the data buffer array
   virtual int       GetDataTotal(const uint buffer_index=0)   const;
//--- Return the value from the specified index of the specified (1) data, (2) color index and (3) color buffer arrays
   double            GetDataBufferValue(const uint buffer_index,const uint series_index) const;
   int               GetColorBufferValueIndex(const uint series_index) const;
   color             GetColorBufferValueColor(const uint series_index) const;
//--- Set the value to the specified index of the specified (1) data and (2) color buffer arrays

これで、宣言されたバッファの色を処理する2つのメソッドができました。1つは色を返し、もう1つはカラーインデックスを返します。

クラス本体の外側で、カラーインデックスを返すメソッドを実装し、バッファクラスを返すメソッドの実装を修正します。

//+------------------------------------------------------------------+
//| Return the color index value from the specified timeseries index |
//| of the specified color buffer array                              |
//+------------------------------------------------------------------+
int CBuffer::GetColorBufferValueIndex(const uint series_index) const
  {
   int data_total=this.GetDataTotal(0);
   if(data_total==0)
      return WRONG_VALUE;
   int data_index=((int)series_index<data_total ? (int)series_index : data_total-1);
   return(this.ColorsTotal()==1 ? 0 : (int)this.ColorBufferArray[data_index]);

  }
//+------------------------------------------------------------------+
//| Return the color value from the specified timeseries index       |
//| of the specified color buffer array                              |
//+------------------------------------------------------------------+
color CBuffer::GetColorBufferValueColor(const uint series_index) const
  {
   int data_total=this.GetDataTotal(0);
   if(data_total==0)
      return clrNONE;
   int color_index=this.GetColorBufferValueIndex(series_index);
   return(color_index>WRONG_VALUE ? (color)this.ArrayColors[color_index] : clrNONE);
  }
//+------------------------------------------------------------------+

以前は、メソッドは1つしかなく、カラーインデックスはその内部で取得されていました

//+------------------------------------------------------------------+
//| Return the value from the specified timeseries index             |
//| of the specified color buffer array                              |
//+------------------------------------------------------------------+
color CBuffer::GetColorBufferValue(const uint series_index) const
  {
   int data_total=this.GetDataTotal(0);
   if(data_total==0)
      return clrNONE;
   int data_index=((int)series_index<data_total ? (int)series_index : data_total-1);
   int color_index=(this.ColorsTotal()==1 ? 0 : (int)this.ColorBufferArray[data_index]);
   return (color)this.ArrayColors[color_index];
  }
//+------------------------------------------------------------------+

これで、この計算は別のGetColorBufferValueIndex()メソッドに移動されましたが、バーの色の戻りメソッドでは、インデックス計算の代わりに新しいメソッドの呼び出しが使用されるようになりました

抽象バッファの子孫である矢印バッファオブジェクトクラス(残りのバッファクラスと同様)を作成するときに、改善を行いました。矢印コードを設定およびシフトするための仮想メソッドはCBufferクラスで宣言されていますが、子孫クラスに実装するのを忘れています。これを修正しましょう。

矢印バッファオブジェクトクラス\MQL5\Include\DoEasy\Objects\Indicators\BufferArrow.mqhのファイルを開き、これらのメソッドを宣言します。また、指標バッファによって割り当てられた配列との間で設定するおよび返す別の2つのメソッドを追加します。

//+------------------------------------------------------------------+
//| Buffer with the "Drawing with arrows" drawing style              |
//+------------------------------------------------------------------+
class CBufferArrow : public CBuffer
  {
private:

public:
//--- Constructor
                     CBufferArrow(const uint index_plot,const uint index_base_array) :
                        CBuffer(BUFFER_STATUS_ARROW,BUFFER_TYPE_DATA,index_plot,index_base_array,1,1,"Arrows") {}
//--- Supported integer properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_INTEGER property);
//--- Supported real properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_DOUBLE property);
//--- Supported string properties of a buffer
   virtual bool      SupportProperty(ENUM_BUFFER_PROP_STRING property);
//--- Display a short buffer description in the journal
   virtual void      PrintShort(void);
   
//--- Set (1) the arrow code, (2) vertical shift of arrows
   virtual void      SetArrowCode(const uchar code);
   virtual void      SetArrowShift(const int shift);
   
//--- Set the value to the data buffer array
   void              SetData(const uint series_index,const double value)               { this.SetBufferValue(0,series_index,value);       }
//--- Return the value from the data buffer array
   double            GetData(const uint series_index)                            const { return this.GetDataBufferValue(0,series_index);  }
   
  };
//+------------------------------------------------------------------+

クラス本体の外で、矢印コードを設定およびシフトするメソッドを実装します。

//+------------------------------------------------------------------+
//| Set the arrow code                                               |
//+------------------------------------------------------------------+
void CBufferArrow::SetArrowCode(const uchar code)
  {
   this.SetProperty(BUFFER_PROP_ARROW_CODE,code);
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW,code);
  }
//+------------------------------------------------------------------+
//| Set the vertical shift of the arrows                             |
//+------------------------------------------------------------------+
void CBufferArrow::SetArrowShift(const int shift)
  {
   this.SetProperty(BUFFER_PROP_ARROW_SHIFT,shift);
   ::PlotIndexSetInteger((int)this.GetProperty(BUFFER_PROP_INDEX_PLOT),PLOT_ARROW_SHIFT,shift);
  }
//+------------------------------------------------------------------+

メソッドは、渡された値を適切なバッファオブジェクトプロパティに書き込みこのプロパティを描画されたバッファオブジェクトバッファに設定します

単一バッファを備えて、バッファ配列値をバッファオブジェクトに設定するメソッドおよびバッファオブジェクトからバッファ配列に値を返すメソッドの2つをバッファオブジェクトファイルに追加します(線(BufferLine.mqh)、セクション(BufferSection.mqh)、ゼロからのヒストグラム(BufferHistogram.mqh))。

//--- Set the value to the data buffer array
   void              SetData(const uint series_index,const double value)               { this.SetBufferValue(0,series_index,value);       }
//--- Return the value from the data buffer array
   double            GetData(const uint series_index)                            const { return this.GetDataBufferValue(0,series_index);  }

2つのレンダリング用バッファを備えた、バッファオブジェクトデータバッファ配列の値をバッファオブジェクトファイルに設定するメソッドおよびバッファオブジェクトファイルからバッファオブジェクトデータバッファ配列に値を返す4つのメソッドをバッファオブジェクトファイルに追加します(2つのデータ配列のヒストグラム(BufferHistogram2.mqh)、ジグザグ(BufferZigZag.mqh)、2つのデータ配列間の塗りつぶし(BufferFilling.mqh))。

//--- Set the value to the (1) zero and (2) the first data buffer array
   void              SetData0(const uint series_index,const double value)              { this.SetBufferValue(0,series_index,value);       }
   void              SetData1(const uint series_index,const double value)              { this.SetBufferValue(1,series_index,value);       }
//--- Return the value from the (1) zero and (2) the first data buffer array
   double            GetData0(const uint series_index)                           const { return this.GetDataBufferValue(0,series_index);  }
   double            GetData1(const uint series_index)                           const { return this.GetDataBufferValue(1,series_index);  }

4つのレンダリング用バッファを備えた、OHLC値をバッファオブジェクトデータバッファ配列に設定メソッドおよびバッファオブジェクトデータバッファ配列からOHLCに値を返す8つのメソッドを追加します(バー(BufferBars.mqh)、ローソク足(BufferCandles.mqh))。

//--- Set (1) Open, (2) High, (3) Low and (4) Close values to the appropriate data buffer array
   void              SetDataOpen(const uint series_index,const double value)           { this.SetBufferValue(0,series_index,value);       }
   void              SetDataHigh(const uint series_index,const double value)           { this.SetBufferValue(1,series_index,value);       }
   void              SetDataLow(const uint series_index,const double value)            { this.SetBufferValue(2,series_index,value);       }
   void              SetDataClose(const uint series_index,const double value)          { this.SetBufferValue(3,series_index,value);       }
//--- Return (1) Open, (2) High, (3) Low and (4) Close value from the appropriate data buffer array
   double            GetDataOpen(const uint series_index)                        const { return this.GetDataBufferValue(0,series_index);  }
   double            GetDataHigh(const uint series_index)                        const { return this.GetDataBufferValue(1,series_index);  }
   double            GetDataLow(const uint series_index)                         const { return this.GetDataBufferValue(2,series_index);  }
   double            GetDataClose(const uint series_index)                       const { return this.GetDataBufferValue(3,series_index);  }

もちろん、基本的なSetBufferValue()およびGetBufferValue()抽象バッファオブジェクトの既に記述されたメソッドがなくても問題はありませんが、これらのメソッドでは必要なバッファ番号を指定する必要があります。エンドユーザの作業を簡素化するために最善を尽くします。したがって、適用するメソッドを選択する機能を実装します。

これで、指標バッファオブジェクトのコレクションクラスを開発する準備が整いました。

このクラスには、作成されたすべてのバッファオブジェクトのリストが含まれ、プログラムで使用するためのバッファを作成および取得する機能が提供されます。以前のコレクションクラスとは異なり、ここでは、同じプロパティを持つ同じオブジェクトが存在するかどうかを確認する必要はありません。代わりに、さまざまなイベントを視覚化するために同じバッファを使用できます。

バッファオブジェクトのコレクションクラス

\MQL5\Include\DoEasy\Collections\で、標準ライブラリの基本的なCObjectクラスを持つBuffersCollection.mqhファイルを作成します。ライブラリ基本リストバッファオブジェクトのクラスファイルをただちにインクルードします

//+------------------------------------------------------------------+
//|                                            BuffersCollection.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "ListObj.mqh"
#include "..\Objects\Indicators\BufferArrow.mqh"
#include "..\Objects\Indicators\BufferLine.mqh"
#include "..\Objects\Indicators\BufferSection.mqh"
#include "..\Objects\Indicators\BufferHistogram.mqh"
#include "..\Objects\Indicators\BufferHistogram2.mqh"
#include "..\Objects\Indicators\BufferZigZag.mqh"
#include "..\Objects\Indicators\BufferFilling.mqh"
#include "..\Objects\Indicators\BufferBars.mqh"
#include "..\Objects\Indicators\BufferCandles.mqh"
//+------------------------------------------------------------------+
//| Collection of indicator buffers                                  |
//+------------------------------------------------------------------+
class CBuffersCollection : public CObject
  {

クラス本体に必要なコンテンツを入力して(残念ながら、それほど多くはありません)、その目的を検討しましょう。

//+------------------------------------------------------------------+
//| Collection of indicator buffers                                  |
//+------------------------------------------------------------------+
class CBuffersCollection : public CObject
  {
private:
   CListObj                m_list;                       // Buffer object list
   
//--- Return the index of the next (1) drawn and (2) basic buffer
   int                     GetIndexNextPlot(void);
   int                     GetIndexNextBase(void);
//--- Create a new buffer object and place it to the collection list
   bool                    CreateBuffer(ENUM_BUFFER_STATUS status);
   
public:
//--- Return (1) oneself and (2) the timeseries list
   CBuffersCollection     *GetObject(void)               { return &this;                                       }
   CArrayObj              *GetList(void)                 { return &this.m_list;                                }
//--- Return the number of (1) drawn buffers, (2) all arrays used to build all buffers in the collection
   int                     PlotsTotal(void);
   int                     BuffersTotal(void);
   
//--- Create the new buffer (1) "Drawing with arrows", (2) "Line", (3) "Sections", (4) "Histogram from the zero line", 
//--- (5) "Histogram on two indicator buffers", (6) "Zigzag", (7) "Color filling between two levels",
//--- (8) "Display as bars", (9) "Display as candles",
   bool                    CreateArrow(void)             { return this.CreateBuffer(BUFFER_STATUS_ARROW);      }
   bool                    CreateLine(void)              { return this.CreateBuffer(BUFFER_STATUS_LINE);       }
   bool                    CreateSection(void)           { return this.CreateBuffer(BUFFER_STATUS_SECTION);    }
   bool                    CreateHistogram(void)         { return this.CreateBuffer(BUFFER_STATUS_HISTOGRAM);  }
   bool                    CreateHistogram2(void)        { return this.CreateBuffer(BUFFER_STATUS_HISTOGRAM2); }
   bool                    CreateZigZag(void)            { return this.CreateBuffer(BUFFER_STATUS_ZIGZAG);     }
   bool                    CreateFilling(void)           { return this.CreateBuffer(BUFFER_STATUS_FILLING);    }
   bool                    CreateBars(void)              { return this.CreateBuffer(BUFFER_STATUS_BARS);       }
   bool                    CreateCandles(void)           { return this.CreateBuffer(BUFFER_STATUS_CANDLES);    }
   
//--- Return the buffer by the Plot index
   CBuffer                *GetBufferByPlot(const int plot_index);
//--- Return buffers by drawing style by a serial number
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   CBufferArrow           *GetBufferArrow(const int number);
   CBufferLine            *GetBufferLine(const int number);
   CBufferSection         *GetBufferSection(const int number);
   CBufferHistogram       *GetBufferHistogram(const int number);
   CBufferHistogram2      *GetBufferHistogram2(const int number);
   CBufferZigZag          *GetBufferZigZag(const int number);
   CBufferFilling         *GetBufferFilling(const int number);
   CBufferBars            *GetBufferBars(const int number);
   CBufferCandles         *GetBufferCandles(const int number);
   
//--- Constructor
                           CBuffersCollection();
  };
//+------------------------------------------------------------------+

したがって、m_listは、作成されたすべてのバッファオブジェクトを追加して保存するリストです。これは、CObjectクラスインスタンスへのポインタの動的配列のクラスの子孫です。

次に作成される指標バッファのインデックスを指定するには、次に描画されるバッファのインデックスを返すGetIndexNextPlot()privateメソッドが必要ですが、GetIndexNextBase()メソッド(private)新しく作成されたバッファオブジェクトの指標バッファとして割り当てることができる実配列のインデックスを指定するには、次の基本バッファのインデックスを返す必要があります。

これを明確にしましょう。指標バッファを作成するときは、データウィンドウでその番号(描画されたバッファ番号)を指定し、それをdouble 配列(基本バッファ配列のインデックス)にバインドします。何故「基本的」なのでしょうか。描画バッファは複数の配列を使用できます。指標として割り当てられた最初の配列のみが基本です。描画に使用される他の配列のインデックスは、「基本配列」+ Nに等しくなります。

したがって、2つの配列に基づく3つの色付きバッファの場合、描画基本のインデックスは次のようになります。

1番目のバッファ

2番目のバッファ

3番目のバッファ

ご覧のとおり、インデックスは、描画されたバッファと各バッファごとの基本配列に対して個別です。指標に複数のバッファが適用されている場合、混乱しやすくなります。コレクションクラスは、描画されたバッファとその配列に正しいインデックスを自動的に割り当てます。これは、プログラムからいつでも参照できることを意味します。

CreateBuffer()メソッドは、新しいバッファを作成し、それをコレクションリストに配置します。
GetObject()メソッドとGetList()メソッドは、コレクションクラスオブジェクトへのポインタと、それに応じてコレクションクラスのバッファオブジェクトのリストを返します。
PlotsTotal()メソッドBuffersTotal() メソッドは、コレクション内に作成された描画バッファの数と、それに応じてすべての描画バッファを構築するために使用された配列の総数を返します。

以下は、特定の描画スタイルでバッファオブジェクトを作成するためのパブリックメソッドです。

//--- Create the new buffer (1) "Drawing with arrows", (2) "Line", (3) "Sections", (4) "Histogram from the zero line", 
//--- (5) "Histogram on two indicator buffers", (6) "Zigzag", (7) "Color filling between two levels",
//--- (8) "Display as bars", (9) "Display as candles",
   bool                    CreateArrow(void)             { return this.CreateBuffer(BUFFER_STATUS_ARROW);      }
   bool                    CreateLine(void)              { return this.CreateBuffer(BUFFER_STATUS_LINE);       }
   bool                    CreateSection(void)           { return this.CreateBuffer(BUFFER_STATUS_SECTION);    }
   bool                    CreateHistogram(void)         { return this.CreateBuffer(BUFFER_STATUS_HISTOGRAM);  }
   bool                    CreateHistogram2(void)        { return this.CreateBuffer(BUFFER_STATUS_HISTOGRAM2); }
   bool                    CreateZigZag(void)            { return this.CreateBuffer(BUFFER_STATUS_ZIGZAG);     }
   bool                    CreateFilling(void)           { return this.CreateBuffer(BUFFER_STATUS_FILLING);    }
   bool                    CreateBars(void)              { return this.CreateBuffer(BUFFER_STATUS_BARS);       }
   bool                    CreateCandles(void)           { return this.CreateBuffer(BUFFER_STATUS_CANDLES);    }

メソッドは、CreateBuffer()バッファオブジェクトを作成するためのprivateメソッドの結果を返して作成されたバッファの描画スタイルを指定します

GetBufferByPlot()メソッドは、描画されたバッファインデックスによってバッファへのポインタを返します。

以下は、シリアル番号でバッファオブジェクトへのポインタを返すメソッドです。

//--- Return buffers by drawing style by a serial number
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   CBufferArrow           *GetBufferArrow(const int number);
   CBufferLine            *GetBufferLine(const int number);
   CBufferSection         *GetBufferSection(const int number);
   CBufferHistogram       *GetBufferHistogram(const int number);
   CBufferHistogram2      *GetBufferHistogram2(const int number);
   CBufferZigZag          *GetBufferZigZag(const int number);
   CBufferFilling         *GetBufferFilling(const int number);
   CBufferBars            *GetBufferBars(const int number);
   CBufferCandles         *GetBufferCandles(const int number);

特定の描画スタイルのオブジェクトを、作成順に番号で返します。
次の例でこれを明確にしましょう。

描画されたバッファインデックス0、1、2、3を使用して4つのBufferArrow()矢印バッファを作成しました。
次に、描画されたバッファインデックスが4、5、6、7、8の5つのBufferLine()ラインバッファを作成しました。

次に、3番目の矢印バッファ(インデックスが2)と4番目の行バッファ(インデックスが7)を操作する必要があります。
3番目の矢印バッファへのポインタを取得するには、(インデックスではなく)シリアル番号でポインタを取得するだけです。数はゼロから数える必要があります。たとえば、3番目の矢印バッファが必要な場合は、次のように取得する必要があります。

CBufferArrow *buffer_arrow=GetBufferArrow(2); // the third arrow buffer (0,1,2)

4番目の線バッファへのポインタは次のように取得されます。

CBufferLine *buffer_line=GetBufferLine(3); // the fourth line buffer (0,1,2,3)


次に、宣言されたすべてのメソッドの実装について考えてみましょう。

クラスコンストラクタ:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CBuffersCollection::CBuffersCollection()
  {
   this.m_list.Clear();
   this.m_list.Sort();
   this.m_list.Type(COLLECTION_BUFFERS_ID);
  }
//+------------------------------------------------------------------+

リストをクリアし、リストの並び替え済みリストフラグを設定し、コレクションタイプの指標バッファコレクションリストIDを設定します。

以下は、次に描画されるバッファのインデックスを返すメソッド次の基本バッファのインデックスを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the index of the next drawn buffer                        |
//+------------------------------------------------------------------+
int CBuffersCollection::GetIndexNextPlot(void)
  {
//--- Return the pointer to the list. If the list is not created for some reason, return -1
   CArrayObj *list=this.GetList();
   if(list==NULL)
      return WRONG_VALUE;
//--- Get the index of the drawn buffer with the highest value. If the FindBufferMax() method returns -1,
//--- the list is empty, return index 0 for the very first buffer in the list
   int index=CSelect::FindBufferMax(list,BUFFER_PROP_INDEX_PLOT);
   if(index==WRONG_VALUE)
      index=0;
//--- if the index is not -1,
   else
     {
      //--- get the buffer object from the list by its index
      CBuffer *buffer=this.m_list.At(index);
      if(buffer==NULL)
         return WRONG_VALUE;
      //--- Return the index following the Plot index of the buffer object
      index=buffer.IndexPlot()+1;
     }
//--- Return the index value
   return index;
  }
//+------------------------------------------------------------------+
//| Return the index of the next basic buffer                        |
//+------------------------------------------------------------------+
int CBuffersCollection::GetIndexNextBase(void)
  {
//--- Return the pointer to the list. If the list is not created for some reason, return -1
   CArrayObj *list=this.GetList();
   if(list==NULL)
      return WRONG_VALUE;
//--- Get the highest index of the next array that can be assigned as an indicator buffer,
//--- if the FindBufferMax() method returns -1,
//--- the list is empty, return index 0 for the very first buffer in the list
   int index=CSelect::FindBufferMax(list,BUFFER_PROP_INDEX_NEXT);
   if(index==WRONG_VALUE)
      index=0;
//--- if the index is not -1,
   else
     {
      //--- get the buffer object from the list by its index
      CBuffer *buffer=this.m_list.At(index);
      if(buffer==NULL)
         return WRONG_VALUE;
      //--- Return the index of the next array from the buffer object properties
      index=buffer.IndexNextBuffer();
     }
//--- Return the index value
   return index;
  }
//+------------------------------------------------------------------+

これら2つのメソッドのロジックは同じで、コードのコメントで説明しています。

以下は、新しいバッファオブジェクトを作成し、それをコレクションリストに配置するメソッドです。

//+------------------------------------------------------------------+
//| Create a new buffer object and place it to the collection list   |
//+------------------------------------------------------------------+
bool CBuffersCollection::CreateBuffer(ENUM_BUFFER_STATUS status)
  {
//--- Get the drawn buffer index and the index used to assign the first buffer array as an indicator one
   int index_plot=this.GetIndexNextPlot();
   int index_base=this.GetIndexNextBase();
//--- If any of the indices is not received, return 'false'
   if(index_plot==WRONG_VALUE || index_base==WRONG_VALUE)
      return false;
//--- If the maximum possible number of indicator buffers has already been reached, inform about it and return 'false'
   if(this.m_list.Total()==IND_BUFFERS_MAX)
     {
      ::Print(CMessage::Text(MSG_LIB_TEXT_BUFFER_TEXT_MAX_BUFFERS_REACHED));
      return false;
     }
//--- Create the buffer drawing style description
   string descript=::StringSubstr(::EnumToString(status),14);
//--- Declare the abstract buffer object
   CBuffer *buffer=NULL;
//--- Create a buffer object depending on the status passed to the method (drawing style)
   switch(status)
     {
      case BUFFER_STATUS_ARROW      : buffer=new CBufferArrow(index_plot,index_base);        break;
      case BUFFER_STATUS_LINE       : buffer=new CBufferLine(index_plot,index_base);         break;
      case BUFFER_STATUS_SECTION    : buffer=new CBufferSection(index_plot,index_base);      break;
      case BUFFER_STATUS_HISTOGRAM  : buffer=new CBufferHistogram(index_plot,index_base);    break;
      case BUFFER_STATUS_HISTOGRAM2 : buffer=new CBufferHistogram2(index_plot,index_base);   break;
      case BUFFER_STATUS_ZIGZAG     : buffer=new CBufferZigZag(index_plot,index_base);       break;
      case BUFFER_STATUS_FILLING    : buffer=new CBufferFilling(index_plot,index_base);      break;
      case BUFFER_STATUS_BARS       : buffer=new CBufferBars(index_plot,index_base);         break;
      case BUFFER_STATUS_CANDLES    : buffer=new CBufferCandles(index_plot,index_base);      break;
      default: break;
     }
//--- Failed to create a buffer, inform of that and return 'false'
   if(buffer==NULL)
     {
      ::Print(CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_BUFFER_OBJ)," ",descript);
      return false;
     }
//--- If failed to add a buffer object to the collection list for some reason,
//--- inform of that, remove the created buffer object and return 'false'
   if(!this.m_list.Add(buffer))
     {
      ::Print(CMessage::Text(MSG_LIB_SYS_FAILED_ADD_BUFFER));
      delete buffer;
      return false;
     }
//--- Set a name for the buffer object and return 'true'
   buffer.SetName("Buffer"+descript+"("+(string)buffer.IndexPlot()+")");
   return true;
  }
//+------------------------------------------------------------------+

ロジックは、ここのコメントにも記載されています。CBuffer抽象バッファオブジェクトを宣言していることに注意してください。ただし、実際には、ステータスによってメソッドに渡される描画タイプを使用して新しいオブジェクトを作成します(ステータスは描画スタイルを表します)。すべてのバッファオブジェクトは抽象バッファオブジェクトの子孫であるため、このような宣言とオブジェクトの作成は許容され、便利です。

以下は、プロットインデックス(データウィンドウのインデックス)によってバッファを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the buffer by the Plot index                              |
//+------------------------------------------------------------------+
CBuffer *CBuffersCollection::GetBufferByPlot(const int plot_index)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_INDEX_PLOT,plot_index,EQUAL);
   return(list!=NULL && list.Total()==1 ? list.At(0) : NULL);
  }
//+------------------------------------------------------------------+

CSelectクラスを使用すると、指定したインデックスを持つバッファオブジェクトのみを含むリストを取得できます(リストにはオブジェクトが1つだけあります)。取得したリストからバッファオブジェクト(見つかった場合)を返します。コレクションリストにそのようなオブジェクトがない場合、NULLを返します。

以下は、特定のタイプのバッファオブジェクトを返すメソッドです。

//+------------------------------------------------------------------+
//| Return the "Drawing by arrows" buffer by a serial number         |
//| (0 - the very first arrow buffer, 1,2,N - subsequent ones)       |
//+------------------------------------------------------------------+
CBufferArrow *CBuffersCollection::GetBufferArrow(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_ARROW,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }
//+------------------------------------------------------------------+
//| Return the Line buffer by a serial number                        |
//| (0 - the very first line buffer, 1,2,N - subsequent ones)        |
//+------------------------------------------------------------------+
CBufferLine *CBuffersCollection::GetBufferLine(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_LINE,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }
//+------------------------------------------------------------------+
//| Return the Sections buffer by a serial number                    |
//| (0 - the very first sections buffer, 1,2,N - subsequent ones)    |
//+------------------------------------------------------------------+
CBufferSection *CBuffersCollection::GetBufferSection(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_SECTION,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }
//+------------------------------------------------------------------+
//| Return the "Histogram from the zero line" buffer by number       |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
CBufferHistogram *CBuffersCollection::GetBufferHistogram(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_HISTOGRAM,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }
//+------------------------------------------------------------------+
//| Return the "Histogram on two buffers" buffer by number           |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
CBufferHistogram2 *CBuffersCollection::GetBufferHistogram2(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_HISTOGRAM2,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }
//+------------------------------------------------------------------+
//| Return the ZigZag buffer by a serial number                      |
//| (0 - the very first zigzag buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
CBufferZigZag *CBuffersCollection::GetBufferZigZag(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_ZIGZAG,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }
//+------------------------------------------------------------------+
//|Return the "Color filling between two levels" buffer by number    |
//| (0 - the very first filling buffer, 1,2,N - subsequent ones)     |
//+------------------------------------------------------------------+
CBufferFilling *CBuffersCollection::GetBufferFilling(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_FILLING,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }
//+------------------------------------------------------------------+
//| Return the "Display as bars" buffer by a serial number           |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
CBufferBars *CBuffersCollection::GetBufferBars(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_BARS,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }
//+------------------------------------------------------------------+
//|Return the "Display as candles" buffer by a serial number         |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
CBufferCandles *CBuffersCollection::GetBufferCandles(const int number)
  {
   CArrayObj *list=CSelect::ByBufferProperty(this.GetList(),BUFFER_PROP_STATUS,BUFFER_STATUS_CANDLES,EQUAL);
   return(list!=NULL && list.Total()>0 ? list.At(number) : NULL);
  }


すべてのメソッドは同じなので、そのうちの1つだけを考えてみましょう。
必要な描画スタイルのみのバッファオブジェクトを含むリストを取得します。
リストが取得され、空ではない場合は、取得されたリストから指定されたインデックスでオブジェクトを返します
リストでは、オブジェクトはインデックスの昇順で配置されているため、インデックスの調整は必要ありません。
インデックスがリストの外にある場合、CArrayObjクラスのAt()メソッドNULLを返します。
リストが取得できなかったか空の場合は、NULLを返します

以下は、描画されたバッファの数とすべての指標配列の数を返すメソッドです。

//+------------------------------------------------------------------+
//| Return the number of drawn buffers                               |
//+------------------------------------------------------------------+
int CBuffersCollection::PlotsTotal(void)
  {
   int index=CSelect::FindBufferMax(this.GetList(),BUFFER_PROP_INDEX_PLOT);
   CBuffer *buffer=this.m_list.At(index);
   return(buffer!=NULL ? buffer.IndexPlot()+1 : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Returns the number of all indicator arrays                       |
//+------------------------------------------------------------------+
int CBuffersCollection::BuffersTotal(void)
  {
   int index=CSelect::FindBufferMax(this.GetList(),BUFFER_PROP_INDEX_NEXT);
   CBuffer *buffer=this.m_list.At(index);
   return(buffer!=NULL ? buffer.IndexNextBuffer() : WRONG_VALUE);
  }
//+------------------------------------------------------------------+

メソッドのロジックは似ています。必要なプロパティの値が最も高いインデックスを取得します取得したインデックスによってコレクションリストからバッファオブジェクトを取得しますバッファが取得された場合、メソッドに対応するプロパティを返します。それ以外の場合は-1を返します

これで、指標バッファコレクションクラスの開発は完了です。

次に、ライブラリベースのプログラムのクラスメソッドへのアクセスを提供する必要があります。私の場合、これはCEngineライブラリの基本オブジェクトクラスで行われます。

\MQL5\Include\DoEasy\Engine.mqhを開いて必要な変更を加えます。ここでは、指標バッファコレクションクラスの作成済みのメソッドを複製し、便宜上補助メソッドを追加するだけです。

まず、クラスファイルをインクルードし、バッファコレクションクラスのオブジェクトを宣言します

//+------------------------------------------------------------------+
//|                                                       Engine.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Include files                                                    |
//+------------------------------------------------------------------+
#include "Services\TimerCounter.mqh"
#include "Collections\HistoryCollection.mqh"
#include "Collections\MarketCollection.mqh"
#include "Collections\EventsCollection.mqh"
#include "Collections\AccountsCollection.mqh"
#include "Collections\SymbolsCollection.mqh"
#include "Collections\ResourceCollection.mqh"
#include "Collections\TimeSeriesCollection.mqh"
#include "Collections\BuffersCollection.mqh"
#include "TradingControl.mqh"
//+------------------------------------------------------------------+
//| Library basis class                                              |
//+------------------------------------------------------------------+
class CEngine
  {
private:
   CHistoryCollection   m_history;                       // Collection of historical orders and deals
   CMarketCollection    m_market;                        // Collection of market orders and deals
   CEventsCollection    m_events;                        // Event collection
   CAccountsCollection  m_accounts;                      // Account collection
   CSymbolsCollection   m_symbols;                       // Symbol collection
   CTimeSeriesCollection m_time_series;                  // Timeseries collection
   CBuffersCollection   m_buffers;                       // Collection of indicator buffers
   CResourceCollection  m_resource;                      // Resource list
   CTradingControl      m_trading;                       // Trading management object
   CPause               m_pause;                         // Pause object
   CArrayObj            m_list_counters;                 // List of timer counters

publicクラスセクションで、同じ名前のバッファコレクションクラスメソッドの結果を呼び出して返すメソッドを記述しバッファコレクションクラスを操作するための追加のメソッドを宣言します

//--- Copy the specified double property of the specified timeseries of the specified symbol to the array
//--- Regardless of the array indexing direction, copying is performed the same way as copying to a timeseries array
   bool                 SeriesCopyToBufferAsSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const ENUM_BAR_PROP_DOUBLE property,
                                                   double &array[],const double empty=EMPTY_VALUE)
                          { return this.m_time_series.CopyToBufferAsSeries(symbol,timeframe,property,array,empty);}

//--- Return (1) the buffer collection, (2) the buffer list from the buffer collection and (3) the buffer by the Plot index
   CBuffersCollection  *GetBuffersCollection(void)                                     { return &this.m_buffers;                             }
   CArrayObj           *GetListBuffers(void)                                           { return this.m_buffers.GetList();                    }
   CBuffer             *GetBufferByPlot(const int plot_index)                          { return this.m_buffers.GetBufferByPlot(plot_index);  }
//--- Return buffers by drawing style by a serial number
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   CBufferArrow        *GetBufferArrow(const int number)                               { return this.m_buffers.GetBufferArrow(number);       }
   CBufferLine         *GetBufferLine(const int number)                                { return this.m_buffers.GetBufferLine(number);        }
   CBufferSection      *GetBufferSection(const int number)                             { return this.m_buffers.GetBufferSection(number);     }
   CBufferHistogram    *GetBufferHistogram(const int number)                           { return this.m_buffers.GetBufferHistogram(number);   }
   CBufferHistogram2   *GetBufferHistogram2(const int number)                          { return this.m_buffers.GetBufferHistogram2(number);  }
   CBufferZigZag       *GetBufferZigZag(const int number)                              { return this.m_buffers.GetBufferZigZag(number);      }
   CBufferFilling      *GetBufferFilling(const int number)                             { return this.m_buffers.GetBufferFilling(number);     }
   CBufferBars         *GetBufferBars(const int number)                                { return this.m_buffers.GetBufferBars(number);        }
   CBufferCandles      *GetBufferCandles(const int number)                             { return this.m_buffers.GetBufferCandles(number);     }

//--- Return the number of (1) drawn buffers and (2) all indicator arrays
   int                  BufferPlotsTotal(void)                                         { return this.m_buffers.PlotsTotal();                 }
   int                  BuffersTotal(void)                                             { return this.m_buffers.BuffersTotal();               }

//--- Create the new buffer (1) "Drawing with arrows", (2) "Line", (3) "Sections", (4) "Histogram from the zero line", 
//--- (5) "Histogram on two indicator buffers", (6) "Zigzag", (7) "Color filling between two levels",
//--- (8) "Display as bars", (9) "Display as candles",
   bool                 BufferCreateArrow(void)                                        { return this.m_buffers.CreateArrow();                }
   bool                 BufferCreateLine(void)                                         { return this.m_buffers.CreateLine();                 }
   bool                 BufferCreateSection(void)                                      { return this.m_buffers.CreateSection();              }
   bool                 BufferCreateHistogram(void)                                    { return this.m_buffers.CreateHistogram();            }
   bool                 BufferCreateHistogram2(void)                                   { return this.m_buffers.CreateHistogram2();           }
   bool                 BufferCreateZigZag(void)                                       { return this.m_buffers.CreateZigZag();               }
   bool                 BufferCreateFilling(void)                                      { return this.m_buffers.CreateFilling();              }
   bool                 BufferCreateBars(void)                                         { return this.m_buffers.CreateBars();                 }
   bool                 BufferCreateCandles(void)                                      { return this.m_buffers.CreateCandles();              }
   
//--- Return buffer data by its serial number of (1) arrows, (2) line, (3) sections and (4) histogram from zero
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   double               BufferDataArrow(const int number,const int series_index);
   double               BufferDataLine(const int number,const int series_index);
   double               BufferDataSection(const int number,const int series_index);
   double               BufferDataHistogram(const int number,const int series_index);
//--- Return buffer data by its serial number of (1) the zero and (2) the first histogram buffer on two buffers
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   double               BufferDataHistogram20(const int number,const int series_index);
   double               BufferDataHistogram21(const int number,const int series_index);
//--- Return buffer data by its serial number of (1) the zero and (2) the first zigzag buffer
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   double               BufferDataZigZag0(const int number,const int series_index);
   double               BufferDataZigZag1(const int number,const int series_index);
//--- Return buffer data by its serial number of (1) the zero and (2) the first filling buffer
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   double               BufferDataFilling0(const int number,const int series_index);
   double               BufferDataFilling1(const int number,const int series_index);
//--- Return buffer data by its serial number of (1) Open, (2) High, (3) Low and (4) Close bar buffers
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   double               BufferDataBarsOpen(const int number,const int series_index);
   double               BufferDataBarsHigh(const int number,const int series_index);
   double               BufferDataBarsLow(const int number,const int series_index);
   double               BufferDataBarsClose(const int number,const int series_index);
//--- Return buffer data by its serial number of (1) Open, (2) High, (3) Low and (4) Close candle buffers
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   double               BufferDataCandlesOpen(const int number,const int series_index);
   double               BufferDataCandlesHigh(const int number,const int series_index);
   double               BufferDataCandlesLow(const int number,const int series_index);
   double               BufferDataCandlesClose(const int number,const int series_index);

//--- Set buffer data by its serial number of (1) arrows, (2) line, (3) sections and (4) histogram from zero
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   void                 BufferSetDataArrow(const int number,const int series_index,const double value);
   void                 BufferSetDataLine(const int number,const int series_index,const double value);
   void                 BufferSetDataSection(const int number,const int series_index,const double value);
   void                 BufferSetDataHistogram(const int number,const int series_index,const double value);
//--- Set data of the (1) zero, (2) first and (3) all histogram buffers on two buffers by a serial number of a created buffer
//--- (0 - the very first created buffer with the HISTOGRAM2 drawing style, 1,2,N - subsequent ones)
   void                 BufferSetDataHistogram20(const int number,const int series_index,const double value);
   void                 BufferSetDataHistogram21(const int number,const int series_index,const double value);
   void                 BufferSetDataHistogram2(const int number,const int series_index,const double value0,const double value1);
//--- Set data of the (1) zero, (2) first and (3) all zigzag buffers by a serial number of a created buffer
//--- (0 - the very first created buffer with the ZIGZAG drawing style, 1,2,N - subsequent ones)
   void                 BufferSetDataZigZag0(const int number,const int series_index,const double value);
   void                 BufferSetDataZigZag1(const int number,const int series_index,const double value);
   void                 BufferSetDataZigZag(const int number,const int series_index,const double value0,const double value1);
//--- Set data of the (1) zero, (2) first and (3) all filling buffers by a serial number of a created buffer
//--- (0 - the very first created buffer with the FILLING drawing style, 1,2,N - subsequent ones)
   void                 BufferSetDataFilling0(const int number,const int series_index,const double value);
   void                 BufferSetDataFilling1(const int number,const int series_index,const double value);
   void                 BufferSetDataFilling(const int number,const int series_index,const double value0,const double value1);
//--- Set data of the (1) Open, (2) High, (3) Low, (4) Close and (5) all bar buffers by a serial number of a created buffer
//--- (0 - the very first created buffer with the BARS drawing style, 1,2,N - subsequent ones)
   void                 BufferSetDataBarsOpen(const int number,const int series_index,const double value);
   void                 BufferSetDataBarsHigh(const int number,const int series_index,const double value);
   void                 BufferSetDataBarsLow(const int number,const int series_index,const double value);
   void                 BufferSetDataBarsClose(const int number,const int series_index,const double value);
   void                 BufferSetDataBars(const int number,const int series_index,const double open,const double high,const double low,const double close);
//--- Set data of the (1) Open, (2) High, (3) Low, (4) Close and (5) all candle buffers by a serial number of a created buffer
//--- (0 - the very first created buffer with the CANDLES drawing style, 1,2,N - subsequent ones)
   void                 BufferSetDataCandlesOpen(const int number,const int series_index,const double value);
   void                 BufferSetDataCandlesHigh(const int number,const int series_index,const double value);
   void                 BufferSetDataCandlesLow(const int number,const int series_index,const double value);
   void                 BufferSetDataCandlesClose(const int number,const int series_index,const double value);
   void                 BufferSetDataCandles(const int number,const int series_index,const double open,const double high,const double low,const double close);
   
//--- Return buffer color by its serial number of (1) arrows, (2) line, (3) sections, (4) histogram from zero
//--- (5) histogram on two buffers, (6) zigzag, (7) filling, (8) bars and (9) candles
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   color                BufferColorArrow(const int number,const int series_index);
   color                BufferColorLine(const int number,const int series_index);
   color                BufferColorSection(const int number,const int series_index);
   color                BufferColorHistogram(const int number,const int series_index);
   color                BufferColorHistogram2(const int number,const int series_index);
   color                BufferColorZigZag(const int number,const int series_index);
   color                BufferColorFilling(const int number,const int series_index);
   color                BufferColorBars(const int number,const int series_index);
   color                BufferColorCandles(const int number,const int series_index);
   
//--- Return buffer color index by its serial number of (1) arrows, (2) line, (3) sections, (4) histogram from zero
//--- (5) histogram on two buffers, (6) zigzag, (7) filling, (8) bars and (9) candles
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   int                  BufferColorIndexArrow(const int number,const int series_index);
   int                  BufferColorIndexLine(const int number,const int series_index);
   int                  BufferColorIndexSection(const int number,const int series_index);
   int                  BufferColorIndexHistogram(const int number,const int series_index);
   int                  BufferColorIndexHistogram2(const int number,const int series_index);
   int                  BufferColorIndexZigZag(const int number,const int series_index);
   int                  BufferColorIndexFilling(const int number,const int series_index);
   int                  BufferColorIndexBars(const int number,const int series_index);
   int                  BufferColorIndexCandles(const int number,const int series_index);

//--- Set the color index to the color buffer by its serial number of (1) arrows, (2) line, (3) sections, (4) histogram from zero
//--- (5) histogram on two buffers, (6) zigzag, (7) filling, (8) bars and (9) candles
//--- (0 - the very first created buffer with the ХХХ drawing style, 1,2,N - subsequent ones)
   void                 BufferSetColorIndexArrow(const int number,const int series_index,const int color_index);
   void                 BufferSetColorIndexLine(const int number,const int series_index,const int color_index);
   void                 BufferSetColorIndexSection(const int number,const int series_index,const int color_index);
   void                 BufferSetColorIndexHistogram(const int number,const int series_index,const int color_index);
   void                 BufferSetColorIndexHistogram2(const int number,const int series_index,const int color_index);
   void                 BufferSetColorIndexZigZag(const int number,const int series_index,const int color_index);
   void                 BufferSetColorIndexFilling(const int number,const int series_index,const int color_index);
   void                 BufferSetColorIndexBars(const int number,const int series_index,const int color_index);
   void                 BufferSetColorIndexCandles(const int number,const int series_index,const int color_index);
   
//--- Set the following for the trading classes:

以下は、描画スタイルと同じ描画スタイルのバッファシリアル番号で特定のバッファデータを返すメソッドです。

//+------------------------------------------------------------------+
//| Return arrow buffer data by its serial number                    |
//| (0 - the very first arrow buffer, 1,2,N - subsequent ones)       |
//+------------------------------------------------------------------+
double CEngine::BufferDataArrow(const int number,const int series_index)
  {
   CBufferArrow *buff=this.m_buffers.GetBufferArrow(number);
   return(buff!=NULL ? buff.GetData(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return line buffer data by its serial number                     |
//| (0 - the very first line buffer, 1,2,N - subsequent ones)        |
//+------------------------------------------------------------------+
double CEngine::BufferDataLine(const int number,const int series_index)
  {
   CBufferLine *buff=this.m_buffers.GetBufferLine(number);
   return(buff!=NULL ? buff.GetData(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return section buffer data by its serial number                  |
//| (0 - the very first sections buffer, 1,2,N - subsequent ones)    |
//+------------------------------------------------------------------+
double CEngine::BufferDataSection(const int number,const int series_index)
  {
   CBufferSection *buff=this.m_buffers.GetBufferSection(number);
   return(buff!=NULL ? buff.GetData(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return histogram buffer data from zero                           |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
double CEngine::BufferDataHistogram(const int number,const int series_index)
  {
   CBufferHistogram *buff=this.m_buffers.GetBufferHistogram(number);
   return(buff!=NULL ? buff.GetData(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return histogram zero buffer data on two buffers                 |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
double CEngine::BufferDataHistogram20(const int number,const int series_index)
  {
   CBufferHistogram2 *buff=this.m_buffers.GetBufferHistogram2(number);
   return(buff!=NULL ? buff.GetData0(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return histogram first buffer data on two buffers                |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
double CEngine::BufferDataHistogram21(const int number,const int series_index)
  {
   CBufferHistogram2 *buff=this.m_buffers.GetBufferHistogram2(number);
   return(buff!=NULL ? buff.GetData1(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return zigzag zero buffer data                                   |
//| by its serial number                                             |
//| (0 - the very first zigzag buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
double CEngine::BufferDataZigZag0(const int number,const int series_index)
  {
   CBufferZigZag *buff=this.m_buffers.GetBufferZigZag(number);
   return(buff!=NULL ? buff.GetData0(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return zigzag first buffer data                                  |
//| by its serial number                                             |
//| (0 - the very first zigzag buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
double CEngine::BufferDataZigZag1(const int number,const int series_index)
  {
   CBufferZigZag *buff=this.m_buffers.GetBufferZigZag(number);
   return(buff!=NULL ? buff.GetData1(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return filling zero buffer data                                  |
//| by its serial number                                             |
//| (0 - the very first filling buffer, 1,2,N - subsequent ones)     |
//+------------------------------------------------------------------+
double CEngine::BufferDataFilling0(const int number,const int series_index)
  {
   CBufferFilling *buff=this.m_buffers.GetBufferFilling(number);
   return(buff!=NULL ? buff.GetData0(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return filling first buffer data                                 |
//| by its serial number                                             |
//| (0 - the very first filling buffer, 1,2,N - subsequent ones)     |
//+------------------------------------------------------------------+
double CEngine::BufferDataFilling1(const int number,const int series_index)
  {
   CBufferFilling *buff=this.m_buffers.GetBufferFilling(number);
   return(buff!=NULL ? buff.GetData1(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return Open data of the bar buffer by its serial number          |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
double CEngine::BufferDataBarsOpen(const int number,const int series_index)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   return(buff!=NULL ? buff.GetDataOpen(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return High data of the bar buffer by its serial number          |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
double CEngine::BufferDataBarsHigh(const int number,const int series_index)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   return(buff!=NULL ? buff.GetDataHigh(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return Low data of the bar buffer by its serial number           |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
double CEngine::BufferDataBarsLow(const int number,const int series_index)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   return(buff!=NULL ? buff.GetDataLow(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return Close data of the bar buffer by its serial number         |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
double CEngine::BufferDataBarsClose(const int number,const int series_index)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   return(buff!=NULL ? buff.GetDataClose(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return Open data of the candle buffer by its serial number       |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
double CEngine::BufferDataCandlesOpen(const int number,const int series_index)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   return(buff!=NULL ? buff.GetDataOpen(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return High data of the candle buffer by its serial number       |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
double CEngine::BufferDataCandlesHigh(const int number,const int series_index)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   return(buff!=NULL ? buff.GetDataHigh(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return Low data of the candle buffer by its serial number        |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
double CEngine::BufferDataCandlesLow(const int number,const int series_index)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   return(buff!=NULL ? buff.GetDataLow(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Return Close data of the candle buffer by its serial number      |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
double CEngine::BufferDataCandlesClose(const int number,const int series_index)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   return(buff!=NULL ? buff.GetDataClose(series_index) : EMPTY_VALUE);
  }
//+------------------------------------------------------------------+

すべてのメソッドは同じです。Candles描画スタイルでバッファオブジェクトのCloseバッファ値を返すメソッドを考えてみましょう。
このメソッドは、Candlesスタイルの作成されたすべてのバッファからCandlesスタイルのバッファシリアル番号を受け取り(特定の描画スタイルのバッファ番号が何を意味するかを上で詳細に検討しました)、CloseCandleバッファデータを取得する必要がある時系列インデックスを受け取ります。

バッファコレクションクラスのGetBufferCandles()メソッドを使用して、必要なバッファへのポインタを受け取りますバッファを受け取った場合は、指定された時系列インデックスでCloseバッファからデータを返しますその他の場合は「空の値」を返します

今説明したのとは反対のメソッドです。描画スタイルとシリアル番号によって、適切なバッファオブジェクトの特定のバッファの値を指定された時系列インデックスに設定します。

//+------------------------------------------------------------------+
//| Set arrow buffer data by its serial number                       |
//| (0 - the very first arrow buffer, 1,2,N - subsequent ones)       |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataArrow(const int number,const int series_index,const double value)
  {
   CBufferArrow *buff=this.m_buffers.GetBufferArrow(number);
   if(buff==NULL)
      return;
   buff.SetData(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set line buffer data by its serial number                        |
//| (0 - the very first line buffer, 1,2,N - subsequent ones)        |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataLine(const int number,const int series_index,const double value)
  {
   CBufferLine *buff=this.m_buffers.GetBufferLine(number);
   if(buff==NULL)
      return;
   buff.SetData(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set section buffer data by its serial number                     |
//| (0 - the very first sections buffer, 1,2,N - subsequent ones)    |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataSection(const int number,const int series_index,const double value)
  {
   CBufferSection *buff=this.m_buffers.GetBufferSection(number);
   if(buff==NULL)
      return;
   buff.SetData(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set histogram buffer data from zero                              |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataHistogram(const int number,const int series_index,const double value)
  {
   CBufferHistogram *buff=this.m_buffers.GetBufferHistogram(number);
   if(buff==NULL)
      return;
   buff.SetData(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set histogram zero buffer data on two buffers                    |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataHistogram20(const int number,const int series_index,const double value)
  {
   CBufferHistogram2 *buff=this.m_buffers.GetBufferHistogram2(number);
   if(buff==NULL)
      return;
   buff.SetData0(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set histogram first buffer data on two buffers                   |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataHistogram21(const int number,const int series_index,const double value)
  {
   CBufferHistogram2 *buff=this.m_buffers.GetBufferHistogram2(number);
   if(buff==NULL)
      return;
   buff.SetData1(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set data of all histogram buffers on two buffers                 |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataHistogram2(const int number,const int series_index,const double value0,const double value1)
  {
   CBufferHistogram2 *buff=this.m_buffers.GetBufferHistogram2(number);
   if(buff==NULL)
      return;
   buff.SetData0(series_index,value0);
   buff.SetData1(series_index,value1);
  }
//+------------------------------------------------------------------+
//| Set zigzag zero buffer data                                      |
//| by its serial number                                             |
//| (0 - the very first zigzag buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataZigZag0(const int number,const int series_index,const double value)
  {
   CBufferZigZag *buff=this.m_buffers.GetBufferZigZag(number);
   if(buff==NULL)
      return;
   buff.SetData0(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set zigzag first buffer data                                     |
//| by its serial number                                             |
//| (0 - the very first zigzag buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataZigZag1(const int number,const int series_index,const double value)
  {
   CBufferZigZag *buff=this.m_buffers.GetBufferZigZag(number);
   if(buff==NULL)
      return;
   buff.SetData1(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set data of all zizag buffers                                    |
//| by its serial number                                             |
//| (0 - the very first zigzag buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataZigZag(const int number,const int series_index,const double value0,const double value1)
  {
   CBufferZigZag *buff=this.m_buffers.GetBufferZigZag(number);
   if(buff==NULL)
      return;
   buff.SetData0(series_index,value0);
   buff.SetData1(series_index,value1);
  }
//+------------------------------------------------------------------+
//| Set filling zero buffer data                                     |
//| by its serial number                                             |
//| (0 - the very first filling buffer, 1,2,N - subsequent ones)     |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataFilling0(const int number,const int series_index,const double value)
  {
   CBufferFilling *buff=this.m_buffers.GetBufferFilling(number);
   if(buff==NULL)
      return;
   buff.SetData0(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set filling first buffer data                                    |
//| by its serial number                                             |
//| (0 - the very first filling buffer, 1,2,N - subsequent ones)     |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataFilling1(const int number,const int series_index,const double value)
  {
   CBufferFilling *buff=this.m_buffers.GetBufferFilling(number);
   if(buff==NULL)
      return;
   buff.SetData1(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set data of all filling buffers                                  |
//| by its serial number                                             |
//| (0 - the very first filling buffer, 1,2,N - subsequent ones)     |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataFilling(const int number,const int series_index,const double value0,const double value1)
  {
   CBufferFilling *buff=this.m_buffers.GetBufferFilling(number);
   if(buff==NULL)
      return;
   buff.SetData0(series_index,value0);
   buff.SetData1(series_index,value1);
  }
//+------------------------------------------------------------------+
//| Set buffer data of Open bars                                     |
//| by its serial number                                             |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataBarsOpen(const int number,const int series_index,const double value)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   if(buff==NULL)
      return;
   buff.SetDataOpen(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set buffer data of High bars                                     |
//| by its serial number                                             |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataBarsHigh(const int number,const int series_index,const double value)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   if(buff==NULL)
      return;
   buff.SetDataHigh(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set buffer data of Low bars                                      |
//| by its serial number                                             |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataBarsLow(const int number,const int series_index,const double value)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   if(buff==NULL)
      return;
   buff.SetDataLow(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set buffer data of Close bars                                    |
//| by its serial number                                             |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataBarsClose(const int number,const int series_index,const double value)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   if(buff==NULL)
      return;
   buff.SetDataClose(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set buffer data of Open candles                                  |
//| by its serial number                                             |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataCandlesOpen(const int number,const int series_index,const double value)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   if(buff==NULL)
      return;
   buff.SetDataOpen(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set buffer data of High candles                                  |
//| by its serial number                                             |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataCandlesHigh(const int number,const int series_index,const double value)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   if(buff==NULL)
      return;
   buff.SetDataHigh(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set buffer data of Low candles                                   |
//| by its serial number                                             |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataCandlesLow(const int number,const int series_index,const double value)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   if(buff==NULL)
      return;
   buff.SetDataLow(series_index,value);
  }
//+------------------------------------------------------------------+
//| Set buffer data of Close candles                                 |
//| by its serial number                                             |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataCandlesClose(const int number,const int series_index,const double value)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   if(buff==NULL)
      return;
   buff.SetDataClose(series_index,value);
  }
//+------------------------------------------------------------------+

すべてのメソッドは同じです。時系列インデックスによる値を、シリアル番号によるCandles描画スタイルのバッファオブジェクトのCloseバッファに設定するメソッドを考えてみましょう。
バッファコレクションクラスのGetBufferCandles()メソッドを使用して、Candles描画スタイルのバッファオブジェクトをシリアル番号で取得します
オブジェクトの取得に失敗した場合は、メソッドを終了しますメソッドに渡された値を、取得した必要なバッファオブジェクトのCloseバッファに時系列インデックスで設定します

指定された時系列インデックスによってOHLC値をBarsおよびCandlesバッファオブジェクトのすべてのバッファに同時に設定する、さらに2つの個別のメソッドがあります。

//+------------------------------------------------------------------+
//| Set data of all bar buffers                                      |
//| by its serial number                                             |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataBars(const int number,const int series_index,const double open,const double high,const double low,const double close)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   if(buff==NULL)
      return;
   buff.SetDataOpen(series_index,open);
   buff.SetDataHigh(series_index,high);
   buff.SetDataLow(series_index,low);
   buff.SetDataClose(series_index,close);
  }
//+------------------------------------------------------------------+
//| Set data of all candle buffers                                   |
//| by its serial number                                             |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
void CEngine::BufferSetDataCandles(const int number,const int series_index,const double open,const double high,const double low,const double close)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   if(buff==NULL)
      return;
   buff.SetDataOpen(series_index,open);
   buff.SetDataHigh(series_index,high);
   buff.SetDataLow(series_index,low);
   buff.SetDataClose(series_index,close);
  }
//+------------------------------------------------------------------+

ここではすべて上記と同じです。ただし、4つのバッファオブジェクトバッファすべてのすべての値が渡され、メソッドに設定されます。

以下は、描画スタイルとシリアル番号によって、指定された色を特定のバッファオブジェクトのカラーバッファ時系列の指定されたインデックスに返すメソッドです。

//+------------------------------------------------------------------+
//| Return the arrow buffer color by its serial number               |
//| (0 - the very first arrow buffer, 1,2,N - subsequent ones)       |
//+------------------------------------------------------------------+
color CEngine::BufferColorArrow(const int number,const int series_index)
  {
   CBufferArrow *buff=this.m_buffers.GetBufferArrow(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+
//| Return the line buffer color by its serial number                |
//| (0 - the very first candle line, 1,2,N - subsequent ones)        |
//+------------------------------------------------------------------+
color CEngine::BufferColorLine(const int number,const int series_index)
  {
   CBufferLine *buff=this.m_buffers.GetBufferLine(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+
//| Return the section buffer color by its serial number             |
//| (0 - the very first sections buffer, 1,2,N - subsequent ones)    |
//+------------------------------------------------------------------+
color CEngine::BufferColorSection(const int number,const int series_index)
  {
   CBufferSection *buff=this.m_buffers.GetBufferSection(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+
//| Return histogram buffer color from zero                          |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
color CEngine::BufferColorHistogram(const int number,const int series_index)
  {
   CBufferHistogram *buff=this.m_buffers.GetBufferHistogram(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+
//| Return histogram buffer color on two buffers                     |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
color CEngine::BufferColorHistogram2(const int number,const int series_index)
  {
   CBufferHistogram2 *buff=this.m_buffers.GetBufferHistogram2(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+
//| Return the zigzag buffer color by its serial number              |
//| (0 - the very first zigzag buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
color CEngine::BufferColorZigZag(const int number,const int series_index)
  {
   CBufferZigZag *buff=this.m_buffers.GetBufferZigZag(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+
//| Return the filling buffer color by its serial number             |
//| (0 - the very first filling buffer, 1,2,N - subsequent ones)     |
//+------------------------------------------------------------------+
color CEngine::BufferColorFilling(const int number,const int series_index)
  {
   CBufferFilling *buff=this.m_buffers.GetBufferFilling(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+
//| Return the bar buffer color by its serial number                 |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
color CEngine::BufferColorBars(const int number,const int series_index)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+
//| Return the candle buffer color by its serial number              |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
color CEngine::BufferColorCandles(const int number,const int series_index)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   return(buff!=NULL ? buff.GetColorBufferValueColor(series_index) : clrNONE);
  }
//+------------------------------------------------------------------+

ここではすべてが似ています。必要なバッファオブジェクトをその番号で取得しますオブジェクトを取得できた場合は 指定された時系列インデックスでカラーバッファに設定された色を返しますその他の場合は、「色が未設定」を返します

(カラー値ではなく)カラーインデックス値は実際にはカラーバッファに設定されているため、特定のバッファオブジェクトのカラーインデックスを指定された時系列インデックスによってカラーバッファから返す適切なメソッドがあります。

//+------------------------------------------------------------------+
//| Return the arrow buffer color index by its serial number         |
//| (0 - the very first arrow buffer, 1,2,N - subsequent ones)       |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexArrow(const int number,const int series_index)
  {
   CBufferArrow *buff=this.m_buffers.GetBufferArrow(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Return the line buffer color index by its serial number          |
//| (0 - the very first candle line, 1,2,N - subsequent ones)        |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexLine(const int number,const int series_index)
  {
   CBufferLine *buff=this.m_buffers.GetBufferLine(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Return the section buffer color index by its serial number       |
//| (0 - the very first sections buffer, 1,2,N - subsequent ones)    |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexSection(const int number,const int series_index)
  {
   CBufferSection *buff=this.m_buffers.GetBufferSection(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Return histogram buffer color index from zero                    |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexHistogram(const int number,const int series_index)
  {
   CBufferHistogram *buff=this.m_buffers.GetBufferHistogram(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Return histogram buffer color index on two buffers               |
//| by its serial number                                             |
//| (0 - the very first buffer, 1,2,N - subsequent ones)             |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexHistogram2(const int number,const int series_index)
  {
   CBufferHistogram2 *buff=this.m_buffers.GetBufferHistogram2(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Return the zigzag buffer color index by its serial number        |
//| (0 - the very first zigzag buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexZigZag(const int number,const int series_index)
  {
   CBufferZigZag *buff=this.m_buffers.GetBufferZigZag(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Return the filling buffer color index by its serial number       |
//| (0 - the very first filling buffer, 1,2,N - subsequent ones)     |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexFilling(const int number,const int series_index)
  {
   CBufferFilling *buff=this.m_buffers.GetBufferFilling(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Return the bar buffer color index by its serial number           |
//| (0 - the very first bar buffer, 1,2,N - subsequent ones)         |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexBars(const int number,const int series_index)
  {
   CBufferBars *buff=this.m_buffers.GetBufferBars(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+
//| Return the candle buffer color index by its serial number        |
//| (0 - the very first candle buffer, 1,2,N - subsequent ones)      |
//+------------------------------------------------------------------+
int CEngine::BufferColorIndexCandles(const int number,const int series_index)
  {
   CBufferCandles *buff=this.m_buffers.GetBufferCandles(number);
   return(buff!=NULL ? buff.GetColorBufferValueIndex(series_index) : WRONG_VALUE);
  }
//+------------------------------------------------------------------+

ここでのすべては、メソッドがカラーインデックスを返すことを除いて、カラーを返すメソッドと同じです。

これらはすべて、指標バッファのコレクションクラスをテストするために必要なCEngineクラスの改善です。


バッファコレクションを使用して指標を作成する機能のテスト

バッファコレクションクラスをテストするために、前の記事の指標を使用して、新しいフォルダ\MQL5\Indicators\TestDoEasy\Part44\TestDoEasyPart44.mq5として保存します。

ヘッダ全体は次のようになります。

//+------------------------------------------------------------------+
//|                                             TestDoEasyPart44.mq5 |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                             https://mql5.com/en/users/artmedia70 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://mql5.com/en/users/artmedia70"
#property version   "1.00"
//--- includes
#include <DoEasy\Engine.mqh>
//--- properties
#property indicator_chart_window
#property indicator_buffers 28
#property indicator_plots   10

//--- classes

//--- enums

//--- defines

//--- structures

//--- input variables
/*sinput*/ ENUM_SYMBOLS_MODE  InpModeUsedSymbols=  SYMBOLS_MODE_CURRENT;            // Mode of used symbols list
/*sinput*/   string               InpUsedSymbols    =  "EURUSD,AUDUSD,EURAUD,EURGBP,EURCAD,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY";  // List of used symbols (comma - separator)
/*sinput*/   ENUM_TIMEFRAMES_MODE InpModeUsedTFs    =  TIMEFRAMES_MODE_CURRENT;            // Mode of used timeframes list
/*sinput*/   string               InpUsedTFs        =  "M1,M5,M15,M30,H1,H4,D1,W1,MN1"; // List of used timeframes (comma - separator)
sinput   ENUM_INPUT_YES_NO    InpDrawArrow      =  INPUT_YES;  // Draw Arrow
sinput   ENUM_INPUT_YES_NO    InpDrawLine       =  INPUT_NO;   // Draw Line
sinput   ENUM_INPUT_YES_NO    InpDrawSection    =  INPUT_NO;   // Draw Section
sinput   ENUM_INPUT_YES_NO    InpDrawHistogram  =  INPUT_NO;   // Draw Histogram
sinput   ENUM_INPUT_YES_NO    InpDrawHistogram2 =  INPUT_NO;   // Draw Histogram2
sinput   ENUM_INPUT_YES_NO    InpDrawZigZag     =  INPUT_NO;   // Draw ZigZag
sinput   ENUM_INPUT_YES_NO    InpDrawFilling    =  INPUT_NO;   // Draw Filling
sinput   ENUM_INPUT_YES_NO    InpDrawBars       =  INPUT_NO;   // Draw Bars
sinput   ENUM_INPUT_YES_NO    InpDrawCandles    =  INPUT_YES;  // Draw Candles
 
sinput   bool                 InpUseSounds      =  true; // Use sounds
//--- indicator buffers
CArrayObj     *list_buffers;                    // Pointer to the buffer object list
//--- global variables
CEngine        engine;                          // CEngine library main object
string         prefix;                          // Prefix of graphical object names
int            min_bars;                        // The minimum number of bars for the indicator calculation
int            used_symbols_mode;               // Mode of working with symbols
string         array_used_symbols[];            // The array for passing used symbols to the library
string         array_used_periods[];            // The array for passing used timeframes to the library
//+------------------------------------------------------------------+

すべてのバッファオブジェクトファイルのインクルードを「includes」ブロックから削除します。これらはすでにライブラリにインクルードされています。

//--- includes
#include <DoEasy\Engine.mqh>
#include <DoEasy\Objects\Indicators\BufferArrow.mqh>        // 1 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferLine.mqh>         // 1 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferSection.mqh>      // 1 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferHistogram.mqh>    // 1 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferHistogram2.mqh>   // 2 construction buffers + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferZigZag.mqh>       // 2 construction buffers + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferFilling.mqh>      // 2 construction buffers + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferBars.mqh>         // 4 construction buffer + 1 color buffer
#include <DoEasy\Objects\Indicators\BufferCandles.mqh>      // 4 construction buffer + 1 color buffer
//--- In total: 18 construction buffers + 9 color buffers:       27 indicator buffers, of which 9 are drawn ones
//--- properties

コンパイラの描画バッファとインジケータバッファの数を設定します。

#property indicator_buffers 28
#property indicator_plots   10

指標に複数のさまざまなバッファが予想される場合は、「指を数える」のではなく、初期段階で任意の値を設定するだけで済みます。指標を初めて起動すると、誤って指定した場合に備えて、描画されたバッファと指標バッファの有効な数を示すアラートが表示されます。

ライブラリは、作成された指標バッファに、作成順に描画スタイルと番号でアクセスすることを意味します。プログラムから直接バッファプロパティにアクセスすることはまだ実装されていません。これまでのところ、バッファ配列にアクセスすることしかできません。今日は、コレクションからバッファオブジェクトのリストを受け取り、リストから直接バッファにアクセスして(このような機能はすべてのオブジェクトコレクションに存在します)、作成されたオブジェクトを直接操作することで、この制限を回避します。したがって、CObjectオブジェクトへのポインタの動的配列を「指標バッファ」として使用しましょう。


OnInit()ハンドラで、テストに必要なバッファを準備し、2つの異なる方法でアクセスできるかどうかを確認します。

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Initialize DoEasy library
   OnInitDoEasy();

//--- Set indicator global variables
   prefix=engine.Name()+"_";
   //--- Get the index of the maximum used timeframe in the array,
   //--- calculate the number of bars of the current period fitting in the maximum used period
   //--- Use the obtained value if it exceeds 2, otherwise use 2
   int index=ArrayMaximum(ArrayUsedTimeframes);
   int num_bars=NumberBarsInTimeframe(ArrayUsedTimeframes[index]);
   min_bars=(index>WRONG_VALUE ? (num_bars>2 ? num_bars : 2) : 2);

//--- Check and remove remaining indicator graphical objects
   if(IsPresentObectByPrefix(prefix))
      ObjectsDeleteAll(0,prefix);

//--- Create the button panel

//--- Check playing a standard sound using macro substitutions
   engine.PlaySoundByDescription(SND_OK);
//--- Wait for 600 milliseconds
   engine.Pause(600);
   engine.PlaySoundByDescription(SND_NEWS);

//--- indicator buffers mapping
//--- Create all the necessary buffer objects
   engine.BufferCreateArrow();
   engine.BufferCreateLine();
   engine.BufferCreateSection();
   engine.BufferCreateHistogram();
   engine.BufferCreateHistogram2();
   engine.BufferCreateZigZag();
   engine.BufferCreateFilling();
   engine.BufferCreateBars();
   engine.BufferCreateCandles();
   engine.BufferCreateArrow();
   
//--- Check the number of buffers specified in the 'properties' block
   if(engine.BufferPlotsTotal()!=indicator_plots)
      Alert(TextByLanguage("Внимание! Значение \"indicator_plots\" должно быть ","Attention! Value of \"indicator_plots\" should be "),engine.BufferPlotsTotal());
   if(engine.BuffersTotal()!=indicator_buffers)
      Alert(TextByLanguage("Внимание! Значение \"indicator_buffers\" должно быть ","Attention! Value of \"indicator_buffers\" should be "),engine.BuffersTotal());
      
//--- Create color array
   color array_colors[]={clrDodgerBlue,clrRed,clrGray};
//--- Get the pointer to the collection list of buffer objects and
//--- set non-default color values for buffers in a loop according to the list
   list_buffers=engine.GetListBuffers();
   for(int i=0;i<list_buffers.Total();i++)
     {
      CBuffer *buff=list_buffers.At(i);
      buff.SetColors(array_colors);
      //--- Print data on the next buffer
      buff.Print();
     }
//--- Set the line width for ZigZag (the sixth drawn buffer)
//--- It has the index of 5 considering that the starting point is zero
   CBuffer *buff_zz=engine.GetBufferByPlot(5);
   if(buff_zz!=NULL)
     {
      buff_zz.SetWidth(2);
     }
//--- Get the second arrow buffer (created last).
//--- The first arrow buffer has the number of 0, while the second one has the number of 1
//--- Set the arrow size of 2 and the code of 161
   CBuffer *buff=engine.GetBufferArrow(1);
   if(buff!=NULL)
     {
      buff.SetWidth(2);
      buff.SetArrowCode(161);
     }
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+

バッファの作成が簡単になりましたあるタイプまたは別のタイプの指標バッファを作成するように設計されたライブラリメソッドを使用します。ライブラリはすべての配列関数を引き継ぎ、作成されたバッファのプロパティを作成後に変更できます。すぐに指標ヘッダの#propertyで指定された数のバッファを確認します。バッファ数の指定を間違えた場合は、適切な警告が表示されます。このようなチェックは、指標を開発するときに便利です。その後、コードから削除できます。

バッファへのアクセスをテストするために2つのメソッドを使用してみましょう。
まず、GetBufferByPlot()メソッドを使用して、描画されたバッファインデックスによってジグザグバッファにアクセスします。このメソッドでは、描画されたバッファインデックスが指定されます(ここではインデックスです)。ジグザグの場合は5)、
次に、最後に作成された最後の矢印バッファにアクセスします。それは2番目の矢印バッファですGetBufferArrow()メソッドを使用してアクセスしましょう。このメソッドでは、必要な矢印バッファのシリアル番号を指定します(ここでは、カウントはゼロから始まるため、番号は1です)。

OnCalculate()ハンドラは、データがローソク足バッファオブジェクトメソッドを使用してキャンドルバッファとバーバッファに設定されることを除いて、ほとんど変更されていません(データを1つずつOpen、High、Low、およびCloseに書き込みます)。また、すべてのOHLC値を一度にバーバッファ配列に書き込みます。したがって、バッファオブジェクトを操作するために作成されたすべてのメソッドの動作を確認できます。

//--- Calculate the indicator
   for(int i=limit; i>WRONG_VALUE && !IsStopped(); i--)
     {
      //--- In a loop by the number of buffers in the list
      for(int j=0;j<total;j++)
        {
         //--- get the next buffer and
         CBuffer *buff=list_buffers.At(j);
         //--- clear its current data
         buff.ClearData(0);
         //--- If drawing is not used, move on to the next one
         if(!IsUse(buff.Status()))
            continue;
         //--- Depending on the number of buffers, fill them with price data
         //--- one buffer
         if(buff.BuffersTotal()==1)
            buff.SetBufferValue(0,i,close[i]);
         //--- two buffers - the first one is to store the bar open price, while the second one is to store the bar close price
         else if(buff.BuffersTotal()==2)
           {
            buff.SetBufferValue(0,i,open[i]);
            buff.SetBufferValue(1,i,close[i]);
           }
         //--- four buffers - each buffer is to store OHLC bar prices
         else if(buff.BuffersTotal()==4)
           {
            //--- If this is the candle buffer
            if(buff.Status()==BUFFER_STATUS_CANDLES)
              {
               //--- create the pointer to the candle buffer object by assigning the pointer to the abstract buffer object to it
               //--- and write the appropriate timeseries data to the "candle" object buffers
               CBufferCandles *candle=buff;
               candle.SetDataOpen(i,open[i]);
               candle.SetDataHigh(i,high[i]);
               candle.SetDataLow(i,low[i]);
               candle.SetDataClose(i,close[i]);
              }
            //--- If this is the bar buffer, use access to the first (and only) created bar buffer object
            //--- and write the appropriate timeseries data to the "bars" object buffers in one go
            else
              {
               engine.BufferSetDataBars(0,i,open[i],high[i],low[i],close[i]);
              }
           }
         //--- Set the buffer color depending on the candle direction
         if(open[i]<close[i])
            buff.SetBufferColorIndex(i,0);
         else if(open[i]>close[i])
            buff.SetBufferColorIndex(i,1);
         else
            buff.SetBufferColorIndex(i,2);
        }
     }
//--- return value of prev_calculated for next call

完全な指標コードは、以下に添付されているファイルで提供されます。

指標をコンパイルして、銘柄チャートで起動します。設定で単一の矢印バッファを表示するように設定します。このバッファは、チャート上にドットとして表示されます。ただし、最後に作成された2番目の矢印バッファもあります。OnInit()の2番目の矢印バッファにアクセスして、コードとアイコンのサイズを変更しました。したがって、バッファオブジェクトを操作するために作成されたすべてのメソッドの動作を確認できます。

//--- Get the second arrow buffer (created last).
//--- The first arrow buffer has the number of 0, while the second one has the number of 1
//--- Set the arrow size of 2 and the code of 161
   CBuffer *buff=engine.GetBufferArrow(1);
   if(buff!=NULL)
     {
      buff.SetWidth(2);
      buff.SetArrowCode(161);
     }

特定のバッファタイプに番号でアクセスしてオブジェクトを取得できた場合、2つの矢印バッファがグラフに表示されます。最初のバッファはドットで表示され、2番目のバッファはサイズが2の円で表示されます。

Plotインデックスでバッファオブジェクトを返すメソッドを使用してジグザグバッファを受信することにより、ジグザグ線幅を設定しました。ジグザグ表示を接続し、その線幅がOnInit()で設定された線幅に対応していることを確認します。

//--- Set the line width for ZigZag (the sixth drawn buffer)
//--- It has the index of 5 considering that the starting point is zero
   CBuffer *buff_zz=engine.GetBufferByPlot(5);
   if(buff_zz!=NULL)
     {
      buff_zz.SetWidth(2);
     }

最後に、バーとローソク足がどのように表示されるかを見てみましょう。バッファ配列に価格値を書き込むメソッドが機能する場合は、バーとローソク足がチャートに正しく表示されるはずです。

確認しましょう。


ご覧のとおり、すべてが想定どおりに機能します。


次の段階

次の記事では、複数銘柄モードと複数期間モードでの指標操作の配置に関して、指標バッファコレクションクラスの開発を継続します。

現在のバージョンのライブラリのすべてのファイルは、テスト用EAファイルと一緒に以下に添付されているので、テストするにはダウンロードしてください。
質問、コメント、提案はコメント欄にお願いします。テスト指標はMQL5向けに開発されたのでご注意ください
添付ファイルはMetaTrader 5のみを対象としています。現在のライブラリバージョンはMetaTrader 4ではテストされていません。
指標バッファコレクションを作成してテストした後で、MetaTrader 4にいくつかのMQL5機能を実装してみます。

目次に戻る

シリーズのこれまでの記事:

DoEasyライブラリの時系列(第35部): バーオブジェクトと銘柄の時系列リスト
DoEasyライブラリの時系列(第36部): すべての使用銘柄期間の時系列オブジェクト
DoEasyライブラリの時系列(第37部): すべての使用銘柄期間の時系列オブジェクト
DoEasyライブラリの時系列(第38部): 時系列コレクション-リアルタイムの更新とプログラムからのデータへのアクセス
DoEasyライブラリの時系列(第39部): ライブラリに基づいた指標 - データイベントと時系列イベントの準備
DoEasyライブラリの時系列(第40部): ライブラリに基づいた指標 - 実時間でのデータ更新
DoEasyライブラリの時系列(第41部): 複数銘柄・複数期間指標の例
DoEasyライブラリの時系列(第42部): 抽象指標バッファオブジェクトクラス
DoEasyライブラリの時系列(第43部): 指標バッファオブジェクトクラス