
DoEasyライブラリの時系列(第37部): すべての使用銘柄期間の時系列オブジェクト
内容
概念
- 連載の開始時に、指定されたチャート銘柄と期間の単一のバーのデータを含むバーオブジェクトを作成しました。
- 指定されたチャート銘柄と期間の時系列オブジェクトであるバーコレクションを作成しました。
- 1つの銘柄のすべての時系列オブジェクトは、1つの銘柄の時系列オブジェクトに結合されました。
今日は、プログラムで使用される銘柄の時系列のコレクションオブジェクトを作成します。それぞれのコレクションには、1つの銘柄の特定の時系列のデータが含まれています。その結果、各銘柄の時系列ごとに、指定された数のバーのすべてのデータを含む1つのオブジェクトを取得します。
時系列コレクションは、プログラムで使用される各銘柄と、プログラム設定で設定されるすべての時間枠に必要なすべての履歴データを保存するためのものです。
さらに、コレクションにより、各銘柄の各時間枠に必要なデータを個別に設定できます。
時系列コレクション機能の説明は非常に長いため、そのリアルタイム更新とそこから可能なすべてのデータを取得することは、次の記事で実装する予定です。
以前に作成された時系列オブジェクトの改善
ほとんどのライブラリオブジェクトは、すべてのライブラリオブジェクトの基本オブジェクトから派生します。この基本オブジェクトは、 MQL5標準ライブラリを構築するための基本クラスから派生します。
ライブラリのニーズが増大するのに伴って、基本ライブラリオブジェクトのCBaseObjクラスも大きくなりました。さて、そこから新しいオブジェクトを継承すると、余分なしばしば完全に不必要なメソッドが含まれます。
この問題を解決するために、基本オブジェクトクラスを2つに分割してみましょう。
- 最初の部分(CBaseObj)には、各ライブラリオブジェクトのプロパティとメソッドのベースラインとなる最小セットが含まれます。
- 2番目は拡張された(CBaseObjExt) CBaseObjの子孫です。これには、ユーザとの対話のためのプロパティとメソッド、および子孫オブジェクトのイベント機能が含まれます。
したがって、基本プロパティとメソッドを必要とするオブジェクトは、CBaseObjから派生しますが、イベント機能を必要とするオブジェクトは、CBaseObjExtから派生します。
まず、 \MQL5\Include\DoEasy\Objects\BaseObj.mqhのCBaseObj基本オブジェクトクラスの名前をCBaseObjExtに変更して\MQL5\Include\DoEasy\Engine.mqhのCEngineライブラリメインオブジェクトのファイルをコンパイルすると、多数のコンパイルエラーが発生します(ライブラリの基本オブジェクトクラスの名前を変更したため)。
CBaseObjクラスが存在しないことを示すすべてのエラーのリストを確認しながら、クラス内のすべての「CBaseObj」文字列を 「CBaseObjExt」で置き換えます。修正された基本オブジェクトクラス名での再コンパイルは成功するはずです。
次に、基本オブジェクトクラスに新しいCBaseObjクラスを追加してMQL5ライブラリ基本オブジェクトから派生させCBaseObjExtクラスからすべての変数とメソッド 基本オブジェクトを新しいクラスに移動します。CBaseObjExtクラスは CBaseObjから派生しています。
複雑に思えますが、クラスのコードを見ると、すべてが明らかになります(ここに完全なコードを表示しても意味がありません。コード全体は添付ファイルにあります)。
//+------------------------------------------------------------------+ //| Base object class for all library objects | //+------------------------------------------------------------------+ class CBaseObj : public CObject { protected: ENUM_LOG_LEVEL m_log_level; // Logging level ENUM_PROGRAM_TYPE m_program; // Program type bool m_first_start; // First launch flag bool m_use_sound; // Flag of playing the sound set for an object bool m_available; // Flag of using a descendant object in the program int m_global_error; // Global error code long m_chart_id_main; // Control program chart ID long m_chart_id; // Chart ID string m_name; // Object name string m_folder_name; // Name of the folder storing CBaseObj descendant objects string m_sound_name; // Object sound file name int m_type; // Object type (corresponds to the collection IDs) public: //--- (1) Set, (2) return the error logging level void SetLogLevel(const ENUM_LOG_LEVEL level) { this.m_log_level=level; } ENUM_LOG_LEVEL GetLogLevel(void) const { return this.m_log_level; } //--- (1) Set and (2) return the chart ID of the control program void SetMainChartID(const long id) { this.m_chart_id_main=id; } long GetMainChartID(void) const { return this.m_chart_id_main; } //--- (1) Set and (2) return chart ID void SetChartID(const long id) { this.m_chart_id=id; } long GetChartID(void) const { return this.m_chart_id; } //--- (1) Set the sub-folder name, (2) return the folder name for storing descendant object files void SetSubFolderName(const string name) { this.m_folder_name=DIRECTORY+name; } string GetFolderName(void) const { return this.m_folder_name; } //--- (1) Set and (2) return the name of the descendant object sound file void SetSoundName(const string name) { this.m_sound_name=name; } string GetSoundName(void) const { return this.m_sound_name; } //--- (1) Set and (2) return the flag of playing descendant object sounds void SetUseSound(const bool flag) { this.m_use_sound=flag; } bool IsUseSound(void) const { return this.m_use_sound; } //--- (1) Set and (2) return the flag of using the descendant object in the program void SetAvailable(const bool flag) { this.m_available=flag; } bool IsAvailable(void) const { return this.m_available; } //--- Return the global error code int GetError(void) const { return this.m_global_error; } //--- Return the object name string GetName(void) const { return this.m_name; } //--- Return an object type virtual int Type(void) const { return this.m_type; } //--- Constructor CBaseObj() : m_program((ENUM_PROGRAM_TYPE)::MQLInfoInteger(MQL_PROGRAM_TYPE)), m_global_error(ERR_SUCCESS), m_log_level(LOG_LEVEL_ERROR_MSG), m_chart_id_main(::ChartID()), m_chart_id(::ChartID()), m_folder_name(DIRECTORY), m_sound_name(""), m_name(__FUNCTION__), m_type(0), m_use_sound(false), m_available(true), m_first_start(true) {} }; //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Extended base object class for all library objects | //+------------------------------------------------------------------+ #define CONTROLS_TOTAL (10) class CBaseObjExt : public CBaseObj { private: int m_long_prop_total; int m_double_prop_total; //--- Fill in the object property array template<typename T> bool FillPropertySettings(const int index,T &array[][CONTROLS_TOTAL],T &array_prev[][CONTROLS_TOTAL],int &event_id); protected: CArrayObj m_list_events_base; // Object base event list CArrayObj m_list_events; // Object event list MqlTick m_tick; // Tick structure for receiving quote data double m_hash_sum; // Object data hash sum double m_hash_sum_prev; // Object data hash sum during the previous check int m_digits_currency; // Number of decimal places in an account currency bool m_is_event; // Object event flag int m_event_code; // Object event code int m_event_id; // Event ID (equal to the object property value) //--- Data for storing, controlling and returning tracked properties: //--- [Property index][0] Controlled property increase value //--- [Property index][1] Controlled property decrease value //--- [Property index][2] Controlled property value level //--- [Property index][3] Property value //--- [Property index][4] Property value change //--- [Property index][5] Flag of a property change exceeding the increase value //--- [Property index][6] Flag of a property change exceeding the decrease value //--- [Property index][7] Flag of a property increase exceeding the control level //--- [Property index][8] Flag of a property decrease being less than the control level //--- [Property index][9] Flag of a property value being equal to the control level long m_long_prop_event[][CONTROLS_TOTAL]; // The array for storing object's integer properties values and controlled property change values double m_double_prop_event[][CONTROLS_TOTAL]; // The array for storing object's real properties values and controlled property change values long m_long_prop_event_prev[][CONTROLS_TOTAL]; // The array for storing object's controlled integer properties values during the previous check double m_double_prop_event_prev[][CONTROLS_TOTAL]; // The array for storing object's controlled real properties values during the previous check //--- Return (1) time in milliseconds, (2) milliseconds from the MqlTick time value long TickTime(void) const { return #ifdef __MQL5__ this.m_tick.time_msc #else this.m_tick.time*1000 #endif ; } ushort MSCfromTime(const long time_msc) const { return #ifdef __MQL5__ ushort(this.TickTime()%1000) #else 0 #endif ; } //--- return the flag of the event code presence in the event object bool IsPresentEventFlag(const int change_code) const { return (this.m_event_code & change_code)==change_code; } //--- Return the number of decimal places of the account currency int DigitsCurrency(void) const { return this.m_digits_currency; } //--- Returns the number of decimal places in the 'double' value int GetDigits(const double value) const; //--- Set the size of the array of controlled (1) integer and (2) real object properties bool SetControlDataArraySizeLong(const int size); bool SetControlDataArraySizeDouble(const int size); //--- Check the array size of object properties bool CheckControlDataArraySize(bool check_long=true); //--- Check the list of object property changes and create an event void CheckEvents(void); //--- (1) Pack a 'ushort' number to a passed 'long' number long UshortToLong(const ushort ushort_value,const uchar to_byte,long &long_value); protected: //--- (1) convert a 'ushort' value to a specified 'long' number byte long UshortToByte(const ushort value,const uchar to_byte) const; public: //--- Set the value of the pbject property controlled (1) increase, (2) decrease, (3) control level template<typename T> void SetControlledValueINC(const int property,const T value); template<typename T> void SetControlledValueDEC(const int property,const T value); template<typename T> void SetControlledValueLEVEL(const int property,const T value); //--- Return the set value of the controlled (1) integer and (2) real object properties increase long GetControlledLongValueINC(const int property) const { return this.m_long_prop_event[property][0]; } double GetControlledDoubleValueINC(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][0]; } //--- Return the set value of the controlled (1) integer and (2) real object properties decrease long GetControlledLongValueDEC(const int property) const { return this.m_long_prop_event[property][1]; } double GetControlledDoubleValueDEC(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][1]; } //--- Return the specified control level of object's (1) integer and (2) real properties long GetControlledLongValueLEVEL(const int property) const { return this.m_long_prop_event[property][2]; } double GetControlledDoubleValueLEVEL(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][2]; } //--- Return the current value of the object (1) integer and (2) real property long GetPropLongValue(const int property) const { return this.m_long_prop_event[property][3]; } double GetPropDoubleValue(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][3]; } //--- Return the change value of the controlled (1) integer and (2) real object property long GetPropLongChangedValue(const int property) const { return this.m_long_prop_event[property][4]; } double GetPropDoubleChangedValue(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][4]; } //--- Return the flag of an (1) integer and (2) real property value change exceeding the increase value long GetPropLongFlagINC(const int property) const { return this.m_long_prop_event[property][5]; } double GetPropDoubleFlagINC(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][5]; } //--- Return the flag of an (1) integer and (2) real property value change exceeding the decrease value long GetPropLongFlagDEC(const int property) const { return this.m_long_prop_event[property][6]; } double GetPropDoubleFlagDEC(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][6]; } //--- Return the flag of an (1) integer and (2) real property value increase exceeding the control level long GetPropLongFlagMORE(const int property) const { return this.m_long_prop_event[property][7]; } double GetPropDoubleFlagMORE(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][7]; } //--- Return the flag of an (1) integer and (2) real property value decrease being less than the control level long GetPropLongFlagLESS(const int property) const { return this.m_long_prop_event[property][8]; } double GetPropDoubleFlagLESS(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][8]; } //--- Return the flag of an (1) integer and (2) real property being equal to the control level long GetPropLongFlagEQUAL(const int property) const { return this.m_long_prop_event[property][9]; } double GetPropDoubleFlagEQUAL(const int property) const { return this.m_double_prop_event[property-this.m_long_prop_total][9]; } //--- Reset the variables of (1) tracked and (2) controlled object data (can be reset in the descendants) void ResetChangesParams(void); virtual void ResetControlsParams(void); //--- Add the (1) object event and (2) the object event reason to the list bool EventAdd(const ushort event_id,const long lparam,const double dparam,const string sparam); bool EventBaseAdd(const int event_id,const ENUM_BASE_EVENT_REASON reason,const double value); //--- Set/return the occurred event flag to the object data void SetEvent(const bool flag) { this.m_is_event=flag; } bool IsEvent(void) const { return this.m_is_event; } //--- Return (1) the list of events, (2) the object event code and (3) the global error code CArrayObj *GetListEvents(void) { return &this.m_list_events; } int GetEventCode(void) const { return this.m_event_code; } //--- Return (1) an event object and (2) a base event by its number in the list CEventBaseObj *GetEvent(const int shift=WRONG_VALUE,const bool check_out=true); CBaseEvent *GetEventBase(const int index); //--- Return the number of (1) object events int GetEventsTotal(void) const { return this.m_list_events.Total(); } //--- Update the object data to search for changes (Calling from the descendants: CBaseObj::Refresh()) virtual void Refresh(void); //--- Return an object event description string EventDescription(const int property, const ENUM_BASE_EVENT_REASON reason, const int source, const string value, const string property_descr, const int digits); //--- Data location in the magic number int value //----------------------------------------------------------- // bit 32|31 24|23 16|15 8|7 0| //----------------------------------------------------------- // byte | 3 | 2 | 1 | 0 | //----------------------------------------------------------- // data | uchar | uchar | ushort | //----------------------------------------------------------- // descr |pend req id| id2 | id1 | magic | //----------------------------------------------------------- //--- Set the ID of the (1) first group, (2) second group, (3) pending request to the magic number value void SetGroupID1(const uchar group,uint &magic) { magic &=0xFFF0FFFF; magic |= uint(this.ConvToXX(group,0)<<16); } void SetGroupID2(const uchar group,uint &magic) { magic &=0xFF0FFFFF; magic |= uint(this.ConvToXX(group,1)<<16); } void SetPendReqID(const uchar id,uint &magic) { magic &=0x00FFFFFF; magic |= (uint)id<<24; } //--- Convert the value of 0 - 15 into the necessary uchar number bits (0 - lower, 1 - upper ones) uchar ConvToXX(const uchar number,const uchar index) const { return((number>15 ?15 : number)<<(4*(index>1 ?1 : index))); } //--- Return (1) the specified magic number, the ID of (2) the first group, (3) second group, (4) pending request from the magic number value ushort GetMagicID(const uint magic) const { return ushort(magic & 0xFFFF); } uchar GetGroupID1(const uint magic) const { return uchar(magic>>16) & 0x0F; } uchar GetGroupID2(const uint magic) const { return uchar((magic>>16) & 0xF0)>>4; } uchar GetPendReqID(const uint magic) const { return uchar(magic>>24) & 0xFF; } //--- Constructor CBaseObjExt(); }; //+------------------------------------------------------------------+
3つの新しいクラスメンバ変数が、すべてのライブラリオブジェクトの新しい基本オブジェクトクラスで宣言されるようになりました。
bool m_use_sound; // Flag of playing the sound set for an object bool m_available; // Flag of using a descendant object in the program string m_sound_name; // Object sound file name
変数の値を設定および返す適切なメソッドも追加されます。
//--- (1) Set and (2) return the name of the descendant object sound file void SetSoundName(const string name) { this.m_sound_name=name; } string GetSoundName(void) const { return this.m_sound_name; } //--- (1) Set and (2) return the flag of playing descendant object sounds void SetUseSound(const bool flag) { this.m_use_sound=flag; } bool IsUseSound(void) const { return this.m_use_sound; } //--- (1) Set and (2) return the flag of using the descendant object in the program void SetAvailable(const bool flag) { this.m_available=flag; } bool IsAvailable(void) const { return this.m_available; }
子孫オブジェクトのサウンドファイルの名前により、オブジェクトのプロパティを制御する条件がある場合に再生できるオブジェクトサウンドファイルの名前を設定(SetSoundName())または受信(GetSoundName())できます。
名前をオブジェクトに割り当てることができるという事実に加えて、ファイルを再生する権限を有効化/無効化(SetUseSound())し、ファイルを再生するために設定された権限のフラグを取得することができます(IsUseSound())。
では、実際に「子孫オブジェクトを使用するフラグ」とは何であり、なぜそれを設定して受け取る必要があるのでしょうか。
例えば、М5、М30、Н1、D1の銘柄時系列オブジェクトがあって、ある時点でM5時系列を処理したくないとすれば、フラグを有効/無効にすることで、M5時系列の新しいバーなど、イベントライブラリを管理する必要性を規制できます。
すべてのライブラリオブジェクトの基本オブジェクトにこのようなフラグが存在することで、そのようなオブジェクトのプロパティの状態を処理する必要性を柔軟に制御できます。つまり、プログラムでオブジェクトを処理して使用する必要がある場合は、フラグを設定します。必要がなくなった場合は、フラグを削除してください。
当然、クラスコンストラクタも変更されました。新しいクラスに移動された変数は削除され、新しいクラスのすべての変数は初期化されています。添付ファイルで変更の詳細を確認してください。
拡張基本オブジェクトCBaseObjExtから派生するすようになったクラスは以下の通りです。
- CAccountsCollection(\MQL5\Include\DoEasy\Collections\AccountsCollection.mqh)
- CEventsCollection(\MQL5\Include\DoEasy\Collections\EventsCollection.mqh)
(CBaseObj::EventAddをCBaseObjExt::EventAddで置き換え)
- CSymbolsCollection(\MQL5\Include\DoEasy\Collections\SymbolsCollection.mqh)
- CAccount (\MQL5\Include\DoEasy\Objects\Accounts\Account.mqh)
(CBaseObj::Refresh()をCBaseObjExt::Refresh()で置き換え) - COrder (\MQL5\Include\DoEasy\Objects\Orders\Order.mqh)
- CPendRequest(\MQL5\Include\DoEasy\Objects\PendRequest\PendRequest.mqh)
(return CBaseObj::GetMagicIDをreturn CBaseObjExt::GetMagicID、
CBaseObj::GetGroupID1をreturn CBaseObjExt::GetGroupID1、CBaseObj::GetGroupID2をreturn CBaseObjExt::GetGroupID2で置き換え) - CSymbol (\MQL5\Include\DoEasy\Objects\Symbols\Symbol.mqh)
(CBaseObj::Refresh()をCBaseObjExt::Refresh()で置き換え) - CTradeObj (\MQL5\Include\DoEasy\Objects\Trade\TradeObj.mqh)
(bool m_use_sound変数、SetUseSound()メソッド、IsUseSound()メソッドを削除して基本クラスに移動) - CTrading (\MQL5\Include\DoEasy\Trading.mqh)
(bool m_use_sound変数とIsUseSounds()メソッドを削除して基本クラスに移動)
すでに作成されている時系列オブジェクトクラスを改善する前に、必要なデータ(プログラムの入力で使用されている銘柄と時間枠のリストの文字列で区切り文字を指定する新しいマクロ置換、 時間枠操作モードの列挙、宣言されたインデックスに対応する新しいメッセージインデックスおよびメッセージテキスト)をDatas.mqhファイルに追加しましょう。
//+------------------------------------------------------------------+ //| Datas.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" //+------------------------------------------------------------------+ //| Macro substitutions | //+------------------------------------------------------------------+ #define INPUT_SEPARATOR (",") // Separator in the inputs string #define TOTAL_LANG (2) // Number of used languages //+------------------------------------------------------------------+ //| Enumerations | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work with the current symbol only SYMBOLS_MODE_DEFINES, // Work with the specified symbol list SYMBOLS_MODE_MARKET_WATCH, // Work with the Market Watch window symbols SYMBOLS_MODE_ALL // Work with the full symbol list }; //+------------------------------------------------------------------+ //| Mode of working with timeframes | //+------------------------------------------------------------------+ enum ENUM_TIMEFRAMES_MODE { TIMEFRAMES_MODE_CURRENT, // Work with the current timeframe only TIMEFRAMES_MODE_LIST, // Work with the specified timeframe list TIMEFRAMES_MODE_ALL // Work with the full timeframe list }; //+------------------------------------------------------------------+ MSG_LIB_SYS_ERROR_EMPTY_SYMBOLS_STRING, // Error. Predefined symbols string empty, to be used MSG_LIB_SYS_FAILED_PREPARING_SYMBOLS_ARRAY, // Failed to prepare array of used symbols. Error MSG_LIB_SYS_ERROR_EMPTY_PERIODS_STRING, // Error. The string of predefined periods is empty and is to be used MSG_LIB_SYS_FAILED_PREPARING_PERIODS_ARRAY, // Failed to prepare array of used periods. Error MSG_LIB_SYS_INVALID_ORDER_TYPE, // Invalid order type:
...
//--- CTimeSeries MSG_LIB_TEXT_TS_TEXT_FIRS_SET_SYMBOL, // First, set a symbol using SetSymbol() MSG_LIB_TEXT_TS_TEXT_UNKNOWN_TIMEFRAME, // Unknown timeframe MSG_LIB_TEXT_TS_FAILED_GET_SERIES_OBJ, // Failed to receive the timeseries object MSG_LIB_TEXT_TS_REQUIRED_HISTORY_DEPTH, // Requested history depth MSG_LIB_TEXT_TS_ACTUAL_DEPTH, // Actual history depth MSG_LIB_TEXT_TS_AMOUNT_HISTORY_DATA, // Created historical data MSG_LIB_TEXT_TS_HISTORY_BARS, // Number of history bars on the server MSG_LIB_TEXT_TS_TEXT_SYMBOL_TIMESERIES, // Symbol timeseries MSG_LIB_TEXT_TS_TEXT_TIMESERIES, // Timeseries MSG_LIB_TEXT_TS_TEXT_REQUIRED, // Requested MSG_LIB_TEXT_TS_TEXT_ACTUAL, // Actual MSG_LIB_TEXT_TS_TEXT_CREATED, // Created MSG_LIB_TEXT_TS_TEXT_HISTORY_BARS, // On the server MSG_LIB_TEXT_TS_TEXT_SYMBOL_FIRSTDATE, // The very first date by a period symbol MSG_LIB_TEXT_TS_TEXT_SYMBOL_LASTBAR_DATE, // Time of opening the last bar by period symbol MSG_LIB_TEXT_TS_TEXT_SYMBOL_SERVER_FIRSTDATE, // The very first date in history by a server symbol MSG_LIB_TEXT_TS_TEXT_SYMBOL_TERMINAL_FIRSTDATE, // The very first date in history by a symbol in the client terminal }; //+------------------------------------------------------------------+
...
{"Ошибка. Строка предопределённых символов пустая, будет использоваться ","Error. String of predefined symbols is empty, the Symbol will be used: "}, {"Не удалось подготовить массив используемых символов. Ошибка ","Failed to create an array of used symbols. Error "}, {"Ошибка. Строка предопределённых периодов пустая, будет использоваться ","Error. String of predefined periods is empty, the Period will be used: "}, {"Не удалось подготовить массив используемых периодов. Ошибка ","Failed to create an array of used periods. Error "}, {"Неправильный тип ордера: ","Invalid order type: "},...
{"Сначала нужно установить символ при помощи SetSymbol()","First you need to set the Symbol using SetSymbol()"}, {"Неизвестный таймфрейм","Unknown timeframe"}, {"Не удалось получить объект-таймсерию ","Failed to get timeseries object "}, {"Запрошенная глубина истории: ","Required history depth: "}, {"Фактическая глубина истории: ","Actual history depth: "}, {"Создано исторических данных: ","Total historical data created: "}, {"Баров истории на сервере: ","Server history Bars number: "}, {"Таймсерия символа","Symbol time series"}, {"Таймсерия","Timeseries"}, {"Запрошено","Required"}, {"Фактически","Actual"}, {"Создано","Created"}, {"На сервере","On server"}, {"Самая первая дата по символу-периоду","The very first date for the symbol-period"}, {"Время открытия последнего бара по символу-периоду","Open time of the last bar of the symbol-period"}, {"Самая первая дата в истории по символу на сервере","The very first date in the history of the symbol on the server"}, {"Самая первая дата в истории по символу в клиентском терминале","The very first date in the history of the symbol in the client terminal"}, }; //+---------------------------------------------------------------------+
以前に開発された時系列クラスを改善し、すべての時系列のコレクションを作成するために必要なすべてのデータを準備しました。
単一のCSeries時間枠の銘柄時間枠オブジェクトクラスを改善しましょう。
クラスのprivateセクションに、4つの新しい変数と1つの時間枠の日付を設定するメソッドを追加します。
//+------------------------------------------------------------------+ //| Timeseries class | //+------------------------------------------------------------------+ class CSeries : public CBaseObj { private: ENUM_TIMEFRAMES m_timeframe; // Timeframe string m_symbol; // Symbol string m_period_description; // Timeframe string description datetime m_firstdate; // The very first date by a period symbol at the moment datetime m_lastbar_date; // Time of opening the last bar by period symbol uint m_amount; // Amount of applied timeseries data uint m_required; // Required 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 //--- Set the very first date by a period symbol at the moment and the new time of opening the last bar by a period symbol void SetServerDate(void) { this.m_firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_FIRSTDATE); this.m_lastbar_date=(datetime)::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_LASTBAR_DATE); } public:
コンストラクタでクラスオブジェクトを作成するときおよび時系列オブジェクトの時間枠を設定するメソッドで、時系列チャートの期間の説明をm_period_description変数にすぐに書き込みます。これは、ライブラリのDELib.mqhサービス関数ファイルからTimeframeDescription()関数に常にアクセスしないようにするために行われます。この関数は、ENUM_TIMEFRAMES列挙から時間枠文字列の説明で部分文字列を探し、実行を妨げます。したがって、データが変更されない場合、またはプログラムからのリクエストに応じてほとんど変更されない場合に備えて、オブジェクトの構築時にすぐに「低速」な関数を実行することをお勧めします。
m_firstdate変数は、SERIES_FIRSTDATEプロパティIDを持つSeriesInfoInteger()関数によって取得された瞬間の銘柄期間ごとの最初の日付を格納します。
m_lastbar_date変数は、SERIES_LASTBAR_DATEプロパティIDを持つSeriesInfoInteger()関数によって取得された銘柄期間ごとの最後のバーのオープン時間を格納します。
どちらの変数も、クラスオブジェクトの作成時または新しいバーのデータの変更時、および時系列オブジェクトに新しい銘柄または時間枠を設定するときにのみ SetServerDate()メソッドを呼び出すことによって設定されます。
m_required変数は、使用された時系列データを必要な(最後にリクエストされた)数格納します。必要な数の時系列バーをリクエストすると、時系列を作成するためにリクエストされた量のデータがサーバに存在しない場合があります。この場合、時系列は、使用可能なサーバ履歴の量と同じ量で作成されます。変数には、実際に取得および作成されたデータの量に関係なく、常に最後に要求された量のデータが格納されます。「要求されたデータ」の概念を使用していることを考慮して、「Amount」を含むクラスのメソッドの名前が「Required」に置き換えられています。
クラスのpublicセクションでは、新しいメソッドが追加されました。
public: //--- Return (1) oneself and (2) the timeseries list CSeries *GetObject(void) { return &this; } 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, (2) timeframe, (3) symbol and timeframe, (4) amount of applied timeseries data void SetSymbol(const string symbol); void SetTimeframe(const ENUM_TIMEFRAMES timeframe); void SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe); bool SetRequiredUsedData(const uint required,const uint rates_total); //--- Return (1) symbol, (2) timeframe, number of (3) used and (4) requested timeseries data, //--- (5) number of bars in the timeseries, (6) the very first date, (7) time of opening the last bar by a symbol period, //--- new bar flag with (8) automatic and (9) manual time management string Symbol(void) const { return this.m_symbol; } ENUM_TIMEFRAMES Timeframe(void) const { return this.m_timeframe; } ulong AvailableUsedData(void) const { return this.m_amount; } ulong RequiredUsedData(void) const { return this.m_required; } ulong Bars(void) const { return this.m_bars; } datetime FirstDate(void) const { return this.m_firstdate; } datetime LastBarDate(void) const { return this.m_lastbar_date; } 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, as well as (3) the real list size CBar *GetBarByListIndex(const uint index); CBar *GetBarBySeriesIndex(const uint index); int DataTotal(void) const { return this.m_list_series.Total(); } //--- 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); //--- (1) Set and (2) return the sound of a sound file of the "New bar" timeseries event void SetNewBarSoundName(const string name) { this.m_new_bar_obj.SetSoundName(name); } string NewBarSoundName(void) const { return this.m_new_bar_obj.GetSoundName(); } //--- Save the new bar time during the manual time management void SaveNewBarTime(const datetime time) { this.m_new_bar_obj.SaveNewBarTime(time); } //--- Synchronize symbol and timeframe data with server data bool SyncData(const uint required,const uint rates_total); //--- (1) Create and (2) update the timeseries list int Create(const uint required=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); //--- Return the timeseries name string Header(void); //--- Display (1) the timeseries description and (2) the brief timeseries description in the journal void Print(void); void PrintShort(void); //--- Constructors CSeries(void); CSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0); }; //+------------------------------------------------------------------+
GetObject()メソッドは、時系列オブジェクト全体へのポインタを制御プログラムに返します。これにより、時系列オブジェクト全体を取得して、カスタムプログラムで操作できます。
RequiredUsedData()メソッドは、上記のm_required変数の値を呼び出し側プログラムに返します。
FirstDate()メソッドとLastBarDate()メソッドは、上記のm_firstdate変数とm_lastbar_date変数の値を返します。
SetNewBarSoundName()メソッドは、時系列オブジェクトの一部であるCNewBarObj「新規バー」オブジェクトのサウンドファイル名を設定します。NewBarSoundName()メソッドは、時系列オブジェクトの一部であるCNewBarObj「新規バー」オブジェクトに割り当てられたサウンドファイル名を返します。
メソッドを使用すると、任意の時系列オブジェクトにサウンドを割り当てることができます。「新規バー」イベントが検出されたときにサウンドが再生されます。
Header()メソッドは、時系列オブジェクトの短い名前を作成して返します。
//+------------------------------------------------------------------+ //| Return the timeseries name | //+------------------------------------------------------------------+ string CSeries::Header(void) { return CMessage::Text(MSG_LIB_TEXT_TS_TEXT_TIMESERIES)+" \""+this.m_symbol+"\" "+this.m_period_description; } //+------------------------------------------------------------------+
時系列の文字列の説明は、メソッドから次の形式で返されます。
Timeseries "SYMBOL" TIMEFRAME_DESCRIPTION
以下は例です。
Timeseries "AUDUSD" M15
Print()メソッドは、時系列の完全な説明を操作ログに表示します。
//+------------------------------------------------------------------+ //| Display the timeseries description in the journal | //+------------------------------------------------------------------+ void CSeries::Print(void) { string txt= ( CMessage::Text(MSG_LIB_TEXT_TS_REQUIRED_HISTORY_DEPTH)+(string)this.RequiredUsedData()+", "+ CMessage::Text(MSG_LIB_TEXT_TS_ACTUAL_DEPTH)+(string)this.AvailableUsedData()+", "+ CMessage::Text(MSG_LIB_TEXT_TS_AMOUNT_HISTORY_DATA)+(string)this.DataTotal()+", "+ CMessage::Text(MSG_LIB_TEXT_TS_HISTORY_BARS)+(string)this.Bars() ); ::Print(this.Header(),": ",txt); } //+------------------------------------------------------------------+
次の形式で時系列データを操作ログに出力します。
HEADER: HISTORY_DEPTH: XXXX, ACTUAL_DEPTH: XXXX, AMOUNT_HISTORY_DATA: XXXX, HISTORY_BARS: XXXX
以下は例です。
Timeseries "AUDUSD" W1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 1400 Timeseries "AUDUSD" MN1: Requested history depth: 1000, Actual history depth: 322, Historical data created: 322, History bars on the server: 322
PrintShort()メソッドは、操作ログに短い時系列の説明を表示します。
//+------------------------------------------------------------------+ //| Display a short timeseries description in the journal | //+------------------------------------------------------------------+ void CSeries::PrintShort(void) { string txt= ( CMessage::Text(MSG_LIB_TEXT_TS_TEXT_REQUIRED)+": "+(string)this.RequiredUsedData()+", "+ CMessage::Text(MSG_LIB_TEXT_TS_TEXT_ACTUAL)+": "+(string)this.AvailableUsedData()+", "+ CMessage::Text(MSG_LIB_TEXT_TS_TEXT_CREATED)+": "+(string)this.DataTotal()+", "+ CMessage::Text(MSG_LIB_TEXT_TS_TEXT_HISTORY_BARS)+": "+(string)this.Bars() ); ::Print(this.Header(),": ",txt); } //+------------------------------------------------------------------+
次の形式で時系列データを操作ログに出力します。
HEADER: REQUIRED: XXXX, ACTUAL: XXXX, CREATED: XXXX, HISTORY_BARS: XXXX
以下は例です。
Timeseries "USDJPY" W1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2562 Timeseries "USDJPY" MN1: Requested: 1000, Actual: 589, Created: 589, On the server: 589
両方のクラスコンストラクタで時間枠の説明を保存して時系列の日付を設定するようにします。
//+------------------------------------------------------------------+ //| Constructor 1 (current symbol and period timeseries) | //+------------------------------------------------------------------+ CSeries::CSeries(void) : m_bars(0),m_amount(0),m_required(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(NULL,(ENUM_TIMEFRAMES)::Period()); this.m_period_description=TimeframeDescription(this.m_timeframe); this.SetServerDate(); } //+------------------------------------------------------------------+ //| Constructor 2 (specified symbol and period timeseries) | //+------------------------------------------------------------------+ CSeries::CSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0) : m_bars(0), m_amount(0),m_required(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.SetRequiredUsedData(required,0); this.m_period_description=TimeframeDescription(this.m_timeframe); this.SetServerDate(); } //+------------------------------------------------------------------+
銘柄設定メソッドでは、同じ銘柄に対するチェックと時系列の日付設定を追加します。
//+------------------------------------------------------------------+ //| Set a symbol | //+------------------------------------------------------------------+ void CSeries::SetSymbol(const string symbol) { if(this.m_symbol==symbol) return; this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); this.m_new_bar_obj.SetSymbol(this.m_symbol); this.SetServerDate(); } //+------------------------------------------------------------------+
ここで、オブジェクトですでに使用されている銘柄がメソッドに渡された場合は、何も設定する必要がないので、メソッドを終了します。
時間枠を設定するメソッドで、同じ時間枠のチェックと時系列の日のを設定を追加します。
//+------------------------------------------------------------------+ //| Set a timeframe | //+------------------------------------------------------------------+ void CSeries::SetTimeframe(const ENUM_TIMEFRAMES timeframe) { if(this.m_timeframe==timeframe) return; this.m_timeframe=(timeframe==PERIOD_CURRENT ? (ENUM_TIMEFRAMES)::Period() : timeframe); this.m_new_bar_obj.SetPeriod(this.m_timeframe); this.m_period_description=TimeframeDescription(this.m_timeframe); this.SetServerDate(); } //+------------------------------------------------------------------+
ここで、オブジェクトですでに使用されている時間枠がメソッドに渡された場合は、何も設定する必要がないので、メソッドを終了します。
銘柄と時間枠を設定するメソッドを変更しましょう。
//+------------------------------------------------------------------+ //| Set a symbol and timeframe | //+------------------------------------------------------------------+ void CSeries::SetSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES timeframe) { if(this.m_symbol==symbol && this.m_timeframe==timeframe) return; this.SetSymbol(symbol); this.SetTimeframe(timeframe); } //+------------------------------------------------------------------+
ここで、同じ銘柄と時間枠がメソッドに渡された場合は、何も変更する必要がないので、メソッドを終了します。
次に、銘柄を設定するメソッドと時間枠を設定するメソッドを呼び出します。
必要な時系列履歴の深さを設定するメソッドで、リクエストされた履歴の深さを保存します。
//+------------------------------------------------------------------+ //| Set the number of required data | //+------------------------------------------------------------------+ bool CSeries::SetRequiredUsedData(const uint required,const uint rates_total) { this.m_required=(required==0 ? SERIES_DEFAULT_BARS_COUNT : required); //--- Set the number of available timeseries bars this.m_bars=(uint) ( //--- 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 : ::SeriesInfoInteger(this.m_symbol,this.m_timeframe,SERIES_BARS_COUNT) ); //--- If managed to set the number of available history, set the amount of data in the list: if(this.m_bars>0) { //--- if zero 'required' 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 'required' value is passed, //--- use either the 'required' value or the number of available history bars - the least one of them this.m_amount=(required==0 ? ::fmin(SERIES_DEFAULT_BARS_COUNT,this.m_bars) : ::fmin(required,this.m_bars)); return true; } return false; } //+------------------------------------------------------------------+
requiredの値が0として渡された場合は、Define.mqhファイルのSERIES_DEFAULT_BARS_COUNTマクロ置き換えで指定されたデフォルトの量(1000バー)の履歴をリクエストします。その他の場合は「required」に渡された値を使用します。
時系列を更新するメソッドは、プログラムで時系列を使用するためのチェックを受けます。時系列を使用しない場合は、何も更新する必要はありません。
//+------------------------------------------------------------------+ //| 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) { //--- If the timeseries is not used, exit if(!this.m_available) return; 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; } //--- Write the very first date by a period symbol at the moment and the new time of opening the last bar by a period symbol this.SetServerDate(); //--- if the timeseries exceeds the requested number of bars, remove the earliest bar if(this.m_list_series.Total()>(int)this.m_required) 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]); } //+------------------------------------------------------------------+
また、時系列に新しいバーが表示された場合、時系列の日付を更新します。
これらは、クラスの主な変更点です。ここでは、メソッド名の小さな変更は考慮していません。添付ファイルで完全なクラスリストを見つけることができます。
これで、現在の段階でのCSeriesクラスの作業は完了です。
CSeriesオブジェクトを含むCTimeSeriesクラスを完成させて、1つの銘柄のすべての可能なチャート期間について説明します。
クラスリストは、適切なチャートの時系列とリストインデックスによる時間枠期間を格納するリストで時間枠インデックスを受信するためのIndexTimeframe()メソッドとTimeframeByIndex()メソッドを備えています。これらのメソッドは非常に具体的で、可能な限り短い時間枠のインデックス(PERIOD_M1)がリストのゼロインデックスに含まれているという事実に基づいています。ENUM_TIMEFRAMES列挙内では、ゼロインデックスにPERIOD_CURRENT定数が含まれているため、М1インデックスは既に1になっています。つまり、すべてのインデックスはゼロに対して1だけオフセットされます。
ENUM_TIMEFRAMES列挙内のチャート期間定数インデックスを返す関数が必要です。また、その逆で、チャート期間による列挙から定数を返す関数も必要です。サービス関数のファイルに適切な関数(IndexEnumTimeframe()とTimeframeByEnumIndex())を作成するとともに、CTimeSeriesクラスでは、IndexTimeframe()メソッドとTimeframeByIndex()メソッドの実装を削除し、IndexEnumTimeframe()およびTimeframeByEnumIndex()の呼び出しを1のオフセットでクラス本体に追加します。
サービス関数のDELib.mqhファイルに3つの関数を追加します。
//+------------------------------------------------------------------+ //| Return the timeframe index in the ENUM_TIMEFRAMES enumeration | //+------------------------------------------------------------------+ char IndexEnumTimeframe(ENUM_TIMEFRAMES timeframe) { int statement=(timeframe==PERIOD_CURRENT ? Period() : timeframe); switch(statement) { case PERIOD_M1 : return 1; case PERIOD_M2 : return 2; case PERIOD_M3 : return 3; case PERIOD_M4 : return 4; case PERIOD_M5 : return 5; case PERIOD_M6 : return 6; case PERIOD_M10 : return 7; case PERIOD_M12 : return 8; case PERIOD_M15 : return 9; case PERIOD_M20 : return 10; case PERIOD_M30 : return 11; case PERIOD_H1 : return 12; case PERIOD_H2 : return 13; case PERIOD_H3 : return 14; case PERIOD_H4 : return 15; case PERIOD_H6 : return 16; case PERIOD_H8 : return 17; case PERIOD_H12 : return 18; case PERIOD_D1 : return 19; case PERIOD_W1 : return 20; case PERIOD_MN1 : return 21; default : Print(DFUN,CMessage::Text(MSG_LIB_TEXT_TS_TEXT_UNKNOWN_TIMEFRAME)); return WRONG_VALUE; } } //+------------------------------------------------------------------+ //| Return the timeframe by the ENUM_TIMEFRAMES enumeration index | //+------------------------------------------------------------------+ ENUM_TIMEFRAMES TimeframeByEnumIndex(const uchar index) { if(index==0) return(ENUM_TIMEFRAMES)Period(); switch(index) { case 1 : return PERIOD_M1; case 2 : return PERIOD_M2; case 3 : return PERIOD_M3; case 4 : return PERIOD_M4; case 5 : return PERIOD_M5; case 6 : return PERIOD_M6; case 7 : return PERIOD_M10; case 8 : return PERIOD_M12; case 9 : return PERIOD_M15; case 10 : return PERIOD_M20; case 11 : return PERIOD_M30; case 12 : return PERIOD_H1; case 13 : return PERIOD_H2; case 14 : return PERIOD_H3; case 15 : return PERIOD_H4; case 16 : return PERIOD_H6; case 17 : return PERIOD_H8; case 18 : return PERIOD_H12; case 19 : return PERIOD_D1; case 20 : return PERIOD_W1; case 21 : return PERIOD_MN1; default : Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_DATAS),"... ",CMessage::Text(MSG_SYM_STATUS_INDEX),": ",(string)index); return WRONG_VALUE; } } //+------------------------------------------------------------------+ //| Return the timeframe by its description | //+------------------------------------------------------------------+ ENUM_TIMEFRAMES TimeframeByDescription(const string timeframe) { return ( timeframe=="M1" ? PERIOD_M1 : timeframe=="M2" ? PERIOD_M2 : timeframe=="M3" ? PERIOD_M3 : timeframe=="M4" ? PERIOD_M4 : timeframe=="M5" ? PERIOD_M5 : timeframe=="M6" ? PERIOD_M6 : timeframe=="M10" ? PERIOD_M10 : timeframe=="M12" ? PERIOD_M12 : timeframe=="M15" ? PERIOD_M15 : timeframe=="M20" ? PERIOD_M20 : timeframe=="M30" ? PERIOD_M30 : timeframe=="H1" ? PERIOD_H1 : timeframe=="H2" ? PERIOD_H2 : timeframe=="H3" ? PERIOD_H3 : timeframe=="H4" ? PERIOD_H4 : timeframe=="H6" ? PERIOD_H6 : timeframe=="H8" ? PERIOD_H8 : timeframe=="H12" ? PERIOD_H12 : timeframe=="D1" ? PERIOD_D1 : timeframe=="W1" ? PERIOD_W1 : timeframe=="MN1" ? PERIOD_MN1 : PERIOD_CURRENT ); } //+------------------------------------------------------------------+
CTimeSeriesクラスファイルで、IndexTimeframe()メソッドとTimeframeByIndex()メソッドの実装を削除します。
//+------------------------------------------------------------------+
//| Return the timeframe index in the list |
//+------------------------------------------------------------------+
char CTimeSeries::IndexTimeframe(ENUM_TIMEFRAMES timeframe) const
{
int statement=(timeframe==PERIOD_CURRENT ? ::Period() : timeframe);
switch(statement)
{
case PERIOD_M1 : return 0;
case PERIOD_M2 : return 1;
case PERIOD_M3 : return 2;
case PERIOD_M4 : return 3;
case PERIOD_M5 : return 4;
case PERIOD_M6 : return 5;
case PERIOD_M10 : return 6;
case PERIOD_M12 : return 7;
case PERIOD_M15 : return 8;
case PERIOD_M20 : return 9;
case PERIOD_M30 : return 10;
case PERIOD_H1 : return 11;
case PERIOD_H2 : return 12;
case PERIOD_H3 : return 13;
case PERIOD_H4 : return 14;
case PERIOD_H6 : return 15;
case PERIOD_H8 : return 16;
case PERIOD_H12 : return 17;
case PERIOD_D1 : return 18;
case PERIOD_W1 : return 19;
case PERIOD_MN1 : return 20;
default : ::Print(DFUN,CMessage::Text(MSG_LIB_TEXT_TS_TEXT_UNKNOWN_TIMEFRAME)); return WRONG_VALUE;
}
}
//+------------------------------------------------------------------+
//| Return a timeframe by index |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES CTimeSeries::TimeframeByIndex(const uchar index) const
{
switch(index)
{
case 0 : return PERIOD_M1;
case 1 : return PERIOD_M2;
case 2 : return PERIOD_M3;
case 3 : return PERIOD_M4;
case 4 : return PERIOD_M5;
case 5 : return PERIOD_M6;
case 6 : return PERIOD_M10;
case 7 : return PERIOD_M12;
case 8 : return PERIOD_M15;
case 9 : return PERIOD_M20;
case 10 : return PERIOD_M30;
case 11 : return PERIOD_H1;
case 12 : return PERIOD_H2;
case 13 : return PERIOD_H3;
case 14 : return PERIOD_H4;
case 15 : return PERIOD_H6;
case 16 : return PERIOD_H8;
case 17 : return PERIOD_H12;
case 18 : return PERIOD_D1;
case 19 : return PERIOD_W1;
case 20 : return PERIOD_MN1;
default : ::Print(DFUN,CMessage::Text(MSG_LIB_SYS_NOT_GET_DATAS),"... ",CMessage::Text(MSG_SYM_STATUS_INDEX),": ",(string)index); return WRONG_VALUE;
}
}
//+------------------------------------------------------------------+
メソッドの代わりに、サービス関数のDELib.mqhファイルから関数を呼び出します。
//--- Return (1) the timeframe index in the list and (2) the timeframe by the list index char IndexTimeframe(const ENUM_TIMEFRAMES timeframe) const { return IndexEnumTimeframe(timeframe)-1; } ENUM_TIMEFRAMES TimeframeByIndex(const uchar index) const { return TimeframeByEnumIndex(uchar(index+1)); }
クラス時系列のリストにはすべての可能なチャート期間が含まれているため、ゼロリストインデックスにはM1チャート期間の時系列が含まれています。ENUM_TIMEFRAMES列挙には、ゼロインデックスにPERIOD_CURRENTが含まれていますが、最初のインデックスにはМ1が含まれているため、リスト内の正しいインデックスを取得するには、インデックス値を1だけシフトする必要があります。これがまさにここで行っていることです。
クラスのprivateセクションには、サーバおよびターミナルでの履歴の最初の日付を設定するための2つのクラスメンバ変数、およびこれらの日付の値を変数に設定するメソッドを追加します。
//+------------------------------------------------------------------+ //| Symbol timeseries class | //+------------------------------------------------------------------+ class CTimeSeries : public CBaseObj { private: string m_symbol; // Timeseries symbol CArrayObj m_list_series; // List of timeseries by timeframes datetime m_server_firstdate; // The very first date in history by a server symbol datetime m_terminal_firstdate; // The very first date in history by a symbol in the client terminal //--- Return (1) the timeframe index in the list and (2) the timeframe by the list index char IndexTimeframe(const ENUM_TIMEFRAMES timeframe) const { return IndexEnumTimeframe(timeframe)-1; } ENUM_TIMEFRAMES TimeframeByIndex(const uchar index) const { return TimeframeByEnumIndex(uchar(index+1)); } //--- Set the very first date in history by symbol on the server and in the client terminal void SetTerminalServerDate(void) { this.m_server_firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,::Period(),SERIES_SERVER_FIRSTDATE); this.m_terminal_firstdate=(datetime)::SeriesInfoInteger(this.m_symbol,::Period(),SERIES_TERMINAL_FIRSTDATE); } public:
m_server_firstdate変数は、SERIES_SERVER_FIRSTDATEプロパティIDでSeriesInfoInteger()関数によって取得された、サーバ上の銘柄によって、履歴の最初の日付を銘柄で格納します。
m_terminal_firstdate変数は、SERIES_TERMINAL_FIRSTDATEプロパティIDでSeriesInfoInteger()関数によって取得された、ターミナル上の銘柄によって、履歴の最初の日付を銘柄で格納します。
6つの新規メソッドおよびパラメトリックコンストラクタがクラスのpublicセクションに追加されました。
public: //--- Return (1) oneself, (2) the full list of timeseries, (3) specified timeseries object and (4) timeseries object by index CTimeSeries *GetObject(void) { return &this; } CArrayObj *GetListSeries(void) { return &this.m_list_series; } CSeries *GetSeries(const ENUM_TIMEFRAMES timeframe) { return this.m_list_series.At(this.IndexTimeframe(timeframe)); } CSeries *GetSeriesByIndex(const uchar index) { return this.m_list_series.At(index); } //--- Set/return timeseries symbol void SetSymbol(const string symbol) { this.m_symbol=(symbol==NULL || symbol=="" ? ::Symbol() : symbol); } string Symbol(void) const { return this.m_symbol; } //--- Set the history depth (1) of a specified timeseries and (2) of all applied symbol timeseries bool SetRequiredUsedData(const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0); bool SetRequiredAllUsedData(const uint required=0,const int rates_total=0); //--- Return the flag of data synchronization with the server data of the (1) specified timeseries, (2) all timeseries bool SyncData(const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0); bool SyncAllData(const uint required=0,const int rates_total=0); //--- Return the very first date in history by symbol (1) on the server and (2) in the client terminal datetime ServerFirstDate(void) const { return this.m_server_firstdate; } datetime TerminalFirstDate(void) const { return this.m_terminal_firstdate; } //--- Create (1) the specified timeseries list and (2) all timeseries lists bool Create(const ENUM_TIMEFRAMES timeframe,const uint required=0); bool CreateAll(const uint required=0); //--- Update (1) the specified timeseries list and (2) all timeseries lists void Refresh(const ENUM_TIMEFRAMES timeframe, 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); void RefreshAll(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); //--- Compare CTimeSeries objects (by symbol) virtual int Compare(const CObject *node,const int mode=0) const; //--- Display (1) description and (2) short symbol timeseries description in the journal void Print(const bool created=true); void PrintShort(const bool created=true); //--- Constructors CTimeSeries(void){;} CTimeSeries(const string symbol); }; //+------------------------------------------------------------------+
GetObject()メソッドはクラスオブジェクトへのポインタを返します。これにより、銘柄時系列クラスオブジェクトを受け取り、カスタムプログラムで操作できます。
ServerFirstDate()メソッドとTerminalFirstDate()メソッドは上記のm_server_firstdate変数と m_terminal_firstdate変数の値を返します。
Compare()仮想メソッドを使用すると、2つの時系列オブジェクトを時系列銘柄名で比較できます。
//+------------------------------------------------------------------+ //| Compare CTimeSeries objects | //+------------------------------------------------------------------+ int CTimeSeries::Compare(const CObject *node,const int mode=0) const { const CTimeSeries *compared_obj=node; return(this.Symbol()>compared_obj.Symbol() ? 1 : this.Symbol()<compared_obj.Symbol() ? -1 : 0); } //+------------------------------------------------------------------+
メソッドは、2つの比較された時系列オブジェクトの銘柄が等しい場合はゼロを返し、それ以外の場合は+/-1を返します。メソッドは標準ライブラリのCObjectクラスで宣言されていて、子孫で再定義されます。
Print()メソッドは、すべての銘柄時系列の完全な説明を操作ログに表示します。
//+------------------------------------------------------------------+ //| Display descriptions of all symbol timeseries in the journal | //+------------------------------------------------------------------+ void CTimeSeries::Print(const bool created=true) { ::Print(CMessage::Text(MSG_LIB_TEXT_TS_TEXT_SYMBOL_TIMESERIES)," ",this.m_symbol,": "); for(int i=0;i<this.m_list_series.Total();i++) { CSeries *series=this.m_list_series.At(i); if(series==NULL || (created && series.DataTotal()==0)) continue; series.Print(); } } //+------------------------------------------------------------------+
操作ログは、作成されたすべての(created=true)または作成および宣言された(created=false)銘柄時系列のリストを適切な形式で表示します。次に例を示します。
created=true:
GBPUSD symbol timeseries: Timeseries "GBPUSD" M1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 6296 Timeseries "GBPUSD" M5: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 3921 Timeseries "GBPUSD" M15: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 3227 Timeseries "GBPUSD" M30: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 3053 Timeseries "GBPUSD" H1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 6187 Timeseries "GBPUSD" H4: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 5298 Timeseries "GBPUSD" D1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 5288 Timeseries "GBPUSD" W1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 1398 Timeseries "GBPUSD" MN1: Requested history depth: 1000, Actual history depth: 321, Historical data created: 321, History bars on the server: 321
created=false:
GBPUSD symbol timeseries: Timeseries "GBPUSD" M1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 6296 Timeseries "GBPUSD" M2: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 5483 Timeseries "GBPUSD" M3: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 4616 Timeseries "GBPUSD" M4: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 4182 Timeseries "GBPUSD" M5: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 3921 Timeseries "GBPUSD" M6: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 3748 Timeseries "GBPUSD" M10: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 3401 Timeseries "GBPUSD" M12: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 3314 Timeseries "GBPUSD" M15: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 3227 Timeseries "GBPUSD" M20: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 3140 Timeseries "GBPUSD" M30: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 3053 Timeseries "GBPUSD" H1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 6187 Timeseries "GBPUSD" H2: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 5047 Timeseries "GBPUSD" H3: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 5031 Timeseries "GBPUSD" H4: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 5298 Timeseries "GBPUSD" H6: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 6324 Timeseries "GBPUSD" H8: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 6301 Timeseries "GBPUSD" H12: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 0, History bars on the server: 5762 Timeseries "GBPUSD" D1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 5288 Timeseries "GBPUSD" W1: Requested history depth: 1000, Actual history depth: 1000, Historical data created: 1000, History bars on the server: 1398 Timeseries "GBPUSD" MN1: Requested history depth: 1000, Actual history depth: 321, Historical data created: 321, History bars on the server: 321
PrintShort()メソッドは、すべての銘柄時系列の短い説明を操作ログに表示します。
//+-------------------------------------------------------------------+ //| Display short descriptions of all symbol timeseries in the journal| //+-------------------------------------------------------------------+ void CTimeSeries::PrintShort(const bool created=true) { ::Print(CMessage::Text(MSG_LIB_TEXT_TS_TEXT_SYMBOL_TIMESERIES)," ",this.m_symbol,": "); for(int i=0;i<this.m_list_series.Total();i++) { CSeries *series=this.m_list_series.At(i); if(series==NULL || (created && series.DataTotal()==0)) continue; series.PrintShort(); } } //+------------------------------------------------------------------+
操作ログは、作成されたすべての(created=true)または作成および宣言された(created=false)銘柄時系列のリストを適切な形式で表示します。次に例を示します。
created=true:
USDJPY symbol timeseries: Timeseries "USDJPY" M1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2880 Timeseries "USDJPY" M5: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3921 Timeseries "USDJPY" M15: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3227 Timeseries "USDJPY" M30: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3053 Timeseries "USDJPY" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5095 Timeseries "USDJPY" H4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5023 Timeseries "USDJPY" D1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5305 Timeseries "USDJPY" W1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2562 Timeseries "USDJPY" MN1: Requested: 1000, Actual: 589, Created: 589, On the server: 589
created=false:
USDJPY symbol timeseries: Timeseries "USDJPY" M1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2880 Timeseries "USDJPY" M2: Requested: 1000, Actual: 1000, Created: 0, On the server: 3608 Timeseries "USDJPY" M3: Requested: 1000, Actual: 1000, Created: 0, On the server: 4616 Timeseries "USDJPY" M4: Requested: 1000, Actual: 1000, Created: 0, On the server: 4182 Timeseries "USDJPY" M5: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3921 Timeseries "USDJPY" M6: Requested: 1000, Actual: 1000, Created: 0, On the server: 3748 Timeseries "USDJPY" M10: Requested: 1000, Actual: 1000, Created: 0, On the server: 3401 Timeseries "USDJPY" M12: Requested: 1000, Actual: 1000, Created: 0, On the server: 3314 Timeseries "USDJPY" M15: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3227 Timeseries "USDJPY" M20: Requested: 1000, Actual: 1000, Created: 0, On the server: 3140 Timeseries "USDJPY" M30: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3053 Timeseries "USDJPY" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5095 Timeseries "USDJPY" H2: Requested: 1000, Actual: 1000, Created: 0, On the server: 5047 Timeseries "USDJPY" H3: Requested: 1000, Actual: 1000, Created: 0, On the server: 5031 Timeseries "USDJPY" H4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5023 Timeseries "USDJPY" H6: Requested: 1000, Actual: 1000, Created: 0, On the server: 6390 Timeseries "USDJPY" H8: Requested: 1000, Actual: 1000, Created: 0, On the server: 6352 Timeseries "USDJPY" H12: Requested: 1000, Actual: 1000, Created: 0, On the server: 5796 Timeseries "USDJPY" D1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5305 Timeseries "USDJPY" W1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2562 Timeseries "USDJPY" MN1: Requested: 1000, Actual: 589, Created: 589, On the server: 589
クラスコンストラクタで時系列の日付を設定します。
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTimeSeries::CTimeSeries(const string symbol) : m_symbol(symbol) { this.m_list_series.Clear(); this.m_list_series.Sort(); for(int i=0;i<21;i++) { ENUM_TIMEFRAMES timeframe=this.TimeframeByIndex((uchar)i); CSeries *series_obj=new CSeries(this.m_symbol,timeframe); this.m_list_series.Add(series_obj); } this.SetTerminalServerDate(); } //+------------------------------------------------------------------+
指定された時系列更新メソッドは、更新された時系列の「新しいバー」イベントが検出されたときに時系列日付を設定 します。
//+------------------------------------------------------------------+ //| Update a specified timeseries list | //+------------------------------------------------------------------+ void CTimeSeries::Refresh(const ENUM_TIMEFRAMES timeframe, 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) { CSeries *series_obj=this.m_list_series.At(this.IndexTimeframe(timeframe)); if(series_obj==NULL || series_obj.DataTotal()==0) return; series_obj.Refresh(time,open,high,low,close,tick_volume,volume,spread); if(series_obj.IsNewBar(time)) this.SetTerminalServerDate(); } //+------------------------------------------------------------------+
すべての時系列を更新するメソッドには、時系列日付の更新も含まれます。
//+------------------------------------------------------------------+ //| Update all timeseries lists | //+------------------------------------------------------------------+ void CTimeSeries::RefreshAll(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) { bool upd=false; for(int i=0;i<21;i++) { CSeries *series_obj=this.m_list_series.At(i); if(series_obj==NULL || series_obj.DataTotal()==0) continue; series_obj.Refresh(time,open,high,low,close,tick_volume,volume,spread); if(series_obj.IsNewBar(time)) upd &=true; } if(upd) this.SetTerminalServerDate(); } //+------------------------------------------------------------------+
ただし、ここでは1度だけ日付を更新する必要があります。これは、リストに存在する更新された時系列のいずれかで「新しいバー」イベントが検出された場合(21の時系列があり、同じ日付を21回設定したくありません)。したがって「新しいバー」イベントがすべての時系列でループで満たされたときに日付を更新する必要があるというフラグがtrueに設定されます。ループが完了し、有効化フラグの場合は、日付を更新します。
これでCTimeSeriesクラスの改善は終わりです。ここでは、小さな変更は考慮していません。それらのすべては添付ファイルでご覧になれます。
現在、時系列コレクションを作成するために必要なすべてのデータを含む3つのクラスがあります。
- CBar「単一銘柄の単一期間バー」には、指定された期間の指定された銘柄の単一バーのデータが含まれます。
- CSeriesの「単一銘柄の単一期間時系列」は、単一銘柄の単一期間のバーリストコレクション(1)を有効にします。
- CTimeSeries「単一銘柄の全期間時系列」には、単一銘柄の各期間の時系列のリスト(2)が含まれています。
次に、プログラムで使用される各銘柄の時系列リストコレクションである時系列コレクション(3)を作成します。
銘柄と期間による時系列オブジェクトのコレクションクラス
時系列コレクションは、CObjectクラスインスタンスへのポインタの動的配列とその子孫( CTimeSeriesクラスオブジェクトへのポインタ)で構成されます 。
\MQL5\Include\DoEasy\Collections\ライブラリフォルダで、CTimeSeriesCollectionクラスのTimeSeriesCollection.mqhファイルを作成します。
基本クラスオブジェクトはCObject標準ライブラリを構築するための基本オブジェクトです。
クラスを見てみましょう。
//+------------------------------------------------------------------+ //| TimeSeriesCollection.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 "..\Objects\Series\TimeSeries.mqh" #include "..\Objects\Symbols\Symbol.mqh" //+------------------------------------------------------------------+ //| Symbol timeseries collection | //+------------------------------------------------------------------+ class CTimeSeriesCollection : public CObject { private: CArrayObj m_list; // List of applied symbol timeseries //--- Return the timeseries index by symbol name int IndexTimeSeries(const string symbol); public: //--- Return (1) oneself and (2) the timeseries list CTimeSeriesCollection *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list; } //--- Create the symbol timeseries list collection bool CreateCollection(const CArrayObj *list_symbols); //--- Set the flag of using (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols void SetAvailable(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag=true); void SetAvailable(const ENUM_TIMEFRAMES timeframe,const bool flag=true); void SetAvailable(const string symbol,const bool flag=true); void SetAvailable(const bool flag=true); //--- Get the flag of using (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols bool IsAvailable(const string symbol,const ENUM_TIMEFRAMES timeframe); bool IsAvailable(const ENUM_TIMEFRAMES timeframe); bool IsAvailable(const string symbol); bool IsAvailable(void); //--- Set the history depth of (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols bool SetRequiredUsedData(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0); bool SetRequiredUsedData(const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0); bool SetRequiredUsedData(const string symbol,const uint required=0,const int rates_total=0); bool SetRequiredUsedData(const uint required=0,const int rates_total=0); //--- Return the flag of data synchronization with the server data of the (1) specified timeseries of the specified symbol, //--- (2) the specified timeseries of all symbols, (3) all timeseries of the specified symbol and (4) all timeseries of all symbols bool SyncData(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0); bool SyncData(const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0); bool SyncData(const string symbol,const uint required=0,const int rates_total=0); bool SyncData(const uint required=0,const int rates_total=0); //--- Create (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols, //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols bool CreateSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0); bool CreateSeries(const ENUM_TIMEFRAMES timeframe,const uint required=0); bool CreateSeries(const string symbol,const uint required=0); bool CreateSeries(const uint required=0); //--- Update (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols, //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols void Refresh(const string symbol,const ENUM_TIMEFRAMES timeframe, 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); void Refresh(const ENUM_TIMEFRAMES timeframe, 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); void Refresh(const string symbol, 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); 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); //--- Display (1) the complete and (2) short collection description in the journal void Print(const bool created=true); void PrintShort(const bool created=true); //--- Constructor CTimeSeriesCollection(); }; //+------------------------------------------------------------------+
現時点では、このクラスは時系列オブジェクトのリストであり、パラメータを作成/設定し、必要な時系列を銘柄と期間ごとに更新するメソッドです。
m_list CObjectクラスオブジェクトへのポインタの配列には、CTimeSeriesクラスオブジェクトへのポインタが含まれます。これはリストであり、そこから作業に必要な時系列のデータを取得します。
銘柄名で時系列インデックスを返すIndexTimeSeries()メソッドを使用すると、必要なCTimeSeriesオブジェクトに銘柄名でアクセスできます。
//+------------------------------------------------------------------+ //| Return the timeseries index by symbol name | //+------------------------------------------------------------------+ int CTimeSeriesCollection::IndexTimeSeries(const string symbol) { CTimeSeries *tmp=new CTimeSeries(symbol); if(tmp==NULL) return WRONG_VALUE; this.m_list.Sort(); int index=this.m_list.Search(tmp); delete tmp; return index; } //+------------------------------------------------------------------+
メソッドに渡された銘柄値で新しい一時的な時系列オブジェクトを作成し、 m_listリストの「並び替え済み」フラグを設定し、Search()メソッドを使用して、リスト内のオブジェクトインデックスを取得します。
必ず一時的な時系列オブジェクトを削除し、取得したインデックスを返します。
指定された銘柄を持つオブジェクトがリストにない場合、メソッドは-1を返します。それ以外の場合は、検出されたオブジェクトのインデックス値を返します。
GetObject()メソッドは、時系列コレクションオブジェクトへのポインタを制御プログラムに返します。これにより、コレクションオブジェクト全体を取得して、カスタムプログラムで操作できます。
GetList()メソッドは、CTimeSeries時系列コレクションリストへのポインタを返します。すべての銘柄の時系列のリストを取得し、カスタムプログラムで操作できます。
CreateCollection()メソッドは、時系列オブジェクトの空のコレクションを作成します。
//+------------------------------------------------------------------+ //| Create the symbol timeseries collection list | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::CreateCollection(const CArrayObj *list_symbols) { //--- If an empty list of symbol objects is passed, exit if(list_symbols==NULL) return false; //--- Get the number of symbol objects in the passed list int total=list_symbols.Total(); //--- Clear the timeseries collection list this.m_list.Clear(); //--- In a loop by all symbol objects for(int i=0;i<total;i++) { //--- get the next symbol object CSymbol *symbol_obj=list_symbols.At(i); //--- if failed to get a symbol object, move on to the next one in the list if(symbol_obj==NULL) continue; //--- Create a new timeseries object with the current symbol name CTimeSeries *timeseries=new CTimeSeries(symbol_obj.Name()); //--- If failed to create the timeseries object, move on to the next symbol in the list if(timeseries==NULL) continue; //--- Set the sorted list flag for the timeseries collection list this.m_list.Sort(); //--- If the object with the same symbol name is already present in the timeseries collection list, remove the timeseries object if(this.m_list.Search(timeseries)>WRONG_VALUE) delete timeseries; //--- if failed to add the timeseries object to the collection list, remove the timeseries object else if(!this.m_list.Add(timeseries)) delete timeseries; } //--- Return the flag indicating that the created collection list has a size greater than zero return this.m_list.Total()>0; } //+-----------------------------------------------------------------------+
各メソッド文字列には、そのリストにコメントが付いています。
プログラムで以前に作成されたすべての銘柄のリストがメソッドに渡され、CTimeSeries時系列オブジェクトがリストに沿ってループで作成されます。銘柄名はすぐに指定されます。したがって、プログラムで使用される銘柄の数によって時系列コレクションリストを取得します。作成された銘柄オブジェクトの残りのデータはすべて空のままです。個別に設定する必要があります。
これは、ライブラリが常に、作業用に指定された銘柄の数に等しい量の空の時系列のコレクションリストを持つように行われます。時間枠とその時系列オブジェクト(ユーザはプログラムで作業することになります)は、次のステップで、または必要に応じて設定されます。
特にプログラムが「コールド」起動された場合、多数の時系列の作成には時間がかかるため、プログラムのOnInit()ハンドラで、または起動直後にそれらを作成することをお勧めします。
4つのオーバーロードされたSetAvailable()メソッドを使用して、指定された時系列でプログラムで作業する必要があることを示すフラグを設定します。
以下は、指定された銘柄の指定された時系列を使用するフラグを設定するメソッドです。
//+-----------------------------------------------------------------------+ //|Set the flag of using the specified timeseries of the specified symbol | //+-----------------------------------------------------------------------+ void CTimeSeriesCollection::SetAvailable(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag=true) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return; CSeries *series=timeseries.GetSeries(timeframe); if(series==NULL) return; series.SetAvailable(flag); } //+------------------------------------------------------------------+
メソッドは、銘柄、時間枠、および時間枠銘柄に対応する時系列に設定されるフラグを受け取ります。
まず、上で説明したIndexTimeSeries()メソッドを使用して、銘柄でm_listリスト内のCTimeSeries時系列インデックスを取得します。 インデックスでリストから時系列を取得します。取得した時系列オブジェクトから、前の記事で説明したGetSeries()メソッドを使用して指定されたチャート期間の必要なCSeries時系列を取得し、CBaseObjクラスのSetAvailable()メソッドを使用してそのメソッドに渡されるフラグを設定します。
以下は、すべての銘柄の指定された時系列を使用するフラグを設定するメソッドです。
//+------------------------------------------------------------------+ //|Set the flag of using the specified timeseries of all symbols | //+------------------------------------------------------------------+ void CTimeSeriesCollection::SetAvailable(const ENUM_TIMEFRAMES timeframe,const bool flag=true) { int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; CSeries *series=timeseries.GetSeries(timeframe); if(series==NULL) continue; series.SetAvailable(flag); } } //+------------------------------------------------------------------+
このメソッドは、すべての銘柄の指定された時系列に設定される時間枠とフラグを受け取ります。
すべての銘柄時系列のリストによるループで、ループインデックスによって次のCTimeSeries時系列を取得します。取得した時系列オブジェクトから、前の記事で説明したGetSeries()メソッドを使用して指定されたチャート期間の指定されたCSeries時系列を取得し、CBaseObjクラスのSetAvailable()メソッドを使用してそのメソッドに渡されるフラグを設定します。
以下は、指定された銘柄のすべての時系列を使用するフラグを設定するメソッドです。
//+------------------------------------------------------------------+ //|Set the flag of using all timeseries of the specified symbol | //+------------------------------------------------------------------+ void CTimeSeriesCollection::SetAvailable(const string symbol,const bool flag=true) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return; CArrayObj *list=timeseries.GetListSeries(); if(list==NULL) return; int total=list.Total(); for(int i=0;i<total;i++) { CSeries *series=list.At(i); if(series==NULL) continue; series.SetAvailable(flag); } } //+------------------------------------------------------------------+
このメソッドは、すべての銘柄の指定された時系列に設定される銘柄とフラグを受け取ります。
まず、上で説明したIndexTimeSeries()メソッドを使用して、m_listリスト内のCTimeSeries時系列インデックスを銘柄で取得 します。インデックスでリストからCTimeSeries時系列を取得します。取得した時系列オブジェクトから、GetListSeries()メソッドを使用して、すべてのCSeries時系列の完全なリストを取得します。取得したリストによるループで、 次のCSeries時系列を取得し、CBaseObjクラスのSetAvailable()メソッドを使用して、そのメソッドに渡されるフラグを設定します。
以下は、すべての銘柄の指定された時系列を使用するフラグを設定するメソッドです。
//+------------------------------------------------------------------+ //| Set the flag of using all timeseries of all symbols | //+------------------------------------------------------------------+ void CTimeSeriesCollection::SetAvailable(const bool flag=true) { int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; CArrayObj *list=timeseries.GetListSeries(); if(list==NULL) continue; int total_series=list.Total(); for(int j=0;j<total_series;j++) { CSeries *series=list.At(j); if(series==NULL) continue; series.SetAvailable(flag); } } } //+--------------------------------------------------------------------+
このメソッドは、すべての銘柄のすべての時系列に追加で設定する必要があるフラグを受け取ります。
時系列リストによるループで、ループインデックスによって次のCTimeSeries時系列オブジェクトを取得します。GetListSeries()メソッドを使用して、取得したオブジェクトからすべてのCSeries時系列のリストを取得します。CSeries時系列リストによるループで、ループインデックすで次の時系列を取得し、CBaseObjクラスのSetAvailable()メソッドを使用して、そのメソッドに渡されるフラグを設定します。
以下は、指定した、またはすべての時系列を使用するフラグを返す4つのメソッドです。
//+-------------------------------------------------------------------------+ //|Return the flag of using the specified timeseries of the specified symbol| //+-------------------------------------------------------------------------+ bool CTimeSeriesCollection::IsAvailable(const string symbol,const ENUM_TIMEFRAMES timeframe) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return false; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return false; CSeries *series=timeseries.GetSeries(timeframe); if(series==NULL) return false; return series.IsAvailable(); } //+------------------------------------------------------------------+ //| Return the flag of using the specified timeseries of all symbols | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::IsAvailable(const ENUM_TIMEFRAMES timeframe) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; CSeries *series=timeseries.GetSeries(timeframe); if(series==NULL) continue; res &=series.IsAvailable(); } return res; } //+------------------------------------------------------------------+ //| Return the flag of using all timeseries of the specified symbol | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::IsAvailable(const string symbol) { bool res=true; int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return false; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return false; CArrayObj *list=timeseries.GetListSeries(); if(list==NULL) return false; int total=list.Total(); for(int i=0;i<total;i++) { CSeries *series=list.At(i); if(series==NULL) continue; res &=series.IsAvailable(); } return res; } //+------------------------------------------------------------------+ //| Return the flag of using all timeseries of all symbols | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::IsAvailable(void) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; CArrayObj *list=timeseries.GetListSeries(); if(list==NULL) continue; int total_series=list.Total(); for(int j=0;j<total_series;j++) { CSeries *series=list.At(j); if(series==NULL) continue; res &=series.IsAvailable(); } } return res; } //+--------------------------------------------------------------------+
メソッドは、上で説明した時系列のフラグを設定するメソッドと同様に機能します。違いは、trueの初期状態を持つresローカル変数を使用して、 複数の時系列を使用する共通のフラグを返すメソッドですべての時系列から「集合」フラグを取得することです。CSeries時系列によるループで、チェックされた各時系列のフラグステータスが変数に書き込まれます。時系列の少なくとも1つがfalseと等しい場合、変数にfalseフラグが設定されます。変数の値は、すべての時系列のすべてのループが完了すると、メソッドから返されます。
以下は、指定された時系列またはすべての時系列に一度に必要な深度履歴を設定する4つのメソッドです。
//+--------------------------------------------------------------------------+ //|Set the history depth for the specified timeseries of the specified symbol| //+--------------------------------------------------------------------------+ bool CTimeSeriesCollection::SetRequiredUsedData(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return false; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return false; CSeries *series=timeseries.GetSeries(timeframe); if(series==NULL) return false; return series.SetRequiredUsedData(required,rates_total); } //+------------------------------------------------------------------+ //| Set the history depth of the specified timeseries of all symbols | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::SetRequiredUsedData(const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; CSeries *series=timeseries.GetSeries(timeframe); if(series==NULL) continue; res &=series.SetRequiredUsedData(required,rates_total); } return res; } //+------------------------------------------------------------------+ //| Set the history depth for all timeseries of the specified symbol | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::SetRequiredUsedData(const string symbol,const uint required=0,const int rates_total=0) { bool res=true; int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return false; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return false; CArrayObj *list=timeseries.GetListSeries(); if(list==NULL) return false; int total=list.Total(); for(int i=0;i<total;i++) { CSeries *series=list.At(i); if(series==NULL) continue; res &=series.SetRequiredUsedData(required,rates_total); } return res; } //+------------------------------------------------------------------+ //| Set the history depth for all timeseries of all symbols | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::SetRequiredUsedData(const uint required=0,const int rates_total=0) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; CArrayObj *list=timeseries.GetListSeries(); if(list==NULL) continue; int total_series=list.Total(); for(int j=0;j<total_series;j++) { CSeries *series=list.At(j); if(series==NULL) continue; res &=series.SetRequiredUsedData(required,rates_total); } } return res; } //+------------------------------------------------------------------+
これらのメソッドは、時系列使用フラグを返すメソッドと同様に機能します。これらは、ブール値を返すSetRequiredUsedData()メソッドを使用して、CSeries時系列オブジェクトに要求された量のデータを設定した結果を返します。したがって、複数のCSeries時系列の履歴の深さを設定するときに使用される共通のフラグは、ここでも適用されます。
以下は、指定した、またはすべての時系列のいずれかを同期するフラグを返す4つのメソッドです。
//+------------------------------------------------------------------+ //| Return the flag of data synchronization with the server data | //| for a specified timeseries of a specified symbol | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::SyncData(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return false; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return false; CSeries *series=timeseries.GetSeries(timeframe); if(series==NULL) return false; return series.SyncData(required,rates_total); } //+------------------------------------------------------------------+ //| Return the flag of data synchronization with the server data | //| for a specified timeseries of all symbols | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::SyncData(const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; CSeries *series=timeseries.GetSeries(timeframe); if(series==NULL) continue; res &=series.SyncData(required,rates_total); } return res; } //+------------------------------------------------------------------+ //| Return the flag of data synchronization with the server data | //| for all timeseries of a specified symbol | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::SyncData(const string symbol,const uint required=0,const int rates_total=0) { bool res=true; int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return false; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return false; CArrayObj *list=timeseries.GetListSeries(); if(list==NULL) return false; int total=list.Total(); for(int i=0;i<total;i++) { CSeries *series=list.At(i); if(series==NULL) continue; res &=series.SyncData(required,rates_total); } return res; } //+------------------------------------------------------------------+ //| Return the flag of data synchronization with the server data | //| for all timeseries of all symbols | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::SyncData(const uint required=0,const int rates_total=0) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; CArrayObj *list=timeseries.GetListSeries(); if(list==NULL) continue; int total_series=list.Total(); for(int j=0;j<total_series;j++) { CSeries *series=list.At(j); if(series==NULL) continue; res &=series.SyncData(required,rates_total); } } return res; } //+------------------------------------------------------------------+
メソッドは、上記のメソッドと同様に機能します。これらは、CSeriesクラスのSyncData()メソッドを使用して時系列同期を確認した結果を返します。
指定した、またはすべての時系列を作成するための4つのメソッドです。
以下は、指定された銘柄の指定された時系列を作成するメソッドです。
//+------------------------------------------------------------------+ //| Create the specified timeseries of the specified symbol | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::CreateSeries(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return false; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return false; return timeseries.Create(timeframe,required); } //+------------------------------------------------------------------+
このメソッドは、時系列を作成する必要がある銘柄を受け取ります。時系列期間もメソッドに渡されます。
IndexTimeSeries()メソッドを使用して銘柄名でリストの時系列インデックスを取得します。取得したインデックスを使用して、リストからCTimeSeries時系列を取得し、CTimeSeriesクラスのCreate()メソッドを使用して指定した時系列を作成した結果を返します 。
以下は、すべての銘柄の指定された時系列を作成するメソッドです。
//+------------------------------------------------------------------+ //| Create the specified timeseries of all symbols | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::CreateSeries(const ENUM_TIMEFRAMES timeframe,const uint required=0) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; res &=timeseries.Create(timeframe,required); } return res; } //+------------------------------------------------------------------+
このメソッドは、時系列を作成する必要がある時間枠を受け取ります。
すべてのオブジェクト時系列のオブジェクトによるループで、ループインデックスによって次のCTimeSeries時系列を取得します。res 変数に、CTimeSeriesクラスのCreate()メソッドを使用して、指定された時系列を作成した結果を追加します。ループが完了すると、すべての銘柄に対して指定された時系列を作成した結果が返されます。少なくとも1つの時系列が作成されていない場合、結果はfalseになります。
以下は、指定された銘柄のすべての時系列を作成するメソッドです。
//+------------------------------------------------------------------+ //| Create all timeseries of the specified symbol | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::CreateSeries(const string symbol,const uint required=0) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return false; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return false; return timeseries.CreateAll(required); } //+------------------------------------------------------------------+
このメソッドは、時系列を作成する必要がある銘柄を受け取ります。
IndexTimeSeries()メソッドを使用して銘柄名でリストの時系列インデックスを取得します。取得したインデックスを使用して、リストからCTimeSeries時系列を取得し、CTimeSeriesクラスのCreateAll()メソッドを使用してすべての時系列を作成した結果を返します 。
以下は、すべての銘柄のすべての時系列を作成するメソッドです。
//+------------------------------------------------------------------+ //| Create all timeseries of all symbols | //+------------------------------------------------------------------+ bool CTimeSeriesCollection::CreateSeries(const uint required=0) { bool res=true; int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; res &=timeseries.CreateAll(required); } return res; } //+------------------------------------------------------------------+
このメソッドは、作成された履歴の深さの数のみを受け取ります(上記のすべてのメソッドと同様)。デフォルトで0が渡されます。これは、Defines.mqhファイルのSERIES_DEFAULT_BARS_COUNTマクロ置換によって設定された1000バーの履歴の深さを意味します。
時系列リストによるループで、ループインデックスによって次のCTimeSeries時系列オブジェクトを取得します。res変数は、CTimeSeriesオブジェクトのすべての銘柄時系列を作成するフラグを返すCreateAll()メソッドを使用して、CTimeSeries現在のオブジェクト銘柄のすべての時系列を作成した結果を受け取ります。
ループが完了すると、すべての銘柄のすべての時系列を作成した結果が返されます。少なくとも1つの時系列が作成されていない場合、結果はfalseになります。
以下は、指定された銘柄の指定された時系列またはすべての時系列を更新する4つのメソッドです。
//+------------------------------------------------------------------+ //| Update the specified timeseries of the specified symbol | //+------------------------------------------------------------------+ void CTimeSeriesCollection::Refresh(const string symbol,const ENUM_TIMEFRAMES timeframe, 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) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return; timeseries.Refresh(timeframe,time,open,high,low,close,tick_volume,volume,spread); } //+------------------------------------------------------------------+ //| Update the specified timeseries of all symbols | //+------------------------------------------------------------------+ void CTimeSeriesCollection::Refresh(const ENUM_TIMEFRAMES timeframe, 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) { int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; timeseries.Refresh(timeframe,time,open,high,low,close,tick_volume,volume,spread); } } //+------------------------------------------------------------------+ //| Update all timeseries of the specified symbol | //+------------------------------------------------------------------+ void CTimeSeriesCollection::Refresh(const string symbol, 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) { int index=this.IndexTimeSeries(symbol); if(index==WRONG_VALUE) return; CTimeSeries *timeseries=this.m_list.At(index); if(timeseries==NULL) return; timeseries.RefreshAll(time,open,high,low,close,tick_volume,volume,spread); } //+------------------------------------------------------------------+ //| Update all timeseries of all symbols | //+------------------------------------------------------------------+ void CTimeSeriesCollection::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) { int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; timeseries.RefreshAll(time,open,high,low,close,tick_volume,volume,spread); } } //+------------------------------------------------------------------+
ここでは、必要なCTimeSeries時系列オブジェクトを何らかの方法で取得し(前のメソッドではすべての方法が考慮されています)、CTimeSeriesクラスの指定された単一の時系列またはすべての時系列を一度に更新するメソッド(Refresh()またはRefreshAll())を呼び出します。
時系列配列の現在のデータはすべてのメソッドに渡されます。これは、現在の銘柄の現在の期間の指標で機能するために必要です。残りの場合、渡された値は重要ではありません。したがって、デフォルト値を0に設定します。
以下は、完全なコレクションリストを操作ログに返すメソッドです。
//+------------------------------------------------------------------+ //| Display complete collection description to the journal | //+------------------------------------------------------------------+ void CTimeSeriesCollection::Print(const bool created=true) { int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; timeseries.Print(created); } } //+------------------------------------------------------------------+
このメソッドは、作成された時系列のみを操作ログに表示する必要があることを示すフラグを受け取ります。
時系列オブジェクトのリストによるループで、次のCTimeSeries時系列オブジェクトを取得し、同じ名前のメソッドを呼び出し、上記の演算結果が考慮されます 。その結果、すべてのコレクション銘柄の現在のすべての時系列のデータを操作ログで利用できます。
短いコレクションリストを操作ログに返すメソッドです。
//+------------------------------------------------------------------+ //| Display the short collection description in the journal | //+------------------------------------------------------------------+ void CTimeSeriesCollection::PrintShort(const bool created=true) { int total=this.m_list.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=this.m_list.At(i); if(timeseries==NULL) continue; timeseries.PrintShort(created); } } //+------------------------------------------------------------------+
このメソッドは、作成された時系列のみを操作ログに表示する必要があることを示すフラグを受け取ります。
時系列オブジェクトのリストによるループで、次のCTimeSeries時系列オブジェクトを取得し、同じ名前のメソッドを呼び出し、上記の演算結果が考慮されます 。その結果、すべてのコレクション銘柄の現在のすべての時系列のデータが簡単な形式で操作ログに表示されます。
時系列コレクションクラスの現在のバージョンの準備ができています。添付ファイルの完全なクラスリストを参照してください。
次に、作成された時系列コレクションへの外部アクセスと、作成された時系列のパラメータの便利な設定を調整する必要があります。
すべてのプログラムは、CEngineライブラリのメインオブジェクトからライブラリメソッドにアクセスします。
時系列コレクションにアクセスする機能をCEngineクラスファイルに追加します。
Engine.mqhファイルを\MQL5\Include\DoEasy\ライブラリディレクトリから開いて必要な変更を加えます。
CTimeSeriesクラスファイルは、以前のバージョンのCEngineクラスにその動作を確認するためだけに含まれていたため、含まれているファイルのリストから削除します。
//+------------------------------------------------------------------+ //| 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\TimeSeries.mqh" //+------------------------------------------------------------------+
時系列コレクションクラスのファイルを含めます。
//+------------------------------------------------------------------+ //| Engine.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://mql5.com/en/users/artmedia70 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://mql5.com/en/users/artmedia70" #property version "1.00" //+------------------------------------------------------------------+ //| Include files | //+------------------------------------------------------------------+ #include "Services\TimerCounter.mqh" #include "Collections\HistoryCollection.mqh" #include "Collections\MarketCollection.mqh" #include "Collections\EventsCollection.mqh" #include "Collections\AccountsCollection.mqh" #include "Collections\SymbolsCollection.mqh" #include "Collections\ResourceCollection.mqh" #include "Collections\TimeSeriesCollection.mqh" #include "TradingControl.mqh" //+------------------------------------------------------------------+
クラスのprivateセクションで、時系列コレクションクラス型の変数を宣言します。
//+------------------------------------------------------------------+ //| Library basis class | //+------------------------------------------------------------------+ class CEngine { private: CHistoryCollection m_history; // Collection of historical orders and deals CMarketCollection m_market; // Collection of market orders and deals CEventsCollection m_events; // Event collection CAccountsCollection m_accounts; // Account collection CSymbolsCollection m_symbols; // Symbol collection CTimeSeriesCollection m_series; // Timeseries collection CResourceCollection m_resource; // Resource list CTradingControl m_trading; // Trading management object CArrayObj m_list_counters; // List of timer counters
クラスのpublicセクションで、使用される銘柄のリストを設定するためのメソッドの実装を変更します。
//--- Set the list of (1) used symbols bool SetUsedSymbols(const string &array_symbols[]) { return this.m_symbols.SetUsedSymbols(array_symbols);}
現在の実装では、このメソッドは、銘柄コレクションクラスの銘柄のリストを設定する同じ名前のメソッドを呼び出します。ここで、銘柄コレクションに銘柄リストを設定した直後に、作成された銘柄コレクションリストに基づいて時系列コレクションを作成するのが最も便利です。
ここではメソッド宣言のみを残します。
//--- Set the list of used symbols in the symbol collection and create the collection of symbol timeseries bool SetUsedSymbols(const string &array_symbols[]);
クラス本体外に実装します。
//+------------------------------------------------------------------+ //| Set the list of used symbols in the symbol collection | //| and create the symbol timeseries collection | //+------------------------------------------------------------------+ bool CEngine::SetUsedSymbols(const string &array_symbols[]) { bool res=this.m_symbols.SetUsedSymbols(array_symbols); CArrayObj *list=this.GetListAllUsedSymbols(); if(list==NULL) return false; res&=this.m_series.CreateCollection(list); return res; } //+------------------------------------------------------------------+
ここでは、res変数を宣言し、銘柄コレクション内の銘柄リストを設定するメソッドの結果によってそれを初期化します。
次に、銘柄コレクションクラスから使用されている銘柄のリストを取得します。リストが作成されていない場合はfalseを返し、それ以外の場合は、銘柄コレクションリストに基づいて、時系列コレクションリストの作成結果をres変数に追加します。
メソッドから最終結果を返します。
時系列コレクションを操作するメソッドをクラスのpublicセクションに追加します。
//--- Return the list of pending requests CArrayObj *GetListPendingRequests(void) { return this.m_trading.GetListRequests(); } //--- Return (1) the timeseries collection and (2) the list of timeseries from the timeseries collection CTimeSeriesCollection *GetTimeSeriesCollection(void) { return &this.m_series; } CArrayObj *GetListTimeSeries(void) { return this.m_series.GetList(); } //--- Set the flag of using (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols void SeriesSetAvailable(const string symbol,const ENUM_TIMEFRAMES timeframe,const bool flag=true) { this.m_series.SetAvailable(symbol,timeframe,flag);} void SeriesSetAvailable(const ENUM_TIMEFRAMES timeframe,const bool flag=true) { this.m_series.SetAvailable(timeframe,flag); } void SeriesSetAvailable(const string symbol,const bool flag=true) { this.m_series.SetAvailable(symbol,flag); } void SeriesSetAvailable(const bool flag=true) { this.m_series.SetAvailable(flag); } //--- Set the history depth of (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols bool SeriesSetRequiredUsedData(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0) { return this.m_series.SetRequiredUsedData(symbol,timeframe,required,rates_total);} bool SeriesSetRequiredUsedData(const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0) { return this.m_series.SetRequiredUsedData(timeframe,required,rates_total); } bool SeriesSetRequiredUsedData(const string symbol,const uint required=0,const int rates_total=0) { return this.m_series.SetRequiredUsedData(symbol,required,rates_total); } bool SeriesSetRequiredUsedData(const uint required=0,const int rates_total=0) { return this.m_series.SetRequiredUsedData(required,rates_total); } //--- Return the flag of data synchronization with the server data of the (1) specified timeseries of the specified symbol, //--- (2) the specified timeseries of all symbols, (3) all timeseries of the specified symbol and (4) all timeseries of all symbols bool SeriesSyncData(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0) { return this.m_series.SyncData(symbol,timeframe,required,rates_total); } bool SeriesSyncData(const ENUM_TIMEFRAMES timeframe,const uint required=0,const int rates_total=0) { return this.m_series.SyncData(timeframe,required,rates_total); } bool SeriesSyncData(const string symbol,const uint required=0,const int rates_total=0) { return this.m_series.SyncData(symbol,required,rates_total); } bool SeriesSyncData(const uint required=0,const int rates_total=0) { return this.m_series.SyncData(required,rates_total); } //--- Create (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols, //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols bool SeriesCreate(const string symbol,const ENUM_TIMEFRAMES timeframe,const uint required=0) { return this.m_series.CreateSeries(symbol,timeframe,required); } bool SeriesCreate(const ENUM_TIMEFRAMES timeframe,const uint required=0) { return this.m_series.CreateSeries(timeframe,required); } bool SeriesCreate(const string symbol,const uint required=0) { return this.m_series.CreateSeries(symbol,required); } bool SeriesCreate(const uint required=0) { return this.m_series.CreateSeries(required); } //--- Update (1) the specified timeseries of the specified symbol, (2) the specified timeseries of all symbols, //--- (3) all timeseries of the specified symbol and (4) all timeseries of all symbols void SeriesRefresh(const string symbol,const ENUM_TIMEFRAMES timeframe, 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) { this.m_series.Refresh(symbol,timeframe,time,open,high,low,close,tick_volume,volume,spread); } void SeriesRefresh(const ENUM_TIMEFRAMES timeframe, 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) { this.m_series.Refresh(timeframe,time,open,high,low,close,tick_volume,volume,spread); } void SeriesRefresh(const string symbol, 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) { this.m_series.Refresh(symbol,time,open,high,low,close,tick_volume,volume,spread); } void SeriesRefresh(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) { this.m_series.Refresh(time,open,high,low,close,tick_volume,volume,spread); }
GetTimeSeriesCollection()メソッドは、時系列コレクションオブジェクトへのポインタを呼び出し側プログラムに返します。これにより、プログラム内のコレクションへのポインタを受け取り、それを効率的に操作できます。
GetListTimeSeries()メソッドは、コレクション時系列リストへのポインタを呼び出し側プログラムに返します。これにより、CTimeSeries timeseriesオブジェクトリストへのポインタを受け取り、効率的に操作できます。
SeriesSetAvailable()オーバーロードメソッドは、上記で検討したCTimeSeriesCollection()時系列コレクションクラスのSetAvailable()メソッドへのアクセスを提供します。
SeriesSetRequiredUsedData()オーバーロードメソッドは、上記で検討したCTimeSeriesCollection()時系列コレクションクラスのSetRequiredUsedData()メソッドへのアクセスを提供します。
SeriesSyncData()オーバーロードメソッドは、上記で検討したCTimeSeriesCollection()時系列コレクションクラスのSyncData()メソッドへのアクセスを提供します。
The SeriesCreate()オーバーロードメソッドは、上記で検討したCTimeSeriesCollection()時系列コレクションクラスのCreateSeries()メソッドへのアクセスを提供します。
SeriesRefresh()オーバーロードメソッドは、上記で検討したCTimeSeriesCollection()時系列コレクションクラスのRefresh()メソッドへのアクセスを提供します。
時系列コレクションクラスで必要な変更はこれですべてです。
テスト
前の記事からのEAを使用して、時系列コレクションの作成と入力をテストします。新しい\MQL5\Experts\TestDoEasy\Part37\フォルダでTestDoEasyPart37.mq5として保存します。
銘柄の操作モードを選択するために、Datas.mqhファイルに列挙型があります。
//+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work with the current symbol only SYMBOLS_MODE_DEFINES, // Work with the specified symbol list SYMBOLS_MODE_MARKET_WATCH, // Work with the Market Watch window symbols SYMBOLS_MODE_ALL // Work with the full symbol list }; //+------------------------------------------------------------------+
EA入力は変数を備えており、それらを使用して銘柄を選択できます。
sinput ENUM_SYMBOLS_MODE InpModeUsedSymbols = SYMBOLS_MODE_CURRENT; // Mode of used symbols list
変数の値に応じて、銘柄の配列が作成され、OnInitDoEasy()EA関数での初期化中にライブラリに渡されます。次に、作業用銘柄のリストがライブラリに作成されます。
動作中のEA時間枠のリストを選択して作成するには、同じ操作を実行する必要があります。
Datas.mqhファイルに新しい列挙を作成して、銘柄チャートの周期を持つ動作モードを選択します。
//+------------------------------------------------------------------+ //| Datas.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" //+------------------------------------------------------------------+ //| Macro substitutions | //+------------------------------------------------------------------+ #define INPUT_SEPARATOR (",") // Separator in the inputs string #define TOTAL_LANG (2) // Number of used languages //+------------------------------------------------------------------+ //| Enumerations | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Modes of working with symbols | //+------------------------------------------------------------------+ enum ENUM_SYMBOLS_MODE { SYMBOLS_MODE_CURRENT, // Work with the current symbol only SYMBOLS_MODE_DEFINES, // Work with the specified symbol list SYMBOLS_MODE_MARKET_WATCH, // Work with the Market Watch window symbols SYMBOLS_MODE_ALL // Work with the full symbol list }; //+------------------------------------------------------------------+ //| Mode of working with timeframes | //+------------------------------------------------------------------+ enum ENUM_TIMEFRAMES_MODE { TIMEFRAMES_MODE_CURRENT, // Work with the current timeframe only TIMEFRAMES_MODE_LIST, // Work with the specified timeframe list TIMEFRAMES_MODE_ALL // Work with the full timeframe list }; //+------------------------------------------------------------------+
サービス関数のファイルは、使用されるライブラリ銘柄の配列を準備するための関数を備えています。
//+------------------------------------------------------------------+ //| Prepare the symbol array for a symbol collection | //+------------------------------------------------------------------+ bool CreateUsedSymbolsArray(const ENUM_SYMBOLS_MODE mode_used_symbols,string defined_used_symbols,string &used_symbols_array[]) { //--- When working with the current symbol if(mode_used_symbols==SYMBOLS_MODE_CURRENT) { //--- Write the name of the current symbol to the only array cell ArrayResize(used_symbols_array,1); used_symbols_array[0]=Symbol(); return true; } //--- If working with a predefined symbol set (from the defined_used_symbols string) else if(mode_used_symbols==SYMBOLS_MODE_DEFINES) { //--- Set a comma as a separator string separator=","; //--- Replace erroneous separators with correct ones if(StringFind(defined_used_symbols,";")>WRONG_VALUE) StringReplace(defined_used_symbols,";",separator); if(StringFind(defined_used_symbols,":")>WRONG_VALUE) StringReplace(defined_used_symbols,":",separator); if(StringFind(defined_used_symbols,"|")>WRONG_VALUE) StringReplace(defined_used_symbols,"|",separator); if(StringFind(defined_used_symbols,"/")>WRONG_VALUE) StringReplace(defined_used_symbols,"/",separator); if(StringFind(defined_used_symbols,"\\")>WRONG_VALUE) StringReplace(defined_used_symbols,"\\",separator); if(StringFind(defined_used_symbols,"'")>WRONG_VALUE) StringReplace(defined_used_symbols,"'",separator); if(StringFind(defined_used_symbols,"-")>WRONG_VALUE) StringReplace(defined_used_symbols,"-",separator); if(StringFind(defined_used_symbols,"`")>WRONG_VALUE) StringReplace(defined_used_symbols,"`",separator); //--- Delete as long as there are spaces while(StringFind(defined_used_symbols," ")>WRONG_VALUE && !IsStopped()) StringReplace(defined_used_symbols," ",""); //--- As soon as there are double separators (after removing spaces between them), replace them with a separator while(StringFind(defined_used_symbols,separator+separator)>WRONG_VALUE && !IsStopped()) StringReplace(defined_used_symbols,separator+separator,separator); //--- If a single separator remains before the first symbol in the string, replace it with a space if(StringFind(defined_used_symbols,separator)==0) StringSetCharacter(defined_used_symbols,0,32); //--- If a single separator remains after the last symbol in the string, replace it with a space if(StringFind(defined_used_symbols,separator)==StringLen(defined_used_symbols)-1) StringSetCharacter(defined_used_symbols,StringLen(defined_used_symbols)-1,32); //--- Remove all redundant things to the left and right #ifdef __MQL5__ StringTrimLeft(defined_used_symbols); StringTrimRight(defined_used_symbols); //--- __MQL4__ #else defined_used_symbols=StringTrimLeft(defined_used_symbols); defined_used_symbols=StringTrimRight(defined_used_symbols); #endif //--- Prepare the array ArrayResize(used_symbols_array,0); ResetLastError(); //--- divide the string by separators (comma) and add all found substrings to the array int n=StringSplit(defined_used_symbols,StringGetCharacter(separator,0),used_symbols_array); //--- if nothing is found, display the appropriate message (working with the current symbol is selected automatically) if(n<1) { string err= (n==0 ? DFUN_ERR_LINE+CMessage::Text(MSG_LIB_SYS_ERROR_EMPTY_STRING)+Symbol() : DFUN_ERR_LINE+CMessage::Text(MSG_LIB_SYS_FAILED_PREPARING_SYMBOLS_ARRAY)+(string)GetLastError() ); Print(err); return false; } } //--- If working with the Market Watch window or the full list else { //--- Add the (mode_used_symbols) working mode to the only array cell ArrayResize(used_symbols_array,1); used_symbols_array[0]=EnumToString(mode_used_symbols); } return true; } //+------------------------------------------------------------------+
使用される時間枠の配列を準備するための同様の関数が必要です。2つの類似した関数に同じコードブロック(提供されたリストでは色で強調表示)があることが明らかになります。
このコードブロックを別の関数に移動しましょう。
//+------------------------------------------------------------------+ //| Prepare the passed string of parameters | //+------------------------------------------------------------------+ int StringParamsPrepare(string defined_used,string separator,string &array[]) { //--- Replace erroneous separators with correct ones if(separator!=";" && StringFind(defined_used,";")>WRONG_VALUE) StringReplace(defined_used,";",separator); if(separator!=":" && StringFind(defined_used,":")>WRONG_VALUE) StringReplace(defined_used,":",separator); if(separator!="|" && StringFind(defined_used,"|")>WRONG_VALUE) StringReplace(defined_used,"|",separator); if(separator!="/" && StringFind(defined_used,"/")>WRONG_VALUE) StringReplace(defined_used,"/",separator); if(separator!="\\"&& StringFind(defined_used,"\\")>WRONG_VALUE) StringReplace(defined_used,"\\",separator); if(separator!="'" && StringFind(defined_used,"'")>WRONG_VALUE) StringReplace(defined_used,"'",separator); if(separator!="-" && StringFind(defined_used,"-")>WRONG_VALUE) StringReplace(defined_used,"-",separator); if(separator!="`" && StringFind(defined_used,"`")>WRONG_VALUE) StringReplace(defined_used,"`",separator); //--- Delete as long as there are spaces while(StringFind(defined_used," ")>WRONG_VALUE && !IsStopped()) StringReplace(defined_used," ",""); //--- As soon as there are double separators (after removing spaces between them), replace them with a separator while(StringFind(defined_used,separator+separator)>WRONG_VALUE && !IsStopped()) StringReplace(defined_used,separator+separator,separator); //--- If a single separator remains before the first symbol in the string, replace it with a space if(StringFind(defined_used,separator)==0) StringSetCharacter(defined_used,0,32); //--- If a single separator remains after the last symbol in the string, replace it with a space if(StringFind(defined_used,separator)==StringLen(defined_used)-1) StringSetCharacter(defined_used,StringLen(defined_used)-1,32); //--- Remove all redundant things to the left and right #ifdef __MQL5__ StringTrimLeft(defined_used); StringTrimRight(defined_used); //--- __MQL4__ #else defined_used=StringTrimLeft(defined_used); defined_used=StringTrimRight(defined_used); #endif //--- Prepare the array ArrayResize(array,0); ResetLastError(); //--- divide the string by separators (comma), write all detected substrings into the array and return the number of obtained substrings return StringSplit(defined_used,StringGetCharacter(separator,0),array); } //+------------------------------------------------------------------+
この場合、使用される銘柄の配列を作成する関数は次のようになります。
//+------------------------------------------------------------------+ //| Prepare the symbol array for a symbol collection | //+------------------------------------------------------------------+ bool CreateUsedSymbolsArray(const ENUM_SYMBOLS_MODE mode_used_symbols,string defined_used_symbols,string &used_symbols_array[]) { //--- When working with the current symbol if(mode_used_symbols==SYMBOLS_MODE_CURRENT) { //--- Write the name of the current symbol to the only array cell ArrayResize(used_symbols_array,1); used_symbols_array[0]=Symbol(); return true; } //--- If working with a predefined symbol set (from the defined_used_symbols string) else if(mode_used_symbols==SYMBOLS_MODE_DEFINES) { //--- Set comma as a separator (defined in the Datas.mqh file, page 11) string separator=INPUT_SEPARATOR; int n=StringParamsPrepare(defined_used_symbols,separator,used_symbols_array); //--- if nothing is found, display the appropriate message (working with the current symbol is selected automatically) if(n<1) { int err_code=GetLastError(); string err= (n==0 ? DFUN_ERR_LINE+CMessage::Text(MSG_LIB_SYS_ERROR_EMPTY_SYMBOLS_STRING)+Symbol() : DFUN_ERR_LINE+CMessage::Text(MSG_LIB_SYS_FAILED_PREPARING_SYMBOLS_ARRAY)+(string)err_code+": "+CMessage::Text(err_code) ); Print(err); return false; } } //--- If working with the Market Watch window or the full list else { //--- Add the (mode_used_symbols) working mode to the only array cell ArrayResize(used_symbols_array,1); used_symbols_array[0]=EnumToString(mode_used_symbols); } //--- All is successful return true; } //+------------------------------------------------------------------+
別の関数に移動したコードブロックは、パラメーターの文字列を準備するための関数に置き換えられます。
同様に、プログラムで使用される時間枠の配列を準備するための関数を作成してみましょう。
//+------------------------------------------------------------------+ //| Prepare the array of timeframes for the timeseries collection | //+------------------------------------------------------------------+ bool CreateUsedTimeframesArray(const ENUM_TIMEFRAMES_MODE mode_used_periods,string defined_used_periods,string &used_periods_array[]) { //--- If working with the current chart period, set the current timeframe flag if(mode_used_periods==TIMEFRAMES_MODE_CURRENT) { ArrayResize(used_periods_array,1,21); used_periods_array[0]=TimeframeDescription((ENUM_TIMEFRAMES)Period()); return true; } //--- If working with a predefined set of chart periods (from the defined_used_periods string) else if(mode_used_periods==TIMEFRAMES_MODE_LIST) { //--- Set comma as a separator (defined in the Datas.mqh file, page 11) string separator=INPUT_SEPARATOR; //--- Fill in the array of parameters from the string with predefined timeframes int n=StringParamsPrepare(defined_used_periods,separator,used_periods_array); //--- if nothing is found, display the appropriate message (working with the current period is selected automatically) if(n<1) { int err_code=GetLastError(); string err= (n==0 ? DFUN_ERR_LINE+CMessage::Text(MSG_LIB_SYS_ERROR_EMPTY_PERIODS_STRING)+TimeframeDescription((ENUM_TIMEFRAMES)Period()) : DFUN_ERR_LINE+CMessage::Text(MSG_LIB_SYS_FAILED_PREPARING_PERIODS_ARRAY)+(string)err_code+": "+CMessage::Text(err_code) ); Print(err); //--- Set the current period to the array ArrayResize(used_periods_array,1,21); used_periods_array[0]=TimeframeDescription((ENUM_TIMEFRAMES)Period()); return false; } } //--- If working with the full list of timeframes, fill in the array with strings describing all timeframes else { ArrayResize(used_periods_array,21,21); for(int i=0;i<21;i++) used_periods_array[i]=TimeframeDescription(TimeframeByEnumIndex(uchar(i+1))); } //--- All is successful return true; } //+------------------------------------------------------------------+
パラメータ文字列を準備するための関数は、ここでも同じように呼び出されます。CreateUsedSymbolsArray()関数とCreateUsedTimeframesArray()関数の適切なコードは同じです。
DELib.mqhファイルには、ミリ秒で時間を表示する関数もあります。
//+------------------------------------------------------------------+ //| Return time with milliseconds | //+------------------------------------------------------------------+ string TimeMSCtoString(const long time_msc) { return TimeToString(time_msc/1000,TIME_DATE|TIME_MINUTES|TIME_SECONDS)+"."+IntegerToString(time_msc%1000,3,'0'); } //+------------------------------------------------------------------+
関数は常に「YYYY.MM.DD HH:MM:SS.MSC」形式で時間を表示します。
時間の表示形式を選択する機能を追加しましょう。
//+------------------------------------------------------------------+ //| Return time with milliseconds | //+------------------------------------------------------------------+ string TimeMSCtoString(const long time_msc,int flags=TIME_DATE|TIME_MINUTES|TIME_SECONDS) { return TimeToString(time_msc/1000,flags)+"."+IntegerToString(time_msc%1000,3,'0'); } //+------------------------------------------------------------------+
時間の表示形式+ミリ秒を設定できるようになりました。
適用された時間枠の選択をEAファイル入力のブロックに追加します。
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 ENUM_TIMEFRAMES_MODE InpModeUsedTFs = TIMEFRAMES_MODE_LIST; // Mode of used timeframes list sinput string InpUsedTFs = "M1,M5,M15,M30,H1,H4,D1,W1,MN1"; // List of used timeframes (comma - separator) sinput bool InpUseSounds = true; // Use sounds
InpModeUsedTFsでは時間枠使用モードを選択できます。
- 現在の時間枠のみの操作
- 指定された時間枠リストの操作
- 完全な時間枠リストの操作
2番目のモードを選択すると、プログラムは、InpUsedTFs 変数入力で指定された文字列で記述された時間枠のリストを使用します。
EAグローバル変数のブロックから、CTimeSeriesクラスオブジェクトを宣言する変数を削除します。もう必要ありません。時系列にアクセスするには、engineライブラリオブジェクトにアクセスすることになります。
//--- global variables CEngine engine; CTimeSeries timeseries; SDataButt butt_data[TOTAL_BUTT];
グローバル変数の同じブロックが新しい配列を受け取り 、プログラムで使用される時間枠の名前が書き込まれます。
//--- global variables CEngine engine; 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 array_used_symbols[]; string array_used_periods[]; bool testing; uchar group1; uchar group2; double g_point; int g_digits; //+------------------------------------------------------------------+
EAのOnInit()ハンドラから、前のテストから残っている2つの時系列を作成するコードを削除します。
//+------------------------------------------------------------------+ //| 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 a symbol for created timeseries timeseries.SetSymbol(Symbol()); //#define TIMESERIES_ALL //--- Create two timeseries #ifndef TIMESERIES_ALL timeseries.SyncData(PERIOD_CURRENT,10); timeseries.Create(PERIOD_CURRENT); timeseries.SyncData(PERIOD_M15,2); timeseries.Create(PERIOD_M15); //--- Create all timeseries #else timeseries.SyncAllData(); timeseries.CreateAll(); #endif //--- Check created timeseries CArrayObj *list=timeseries.GetList(); Print(TextByLanguage("Данные созданных таймсерий:","Data of created timeseries:")); for(int i=0;i<list.Total();i++) { CSeries *series_obj=timeseries.GetSeriesByIndex((uchar)i); if(series_obj==NULL || series_obj.AmountUsedData()==0 || series_obj.DataTotal()==0) continue; Print( DFUN,i,": ",series_obj.Symbol()," ",TimeframeDescription(series_obj.Timeframe()), ": AmountUsedData=",series_obj.AmountUsedData(),", DataTotal=",series_obj.DataTotal(),", Bars=",series_obj.Bars() ); } Print(""); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
EAのOnTick()ハンドラから、作成された時系列を更新するコードを削除します(時系列は次の記事で更新される予定です)。
//+------------------------------------------------------------------+ //| 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 } //--- Update created timeseries CArrayObj *list=timeseries.GetList(); for(int i=0;i<list.Total();i++) { CSeries *series_obj=timeseries.GetSeriesByIndex((uchar)i); if(series_obj==NULL || series_obj.DataTotal()==0) continue; series_obj.Refresh(); if(series_obj.IsNewBar(0)) { Print(TextByLanguage("Новый бар на ","New bar on "),series_obj.Symbol()," ",TimeframeDescription(series_obj.Timeframe())," ",TimeToString(series_obj.Time(0))); if(series_obj.Timeframe()==Period()) engine.PlaySoundByDescription(SND_NEWS); } } } //+------------------------------------------------------------------+
OnInitDoEasy()ライブラリ初期化関数で、EAで使用される時間枠のリストの作成と表示、およびライブラリ初期化の時刻を操作ログでの表示を追加します。
以下は、完全な変更内容が色で強調表示されたコードと、理解を深めるためのコメント付きの文字列です。
//+------------------------------------------------------------------+ //| Initializing DoEasy library | //+------------------------------------------------------------------+ void OnInitDoEasy() { //--- Check if working with the full list is selected used_symbols_mode=InpModeUsedSymbols; if((ENUM_SYMBOLS_MODE)used_symbols_mode==SYMBOLS_MODE_ALL) { int total=SymbolsTotal(false); string ru_n="\nКоличество символов на сервере "+(string)total+".\nМаксимальное количество: "+(string)SYMBOLS_COMMON_TOTAL+" символов."; string en_n="\nNumber of symbols on server "+(string)total+".\nMaximum number: "+(string)SYMBOLS_COMMON_TOTAL+" symbols."; string caption=TextByLanguage("Внимание!","Attention!"); string ru="Выбран режим работы с полным списком.\nВ этом режиме первичная подготовка списков коллекций символов и таймсерий может занять длительное время."+ru_n+"\nПродолжить?\n\"Нет\" - работа с текущим символом \""+Symbol()+"\""; string en="Full list mode selected.\nIn this mode, the initial preparation of lists of symbol collections and timeseries can take a long time."+en_n+"\nContinue?\n\"No\" - working with the current symbol \""+Symbol()+"\""; string message=TextByLanguage(ru,en); int flags=(MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2); int mb_res=MessageBox(message,caption,flags); switch(mb_res) { case IDNO : used_symbols_mode=SYMBOLS_MODE_CURRENT; break; default: break; } } //--- Set the counter start point to measure the approximate library initialization time ulong begin=GetTickCount(); Print(TextByLanguage("--- Инициализация библиотеки \"DoEasy\" ---","--- Initializing the \"DoEasy\" library ---")); //--- Fill in the array of used symbols CreateUsedSymbolsArray((ENUM_SYMBOLS_MODE)used_symbols_mode,InpUsedSymbols,array_used_symbols); //--- Set the type of the used symbol list in the symbol collection and fill in the list of symbol timeseries engine.SetUsedSymbols(array_used_symbols); //--- Displaying the selected mode of working with the symbol object collection in the journal string num= ( used_symbols_mode==SYMBOLS_MODE_CURRENT ? ": \""+Symbol()+"\"" : TextByLanguage(". Количество используемых символов: ",". The number of symbols used: ")+(string)engine.GetSymbolsCollectionTotal() ); Print(engine.ModeSymbolsListDescription(),num); //--- Implement displaying the list of used symbols only for MQL5 - MQL4 has no ArrayPrint() function #ifdef __MQL5__ if(InpModeUsedSymbols!=SYMBOLS_MODE_CURRENT) { string array_symbols[]; CArrayObj* list_symbols=engine.GetListAllUsedSymbols(); for(int i=0;i<list_symbols.Total();i++) { CSymbol *symbol=list_symbols.At(i); if(symbol==NULL) continue; ArrayResize(array_symbols,ArraySize(array_symbols)+1,1000); array_symbols[ArraySize(array_symbols)-1]=symbol.Name(); } ArrayPrint(array_symbols); } #endif //--- Set used timeframes CreateUsedTimeframesArray(InpModeUsedTFs,InpUsedTFs,array_used_periods); //--- Display the selected mode of working with the timeseries object collection string mode= ( InpModeUsedTFs==TIMEFRAMES_MODE_CURRENT ? TextByLanguage("Работа только с текущим таймфреймом: ","Work only with the current Period: ")+TimeframeDescription((ENUM_TIMEFRAMES)Period()) : InpModeUsedTFs==TIMEFRAMES_MODE_LIST ? TextByLanguage("Работа с заданным списком таймфреймов:","Work with a predefined list of Periods:") : TextByLanguage("Работа с полным списком таймфреймов:","Work with the full list of all Periods:") ); Print(mode); //--- Implement displaying the list of used timeframes only for MQL5 - MQL4 has no ArrayPrint() function #ifdef __MQL5__ if(InpModeUsedTFs!=TIMEFRAMES_MODE_CURRENT) ArrayPrint(array_used_periods); #endif //--- Create timeseries of all used symbols CArrayObj *list_timeseries=engine.GetListTimeSeries(); int total=list_timeseries.Total(); for(int i=0;i<total;i++) { CTimeSeries *timeseries=list_timeseries.At(i); if(list_timeseries==NULL) continue; int total_periods=ArraySize(array_used_periods); for(int j=0;j<total_periods;j++) { ENUM_TIMEFRAMES timeframe=TimeframeByDescription(array_used_periods[j]); engine.SeriesSyncData(timeseries.Symbol(),timeframe); engine.SeriesCreate(timeseries.Symbol(),timeframe); } } //--- Check created timeseries - display descriptions of all created timeseries in the journal //--- (true - only created ones, false - created and declared ones) engine.GetTimeSeriesCollection().PrintShort(true); // Short descriptions //engine.GetTimeSeriesCollection().Print(false); // Full descriptions //--- Create resource text files engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_01",TextByLanguage("Звук упавшей монетки 1","Falling coin 1"),sound_array_coin_01); engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_02",TextByLanguage("Звук упавших монеток","Falling coins"),sound_array_coin_02); engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_03",TextByLanguage("Звук монеток","Coins"),sound_array_coin_03); engine.CreateFile(FILE_TYPE_WAV,"sound_array_coin_04",TextByLanguage("Звук упавшей монетки 2","Falling coin 2"),sound_array_coin_04); engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_01",TextByLanguage("Звук щелчка по кнопке 1","Button click 1"),sound_array_click_01); engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_02",TextByLanguage("Звук щелчка по кнопке 2","Button click 2"),sound_array_click_02); engine.CreateFile(FILE_TYPE_WAV,"sound_array_click_03",TextByLanguage("Звук щелчка по кнопке 3","Button click 3"),sound_array_click_03); engine.CreateFile(FILE_TYPE_WAV,"sound_array_cash_machine_01",TextByLanguage("Звук кассового аппарата","Cash machine"),sound_array_cash_machine_01); engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_green",TextByLanguage("Изображение \"Зелёный светодиод\"","Image \"Green Spot lamp\""),img_array_spot_green); engine.CreateFile(FILE_TYPE_BMP,"img_array_spot_red",TextByLanguage("Изображение \"Красный светодиод\"","Image \"Red Spot lamp\""),img_array_spot_red); //--- Pass all existing collections to the trading class engine.TradingOnInit(); //--- Set the default magic number for all used symbols engine.TradingSetMagic(engine.SetCompositeMagicNumber(magic_number)); //--- Set synchronous passing of orders for all used symbols engine.TradingSetAsyncMode(false); //--- Set the number of trading attempts in case of an error engine.TradingSetTotalTry(InpTotalAttempts); //--- Set correct order expiration and filling types to all trading objects engine.TradingSetCorrectTypeExpiration(); engine.TradingSetCorrectTypeFilling(); //--- Set standard sounds for trading objects of all used symbols engine.SetSoundsStandart(); //--- Set the general flag of using sounds engine.SetUseSounds(InpUseSounds); //--- Set the spread multiplier for symbol trading objects in the symbol collection engine.SetSpreadMultiplier(InpSpreadMultiplier); //--- Set controlled values for symbols //--- Get the list of all collection symbols CArrayObj *list=engine.GetListAllUsedSymbols(); if(list!=NULL && list.Total()!=0) { //--- In a loop by the list, set the necessary values for tracked symbol properties //--- By default, the LONG_MAX value is set to all properties, which means "Do not track this property" //--- It can be enabled or disabled (by setting the value less than LONG_MAX or vice versa - set the LONG_MAX value) at any time and anywhere in the program /* for(int i=0;i<list.Total();i++) { CSymbol* symbol=list.At(i); if(symbol==NULL) continue; //--- Set control of the symbol price increase by 100 points symbol.SetControlBidInc(100000*symbol.Point()); //--- Set control of the symbol price decrease by 100 points symbol.SetControlBidDec(100000*symbol.Point()); //--- Set control of the symbol spread increase by 40 points symbol.SetControlSpreadInc(400); //--- Set control of the symbol spread decrease by 40 points symbol.SetControlSpreadDec(400); //--- Set control of the current spread by the value of 40 points symbol.SetControlSpreadLevel(400); } */ } //--- Set controlled values for the current account CAccount* account=engine.GetAccountCurrent(); if(account!=NULL) { //--- Set control of the profit increase to 10 account.SetControlledValueINC(ACCOUNT_PROP_PROFIT,10.0); //--- Set control of the funds increase to 15 account.SetControlledValueINC(ACCOUNT_PROP_EQUITY,15.0); //--- Set profit control level to 20 account.SetControlledValueLEVEL(ACCOUNT_PROP_PROFIT,20.0); } //--- Get the end of the library initialization time counting and display it in the journal ulong end=GetTickCount(); Print(TextByLanguage("Время инициализации библиотеки: ","Library initialization time: "),TimeMSCtoString(end-begin,TIME_MINUTES|TIME_SECONDS)); } //+------------------------------------------------------------------+
テストEAの改善点はこれですべてです。
パラメータで現在の銘柄と現在の時間枠の使用法を指定して、コンパイルして起動します。
操作ログには次のメッセージが表示されます。
--- Initializing "DoEasy" library --- Working with the current symbol only: "EURUSD" Working with the current timeframe only: H4 EURUSD symbol timeseries: Timeseries "EURUSD" H4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5330 Library initialization time: 00:00:00.141
現在の銘柄と設定の指定された時間枠リストを使用して設定します(リストには主な時間枠が表示されます)。操作ログには次のメッセージが表示されます。
--- Initializing "DoEasy" library --- Working with the current symbol only: "EURUSD" Working with the specified timeframe list: "M1" "M5" "M15" "M30" "H1" "H4" "D1" "W1" "MN1" EURUSD symbol timeseries: Timeseries "EURUSD" M1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3286 Timeseries "EURUSD" M5: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3566 Timeseries "EURUSD" M15: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3109 Timeseries "EURUSD" M30: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2894 Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5505 Timeseries "EURUSD" H4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5330 Timeseries "EURUSD" D1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5087 Timeseries "EURUSD" W1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2564 Timeseries "EURUSD" MN1: Requested: 1000, Actual: 590, Created: 590, On the server: 590 Library initialization time: 00:00:00.032
現在の銘柄と時間枠の完全なリストを使用して設定します。
操作ログには次のメッセージが表示されます。
--- Initializing "DoEasy" library --- Working with the current symbol only: "EURUSD" Working with the full list of timeframes: "M1" "M2" "M3" "M4" "M5" "M6" "M10" "M12" "M15" "M20" "M30" "H1" "H2" "H3" "H4" "H6" "H8" "H12" "D1" "W1" "MN1" EURUSD symbol timeseries: Timeseries "EURUSD" M1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3390 Timeseries "EURUSD" M2: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5626 Timeseries "EURUSD" M3: Requested: 1000, Actual: 1000, Created: 1000, On the server: 4713 Timeseries "EURUSD" M4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 4254 Timeseries "EURUSD" M5: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3587 Timeseries "EURUSD" M6: Requested: 1000, Actual: 1000, Created: 1000, On the server: 4805 Timeseries "EURUSD" M10: Requested: 1000, Actual: 1000, Created: 1000, On the server: 4035 Timeseries "EURUSD" M12: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3842 Timeseries "EURUSD" M15: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3116 Timeseries "EURUSD" M20: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3457 Timeseries "EURUSD" M30: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2898 Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5507 Timeseries "EURUSD" H2: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6303 Timeseries "EURUSD" H3: Requested: 1000, Actual: 1000, Created: 1000, On the server: 6263 Timeseries "EURUSD" H4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5331 Timeseries "EURUSD" H6: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5208 Timeseries "EURUSD" H8: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5463 Timeseries "EURUSD" H12: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5205 Timeseries "EURUSD" D1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5087 Timeseries "EURUSD" W1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2564 Timeseries "EURUSD" MN1: Requested: 1000, Actual: 590, Created: 590, On the server: 590 Library initialization time: 00:00:00.094
指定された銘柄リストを使用して構成し、設定で3つの銘柄EURUSD、AUDUSD、EURAUDを設定します。また、指定された時間枠リストを使用して構成します(リストにはメイン時間枠が指定されています)。操作ログには次のメッセージが表示されます。
--- Initializing "DoEasy" library --- Working with predefined symbol list. The number of used symbols: 3 "AUDUSD" "EURUSD" "EURAUD" Working with the specified timeframe list: "M1" "M5" "M15" "M30" "H1" "H4" "D1" "W1" "MN1" AUDUSD symbol timeseries: Timeseries "AUDUSD" M1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3394 Timeseries "AUDUSD" M5: Requested: 1000, Actual: 1000, Created: 1000, On the server: 4024 Timeseries "AUDUSD" M15: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3262 Timeseries "AUDUSD" M30: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3071 Timeseries "AUDUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5104 Timeseries "AUDUSD" H4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5026 Timeseries "AUDUSD" D1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5289 Timeseries "AUDUSD" W1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 1401 Timeseries "AUDUSD" MN1: Requested: 1000, Actual: 323, Created: 323, On the server: 323 EURAUD symbol timeseries: Timeseries "EURAUD" M1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3393 Timeseries "EURAUD" M5: Requested: 1000, Actual: 1000, Created: 1000, On the server: 4025 Timeseries "EURAUD" M15: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3262 Timeseries "EURAUD" M30: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3071 Timeseries "EURAUD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5104 Timeseries "EURAUD" H4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5026 Timeseries "EURAUD" D1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 4071 Timeseries "EURAUD" W1: Requested: 1000, Actual: 820, Created: 820, On the server: 820 Timeseries "EURAUD" MN1: Requested: 1000, Actual: 189, Created: 189, On the server: 189 EURUSD symbol timeseries: Timeseries "EURUSD" M1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3394 Timeseries "EURUSD" M5: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3588 Timeseries "EURUSD" M15: Requested: 1000, Actual: 1000, Created: 1000, On the server: 3116 Timeseries "EURUSD" M30: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2898 Timeseries "EURUSD" H1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5507 Timeseries "EURUSD" H4: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5331 Timeseries "EURUSD" D1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 5087 Timeseries "EURUSD" W1: Requested: 1000, Actual: 1000, Created: 1000, On the server: 2564 Timeseries "EURUSD" MN1: Requested: 1000, Actual: 590, Created: 590, On the server: 590 Library initialization time: 00:00:00.266
ご覧のとおり、必要な時系列は、EA設定で指定された銘柄と時間枠に応じて作成されます。時系列の作成時間は、EAの起動(コールド/ホット)と、選択した銘柄とその時間枠が以前に使用されたかどうかによって異なります。
次の段階
次回の記事では、作成された時系列のリアルタイム更新、および使用されているすべての時系列の「新しいバー」イベントに関するメッセージをプログラムに送信する機能と、既存の時系列から必要なデータを受信する機能を作成します。
現在のバージョンのライブラリのすべてのファイルは、テスト用EAファイルと一緒に以下に添付されているので、テストするにはダウンロードしてください。
質問や提案はコメント欄にお願いします。
シリーズのこれまでの記事:
DoEasyライブラリの時系列(第35部): バーオブジェクトと銘柄の時系列リスト
DoEasyライブラリの時系列(第36部): すべての使用銘柄期間の時系列オブジェクト
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/7663





- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索