
DoEasyライブラリでのその他のクラス(第71部): チャットオブジェクトコレクションイベント
内容
概念
前回の記事では、いくつかのチャートオブジェクトのプロパティと関連オブジェクト(新規銘柄チャート(チャートオブジェクト)の追加と既存銘柄チャートの削除、チャートオブジェクトからの新規指標ウィンドウの追加と既存指標ウィンドウの削除、チャートウィンドウからの新規指標の追加と既存指標の削除)の自動更新を導入しました。
本稿では、チャートオブジェクト、チャートウィンドウオブジェクト、チャートウィンドウ内の指標オブジェクトのイベント機能を作成します。上記で検討したオブジェクトイベントを登録するときに、カスタムイベントを制御プログラムチャートに送信できるようになります。
チャートの操作は、手動のチャート制御を念頭に置いて実装されます。つまり、チャートを手動で変更したり、プログラムの制御要素を使用したりすると、操作は一度に1オブジェクトずつ実行されます。1つのタイマーティック内で一度に複数のオブジェクトをプログラムで変更すると、発生するイベントの定義が正しくなくなる可能性があります。記録されるのはせいぜい最後のイベントだけになります。最悪の場合、変更されたオブジェクトは正しく定義されません。そのような可能性を考慮しながらコードを書いたので、可能な限りオブジェクトパラメータを一括変更できるようにコードを挿入しています。ただし、複数のチャート要素のプログラムによる同時処理を微調整してテストするつもりはありません。ライブラリ利用者からのご要望があれば、このタスクに戻ります。
ライブラリクラスの改善
新しいメッセージをライブラリに追加しましょう。\MQL5\Include\DoEasy\Data.mqhに、新しいメッセージインデックスを追加します。
MSG_CHART_OBJ_TEMPLATE_SAVED, // Chart template saved MSG_CHART_OBJ_TEMPLATE_APPLIED, // Template applied to chart MSG_CHART_OBJ_INDICATOR_ADDED, // Indicator added MSG_CHART_OBJ_INDICATOR_REMOVED, // Indicator removed MSG_CHART_OBJ_INDICATOR_CHANGED, // Indicator changed MSG_CHART_OBJ_WINDOW_ADDED, // Subwindow added MSG_CHART_OBJ_WINDOW_REMOVED, // Subwindow removed //--- CChartObjCollection MSG_CHART_COLLECTION_TEXT_CHART_COLLECTION, // Chart collection MSG_CHART_COLLECTION_ERR_FAILED_CREATE_CHART_OBJ, // Failed to create a new chart object MSG_CHART_COLLECTION_ERR_FAILED_ADD_CHART, // Failed to add a chart object to the collection MSG_CHART_COLLECTION_ERR_CHARTS_MAX, // Cannot open new chart. Number of open charts at maximum MSG_CHART_COLLECTION_CHART_OPENED, // Chart opened MSG_CHART_COLLECTION_CHART_CLOSED, // Chart closed }; //+------------------------------------------------------------------+
また、新しく追加したインデックスに対応するメッセージテキストも追加します。
{"Шаблон графика сохранён","Chart template saved"}, {"Шаблон применён к графику","Template applied to the chart"}, {"Добавлен индикатор","Added indicator"}, {"Удалён индикатор","Removed indicator"}, {"Изменён индикатор","Changed indicator"}, {"Добавлено подокно","Added subwindow"}, {"Удалено подокно","Removed subwindow"}, //--- CChartObjCollection {"Коллекция чартов","Chart collection"}, {"Не удалось создать новый объект-чарт","Failed to create new chart object"}, {"Не удалось добавить объект-чарт в коллекцию","Failed to add chart object to collection"}, {"Нельзя открыть новый график, так как количество открытых графиков уже максимальное","You cannot open a new chart, since the number of open charts is already maximum"}, {"Открыт график","Open chart"}, {"Закрыт график","Closed chart"}, }; //+---------------------------------------------------------------------+
本稿では、いくつかのチャートイベントを処理します。それらを追跡して特定のイベントを指定するには、\MQL5\Include\DoEasy\Defines.mqhに可能なチャートイベントの新しい列挙を作成します。
//+------------------------------------------------------------------+ //| Data for working with charts | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| List of possible chart events | //+------------------------------------------------------------------+ enum ENUM_CHART_OBJ_EVENT { CHART_OBJ_EVENT_NO_EVENT = SIGNAL_MQL5_EVENTS_NEXT_CODE, // No event CHART_OBJ_EVENT_CHART_OPEN, // "New chart opening" event CHART_OBJ_EVENT_CHART_CLOSE, // "Chart closure" event CHART_OBJ_EVENT_CHART_WND_ADD, // "Adding a new window on the chart" event CHART_OBJ_EVENT_CHART_WND_DEL, // "Removing a window from the chart" event CHART_OBJ_EVENT_CHART_WND_IND_ADD, // "Adding a new indicator to the chart window" event CHART_OBJ_EVENT_CHART_WND_IND_DEL, // "Removing an indicator from the chart window" event CHART_OBJ_EVENT_CHART_WND_IND_CHANGE, // "Changing indicator parameters in the chart window" event }; #define CHART_OBJ_EVENTS_NEXT_CODE (CHART_OBJ_EVENT_CHART_WND_IND_CHANGE+1) // The code of the next event after the last chart event code //+------------------------------------------------------------------+
この列挙で指定されたチャートイベントを登録すると、カスタムイベントがプログラムチャートに送信されます。このカスタムイベントでは列挙型の適切な定数を使用し、発生したイベントのタイプが含まれます。次に、プログラムはイベントコードを分析し、それに応じて処理します。
イベント処理を実装しているときに、予期しない課題にぶつかりました。すでに削除されたチャートサブウィンドウのインデックスとその中の指標を定義するのは難しいということです。それらをより便利に定義するために、チャートウィンドウの指標オブジェクトの新しいプロパティ(オブジェクトが配置されているウィンドウのインデックス)を実装することにしました。
削除されたすべてのチャート、チャートウィンドウ、および適切な指標(それらを説明するオブジェクト)は特別なリストに保存され、以前に削除されたオブジェクトをいつでも受け取ることができます。これは、指標ウィンドウのインデックスの取得元となるオブジェクトです(指標が削除された場合)。
チャートウィンドウの指標オブジェクトの新しいプロパティ定数をチャートオブジェクトの整数プロパティの列挙に追加します。
//+------------------------------------------------------------------+ //| Chart integer property | //+------------------------------------------------------------------+ enum ENUM_CHART_PROP_INTEGER { CHART_PROP_ID = 0, // Chart ID CHART_PROP_TIMEFRAME, // Chart timeframe CHART_PROP_SHOW, // Price chart drawing CHART_PROP_IS_OBJECT, // Chart object (OBJ_CHART) identification attribute CHART_PROP_BRING_TO_TOP, // Show chart above all others CHART_PROP_CONTEXT_MENU, // Enable/disable access to the context menu using the right click CHART_PROP_CROSSHAIR_TOOL, // Enable/disable access to the Crosshair tool using the middle click CHART_PROP_MOUSE_SCROLL, // Scroll the chart horizontally using the left mouse button CHART_PROP_EVENT_MOUSE_WHEEL, // Send messages about mouse wheel events (CHARTEVENT_MOUSE_WHEEL) to all MQL5 programs on a chart CHART_PROP_EVENT_MOUSE_MOVE, // Send messages about mouse button click and movement events (CHARTEVENT_MOUSE_MOVE) to all MQL5 programs on a chart CHART_PROP_EVENT_OBJECT_CREATE, // Send messages about the graphical object creation event (CHARTEVENT_OBJECT_CREATE) to all MQL5 programs on a chart CHART_PROP_EVENT_OBJECT_DELETE, // Send messages about the graphical object destruction event (CHARTEVENT_OBJECT_DELETE) to all MQL5 programs on a chart CHART_PROP_MODE, // Type of the chart (candlesticks, bars or line (ENUM_CHART_MODE)) CHART_PROP_FOREGROUND, // Price chart in the foreground CHART_PROP_SHIFT, // Mode of shift of the price chart from the right border CHART_PROP_AUTOSCROLL, // The mode of automatic shift to the right border of the chart CHART_PROP_KEYBOARD_CONTROL, // Allow managing the chart using a keyboard CHART_PROP_QUICK_NAVIGATION, // Allow the chart to intercept Space and Enter key strokes to activate the quick navigation bar CHART_PROP_SCALE, // Scale CHART_PROP_SCALEFIX, // Fixed scale mode CHART_PROP_SCALEFIX_11, // 1:1 scale mode CHART_PROP_SCALE_PT_PER_BAR, // The mode of specifying the scale in points per bar CHART_PROP_SHOW_TICKER, // Display a symbol ticker in the upper left corner CHART_PROP_SHOW_OHLC, // Display OHLC values in the upper left corner CHART_PROP_SHOW_BID_LINE, // Display Bid value as a horizontal line on the chart CHART_PROP_SHOW_ASK_LINE, // Display Ask value as a horizontal line on a chart CHART_PROP_SHOW_LAST_LINE, // Display Last value as a horizontal line on a chart CHART_PROP_SHOW_PERIOD_SEP, // Display vertical separators between adjacent periods CHART_PROP_SHOW_GRID, // Display a grid on the chart CHART_PROP_SHOW_VOLUMES, // Display volumes on a chart CHART_PROP_SHOW_OBJECT_DESCR, // Display text descriptions of objects CHART_PROP_VISIBLE_BARS, // Number of bars on a chart that are available for display CHART_PROP_WINDOWS_TOTAL, // The total number of chart windows including indicator subwindows CHART_PROP_WINDOW_HANDLE, // Chart window handle CHART_PROP_WINDOW_YDISTANCE, // Distance in Y axis pixels between the upper frame of the indicator subwindow and the upper frame of the chart main window CHART_PROP_FIRST_VISIBLE_BAR, // Number of the first visible bar on the chart CHART_PROP_WIDTH_IN_BARS, // Width of the chart in bars CHART_PROP_WIDTH_IN_PIXELS, // Width of the chart in pixels CHART_PROP_HEIGHT_IN_PIXELS, // Height of the chart in pixels CHART_PROP_COLOR_BACKGROUND, // Color of background of the chart CHART_PROP_COLOR_FOREGROUND, // Color of axes, scale and OHLC line CHART_PROP_COLOR_GRID, // Grid color CHART_PROP_COLOR_VOLUME, // Color of volumes and position opening levels CHART_PROP_COLOR_CHART_UP, // Color for the up bar, shadows and body borders of bull candlesticks CHART_PROP_COLOR_CHART_DOWN, // Color of down bar, its shadow and border of body of the bullish candlestick CHART_PROP_COLOR_CHART_LINE, // Color of the chart line and the Doji candlesticks CHART_PROP_COLOR_CANDLE_BULL, // Color of body of a bullish candlestick CHART_PROP_COLOR_CANDLE_BEAR, // Color of body of a bearish candlestick CHART_PROP_COLOR_BID, // Color of the Bid price line CHART_PROP_COLOR_ASK, // Color of the Ask price line CHART_PROP_COLOR_LAST, // Color of the last performed deal's price line (Last) CHART_PROP_COLOR_STOP_LEVEL, // Color of stop order levels (Stop Loss and Take Profit) CHART_PROP_SHOW_TRADE_LEVELS, // Display trade levels on the chart (levels of open positions, Stop Loss, Take Profit and pending orders) CHART_PROP_DRAG_TRADE_LEVELS, // Enable the ability to drag trading levels on a chart using mouse CHART_PROP_SHOW_DATE_SCALE, // Display the time scale on a chart CHART_PROP_SHOW_PRICE_SCALE, // Display a price scale on a chart CHART_PROP_SHOW_ONE_CLICK, // Display the quick trading panel on the chart CHART_PROP_IS_MAXIMIZED, // Chart window maximized CHART_PROP_IS_MINIMIZED, // Chart window minimized CHART_PROP_IS_DOCKED, // Chart window docked CHART_PROP_FLOAT_LEFT, // Left coordinate of the undocked chart window relative to the virtual screen CHART_PROP_FLOAT_TOP, // Upper coordinate of the undocked chart window relative to the virtual screen CHART_PROP_FLOAT_RIGHT, // Right coordinate of the undocked chart window relative to the virtual screen CHART_PROP_FLOAT_BOTTOM, // Bottom coordinate of the undocked chart window relative to the virtual screen //--- CWndInd CHART_PROP_WINDOW_IND_HANDLE, // Indicator handle in the chart window CHART_PROP_WINDOW_IND_INDEX, // Indicator index in the chart window CHART_PROP_WINDOW_NUM, // Chart window index }; #define CHART_PROP_INTEGER_TOTAL (67) // Total number of integer properties #define CHART_PROP_INTEGER_SKIP (0) // Number of integer DOM properties not used in sorting //+------------------------------------------------------------------+
整数プロパティの数が増えたため、その数を66から67に増やします。
チャートウィンドウインデックスによる並べ替えをチャートオブジェクトの並べ替え基準の列挙に追加します。
//+------------------------------------------------------------------+ //| Possible chart sorting criteria | //+------------------------------------------------------------------+ #define FIRST_CHART_DBL_PROP (CHART_PROP_INTEGER_TOTAL-CHART_PROP_INTEGER_SKIP) #define FIRST_CHART_STR_PROP (CHART_PROP_INTEGER_TOTAL-CHART_PROP_INTEGER_SKIP+CHART_PROP_DOUBLE_TOTAL-CHART_PROP_DOUBLE_SKIP) enum ENUM_SORT_CHART_MODE { //--- Sort by integer properties SORT_BY_CHART_ID = 0, // Sort by chart ID SORT_BY_CHART_TIMEFRAME, // Sort by chart timeframe SORT_BY_CHART_SHOW, // Sort by the price chart drawing attribute SORT_BY_CHART_IS_OBJECT, // Sort by chart object (OBJ_CHART) identification attribute SORT_BY_CHART_BRING_TO_TOP, // Sort by the flag of displaying a chart above all others SORT_BY_CHART_CONTEXT_MENU, // Sort by the flag of enabling/disabling access to the context menu using the right click SORT_BY_CHART_CROSSHAIR_TOO, // Sort by the flag of enabling/disabling access to the Crosshair tool using the middle click SORT_BY_CHART_MOUSE_SCROLL, // Sort by the flag of scrolling the chart horizontally using the left mouse button SORT_BY_CHART_EVENT_MOUSE_WHEEL, // Sort by the flag of sending messages about mouse wheel events to all MQL5 programs on a chart SORT_BY_CHART_EVENT_MOUSE_MOVE, // Sort by the flag of sending messages about mouse button click and movement events to all MQL5 programs on a chart SORT_BY_CHART_EVENT_OBJECT_CREATE, // Sort by the flag of sending messages about the graphical object creation event to all MQL5 programs on a chart SORT_BY_CHART_EVENT_OBJECT_DELETE, // Sort by the flag of sending messages about the graphical object destruction event to all MQL5 programs on a chart SORT_BY_CHART_MODE, // Sort by chart type SORT_BY_CHART_FOREGROUND, // Sort by the "Price chart in the foreground" flag SORT_BY_CHART_SHIFT, // Sort by the "Mode of shift of the price chart from the right border" flag SORT_BY_CHART_AUTOSCROLL, // Sort by the "The mode of automatic shift to the right border of the chart" flag SORT_BY_CHART_KEYBOARD_CONTROL, // Sort by the flag allowing the chart management using a keyboard SORT_BY_CHART_QUICK_NAVIGATION, // Sort by the flag allowing the chart to intercept Space and Enter key strokes to activate the quick navigation bar SORT_BY_CHART_SCALE, // Sort by scale SORT_BY_CHART_SCALEFIX, // Sort by the fixed scale flag SORT_BY_CHART_SCALEFIX_11, // Sort by the 1:1 scale flag SORT_BY_CHART_SCALE_PT_PER_BAR, // Sort by the flag of specifying the scale in points per bar SORT_BY_CHART_SHOW_TICKER, // Sort by the flag displaying a symbol ticker in the upper left corner SORT_BY_CHART_SHOW_OHLC, // Sort by the flag displaying OHLC values in the upper left corner SORT_BY_CHART_SHOW_BID_LINE, // Sort by the flag displaying Bid value as a horizontal line on the chart SORT_BY_CHART_SHOW_ASK_LINE, // Sort by the flag displaying Ask value as a horizontal line on the chart SORT_BY_CHART_SHOW_LAST_LINE, // Sort by the flag displaying Last value as a horizontal line on the chart SORT_BY_CHART_SHOW_PERIOD_SEP, // Sort by the flag displaying vertical separators between adjacent periods SORT_BY_CHART_SHOW_GRID, // Sort by the flag of displaying a grid on the chart SORT_BY_CHART_SHOW_VOLUMES, // Sort by the mode of displaying volumes on a chart SORT_BY_CHART_SHOW_OBJECT_DESCR, // Sort by the flag of displaying object text descriptions SORT_BY_CHART_VISIBLE_BARS, // Sort by the number of bars on a chart that are available for display SORT_BY_CHART_WINDOWS_TOTAL, // Sort by the total number of chart windows including indicator subwindows SORT_BY_CHART_WINDOW_HANDLE, // Sort by the chart handle SORT_BY_CHART_WINDOW_YDISTANCE, // Sort by the distance in Y axis pixels between the upper frame of the indicator subwindow and the upper frame of the chart main window SORT_BY_CHART_FIRST_VISIBLE_BAR, // Sort by the number of the first visible bar on the chart SORT_BY_CHART_WIDTH_IN_BARS, // Sort by the width of the chart in bars SORT_BY_CHART_WIDTH_IN_PIXELS, // Sort by the width of the chart in pixels SORT_BY_CHART_HEIGHT_IN_PIXELS, // Sort by the height of the chart in pixels SORT_BY_CHART_COLOR_BACKGROUND, // Sort by the color of the chart background SORT_BY_CHART_COLOR_FOREGROUND, // Sort by color of axes, scale and OHLC line SORT_BY_CHART_COLOR_GRID, // Sort by grid color SORT_BY_CHART_COLOR_VOLUME, // Sort by the color of volumes and position opening levels SORT_BY_CHART_COLOR_CHART_UP, // Sort by the color for the up bar, shadows and body borders of bull candlesticks SORT_BY_CHART_COLOR_CHART_DOWN, // Sort by the color of down bar, its shadow and border of body of the bullish candlestick SORT_BY_CHART_COLOR_CHART_LINE, // Sort by the color of the chart line and the Doji candlesticks SORT_BY_CHART_COLOR_CANDLE_BULL, // Sort by the color of a bullish candlestick body SORT_BY_CHART_COLOR_CANDLE_BEAR, // Sort by the color of a bearish candlestick body SORT_BY_CHART_COLOR_BID, // Sort by the color of the Bid price line SORT_BY_CHART_COLOR_ASK, // Sort by the color of the Ask price line SORT_BY_CHART_COLOR_LAST, // Sort by the color of the last performed deal's price line (Last) SORT_BY_CHART_COLOR_STOP_LEVEL, // Sort by the color of stop order levels (Stop Loss and Take Profit) SORT_BY_CHART_SHOW_TRADE_LEVELS, // Sort by the flag of displaying trading levels on the chart SORT_BY_CHART_DRAG_TRADE_LEVELS, // Sort by the flag enabling the ability to drag trading levels on a chart using mouse SORT_BY_CHART_SHOW_DATE_SCALE, // Sort by the flag of displaying the time scale on the chart SORT_BY_CHART_SHOW_PRICE_SCALE, // Sort by the flag of displaying the price scale on the chart SORT_BY_CHART_SHOW_ONE_CLICK, // Sort by the flag of displaying the quick trading panel on the chart SORT_BY_CHART_IS_MAXIMIZED, // Sort by the "Chart window maximized" flag SORT_BY_CHART_IS_MINIMIZED, // Sort by the "Chart window minimized" flag SORT_BY_CHART_IS_DOCKED, // Sort by the "Chart window docked" flag SORT_BY_CHART_FLOAT_LEFT, // Sort by the left coordinate of the undocked chart window relative to the virtual screen SORT_BY_CHART_FLOAT_TOP, // Sort by the upper coordinate of the undocked chart window relative to the virtual screen SORT_BY_CHART_FLOAT_RIGHT, // Sort by the right coordinate of the undocked chart window relative to the virtual screen SORT_BY_CHART_FLOAT_BOTTOM, // Sort by the bottom coordinate of the undocked chart window relative to the virtual screen SORT_BY_CHART_WINDOW_IND_HANDLE, // Sort by the indicator handle in the chart window SORT_BY_CHART_WINDOW_IND_INDEX, // Sort by the indicator index in the chart window SORT_BY_CHART_WINDOW_NUM, // Sort by chart window index //--- Sort by real properties SORT_BY_CHART_SHIFT_SIZE = FIRST_CHART_DBL_PROP, // Sort by the shift size of the zero bar from the right border in % SORT_BY_CHART_FIXED_POSITION, // Sort by the chart fixed position from the left border in % SORT_BY_CHART_FIXED_MAX, // Sort by the fixed chart maximum SORT_BY_CHART_FIXED_MIN, // Sort by the fixed chart minimum SORT_BY_CHART_POINTS_PER_BAR, // Sort by the scale value in points per bar SORT_BY_CHART_PRICE_MIN, // Sort by the chart minimum SORT_BY_CHART_PRICE_MAX, // Sort by the chart maximum //--- Sort by string properties SORT_BY_CHART_COMMENT = FIRST_CHART_STR_PROP, // Sort by a comment text on the chart SORT_BY_CHART_EXPERT_NAME, // Sort by a name of an EA launched on the chart SORT_BY_CHART_SCRIPT_NAME, // Sort by a name of a script launched on the chart SORT_BY_CHART_WINDOW_IND_NAME, // Sort by a name of an indicator launched in the chart window SORT_BY_CHART_SYMBOL, // Sort by chart symbol }; //+------------------------------------------------------------------+
上記のように、削除された指標、ウィンドウ、チャートのオブジェクトコピーを保存するために、特別なリストを使用します。これらのリストには、各チャートオブジェクト、そのウィンドウ、およびウィンドウに属する指標でアクセスする必要があります。各オブジェクトクラスにカスタムリストが保存されないようにし、特定の削除されたオブジェクトのデータを必要とする他のオブジェクトからのアクセスを調整するには、チャートオブジェクトコレクションクラスでこれらすべてのリストを宣言します(クラスはすべてのチャートオブジェクトへのアクセスを提供します)。 リストは他のオブジェクト(チャート、チャートウィンドウ、チャートウィンドウの指標)に渡されます。したがって、コレクションに格納されている各オブジェクトは、すべてのリストにアクセスできます。
コレクションオブジェクト自体以外の、コレクションオブジェクト内でのこれらのリストの使用にいくつかの制限が課せられます。リスト内のオブジェクトを削除したり、コレクション自体を除くすべてのコレクションオブジェクト内で作業しているときに、リストをリセットしたり、リストへのポインタを変更したりすることはできないということです。ただし、リストへのポインタを使用する(実際には読み取り専用モードで適用する)というこの機能を念頭に置くと、内容を読むためにリストオブジェクトへのポインタを渡すだけで十分なので、さまざまなオブジェクトからリストへのアクセスを調整することが簡単になります。
チャートウィンドウの指標オブジェクトクラスファイルとチャートウィンドウオブジェクトファイルを改善しましょう(どちらのクラスも\MQL5\Include\DoEasy\Objects\Chart\ChartWnd.mqhにあります)。
クラスのprivateセクションCWndIndで、指標が配置されているサブウィンドウインデックスを格納するための変数を宣言します。publicセクションでは、すべてのオブジェクトプロパティを設定するメソッドと返すメソッドを記述します(以前は、単一のプロパティ(ウィンドウリストの指標インデックス)を設定できました)。
//+------------------------------------------------------------------+ //| Chart window indicator object class | //+------------------------------------------------------------------+ class CWndInd : public CObject { private: long m_chart_id; // Chart ID string m_name; // Indicator short name int m_index; // indicator index in the list int m_window_num; // Indicator subwindow index int m_handle; // Indicator handle public: //--- Return itself CWndInd *GetObject(void) { return &this; } //--- Return (1) indicator name, (2) index in the list, (3) indicator handle and (4) subwindow index string Name(void) const { return this.m_name; } int Index(void) const { return this.m_index; } int Handle(void) const { return this.m_handle; } int WindowNum(void) const { return this.m_window_num; } //--- Set (1) subwindow name, (2) window index on the chart, (3) handle, (4) index void SetName(const string name) { this.m_name=name; } void SetIndex(const int index) { this.m_index=index; } void SetHandle(const int handle) { this.m_handle=handle; } void SetWindowNum(const int win_num) { this.m_window_num=win_num; } //--- Display the description of object properties in the journal (dash=true - hyphen before the description, false - description only) void Print(const bool dash=false) { ::Print((dash ? "- " : "")+this.Header()); } //--- Return the object short name string Header(void) const { return CMessage::Text(MSG_CHART_OBJ_INDICATOR)+" "+this.Name(); } //--- Compare CWndInd objects with each other by the specified property virtual int Compare(const CObject *node,const int mode=0) const; //--- Constructors CWndInd(void){;} CWndInd(const int handle,const string name,const int index,const int win_num) : m_handle(handle), m_name(name), m_index(index), m_window_num(win_num) {} }; //+------------------------------------------------------------------+
さらに、パラメトリックコンストラクタに指標が配置されているチャートサブウィンドウインデックスを渡し、渡された値を適切な変数に割り当てるようにします。
このようなオブジェクトを作成するときは、オブジェクトが作成される指標を備えたサブウィンドウのインデックスを追加で指定する必要があります。したがって、指標とウィンドウを削除した後、指標を備えたウィンドウを見つけることができます。オブジェクトが削除されたチャートオブジェクトのリストに配置されている場合、ウィンドウとともに削除された指標が含まれているウィンドウを理解するために、すでに存在しないウィンドウのインデックスを簡単に見つけることができます。
チャートウィンドウオブジェクトにも変更を加えます。クラスのprivateセクションで、ウィンドウで変更されて削除された指標のリストへのポインタを宣言し、ウィンドウが属するチャートの銘柄格納する変数を宣言します。チャートオブジェクトリストのウィンドウから指標の存在を示すフラグを返すメソッド、リストには存在するがチャートウィンドウには存在しない指標オブジェクトを返すメソッド、ウィンドウに存在する指標のパラメータの変更を確認するメソッドを宣言します。
//+------------------------------------------------------------------+ //| Chart window object class | //+------------------------------------------------------------------+ class CChartWnd : public CBaseObjExt { private: CArrayObj m_list_ind; // Indicator list CArrayObj *m_list_ind_del; // Pointer to the list of indicators removed from the indicator window CArrayObj *m_list_ind_param; // Pointer to the list of changed indicators int m_window_num; // Subwindow index int m_wnd_coord_x; // The X coordinate for the time on the chart in the window int m_wnd_coord_y; // The Y coordinate for the price on the chart in the window string m_symbol; // Symbol of a chart the window belongs to //--- Return the flag indicating the presence of an indicator (1) from the list in the window and (2) from the window in the list bool IsPresentInWindow(const CWndInd *ind); bool IsPresentInList(const string name); //--- Return the indicator object present in the list but not present on the chart CWndInd *GetMissingInd(void); //--- Remove indicators not present in the window from the list void IndicatorsDelete(void); //--- Add new indicators to the list void IndicatorsAdd(void); //--- Check the changes of the parameters of existing indicators void IndicatorsChangeCheck(void); public:
これで、クラスはすべてのライブラリオブジェクトの拡張された基本クラスから継承され 、そのようなオブジェクトごとに簡単に実行できるイベント機能を備えるようになりました。
クラスのpublicセクション、つまり、オブジェクトが指定されたプロパティをサポートしていることを示すフラグを返すメソッドで、さらに別のサポートされているプロパティ(チャート銘柄)を追加します。文字列プロパティの説明を返すメソッドの実装をクラス本体の外に移動します(さらに検討します)。
public: //--- Return itself CChartWnd *GetObject(void) { return &this; } //--- Return the flag of the object supporting this property virtual bool SupportProperty(ENUM_CHART_PROP_INTEGER property) { return(property==CHART_PROP_WINDOW_YDISTANCE || property==CHART_PROP_HEIGHT_IN_PIXELS ? true : false); } virtual bool SupportProperty(ENUM_CHART_PROP_DOUBLE property) { return false; } virtual bool SupportProperty(ENUM_CHART_PROP_STRING property) { return (property==CHART_PROP_WINDOW_IND_NAME || property==CHART_PROP_SYMBOL ? true : false); } //--- Get description of (1) integer, (2) real and (3) string properties string GetPropertyDescription(ENUM_CHART_PROP_INTEGER property); string GetPropertyDescription(ENUM_CHART_PROP_DOUBLE property) { return CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED); } string GetPropertyDescription(ENUM_CHART_PROP_STRING property);
クラスのpublicセクションで、チャートイベントを作成して制御プログラムチャートに送信するためのメソッドを宣言します。クラスパラメトリックコンストラクタは、チャート銘柄名と削除されたリストへのポインタと変更されたウィンドウの指標を受け取るようになります。また、クラスデストラクタを宣言します。
//--- Return the object short name virtual string Header(void); //--- Create and send the chart event to the control program chart void SendEvent(ENUM_CHART_OBJ_EVENT event); //--- Compare CChartWnd objects by a specified property (to sort the list by an MQL5 signal object) virtual int Compare(const CObject *node,const int mode=0) const; //--- Compare CChartWnd objects by all properties (to search for equal MQL5 signal objects) bool IsEqual(CChartWnd* compared_obj) const; //--- Constructors CChartWnd(void){;} CChartWnd(const long chart_id,const int wnd_num,const string symbol,CArrayObj *list_ind_del,CArrayObj *list_ind_param); //--- Destructor ~CChartWnd(void);
次に、他の必要なメソッドを追加します。その目的は、リストのコメントに記載されています。
//--- Return (1) the subwindow index, (2) the number of indicators attached to the window and (3) the name of a symbol chart int WindowNum(void) const { return this.m_window_num; } int IndicatorsTotal(void) const { return this.m_list_ind.Total(); } string Symbol(void) const { return m_symbol;} //--- Set (1) the subwindow index and (2) the chart symbol void SetWindowNum(const int num) { this.m_window_num=num; } void SetSymbol(const string symbol) { this.m_symbol=symbol; } //--- Return (1) the indicator list, the window indicator object from the list by (2) index in the list and (3) by handle CArrayObj *GetIndicatorsList(void) { return &this.m_list_ind; } CWndInd *GetIndicatorByIndex(const int index); CWndInd *GetIndicatorByHandle(const int handle); //--- Return (1) the last one added to the window, (2) the last one removed from the window and (3) the changed indicator CWndInd *GetLastAddedIndicator(void) { return this.m_list_ind.At(this.m_list_ind.Total()-1); } CWndInd *GetLastDeletedIndicator(void) { return this.m_list_ind_del.At(this.m_list_ind_del.Total()-1); } CWndInd *GetLastChangedIndicator(void) { return this.m_list_ind_param.At(this.m_list_ind_param.Total()-1);}
新しいメソッドと改善されたメソッドの実装について詳しく考えてみましょう。
パラメトリッククラスコンストラクタの初期化リストで、パラメータで渡された値をm_symbolに割り当て、クラス本体でポインタの値(メソッドに渡されます)をリストへの変数ポインタに割り当てます。
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CChartWnd::CChartWnd(const long chart_id,const int wnd_num,const string symbol,CArrayObj *list_ind_del,CArrayObj *list_ind_param) : m_window_num(wnd_num), m_symbol(symbol), m_wnd_coord_x(0), m_wnd_coord_y(0) { this.m_list_ind_del=list_ind_del; this.m_list_ind_param=list_ind_param; CBaseObj::SetChartID(chart_id); this.IndicatorsListCreate(); } //+------------------------------------------------------------------+
前回の記事(つまり、ウィンドウに取り付けられた指標に関するデータを提供するメソッド)では、指標ハンドルは指標リストから取得されました。指標データを読み取った後、ハンドルはすぐに解放されました。その結果、同じ指標に対して毎回新しいハンドルが作成されました(ヘルプ情報の理解が間違っていたため、指標ハンドルは、本当に必要がなくなったとき、つまりプログラムの操作が完了したときにのみ解放する必要があります。 ハンドルでデータを受信した直後ではなく、指標はプログラムでさらに使用されます)。これは本稿で修正し、すべての指標のハンドルがクラスデストラクタで解放されるようにします。
クラスデストラクタ:
//+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CChartWnd::~CChartWnd(void) { int total=this.m_list_ind.Total(); for(int i=total-1;i>WRONG_VALUE;i--) { CWndInd *ind=this.m_list_ind.At(i); if(ind==NULL) continue; ::IndicatorRelease(ind.Handle()); this.m_list_ind.Delete(i); } } //+------------------------------------------------------------------+
ここで、ウィンドウ指標オブジェクトのリストを反復処理して、次のオブジェクトの取得、指標ハンドルの解放、オブジェクトプロパティの設定、オブジェクト自体の削除を行います。
指定されたプロパティによって2つのオブジェクトを比較する仮想メソッドにウィンドウインデックスによる比較とチャート銘柄による比較を追加します。
//+------------------------------------------------------------------+ //| Compare CChartWnd objects with each other by a specified property| //+------------------------------------------------------------------+ int CChartWnd::Compare(const CObject *node,const int mode=0) const { const CChartWnd *obj_compared=node; if(mode==CHART_PROP_WINDOW_YDISTANCE) return(this.YDistance()>obj_compared.YDistance() ? 1 : this.YDistance()<obj_compared.YDistance() ? -1 : 0); else if(mode==CHART_PROP_HEIGHT_IN_PIXELS) return(this.HeightInPixels()>obj_compared.HeightInPixels() ? 1 : this.HeightInPixels()<obj_compared.HeightInPixels() ? -1 : 0); else if(mode==CHART_PROP_WINDOW_NUM) return(this.WindowNum()>obj_compared.WindowNum() ? 1 : this.WindowNum()<obj_compared.WindowNum() ? -1 : 0); else if(mode==CHART_PROP_SYMBOL) return(this.Symbol()==obj_compared.Symbol() ? 0 : this.Symbol()>obj_compared.Symbol() ? 1 : -1); return -1; } //+------------------------------------------------------------------+
これは、リスト内のオブジェクトをチャート銘柄と新しく実装されたオブジェクトプロパティ(ウィンドウインデックス)で並べ替えたり検索したりするために必要です。
オブジェクト文字列プロパティの説明を返すメソッドの実装は、クラス本体の外に移動されます。
//+------------------------------------------------------------------+ //| Return description of object's string property | //+------------------------------------------------------------------+ string CChartWnd::GetPropertyDescription(ENUM_CHART_PROP_STRING property) { return ( property==CHART_PROP_SYMBOL ? CMessage::Text(MSG_LIB_PROP_SYMBOL)+ (!this.SupportProperty(property) ? ": "+CMessage::Text(MSG_LIB_PROP_NOT_SUPPORTED) : ": "+this.Symbol() ) : "" ); } //+------------------------------------------------------------------+
ライブラリオブジェクトのすべての同様のメソッドと同様、ここでは、メソッドに渡されるプロパティのテキスト説明を作成します。
これが「チャート銘柄」プロパティの場合は文字列の説明を返し、他のプロパティの場合は空の文字列を返します。
プロパティに「プロパティサポートなし」フラグがある場合、同じ内容の文字列が返されます。
ウィンドウに添付された指標のリストを作成するメソッドで、現在選択されている指標のハンドルを解放するコードを削除します(理由は上記で説明しました)。
//--- get and save the indicator handle by its short name int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name); //--- Free the indicator handle ::IndicatorRelease(handle); //--- Create the new indicator object in the chart window
チャートウィンドウに新しい指標オブジェクトを作成するコードに現在のウィンドウインデックスクラスをコンストラクタに渡す機能を追加します。
//+------------------------------------------------------------------+ //| Create the list of indicators attached to the window | //+------------------------------------------------------------------+ void CChartWnd::IndicatorsListCreate(void) { //--- Clear the indicator lists this.m_list_ind.Clear(); //--- Get the total number of indicators in the window int total=::ChartIndicatorsTotal(this.m_chart_id,this.m_window_num); //--- In the loop by the number of indicators, for(int i=0;i<total;i++) { //--- obtain and save the short indicator name, string name=::ChartIndicatorName(this.m_chart_id,this.m_window_num,i); //--- get and save the indicator handle by its short name int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name); //--- Create the new indicator object in the chart window CWndInd *ind=new CWndInd(handle,name,i,this.WindowNum()); if(ind==NULL) continue; //--- set the sorted list flag to the list this.m_list_ind.Sort(); //--- If failed to add the object to the list, remove it if(!this.m_list_ind.Add(ind)) delete ind; } } //+------------------------------------------------------------------+
これで、チャートウィンドウの各指標オブジェクトは、それが配置されているウィンドウを「認識」できるようになります。
リストに新しい指標を追加するメソッドについても同じことが行われます。
以下の文字列を削除して
int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name); //--- Free the indicator handle ::IndicatorRelease(handle); //--- Create the new indicator object in the chart window
チャートウィンドウで新しい指標オブジェクトを作成するときに、ウィンドウインデックスを受け渡しするようにします。
//+------------------------------------------------------------------+ //| Add new indicators to the list | //+------------------------------------------------------------------+ void CChartWnd::IndicatorsAdd(void) { //--- Get the total number of indicators in the window int total=::ChartIndicatorsTotal(this.m_chart_id,this.m_window_num); //--- In the loop by the number of indicators, for(int i=0;i<total;i++) { //--- obtain and save the short indicator name, string name=::ChartIndicatorName(this.m_chart_id,this.m_window_num,i); //--- get and save the indicator handle by its short name int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name); //--- Create the new indicator object in the chart window CWndInd *ind=new CWndInd(handle,name,i,this.WindowNum()); if(ind==NULL) continue; //--- set the sorted list flag to the list this.m_list_ind.Sort(); //--- If the object is already in the list or an attempt to add it to the list failed, remove it if(this.m_list_ind.Search(ind)>WRONG_VALUE || !this.m_list_ind.Add(ind)) delete ind; } } //+------------------------------------------------------------------+
ウィンドウ内のリストから指標の存在のフラグを返すメソッドでもコードを削除します。
int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name); ::IndicatorRelease(handle);
現在、このメソッドでも指標ハンドルを解放していません。
//+--------------------------------------------------------------------------------------+ //| Return the flag indicating the presence of an indicator from the list in the window | //+--------------------------------------------------------------------------------------+ bool CChartWnd::IsPresentInWindow(const CWndInd *ind) { int total=::ChartIndicatorsTotal(this.m_chart_id,this.m_window_num); for(int i=0;i<total;i++) { string name=::ChartIndicatorName(this.m_chart_id,this.m_window_num,i); int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name); if(ind.Name()==name && ind.Handle()==handle) return true; } return false; } //+------------------------------------------------------------------+
以下は、既存の指標のパラメータの変更を確認するメソッドです。
//+------------------------------------------------------------------+ //| Check the changes of the parameters of existing indicators | //+------------------------------------------------------------------+ void CChartWnd::IndicatorsChangeCheck(void) { //--- Get the total number of indicators in the window int total=::ChartIndicatorsTotal(this.m_chart_id,this.m_window_num); //--- In the loop by all window indicators, for(int i=0;i<total;i++) { //--- get the indicator name and get its handle by a name string name=::ChartIndicatorName(this.m_chart_id,this.m_window_num,i); int handle=::ChartIndicatorGet(this.m_chart_id,this.m_window_num,name); //--- If the indicator with such a name is present in the object indicator list, move on to the next one if(this.IsPresentInList(name)) continue; //--- Get the indicator object present in the list but not present in the window CWndInd *ind=this.GetMissingInd(); if(ind==NULL) continue; //--- If the indicator and the detected object have the same index, this is the indicator with changed parameters if(ind.Index()==i) { //--- Create a new indicator object based on the detected indicator object, CWndInd *changed=new CWndInd(ind.Handle(),ind.Name(),ind.Index(),ind.WindowNum()); if(changed==NULL) continue; //--- set the sorted list flag to the list of changed indicators this.m_list_ind_param.Sort(); //--- If failed to add a newly created indicator object to the list of changed indicators, //--- remove the created object and move on to the next indicator in the window if(!this.m_list_ind_param.Add(changed)) { delete changed; continue; } //--- Set the new parameters for the detected "lost" indicator - short name and handle ind.SetName(name); ind.SetHandle(handle); //--- and call the method of sending a custom event to the control program chart this.SendEvent(CHART_OBJ_EVENT_CHART_WND_IND_CHANGE); } } } //+------------------------------------------------------------------+
メソッドロジック全体は、コードで詳しく説明されています。チャートウィンドウの指標は、短縮名で識別されます。指標が変更されたパラメータを備えている場合は、その短縮名を変更する必要があります(これは、正しく作成されたカスタム指標の場合ですが、標準指標はこの機能を考慮に入れています)。したがって、ここでの変更された指標の検索は、その短縮名とは異なり、ウィンドウ内の変更された指標のインデックスは変わらないという事実に基づいています。したがって、ウィンドウオブジェクトリストに存在するがクライアントターミナルチャートウィンドウには存在しない指標を検出した場合、インデックスが一致するかどうかを確認する必要があります。指標と検出されたオブジェクトのインデックスが同じ場合(指標を削除する場合は、インデックスウィンドウ内の他の指標の数が変更された場合)、これは私たちが探している、パラメータが変更された指標です。
ウィンドウから削除された指標は(イベントを処理する際の後続の検索のために)特別なリストに保存されるため、ウィンドウに存在しない指標をリストから削除するメソッドを改善する必要があります。
//+------------------------------------------------------------------+ //| Remove indicators not present in the window from the list | //+------------------------------------------------------------------+ void CChartWnd::IndicatorsDelete(void) { //--- In the loop by the list of window indicator objects, int total=this.m_list_ind.Total(); for(int i=total-1;i>WRONG_VALUE;i--) { //--- get the next indicator object CWndInd *ind=this.m_list_ind.At(i); if(ind==NULL) continue; //--- If such an indicator is present in the chart window, move on to the next object in the list if(this.IsPresentInWindow(ind)) continue; //--- Create a copy of a removed indicator CWndInd *ind_del=new CWndInd(ind.Handle(),ind.Name(),ind.Index(),ind.WindowNum()); if(ind_del==NULL) continue; //--- If failed to place a created object to the list of indicators removed from the window, //--- remove it and go to the next object in the list if(!this.m_list_ind_del.Add(ind_del)) { delete ind_del; continue; } //--- Remove the indicator, which was deleted from the window, from the list this.m_list_ind.Delete(i); } } //+------------------------------------------------------------------+
メソッドロジックは、コードリストで詳細に説明されています。特別な説明は必要ないと思います。ご質問がある場合は、下のコメント欄でお気軽にお問い合わせください。
以下は、リスト内のウィンドウから指標の存在のフラグを返すメソッドです。
//+-----------------------------------------------------------------------------+ //| Return the flag of the presence of an indicator from the window in the list | //+-----------------------------------------------------------------------------+ bool CChartWnd::IsPresentInList(const string name) { CWndInd *ind=new CWndInd(); if(ind==NULL) return false; ind.SetName(name); this.m_list_ind.Sort(SORT_BY_CHART_WINDOW_IND_NAME); int index=this.m_list_ind.Search(ind); delete ind; return(index>WRONG_VALUE); } //+------------------------------------------------------------------+
このメソッドでは、短縮名を使用して、ウィンドウオブジェクトリスト内の適切な指標オブジェクトの存在を定義できます。
ここでは、一時的な指標オブジェクトを作成し、メソッドに渡される短縮名を割り当てます。指標名で並べ替えるフラグを指標オブジェクトのリストに設定し、リストにそのような名前の指標インデックスを取得します。必ず一時オブジェクトを削除し、リストで検出された指標のインデックスが-1を超えることを示すフラグを返します(そのような名前の指標が見つかった場合は、 そのインデックスは-1を超えています)。
以下は、リストには存在するがチャートウィンドウには存在しない指標オブジェクトを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the indicator object present in the list | //| but not on the chart | //+------------------------------------------------------------------+ CWndInd *CChartWnd::GetMissingInd(void) { for(int i=0;i<this.m_list_ind.Total();i++) { CWndInd *ind=this.m_list_ind.At(i); if(!this.IsPresentInWindow(ind)) return ind; } return NULL; } //+------------------------------------------------------------------+
ここで、リスト内のすべての指標オブジェクトを反復処理して、次の指標オブジェクトを取得します。チャートにそのような指標がない場合は、検出された指標オブジェクトへのポインタを返します。それ以外の場合は、 NULLを返します。
以下は、チャートウィンドウリストの指標インデックスによってオブジェクトリストから指標オブジェクトを返すメソッドです。
//+------------------------------------------------------------------+ //| Return the indicator object by the index in the window list | //+------------------------------------------------------------------+ CWndInd *CChartWnd::GetIndicatorByIndex(const int index) { CWndInd *ind=new CWndInd(); if(ind==NULL) return NULL; ind.SetIndex(index); this.m_list_ind.Sort(SORT_BY_CHART_WINDOW_IND_INDEX); int n=this.m_list_ind.Search(ind); delete ind; return this.m_list_ind.At(n); } //+------------------------------------------------------------------+
ここでは、一時的な指標オブジェクトを作成し、メソッドに渡されたインデックスを割り当てます。チャートの指標インデックスによる並べ替えのフラグを指標オブジェクトのリストに設定し、チャートウィンドウリストにそのようなインデックスがあるウィンドウオブジェクトリストの指標インデックスを取得します 。必ず一時オブジェクトを削除し、 指標オブジェクトのリストで指定されたインデックスによってオブジェクトへのポインタを返します。
オブジェクトが見つからなかった場合、Search()メソッドは-1を返し、At()メソッドはそのようなインデックス値の場合は NULLを返します。したがって、このメソッドは、リストで検出されたオブジェクトへのポインタを返すか、チャートウィンドウで指定されたインデックスを持つ指標オブジェクトがリストに存在しない場合は NULLを返します。
以下は、リストからウィンドウ指標オブジェクトをハンドルで返すメソッドです。
//+------------------------------------------------------------------+ //| Return the window indicator object from the list by handle | //+------------------------------------------------------------------+ CWndInd *CChartWnd::GetIndicatorByHandle(const int handle) { CWndInd *ind=new CWndInd(); if(ind==NULL) return NULL; ind.SetHandle(handle); this.m_list_ind.Sort(SORT_BY_CHART_WINDOW_IND_HANDLE); int index=this.m_list_ind.Search(ind); delete ind; return this.m_list_ind.At(index); } //+------------------------------------------------------------------+
このメソッドは、必要な指標オブジェクトのハンドルの値を受け取ることを除いて、上記で検討したメソッドと同じです。したがって、リストは「指標ハンドル」プロパティによって並び替えられ、リスト内の検索はこのオブジェクトプロパティによって実行されます。
パラメータの数またはパラメータ自体に変更があった場合に、カスタムイベントを制御プログラムチャートに送信するためのウィンドウに添付された指標によってデータを更新するメソッドを改善します。
//+------------------------------------------------------------------+ //| Update data on attached indicators | //+------------------------------------------------------------------+ void CChartWnd::Refresh(void) { //--- Calculate the change of the indicator number in the "now and during the previous check" window int change=::ChartIndicatorsTotal(this.m_chart_id,this.m_window_num)-this.m_list_ind.Total(); //--- If there is no change in the number of indicators in the window, if(change==0) { //--- check the change of parameters of all indicators and exit this.IndicatorsChangeCheck(); return; } //--- If indicators are added if(change>0) { //--- Call the method of adding new indicators to the list this.IndicatorsAdd(); //--- In the loop by the number of indicators added to the window, for(int i=0;i<change;i++) { //--- get the new indicator in the list by the index calculated from the end of the list int index=this.m_list_ind.Total()-(1+i); //--- and if failed to obtain the object, move on to the next one CWndInd *ind=this.m_list_ind.At(index); if(ind==NULL) continue; //--- call the method of sending an event to the control program chart this.SendEvent(CHART_OBJ_EVENT_CHART_WND_IND_ADD); } } //--- If there are removed indicators if(change<0) { //--- Call the method of removing unnecessary indicators from the list this.IndicatorsDelete(); //--- In the loop by the number of indicators removed from the window, for(int i=0;i<-change;i++) { //--- get a new removed indicator in the list of removed indicators by index calculated from the end of the list int index=this.m_list_ind_del.Total()-(1+i); //--- and if failed to obtain the object, move on to the next one CWndInd *ind=this.m_list_ind_del.At(index); if(ind==NULL) continue; //--- call the method of sending an event to the control program chart this.SendEvent(CHART_OBJ_EVENT_CHART_WND_IND_DEL); } } } //+------------------------------------------------------------------+
メソッドロジックは、コードで説明されています。指標(または削除された指標)リストに新しく追加された指標オブジェクトの反復処理は、イベント処理の現在の実装では必要ありません。これで、イベントの送信メソッドをすぐに呼び出すことができます。ただし、単一のタイマーティック内で一度に複数の指標の変更を正しく追跡するためにクラスを再配置する必要がある場合は、リストに新しく追加された指標オブジェクトを検索するループが必要になることがあります。これを実装するのは手動よりもプログラムでのほうがはるかに簡単です。現在、チャートに手動変更の処理を実装しています。したがって、これらのループは今のところ必要ありませんが、将来の開発で役立つ可能性があります。
以下は、チャートウィンドウイベントを作成して制御プログラムチャートに送信するメソッドです。
//+------------------------------------------------------------------+ //| Create and send a chart window event | //| to the control program chart | //+------------------------------------------------------------------+ void CChartWnd::SendEvent(ENUM_CHART_OBJ_EVENT event) { //--- If an indicator is added if(event==CHART_OBJ_EVENT_CHART_WND_IND_ADD) { //--- Get the last indicator object added to the list CWndInd *ind=this.GetLastAddedIndicator(); if(ind==NULL) return; //--- Send the CHART_OBJ_EVENT_CHART_WND_IND_ADD event to the control program chart //--- pass the chart ID to lparam, //--- pass the chart window index to dparam, //--- pass the short name of the added indicator to sparam ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name()); } //--- If the indicator is removed else if(event==CHART_OBJ_EVENT_CHART_WND_IND_DEL) { //--- Get the last indicator object added to the list of removed indicators CWndInd *ind=this.GetLastDeletedIndicator(); if(ind==NULL) return; //--- Send the CHART_OBJ_EVENT_CHART_WND_IND_DEL event to the control program chart //--- pass the chart ID to lparam, //--- pass the chart window index to dparam, //--- pass the short name of a deleted indicator to sparam ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name()); } //--- If the indicator has changed else if(event==CHART_OBJ_EVENT_CHART_WND_IND_CHANGE) { //--- Get the last indicator object added to the list of changed indicators CWndInd *ind=this.GetLastChangedIndicator(); if(ind==NULL) return; //--- Send the CHART_OBJ_EVENT_CHART_WND_IND_CHANGE event to the control program chart //--- pass the chart ID to lparam, //--- pass the chart window index to dparam, //--- pass the short name of a changed indicator to sparam ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name()); } } //+------------------------------------------------------------------+
メソッドロジック全体は、コードで詳しく説明されています。ご質問がある場合は、下のコメント欄でお気軽にお問い合わせください。
それでは、\MQL5\Include\DoEasy\Objects\Chart\ChartObj.mqhのチャートオブジェクトクラスを改善しましょう。
チャートウィンドウオブジェクトクラスと同様に、このクラスをすべてのライブラリオブジェクトの拡張オブジェクトのクラスの子孫にします。クラスのprivateセクションでは削除されたチャートウィンドウ、削除および変更された指標へのポインタ、およびチャートウィンドウを再作成するメソッドを宣言します。
//+------------------------------------------------------------------+ //| Chart object class | //+------------------------------------------------------------------+ class CChartObj : public CBaseObjExt { private: CArrayObj m_list_wnd; // List of chart window objects CArrayObj *m_list_wnd_del; // Pointer to the list of chart window objects CArrayObj *m_list_ind_del; // Pointer to the list of indicators removed from the indicator window CArrayObj *m_list_ind_param; // Pointer to the list of changed indicators long m_long_prop[CHART_PROP_INTEGER_TOTAL]; // Integer properties double m_double_prop[CHART_PROP_DOUBLE_TOTAL]; // Real properties string m_string_prop[CHART_PROP_STRING_TOTAL]; // String properties int m_digits; // Symbol's Digits() datetime m_wnd_time_x; // Time for X coordinate on the windowed chart double m_wnd_price_y; // Price for Y coordinate on the windowed chart //--- Return the index of the array the (1) double and (2) string properties are actually located at int IndexProp(ENUM_CHART_PROP_DOUBLE property) const { return(int)property-CHART_PROP_INTEGER_TOTAL; } int IndexProp(ENUM_CHART_PROP_STRING property) const { return(int)property-CHART_PROP_INTEGER_TOTAL-CHART_PROP_DOUBLE_TOTAL; } //--- The methods of setting parameter flags bool SetShowFlag(const string source,const bool flag,const bool redraw=false); bool SetBringToTopFlag(const string source,const bool flag,const bool redraw=false); bool SetContextMenuFlag(const string source,const bool flag,const bool redraw=false); bool SetCrosshairToolFlag(const string source,const bool flag,const bool redraw=false); bool SetMouseScrollFlag(const string source,const bool flag,const bool redraw=false); bool SetEventMouseWhellFlag(const string source,const bool flag,const bool redraw=false); bool SetEventMouseMoveFlag(const string source,const bool flag,const bool redraw=false); bool SetEventObjectCreateFlag(const string source,const bool flag,const bool redraw=false); bool SetEventObjectDeleteFlag(const string source,const bool flag,const bool redraw=false); bool SetForegroundFlag(const string source,const bool flag,const bool redraw=false); bool SetShiftFlag(const string source,const bool flag,const bool redraw=false); bool SetAutoscrollFlag(const string source,const bool flag,const bool redraw=false); bool SetKeyboardControlFlag(const string source,const bool flag,const bool redraw=false); bool SetQuickNavigationFlag(const string source,const bool flag,const bool redraw=false); bool SetScaleFixFlag(const string source,const bool flag,const bool redraw=false); bool SetScaleFix11Flag(const string source,const bool flag,const bool redraw=false); bool SetScalePTPerBarFlag(const string source,const bool flag,const bool redraw=false); bool SetShowTickerFlag(const string source,const bool flag,const bool redraw=false); bool SetShowOHLCFlag(const string source,const bool flag,const bool redraw=false); bool SetShowBidLineFlag(const string source,const bool flag,const bool redraw=false); bool SetShowAskLineFlag(const string source,const bool flag,const bool redraw=false); bool SetShowLastLineFlag(const string source,const bool flag,const bool redraw=false); bool SetShowPeriodSeparatorsFlag(const string source,const bool flag,const bool redraw=false); bool SetShowGridFlag(const string source,const bool flag,const bool redraw=false); bool SetShowObjectDescriptionsFlag(const string source,const bool flag,const bool redraw=false); bool SetShowTradeLevelsFlag(const string source,const bool flag,const bool redraw=false); bool SetDragTradeLevelsFlag(const string source,const bool flag,const bool redraw=false); bool SetShowDateScaleFlag(const string source,const bool flag,const bool redraw=false); bool SetShowPriceScaleFlag(const string source,const bool flag,const bool redraw=false); bool SetShowOneClickPanelFlag(const string source,const bool flag,const bool redraw=false); bool SetDockedFlag(const string source,const bool flag,const bool redraw=false); //--- The methods of setting property values bool SetMode(const string source,const ENUM_CHART_MODE mode,const bool redraw=false); bool SetScale(const string source,const int scale,const bool redraw=false); bool SetModeVolume(const string source,const ENUM_CHART_VOLUME_MODE mode,const bool redraw=false); void SetVisibleBars(void); void SetWindowsTotal(void); void SetFirstVisibleBars(void); void SetWidthInBars(void); void SetWidthInPixels(void); void SetMaximizedFlag(void); void SetMinimizedFlag(void); void SetExpertName(void); void SetScriptName(void); //--- (1) Create, (2) check and re-create the chart window list void CreateWindowsList(void); void RecreateWindowsList(const int change); //--- Add an extension to the screenshot file if it is missing string FileNameWithExtention(const string filename); public:
クラスのpublicセクションで、クラスイベントを操作するための新しいメソッドを実装および宣言 します。
新しいリストへのポインタをパラメトリックコンストラクタに渡します。
public: //--- Set object's (1) integer, (2) real and (3) string properties void SetProperty(ENUM_CHART_PROP_INTEGER property,long value) { this.m_long_prop[property]=value; } void SetProperty(ENUM_CHART_PROP_DOUBLE property,double value) { this.m_double_prop[this.IndexProp(property)]=value; } void SetProperty(ENUM_CHART_PROP_STRING property,string value) { this.m_string_prop[this.IndexProp(property)]=value; } //--- Return object’s (1) integer, (2) real and (3) string property from the properties array long GetProperty(ENUM_CHART_PROP_INTEGER property) const { return this.m_long_prop[property]; } double GetProperty(ENUM_CHART_PROP_DOUBLE property) const { return this.m_double_prop[this.IndexProp(property)]; } string GetProperty(ENUM_CHART_PROP_STRING property) const { return this.m_string_prop[this.IndexProp(property)]; } //--- Return (1) itself, (2) the window object list and (3) the list of removed window objects CChartObj *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list_wnd; } //--- Return the last (1) added (removed) chart window CChartWnd *GetLastAddedWindow(void) { return this.m_list_wnd.At(this.m_list_wnd.Total()-1); } CChartWnd *GetLastDeletedWindow(void) { return this.m_list_wnd_del.At(this.m_list_wnd_del.Total()-1); } //--- Return (1) the last one added to the window, (2) the last one removed from the window and (3) the changed indicator, CWndInd *GetLastAddedIndicator(const int win_num); CWndInd *GetLastDeletedIndicator(void) { return this.m_list_ind_del.At(this.m_list_ind_del.Total()-1); } CWndInd *GetLastChangedIndicator(void) { return this.m_list_ind_param.At(this.m_list_ind_param.Total()-1);} //--- Return the indicator by index from the specified chart window CWndInd *GetIndicator(const int win_num,const int ind_index); //--- Return the flag of the object supporting this property virtual bool SupportProperty(ENUM_CHART_PROP_INTEGER property) { return (property!=CHART_PROP_WINDOW_YDISTANCE ? true : false); } virtual bool SupportProperty(ENUM_CHART_PROP_DOUBLE property) { return true; } virtual bool SupportProperty(ENUM_CHART_PROP_STRING property) { return true; } //--- Get description of (1) integer, (2) real and (3) string properties string GetPropertyDescription(ENUM_CHART_PROP_INTEGER property); string GetPropertyDescription(ENUM_CHART_PROP_DOUBLE property); string GetPropertyDescription(ENUM_CHART_PROP_STRING property); //--- Display the description of object properties in the journal (full_prop=true - all properties, false - supported ones only) void Print(const bool full_prop=false); //--- Display a short description of the object in the journal virtual void PrintShort(const bool dash=false); //--- Return the object short name virtual string Header(void); //--- Create and send the chart event to the control program chart void SendEvent(ENUM_CHART_OBJ_EVENT event); //--- Compare CChartObj objects by a specified property (to sort the list by a specified chart object property) virtual int Compare(const CObject *node,const int mode=0) const; //--- Compare CChartObj objects by all properties (to search for equal chart objects) bool IsEqual(CChartObj* compared_obj) const; //--- Update the chart object and its list of indicator windows void Refresh(void); //--- Constructors CChartObj(){;} CChartObj(const long chart_id,CArrayObj *list_wnd_del,CArrayObj *list_ind_del,CArrayObj *list_ind_param); //+------------------------------------------------------------------+
新しく改善されたクラスメソッドについて考えてみましょう。
パラメトリックコンストラクタで、リストオブジェクトへのポインタを格納する変数がメソッドに渡されるそれらへのポインタを受け取るようにします。
//+------------------------------------------------------------------+ //| Parametric constructor | //+------------------------------------------------------------------+ CChartObj::CChartObj(const long chart_id,CArrayObj *list_wnd_del,CArrayObj *list_ind_del,CArrayObj *list_ind_param) : m_wnd_time_x(0),m_wnd_price_y(0) { this.m_list_wnd_del=list_wnd_del; this.m_list_ind_del=list_ind_del; this.m_list_ind_param=list_ind_param; //--- Set chart ID to the base object
コンストラクタリストの最後で、チャートウィンドウインデックスによる並べ替えのフラグを、削除されたチャートオブジェクトウィンドウのリストに設定します。
this.m_digits=(int)::SymbolInfoInteger(this.Symbol(),SYMBOL_DIGITS); this.m_list_wnd_del.Sort(SORT_BY_CHART_WINDOW_NUM); this.CreateWindowsList(); } //+------------------------------------------------------------------+
以下は、ウィンドウに追加された最後の指標を返すメソッドです。
//+------------------------------------------------------------------+ //| Return the last indicator added to the window | //+------------------------------------------------------------------+ CWndInd *CChartObj::GetLastAddedIndicator(const int win_num) { CChartWnd *wnd=this.GetWindowByNum(win_num); return(wnd!=NULL ? wnd.GetLastAddedIndicator() : NULL); } //+------------------------------------------------------------------+
このメソッドはチャートのウィンドウインデックスを受け取り、そこから最後に追加された指標を取得します。GetWindowByNum()メソッドを使用して、必要なチャートウィンドウを取得します。次に、そのチャートウィンドウから最後に追加された指標を取得します。チャートウィンドウオブジェクトの取得に失敗した場合は、NULLを返します。GetLastAddedIndicator()チャートウィンドウオブジェクトメソッドもNULLを返す可能性があることに注意してください。
以下は、指定されたチャートウィンドウからインデックスで指標を返すメソッドです。
//+------------------------------------------------------------------+ //| Return the indicator by index from the specified chart window | //+------------------------------------------------------------------+ CWndInd *CChartObj::GetIndicator(const int win_num,const int ind_index) { CChartWnd *wnd=this.GetWindowByNum(win_num); return(wnd!=NULL ? wnd.GetIndicatorByIndex(ind_index) : NULL); } //+------------------------------------------------------------------+
このメソッドはチャートウィンドウインデックスを受け取り、このインデックスから、ウィンドウリストで最後に追加された指標と指標インデックスを取得します。
GetWindowByNum()メソッドを使用して、必要なチャートウィンドウを取得して、指標をチャートウィンドウのインデックスによって取得します。チャートウィンドウオブジェクトの取得に失敗した場合は、NULLを返します。GetIndicatorByIndex()チャートウィンドウオブジェクトメソッドも NULLを返す可能性があることに注意してください。
チャートオブジェクトとそのウィンドウのリストを更新するメソッドで、CreateWindowsList()メソッドを新しいRecreateWindowsList()メソッドに置き換えます。
//+------------------------------------------------------------------+ //| Update the chart object and its window list | //+------------------------------------------------------------------+ void CChartObj::Refresh(void) { for(int i=0;i<this.m_list_wnd.Total();i++) { CChartWnd *wnd=this.m_list_wnd.At(i); if(wnd==NULL) continue; wnd.Refresh(); } int change=(int)::ChartGetInteger(this.m_chart_id,CHART_WINDOWS_TOTAL)-this.WindowsTotal(); if(change==0) return; this.RecreateWindowsList(change); } //+------------------------------------------------------------------+
チャートウィンドウのリストを作成するCreateWindowsList()メソッドは、プログラムの起動時にウィンドウを構築するためにのみ使用されます。チャートオブジェクトを更新するときは、変更されたウィンドウを再構築するメソッド(以下で検討)を使用します。
次に、新しいチャートウィンドウオブジェクトを作成するときに、チャート銘柄名とリストへのポインタを渡す必要があります。したがって、チャートウィンドウリストを作成するメソッドで、新しいチャートウィンドウオブジェクトを作成するときに、それらをチャートウィンドウオブジェクトクラスコンストラクタに渡すよう実装します。
//+------------------------------------------------------------------+ //| Create the list of chart windows | //+------------------------------------------------------------------+ void CChartObj::CreateWindowsList(void) { //--- Clear the chart window list this.m_list_wnd.Clear(); //--- Get the total number of chart windows from the environment int total=(int)::ChartGetInteger(this.m_chart_id,CHART_WINDOWS_TOTAL); //--- In the loop by the total number of windows for(int i=0;i<total;i++) { //--- Create a new chart window object CChartWnd *wnd=new CChartWnd(this.m_chart_id,i,this.Symbol(),this.m_list_ind_del,this.m_list_ind_param); if(wnd==NULL) continue; //--- If the window index exceeds 0 (not the main chart window) and it still has no indicator, //--- remove the newly created chart window object and go to the next loop iteration if(wnd.WindowNum()!=0 && wnd.IndicatorsTotal()==0) { delete wnd; continue; } //--- If the object was not added to the list, remove that object this.m_list_wnd.Sort(); if(!this.m_list_wnd.Add(wnd)) delete wnd; } //--- If the number of objects in the list corresponds to the number of windows on the chart, //--- write that value to the chart object property //--- If the number of objects in the list does not correspond to the number of windows on the chart, //--- write the number of objects in the list to the chart object property. int value=int(this.m_list_wnd.Total()==total ? total : this.m_list_wnd.Total()); this.SetProperty(CHART_PROP_WINDOWS_TOTAL,value); } //+------------------------------------------------------------------+
以下は、チャートウィンドウの変更を確認してリストを再作成するメソッドです。
//+------------------------------------------------------------------+ //| Check and re-create the chart window list | //+------------------------------------------------------------------+ void CChartObj::RecreateWindowsList(const int change) { //--- If the window is removed if(change<0) { //--- If the chart has only one window, this means we have only the main chart with no subwindows, //--- while the change in the number of chart windows indicates the removal of a symbol chart in the terminal. //--- This situation is handled in the collection class of chart objects - leave the method if(this.WindowsTotal()==1) return; //--- Get the last removed indicator from the list of removed indicators CWndInd *ind=this.m_list_ind_del.At(this.m_list_ind_del.Total()-1); //--- If managed to get the indicator, if(ind!=NULL) { //--- create a new chart window object CChartWnd *wnd=new CChartWnd(); if(wnd!=NULL) { //--- Set the subwindow index from the last removed indicator object, //--- ID and the chart object symbol name for a new object wnd.SetWindowNum(ind.WindowNum()); wnd.SetChartID(this.ID()); wnd.SetSymbol(this.Symbol()); //--- If failed to add the created object to the list of removed chart window objects, remove it if(!this.m_list_wnd_del.Add(wnd)) delete wnd; } } //--- Call the method of sending an event to the control program chart and re-create the chart window list this.SendEvent(CHART_OBJ_EVENT_CHART_WND_DEL); this.CreateWindowsList(); return; } //--- If there are no changes, leave else if(change==0) return; //--- If a window is added //--- Get the total number of chart windows from the environment int total=(int)::ChartGetInteger(this.m_chart_id,CHART_WINDOWS_TOTAL); //--- In the loop by the total number of windows for(int i=0;i<total;i++) { //--- Create a new chart window object CChartWnd *wnd=new CChartWnd(this.m_chart_id,i,this.Symbol(),this.m_list_ind_del,this.m_list_ind_param); if(wnd==NULL) continue; this.m_list_wnd.Sort(SORT_BY_CHART_WINDOW_NUM); //--- If the window index exceeds 0 (not the main chart window) and it still has no indicator, //--- or such a window is already present in the list or the window object is not added to the list //--- remove the newly created chart window object and go to the next loop iteration if((wnd.WindowNum()!=0 && wnd.IndicatorsTotal()==0) || this.m_list_wnd.Search(wnd)>WRONG_VALUE || !this.m_list_wnd.Add(wnd)) { delete wnd; continue; } //--- If added the window, call the method of sending an event to the control program chart this.SendEvent(CHART_OBJ_EVENT_CHART_WND_ADD); } //--- If the number of objects in the list corresponds to the number of windows on the chart, //--- write that value to the chart object property //--- If the number of objects in the list does not correspond to the number of windows on the chart, //--- write the number of objects in the list to the chart object property. int value=int(this.m_list_wnd.Total()==total ? total : this.m_list_wnd.Total()); this.SetProperty(CHART_PROP_WINDOWS_TOTAL,value); } //+------------------------------------------------------------------+
以下は、チャートイベントを作成して制御プログラムチャートに送信するメソッドです。
//+------------------------------------------------------------------+ //| Create and send a chart event | //| to the control program chart | //+------------------------------------------------------------------+ void CChartObj::SendEvent(ENUM_CHART_OBJ_EVENT event) { //--- If a window is added if(event==CHART_OBJ_EVENT_CHART_WND_ADD) { //--- Get the last chart window object added to the list CChartWnd *wnd=this.GetLastAddedWindow(); if(wnd==NULL) return; //--- Send the CHART_OBJ_EVENT_CHART_WND_ADD event to the control program chart //--- pass the chart ID to lparam, //--- pass the chart window index to dparam, //--- pass the chart symbol to sparam ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,wnd.WindowNum(),this.Symbol()); } //--- If the window is removed else if(event==CHART_OBJ_EVENT_CHART_WND_DEL) { //--- Get the last chart window object added to the list of removed windows CChartWnd *wnd=this.GetLastDeletedWindow(); if(wnd==NULL) return; //--- Send the CHART_OBJ_EVENT_CHART_WND_DEL event to the control program chart //--- pass the chart ID to lparam, //--- pass the chart window index to dparam, //--- pass the chart symbol to sparam ::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,wnd.WindowNum(),this.Symbol()); } } //+------------------------------------------------------------------+
最後の2つのメソッドのロジック全体は、リストに完全に記述されており、説明は必要ありません。
メソッドについてご不明な点がございましたら、コメント欄でお気軽にお問い合わせください。
\MQL5\Include\DoEasy\Collections\ChartObjCollection.mqhのチャートオブジェクトコレクションクラスを改善します。
クラスのprivateセクションで、リストオブジェクトを宣言します。これへのポインタはチャートウィンドウとチャートウィンドウの指標オブジェクトに渡されています。
//+------------------------------------------------------------------+ //| MQL5 signal object collection | //+------------------------------------------------------------------+ class CChartObjCollection : public CBaseObj { private: CListObj m_list; // List of chart objects CListObj m_list_del; // List of deleted chart objects CArrayObj m_list_wnd_del; // List of deleted chart window objects CArrayObj m_list_ind_del; // List of indicators removed from the indicator window CArrayObj m_list_ind_param; // List of changed indicators int m_charts_total_prev; // Previous number of charts in the terminal //--- Return the number of charts in the terminal int ChartsTotal(void) const; //--- Return the flag indicating the existence of (1) a chart object and (2) a chart bool IsPresentChartObj(const long chart_id); bool IsPresentChart(const long chart_id); //--- Create a new chart object and add it to the list bool CreateNewChartObj(const long chart_id,const string source); //--- Find the missing chart object, create it and add it to the collection list bool FindAndCreateMissingChartObj(void); //--- Find a chart object not present in the terminal and remove it from the list void FindAndDeleteExcessChartObj(void); public:
リストへのポインタの代わりに、ここではCArrayObjオブジェクトを宣言します。ここには、削除されたすべてのチャートオブジェクトが格納されます。
クラスのpublicセクションで、チャートオブジェクトイベントの操作に必要な新しいメソッドを宣言します。
public: //--- Return (1) itself, (2) chart object collection list, (3) the list of deleted chart objects, //--- the list (4) of deleted window objects, (5) deleted and (6) changed indicators CChartObjCollection *GetObject(void) { return &this; } CArrayObj *GetList(void) { return &this.m_list; } CArrayObj *GetListDeletedCharts(void) { return &this.m_list_del; } CArrayObj *GetListDeletedWindows(void) { return &this.m_list_wnd_del; } CArrayObj *GetListDeletedIndicators(void) { return &this.m_list_ind_del; } CArrayObj *GetListChangedIndicators(void) { return &this.m_list_ind_param; } //--- Return the list by selected (1) integer, (2) real and (3) string properties meeting the compared criterion CArrayObj *GetList(ENUM_CHART_PROP_INTEGER property,long value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByChartProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_CHART_PROP_DOUBLE property,double value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByChartProperty(this.GetList(),property,value,mode); } CArrayObj *GetList(ENUM_CHART_PROP_STRING property,string value,ENUM_COMPARER_TYPE mode=EQUAL) { return CSelect::ByChartProperty(this.GetList(),property,value,mode); } //--- Return the number of chart objects in the list int DataTotal(void) const { return this.m_list.Total(); } //--- Display (1) the complete and (2) short collection description in the journal void Print(void); void PrintShort(void); //--- Constructor CChartObjCollection(); //--- Return the list of chart objects by (1) symbol and (2) timeframe CArrayObj *GetChartsList(const string symbol) { return this.GetList(CHART_PROP_SYMBOL,symbol,EQUAL); } CArrayObj *GetChartsList(const ENUM_TIMEFRAMES timeframe) { return this.GetList(CHART_PROP_TIMEFRAME,timeframe,EQUAL);} //--- Return the pointer to the chart object (1) by ID and (2) by an index in the list CChartObj *GetChart(const long id); CChartObj *GetChart(const int index) { return this.m_list.At(index); } //--- Return (1) the last added chart and (2) the last removed chart CChartObj *GetLastAddedChart(void) { return this.m_list.At(this.m_list.Total()-1); } CChartObj *GetLastDeletedChart(void) { return this.m_list_del.At(this.m_list_del.Total()-1); } //--- Return (1) the last added window on the chart by chart ID and (2) the last removed chart window CChartWnd *GetLastAddedChartWindow(const long chart_id); CChartWnd *GetLastDeletedChartWindow(void) { return this.m_list_wnd_del.At(this.m_list_wnd_del.Total()-1);} //--- Return (1) the last one added to the specified window of the specified chart, (2) the last one removed from the window and (3) the changed indicator CWndInd *GetLastAddedIndicator(const long chart_id,const int win_num); CWndInd *GetLastDeletedIndicator(void) { return this.m_list_ind_del.At(this.m_list_ind_del.Total()-1); } CWndInd *GetLastChangedIndicator(void) { return this.m_list_ind_param.At(this.m_list_ind_param.Total()-1);} //--- Return the indicator by index from the specified window of the specified chart CWndInd *GetIndicator(const long chart_id,const int win_num,const int ind_index); //--- Return the chart ID with the program long GetMainChartID(void) const { return CBaseObj::GetMainChartID(); } //--- Create the collection list of chart objects bool CreateCollection(void); //--- Update (1) the chart object collection list and (2) the specified chart object void Refresh(void); void Refresh(const long chart_id); //--- (1) Open a new chart with the specified symbol and period, (2) close the specified chart bool Open(const string symbol,const ENUM_TIMEFRAMES timeframe); bool Close(const long chart_id); //--- Create and send the chart event to the control program chart void SendEvent(ENUM_CHART_OBJ_EVENT event); }; //+------------------------------------------------------------------+
新しいメソッドの実装と既存のメソッドの改善について考えてみましょう。
クラスコンストラクタで、新しいリストをクリアし、並び替えられたリストフラグを設定します。
//+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CChartObjCollection::CChartObjCollection() { this.m_list.Clear(); this.m_list.Sort(); this.m_list_ind_del.Clear(); this.m_list_ind_del.Sort(); this.m_list_ind_param.Clear(); this.m_list_ind_param.Sort(); this.m_list_wnd_del.Clear(); this.m_list_wnd_del.Sort(); this.m_list_del.Clear(); this.m_list_del.Sort(); this.m_list.Type(COLLECTION_CHARTS_ID); this.m_charts_total_prev=this.ChartsTotal(); } //+------------------------------------------------------------------+
チャートオブジェクトコレクションリストを宣言するメソッドで、制御プログラムチャートにイベントを送信するメソッドの呼び出しを追加します。
//+------------------------------------------------------------------+ //| Update the collection list of chart objects | //+------------------------------------------------------------------+ void CChartObjCollection::Refresh(void) { //--- In the loop by the number of chart objects in the list, for(int i=0;i<this.m_list.Total();i++) { //--- get the next chart object and CChartObj *chart=this.m_list.At(i); if(chart==NULL) continue; //--- update it chart.Refresh(); } //--- Get the number of open charts in the terminal and int charts_total=this.ChartsTotal(); //--- calculate the difference between the number of open charts in the terminal //--- and chart objects in the collection list int change=charts_total-this.m_list.Total(); //--- If there are no changes, leave if(change==0) return; //--- If a chart is added in the terminal if(change>0) { //--- Find the missing chart object, create and add it to the collection list this.FindAndCreateMissingChartObj(); //--- Get the current chart and return to it since //--- adding a new chart switches the focus to it CChartObj *chart=this.GetChart(GetMainChartID()); if(chart!=NULL) chart.SetBringToTopON(true); for(int i=0;i<change;i++) { chart=m_list.At(m_list.Total()-(1+i)); if(chart==NULL) continue; this.SendEvent(CHART_OBJ_EVENT_CHART_OPEN); } } //--- If a chart is removed in the terminal else if(change<0) { //--- Find an extra chart object in the collection list and remove it from the list this.FindAndDeleteExcessChartObj(); for(int i=0;i<-change;i++) { CChartObj *chart=this.m_list_del.At(this.m_list_del.Total()-(1+i)); if(chart==NULL) continue; this.SendEvent(CHART_OBJ_EVENT_CHART_CLOSE); } } } //+------------------------------------------------------------------+
SendEvent()メソッドが呼び出されるコードブロックは、チャートウィンドウオブジェクトクラスで以前に検討されたものと同じであり、将来の改善の可能性を念頭に置いて実装されています。ターミナルチャートの手動変更を処理するための反復処理は必要ありません。イベントを送信するメソッドをすぐに呼び出すことができます。
新しいチャートオブジェクトを作成してリストに追加するメソッドで、新しいチャートオブジェクトを作成するときに新しいリストへのポインタを渡すことができるようになりました。これらの変更を追加しましょう。
//+------------------------------------------------------------------+ //| Create a new chart object and add it to the list | //+------------------------------------------------------------------+ bool CChartObjCollection::CreateNewChartObj(const long chart_id,const string source) { ::ResetLastError(); CChartObj *chart_obj=new CChartObj(chart_id,this.GetListDeletedWindows(),this.GetListDeletedIndicators(),this.GetListChangedIndicators()); if(chart_obj==NULL) { CMessage::ToLog(source,MSG_CHART_COLLECTION_ERR_FAILED_CREATE_CHART_OBJ,true); return false; } this.m_list.Sort(SORT_BY_CHART_ID); if(!this.m_list.InsertSort(chart_obj)) { CMessage::ToLog(source,MSG_CHART_COLLECTION_ERR_FAILED_ADD_CHART,true); delete chart_obj; return false; } return true; } //+------------------------------------------------------------------+
以下は、最後に追加されたウィンドウをチャートIDでチャートに返すメソッドです。
//+------------------------------------------------------------------+ //| Return the last added window to the chart by ID | //+------------------------------------------------------------------+ CChartWnd* CChartObjCollection::GetLastAddedChartWindow(const long chart_id) { CChartObj *chart=this.GetChart(chart_id); if(chart==NULL) return NULL; CArrayObj *list=chart.GetList(); return(list!=NULL ? list.At(list.Total()-1) : NULL); } //+------------------------------------------------------------------+
このメソッドは、最後に追加されたウィンドウを取得するチャートのIDを受け取ります。
メソッドに渡されたIDでチャートオブジェクトを取得し、ウィンドウのリストを取得します。
最後に追加されたウィンドウは常にリストの最後にあります。チャートウィンドウのリストの最後にあるオブジェクトまたはそれができなかった場合は NULL を返します。
以下は、指定されたチャートの指定されたウィンドウに追加された最後の指標を返すメソッドです。
//+------------------------------------------------------------------+ //| Return the last indicator added | //| to the specified window of the specified chart | //+------------------------------------------------------------------+ CWndInd* CChartObjCollection::GetLastAddedIndicator(const long chart_id,const int win_num) { CChartObj *chart=this.GetChart(chart_id); return(chart!=NULL ? chart.GetLastAddedIndicator(win_num) : NULL); } //+------------------------------------------------------------------+
このメソッドは、チャートID と最後に追加された指標を取得するサブウィンドウの番号を受け取ります。
メソッドに渡されたIDでチャートオブジェクトを取得し、GetLastAddedIndicator()チャートオブジェクトメソッドを使用して、指定されたチャートウィンドウに追加された最後の指標へのポインタを返します。失敗した場合は NULLを返します。
以下は、指定されたチャートの指定されたウィンドウからインデックスによって指標を返すメソッドです。
//+------------------------------------------------------------------+ //| Return the indicator by index | //| from the specified window of the specified chart | //+------------------------------------------------------------------+ CWndInd* CChartObjCollection::GetIndicator(const long chart_id,const int win_num,const int ind_index) { CChartObj *chart=this.GetChart(chart_id); return(chart!=NULL ? chart.GetIndicator(win_num,ind_index) : NULL); } //+------------------------------------------------------------------+
このメソッドは、チャートID、サブウィンドウインデックス、取得したい指標インデックスを受け取ります。
メソッドに渡されたIDでチャートオブジェクトを取得して、GetIndicator()チャートオブジェクトメソッドを使用して指定されたチャートウィンドウから指標へのポインタを返します 。失敗した場合は、 NULLを返します。
ターミナルに存在しないチャートオブジェクトを見つけてリストから削除するメソッドで検出したチャートオブジェクトを削除されたチャートのリストに配置する、コードブロックを追加します。
//+-----------------------------------------------------------------------------+ //|Find a chart object not present in the terminal and remove it from the list | //+-----------------------------------------------------------------------------+ void CChartObjCollection::FindAndDeleteExcessChartObj(void) { for(int i=this.m_list.Total()-1;i>WRONG_VALUE;i--) { CChartObj *chart=this.m_list.At(i); if(chart==NULL) continue; if(!this.IsPresentChart(chart.ID())) { chart=this.m_list.Detach(i); if(chart!=NULL) { if(!this.m_list_del.Add(chart)) this.m_list.Delete(i); } } } } //+------------------------------------------------------------------+
ここで、リストから取得したチャートオブジェクトがクライアントターミナルに存在しない場合、Detach()標準ライブラリメソッドを使用してオブジェクトをリストから削除して削除されたチャートのリストに追加します。削除したオブジェクトを新しいリストに配置できなかった場合、記憶を避けるために削除します。
以下は、チャートイベントを作成して制御プログラムチャートに送信するメソッドです。
//+------------------------------------------------------------------+ //| Create and send a chart event | //| to the control program chart | //+------------------------------------------------------------------+ void CChartObjCollection::SendEvent(ENUM_CHART_OBJ_EVENT event) { //--- If a chart is added if(event==CHART_OBJ_EVENT_CHART_OPEN) { //--- Get the last chart object added to the list CChartObj *chart=this.GetLastAddedChart(); if(chart==NULL) return; //--- Send the CHART_OBJ_EVENT_CHART_OPEN event to the control program chart //--- pass the chart ID to lparam, //--- pass the chart timeframe to dparam, //--- pass the chart symbol to sparam ::EventChartCustom(this.m_chart_id_main,(ushort)event,chart.ID(),chart.Timeframe(),chart.Symbol()); } //--- If a chart is removed else if(event==CHART_OBJ_EVENT_CHART_CLOSE) { //--- Get the last chart object added to the list of removed charts CChartObj *chart=this.GetLastDeletedChart(); if(chart==NULL) return; //--- Send the CHART_OBJ_EVENT_CHART_CLOSE event to the control program chart //--- pass the chart ID to lparam, //--- pass the chart timeframe to dparam, //--- pass the chart symbol to sparam ::EventChartCustom(this.m_chart_id_main,(ushort)event,chart.ID(),chart.Timeframe(),chart.Symbol()); } } //+------------------------------------------------------------------+
メソッドロジックは、コードで詳細に説明されています。説明は必要ないと思います。
チャートイベントを追跡する
いくつかのチャートイベントを追跡する機能を作成しました。次に、制御プログラムにアクセスを提供する必要があります。これを実現するために、CEngineライブラリのメインクラスを使用します。これは、本稿で実装したチャートオブジェクトコレクションクラスメソッドへのアクセスを提供する新しいメソッドを備えている必要があります。前の記事で説明したチャートオブジェクトコレクションリストを更新する関数がすでにあるので、制御プログラムでイベントを追跡する準備が整っています。テストEAのライブラリからの着信イベント(つまり、チャートオブジェクトコレクションクラスから到着するイベント)の処理を実装するだけで済みます。
ライブラリは、すべてのチャートプロパティ、それらのウィンドウ、および指標の変更をまだ追跡できません。ただし、すべてのオブジェクトはすでにすべてのライブラリオブジェクトの基本オブジェクトの拡張クラスの子孫であるため(子孫にイベント機能を自動的に付与します)、オブジェクトのプロパティを管理するためのメソッドを追加するだけです。 これは次の記事に残しておきます。それでは、新しい機能を「外の世界」に接続して、現在の記事で実装したすべてをテストしてみましょう。
CEngineライブラリのメインオブジェクトの\MQL5\Include\DoEasy\Engine.mqhに、チャートオブジェクトコレクションにアクセスするためのメソッドを追加します。
//--- Return the list of chart objects by (1) symbol and (2) timeframe CArrayObj *GetListCharts(const string symbol) { return this.m_charts.GetChartsList(symbol); } CArrayObj *GetListCharts(const ENUM_TIMEFRAMES timeframe) { return this.m_charts.GetChartsList(timeframe); } //--- Return the list of removed (1) chart objects, (2) chart windows, (3) indicators in the chart window and (4) changed indicators in the chart window CArrayObj *GetListChartsClosed(void) { return this.m_charts.GetListDeletedCharts(); } CArrayObj *GetListChartWindowsDeleted(void) { return this.m_charts.GetListDeletedWindows(); } CArrayObj *GetListChartWindowsIndicatorsDeleted(void) { return this.m_charts.GetListDeletedIndicators(); } CArrayObj *GetListChartWindowsIndicatorsChanged(void) { return this.m_charts.GetListChangedIndicators(); } //--- Return (1) the specified chart object and (2) the chart object with the program CChartObj *ChartGetChartObj(const long chart_id) { return this.m_charts.GetChart(chart_id); } CChartObj *ChartGetMainChart(void) { return this.m_charts.GetChart(this.m_charts.GetMainChartID());} //--- Reutrn the chart object of the last (1) open and (2) closed chart CChartObj *ChartGetLastOpenedChart(void) { return this.m_charts.GetLastAddedChart(); } CChartObj *ChartGetLastClosedChart(void) { return this.m_charts.GetLastDeletedChart(); } //--- Return the object (1) of the last added window of the specified chart and (2) the last removed chart window CChartWnd *ChartGetLastAddedChartWindow(const long chart_id) { return this.m_charts.GetLastAddedChartWindow(chart_id);} CChartWnd *ChartGetLastDeletedChartWindow(void) { return this.m_charts.GetLastDeletedChartWindow(); } //--- Return (1) the last one added to the specified window of the specified chart, (2) the last one removed from the window and (3) the changed indicator CWndInd *ChartGetLastAddedIndicator(const long id,const int win) { return m_charts.GetLastAddedIndicator(id,win); } CWndInd *ChartGetLastDeletedIndicator(void) { return this.m_charts.GetLastDeletedIndicator(); } CWndInd *ChartGetLastChangedIndicator(void) { return this.m_charts.GetLastChangedIndicator(); } //--- Return the indicator by index from the specified window of the specified chart CWndInd *ChartGetIndicator(const long chart_id,const int win_num,const int ind_index) { return m_charts.GetIndicator(chart_id,win_num,ind_index); } //--- Return the number of charts in the collection list int ChartsTotal(void) { return this.m_charts.DataTotal(); }
新しく追加されたすべてのメソッドは、適切なチャートオブジェクトコレクションメソッドを呼び出した結果を返します。
検証
テストを実行するには、前の記事のEAを\MQL5\Experts\TestDoEasy\Part71\で TestDoEasyPart71.mq5として保存します。
OnDoEasyEvent()ライブラリイベントハンドラに新しいイベントコードの処理を追加するだけです。
関数のコードを全部を検討しても意味がありません。これは大きく、異なるライブラリオブジェクトからのイベントの個別のハンドラに分割する必要があります。これについては後で扱います。
次に、OnDoEasyEvent()EA関数に追加されるコードブロックについて考えてみましょう。
//--- Handling timeseries events else if(idx>SERIES_EVENTS_NO_EVENT && idx<SERIES_EVENTS_NEXT_CODE) { //--- "New bar" event if(idx==SERIES_EVENTS_NEW_BAR) { Print(TextByLanguage("Новый бар на ","New Bar on "),sparam," ",TimeframeDescription((ENUM_TIMEFRAMES)dparam),": ",TimeToString(lparam)); } } //--- Handle chart events else if(idx>CHART_OBJ_EVENT_NO_EVENT && idx<CHART_OBJ_EVENTS_NEXT_CODE) { //--- "New chart opening" event if(idx==CHART_OBJ_EVENT_CHART_OPEN) { //::EventChartCustom(this.m_chart_id_main,(ushort)event,chart.ID(),chart.Timeframe(),chart.Symbol()); CChartObj *chart=engine.ChartGetLastOpenedChart(); if(chart!=NULL) { string symbol=sparam; long chart_id=lparam; ENUM_TIMEFRAMES timeframe=(ENUM_TIMEFRAMES)dparam; string header=symbol+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id; Print(DFUN,CMessage::Text(MSG_CHART_COLLECTION_CHART_OPENED),": ",header); } } //--- "Chart closure" event if(idx==CHART_OBJ_EVENT_CHART_CLOSE) { //::EventChartCustom(this.m_chart_id_main,(ushort)event,chart.ID(),chart.Timeframe(),chart.Symbol()); CChartObj *chart=engine.ChartGetLastClosedChart(); if(chart!=NULL) { string symbol=sparam; long chart_id=lparam; ENUM_TIMEFRAMES timeframe=(ENUM_TIMEFRAMES)dparam; string header=symbol+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id; Print(DFUN,CMessage::Text(MSG_CHART_COLLECTION_CHART_CLOSED),": ",header); } } //--- "Adding a new window on the chart" event if(idx==CHART_OBJ_EVENT_CHART_WND_ADD) { //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,wnd.WindowNum(),this.Symbol()); ENUM_TIMEFRAMES timeframe=WRONG_VALUE; string ind_name=""; string symbol=sparam; long chart_id=lparam; int win_num=(int)dparam; string header=symbol+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id+": "; CChartObj *chart=engine.ChartGetLastOpenedChart(); if(chart!=NULL) { timeframe=chart.Timeframe(); CChartWnd *wnd=engine.ChartGetLastAddedChartWindow(chart.ID()); if(wnd!=NULL) { CWndInd *ind=wnd.GetLastAddedIndicator(); if(ind!=NULL) ind_name=ind.Name(); } } Print(DFUN,header,CMessage::Text(MSG_CHART_OBJ_WINDOW_ADDED)," ",(string)win_num," ",ind_name); } //--- "Removing a window from the chart" event if(idx==CHART_OBJ_EVENT_CHART_WND_DEL) { //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,wnd.WindowNum(),this.Symbol()); CChartWnd *wnd=engine.ChartGetLastDeletedChartWindow(); ENUM_TIMEFRAMES timeframe=WRONG_VALUE; string symbol=sparam; long chart_id=lparam; int win_num=(int)dparam; string header=symbol+" "+TimeframeDescription(timeframe)+", ID "+(string)chart_id+": "; Print(DFUN,header,CMessage::Text(MSG_CHART_OBJ_WINDOW_REMOVED)," ",(string)win_num); } //--- "Adding a new indicator to the chart window" event if(idx==CHART_OBJ_EVENT_CHART_WND_IND_ADD) { //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name()); ENUM_TIMEFRAMES timeframe=WRONG_VALUE; string ind_name=sparam; string symbol=NULL; long chart_id=lparam; int win_num=(int)dparam; string header=NULL; CWndInd *ind=engine.ChartGetLastAddedIndicator(chart_id,win_num); if(ind!=NULL) { CChartObj *chart=engine.ChartGetChartObj(chart_id); if(chart!=NULL) { symbol=chart.Symbol(); timeframe=chart.Timeframe(); CChartWnd *wnd=chart.GetWindowByNum(win_num); if(wnd!=NULL) header=wnd.Header(); } } Print(DFUN,symbol," ",TimeframeDescription(timeframe),", ID ",chart_id,", ",header,": ",CMessage::Text(MSG_CHART_OBJ_INDICATOR_ADDED)," ",ind_name); } //--- "Removing an indicator from the chart window" event if(idx==CHART_OBJ_EVENT_CHART_WND_IND_DEL) { //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name()); ENUM_TIMEFRAMES timeframe=WRONG_VALUE; string ind_name=sparam; string symbol=NULL; long chart_id=lparam; int win_num=(int)dparam; string header=NULL; CWndInd *ind=engine.ChartGetLastDeletedIndicator(); if(ind!=NULL) { CChartObj *chart=engine.ChartGetChartObj(chart_id); if(chart!=NULL) { symbol=chart.Symbol(); timeframe=chart.Timeframe(); CChartWnd *wnd=chart.GetWindowByNum(win_num); if(wnd!=NULL) header=wnd.Header(); } } Print(DFUN,symbol," ",TimeframeDescription(timeframe),", ID ",chart_id,", ",header,": ",CMessage::Text(MSG_CHART_OBJ_INDICATOR_REMOVED)," ",ind_name); } //--- "Changing indicator parameters in the chart window" event if(idx==CHART_OBJ_EVENT_CHART_WND_IND_CHANGE) { //::EventChartCustom(this.m_chart_id_main,(ushort)event,this.m_chart_id,this.WindowNum(),ind.Name()); ENUM_TIMEFRAMES timeframe=WRONG_VALUE; string ind_name=sparam; string symbol=NULL; long chart_id=lparam; int win_num=(int)dparam; string header=NULL; CWndInd *ind=NULL; CWndInd *ind_changed=engine.ChartGetLastChangedIndicator(); if(ind_changed!=NULL) { ind=engine.ChartGetIndicator(chart_id,win_num,ind_changed.Index()); if(ind!=NULL) { CChartObj *chart=engine.ChartGetChartObj(chart_id); if(chart!=NULL) { symbol=chart.Symbol(); timeframe=chart.Timeframe(); CChartWnd *wnd=chart.GetWindowByNum(win_num); if(wnd!=NULL) header=wnd.Header(); } } } Print(DFUN,symbol," ",TimeframeDescription(timeframe),", ID ",chart_id,", ",header,": ",CMessage::Text(MSG_CHART_OBJ_INDICATOR_CHANGED)," ",ind_name," >>> ",ind.Name()); } } //--- Handling trading events
チャートオブジェクトコレクションから到着する各イベントは、コメント内のライブラリクラスからそのイベントを送信する例を示しています。
この例は、3つのハンドラーパラメータ(lparam、dparam、sparam)のそれぞれで取得するデータの種類を明確に示しています。このデータは、ライブラリ内の必要なオブジェクトを検索するために使用されます。また、操作ログに表示される共通のメッセージを作成する際の基礎としても使用されます。テストEAのチャートオブジェクトコレクションからのイベントの別の処理を実装しません。この例は、自分のニーズに合わせて着信イベントを処理する方法を理解するには十分です。
EAをコンパイルし、銘柄チャートで起動します。
新しい銘柄チャートを開く - OnDoEasyEvent()ハンドラから次の操作ログメッセージが発生します。
OnDoEasyEvent: Open chart: AUDNZD H4, ID 131733844391938634
開いているチャートに任意のオシレータの新しいウィンドウを追加 - OnDoEasyEvent()ハンドラーから次の操作ログメッセージが発生します。
OnDoEasyEvent: AUDNZD H1, ID 131733844391938634: Added subwindow 1 Momentum(14)
メインウィンドウに描画された指標を開いているチャートに追加 - OnDoEasyEvent()ハンドラから次の操作ログメッセージが発生します。
OnDoEasyEvent: AUDNZD H4, ID 131733844391938634, Main chart window: Added indicator AMA(14,2,30)
オシレータパラメータを変更 - OnDoEasyEvent()ハンドラから次の操作ログメッセージが発生します。
OnDoEasyEvent: AUDNZD H4, ID 131733844391938634, Chart subwindow 1: Changed indicator Momentum(14) >>> Momentum(20)
メインウィンドウの指標パラメータを変更 - OnDoEasyEvent()ハンドラから次の操作ログメッセージが発生します。
OnDoEasyEvent: AUDNZD H4, ID 131733844391938634, Main chart window: Changed indicator AMA(14,2,30) >>> AMA(20,2,30)
オシレータウィンドウを削除 - OnDoEasyEvent()ハンドラから次の2つの操作ログメッセージが発生します。
OnDoEasyEvent: AUDNZD H4, ID 131733844391938634: Removed indicator Momentum(20) OnDoEasyEvent: AUDNZD H1, ID 131733844391938634: Removed subwindow 1
メインウィンドウから指標を削除 - OnDoEasyEvent()ハンドラから次の操作ログメッセージが発生します。
OnDoEasyEvent: AUDNZD H4, ID 131733844391938634, Main chart window: Removed indicator AMA(20,2,30)
以前に開いたチャートウィンドウを閉じる - OnDoEasyEvent()ハンドラから次の操作ログメッセージが発生します。
OnDoEasyEvent: Closed chart: AUDNZD H4, ID 131733844391938634
ご覧のとおり、すべてのイベントが正しく処理され、制御プログラムに送信されます。
次の段階
次の記事では、変更の自動追跡とすべてのチャートオブジェクトのプロパティの管理を実装します。
ライブラリの現在のバージョンのすべてのファイルは、テストおよびダウンロードできるように、MQL5のテストEAファイルと一緒に以下に添付されています。
質問や提案はコメント欄にお願いします。
*連載のこれまでの記事:
DoEasyライブラリでのその他のクラス(第67部): チャットオブジェクトクラス
DoEasyライブラリでのその他のクラス(第68部): チャットウィンドウオブジェクトクラスとチャートでの指標オブジェクトクラス
DoEasyライブラリでのその他のクラス(第69部): チャットオブジェクトコレクションクラス
DoEasyライブラリでのその他のクラス(第70部): チャットオブジェクトコレクショの機能拡張と自動更新
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/9360





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