手動のチャート作成および取引ツールキット(第I部)準備: 構造の説明とヘルパークラス
はじめに
私は手動トレーダーで、複雑な数式や指標を使用せずに、手動で、つまり目で見てチャートを分析することを好みます。これにより、取引の柔軟性が高まります。形式化が難しいものに気づき、動きが加速または減速している場合には時間枠を簡単に切り替え、取引に入るずっと前に予想される価格行動を知ることができるのです。
基本的に、私はトレンドラインのさまざまな組み合わせ(ピッチフォーク、ファン、レベルなど)を使用するので、文字通り1回のキーストロークでトレンドラインをすばやく描画できる便利なツールを作成しました。ここでは、このツールをコミュニティと共有したいと思います。
ビデオプレゼンテーション:仕組み
一般的な概念タスクの設定
さて、キーボードショートカットを使用して最も頻繁な操作を実行するのに役立つツールを作成しています。
どんなタスクを実装できるでしょうか。以下は例です。
- 「H」キー(「Horizontal」)を押して単純な水平線を描画し、「i」(単に垂直線のように見えるため)を押して垂直線を描画する
- チャートの任意のポイントから開始して、特定の長さ(無限ではない)の水平線を描画する
- 開始点から特定の(任意の)距離で垂直レベルを描画する
- キーを使用して、時間枠を切り替え、チャート上のレイヤーを再配置する
- 最も近い極値で、プリセットレベルでフィボナッチファンを描画する
- 最も近い極値にトレンドラインを描く(長さは極値間の距離の倍数である必要があり、場合によっては半直線)
- さまざまなタイプのアンドリューピッチフォークを描画する(標準、Schiff、逆Schiffピッチフォーク(高速トレンド用))(ビデオを参照)
- ピッチフォーク、ライン、ファンの極値の場合、極値の順序をカスタマイズする機能が必要(バーの数、左側と右側を別々に)
- 設定ウィンドウを開かずに必要なラインと極値のパラメータをカスタマイズできるグラフィカルインターフェイス
- 一連の注文管理機能: 預金の割合に基づいて注文を開き、成行注文またはストップレベルのトリガーがない指値注文を開くときに自動的にストップレベルを設定し、レベルによる部分的なポジション決済、トレーリングストップなどを有効にする
もちろん、ほとんどのタスクはスクリプトを使用して自動化できます。私もいくつか持っているので、以下の添付ファイルのところでご覧ください。しかし、私は別のアプローチを好みます。
エキスパートアドバイザーや指標では、任意のイベント( キーストローク、マウスの動き、グラフィカルオブジェクトの作成または削除など)への反応の説明を含むOnChartEventメソッドを作成できます。
そのため、インクルードファイルとしてプログラムを作成することにしました。すべての関数と変数は、アクセスしやすいように複数のクラスに分散されています。この時点では、関数を便利にグループ化するためのクラスのみが必要です。そのため、この最初の実装では、継承やファクトリなどの複雑なものは使用しません。ただのコレクションです。
さらに、MQL4とMQL5の両方で実行できるクロスプラットフォームクラスを作成したいと思います。
プログラムの構成
ライブラリには、5つの関連ファイルが含まれています。すべてのファイルは、インクルードディレクトリの「Shortcuts」フォルダにあります。図にあるように、それらはGlobalVariables.mqh、Graphics.mqh、Mouse.mqh、Shortcuts.mqh、Utilites.mqhです。
メインのライブラリファイル(Shortcuts.mqh)
プログラムのメインファイルはShortcuts.mqhです。キーストロークに対する反応のロジックは、このファイルに書き込まれます。これは、エキスパートアドバイザーに接続する必要があるファイルです。すべての補助ファイルもインクルードされます。
//+------------------------------------------------------------------+ //| Shortcuts.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://www.mql5.com/ru/articles/7468 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://www.mql5.com/en/articles/7468" #include "GlobalVariables.mqh" #include "Mouse.mqh" #include "Utilites.mqh" #include "Graphics.mqh" //+------------------------------------------------------------------+ //| The main control class of the program. It should be connected | //| to the Expert Advisor | //+------------------------------------------------------------------+ class CShortcuts { private: CGraphics m_graphics; // Object for drawing m_graphics public: CShortcuts(); void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam); }; //+------------------------------------------------------------------+ //| Default constructor | //+------------------------------------------------------------------+ CShortcuts::CShortcuts(void) { ChartSetInteger(0,CHART_EVENT_MOUSE_MOVE,true); } //+------------------------------------------------------------------+ //| Event handling function | //+------------------------------------------------------------------+ void CShortcuts::OnChartEvent( const int id, const long &lparam, const double &dparam, const string &sparam ) { //--- // This will contain the description of the events related to keystrokes // and mouse movements // ... } } CShortcuts shortcuts;
ファイルにはCShortcutsクラスが記述されます。
すべての補助クラスはファイルの冒頭で接続されます。
クラスにあるのは2つのメソッドだけです。1番目はOnChartEventイベントハンドラで、すべてのキーストロークとマウスの動きのイベントが処理されます。2番目はデフォルトのコンストラクタで、ここではマウスの動きが処理されます。
クラス記述の後、shortcuts変数が作成されます。この変数は、ライブラリが接続されたときに、メインのエキスパートアドバイザーのOnChartEventメソッドで使用する必要があります。
接続には2行が必要です。
//+------------------------------------------------------------------+ //| The main Expert (file "Shortcuts-Main-Expert.mq5") | //+------------------------------------------------------------------+ #include <Shortcuts\Shortcuts.mqh> // ... //+------------------------------------------------------------------+ //| The ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- shortcuts.OnChartEvent(id,lparam,dparam,sparam); }
最初の行はクラスファイルを接続します。2行目は、イベント処理制御をクラスに転送します。
エキスパートアドバイザーが動作する準備が整い、コンパイルすると、線を描画できるようになります。
マウスの動きを処理するクラス
クラスは、現在のカーソル位置のすべての基本パラメータ(ピクセル単位および価格/時間単位での座標X、Y、ポインタが配置されているバー番号など)をすべて「Mouse.mqh」ファイルに格納します。
//+------------------------------------------------------------------+ //| Mouse.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://www.mql5.com/ru/articles/7468 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://www.mql5.com/en/articles/7468" //+------------------------------------------------------------------+ //| Mouse movement handling class | //+------------------------------------------------------------------+ class CMouse { //--- Members private: static int m_x; // X static int m_y; // Y static int m_barNumber; // Bar number static bool m_below; // Indication of a cursor above the price static bool m_above; // Indication of a cursor below the price static datetime m_currentTime; // Current time static double m_currentPrice;// Current price //--- Methods public: //--- Remembers the main parameters of the mouse cursor static void SetCurrentParameters( const int id, const long &lparam, const double &dparam, const string &sparam ); //--- Returns the X coordinate (in pixels) of the current cursor position static int X(void) {return m_x;} //--- Returns the Y coordinate (in pixels) of the current cursor position static int Y(void) {return m_y;} //--- Returns the price of the current cursor position static double Price(void) {return m_currentPrice;} //--- Returns the time of the current cursor position static datetime Time(void) {return m_currentTime;} //--- Returns the bar number of the current cursor position static int Bar(void) {return m_barNumber;} //--- Returns a flag showing that the price is below the Low of the current bar static bool Below(void) {return m_below;} //--- Returns a flag showing that the price is above the High of the current bar static bool Above(void) {return m_above;} }; //--- int CMouse::m_x=0; int CMouse::m_y=0; int CMouse::m_barNumber=0; bool CMouse::m_below=false; bool CMouse::m_above=false; datetime CMouse::m_currentTime=0; double CMouse::m_currentPrice=0; //+------------------------------------------------------------------+ //| Remembers the main parameters for a mouse movement: coordinates | //| of cursor in pixels and price/time, whether the cursor is | //| above or below the price. | //|+-----------------------------------------------------------------+ static void CMouse::SetCurrentParameters( const int id, const long &lparam, const double &dparam, const string &sparam ) { //--- int window = 0; //--- ChartXYToTimePrice( 0, (int)lparam, (int)dparam, window, m_currentTime, m_currentPrice ); m_x=(int)lparam; m_y=(int)dparam; m_barNumber=iBarShift( Symbol(), PERIOD_CURRENT, m_currentTime ); m_below=m_currentPrice<iLow(Symbol(),PERIOD_CURRENT,m_barNumber); m_above=m_currentPrice>iHigh(Symbol(),PERIOD_CURRENT,m_barNumber); } //+------------------------------------------------------------------+
このクラスでは、メソッドが静的として宣言されているため、プログラム内のどこからでも使用できます。クラスインスタンスを作成する必要はありません。
エキスパートアドバイザー設定ブロックの説明 - GlobalVariables.mqhファイル
使用できるすべての設定は、GlobalVariables.mqhファイルに保存されます。
次の記事では、描画用のオブジェクトをさらに追加するため、さらに多くの設定について説明します。
以下は、現在のバージョンで使用されている設定のコードです。
//+------------------------------------------------------------------+ //| GlobalVariables.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://www.mql5.com/ru/articles/7468 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://www.mql5.com/en/articles/7468" //+------------------------------------------------------------------+ //| File describing parameters available to the user | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| Key settings | //+------------------------------------------------------------------+ input string Keys="=== Key settings ==="; input string Up_Key="U"; // Switch timeframe up input string Down_Key="D"; // Switch timeframe down input string Trend_Line_Key="T"; // Trend line input string Switch_Trend_Ray_Key="R"; // Indication of a trend line ray input string Z_Index_Key="Z"; // Indication of the chart on top //+------------------------------------------------------------------+ //| Size settings | //+------------------------------------------------------------------+ input string Dimensions="=== Size settings ==="; input int Trend_Line_Width=2; // Trend line width //+------------------------------------------------------------------+ //| Display styles | //+------------------------------------------------------------------+ input string Styles="=== Display styles ==="; input ENUM_LINE_STYLE Trend_Line_Style=STYLE_SOLID; // Trend line style //+------------------------------------------------------------------+ //| Other parameters | //+------------------------------------------------------------------+ input string Others="=== Other parameters ==="; input bool Is_Trend_Ray=false; // Trend line - ray input bool Is_Change_Timeframe_On_Create = true; // Hide objects on higher timeframes? // (true - hide, false - show) input bool Is_Select_On_Create=true; // Select upon creation input bool Is_Different_Colors=true; // Change colors for times // Number of bars on the left and on the right // for trend line and fan extreme points input int Fractal_Size_Left=1; // Size of the left fractal input int Fractal_Size_Right=1; // Size of the right fractal //+------------------------------------------------------------------+ //| Name prefixes of drawn shapes (can be change only in code, | //| not visible in EA parameters) | //+------------------------------------------------------------------+ // string Prefixes="=== Prefixes ==="; string Trend_Line_Prefix="Trend_"; // Trend line prefix //+------------------------------------------------------------------+ //| Colors for objects of one timeframe (can be changed only in code,| //| not visible in EA parameters) | //+------------------------------------------------------------------+ // string TimeframeColors="=== Time frame colors ==="; color mn1_color=clrCrimson; color w1_color=clrDarkOrange; color d1_color=clrGoldenrod; color h4_color=clrLimeGreen; color h1_color=clrLime; color m30_color=clrDeepSkyBlue; color m15_color=clrBlue; color m5_color=clrViolet; color m1_color=clrDarkViolet; color common_color=clrGray; //--- Auxiliary constant for displaying error messages #define DEBUG_MESSAGE_PREFIX "=== ",__FUNCTION__," === " //--- Constants for describing the main timeframes when drawing #define PERIOD_LOWER_M5 OBJ_PERIOD_M1|OBJ_PERIOD_M5 #define PERIOD_LOWER_M15 PERIOD_LOWER_M5|OBJ_PERIOD_M15 #define PERIOD_LOWER_M30 PERIOD_LOWER_M15|OBJ_PERIOD_M30 #define PERIOD_LOWER_H1 PERIOD_LOWER_M30|OBJ_PERIOD_H1 #define PERIOD_LOWER_H4 PERIOD_LOWER_H1|OBJ_PERIOD_H4 #define PERIOD_LOWER_D1 PERIOD_LOWER_H4|OBJ_PERIOD_D1 #define PERIOD_LOWER_W1 PERIOD_LOWER_D1|OBJ_PERIOD_W1 //+------------------------------------------------------------------+
補助関数
このプログラムには、極値の検索、時間枠の切り替えなどに役立ち、チャート作成とは直接関係のない多くの関数があります。これらの関数はすべて、「Utilites.mqh」ファイルに実装されています。
Utilites.mqhファイルヘッダ
//+------------------------------------------------------------------+ //| Utilites.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://www.mql5.com/ru/articles/7468 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://www.mql5.com/en/articles/7468" //+------------------------------------------------------------------+ //| Class describing auxiliary functions | //+------------------------------------------------------------------+ class CUtilites { public: //--- Changes the timeframe to the next one on the toolbar static void ChangeTimeframes(bool isUp); //--- Converts string command constants to keycodes static int GetCurrentOperationChar(string keyString); //--- Switches layers in charts (the chart is on top of all objects) static void ChangeChartZIndex(void); //--- Returns the number of the nearest extreme bar static int GetNearestExtremumBarNumber( int starting_number=0, bool is_search_right=false, bool is_up=false, int left_side_bars=1, int right_side_bars=1, string symbol=NULL, ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT ); //--- Returns the color for the current timeframe static color GetTimeFrameColor(long allDownPeriodsValue); //--- Returns a list of all timeframes lower than the current one (including the current one) static long GetAllLowerTimeframes(int NeededTimeframe=PERIOD_CURRENT); //--- Coordinates of the straight line. Writes numbers of extreme bars to points p1 and p2 static void SetExtremumsBarsNumbers(bool _is_up,int &p1, int &p2); //--- Converts a string to an array of floating point numbers static void StringToDoubleArray( string _haystack, double &_result[], const string _delimiter="," ); //--- Determines the name of the current object static string GetCurrentObjectName( const string _prefix, const ENUM_OBJECT _type=OBJ_TREND, int _number = -1 ); //--- Obtains the number of the next object static int GetNextObjectNumber( const string _prefix, const ENUM_OBJECT _object_type, bool true ); //--- Returns the distance, in screen pixels, between adjacent bars static int GetBarsPixelDistance(void); //--- Converts a numeric value of the timeframe to its string name static string GetTimeframeSymbolName( ENUM_TIMEFRAMES _timeframe=PERIOD_CURRENT // Desired timeframe ); };
この関数は、チャートの期間を順番に変更します。
このファイルの最初の関数は単純です。たとえば、現在のチャートの期間を順番に変更する関数は、次のようになります。
//+------------------------------------------------------------------+ //| Sequentially changes the current chart period | //| | //| In this implementation, only the timeframes shown in the | //| standard panel are used. | //| | //| Parameters: | //| _isUp - timeframe switch direction: up (true) | //| or down (false) | //+------------------------------------------------------------------+ static void CUtilites::ChangeTimeframes(bool _isUp) { ENUM_TIMEFRAMES timeframes[] = { PERIOD_CURRENT, PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1, PERIOD_W1, PERIOD_MN1 }; int period = Period(); int shift = ArrayBsearch(timeframes,period); if(_isUp && shift < ArraySize(timeframes)-1) { ChartSetSymbolPeriod(0,NULL,timeframes[++shift]); } else if(!_isUp && shift > 1) { ChartSetSymbolPeriod(0,NULL,timeframes[--shift]); } }
まず、関数では、デフォルトツールバーに指定されたすべての時間枠の配列が記述されています。MetaTrader5で利用可能なすべての時間枠を切り替えたい場合は、適切な定数を配列に書き込む必要があります。ただし、この場合、互換性が失われ、ライブラリがMQL4で動作しなくなる可能性があります。
次に、標準関数を使用して、現在の期間を取得し、リストでそれを検索します。
次に、標準の ChartSetSymbolPeriod 関数を使用して、チャートの時間枠が切り替えられます。この関数には、現在のチャートの次の期間が渡されます。
コードで使用されている他の関数は、説明なしで明確にする必要があります。これは単なるコードです。
いくつかの簡単な関数
//+------------------------------------------------------------------+ //| Converts string command constants to keycodes | //+------------------------------------------------------------------+ static int CUtilites::GetCurrentOperationChar(string keyString) { string keyValue = keyString; StringToUpper(keyValue); return(StringGetCharacter(keyValue,0)); } //+------------------------------------------------------------------+ //| Switch chart position to display on top of other objects | //+------------------------------------------------------------------+ static void CUtilites::ChangeChartZIndex(void) { ChartSetInteger( 0, CHART_FOREGROUND, !(bool)ChartGetInteger(0,CHART_FOREGROUND) ); ChartRedraw(0); } //+------------------------------------------------------------------+ //| Returns a string name for any standard timeframe | //| Parameters: | //| _timeframe - ENUM_TIMEFRAMES numeric value for which we need | //| to find a string name | //| Return value: | //| string name of the required timeframe | //+------------------------------------------------------------------+ static string CUtilites::GetTimeframeSymbolName( ENUM_TIMEFRAMES _timeframe=PERIOD_CURRENT // Desired timeframe ) { ENUM_TIMEFRAMES current_timeframe; // current timeframe string result = ""; //--- if(_timeframe == PERIOD_CURRENT) { current_timeframe = Period(); } else { current_timeframe = _timeframe; } //--- switch(current_timeframe) { case PERIOD_M1: return "M1"; case PERIOD_M2: return "M2"; case PERIOD_M3: return "M3"; case PERIOD_M4: return "M4"; case PERIOD_M5: return "M5"; case PERIOD_M6: return "M6"; case PERIOD_M10: return "M10"; case PERIOD_M12: return "M12"; case PERIOD_M15: return "M15"; case PERIOD_M20: return "M20"; case PERIOD_M30: return "M30"; case PERIOD_H1: return "H1"; case PERIOD_H2: return "M1"; case PERIOD_H3: return "H3"; case PERIOD_H4: return "H4"; case PERIOD_H6: return "H6"; case PERIOD_H8: return "H8"; case PERIOD_D1: return "D1"; case PERIOD_W1: return "W1"; case PERIOD_MN1: return "MN1"; default: return "Unknown"; } } //+------------------------------------------------------------------+ //| Returns the standard color for the current timeframe | //+------------------------------------------------------------------+ static color CUtilites::GetTimeFrameColor(long _all_down_periods_value) { if(Is_Different_Colors) { switch((int)_all_down_periods_value) { case OBJ_PERIOD_M1: return (m1_color); case PERIOD_LOWER_M5: return (m5_color); case PERIOD_LOWER_M15: return (m15_color); case PERIOD_LOWER_M30: return (m30_color); case PERIOD_LOWER_H1: return (h1_color); case PERIOD_LOWER_H4: return (h4_color); case PERIOD_LOWER_D1: return (d1_color); case PERIOD_LOWER_W1: return (w1_color); case OBJ_ALL_PERIODS: return (mn1_color); default: return (common_color); } } else { return (common_color); } }
極値検索関数とその応用
次の関数は、極値を見つけるのに役立ちます。パラメータに応じて、極値点はマウスポインタの右または左のいずれかになります。また、極値の左右で望まれるバーの数を指定できます。
//+------------------------------------------------------------------+ //| Returns the number of the nearest fractal in the selected | //| direction | //| Parameters: | //| starting_number - bar number at which the search starts | //| is_search_right - search to the right (true) or left (false) | //| is_up - if "true", search by High levels, otherwise - Low | //| left_side_bars - number of bars on the left | //| right_side_bars - number of bars on the right | //| symbol - symbol name for search | //| timeframe - period for search | //| Return value: | //| the number of the extremum closest to starting_number, | //| matching the specified parameters | | //+------------------------------------------------------------------+ static int CUtilites::GetNearestExtremumBarNumber( int starting_number=0, // Initial bar number const bool is_search_right=false, // Direction to the right const bool is_up=false, // Search by Highs const int left_side_bars=1, // Number of bars to the left const int right_side_bars=1, // Number of bars to the right const string symbol=NULL, // The required symbol const ENUM_TIMEFRAMES timeframe=PERIOD_CURRENT // The required timeframe ) { //--- int i, nextExtremum, sign = is_search_right ? -1 : 1; //--- If the starting bar is specified incorrectly //--- (is beyond the current chart borders) //--- and search - towards the border... if((starting_number-right_side_bars<0 && is_search_right) || (starting_number+left_side_bars>iBars(symbol,timeframe) && !is_search_right) ) { //--- ...it is necessary to display an error message if(Print_Warning_Messages) { Print(DEBUG_MESSAGE_PREFIX, "Can't find extremum: ", "wrong direction"); Print("left_side_bars = ",left_side_bars,"; ", "right_side_bars = ",right_side_bars); } return (-2); } else { //--- otherwise - the direction allows you to select the correct bar. //--- check all bars in the required direction, //--- as long as we are beyond the known chart borders while((starting_number-right_side_bars<0 && !is_search_right) || (starting_number+left_side_bars>iBars(symbol,timeframe) && is_search_right) ) { starting_number +=sign; } } //--- i=starting_number; //--- Preparation is complete. Proceed to search while(i-right_side_bars>=0 && i+left_side_bars<iBars(symbol,timeframe) ) { //--- Depending on the level, check the required extremum if(is_up) { //--- either the upper one nextExtremum = iHighest( Symbol(), Period(), MODE_HIGH, left_side_bars+right_side_bars+1, i-right_side_bars ); } else { //--- or the lower one nextExtremum = iLowest( Symbol(), Period(), MODE_LOW, left_side_bars+right_side_bars+1, i-right_side_bars ); } if(nextExtremum == i) // If the current bar is an extremum, { return nextExtremum; // the problem is solved } else // Otherwise - continue to shift the counter of the checked candlestick to the desired direction if(is_search_right) { if(nextExtremum<i) { i=nextExtremum; } else { i--; } } else { if(nextExtremum>i) { i=nextExtremum; } else { i++; } } } //--- If the edge is reached but no extremum has been found, if(Print_Warning_Messages) { //--- show an error message. Print(DEBUG_MESSAGE_PREFIX, "Can't find extremum: ", "an incorrect starting point or wrong border conditions."); Print("left_side_bars = ",left_side_bars,"; ", "right_side_bars = ",right_side_bars); } return (-1); }
トレンドラインを描画するには、マウスの右側にある2つの最も近い極値を見つける関数が必要です。この関数は前の関数を使用できます。
//+------------------------------------------------------------------+ //| Finds 2 nearest extreme points to the right of the current | //| mouse pointer position | //| Parameters: | //| _is_up - search by High (true) or Low (false) | //| int &_p1 - bar number of the first point | //| int &_p2 - bar number of the second point | //+------------------------------------------------------------------+ static void CUtilites::SetExtremumsBarsNumbers( bool _is_up, // search by High (true) or by Low (false) int &_p1, // bar number of the first point int &_p2 // bar number of second point ) { int dropped_bar_number=CMouse::Bar(); //--- _p1=CUtilites::GetNearestExtremumBarNumber( dropped_bar_number, true, _is_up, Fractal_Size_Left, Fractal_Size_Right ); _p2=CUtilites::GetNearestExtremumBarNumber( _p1-1, // Bar to the left of the previous found extremum true, _is_up, Fractal_Size_Left, Fractal_Size_Right ); if(_p2<0) { _p2=0; } }
オブジェクト名の生成
同じオブジェクトのシリーズを描画できるようにするには、オブジェクトに一意の名前を付ける必要があります。最も効率的な方法は、このオブジェクトタイプに対応するプレフィックスを使用し、それに一意の番号を追加することです。さまざまなオブジェクトタイプのプレフィックスは、GlobalVariables.mqhにリストされています。
数値は適切な関数によって生成されます。
//+------------------------------------------------------------------+ //| Returns the number of the next object in the series | //| Parameters: | //| prefix - name prefix for this group of objects. | //| object_type - the type of objects to search in. | //| only_prefixed - if "false", search in all objects | //| of this type, "true" - only the objects | //| with the specified prefix | //| Return value: | //| number of the next object in series. If search by prefix, | //| and the existing numbering has a gap, the next number | //| will be at gap beginning. | //+------------------------------------------------------------------+ int CUtilites::GetNextObjectNumber( const string prefix, const ENUM_OBJECT object_type, bool true ) { int count = ObjectsTotal(0,0,object_type), i, current_element_number, total_elements = 0; string current_element_name = "", comment_text = ""; //--- if(only_prefixed) { for(i=0; i<count; i++) { current_element_name=ObjectName(0,i,0,object_type); if(StringSubstr(current_element_name,0,StringLen(prefix))==prefix) { current_element_number= (int)StringToInteger( StringSubstr(current_element_name, StringLen(prefix), -1) ); if(current_element_number!=total_elements) { break; } total_elements++; } } } else { total_elements = ObjectsTotal(0,-1,object_type); do { current_element_name = GetCurrentObjectName( prefix, object_type, total_elements ); if(ObjectFind(0,current_element_name)>=0) { total_elements++; } } while(ObjectFind(0,current_element_name)>=0); } //--- return(total_elements); }
コードには2つの検索アルゴリズムが実装されています。1番目のアルゴリズム(このライブラリのメインアルゴリズム)は、タイプに対応し、指定されたプレフィックスを持つすべてのオブジェクトを確認します。アルゴリズムは見つけた空き番号をユーザに返すので、番号付けの「隙間」を埋めることができます。
ただし、このアルゴリズムは、同じ番号でサフィックスが異なる複数のオブジェクトが存在する可能性がある場合には適していません。以前のバージョンでは、スクリプトを使用してオブジェクトを描画するときに、ピッチフォークセットにそのような名前を使用していました。
したがって、ライブラリには2番目の検索メソッドがあります。このアルゴリズムは、このタイプのオブジェクトの総数を取得し、同じプレフィックスで始まって同じインデックスを持つ名前があるかどうかを確認します。確認できた場合、空き値が見つかるまで数値が1ずつ増加します。
また、番号がある場合(または関数を使用して簡単に取得できる場合)、名前を簡単に作成できます。
//+------------------------------------------------------------------+ //| Generates the current element name | //| Parameters: | //| _prefix - name prefix for this group of objects. | //| _type - the type of objects to search in. | //| _number - the number of the current object if it is ready. | //| Return value: | //| current object name string. | //+------------------------------------------------------------------+ string CUtilites::GetCurrentObjectName( string _prefix, ENUM_OBJECT _type=OBJ_TREND, int _number = -1 ) { int Current_Line_Number; //--- Addition to the prefix - current timeframe string Current_Line_Name=IntegerToString(PeriodSeconds()/60)+"_"+_prefix; //--- Get the element number if(_number<0) { Current_Line_Number = GetNextObjectNumber(Current_Line_Name,_type); } else { Current_Line_Number = _number; } //--- Generate the name Current_Line_Name +=IntegerToString(Current_Line_Number,4,StringGetCharacter("0",0)); //--- return (Current_Line_Name); }
隣接するバー間の距離(ピクセル単位)
将来のある地点までの距離を計算する必要がある場合があります。最も信頼できる方法の1つは、2つの隣接するバー間のピクセル単位の距離を計算し、それに必要な係数(インデントに必要なバーの数)を掛けることです。
隣接するバー間の距離は、次の関数を使用して計算できます。
//+------------------------------------------------------------------+ //| Calculates a distance in pixels between two adjacent bars | //+------------------------------------------------------------------+ int CUtilites::GetBarsPixelDistance(void) { double price; // arbitrary price on the chart (used for // standard functions calculating coordinates datetime time1,time2; // the time of the current and adjacent candlesticks int x1,x2,y1,y2; // screen coordinates of two points // on adjacent candlesticks int deltha; // result - the desired distance //--- Initial settings price = iHigh(Symbol(),PERIOD_CURRENT,CMouse::Bar()); time1 = CMouse::Time(); //--- Get the time of the current candlestick if(CMouse::Bar()<Bars(Symbol(),PERIOD_CURRENT)){ // if at the middle of the chart, time2 = time1+PeriodSeconds(); // take the candlestick on the left } else { // otherwise time2 = time1; time1 = time1-PeriodSeconds(); // take the candlestick on the right } //--- Convert coordinates form price/time values to screen pixels ChartTimePriceToXY(0,0,time1,price,x1,y1); ChartTimePriceToXY(0,0,time2,price,x2,y2); //--- Calculate the distance deltha = MathAbs(x2-x1); //--- return (deltha); }
文字列をdoubleの配列に変換する関数
EAパラメータを使用してフィボナッチレベルを設定する最も便利な方法は、カンマ区切りの値で構成される文字列を使用することです。ただし、MQLでは、レベルの設定に2倍の数値を使用する必要があります。
次の関数は、文字列から数値を抽出するのに役立ちます。
//+------------------------------------------------------------------+ //| Converts a string with separators to an array of double | //| numbers | //| Parameters: | //| _haystack - source string for conversion | //| _result[] - resulting array | //| _delimiter - separator character | //+------------------------------------------------------------------+ static void CUtilites::StringToDoubleArray( string _haystack, // source string double &_result[], // array of results const string _delimiter="," // separator ) { //--- string haystack_pieces[]; // Array of string fragments int pieces_count, // Number of fragments i; // Counter string current_number=""; // The current string fragment (estimated number) //--- Split the string into fragments pieces_count=StringSplit(_haystack,StringGetCharacter(_delimiter,0),haystack_pieces); //--- Convert if(pieces_count>0) { ArrayResize(_result,pieces_count); for(i=0; i<pieces_count; i++) { StringTrimLeft(haystack_pieces[i]); StringTrimRight(haystack_pieces[i]); _result[i]=StringToDouble(haystack_pieces[i]); } } else { ArrayResize(_result,1); _result[0]=0; } }
描画クラス: ユーティリティ関数の使用例
記事が長くなってしまったので、ほとんどの描画機能については次の記事で説明します。ただし、作成された関数のいくつかをテストするために、(最も近い2つの極値に基づいて)単純な直線を描画するコードをここに追加します。
Graphics.mqhファイルヘッダ
//+------------------------------------------------------------------+ //| Graphics.mqh | //| Copyright 2020, MetaQuotes Software Corp. | //| https://www.mql5.com/ru/articles/7468 | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, MetaQuotes Software Corp." #property link "https://www.mql5.com/en/articles/7468" //+------------------------------------------------------------------+ //| Class for plotting graphic objects | //+------------------------------------------------------------------+ class CGraphics { //--- Fields private: bool m_Is_Trend_Ray; bool m_Is_Change_Timeframe_On_Create; //--- Methods private: //--- Sets general parameters for any newly created object void CurrentObjectDecorate( const string _name, const color _color=clrNONE, const int _width = 1, const ENUM_LINE_STYLE _style = STYLE_SOLID ); public: //--- Default constructor CGraphics(); //--- Universal function for creating trend lines with specified parameters bool TrendCreate( const long chart_ID=0, // chart ID const string name="TrendLine", // line name const int sub_window=0, // subwindow number datetime time1=0, // time of the first point double price1=0, // price of the first point datetime time2=0, // time of the second point double price2=0, // price of the second point const color clr=clrRed, // line color const ENUM_LINE_STYLE style=STYLE_SOLID, // line style const int width=1, // line width const bool back=false, // in the background const bool selection=true, // if the line is selected const bool ray_right=false, // ray to the right const bool hidden=true, // hide in the list of objects const long z_order=0 // Z-Index ); //--- Plots a trend line based on the two nearest (to the right of the mouse) extreme points void DrawTrendLine(void); //--- Checks if the straight line is a ray bool IsRay() {return m_Is_Trend_Ray;} //--- Sets the ray indication (whether the line should be extended to the right) void IsRay(bool _is_ray) {m_Is_Trend_Ray = _is_ray;} //--- Checks if the display of objects created by the program should be changed on higher timeframes bool IsChangeTimeframe(void) {return m_Is_Change_Timeframe_On_Create;} //--- Sets flags for the display of objects created by the program on higher timeframes void IsChangeTimeframe(bool _is_tf_change) {m_Is_Change_Timeframe_On_Create = _is_tf_change;} };
新しく作成されたオブジェクトの一般的なパラメータを設定する関数
//+------------------------------------------------------------------+ //| Sets general parameters for all new objects | //| Parameters: | //| _name - the name of the object being modified | //| _color - the color of the object being modified. If not set, | //| standard color of the current period is used | //| _width - object line width | //| _style - object line type | //+------------------------------------------------------------------+ void CGraphics::CurrentObjectDecorate( const string _name, // the name of the object being modified const color _color=clrNONE, // the color of the object being modified const int _width = 1, // object line width const ENUM_LINE_STYLE _style = STYLE_SOLID // object line style ) { long timeframes; // timeframes on which the object will be displayed color currentColor; // object color //--- Specify timeframes on which the object will be displayed if(Is_Change_Timeframe_On_Create) { timeframes = CUtilites::GetAllLowerTimeframes(); } else { timeframes = OBJ_ALL_PERIODS; } //--- Specify the object color if(_color != clrNONE) { currentColor = _color; } else { currentColor = CUtilites::GetTimeFrameColor(timeframes); } //--- Set attributes ObjectSetInteger(0,_name,OBJPROP_COLOR,currentColor); // Color ObjectSetInteger(0,_name,OBJPROP_TIMEFRAMES,timeframes); // Periods ObjectSetInteger(0,_name,OBJPROP_HIDDEN,true); // Hide in the list of objects ObjectSetInteger(0,_name,OBJPROP_SELECTABLE,true); // Ability to select ObjectSetInteger(0,_name,OBJPROP_SELECTED,Is_Select_On_Create); // Stay selected after creation? ObjectSetInteger(0,_name,OBJPROP_WIDTH,_width); // Line width ObjectSetInteger(0,_name,OBJPROP_STYLE,_style); // Line style }
直線をプロットする関数
//+------------------------------------------------------------------+ //| Universal function for creating trend lines with specified | //| parameters | //| Parameters: | //| chart_ID - chart ID | //| name - line name | //| sub_window - subwindow number | //| time1 - time of the first point | //| price1 - price of the first point | //| time2 - time of the second point | //| price2 - price of the second point | //| clr - line color | //| style - line style | //| width - line width | //| back - in the background | //| selection - if the line is selected | //| ray_right - ray to the right | //| hidden - hide in the list of objects | //| z_order - priority of mouse clicks (Z-Index) | //| Return value: | //| indication of success. If line drawing failed, | //| false is returned, otherwise - true | //+------------------------------------------------------------------+ bool CGraphics::TrendCreate( const long chart_ID=0, // chart ID const string name="TrendLine", // line name const int sub_window=0, // subwindow number datetime time1=0, // time of the first point double price1=0, // price of the first point datetime time2=0, // time of the second point double price2=0, // price of the second point const color clr=clrRed, // line color const ENUM_LINE_STYLE style=STYLE_SOLID, // line style const int width=1, // line width const bool back=false, // in the background const bool selection=true, // if the line is selected const bool ray_right=false, // ray to the right const bool hidden=true, // hide in the list of objects const long z_order=0 // Z-Index ) { //--- Reset the last error message ResetLastError(); //--- Create a line if(!ObjectCreate(chart_ID,name,OBJ_TREND,sub_window,time1,price1,time2,price2)) { if(Print_Warning_Messages) // if failed, show an error message { Print(__FUNCTION__, ": Can't create trend line! Error code = ",GetLastError()); } return(false); } //--- Set additional attributes CurrentObjectDecorate(name,clr,width,style); //--- line in the foreground (false) or in the background (true) ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back); //--- ray to the right (true) or exact borders (false) ObjectSetInteger(chart_ID,name,OBJPROP_RAY_RIGHT,ray_right); //--- mouse click priority (Z-index) ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order); //--- Update the chart image ChartRedraw(0); //--- Everything is good. The line has been drawn successfully. return(true); }
この共通の関数を基礎として使用し、2つの隣接する極値によって直線を描く別の関数を作成しましょう。
//+------------------------------------------------------------------+ //| Draws a trend line by nearest extreme points in the right | //+------------------------------------------------------------------+ void CGraphics::DrawTrendLine(void) { int dropped_bar_number=CMouse::Bar(); // candlestick number under the mouse int p1=0,p2=0; // numbers of the first and seconds points string trend_name = // trend line name CUtilites::GetCurrentObjectName(Trend_Line_Prefix,OBJ_TREND); double price1=0, // price of the first point price2=0, // price of the second point tmp_price; // variable for temporary storing of the price datetime time1=0, // time of the first point time2=0, // time of the second point tmp_time; int x1,x2,y1,y2; // Point coordinates int window=0; // Subwindow number //--- Setting initial parameters if(CMouse::Below()) // If a mouse cursor is below the candlestick Low { //--- Find two extreme points below CUtilites::SetExtremumsBarsNumbers(false,p1,p2); //--- Determine point coordinates time1=iTime(Symbol(),PERIOD_CURRENT,p1); price1=iLow(Symbol(),PERIOD_CURRENT,p1); time2=iTime(Symbol(),PERIOD_CURRENT,p2); price2=iLow(Symbol(),PERIOD_CURRENT,p2); } else // otherwise if(CMouse::Above()) // If a mouse cursor is below the candlestick High { //--- Find two extreme points above CUtilites::SetExtremumsBarsNumbers(true,p1,p2); //--- Determine point coordinates time1=iTime(Symbol(),PERIOD_CURRENT,p1); price1=iHigh(Symbol(),PERIOD_CURRENT,p1); time2=iTime(Symbol(),PERIOD_CURRENT,p2); price2=iHigh(Symbol(),PERIOD_CURRENT,p2); } //--- Draw the line TrendCreate(0,trend_name,0, time1,price1,time2,price2, CUtilites::GetTimeFrameColor(CUtilites::GetAllLowerTimeframes()), 0,Trend_Line_Width,false,true,m_Is_Trend_Ray ); //--- Redraw the chart ChartRedraw(0); }
ポイント1と2のバー番号を取得するCUtilites::SetExtremumsBarsNumbers関数呼び出しに注目してください。コードは以前に説明しました。残りは明確なので、ここでは長々と説明しないことにします。
最後の関数は、2点に基づいて単純な線を描画します。Is_Trend_Rayグローバルパラメータ(GlobalVariables.mqhファイルで説明)に応じて、線は右に伸びる半直線か、2つの極値間の短い線分になります。
キーボードを使用して線を延長する可能性を追加しましょう。
制御ブロックの作成: OnChartEventメソッドの設定
基本的な機能の準備ができたので、キーボードショートカットをカスタマイズできます。
Shortcuts.mqhで、CShortcuts::OnChartEventメソッドを書きます。
//+------------------------------------------------------------------+ //| Event handling function | //+------------------------------------------------------------------+ void CShortcuts::OnChartEvent( const int id, const long &lparam, const double &dparam, const string &sparam ) { //--- switch(id) { //--- Save the coordinates of the mouse cursor case CHARTEVENT_MOUSE_MOVE: CMouse::SetCurrentParameters(id,lparam,dparam,sparam); break; //--- Handle keystrokes case CHARTEVENT_KEYDOWN: //--- Change the timeframe 1 level up if(CUtilites::GetCurrentOperationChar(Up_Key) == lparam) { CUtilites::ChangeTimeframes(true); }; //--- Change the timeframe 1 level down if(CUtilites::GetCurrentOperationChar(Down_Key) == lparam) { CUtilites::ChangeTimeframes(false); }; //--- Change the Z Index of the chart (chart on top of all objects) if(CUtilites::GetCurrentOperationChar(Z_Index_Key) == lparam) { CUtilites::ChangeChartZIndex(); } //--- Draw a trend line if(CUtilites::GetCurrentOperationChar(Trend_Line_Key) == lparam) { m_graphics.DrawTrendLine(); } //--- Switch the Is_Trend_Ray parameter if(CUtilites::GetCurrentOperationChar(Switch_Trend_Ray_Key) == lparam) { m_graphics.IsRay(!m_graphics.IsRay()); } break; //--- } }
現在のライブラリ実装で使用されているキー
アクション | キー | 説明 |
---|---|---|
メインのTFの時間枠を長くする(TFパネルから) | U | Up |
時間枠を短くする | D | Down |
チャートのZレベルを変える(チャートが他のすべてのオブジェクトの上になるかどうか) | Z | Z order |
マウスに最も近い2つの一方向の極値点に基づいて傾斜した傾向線を描画する | T | Trend line |
新しいラインを線分モードに切り替える | R | Ray |
終わりに
添付ファイルには、ライブラリの現在のバージョンが含まれています。また、添付ファイルには3つのスクリプトが含まれています。
- 1つ目はDel-All-Graphicsです。これは、現在のウィンドウからすべてのグラフィックオブジェクトを削除します。私の端末では、このスクリプトにCtrl+A(All)キーボードショートカットを設定しました。
- 2番目のスクリプトはDel-All-Prefixedです。これは、プレフィックスが付いたすべてのオブジェクト(たとえば、H1で始まるすべてのトレンドラインまたはオブジェクト)を削除できます。Alt+R(Remove)で呼び出します。
- 最後に、3番目のスクリプト(DeselectAllObjects)を使用すると、現在のウィンドウ内のすべてのオブジェクトの選択を解除できます。私のキーボードショートカットはCtrl+Dです(Photoshop同様にDeselect)。
ライブラリを指標ではなくエキスパートアドバイザーに接続することをお勧めします。指標に接続してこの指標を他のエキスパートアドバイザーと一緒に使用しようとすると、深刻な速度低下が発生する可能性があるためです。少なくとも私の場合は速度低下でしたが、もちろん、他のエラーだった可能性もあります。
今後の実装
ライブラリの2番目のバージョンでは、ビデオに示されている便利なオブジェクトの実装について説明します。一部のオブジェクトはプリミティブ(垂直線や水平線など)で、特定の長さの線などの他のオブジェクトは、より多くの労力を必要としました。「出力エラー」などの理由で、正常に動作しないものもあります。私の決定について説明しますが、もちろん、フィードバックは大歓迎です。
3番目のバージョンには、パラメータを構成するためのグラフィカルインターフェイスが含まれます。
4番目のバージョンでは、あるとしたら、手動取引を容易にする本格的なアシスタントEAを提示します。コミュニティからのアドバイスが必要です。既存のソリューションと比較して、新しいアイデアを適用するかどうかはわかりません。もちろん、インターフェイスは私が描きますが、これはすべて手動取引に適用されます。この開発は何に役に立つと思いますか?
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/7468
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索