![DoEasyライブラリの時系列(第35部): バーオブジェクトと銘柄の時系列リスト](https://c.mql5.com/i/articles/overlay.png)
DoEasyライブラリの時系列(第35部): バーオブジェクトと銘柄の時系列リスト
内容
本稿は、MetaTrader 5および4ターミナル用のプログラムを簡単に開発するためのライブラリの説明に関する新しいセクションの始まりとなります。初めのセクション(34稿)ではライブラリオブジェクトとその相互接続の概念に専念しました。この概念は、口座の現在のステータスと履歴を操作するための機能を開発するために使用されました。
現在、ライブラリには次の機能があります。
- 任意の注文またはポジションのデータの検索、並べ替え、比較をおこなう
- 注文およびポジションのプロパティへの迅速で便利なアクセスを提供する
- 口座イベントを追跡する
- 口座および銘柄データを取得および比較する
- データベース(コレクション)内のすべての既存オブジェクトのプロパティ変更に応答し、発生したイベントの通知をプログラムに送信する
また、ライブラリが応答する必要のあるイベントをライブラリに通知したり、監視対象イベントに関する通知を送信したりすることもできます。
さらに、ターミナル取引機能と連携する機能を実装しました。また、新しいタイプの取引リクエストも作成しました。保留中取引リクエストにより、さまざまな取引条件でプログラムの動作ロジックを作成したり、新しいタイプの未決注文を作成するための機能一式を提供したりできます。
以前のセクションでは、これらすべておよびその他の多くのものが作成され、説明されました。
この2番目のセクションでは、価格データ、銘柄チャート、市場深度、指標などを操作する多くの側面を考慮しています。一般的に、今回の連載では、価格データ配列およびそれらのストレージオブジェクトとソースへの迅速なアクセス、検索、比較、並び替えのためのライブラリ機能の開発に当てられます。
概念
ライブラリオブジェクトの配置、格納、およびそれらの操作の概念については、前回の連載の最初の記事で詳しく説明しました。本稿では、ライブラリオブジェクトの配置と格納の基本原則を簡単に繰り返します。
同じ型のデータのセットは、このデータ型に固有の同一のプロパティを持つオブジェクトのリストとして表すことができます。同じ型のデータのオブジェクトのリストからの各オブジェクトは同様のプロパティセットを備えていますが、同じ並び替え済みリストの各オブジェクトは異なる値を持っています。
同じ型のオブジェクトのセットを格納する各リストは、リストオブジェクトが持つ任意のプロパティで並び替えできます。オブジェクトプロパティには、整数、実数、文字列の3つの主要な型があります。
このようなオブジェクトを並べ替え済みリストで並べ替えることにより、オブジェクトをすばやく見つけ、そこからデータを取得して、カスタムプログラムで使用することができます。ほとんどすべてのライブラリオブジェクトは、独自のプロパティを個別に追跡できます。つまり、関心のある各オブジェクトに設定できる特定の量だけ値を変更します。オブジェクトのプロパティが指定された値によって変更されると、追跡されたオブジェクトは、追跡用に設定された閾値に達したことを通知するメッセージを制御プログラムに送信します。
すべてのライブラリオブジェクトの基本は、取引プラットフォームで提供される基本標準ライブラリオブジェクトですが、オブジェクトリスト(オブジェクトコレクション)は、CObjectクラスインスタンスへのポインタの動的配列とその標準ライブラリの子孫です。
本稿ではバーオブジェクトを作成し、銘柄チャートの単一のバーに固有のデータ全体と、単一の銘柄と時間枠のすべてのバーオブジェクトのリストを格納します。
銘柄チャートの各バーには、MqlRates構造体で説明されている特定のパラメータセットがあります。
- 期間開始時
- 始値
- 期間の最高値
- 期間の最安値
- 終値
- ティックボリューム
- スプレッド
- ボリューム
バーオブジェクトの主要プロパティとは別に、オブジェクトの作成時には追加のプロパティを設定できます。
- バーが属する年
- バーが属する月
- バーが属する日
- 年でのバーのシリアル番号
- 日(数)
- バーの時間
- バーの分
- 銘柄時系列でのバーインデックス
- バーサイズ(High~Low)
- ローソク足実体の上限(Max(Open,Close))
- ローソク足実体の下限(Min(Open,Close)).
- ローソク足実体サイズ(上限~下限)
- ローソク足上髭(High~ローソク足実体の上限)
- ローソク足下髭(ローソク足実体の下限~Low)
これらすべてのプロパティにより、範囲内のバーとローソク足(バーリストに格納)の任意の組み合わせを探すことができます。保存するデータの目的の範囲は、バーオブジェクトのリストに設定できます。デフォルトでは、リストに1000本のバー(または、利用可能な履歴全体が1000本またはその他の指定された範囲未満の場合は利用可能な履歴全体)を保存します。
バーオブジェクト
すべてのバーオブジェクトプロパティの列挙を作成してみましょう。これには、\MQL5\Include\DoEasy\Defines.mqhファイルを開いて、バーオブジェクトのバータイプ、整数、 実数、文字列プロパティの列挙とバーオブジェクトリストを並び替えるメソッドをファイル末尾に追加します。
//+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Info for working with serial data | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Bar type (candle body) | //+------------------------------------------------------------------+ enum ENUM_BAR_BODY_TYPE { BAR_BODY_TYPE_BULLISH, // Bullish bar BAR_BODY_TYPE_BEARISH, // Bearish bar BAR_BODY_TYPE_NULL, // Zero bar BAR_BODY_TYPE_CANDLE_ZERO_BODY, // Candle with a zero body }; //+------------------------------------------------------------------+ //| Bar integer properties | //+------------------------------------------------------------------+ enum ENUM_BAR_PROP_INTEGER { BAR_PROP_INDEX = 0, // Bar index in timeseries BAR_PROP_TYPE, // Bar type (from the ENUM_BAR_BODY_TYPE enumeration) BAR_PROP_PERIOD, // Bar period (timeframe) BAR_PROP_SPREAD, // Bar spread BAR_PROP_VOLUME_TICK, // Bar tick volume BAR_PROP_VOLUME_REAL, // Bar exchange volume BAR_PROP_TIME, // Bar period start time BAR_PROP_TIME_DAY_OF_YEAR, // Bar day serial number in a year BAR_PROP_TIME_YEAR, // A year the bar belongs to BAR_PROP_TIME_MONTH, // A month the bar belongs to BAR_PROP_TIME_DAY_OF_WEEK, // Bar week day BAR_PROP_TIME_DAY, // Bar day of month (number) BAR_PROP_TIME_HOUR, // Bar hour BAR_PROP_TIME_MINUTE, // Bar minute }; #define BAR_PROP_INTEGER_TOTAL (14) // Total number of integer bar properties #define BAR_PROP_INTEGER_SKIP (0) // Number of bar properties not used in sorting //+------------------------------------------------------------------+ //| Real bar properties | //+------------------------------------------------------------------+ enum ENUM_BAR_PROP_DOUBLE { //--- bar data BAR_PROP_OPEN = BAR_PROP_INTEGER_TOTAL, // Bar open price BAR_PROP_HIGH, // Highest price for the bar period BAR_PROP_LOW, // Lowest price for the bar period BAR_PROP_CLOSE, // Bar close price //--- candle data BAR_PROP_CANDLE_SIZE, // Candle size BAR_PROP_CANDLE_SIZE_BODY, // Candle body size BAR_PROP_CANDLE_BODY_TOP, // Candle body top BAR_PROP_CANDLE_BODY_BOTTOM, // Candle body bottom BAR_PROP_CANDLE_SIZE_SHADOW_UP, // Candle upper wick size BAR_PROP_CANDLE_SIZE_SHADOW_DOWN, // Candle lower wick size }; #define BAR_PROP_DOUBLE_TOTAL (10) // Total number of real bar properties #define BAR_PROP_DOUBLE_SKIP (0) // Number of bar properties not used in sorting //+------------------------------------------------------------------+ //| Bar string properties | //+------------------------------------------------------------------+ enum ENUM_BAR_PROP_STRING { BAR_PROP_SYMBOL = (BAR_PROP_INTEGER_TOTAL+BAR_PROP_DOUBLE_TOTAL), // Bar symbol }; #define BAR_PROP_STRING_TOTAL (1) // Total number of string bar properties //+------------------------------------------------------------------+ //| Possible bar sorting criteria | //+------------------------------------------------------------------+ #define FIRST_BAR_DBL_PROP (BAR_PROP_INTEGER_TOTAL-BAR_PROP_INTEGER_SKIP) #define FIRST_BAR_STR_PROP (BAR_PROP_INTEGER_TOTAL-BAR_PROP_INTEGER_SKIP+BAR_PROP_DOUBLE_TOTAL-BAR_PROP_DOUBLE_SKIP) enum ENUM_SORT_BAR_MODE { //--- Sort by integer properties SORT_BY_BAR_INDEX = 0, // Sort by bar index SORT_BY_BAR_TYPE, // Sort by bar type (from the ENUM_BAR_BODY_TYPE enumeration) SORT_BY_BAR_PERIOD, // Sort by bar period (timeframe) SORT_BY_BAR_SPREAD, // Sort by bar spread SORT_BY_BAR_VOLUME_TICK, // Sort by bar tick volume SORT_BY_BAR_VOLUME_REAL, // Sort by bar exchange volume SORT_BY_BAR_TIME, // Sort by bar period start time SORT_BY_BAR_TIME_DAY_OF_YEAR, // Sort by bar day number in a year SORT_BY_BAR_TIME_YEAR, // Sort by a year the bar belongs to SORT_BY_BAR_TIME_MONTH, // Sort by a month the bar belongs to SORT_BY_BAR_TIME_DAY_OF_WEEK, // Sort by a bar week day SORT_BY_BAR_TIME_DAY, // Sort by a bar day SORT_BY_BAR_TIME_HOUR, // Sort by a bar hour SORT_BY_BAR_TIME_MINUTE, // Sort by a bar minute //--- Sort by real properties SORT_BY_BAR_OPEN = FIRST_BAR_DBL_PROP, // Sort by bar open price SORT_BY_BAR_HIGH, // Sort by the highest price for the bar period SORT_BY_BAR_LOW, // Sort by the lowest price for the bar period SORT_BY_BAR_CLOSE, // Sort by a bar close price SORT_BY_BAR_CANDLE_SIZE, // Sort by a candle price SORT_BY_BAR_CANDLE_SIZE_BODY, // Sort by a candle body size SORT_BY_BAR_CANDLE_BODY_TOP, // Sort by a candle body top SORT_BY_BAR_CANDLE_BODY_BOTTOM, // Sort by a candle body bottom SORT_BY_BAR_CANDLE_SIZE_SHADOW_UP, // Sort by candle upper wick size SORT_BY_BAR_CANDLE_SIZE_SHADOW_DOWN, // Sort by candle lower wick size //--- Sort by string properties SORT_BY_BAR_SYMBOL = FIRST_BAR_STR_PROP, // Sort by a bar symbol }; //+------------------------------------------------------------------+
バータイプは強気、弱気、ゼロのいずれかです。ローソク足の実体サイズはさまざまなローソク足の形成を定義するために使用されるパラメータの1つであるため、ローソク足の実体タイプを設定するためには別のバータイププロパティが使用されます。したがって、実体のサイズがゼロであるローソク足とゼロバーは同等であると見なすべきではありません。ゼロバーでは4つのOHLC価格すべてに対して1つの価格しかありませんが、実体のサイズがゼロであるローソク足には髭がある場合があり、ローソク足の形成を定義するときに位置と髭サイズが考慮されます。
バーのプロパティやその他のライブラリメッセージの説明を表示するには、新しいテキストメッセージが必要です。
\MQL5\Include\DoEasy\Datas.mqhファイルは新しいメッセージのインデックスを受け取ります。
MSG_LIB_SYS_ERROR_CODE_OUT_OF_RANGE, // Return code out of range of error codes MSG_LIB_SYS_FAILED_CREATE_PAUSE_OBJ, // Failed to create the \"Pause\" object MSG_LIB_SYS_FAILED_CREATE_BAR_OBJ, // Failed to create the \"Bar\" object MSG_LIB_SYS_FAILED_SYNC_DATA, // Failed to synchronize data with the server
...
MSG_LIB_TEXT_TIME_UNTIL_THE_END_DAY, // Order lifetime till the end of the current day to be used MSG_LIB_TEXT_JANUARY, // January MSG_LIB_TEXT_FEBRUARY, // February MSG_LIB_TEXT_MARCH, // March MSG_LIB_TEXT_APRIL, // April MSG_LIB_TEXT_MAY, // May MSG_LIB_TEXT_JUNE, // June MSG_LIB_TEXT_JULY, // July MSG_LIB_TEXT_AUGUST, // August MSG_LIB_TEXT_SEPTEMBER, // September MSG_LIB_TEXT_OCTOBER, // October MSG_LIB_TEXT_NOVEMBER, // November MSG_LIB_TEXT_DECEMBER, // December MSG_LIB_TEXT_SUNDAY, // Sunday
...
MSG_LIB_TEXT_PEND_REQUEST_ADD_CRITERIONS, // Added pending request activation conditions //--- CBar MSG_LIB_TEXT_BAR_FAILED_GET_BAR_DATA, // Failed to receive bar data MSG_LIB_TEXT_BAR_FAILED_GET_SERIES_DATA, // Failed to receive timeseries data MSG_LIB_TEXT_BAR_FAILED_ADD_TO_LIST, // Could not add bar object to the list MSG_LIB_TEXT_BAR, // Bar MSG_LIB_TEXT_BAR_PERIOD, // Timeframe MSG_LIB_TEXT_BAR_SPREAD, // Spread MSG_LIB_TEXT_BAR_VOLUME_TICK, // Tick volume MSG_LIB_TEXT_BAR_VOLUME_REAL, // Exchange volume MSG_LIB_TEXT_BAR_TIME, // Period start time MSG_LIB_TEXT_BAR_TIME_YEAR, // Year MSG_LIB_TEXT_BAR_TIME_MONTH, // Month MSG_LIB_TEXT_BAR_TIME_DAY_OF_YEAR, // Day serial number in a year MSG_LIB_TEXT_BAR_TIME_DAY_OF_WEEK, // Week day MSG_LIB_TEXT_BAR_TIME_DAY, // Two months MSG_LIB_TEXT_BAR_TIME_HOUR, // Hour MSG_LIB_TEXT_BAR_TIME_MINUTE, // Minute MSG_LIB_TEXT_BAR_INDEX, // Index in timeseries MSG_LIB_TEXT_BAR_HIGH, // Highest price for the period MSG_LIB_TEXT_BAR_LOW, // Lowest price for the period MSG_LIB_TEXT_BAR_CANDLE_SIZE, // Candle size MSG_LIB_TEXT_BAR_CANDLE_SIZE_BODY, // Candle body size MSG_LIB_TEXT_BAR_CANDLE_SIZE_SHADOW_UP, // Candle upper wick size MSG_LIB_TEXT_BAR_CANDLE_SIZE_SHADOW_DOWN, // Candle lower wick size MSG_LIB_TEXT_BAR_CANDLE_BODY_TOP, // Candle body top MSG_LIB_TEXT_BAR_CANDLE_BODY_BOTTOM, // Candle body bottom MSG_LIB_TEXT_BAR_TYPE_BULLISH, // Bullish bar MSG_LIB_TEXT_BAR_TYPE_BEARISH, // Bearish bar MSG_LIB_TEXT_BAR_TYPE_NULL, // Zero bar MSG_LIB_TEXT_BAR_TYPE_CANDLE_ZERO_BODY, // Candle with a zero body MSG_LIB_TEXT_BAR_TEXT_FIRS_SET_AMOUNT_DATA, // First, we need to set the required amount of data using SetAmountUsedData() }; //+------------------------------------------------------------------+
また、新しく追加されたインデックスに対応するテキストも受け取りします。
{"Код возврата вне заданного диапазона кодов ошибок","Out of range of error codes return code"}, {"Не удалось создать объект \"Пауза\"","Failed to create \"Pause\" object"}, {"Не удалось создать объект \"Бар\"","Failed to create \"Bar\" object"}, {"Не удалось синхронизировать данные с сервером","Failed to sync data with server"},
...
{"Будет использоваться время действия ордера до конца текущего дня","Order validity time until the end of the current day will be used"}, {"Январь","January"}, {"Февраль","February"}, {"Март","March"}, {"Апрель","April"}, {"Май","May"}, {"Июнь","June"}, {"Июль","July"}, {"Август","August"}, {"Сентябрь","September"}, {"Октябрь","October"}, {"Ноябрь","November"}, {"Декабрь","December"}, {"Воскресение","Sunday"},
...
{"Добавлены условия активации отложенного запроса","Pending request activation conditions added"}, {"Не удалось получить данные бара","Failed to get bar data"}, {"Не удалось получить данные таймсерии","Failed to get timeseries data"}, {"Не удалось добавить объект-бар в список","Failed to add bar object to list"}, {"Бар","Bar"}, {"Таймфрейм","Timeframe"}, {"Спред","Spread"}, {"Тиковый объём","Tick volume"}, {"Биржевой объём","Real volume"}, {"Время начала периода","Period start time"}, {"Год","Year"}, {"Месяц","Month"}, {"Порядковый номер дня в году","Sequence day number in a year"}, {"День недели","Day of week"}, {"День месяца","Day of month"}, {"Час","Hour"}, {"Минута","Minute"}, {"Индекс в таймсерии","Timeseries index"}, {"Наивысшая цена за период","Highest price for the period"}, {"Наименьшая цена за период","Lowest price for the period"}, {"Размер свечи","Candle size"}, {"Размер тела свечи","Candle body size"}, {"Размер верхней тени свечи","Candle upper shadow size"}, {"Размер нижней тени свечи","Candle lower shadow size"}, {"Верх тела свечи","Top of candle body"}, {"Низ тела свечи","Bottom of candle body"}, {"Бычий бар","Bullish bar"}, {"Медвежий бар","Bearish bar"}, {"Нулевой бар","Zero bar"}, {"Свеча с нулевым телом","Candle with zero body"}, {"Сначала нужно установить требуемое количество данных при помощи SetAmountUsedData()","First you need to set required amount of data using SetAmountUsedData()"}, }; //+---------------------------------------------------------------------+
\MQL5\Include\DoEasy\Services\DELib.mqhサービス関数ファイルは、月の名前を返す関数と時間枠の説明を返す関数を受け取ります。
//+------------------------------------------------------------------+ //| Return month names | //+------------------------------------------------------------------+ string MonthDescription(const int month) { return ( month==1 ? CMessage::Text(MSG_LIB_TEXT_JANUARY) : month==2 ? CMessage::Text(MSG_LIB_TEXT_FEBRUARY) : month==3 ? CMessage::Text(MSG_LIB_TEXT_MARCH) : month==4 ? CMessage::Text(MSG_LIB_TEXT_APRIL) : month==5 ? CMessage::Text(MSG_LIB_TEXT_MAY) : month==6 ? CMessage::Text(MSG_LIB_TEXT_JUNE) : month==7 ? CMessage::Text(MSG_LIB_TEXT_JULY) : month==8 ? CMessage::Text(MSG_LIB_TEXT_AUGUST) : month==9 ? CMessage::Text(MSG_LIB_TEXT_SEPTEMBER) : month==10 ? CMessage::Text(MSG_LIB_TEXT_OCTOBER) : month==11 ? CMessage::Text(MSG_LIB_TEXT_NOVEMBER) : month==12 ? CMessage::Text(MSG_LIB_TEXT_DECEMBER) : (string)month ); } //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Return timeframe description | //+------------------------------------------------------------------+ string TimeframeDescription(const ENUM_TIMEFRAMES timeframe) { return StringSubstr(EnumToString(timeframe),7); } //+------------------------------------------------------------------+
月の名前を返す関数は月の番号を受け取り、そのテキストの説明はそれに従って返されます。
時間枠名を返す関数は時間枠を受け取ります。次に、時間枠の列挙値のテキスト表現を使用して、位置7から文字列の終わりまでの部分文字列を取得します。得られた結果をテキストとして返します。たとえば、H1の値は、PERIOD_H1時間の時間枠のテキスト表現から取得されます。
バーオブジェクトクラスを保存するには、ライブラリのオブジェクトカタログ(\MQL5\Include\DoEasy\Objects\)に新しいフォルダを作成します(\MQL5\Include\DoEasy\Objects\Series\)。次に、この新しいフォルダにCBarクラスのBar.mqhファイルを作成します。
クラス本体のリストとそのメソッドの実装について考えてみましょう。
//+------------------------------------------------------------------+ //| Bar.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\DELib.mqh" //+------------------------------------------------------------------+ //| bar class | //+------------------------------------------------------------------+ class CBar : public CObject { private: MqlDateTime m_dt_struct; // Date structure int m_digits; // Symbol's digits value string m_period_description; // Timeframe string description long m_long_prop[BAR_PROP_INTEGER_TOTAL]; // Integer properties double m_double_prop[BAR_PROP_DOUBLE_TOTAL]; // Real properties string m_string_prop[BAR_PROP_STRING_TOTAL]; // String properties //--- Return the index of the array the bar's (1) double and (2) string properties are located at int IndexProp(ENUM_BAR_PROP_DOUBLE property) const { return(int)property-BAR_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_BAR_PROP_STRING property) const { return(int)property-BAR_PROP_INTEGER_TOTAL-BAR_PROP_DOUBLE_TOTAL; } //--- Return the bar type (bullish/bearish/zero) ENUM_BAR_BODY_TYPE BodyType(void) const; //--- Calculate and return the size of (1) candle, (2) candle body, //--- (3) upper, (4) lower candle wick, //--- (5) candle body top and (6) bottom double CandleSize(void) const { return(this.High()-this.Low()); } double BodySize(void) const { return(this.BodyHigh()-this.BodyLow()); } double ShadowUpSize(void) const { return(this.High()-this.BodyHigh()); } double ShadowDownSize(void) const { return(this.BodyLow()-this.Low()); } double BodyHigh(void) const { return ::fmax(this.Close(),this.Open()); } double BodyLow(void) const { return ::fmin(this.Close(),this.Open()); } //--- Return the (1) year and (2) month the bar belongs to, (3) week day, //--- (4) bar serial number in a year, (5) day, (6) hour, (7) minute, int TimeYear(void) const { return this.m_dt_struct.year; } int TimeMonth(void) const { return this.m_dt_struct.mon; } int TimeDayOfWeek(void) const { return this.m_dt_struct.day_of_week; } int TimeDayOfYear(void) const { return this.m_dt_struct.day_of_year; } int TimeDay(void) const { return this.m_dt_struct.day; } int TimeHour(void) const { return this.m_dt_struct.hour; } int TimeMinute(void) const { return this.m_dt_struct.min; } public: //--- Set bar's (1) integer, (2) real and (3) string properties void SetProperty(ENUM_BAR_PROP_INTEGER property,long value) { this.m_long_prop[property]=value; } void SetProperty(ENUM_BAR_PROP_DOUBLE property,double value){ this.m_double_prop[this.IndexProp(property)]=value; } void SetProperty(ENUM_BAR_PROP_STRING property,string value){ this.m_string_prop[this.IndexProp(property)]=value; } //--- Return (1) integer, (2) real and (3) string bar properties from the properties array long GetProperty(ENUM_BAR_PROP_INTEGER property) const { return this.m_long_prop[property]; } double GetProperty(ENUM_BAR_PROP_DOUBLE property) const { return this.m_double_prop[this.IndexProp(property)]; } string GetProperty(ENUM_BAR_PROP_STRING property) const { return this.m_string_prop[this.IndexProp(property)]; } //--- Return the flag of the bar supporting the property virtual bool SupportProperty(ENUM_BAR_PROP_INTEGER property) { return true; } virtual bool SupportProperty(ENUM_BAR_PROP_DOUBLE property) { return true; } virtual bool SupportProperty(ENUM_BAR_PROP_STRING property) { return true; } //--- Return itself CBar *GetObject(void) { return &this;} //--- Set (1) bar symbol, timeframe and index, (2) bar object parameters void SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe,const int index); void SetProperties(const MqlRates &rates); //--- Compare CBar objects by all possible properties (for sorting the lists by a specified bar object property) virtual int Compare(const CObject *node,const int mode=0) const; //--- Compare CBar objects by all properties (to search for equal bar objects) bool IsEqual(CBar* compared_bar) const; //--- Constructors CBar(){;} CBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const int index); CBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const int index,const MqlRates &rates); //+------------------------------------------------------------------+ //| Methods of a simplified access to the order object properties | //+------------------------------------------------------------------+ //--- Return the (1) type, (2) period, (3) spread, (4) tick, (5) exchange volume, //--- (6) bar period start time, (7) year, (8) month the bar belongs to //--- (9) week number since the year start, (10) week number since the month start //--- (11) bar's day, (12) hour, (13) minute, (14) index ENUM_BAR_BODY_TYPE TypeBody(void) const { return (ENUM_BAR_BODY_TYPE)this.GetProperty(BAR_PROP_TYPE); } ENUM_TIMEFRAMES Period(void) const { return (ENUM_TIMEFRAMES)this.GetProperty(BAR_PROP_PERIOD); } int Spread(void) const { return (int)this.GetProperty(BAR_PROP_SPREAD); } long VolumeTick(void) const { return this.GetProperty(BAR_PROP_VOLUME_TICK); } long VolumeReal(void) const { return this.GetProperty(BAR_PROP_VOLUME_REAL); } datetime Time(void) const { return (datetime)this.GetProperty(BAR_PROP_TIME); } long Year(void) const { return this.GetProperty(BAR_PROP_TIME_YEAR); } long Month(void) const { return this.GetProperty(BAR_PROP_TIME_MONTH); } long DayOfWeek(void) const { return this.GetProperty(BAR_PROP_TIME_DAY_OF_WEEK); } long DayOfYear(void) const { return this.GetProperty(BAR_PROP_TIME_DAY_OF_YEAR); } long Day(void) const { return this.GetProperty(BAR_PROP_TIME_DAY); } long Hour(void) const { return this.GetProperty(BAR_PROP_TIME_HOUR); } long Minute(void) const { return this.GetProperty(BAR_PROP_TIME_MINUTE); } long Index(void) const { return this.GetProperty(BAR_PROP_INDEX); } //--- Return bar's (1) Open, (2) High, (3) Low, (4) Close price, //--- size of the (5) candle, (6) body, (7) candle top, (8) bottom, //--- size of the (9) candle upper, (10) lower wick double Open(void) const { return this.GetProperty(BAR_PROP_OPEN); } double High(void) const { return this.GetProperty(BAR_PROP_HIGH); } double Low(void) const { return this.GetProperty(BAR_PROP_LOW); } double Close(void) const { return this.GetProperty(BAR_PROP_CLOSE); } double Size(void) const { return this.GetProperty(BAR_PROP_CANDLE_SIZE); } double SizeBody(void) const { return this.GetProperty(BAR_PROP_CANDLE_SIZE_BODY); } double TopBody(void) const { return this.GetProperty(BAR_PROP_CANDLE_BODY_TOP); } double BottomBody(void) const { return this.GetProperty(BAR_PROP_CANDLE_BODY_BOTTOM); } double SizeShadowUp(void) const { return this.GetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_UP); } double SizeShadowDown(void) const { return this.GetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_DOWN); } //--- Return bar symbol string Symbol(void) const { return this.GetProperty(BAR_PROP_SYMBOL); } //+------------------------------------------------------------------+ //| Descriptions of bar object properties | //+------------------------------------------------------------------+ //--- Get description of a bar's (1) integer, (2) real and (3) string properties string GetPropertyDescription(ENUM_BAR_PROP_INTEGER property); string GetPropertyDescription(ENUM_BAR_PROP_DOUBLE property); string GetPropertyDescription(ENUM_BAR_PROP_STRING property); //--- Return the bar type description string BodyTypeDescription(void) const; //--- Send description of bar properties to the journal (full_prop=true - all properties, false - only supported ones) void Print(const bool full_prop=false); //--- Display a short bar description in the journal virtual void PrintShort(void); //--- Return the bar object short name virtual string Header(void); //--- }; //+------------------------------------------------------------------+
前に説明した資料について、クラスのコンテンツでメモリをリフレッシュしてみましょう。
クラスのprivateセクションの機能は、以下の通りです。
対応するバーオブジェクトプロパティ(整数、実数、文字列)を格納する3つの配列
適切な配列のオブジェクトプロパティの真のインデックスを計算するメソッド
追加のバーオブジェクトプロパティを計算して返すメソッド
クラスのpublicセクションの機能は、以下の通りです。
渡されたオブジェクトプロパティ値を整数、実数、文字列プロパティの配列に書き込むメソッド
配列から要求された整数、実数、または文字列プロパティの値を返すメソッド
各プロパティのオブジェクトによってプロパティをサポートするフラグを返す仮想メソッド。これらのメソッドは、バーオブジェクトの子孫オブジェクトに実装されることを意図しており、子孫オブジェクトが指定されたプロパティをサポートしていない場合にはfalseを返す必要があります。バーオブジェクトでは、すべてのプロパティがサポートされ、メソッドはtrueを返します。
最初の記事でライブラリオブジェクトの構造全体について説明したので、ここでは、残りのクラスメソッドの実装について簡単に説明します。
このクラスは3つのコンストラクタを備えています。
1. デフォルトでは、パラメータのないコンストラクタは、作成されたオブジェクトに必要なすべてのパラメータのその後の設定を伴うオブジェクトクラスの単純な宣言に使用されます。
2. 最初のパラメトリックコンストラクタは、銘柄、時間枠、バーインデックスの3つのパラメータを受け取ります。これらの3つのパラメータに基づいて、CopyRates()関数の最初の形式を使用して時系列から単一のバーオブジェクトのすべてのプロパティを取得します。
//+------------------------------------------------------------------+ //| Constructor 1 | //+------------------------------------------------------------------+ CBar::CBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const int index) { MqlRates rates_array[1]; this.SetSymbolPeriod(symbol,timeframe,index); ::ResetLastError(); //--- If failed to write bar data to the array by index or set the time to the time structure //--- display an error message, create and fill the structure with zeros, and write it to the rates_array array if(::CopyRates(symbol,timeframe,index,1,rates_array)<1 || !::TimeToStruct(rates_array[0].time,this.m_dt_struct)) { int err_code=::GetLastError(); ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_BAR_FAILED_GET_BAR_DATA),". ",CMessage::Text(MSG_LIB_SYS_ERROR)," ",CMessage::Text(err_code)," ",CMessage::Retcode(err_code)); MqlRates err={0}; rates_array[0]=err; } //--- Set the bar properties this.SetProperties(rates_array[0]); } //+------------------------------------------------------------------+
このコンストラクタは、バーオブジェクトを作成するときに時系列からデータを取得するのに一度だけ使用されます。
3. 2番目のパラメトリックコンストラクタは、MqlRates構造体の既に準備された配列からバーオブジェクトを作成するために使用されます。
言い換えると、これはMqlRates構造体配列をループで通過し、配列インデックスによってオブジェクトを作成することを意味します。
//+------------------------------------------------------------------+ //| Constructor 2 | //+------------------------------------------------------------------+ CBar::CBar(const string symbol,const ENUM_TIMEFRAMES timeframe,const int index,const MqlRates &rates) { this.SetSymbolPeriod(symbol,timeframe,index); ::ResetLastError(); //--- If failed to set time to the time structure, display the error message, //--- create and fill the structure with zeros, set the bar properties from this structure and exit if(!::TimeToStruct(rates.time,this.m_dt_struct)) { int err_code=::GetLastError(); ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_BAR_FAILED_GET_BAR_DATA),". ",CMessage::Text(MSG_LIB_SYS_ERROR)," ",CMessage::Text(err_code)," ",CMessage::Retcode(err_code)); MqlRates err={0}; this.SetProperties(err); return; } //--- Set the bar properties this.SetProperties(rates); } //+------------------------------------------------------------------+
ここでは、MqlRates構造へのリンクが、銘柄、時間枠、インデックスとは別にコンストラクタに渡されます。バーオブジェクトは、このデータに基づいて作成されます。
Compare()仮想メソッドは、指定したプロパティで2つのオブジェクトを比較するためのものです。これは、標準ライブラリのCObject基本オブジェクトクラスで定義されており、値が等しい場合はゼロを返し、比較された値のいずれかがより高い/低い場合は1 /-1を返します。検索と並べ替えには標準ライブラリのSearch()メソッドが使用されます。メソッドは、子孫クラスで再定義する必要があります。
//+------------------------------------------------------------------+ //| Compare CBar objects by all possible properties | //+------------------------------------------------------------------+ int CBar::Compare(const CObject *node,const int mode=0) const { const CBar *bar_compared=node; //--- compare integer properties of two bars if(mode<BAR_PROP_INTEGER_TOTAL) { long value_compared=bar_compared.GetProperty((ENUM_BAR_PROP_INTEGER)mode); long value_current=this.GetProperty((ENUM_BAR_PROP_INTEGER)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } //--- compare real properties of two bars else if(mode<BAR_PROP_DOUBLE_TOTAL+BAR_PROP_INTEGER_TOTAL) { double value_compared=bar_compared.GetProperty((ENUM_BAR_PROP_DOUBLE)mode); double value_current=this.GetProperty((ENUM_BAR_PROP_DOUBLE)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } //--- compare string properties of two bars else if(mode<BAR_PROP_DOUBLE_TOTAL+BAR_PROP_INTEGER_TOTAL+BAR_PROP_STRING_TOTAL) { string value_compared=bar_compared.GetProperty((ENUM_BAR_PROP_STRING)mode); string value_current=this.GetProperty((ENUM_BAR_PROP_STRING)mode); return(value_current>value_compared ? 1 : value_current<value_compared ? -1 : 0); } return 0; } //+------------------------------------------------------------------+
2つの類似バーオブジェクトを定義するメソッドは、2つのオブジェクトバーを比較するために使用されます。比較された2つのオブジェクトのすべてのフィールドが同一である場合にのみ、trueを返します。
//+------------------------------------------------------------------+ //| Compare CBar objects by all properties | //+------------------------------------------------------------------+ bool CBar::IsEqual(CBar *compared_bar) const { int beg=0, end=BAR_PROP_INTEGER_TOTAL; for(int i=beg; i<end; i++) { ENUM_BAR_PROP_INTEGER prop=(ENUM_BAR_PROP_INTEGER)i; if(this.GetProperty(prop)!=compared_bar.GetProperty(prop)) return false; } beg=end; end+=BAR_PROP_DOUBLE_TOTAL; for(int i=beg; i<end; i++) { ENUM_BAR_PROP_DOUBLE prop=(ENUM_BAR_PROP_DOUBLE)i; if(this.GetProperty(prop)!=compared_bar.GetProperty(prop)) return false; } beg=end; end+=BAR_PROP_STRING_TOTAL; for(int i=beg; i<end; i++) { ENUM_BAR_PROP_STRING prop=(ENUM_BAR_PROP_STRING)i; if(this.GetProperty(prop)!=compared_bar.GetProperty(prop)) return false; } return true; } //+------------------------------------------------------------------+
以下は、時系列に銘柄、時間枠、バーオブジェクトインデックスを配置するメソッドです。
//+------------------------------------------------------------------+ //| Set bar symbol, timeframe and index | //+------------------------------------------------------------------+ void CBar::SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe,const int index) { this.SetProperty(BAR_PROP_INDEX,index); this.SetProperty(BAR_PROP_SYMBOL,symbol); this.SetProperty(BAR_PROP_PERIOD,timeframe); this.m_digits=(int)::SymbolInfoInteger(symbol,SYMBOL_DIGITS); this.m_period_description=TimeframeDescription(timeframe); } //+------------------------------------------------------------------+
上記の3つのプロパティの設定とは別に、このメソッドは銘柄価格の小数点以下の桁数をm_digits変数に設定し、時間枠テキストの説明をm_period_description変数に設定します。これらは、バーオブジェクトを作成するときに一度指定するだけで十分です。
すべてのバーオブジェクトパラメータを設定するメソッドは、メソッドに渡されたMqlRates構造体からオブジェクトプロパティに値を書き込むだけでなく、適切なメソッドを使用して追加のオブジェクトプロパティのパラメータを計算します。
//+------------------------------------------------------------------+ //| Set bar object parameters | //+------------------------------------------------------------------+ void CBar::SetProperties(const MqlRates &rates) { this.SetProperty(BAR_PROP_SPREAD,rates.spread); this.SetProperty(BAR_PROP_VOLUME_TICK,rates.tick_volume); this.SetProperty(BAR_PROP_VOLUME_REAL,rates.real_volume); this.SetProperty(BAR_PROP_TIME,rates.time); this.SetProperty(BAR_PROP_TIME_YEAR,this.TimeYear()); this.SetProperty(BAR_PROP_TIME_MONTH,this.TimeMonth()); this.SetProperty(BAR_PROP_TIME_DAY_OF_YEAR,this.TimeDayOfYear()); this.SetProperty(BAR_PROP_TIME_DAY_OF_WEEK,this.TimeDayOfWeek()); this.SetProperty(BAR_PROP_TIME_DAY,this.TimeDay()); this.SetProperty(BAR_PROP_TIME_HOUR,this.TimeHour()); this.SetProperty(BAR_PROP_TIME_MINUTE,this.TimeMinute()); //--- this.SetProperty(BAR_PROP_OPEN,rates.open); this.SetProperty(BAR_PROP_HIGH,rates.high); this.SetProperty(BAR_PROP_LOW,rates.low); this.SetProperty(BAR_PROP_CLOSE,rates.close); this.SetProperty(BAR_PROP_CANDLE_SIZE,this.CandleSize()); this.SetProperty(BAR_PROP_CANDLE_SIZE_BODY,this.BodySize()); this.SetProperty(BAR_PROP_CANDLE_BODY_TOP,this.BodyHigh()); this.SetProperty(BAR_PROP_CANDLE_BODY_BOTTOM,this.BodyLow()); this.SetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_UP,this.ShadowUpSize()); this.SetProperty(BAR_PROP_CANDLE_SIZE_SHADOW_DOWN,this.ShadowDownSize()); //--- this.SetProperty(BAR_PROP_TYPE,this.BodyType()); } //+------------------------------------------------------------------+
以下は、すべてのバーオブジェクトプロパティの説明を表示するメソッドです。
//+------------------------------------------------------------------+ //| Display bar properties in the journal | //+------------------------------------------------------------------+ void CBar::Print(const bool full_prop=false) { ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_BEG)," (",this.Header(),") ============="); int beg=0, end=BAR_PROP_INTEGER_TOTAL; for(int i=beg; i<end; i++) { ENUM_BAR_PROP_INTEGER prop=(ENUM_BAR_PROP_INTEGER)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("------"); beg=end; end+=BAR_PROP_DOUBLE_TOTAL; for(int i=beg; i<end; i++) { ENUM_BAR_PROP_DOUBLE prop=(ENUM_BAR_PROP_DOUBLE)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("------"); beg=end; end+=BAR_PROP_STRING_TOTAL; for(int i=beg; i<end; i++) { ENUM_BAR_PROP_STRING prop=(ENUM_BAR_PROP_STRING)i; if(!full_prop && !this.SupportProperty(prop)) continue; ::Print(this.GetPropertyDescription(prop)); } ::Print("============= ",CMessage::Text(MSG_LIB_PARAMS_LIST_END)," (",this.Header(),") =============\n"); } //+------------------------------------------------------------------+
次の各プロパティの説明は、3つのループのオブジェクトプロパティ配列によって表示されます。プロパティがサポートされていない場合、full_propメソッドの入力がfalse(デフォルト)であれば、操作ログには表示されません。
以下は、操作ログにバーオブジェクトの短い説明を表示するメソッドです。
//+------------------------------------------------------------------+ //| Display a short bar description in the journal | //+------------------------------------------------------------------+ void CBar::PrintShort(void) { int dg=(this.m_digits>0 ? this.m_digits : 1); string params= ( ::TimeToString(this.Time(),TIME_DATE|TIME_MINUTES|TIME_SECONDS)+", "+ "O: "+::DoubleToString(this.Open(),dg)+", "+ "H: "+::DoubleToString(this.High(),dg)+", "+ "L: "+::DoubleToString(this.Low(),dg)+", "+ "C: "+::DoubleToString(this.Close(),dg)+", "+ "V: "+(string)this.VolumeTick()+", "+ (this.VolumeReal()>0 ? "R: "+(string)this.VolumeReal()+", " : "")+ this.BodyTypeDescription() ); ::Print(this.Header(),": ",params); } //+------------------------------------------------------------------+
このメソッドは、バーの説明を次の形式で表示します。
Bar "銘柄" H4[INDEX]: YYYY.MM.DD HH:MM:SS, O: X.XXXXX, H: X.XXXXX, L: X.XXXXX, C: X.XXXXX, V: XXXX, BAR_TYPE
例として:
Bar "EURUSD" H4[6]: 2020.02.06 20:00:00, O: 1.09749, H: 1.09828, L: 1.09706, C: 1.09827, V: 3323, Bullish bar
以下は、短いバー名を表示するメソッドです。
//+------------------------------------------------------------------+ //| Return the bar object short name | //+------------------------------------------------------------------+ string CBar::Header(void) { return ( CMessage::Text(MSG_LIB_TEXT_BAR)+" \""+this.GetProperty(BAR_PROP_SYMBOL)+"\" "+ TimeframeDescription((ENUM_TIMEFRAMES)this.GetProperty(BAR_PROP_PERIOD))+"["+(string)this.GetProperty(BAR_PROP_INDEX)+"]" ); } //+------------------------------------------------------------------+
バー名を次の形式で表示します。
Bar "銘柄" H4[INDEX]
例として:
Bar "EURUSD" H4[6]
以下は、バーオブジェクトの整数プロパティの説明を返すメソッドです。
//+------------------------------------------------------------------+ //| Return the description of the bar integer property | //+------------------------------------------------------------------+ string CBar::GetPropertyDescription(ENUM_BAR_PROP_INTEGER property) { return ( property==BAR_PROP_INDEX ? CMessage::Text(MSG_LIB_TEXT_BAR_INDEX)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BAR_PROP_TYPE ? CMessage::Text(MSG_ORD_TYPE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.BodyTypeDescription() ) : property==BAR_PROP_PERIOD ? CMessage::Text(MSG_LIB_TEXT_BAR_PERIOD)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.m_period_description ) : property==BAR_PROP_SPREAD ? CMessage::Text(MSG_LIB_TEXT_BAR_SPREAD)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BAR_PROP_VOLUME_TICK ? CMessage::Text(MSG_LIB_TEXT_BAR_VOLUME_TICK)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BAR_PROP_VOLUME_REAL ? CMessage::Text(MSG_LIB_TEXT_BAR_VOLUME_REAL)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.GetProperty(property) ) : property==BAR_PROP_TIME ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::TimeToString(this.GetProperty(property),TIME_DATE|TIME_MINUTES|TIME_SECONDS) ) : property==BAR_PROP_TIME_YEAR ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_YEAR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)this.Year() ) : property==BAR_PROP_TIME_MONTH ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_MONTH)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+MonthDescription((int)this.Month()) ) : property==BAR_PROP_TIME_DAY_OF_YEAR ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY_OF_YEAR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)::IntegerToString(this.DayOfYear(),3,'0') ) : property==BAR_PROP_TIME_DAY_OF_WEEK ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY_OF_WEEK)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+DayOfWeekDescription((ENUM_DAY_OF_WEEK)this.DayOfWeek()) ) : property==BAR_PROP_TIME_DAY ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_DAY)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)::IntegerToString(this.Day(),2,'0') ) : property==BAR_PROP_TIME_HOUR ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_HOUR)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)::IntegerToString(this.Hour(),2,'0') ) : property==BAR_PROP_TIME_MINUTE ? CMessage::Text(MSG_LIB_TEXT_BAR_TIME_MINUTE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+(string)::IntegerToString(this.Minute(),2,'0') ) : "" ); } //+------------------------------------------------------------------+
このメソッドは整数プロパティを渡します。その値に応じて、Datas.mqhファイルに設定されたテキストの説明が返されます。
バーオブジェクトの実際のプロパティと文字列プロパティの説明を返すメソッドは、バーオブジェクトの整数プロパティの説明を返すメソッドに似ています。
//+------------------------------------------------------------------+ //| Return the description of the bar's real property | //+------------------------------------------------------------------+ string CBar::GetPropertyDescription(ENUM_BAR_PROP_DOUBLE property) { int dg=(this.m_digits>0 ? this.m_digits : 1); return ( property==BAR_PROP_OPEN ? CMessage::Text(MSG_ORD_PRICE_OPEN)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_HIGH ? CMessage::Text(MSG_LIB_TEXT_BAR_HIGH)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_LOW ? CMessage::Text(MSG_LIB_TEXT_BAR_LOW)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_CLOSE ? CMessage::Text(MSG_ORD_PRICE_CLOSE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_CANDLE_SIZE ? CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_SIZE)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_CANDLE_SIZE_BODY ? CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_SIZE_BODY)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_CANDLE_SIZE_SHADOW_UP ? CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_SIZE_SHADOW_UP)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_CANDLE_SIZE_SHADOW_DOWN ? CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_SIZE_SHADOW_DOWN)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_CANDLE_BODY_TOP ? CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_BODY_TOP)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : property==BAR_PROP_CANDLE_BODY_BOTTOM ? CMessage::Text(MSG_LIB_TEXT_BAR_CANDLE_BODY_BOTTOM)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+::DoubleToString(this.GetProperty(property),dg) ) : "" ); } //+------------------------------------------------------------------+ //| Return the description of the bar string property | //+------------------------------------------------------------------+ string CBar::GetPropertyDescription(ENUM_BAR_PROP_STRING property) { return(property==BAR_PROP_SYMBOL ? CMessage::Text(MSG_LIB_PROP_SYMBOL)+": \""+this.GetProperty(property)+"\"" : ""); } //+------------------------------------------------------------------+
以下は、バータイプを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the bar type (bullish/bearish/zero) | //+------------------------------------------------------------------+ ENUM_BAR_BODY_TYPE CBar::BodyType(void) const { return ( this.Close()>this.Open() ? BAR_BODY_TYPE_BULLISH : this.Close()<this.Open() ? BAR_BODY_TYPE_BEARISH : (this.ShadowUpSize()+this.ShadowDownSize()==0 ? BAR_BODY_TYPE_NULL : BAR_BODY_TYPE_CANDLE_ZERO_BODY) ); } //+------------------------------------------------------------------+
ここではすべて単純です。バーの終値が始値を超える場合、これは強気のバーです。バーの終値が始値よりも低い場合、これは弱気です。ローソク足の髭が両方ともゼロの場合、これは実体がゼロのバーです。それ以外の場合これは実体がゼロのローソク足です。
以下は、バータイプの説明を返すメソッドです。
//+------------------------------------------------------------------+ //| Return the bar type description | //+------------------------------------------------------------------+ string CBar::BodyTypeDescription(void) const { return ( this.BodyType()==BAR_BODY_TYPE_BULLISH ? CMessage::Text(MSG_LIB_TEXT_BAR_TYPE_BULLISH) : this.BodyType()==BAR_BODY_TYPE_BEARISH ? CMessage::Text(MSG_LIB_TEXT_BAR_TYPE_BEARISH) : this.BodyType()==BAR_BODY_TYPE_CANDLE_ZERO_BODY ? CMessage::Text(MSG_LIB_TEXT_BAR_TYPE_CANDLE_ZERO_BODY) : CMessage::Text(MSG_LIB_TEXT_BAR_TYPE_NULL) ); } //+------------------------------------------------------------------+
バータイプに応じて、メソッドはDatas.mqhファイルに設定されたテキストの説明を返します。
バーオブジェクトクラスの準備ができました。次に、必要な時系列の必要なバーごとにバーオブジェクトを作成します。ただし、オブジェクトだけでは、CopyRates()を使用して時系列バーを要求することによる通常のデータ受信に比べて、大きな利点はありません。
時系列データを必要に応じて管理できるようにするには、必要な時系列に対応するバーオブジェクトのリストを必要な数量で作成する必要があります。その後、リストデータを分析して、分析に必要なすべてのデータを検索できます。
つまり、バーオブジェクトを格納するための時系列リストを作成する必要があります。
さらに、新しいバーの開始を検出して別のバーオブジェクトをリストに追加し、その量に関係なく、銘柄と時間枠で新しいバーを開くことを常に通知するツールが必要です。
クラスオブジェクトはバーリストプロパティの1つであるため、バーオブジェクトを格納するリストを作成する前に、「新しいバー」クラスを記述します。
新しいバーオブジェクト
新しいバーを開くイベントを検出するには、現在のバーを開いた時間と前回のバーを開いた時間を比較します。それらが一致しない場合、新しいバーが開かれています。この場合、後続の比較のために、新しい時間を以前の時間として保存する必要があります。
NewBar = false; if(PrevTime != Time) { NewBar = true; PrevTime = Time; }
この場合、新しいバーイベントは1回開かれますが、後続のすべてのコマンドは新しいバーで既に実行されています。
ただし、「新しいバー」の直後に特定のコマンドを実行する必要がある場合があります。イベントは、すべてのコマンドが完了するまで関連性を保つ必要があります。これを実現するには、前のバーに新しい値を割り当てる前に、新しいバーが表示されるまでに完了する必要があるすべてのコマンドを実行する必要があります。
NewBar = false; if(PrevTime != Time) { NewBar = true; // ... commands to be // ... executed // ... when a new bar appears PrevTime = Time; }
したがって、最初のオプションは、新しいバーの開始フラグを返す独立した関数として実行できます。提示されたバージョンの2番目のオプションは、OnTick()ハンドラーのなるべく最初で一部である必要があります。新しいバーが表示されたときに実行されるすべてのコマンドが最初に実行されるようにします。次に、常に実行されるすべてのコマンドが続きます。
最も単純なケースでは、これは新しいバーの開始を制御するのに十分です。
ただし、これはライブラリのニーズには十分ではありません。説明されている2つのオプションで、銘柄と時間枠ごとに個別の新しいバー定義が必要です。
- 指定された銘柄と時間枠の自動制御と保存時間(各銘柄と時間枠の「新しいバー」フラグイベントを個別に返す)、
- 新しい値を保存する手動制御による指定された銘柄と時間枠の時間管理
(「新しいバー」イベントを定義し、銘柄と時間枠ごとに次の新しいバーを後で制御するための新しい時間をいつ保存するかをユーザーが決定できるようにする)
現在の銘柄と時間枠でデータが要求されている場合は、時系列更新機能にアクセスすることはお勧めしません。履歴データは、指標が機能するのと同じスレッドで更新されるため、このような要求は競合を引き起こす可能性があります。したがって、現在の銘柄や時間枠から時系列データを取得しようとしているかどうかを必ず確認してください。している場合は、そのような要求にSeriesInfoInteger()やシリアルデータを返すその他の関数を適用する代わりに、別のメソッドを使用して、履歴の読み込みを開始するアクセスをおこないます。
このようなメソッドは存在し、非常に簡単です。
指標のOnCalculate()ハンドラパラメータには、必要な変数がすでに備わっています。
int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[])
- rates_total — 時系列で利用可能な履歴の数(パラメータなしのBars()関数と同様)
- prev_calculated — 最後の呼び出しで既に計算されたデータの量
- time[] — バー時間のデータを含む時系列配列
指標を使用すると、簡単な計算を使用して履歴データの変化を追跡できます。
- (rates_total - prev_calculated)が1を超える場合、これは履歴が読み込まれ、指標を再描画する必要があることを意味します。
- (rates_total - prev_calculated)が1の場合、現在の時間枠銘柄で新しいバーが開かれます。
- 通常(rates_total - prev_calculated)式は、新しいティックごとに0になります。
指標では、time[]配列からのバー時間が現在の銘柄と時間枠のクラスメソッドに渡され、新しいバーを定義してその時間を指定します。他の場合では、クラスメソッド内で時間を受け取ります。
\MQL5\Include\DoEasy\Objects\Series\に、CNewBarObjクラスの新しいNewBarObj.mqhファイルを作成します。
//+------------------------------------------------------------------+ //| NewBarObj.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 | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| "New bar" object class | //+------------------------------------------------------------------+ class CNewBarObj { private: string m_symbol; // Symbol ENUM_TIMEFRAMES m_timeframe; // Timeframe datetime m_new_bar_time; // New bar time for auto time management datetime m_prev_time; // Previous time for auto time management datetime m_new_bar_time_manual; // New bar time for manual time management datetime m_prev_time_manual; // Previous time for manual time management //--- Return the current bar data datetime GetLastBarDate(const datetime time); public: //--- Set (1) symbol and (2) timeframe void SetSymbol(const string symbol) { this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); } void SetPeriod(const ENUM_TIMEFRAMES timeframe) { this.m_timeframe=(timeframe==PERIOD_CURRENT ? (ENUM_TIMEFRAMES)::Period() : timeframe); } //--- Save the new bar time during the manual time management void SaveNewBarTime(const datetime time) { this.m_prev_time_manual=this.GetLastBarDate(time); } //--- Return (1) symbol and (2) timeframe string Symbol(void) const { return this.m_symbol; } ENUM_TIMEFRAMES Period(void) const { return this.m_timeframe; } //--- Return the (1) new bar time datetime TimeNewBar(void) const { return this.m_new_bar_time; } //--- Return the new bar opening flag during the time (1) auto, (2) manual management bool IsNewBar(const datetime time); bool IsNewBarManual(const datetime time); //--- Constructors CNewBarObj(void) : m_symbol(::Symbol()), m_timeframe((ENUM_TIMEFRAMES)::Period()), m_prev_time(0),m_new_bar_time(0), m_prev_time_manual(0),m_new_bar_time_manual(0) {} CNewBarObj(const string symbol,const ENUM_TIMEFRAMES timeframe); }; //+------------------------------------------------------------------+
ここではすべてが非常に単純だと思います。
銘柄と時間枠を保存するためのクラスメンバ変数は、privateセクションで宣言さ、オブジェクトが「新しいバー」イベントを定義します。
バーが開かれた新しい時間と以前の時間を格納するための変数は、自動と手動の時間管理について別々です(これが必要な理由についてはすでに説明しました)。
GetLastBarDate()メソッドはバーが開かれた新しい時間を返し、以下で検討されます。
新しいバー時間を手動時間管理の以前の時間として保存するためのSaveNewBarTime()メソッドは、クラスのpublicセクションで宣言および実装されています。ライブラリユーザーは、必要なすべてのアクションが完了した後で、新しいバーの時間を格納できます。
残りのメソッドは自明であり、ここでそれらを説明する意味はありません。
このクラスは2つのコンストラクタを備えています。最初のコンストラクタにはパラメータがありません。現在の銘柄と時間枠は初期化リストで設定されますが、すべての新しいバーの時間値と以前のバーを開いた時間はリセットされます。このようなオブジェクトを作成したら、作成したクラスオブジェクトに必要な銘柄と時間枠を設定するメソッドを個別に呼び出す必要があります。
2番目のコンストラクタはパラメトリックで、必要な銘柄と時間枠をすぐに受け取ります。
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CNewBarObj::CNewBarObj(const string symbol,const ENUM_TIMEFRAMES timeframe) : m_symbol(symbol),m_timeframe(timeframe) { this.m_prev_time=this.m_prev_time_manual=this.m_new_bar_time=this.m_new_bar_time_manual=0; } //+------------------------------------------------------------------+
作成されたクラスオブジェクトパラメータに渡される銘柄と時間枠は、その初期化リストで設定されます。次に、クラス本体のすべての時間変数にゼロ値が設定されます。
以下は、自動時間管理中に新しいバーの開始フラグを返すメソッドです。
//+------------------------------------------------------------------+ //| Return new bar opening flag | //+------------------------------------------------------------------+ bool CNewBarObj::IsNewBar(const datetime time) { //--- Get the current bar time datetime tm=this.GetLastBarDate(time); //--- If the previous and current time are equal to zero, this is the first launch if(this.m_prev_time==0 && this.m_new_bar_time==0) { //--- set the new bar opening time, //--- set the previous bar time as the current one and return 'false' this.m_new_bar_time=this.m_prev_time=tm; return false; } //--- If the previous time is not equal to the current bar open time, this is a new bar if(this.m_prev_time!=tm) { //--- set the new bar opening time, //--- set the previous time as the current one and return 'true' this.m_new_bar_time=this.m_prev_time=tm; return true; } //--- in other cases, return 'false' return false; } //+------------------------------------------------------------------+
このメソッドは、オブジェクトに設定された銘柄または時間枠で新しいバーが開かれるたびにtrueを返します。
以下は、手動時間管理中に新しいバーの開始フラグを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the new bar opening flag during the manual management | //+------------------------------------------------------------------+ bool CNewBarObj::IsNewBarManual(const datetime time) { //--- Get the current bar time datetime tm=this.GetLastBarDate(time); //--- If the previous and current time are equal to zero, this is the first launch if(this.m_prev_time_manual==0 && this.m_new_bar_time_manual==0) { //--- set the new bar opening time, //--- set the previous bar time as the current one and return 'false' this.m_new_bar_time_manual=this.m_prev_time_manual=tm; return false; } //--- If the previous time is not equal to the current bar open time, this is a new bar if(this.m_prev_time_manual!=tm) { //--- set the new bar opening time and return 'true' //--- Save the previous time as the current one from the program using the SaveNewBarTime() method //--- Till the previous time is forcibly set as the current one from the program, //--- the method returns the new bar flag allowing the completion of all the necessary actions on the new bar. this.m_new_bar_time=tm; return true; } //--- in other cases, return 'false' return false; } //+------------------------------------------------------------------+
自動時間管理とは異なり、このメソッドは現在のバーが開かれた新しい時間をバーの前回の時間を格納する変数に設定しません。これにより、「新しいバー」イベントを検出した後、ユーザーが新しいバーを開くときに実行するすべてのアクションが完了し、次のことが必要になるまで、新しいティックで毎回新しいバーを開くフラグを送信できます。 新しいバーの開店時間を以前と同じように保存します。新しいバーの時間が両方のメソッドの入力に渡されます。次に、GetLastBarDate()メソッドを使用して、使用する時間を定義します。
//+------------------------------------------------------------------+ //| Return the current bar time | //+------------------------------------------------------------------+ datetime CNewBarObj::GetLastBarDate(const datetime time) { return ( ::MQLInfoInteger(MQL_PROGRAM_TYPE)==PROGRAM_INDICATOR && this.m_symbol==::Symbol() && this.m_timeframe==::Period() ? time : (datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_LASTBAR_DATE) ); } //+------------------------------------------------------------------+
これが指標の場合、「新しいバー」オブジェクトの銘柄と時間枠の両方が現在の銘柄と時間枠と一致し、メソッドに渡される時間が返されます(指標では、時間はOnCalculate()パラメータつまりtime[]配列にあります。これは、新しいバーを定義するメソッドに時間を渡す配列です)、それ以外の場合SeriesInfoInteger()を使用して最後のバー時間を受毛撮ります。この場合、時間の代わりに任意の値を渡すことができます。
「新しいバー」オブジェクトクラスは、現在のニーズに対応しています。次に、バーオブジェクトのリストを作成します。
バーオブジェクトのリストは基本的に、MqlRatesの一部である履歴時系列データのセグメントです。なぜ別のリストが必要なのでしょうか。
まず、並び替え、検索、比較が高速になります。次に、MqlRates構造体フィールドとは別に、指定された数がリストに格納されているバーオブジェクトは、将来のさまざまなローソク足形成の検索を簡略化するための値を持つ追加フィールドを備えています。
バーオブジェクトのリスト、検索と並べ替え
時系列リスト(バーオブジェクトのリスト)には、標準ライブラリのCObjectクラスとその子孫のインスタンスへのポインタの動的配列のクラスを使用します。現在の記事では、バーオブジェクトの唯一のリストオブジェクトを実装して、銘柄と時間枠によって1つの時系列のみのバーを格納します。今後の記事では、ユーザプログラムで適用される個別の銘柄ごとに、時間枠ごとの時系列の収集の基礎としてこのリストを使用する予定です。時系列リストの同じ型のコレクションが複数あり、ライブラリユーザーが利用できる時系列コレクションの他のリストと分析および比較するために必要な情報をすばやく検索できるようになります。
バーオブジェクトの各リストには、ユーザ定義の数のバーオブジェクト(履歴の深さ)が含まれます。デフォルトでは、すべてのリストの履歴の深さは1000バーになります。作成する前に、各リストは取引サーバとのデータの同期を考慮する必要があります。各時系列の各リストには、使用可能な履歴バーの数を指定する値が含まれます。この値は、パラメーターなしでBars()関数によって返されます。ゼロを返す場合、履歴はまだ同期されていません。サーバとのデータの同期を待つ間、少しの間隔を空けて数回試行します。
Defines.mqhファイルで、適用された履歴の深さ、履歴をサーバと同期する試行間の休止ミリ秒数、同期イベントの取得試行回数を定義するマクロ置換を作成します。
//--- Pending request type IDs #define PENDING_REQUEST_ID_TYPE_ERR (1) // Type of a pending request created based on the server return code #define PENDING_REQUEST_ID_TYPE_REQ (2) // Type of a pending request created by request //--- Timeseries parameters #define SERIES_DEFAULT_BARS_COUNT (1000) // Required default amount of timeseries data #define PAUSE_FOR_SYNC_ATTEMPTS (16) // Amount of pause milliseconds between synchronization attempts #define ATTEMPTS_FOR_SYNC (5) // Number of attempts to receive synchronization with the server //+------------------------------------------------------------------+ //| Structures | //+------------------------------------------------------------------+
コレクションリストをすばやく検索して並べ替えるために、サービス関数の\MQL5\Include\DoEasy\Services\フォルダで選択されたCSelectクラスととSelect.mqhファイルのクラスに機能を既に作成しています。
バーオブジェクトリストに検索と並べ替えのメソッドを追加します。
バーオブジェクトクラスファイルをインクルードします。
//+------------------------------------------------------------------+ //| Select.mqh | //| Copyright 2019, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2019, 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\Bar.mqh" //+------------------------------------------------------------------+
バーオブジェクトプロパティによる検索と並べ替えのメソッドの定義をクラス本体に追加します。
//+------------------------------------------------------------------+ //| Class for sorting objects meeting the criterion | //+------------------------------------------------------------------+ class CSelect { private: //--- Method for comparing two values template<typename T> static bool CompareValues(T value1,T value2,ENUM_COMPARER_TYPE mode); public: //+------------------------------------------------------------------+ //| Methods of working with orders | //+------------------------------------------------------------------+ //--- Return the list of orders with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByOrderProperty(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the order index with the maximum value of the order's (1) integer, (2) real and (3) string properties static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property); static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property); static int FindOrderMax(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property); //--- Return the order index with the minimum value of the order's (1) integer, (2) real and (3) string properties static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_INTEGER property); static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_DOUBLE property); static int FindOrderMin(CArrayObj *list_source,ENUM_ORDER_PROP_STRING property); //+------------------------------------------------------------------+ //| Methods of working with events | //+------------------------------------------------------------------+ //--- Return the list of events with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByEventProperty(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the event index with the maximum value of the event's (1) integer, (2) real and (3) string properties static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property); static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property); static int FindEventMax(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property); //--- Return the event index with the minimum value of the event's (1) integer, (2) real and (3) string properties static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_INTEGER property); static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_DOUBLE property); static int FindEventMin(CArrayObj *list_source,ENUM_EVENT_PROP_STRING property); //+------------------------------------------------------------------+ //| Methods of working with accounts | //+------------------------------------------------------------------+ //--- Return the list of accounts with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByAccountProperty(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the event index with the maximum value of the event's (1) integer, (2) real and (3) string properties static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property); static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property); static int FindAccountMax(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property); //--- Return the event index with the minimum value of the event's (1) integer, (2) real and (3) string properties static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_INTEGER property); static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_DOUBLE property); static int FindAccountMin(CArrayObj *list_source,ENUM_ACCOUNT_PROP_STRING property); //+------------------------------------------------------------------+ //| Methods of working with symbols | //+------------------------------------------------------------------+ //--- Return the list of symbols with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *BySymbolProperty(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the symbol index with the maximum value of the order's (1) integer, (2) real and (3) string properties static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property); static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property); static int FindSymbolMax(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property); //--- Return the symbol index with the minimum value of the order's (1) integer, (2) real and (3) string properties static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_INTEGER property); static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_DOUBLE property); static int FindSymbolMin(CArrayObj *list_source,ENUM_SYMBOL_PROP_STRING property); //+------------------------------------------------------------------+ //| Methods of working with pending requests | //+------------------------------------------------------------------+ //--- Return the list of pending requests with one out of (1) integer, (2) real and (3) string properties meeting a specified criterion static CArrayObj *ByPendReqProperty(CArrayObj *list_source,ENUM_PEND_REQ_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByPendReqProperty(CArrayObj *list_source,ENUM_PEND_REQ_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode); static CArrayObj *ByPendReqProperty(CArrayObj *list_source,ENUM_PEND_REQ_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode); //--- Return the pending request index with the maximum value of the order's (1) integer, (2) real and (3) string properties static int FindPendReqMax(CArrayObj *list_source,ENUM_PEND_REQ_PROP_INTEGER property); static int FindPendReqMax(CArrayObj *list_source,ENUM_PEND_REQ_PROP_DOUBLE property); static int FindPendReqMax(CArrayObj *list_source,ENUM_PEND_REQ_PROP_STRING property); //--- Return the pending request index with the minimum value of the order's (1) integer, (2) real and (3) string properties static int FindPendReqMin(CArrayObj *list_source,ENUM_PEND_REQ_PROP_INTEGER property); static int FindPendReqMin(CArrayObj *list_source,ENUM_PEND_REQ_PROP_DOUBLE property); static int FindPendReqMin(CArrayObj *list_source,ENUM_PEND_REQ_PROP_STRING property); //+------------------------------------------------------------------+ //| 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 pending request index 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 pending request index 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 timeseries bar lists | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Return the list of bars with one integer | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByBarProperty(CArrayObj *list_source,ENUM_BAR_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++) { CBar *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 bars with one real | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByBarProperty(CArrayObj *list_source,ENUM_BAR_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++) { CBar *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 bars with one string | //| property meeting the specified criterion | //+------------------------------------------------------------------+ CArrayObj *CSelect::ByBarProperty(CArrayObj *list_source,ENUM_BAR_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++) { CBar *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 listed bar index | //| with the maximum integer property value | //+------------------------------------------------------------------+ int CSelect::FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_INTEGER property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CBar *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CBar *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 listed bar index | //| with the maximum real property value | //+------------------------------------------------------------------+ int CSelect::FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_DOUBLE property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CBar *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CBar *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 listed bar index | //| with the maximum string property value | //+------------------------------------------------------------------+ int CSelect::FindBarMax(CArrayObj *list_source,ENUM_BAR_PROP_STRING property) { if(list_source==NULL) return WRONG_VALUE; int index=0; CBar *max_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CBar *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 listed bar index | //| with the minimum integer property value | //+------------------------------------------------------------------+ int CSelect::FindBarMin(CArrayObj* list_source,ENUM_BAR_PROP_INTEGER property) { int index=0; CBar *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CBar *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 listed bar index | //| with the minimum real property value | //+------------------------------------------------------------------+ int CSelect::FindBarMin(CArrayObj* list_source,ENUM_BAR_PROP_DOUBLE property) { int index=0; CBar *min_obj=NULL; int total=list_source.Total(); if(total== 0) return WRONG_VALUE; for(int i=1; i<total; i++) { CBar *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 listed bar index | //| with the minimum string property value | //+------------------------------------------------------------------+ int CSelect::FindBarMin(CArrayObj* list_source,ENUM_BAR_PROP_STRING property) { int index=0; CBar *min_obj=NULL; int total=list_source.Total(); if(total==0) return WRONG_VALUE; for(int i=1; i<total; i++) { CBar *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; } //+------------------------------------------------------------------+
前のシリーズの第3回の記事で同様のメソッドを検討したので、ここでは説明する意味がありません。ご質問がある場合は、コメント欄でお気軽にお問い合わせください。
\MQL5\Include\DoEasy\Objects\Series\で、CSeriesクラスのSeries.mqhファイルを作成し、新しく作成された「新しいバー」および「バー」オブジェクトスラスとともにCSelectクラスファイルをリンクします。
//+------------------------------------------------------------------+ //| Series.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 "NewBarObj.mqh" #include "Bar.mqh" //+------------------------------------------------------------------+
次に、必要なクラスメンバ変数をすべて追加し、クラス本体でクラスメソッドを宣言します。
//+------------------------------------------------------------------+ //| Series.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 "NewBarObj.mqh" #include "Bar.mqh" //+------------------------------------------------------------------+ //| Timeseries class | //+------------------------------------------------------------------+ class CSeries : public CObject { private: ENUM_PROGRAM_TYPE m_program; // Program type ENUM_TIMEFRAMES m_timeframe; // Timeframe string m_symbol; // Symbol uint m_amount; // Amount of applied timeseries data uint m_bars; // Number of bars in history by symbol and timeframe bool m_sync; // Synchronized data flag CArrayObj m_list_series; // Timeseries list CNewBarObj m_new_bar_obj; // "New bar" object public: //--- Return the timeseries list CArrayObj* GetList(void) { return &m_list_series;} //--- Return the list of bars by selected (1) double, (2) integer and (3) string property fitting a compared condition CArrayObj* GetList(ENUM_BAR_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByBarProperty(this.GetList(),property,value,mode); } CArrayObj* GetList(ENUM_BAR_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByBarProperty(this.GetList(),property,value,mode); } CArrayObj* GetList(ENUM_BAR_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL){ return CSelect::ByBarProperty(this.GetList(),property,value,mode); } //--- Set (1) symbol and timeframe and (2) the number of applied timeseries data void SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe); bool SetAmountUsedData(const uint amount,const uint rates_total); //--- Return (1) symbol, (2) timeframe, (3) number of applied timeseries data, //--- (4) number of bars in the timeseries, the new bar flag with the (5) auto, (6) manual time management string Symbol(void) const { return this.m_symbol; } ENUM_TIMEFRAMES Period(void) const { return this.m_timeframe; } uint AmountUsedData(void) const { return this.m_amount; } uint Bars(void) const { return this.m_bars; } bool IsNewBar(const datetime time) { return this.m_new_bar_obj.IsNewBar(time); } bool IsNewBarManual(const datetime time) { return this.m_new_bar_obj.IsNewBarManual(time); } //--- Return the bar object by index (1) in the list and (2) in the timeseries CBar *GetBarByListIndex(const uint index); CBar *GetBarBySeriesIndex(const uint index); //--- Return (1) Open, (2) High, (3) Low, (4) Close, (5) time, (6) tick volume, (7) real volume, (8) bar spread by index double Open(const uint index,const bool from_series=true); double High(const uint index,const bool from_series=true); double Low(const uint index,const bool from_series=true); double Close(const uint index,const bool from_series=true); datetime Time(const uint index,const bool from_series=true); long TickVolume(const uint index,const bool from_series=true); long RealVolume(const uint index,const bool from_series=true); int Spread(const uint index,const bool from_series=true); //--- Save the new bar time during the manual time management void SaveNewBarTime(const datetime time) { this.m_new_bar_obj.SaveNewBarTime(time); } //--- Synchronize symbol data with server data bool SyncData(const uint amount,const uint rates_total); //--- (1) Create and (2) update the timeseries list int Create(const uint amount=0); void Refresh(const datetime time=0, const double open=0, const double high=0, const double low=0, const double close=0, const long tick_volume=0, const long volume=0, const int spread=0); //--- Constructors CSeries(void); CSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint amount=0); }; //+------------------------------------------------------------------+
リストを受け取るメソッドはすべてのオブジェクトコレクションクラスにあり、これらのメソッドの開発については、前シリーズの第3部で説明しました。
宣言されたメソッドのリストを見て、それらの実装を分析してみましょう。
最初のクラスコンストラクタにはパラメータがなく、現在の銘柄と時間枠のリストを作成するために使用されます。
//+------------------------------------------------------------------+ //| Constructor 1 (current symbol and period timeseries) | //+------------------------------------------------------------------+ CSeries::CSeries(void) : m_bars(0),m_amount(0),m_sync(false) { this.m_program=(ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE); this.m_list_series.Clear(); this.m_list_series.Sort(SORT_BY_BAR_INDEX); this.SetSymbolPeriod(::Symbol(),(ENUM_TIMEFRAMES)::Period()); } //+------------------------------------------------------------------+
使用可能な時系列バーの数、リストに保存されているバーの数、およびサーバとのデータ同期のフラグが初期化リストでリセットされます。
プログラムタイプが設定され、バーオブジェクトのリストがクリアされ、バーインデックスによる並び替えフラグが設定されます。後に現在の銘柄と時間枠がリストに設定されます。
バーオブジェクトリストを作成したら、SetAmountUsedData()メソッドを含むSetAmountUsedData()またはSyncData()メソッドを使用して、バーオブジェクトリストの使用バー数を設定してください。指標の場合は、rates_totalを2番目のパラメータとしてメソッドに渡してください。
クラスの2番目のコンストラクタは3つの入力(銘柄、時間枠、バーオブジェクトリストのサイズ)を備え、必要な履歴の深さを考慮して、指定された銘柄と時間枠のリストを作成するために使用されます。
//+------------------------------------------------------------------+ //| Constructor 2 (specified symbol and period timeseries) | //+------------------------------------------------------------------+ CSeries::CSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint amount=0) : m_bars(0), m_amount(0),m_sync(false) { this.m_program=(ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE); this.m_list_series.Clear(); this.m_list_series.Sort(SORT_BY_BAR_INDEX); this.SetSymbolPeriod(symbol,timeframe); this.m_sync=this.SetAmountUsedData(amount,0); } //+------------------------------------------------------------------+
使用可能な時系列バーの数、リストに保存されているバーの数、およびサーバとのデータ同期のフラグが初期化リストでリセットされます。
プログラムタイプが設定され、バーオブジェクトのリストがクリアされ、バーインデックスによる並び替えフラグが設定されます。
後に現在の銘柄と時間枠がリストに設定されます。
最後に、SetAmountUsedData()バーオブジェクトリストに必要なバーの数を設定するメソッドの結果が同期フラグに設定されます。リストは、コンストラクタのamount入力で指定された必要な履歴の深さを受け取ります。バーオブジェクトのリストを作成したら、プログラムからSyncData()メソッドを使用して、サーバとの同期を確認してください。
以下は、銘柄と時間枠を設定するメソッドです。
//+------------------------------------------------------------------+ //| Set a symbol and timeframe | //+------------------------------------------------------------------+ void CSeries::SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe) { this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); this.m_timeframe=(timeframe==PERIOD_CURRENT ? (ENUM_TIMEFRAMES)::Period() : timeframe); this.m_new_bar_obj.SetSymbol(this.m_symbol); this.m_new_bar_obj.SetPeriod(this.m_timeframe); } //+------------------------------------------------------------------+
このメソッドは銘柄と時間枠を渡し、渡された値の有効性が確認されます。最終的に、現在の銘柄と時間枠、またはメソッドに渡された銘柄と時間枠のいずれかが設定されます。次に、変数に新しく保存された銘柄と時間枠が、バーリストの「新しいバー」オブジェクトに設定されます。
以下は、バーオブジェクトリストに使用される時系列データの数を設定するメソッドです。
//+------------------------------------------------------------------+ //| Set the number of required data | //+------------------------------------------------------------------+ bool CSeries::SetAmountUsedData(const uint amount,const uint rates_total) { //--- Set the number of available timeseries bars this.m_bars= ( //--- If this is an indicator and the work is performed on the current symbol and timeframe, //--- add the rates_total value passed to the method, //--- otherwise, get the number from the environment this.m_program==PROGRAM_INDICATOR && this.m_symbol==::Symbol() && this.m_timeframe==::Period() ? rates_total : ::Bars(this.m_symbol,this.m_timeframe) ); //--- If managed to set the number of available history, set the amount of data in the list: if(this.m_bars>0) { //--- if zero 'amount' value is passed, //--- use either the default value (1000 bars) or the number of available history bars - the least one of them //--- if non-zero 'amount' value is passed, //--- use either the 'amount' value or the number of available history bars - the least one of them this.m_amount=(amount==0 ? ::fmin(SERIES_DEFAULT_BARS_COUNT,this.m_bars) : ::fmin(amount,this.m_bars)); return true; } return false; } //+------------------------------------------------------------------+
このメソッドは、バーオブジェクトリストに必要な量のデータと、現在の時系列の棒の総数(指標用)を受け取ります。
次に、プログラムタイプが確認され、m_bars変数の利用可能な履歴量のソースが、メソッドに渡された値(現在の指標銘柄と時系列)または環境から定義されます。次に、利用可能な必要な履歴の量に基づいて、m_amount変数に設定する値を定義します。
以下は、銘柄と時系列のデータをサーバデータと同期するメソッドです。
//+------------------------------------------------------------------+ //|Synchronize symbol and timeframe data with server data | //+------------------------------------------------------------------+ bool CSeries::SyncData(const uint amount,const uint rates_total) { //--- If managed to obtain the available number of bars in the timeseries //--- and return the size of the bar object list, return 'true' this.m_sync=this.SetAmountUsedData(amount,rates_total); if(this.m_sync) return true; //--- Data is not yet synchronized with the server //--- Create a pause object CPause *pause=new CPause(); if(pause==NULL) { ::Print(DFUN_ERR_LINE,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_PAUSE_OBJ)); return false; } //--- Set the pause duration of 16 milliseconds (PAUSE_FOR_SYNC_ATTEMPTS) and initialize the tick counter pause.SetWaitingMSC(PAUSE_FOR_SYNC_ATTEMPTS); pause.SetTimeBegin(0); //--- Make five (ATTEMPTS_FOR_SYNC) attempts to obtain the available number of bars in the timeseries //--- and set the bar object list size int attempts=0; while(attempts<ATTEMPTS_FOR_SYNC && !::IsStopped()) { //--- If data is currently synchronized with the server if(::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_SYNCHRONIZED)) { //--- if managed to obtain the available number of bars in the timeseries //--- and set the size of the bar object list, break the loop this.m_sync=this.SetAmountUsedData(amount,rates_total); if(this.m_sync) break; } //--- Data is not yet synchronized. //--- If the pause of 16 ms is over if(pause.IsCompleted()) { //--- set the new start of the next waiting for the pause object //--- and increase the attempt counter pause.SetTimeBegin(0); attempts++; } } //--- Remove the pause object and return the m_sync value delete pause; return this.m_sync; } //+------------------------------------------------------------------+
メソッドのロジックは、コードのコメントで説明されています。ここではすべてが明確であると思います。
バーオブジェクトリストの作成メソッドおよび更新メソッドは、リストで詳細にコメントされています。説明のために多くのスペースをとらないように、それら全体を考慮してみましょう。これらのメソッドについて質問がある場合は、コメントでお気軽に質問してください。
//+------------------------------------------------------------------+ //| Create the timeseries list | //+------------------------------------------------------------------+ int CSeries::Create(const uint amount=0) { //--- If the required history depth is not set for the list yet, //--- display the appropriate message and return zero, if(this.m_amount==0) { ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_BAR_TEXT_FIRS_SET_AMOUNT_DATA)); return 0; } //--- otherwise, if the passed 'amount' value exceeds zero and is not equal to the one already set, //--- while being lower than the available bar number, //--- set the new value of the required history depth for the list else if(amount>0 && this.m_amount!=amount && amount<this.m_bars) { //--- If failed to set a new value, return zero if(!this.SetAmountUsedData(amount,0)) return 0; } //--- For the rates[] array we are to receive historical data to, //--- set the flag of direction like in the timeseries, //--- clear the bar object list and set the flag of sorting by bar index MqlRates rates[]; ::ArraySetAsSeries(rates,true); this.m_list_series.Clear(); this.m_list_series.Sort(SORT_BY_BAR_INDEX); ::ResetLastError(); //--- Get historical data of the MqlRates structure to the rates[] array starting from the current bar in the amount of m_amount, //--- if failed to get data, display the appropriate message and return zero int copied=::CopyRates(this.m_symbol,this.m_timeframe,0,this.m_amount,rates),err=ERR_SUCCESS; if(copied<1) { err=::GetLastError(); ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_BAR_FAILED_GET_SERIES_DATA)," ",this.m_symbol," ",TimeframeDescription(this.m_timeframe),". ", CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(err),CMessage::Retcode(err)); return 0; } //--- Historical data is received in the rates[] array //--- In the rates[] array loop, for(int i=0; i<copied; i++) { //--- create a new bar object out of the current MqlRates structure by the loop index ::ResetLastError(); CBar* bar=new CBar(this.m_symbol,this.m_timeframe,i,rates[i]); if(bar==NULL) { ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_FAILED_CREATE_BAR_OBJ),". ",CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(::GetLastError())); continue; } //--- If failed to add bar object to the list, //--- display the appropriate message with the error description in the journal if(!this.m_list_series.Add(bar)) { err=::GetLastError(); ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_BAR_FAILED_ADD_TO_LIST)," ",bar.Header(),". ", CMessage::Text(MSG_LIB_SYS_ERROR),": ",CMessage::Text(err),CMessage::Retcode(err)); } } //--- Return the size of the created bar object list return this.m_list_series.Total(); } //+------------------------------------------------------------------+ //| Update timeseries list and data | //+------------------------------------------------------------------+ void CSeries::Refresh(const datetime time=0, const double open=0, const double high=0, const double low=0, const double close=0, const long tick_volume=0, const long volume=0, const int spread=0) { MqlRates rates[1]; //--- Set the flag of sorting the list of bars by index this.m_list_series.Sort(SORT_BY_BAR_INDEX); //--- If a new bar is present on a symbol and period, if(this.IsNewBarManual(time)) { //--- create a new bar object and add it to the end of the list CBar *new_bar=new CBar(this.m_symbol,this.m_timeframe,0); if(new_bar==NULL) return; if(!this.m_list_series.Add(new_bar)) { delete new_bar; return; } //--- if the specified timeseries size exceeds one bar, remove the earliest bar if(this.m_list_series.Total()>1) this.m_list_series.Delete(0); //--- save the new bar time as the previous one for the subsequent new bar check this.SaveNewBarTime(time); } //--- Get the index of the last bar in the list and the object bar by the index int index=this.m_list_series.Total()-1; CBar *bar=this.m_list_series.At(index); //--- if the work is performed in an indicator and the timeseries belongs to the current symbol and timeframe, //--- copy price parameters (passed to the method from the outside) to the bar price structure int copied=1; if(this.m_program==PROGRAM_INDICATOR && this.m_symbol==::Symbol() && this.m_timeframe==::Period()) { rates[0].time=time; rates[0].open=open; rates[0].high=high; rates[0].low=low; rates[0].close=close; rates[0].tick_volume=tick_volume; rates[0].real_volume=volume; rates[0].spread=spread; } //--- otherwise, get data to the bar price structure from the environment else copied=::CopyRates(this.m_symbol,this.m_timeframe,0,1,rates); //--- If the prices are obtained, set the new properties from the price structure for the bar object if(copied==1) bar.SetProperties(rates[0]); } //+------------------------------------------------------------------+
時系列リストを作成するには、まず、必要な履歴のサイズを設定し、SyncData()メソッドを使用してサーバとの同期のフラグを取得します。次にCreate()メソッドを呼び出します。バーオブジェクトリストデータを更新するには、各ティックで必ずRefresh()メソッドを呼び出します。このメソッドは、新しいバーが開かれると独自に検出し、新しいバーオブジェクトを時系列リストに追加します。リストのサイズは常にSyncData()メソッドで設定されたレベルのままになるように、最も古いバーオブジェクトがバーオブジェクトのリストから削除されます。
データを管理するには、時系列リストからバーオブジェクトを取得する必要があります。インデックスによる並び替えのフラグ(SORT_BY_BAR_INDEX)が時系列リストに設定されている場合、リスト内のバーオブジェクトのシーケンスは、時系列内の実際の棒の位置に対応します。ただし、リストに別の並べ替えフラグを設定すると、リスト内のオブジェクトの順序は、時系列内の実際のバーの位置に対応しなくなって、リストが並べ替えられるプロパティの昇順で配置されます。したがって、バーオブジェクトリストからオブジェクトを選択するには、時系列のインデックスによってオブジェクトバーを返すメソッドと、バーオブジェクトリストのインデックスによってオブジェクトバーを返すメソッドの2つがあります。
これら2つのメソッドについて考えてみましょう。
以下は、バーオブジェクトリスト内のバーオブジェクトをインデックスで返すメソッドです。
//+------------------------------------------------------------------+ //| Return the bar object by index in the list | //+------------------------------------------------------------------+ CBar *CSeries::GetBarByListIndex(const uint index) { return this.m_list_series.At(this.m_list_series.Total()-index-1); } //+------------------------------------------------------------------+
必要なバーオブジェクトのインデックスがメソッドに渡されます。渡されたインデックスは時系列と同じ方向を意味します。ゼロのインデックスはリストの最後のオブジェクトを示します。ただし、リスト内のオブジェクトはゼロインデックスからlist.Total()-1まで保存されます。つまり、リスト内の最新のバーを取得するには、list.Total()-1インデックスでリクエストします。 チャートの右端のバーを取得するには、インデックス0(逆インデックス)で要求します。
したがって、インデックスは適切な方法で再計算されます。渡されたインデックス1の数がリストサイズから差し引かれ、時系列のように、インデックスの方向に従って、計算されたインデックスに基づいてバーオブジェクトが返されます。
以下は、時系列のインデックスによってバーオブジェクトを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the bar object by index in the timeseries | //+------------------------------------------------------------------+ CBar *CSeries::GetBarBySeriesIndex(const uint index) { CArrayObj *list=this.GetList(BAR_PROP_INDEX,index); return(list==NULL || list.Total()==0 ? NULL : list.At(0)); } //+------------------------------------------------------------------+
必要なバーオブジェクトのインデックスがメソッドに渡されます。渡されたインデックスは、時系列と同じ方向を意味します。
時系列と同じバーインデックスを持つオブジェクトを取得するには、BAR_PROP_INDEXプロパティで選択する必要があります。バーオブジェクトのリストが必要なインデックスを持つバーを備えている場合、listは、返される必要がある単一のオブジェクトを備えています。
そのようなオブジェクトがない場合、NULLが返されます。エラーが発生した場合、これらのメソッドはどちらもNULLを返します。
以下は、インデックスによってバーオブジェクトのリストからバーオブジェクトの基本的なプロパティを返すメソッドです。
//+------------------------------------------------------------------+ //| Return bar's Open by the index | //+------------------------------------------------------------------+ double CSeries::Open(const uint index,const bool from_series=true) { CBar *bar=(from_series ? this.GetBarBySeriesIndex(index) : this.GetBarByListIndex(index)); return(bar!=NULL ? bar.Open() : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return bar's High by the timeseries index or the list of bars | //+------------------------------------------------------------------+ double CSeries::High(const uint index,const bool from_series=true) { CBar *bar=(from_series ? this.GetBarBySeriesIndex(index) : this.GetBarByListIndex(index)); return(bar!=NULL ? bar.High() : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return bar's Low by the timeseries index or the list of bars | //+------------------------------------------------------------------+ double CSeries::Low(const uint index,const bool from_series=true) { CBar *bar=(from_series ? this.GetBarBySeriesIndex(index) : this.GetBarByListIndex(index)); return(bar!=NULL ? bar.Low() : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return bar's Close by the timeseries index or the list of bars | //+------------------------------------------------------------------+ double CSeries::Close(const uint index,const bool from_series=true) { CBar *bar=(from_series ? this.GetBarBySeriesIndex(index) : this.GetBarByListIndex(index)); return(bar!=NULL ? bar.Close() : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return bar time by the timeseries index or the list of bars | //+------------------------------------------------------------------+ datetime CSeries::Time(const uint index,const bool from_series=true) { CBar *bar=(from_series ? this.GetBarBySeriesIndex(index) : this.GetBarByListIndex(index)); return(bar!=NULL ? bar.Time() : 0); } //+-------------------------------------------------------------------+ //|Return bar tick volume by the timeseries index or the list of bars | //+-------------------------------------------------------------------+ long CSeries::TickVolume(const uint index,const bool from_series=true) { CBar *bar=(from_series ? this.GetBarBySeriesIndex(index) : this.GetBarByListIndex(index)); return(bar!=NULL ? bar.VolumeTick() : WRONG_VALUE); } //+--------------------------------------------------------------------+ //|Return bar real volume by the timeseries index or the list of bars | //+--------------------------------------------------------------------+ long CSeries::RealVolume(const uint index,const bool from_series=true) { CBar *bar=(from_series ? this.GetBarBySeriesIndex(index) : this.GetBarByListIndex(index)); return(bar!=NULL ? bar.VolumeReal() : WRONG_VALUE); } //+------------------------------------------------------------------+ //| Return bar spread by the timeseries index or the list of bars | //+------------------------------------------------------------------+ int CSeries::Spread(const uint index,const bool from_series=true) { CBar *bar=(from_series ? this.GetBarBySeriesIndex(index) : this.GetBarByListIndex(index)); return(bar!=NULL ? bar.Spread() : WRONG_VALUE); } //+------------------------------------------------------------------+
メソッドはバーインデックスとリクエストされたインデックスが時系列のようにインデックスの方向に対応することを示すフラグ(true)を受け取ります。
フラグ値に基づいて、GetBarBySeriesIndex()またはGetBarByListIndex()メソッドを使用してバーオブジェクトを取得します。その後、メソッドでリクエストされたプロパティの値を返します。
ここで考慮されていない残りのCSeriesクラスメソッドは、クラスメンバ変数の値を設定または返すために使用されます。
現在の記事でおこなったことを確認するには、作成されたクラスについて外部プログラムに通知する必要があります。これには、CEngineライブラリメインオブジェクトファイルにCSeriesクラスファイルをインクルードします。
//+------------------------------------------------------------------+ //| 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 "TradingControl.mqh" #include "Objects\Series\Series.mqh" //+------------------------------------------------------------------+
これで、テストEAでCSeriesクラスタイプの変数を定義して、指定された数のバーオブジェクトを含む時系列リストを作成および使用できます(現在の実装では、リストはテストのみに使用されます)。やってみましょう。
テスト
テストを実行するには、前のシリーズ最終記事のEAを使用して、 \MQL5\Experts\TestDoEasy\Part35\にTestDoEasyPart35.mq5として保存します。
CSeriesクラスオブジェクトの2つの変数(テスト用)を作成します: M1(2バー)と現在の時間枠(10バー)です。OnInit()ハンドラで、テストに必要なパラメータをすべて設定して、3つのリストを表示します。
- ローソク足のサイズ(バーの高値から安値)で並び替えられた現在の時系列のすべてのバーのリスト - バーオブジェクトの短い説明。
- バーのインデックス(バー0~9)で並び替えられた現在の時系列のすべてのバーのリスト - バーオブジェクトの短い説明。
- 現在の時系列の適切なインデックス1(前のバー)に対応するすべてのバーオブジェクトプロパティのリスト — すべてのバープロパティの完全なリスト。
OnTick()ハンドラで、各ティックの両方の時系列を更新し、これら2つの時系列リストのbar1と現在の2つの時系列のそれぞれに新しいバーを開くことに関するエントリを表示します。操作ログエントリとは別に、現在の時系列の新しいバーを開くときに標準の「news.wav」サウンドを再生します。
グローバルEA変数のリストで、CSeriesクラスタイプの2つの変数を定義します — 現在の時間枠の時系列リスト変数および M1時系列の変数リスト。
//+------------------------------------------------------------------+ //| TestDoEasyPart35.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> //--- enums enum ENUM_BUTTONS { BUTT_BUY, BUTT_BUY_LIMIT, BUTT_BUY_STOP, BUTT_BUY_STOP_LIMIT, BUTT_CLOSE_BUY, BUTT_CLOSE_BUY2, BUTT_CLOSE_BUY_BY_SELL, BUTT_SELL, BUTT_SELL_LIMIT, BUTT_SELL_STOP, BUTT_SELL_STOP_LIMIT, BUTT_CLOSE_SELL, BUTT_CLOSE_SELL2, BUTT_CLOSE_SELL_BY_BUY, BUTT_DELETE_PENDING, BUTT_CLOSE_ALL, BUTT_SET_STOP_LOSS, BUTT_SET_TAKE_PROFIT, BUTT_PROFIT_WITHDRAWAL, BUTT_TRAILING_ALL }; #define TOTAL_BUTT (20) //--- structures struct SDataButt { string name; string text; }; //--- input variables input ushort InpMagic = 123; // Magic number input double InpLots = 0.1; // Lots input uint InpStopLoss = 150; // StopLoss in points input uint InpTakeProfit = 150; // TakeProfit in points input uint InpDistance = 50; // Pending orders distance (points) input uint InpDistanceSL = 50; // StopLimit orders distance (points) input uint InpDistancePReq = 50; // Distance for Pending Request's activate (points) input uint InpBarsDelayPReq = 5; // Bars delay for Pending Request's activate (current timeframe) input uint InpSlippage = 5; // Slippage in points input uint InpSpreadMultiplier = 1; // Spread multiplier for adjusting stop-orders by StopLevel input uchar InpTotalAttempts = 5; // Number of trading attempts sinput double InpWithdrawal = 10; // Withdrawal funds (in tester) sinput uint InpButtShiftX = 0; // Buttons X shift sinput uint InpButtShiftY = 10; // Buttons Y shift input uint InpTrailingStop = 50; // Trailing Stop (points) input uint InpTrailingStep = 20; // Trailing Step (points) input uint InpTrailingStart = 0; // Trailing Start (points) input uint InpStopLossModify = 20; // StopLoss for modification (points) input uint InpTakeProfitModify = 60; // TakeProfit for modification (points) sinput ENUM_SYMBOLS_MODE InpModeUsedSymbols = SYMBOLS_MODE_CURRENT; // Mode of used symbols list sinput string InpUsedSymbols = "EURUSD,AUDUSD,EURAUD,EURCAD,EURGBP,EURJPY,EURUSD,GBPUSD,NZDUSD,USDCAD,USDJPY"; // List of used symbols (comma - separator) sinput bool InpUseSounds = true; // Use sounds //--- global variables CEngine engine; CSeries series; CSeries series_m1; SDataButt butt_data[TOTAL_BUTT]; string prefix; double lot; double withdrawal=(InpWithdrawal<0.1 ? 0.1 : InpWithdrawal); ushort magic_number; uint stoploss; uint takeprofit; uint distance_pending; uint distance_stoplimit; uint distance_pending_request; uint bars_delay_pending_request; uint slippage; bool trailing_on; bool pressed_pending_buy; bool pressed_pending_buy_limit; bool pressed_pending_buy_stop; bool pressed_pending_buy_stoplimit; bool pressed_pending_close_buy; bool pressed_pending_close_buy2; bool pressed_pending_close_buy_by_sell; bool pressed_pending_sell; bool pressed_pending_sell_limit; bool pressed_pending_sell_stop; bool pressed_pending_sell_stoplimit; bool pressed_pending_close_sell; bool pressed_pending_close_sell2; bool pressed_pending_close_sell_by_buy; bool pressed_pending_delete_all; bool pressed_pending_close_all; bool pressed_pending_sl; bool pressed_pending_tp; double trailing_stop; double trailing_step; uint trailing_start; uint stoploss_to_modify; uint takeprofit_to_modify; int used_symbols_mode; string used_symbols; string array_used_symbols[]; bool testing; uchar group1; uchar group2; double g_point; int g_digits; //+------------------------------------------------------------------+
EAのOnInit()ハンドラで、時系列オブジェクトの両方の変数に必要なプロパティを設定し、現在の時間枠のバーオブジェクトの作成リストにデータ全体を表示します。М1の場合、リスト作成の成功に関するメッセージを表示するだけです。
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Calling the function displays the list of enumeration constants in the journal //--- (the list is set in the strings 22 and 25 of the DELib.mqh file) for checking the constants validity //EnumNumbersTest(); //--- Set EA global variables prefix=MQLInfoString(MQL_PROGRAM_NAME)+"_"; testing=engine.IsTester(); for(int i=0;i<TOTAL_BUTT;i++) { butt_data[i].name=prefix+EnumToString((ENUM_BUTTONS)i); butt_data[i].text=EnumToButtText((ENUM_BUTTONS)i); } lot=NormalizeLot(Symbol(),fmax(InpLots,MinimumLots(Symbol())*2.0)); magic_number=InpMagic; stoploss=InpStopLoss; takeprofit=InpTakeProfit; distance_pending=InpDistance; distance_stoplimit=InpDistanceSL; slippage=InpSlippage; trailing_stop=InpTrailingStop*Point(); trailing_step=InpTrailingStep*Point(); trailing_start=InpTrailingStart; stoploss_to_modify=InpStopLossModify; takeprofit_to_modify=InpTakeProfitModify; distance_pending_request=(InpDistancePReq<5 ? 5 : InpDistancePReq); bars_delay_pending_request=(InpBarsDelayPReq<1 ? 1 : InpBarsDelayPReq); g_point=SymbolInfoDouble(NULL,SYMBOL_POINT); g_digits=(int)SymbolInfoInteger(NULL,SYMBOL_DIGITS); //--- Initialize random group numbers group1=0; group2=0; srand(GetTickCount()); //--- Initialize DoEasy library OnInitDoEasy(); //--- Check and remove remaining EA graphical objects if(IsPresentObects(prefix)) ObjectsDeleteAll(0,prefix); //--- Create the button panel if(!CreateButtons(InpButtShiftX,InpButtShiftY)) return INIT_FAILED; //--- Set trailing activation button status ButtonState(butt_data[TOTAL_BUTT-1].name,trailing_on); //--- Reset states of the buttons for working using pending requests for(int i=0;i<14;i++) { ButtonState(butt_data[i].name+"_PRICE",false); ButtonState(butt_data[i].name+"_TIME",false); } //--- Check playing a standard sound by macro substitution and a custom sound by description engine.PlaySoundByDescription(SND_OK); Sleep(600); engine.PlaySoundByDescription(TextByLanguage("Звук упавшей монетки 2","Falling coin 2")); //--- Set the M1 timeseries object parameters series_m1.SetSymbolPeriod(Symbol(),PERIOD_M1); //--- If symbol and M1 timeframe data are synchronized if(series_m1.SyncData(2,0)) { //--- create the timeseries list of two bars (the current and previous ones), //--- if the timeseries is created, display the appropriate message in the journal int total=series_m1.Create(2); if(total>0) Print(TextByLanguage("Создана таймсерия М1 с размером ","Created timeseries M1 with size "),(string)total); } //--- Check filling price data on the current symbol and timeframe series.SetSymbolPeriod(Symbol(),(ENUM_TIMEFRAMES)Period()); //--- If symbol and the current timeframe data are synchronized if(series.SyncData(10,0)) { //--- create the timeseries list of ten bars (bars 0 - 9), //--- if the timeseries is created, display three lists: //--- 1. the list of bars sorted by candle size (from bars' High to Low) //--- 2. the list of bars sorted by bar indices (according to their sequence in the timeseries) //--- 3. the full list of all properties of the previous bar object (bar properties with the timeseries index of 1) int total=series.Create(10); if(total>0) { CArrayObj *list=series.GetList(); CBar *bar=NULL; //--- Display short properties of the bar list by the candle size Print("\n",TextByLanguage("Бары, сортированные по размеру свечи от High до Low:","Bars sorted by candle size from High to Low:")); list.Sort(SORT_BY_BAR_CANDLE_SIZE); for(int i=0;i<total;i++) { bar=series.GetBarByListIndex(i); if(bar==NULL) continue; bar.PrintShort(); } //--- Display short properties of the bar list by the timeseries index Print("\n",TextByLanguage("Бары, сортированные по индексу таймсерии:","Bars sorted by timeseries index:")); list.Sort(SORT_BY_BAR_INDEX); for(int i=0;i<total;i++) { bar=series.GetBarByListIndex(i); if(bar==NULL) continue; bar.PrintShort(); } //--- Display all bar 1 properties Print(""); list=CSelect::ByBarProperty(list,BAR_PROP_INDEX,1,EQUAL); if(list.Total()==1) { bar=list.At(0); bar.Print(); } } } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
OnTick()ハンドラで、各ティックでCSeriesクラスオブジェクトの時系列リストを更新する一方、「新しいバー」イベント中には 2つのリストに対してこのイベントに関するメッセージを表示ます。さらに、現在の時間枠で新しいバーを開くイベントの音声を再生します。
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- If working in the tester if(MQLInfoInteger(MQL_TESTER)) { engine.OnTimer(); // Working in the timer PressButtonsControl(); // Button pressing control EventsHandling(); // Working with events } //--- If the trailing flag is set if(trailing_on) { TrailingPositions(); // Trailing positions TrailingOrders(); // Trailing of pending orders } //--- Check the update of the current and M1 timeseries series.Refresh(); if(series.IsNewBar(0)) { Print("New bar on ",series.Symbol()," ",TimeframeDescription(series.Period())," ",TimeToString(series.Time(0))); engine.PlaySoundByDescription(SND_NEWS); } series_m1.Refresh(); if(series_m1.IsNewBar(0)) { Print("New bar on ",series_m1.Symbol()," ",TimeframeDescription(series_m1.Period())," ",TimeToString(series_m1.Time(0))); } } //+------------------------------------------------------------------+
EAをコンパイルし、銘柄チャートで起動します。
まず、操作ログは2本のバーのM1時系列リストの作成の開始のエントリを表示してから、ローソク足のサイズで並び替えられたバーのリストを表示します。次に、時系列のバーインデックスの順に並べ替えられたバーのリスト、最後に時系列のインデックスが1のすべてのオブジェクトバープロパティを表示します。
Account 15585535: Artyom Trishkin (MetaQuotes Software Corp.) 9999.40 USD, 1:100, Demo account MetaTrader 5 Work only with the current symbol. The number of symbols used: 1 Created timeseries M1 with size 2 Bars, sorted by size candle from High to Low: Bar "EURUSD" H1[2]: 2020.02.12 10:00:00, O: 1.09145, H: 1.09255, L: 1.09116, C: 1.09215, V: 2498, Bullish bar Bar "EURUSD" H1[3]: 2020.02.12 09:00:00, O: 1.09057, H: 1.09150, L: 1.09022, C: 1.09147, V: 1773, Bullish bar Bar "EURUSD" H1[1]: 2020.02.12 11:00:00, O: 1.09215, H: 1.09232, L: 1.09114, C: 1.09202, V: 1753, Bearish bar Bar "EURUSD" H1[9]: 2020.02.12 03:00:00, O: 1.09130, H: 1.09197, L: 1.09129, C: 1.09183, V: 1042, Bullish bar Bar "EURUSD" H1[4]: 2020.02.12 08:00:00, O: 1.09108, H: 1.09108, L: 1.09050, C: 1.09057, V: 581, Bearish bar Bar "EURUSD" H1[8]: 2020.02.12 04:00:00, O: 1.09183, H: 1.09197, L: 1.09146, C: 1.09159, V: 697, Bearish bar Bar "EURUSD" H1[5]: 2020.02.12 07:00:00, O: 1.09122, H: 1.09143, L: 1.09096, C: 1.09108, V: 591, Bearish bar Bar "EURUSD" H1[6]: 2020.02.12 06:00:00, O: 1.09152, H: 1.09159, L: 1.09121, C: 1.09122, V: 366, Bearish bar Bar "EURUSD" H1[7]: 2020.02.12 05:00:00, O: 1.09159, H: 1.09177, L: 1.09149, C: 1.09152, V: 416, Bearish bar Bar "EURUSD" H1[0]: 2020.02.12 12:00:00, O: 1.09202, H: 1.09204, L: 1.09181, C: 1.09184, V: 63, Bearish bar Bars, sorted by timeseries index: Bar "EURUSD" H1[9]: 2020.02.12 03:00:00, O: 1.09130, H: 1.09197, L: 1.09129, C: 1.09183, V: 1042, Bullish bar Bar "EURUSD" H1[8]: 2020.02.12 04:00:00, O: 1.09183, H: 1.09197, L: 1.09146, C: 1.09159, V: 697, Bearish bar Bar "EURUSD" H1[7]: 2020.02.12 05:00:00, O: 1.09159, H: 1.09177, L: 1.09149, C: 1.09152, V: 416, Bearish bar Bar "EURUSD" H1[6]: 2020.02.12 06:00:00, O: 1.09152, H: 1.09159, L: 1.09121, C: 1.09122, V: 366, Bearish bar Bar "EURUSD" H1[5]: 2020.02.12 07:00:00, O: 1.09122, H: 1.09143, L: 1.09096, C: 1.09108, V: 591, Bearish bar Bar "EURUSD" H1[4]: 2020.02.12 08:00:00, O: 1.09108, H: 1.09108, L: 1.09050, C: 1.09057, V: 581, Bearish bar Bar "EURUSD" H1[3]: 2020.02.12 09:00:00, O: 1.09057, H: 1.09150, L: 1.09022, C: 1.09147, V: 1773, Bullish bar Bar "EURUSD" H1[2]: 2020.02.12 10:00:00, O: 1.09145, H: 1.09255, L: 1.09116, C: 1.09215, V: 2498, Bullish bar Bar "EURUSD" H1[1]: 2020.02.12 11:00:00, O: 1.09215, H: 1.09232, L: 1.09114, C: 1.09202, V: 1753, Bearish bar Bar "EURUSD" H1[0]: 2020.02.12 12:00:00, O: 1.09202, H: 1.09204, L: 1.09181, C: 1.09184, V: 63, Bearish bar ============= The beginning of the event parameter list (Bar "EURUSD" H1[1]) ============= Timeseries index: 1 Type: Bearish bar Timeframe: H1 Spread: 1 Tick volume: 1753 Real volume: 0 Period start time: 2020.02.12 11:00:00 Sequence day number in the year: 042 Year: 2020 Month: February Day of week: Wednesday Day od month: 12 Hour: 11 Minute: 00 ------ Price open: 1.09215 Highest price for the period: 1.09232 Lowest price for the period: 1.09114 Price close: 1.09202 Candle size: 0.00118 Candle body size: 0.00013 Top of the candle body: 1.09215 Bottom of the candle body: 1.09202 Candle upper shadow size: 0.00017 Candle lower shadow size: 0.00088 ------ Symbol: "EURUSD" ============= End of the parameter list (Bar "EURUSD" H1[1]) =============
次に、М5でテスターのビジュアルモードでEAを起動し、新しいバーを開くことに関するテスター操作ログメッセージを確認します。
ご覧のように、5番目ごとのメッセージはМ5で新しいバーを開くことに関するものであり、М1で新しいバーを開くことに関するメッセージと断続的です。
次の段階
次の記事では、バーリストのコレクションクラスを作成します。
現在のバージョンのライブラリのすべてのファイルは、テスト用EAファイルと一緒に以下に添付されているので、テストするにはダウンロードしてください。
質問や提案はコメント欄にお願いします。
以前の連載記事:
第1部: 概念、データ管理
第2部: 過去の注文と取引のコレクション
第3部: 注文と取引のコレクション、検索と並び替え
第4部: 取引イベント概念
第5部: 取引イベントのクラスとコレクション取引イベントのプログラムへの送信
第6部: ネッティング勘定イベント
第7部: StopLimit注文発動イベント、注文およびポジション変更イベントの機能の準備
第8部: 注文とポジションの変更イベント
第9部: MQL4との互換性 - データの準備
第10部: MQL4との互換性 - ポジションオープンイベントと指値注文発動イベント
第11部: MQL4との互換性 - ポジション決済イベント
第12部: 口座オブジェクトクラスと口座オブジェクトコレクション
第13部: 口座オブジェクトイベント第14部: 銘柄オブジェクト
第15部: 銘柄オブジェクトコレクション
第16部: 銘柄コレクションイベント
第17部: ライブラリオブジェクトの相互作用
第18部:口座と他のライブラリオブジェクトの相互作用
第19部:ライブラリメッセージのクラス
第20部:プログラムリソースの作成と格納
第21部:取引クラス - 基本クロスプラットフォーム取引オブジェクト
第22部:取引クラス - 基本取引クラス、制限の検証
第23部:取引クラス - 基本取引クラス、パラメータ有効性の検証
第24部:取引クラス - 基本取引クラス、無効なパラメータの自動修正
第25部:取引クラス - 取引サーバによって返されたエラーを処理する基本取引クラス
第26部:未決取引リクエストの使用 - 初期実装(ポジションを開く)
第27部:未決取引リクエストの使用 - 指数注文
第28部:未決取引リクエストの使用 - 決済、削除、変更
第29部:未決取引リクエストの使用 - リクエストオブジェクトクラス
第30部:未決取引リクエスト - リクエストオブジェクトの管理
第31部:未決取引リクエスト - 特定の条件下でポジションを開く
第32部:未決取引リクエスト - 特定の条件下で指値注文を開く
第33部:未決取引リクエスト - 特定の条件下でのポジションの決済(完全、部分または反対のポジションによる)第34部:未決取引リクエスト - 特定の条件下での注文とポジションの削除と変更
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/7594
![連続ウォークフォワード最適化(パート4):最適化マネージャ(オートオプティマイザ)](https://c.mql5.com/2/38/MQL5-avatar-continuous_optimization.png)
![トレードシグナルの多通貨監視(パート2):アプリケーションのビジュアル部分の実装](https://c.mql5.com/2/37/Article_Logo__3.png)
![このプロジェクトは、収益性の高いトレーディングロボットを作成する手助けになります! 少なくとも、そうなるでしょう。](https://c.mql5.com/2/39/mql5-avatar-thumbs_up.png)
![ネットワーク関数の適用、または DLL を使用しない MySQL: パートII - シグナル特性の変化を監視するプログラム](https://c.mql5.com/2/37/kisspng-computer-icons-application-programming-interface-c-database-administrator-icon-free-download__1.png)
![MQL5 - MetaTrader 5クライアントターミナルにビルトインされたトレードストラテジーの言語](https://c.mql5.com/i/registerlandings/logo-2.png)
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索