繁簡切換您正在訪問的是FX168財經網,本網站所提供的內容及信息均遵守中華人民共和國香港特別行政區當地法律法規。

FX168財經網>人物頻道>帖子

手工圖表和交易工具包(第二部分)。 圖表圖形繪圖工具

作者/牛市來了 2021-02-08 16:36 0 來源: FX168財經網人物頻道

概述

我撰寫上一篇文章的目的是創建一個方便的工具包,允許使用鍵盤快捷鍵在圖表上快速繪制直線。 第一篇文章里包括一段視頻,演示了現成解決方案的工作原理。

當前的實現中未提供 GUI(盡管其已在未來計劃中)。 該程序簡單地根據鍵盤快捷鍵繪制直線。 它加快了訪問諸如更改當前圖表“層次”(Z-索引),切換時間幀和切換直線繪制模式(射線/線段)之類的操作速度。

鼠標位置判斷對象應繪制的位置。 如果鼠標指針位於價格上方,則選燭條高點作為基點。 如果鼠標指針位於價格下方,則選低點。

當前函數庫版本可以繪制以下對象:

  • 簡單 ("無終點")直線 — 水平垂直線。
  • 常規趨勢線 (最接近鼠標的兩個極值點)。 您可以將線條設置為線段或射線。 如果該線是線段,則可用特殊模式將線段的終點設置到未來的一點。 在這種情況下,該線大小等於兩個極值點之間的距離乘以某個系數,該系數可在 EA 參數中指定。
  • 水平級別具有一定長度的 (非無終點)。 該工具箱可以繪制短線和“延伸”線,您可以為其指定相對於短線的比率。
  • 一條帶有水平標簽的垂線
  • 斐波那契扇形。 級別參數是可配置的,但我用的是經過稍微修改的版本,該版本曾經由綽號為 Vadimcha 的男子在 “Onyx” 上展示。 他們稱這個扇形為 VFan,即我在代碼中繼續采用的名字。
  • 安德魯草叉一套由三個對象組成。

項目結構非常簡單。 該函數庫有五個相關文件:“ GlobalVariables.mqh”,“ Graphics.mqh”,“ Mouse.mqh”,“ Shortcuts.mqh”,“ Utilites.mqh ”。 所有文件都位於標準 Include 目錄中的一個 Shortcuts 文件夾當中。

主文件是 Shortcuts.mqh”,與所有其他文件連接。 在該文件中創建了 CShortcuts 類的實例,從而令該函數庫可以輕松地與您的主要智能交易系統連接。

在前一篇文章中,我曾重點介紹了幫助文件 “Utilites.mqh”。 在本文中,我們將主要處理包含繪圖邏輯的 “Graphics.mqh” 文件。


全局設置文件

第二個函數庫版本提供了豐富的擴展配置選項,因為它含有更多會受到影響的對象。 當前版本的完整代碼如下:

//+------------------------------------------------------------------+
//|                                              GlobalVariables.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                            https://www.mql5.com/en/articles/7908 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, MetaQuotes Software Corp."
#property link      "https://www.mql5.com/en/articles/7908"
//+------------------------------------------------------------------+
//| File describing parameters available to the user                 |
//+------------------------------------------------------------------+
#define VERSION 2.0 // Not #property but a constant. A bit more convenient.   
//+------------------------------------------------------------------+
//| 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
input string   Vertical_With_Short_Levels_Key="V";  // Vertical segment 
input string   Short_Level_Key="S";                 // Short level
input string   Long_Level_Key="L";                  // Extended level
input string   Simple_Horizontal_Line_Key="H";      // Simple horizontal line
input string   Simple_Vertical_Line_Key="I";        // Simple vertical line
input string   VFun_Key="F";                        // Fibonacci fan
input string   Pitchfork_Key="P";                   // Andrews' pitchfork

//+------------------------------------------------------------------+
//| Color setting                                                    |
//+------------------------------------------------------------------+
input string   Colors="=== Color Settings ===";
input color    VFan_Color=clrLightGray;            // Color of the fan lines 
                                                   //   (and an additional 
                                                   //    one for special cases)  
//---
input color    Pitchfork_Main_Color = clrBlue;     // Andrews' pitchfork color
input color    Pitchfork_Shiff_Color = clrRed;     // Schiff pitchfork color
input color    Pitchfork_Reverce_Color = clrYellow;// "Reverse" pitchfork color

//+------------------------------------------------------------------+
//| Size settings                                                    |
//+------------------------------------------------------------------+
input string   Dimensions="=== Size settings ===";
input int      Short_Level_Length=12;     // Short level length (bar)
input int      Short_Level_Width=1;       // Line width for the short level
input int      Long_Level_Width=2;        // Line width for the long level
input int      Vertical_With_Short_Levels_Width=1; // Vertical line width with levels
input int      Short_Level_7_8_Width=1;   // Level 7/8 line width
input int      Short_Level_14_8_Width=1;  // Level 14/8 line width
input int      Simple_Vertical_Width=1;   // Simple vertical line width
input int      Simple_Horizontal_Width=1; // Simple horizontal line width
input int      Trend_Line_Width=2;        // Trend line width

//+------------------------------------------------------------------+
//| Display styles                                                   |
//+------------------------------------------------------------------+
input string   Styles="=== Display styles ===";
input ENUM_LINE_STYLE      Vertical_With_Short_Levels_Style=STYLE_SOLID; // Vertical Line style
                                                                         // with levels
input ENUM_LINE_STYLE      Short_Level_Style=STYLE_SOLID;      // Short Level style
input ENUM_LINE_STYLE      Long_Level_Style=STYLE_SOLID;       // Long level style
input ENUM_LINE_STYLE      Short_Level_7_8_Style=STYLE_SOLID;  // Level 7/8 style
input ENUM_LINE_STYLE      Short_Level_14_8_Style=STYLE_DOT;   // Level 14/8 style
input ENUM_LINE_STYLE      Simple_Vertical_Style=STYLE_DOT;    // Simple Vertical style
input ENUM_LINE_STYLE      Simple_Horizontal_Style=STYLE_DOT;  // Simple Horizontal style
input ENUM_LINE_STYLE      VFun_Levels_Style=STYLE_SOLID;      // Fan Style
input ENUM_LINE_STYLE      Trend_Line_Style=STYLE_SOLID;       // Trend line style
//---
input ENUM_LINE_STYLE      Pitchfork_Main_Style = STYLE_SOLID;    // Andrews' Pitchfork style
input ENUM_LINE_STYLE      Pitchfork_Shiff_Style = STYLE_SOLID;   // Schiff Pitchfork style
input ENUM_LINE_STYLE      Pitchfork_Reverce_Style = STYLE_SOLID; // Reverse Pitchfork style
//+------------------------------------------------------------------+
//| Pitchfork extrema parameters                                     |
//+------------------------------------------------------------------+
input string               Pitchforks="=== Pitchfork Extrema Parameters ===";
//---
input int                  Pitchfork_First_Point_Left_Bars=6;   // Pitchfork - 1st point, bars on the left
input int                  Pitchfork_First_Point_Right_Bars=6;  // Pitchfork - 1st point, bars on the left
//---
input int                  Pitchfork_Second_Point_Left_Bars=6;  // Pitchfork - 2nd point, bars on the left
input int                  Pitchfork_Second_Point_Right_Bars=6; // Pitchfork - 2nd point, bars on the right
//---
input int                  Pitchfork_Third_Point_Left_Bars=6;   // Pitchfork - 3rd point, bars on the left
input int                  Pitchfork_Third_Point_Right_Bars=2;  // Pitchfork - 3rd point, bars on the right
//+------------------------------------------------------------------+
//| Other parameters                                                 |
//+------------------------------------------------------------------+
input string               Others="=== Other Parameters ===";
input double               Vertical_Short_Level_Coefficient=0.825;  // Coefficient of vertical levels
input double               Long_Level_Multiplicator=2;              // Multiplier for the long level
input int                  Trend_Length_Coefficient=4;              // Coefficient for the trend line length
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

input bool                 Pitchfork_Show_Main = true;     // Display Andrews' pitchfork
input bool                 Pitchfork_Show_Shiff = true;    // Display Schiff pitchfork
input bool                 Pitchfork_Show_Reverce = true;  // Display "Reverse" pitchfork
input bool                 Print_Warning_Messages=true;    // Display error messages
input string               VFun_Levels="-1.5,-0.618,-0.236,"+
                                       "  0,0.236,0.382,"+
                                       "  0.618,0.786,0.886,0.942";  // Fan levels
input string               Array_Delimiter=",";            // Array elements separator
//---

//+------------------------------------------------------------------+
//| Name prefixes of drawn shapes (can be change only in code,       |
//| not visible in EA parameters)                                    |
//+------------------------------------------------------------------+
//string   Prefixes="=== Prefixes ===";
//string   Vertical_With_Short_Levels_Prefix="Vertical_";  // Prefix for vertical lines with levels
//string   Short_Level_Prefix="Short_Level_";              // Prefix for short levels
//string   Long_Level_Prefix="Long_Level_";                // Prefix for long levels
//string   Simple_Horizontal_Prefix="Simple_H_";           // Prefix for simple horizontal lines
//string   Simple_Vertical_Prefix="Simple_V_";             // Prefix for simple vertical lines
//string   VFan_Prefix="VFan_";                            // Prefix for fan
//string   Trend_Line_Prefix="Trend_";                     // Prefix for trend lines
//string   Pitchfork_Prefix="Pitchfork_";                  // Prefix for pitchfork
string   allPrefixes[] =      // Prefixes for object names
  {
   "Trend_",            // 0 - Prefix for trend lines
   "Simple_H_",         // 1 - Prefix for simple horizontal lines
   "Simple_V_",         // 2 - Prefix for simple vertical lines
   "VFan_",             // 3 - Prefix for fan
   "Pitchfork_",        // 4 - Prefix for pitchfork
   "Vertical_",         // 5 - Prefix for vertical lines with levels
   "Short_Level_",      // 6 - Prefix for short levels
   "Long_Level_"        // 7 - Prefix for long levels
  };

//+------------------------------------------------------------------+
//| Colors for objects of one timeframe (can be changed only in code,|
//| not visible in EA parameters)                                    |
//+------------------------------------------------------------------+
// string TimeframeColors="=== Standard Colors for Timeframes  ===";
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
//--- For compatibility with version 4, timeframes that do not exist 
//---    in the toolbar are excluded.
#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
//+------------------------------------------------------------------+

與以前版本相比所有新添加的內容均以黃色高亮顯示。 這些新功能不僅可以配置直線,還可以配置屏幕上顯示的其他對象。

我將對象前綴的名稱放入數組中,以便以後使用它們時會更方便。 例如,我計劃添加一個刪除複雜對象的功能(譬如說,帶有級別的垂直線)。 針對這種情況下,該數組將更加方便。

現在我們已研究過設置,可以繼續進行圖形處理了。

繪制“基元”:垂直和水平線

也許您要創建的第一個對象是水平線和時間線(無限的水平和垂直線)。 實際上,函數庫就是從這些直線開始的。

此為代碼:

//+------------------------------------------------------------------+
//| Draws simple straight lines (vertical and horizontal) in the     |
//| position specified by mouse or parameters                        |
//| Parameters:                                                      |
//|   _object_type - object type. Can be OBJ_VLINE or OBJ_HLINE      |
//|   _time - time.  If not specified, mouse time is used            |
//|   _price - price. If not specified, price under index is used.   |
//+------------------------------------------------------------------+
void              CGraphics::DrawSimple(
   ENUM_OBJECT _object_type, // Object type
   datetime    _time=-1,     // Time
   double      _price=-1     // Price
)
  {
//---
   string Current_Object_Name;   // The name of the future object
   color Current_Object_Color=   // Color (depends on the "standard" color of the timeframe)
      CUtilites::GetTimeFrameColor(CUtilites::GetAllLowerTimeframes());
   datetime Current_Object_Time; // Starting point time
   double Current_Object_Price;  // Starting point price
   ENUM_LINE_STYLE Current_Object_Style=STYLE_DOT; // Line style
   int Current_Object_Width=1;   // Line width
   int window=0;                 // Subwindow number

//--- Set up line parameters depending on the type
   if(_object_type==OBJ_VLINE)   // For vertical lines
     {
      Current_Object_Name=       // Generate the name
         CUtilites::GetCurrentObjectName(
            Simple_Vertical_Prefix,
            _object_type
         );
      // style - according to global parameters
      Current_Object_Style=Simple_Vertical_Style;
      // width - according to global parameters
      Current_Object_Width=Simple_Vertical_Width;
     }
   else
      if(_object_type==OBJ_HLINE)// For horizontal lines
        {
         Current_Object_Name=    // Generate the name
            CUtilites::GetCurrentObjectName(
               Simple_Horizontal_Prefix,
               _object_type
            );
         // style - according to global parameters
         Current_Object_Style=Simple_Horizontal_Style;
         // width - according to global parameters
         Current_Object_Width=Simple_Horizontal_Width;
        }
      else  // This function only draws horizontal and vertical lines.
        {
         // If something else is passed in parameters...
         if(Print_Warning_Messages)
           {
            // ...report an error...
            Print(DEBUG_MESSAGE_PREFIX,"Error, wrong object type");
           }
         // ...and exit.
         return;
        }

//--- If coordinates are not specified in the parameters, use the coordinates of the mouse
   Current_Object_Price = _price==-1 ? CMouse::Price() : _price;
   Current_Object_Time = _time==-1 ? CMouse::Time() : _time;

//--- Create the object
   ObjectCreate(
      0,
      Current_Object_Name,
      _object_type,
      0,
      Current_Object_Time,
      Current_Object_Price
   );

//--- Set display parameters for the created object
   CurrentObjectDecorate(
      Current_Object_Name,
      Current_Object_Color,
      Current_Object_Width,
      Current_Object_Style
   );

//--- Redraw the chart and complete
   ChartRedraw(0);
  }

操作非常簡單。 生成名稱,從 “GlobalVariables.mqh” 文件中定義的輸入變量獲取設置,獲取對象起始點的坐標(即可來自函數參數,亦或簡單地取用鼠標的坐標),對象就準備好了。

這就是所有了!

現在我們需要將此函數添加到文件頭文件里

//+------------------------------------------------------------------+
//|                                                     Graphics.mqh |
//|                        Copyright 2020, MetaQuotes Software Corp. |
//|                            https://www.mql5.com/es/articles/7468 |
//+------------------------------------------------------------------+

// ...

//+------------------------------------------------------------------+
//| Class for plotting graphic objects                               |
//+------------------------------------------------------------------+
class CGraphics
  {

   // ...

public:

   // ...

   //--- Draws simple straight lines (vertical and horizontal)
   void              CGraphics::DrawSimple(
      ENUM_OBJECT _object_type, // Object type
      datetime    _time=-1,     // Time
      double      _price=-1     // Price
   )

   // ...
  }
;
//+------------------------------------------------------------------+

還有,為相應的按鍵添加處理:

//+------------------------------------------------------------------+
//|                                                    Shortcuts.mqh |
//+------------------------------------------------------------------+

// ...

//+------------------------------------------------------------------+
//| Event handling function                                          |
//+------------------------------------------------------------------+
void CShortcuts::OnChartEvent(
   const int id,
   const long &lparam,
   const double &dparam,
   const string &sparam
)
  {
//---
   int window = 0;
//---
   switch(id)
     {

      // ...

      //--- Handle keystrokes
      case CHARTEVENT_KEYDOWN:

         // ...

         //--- Draw a simple vertical line
         if(CUtilites::GetCurrentOperationChar(Simple_Vertical_Line_Key) == lparam)
           {
            m_graphics.DrawSimple(OBJ_VLINE);
           }
         //--- Draw a simple horizontal line
         if(CUtilites::GetCurrentOperationChar(Simple_Horizontal_Line_Key) == lparam)
           {
            m_graphics.DrawSimple(OBJ_HLINE);
           }

         // ...

         break;
         //---

     }
  }

在將來,為了節省屏幕空間,並專注於主要思想,在添加函數說明時,我不再編寫頭部注釋,而是顯示新添加命令的相應行(黃色高亮)。

所有添加和編譯的結果非常簡單:兩個命令可在當前窗口的任何位置繪制圖形基元:

圖形基元:垂直線和水平線

這些直線的默認快捷鍵是 "I" (i) 和 "H" (h)。

不要忘記,所創建對象的顏色會有所不同,具體取決於當前時間幀。 來自較低時間幀的對象不會在較高時間幀里顯示(默認設置)。

圖形基元:M30 上的直線

圖形基元:時間幀的演示

為了兼容 MQL4,我們僅采用來自標準工具欄的時間幀,作為默認顯示。 選擇這些時間幀時,您可用 "U" 和 "D" 鍵 (按這些鍵可向上或向下更改一次圖表周期的時間幀;參見 CUtilites::ChangeTimeframes 函數)。

VFun, 或斐波那契扇形

下一個形狀是斐波那契扇形。 我經常這樣用它。 但每次都要用不同的終端來記住所有射線是非常不便的。 因此,我決定將此工具添加到精彩的 EA 當中。

我已進一步發展了這一思路,並決定為使用該函數庫繪制的任何對象實現一個通用的設置斐波那契級別的函數(扇形通道或水平斐波級別)。 此為該函數。

//+------------------------------------------------------------------+
//| Sets level values and form in any Fibonacci object               |
//|    Uses colors and styles from the class fields                  |                        
//| Parameters:                                                      |
//|    _object_name - the name of the Fibonacci object               |
//|    _levels_values[] - array of level values                      |
//+------------------------------------------------------------------+
void CGraphics::SetFiboLevels(
   string _object_name,                      // Object name
   const double &_levels_values[]            // Array of values
)
  {
   int i,                                      // Current level counter
       levels_count=ArraySize(_levels_values); // Total number of levels

//--- Check if the number of values in the array exceeds the allowed range
   if(levels_count>32 || levels_count==0)
     {
      Print(DEBUG_MESSAGE_PREFIX,": Levels cannot be set! Data array is incorrectly. ");
      return;
     }

//--- Proceed with the implementation

//--- Set the number of levels for the current object
   ObjectSetInteger(0,_object_name,OBJPROP_LEVELS,levels_count);
//--- Set value, color and style for each level.
   for(i=0; i<levels_count; i++)
     {
      ObjectSetDouble(0,_object_name,OBJPROP_LEVELVALUE,i,_levels_values[i]);
      ObjectSetInteger(0,_object_name,OBJPROP_LEVELCOLOR,i,m_Fibo_Default_Color);
      ObjectSetInteger(0,_object_name,OBJPROP_LEVELSTYLE,i,m_Fibo_Default_Style);
     }
//--- Redraw the chart before finishing
   ChartRedraw(0);
  }

傳遞給函數的參數包括為其設置級別的對象名稱,以及所有級別值的數組。

首先,該函數檢查所傳遞的級別數量。 如果數組太大,則該函數會假定已發生錯誤,且不執行任何操作。 如果數組中沒有元素,它也會退出。

那麼,若一切正常,且數組中的元素數量未超出允許的範圍,那麼我們開始添加級別。 對象的名稱是在參數中指定的,因此我們只需將對象的相應屬性設置為等於數組元素的數量,並在設置相應級別的同時遍曆整個數組。

MQL5 還允許為不同的參數設置不同的級別。 例如,我們可以設置不同的顏色。 我們也可以使用不同的樣式(實線、虛線、等等)。 MQL4 則未提供此類選項。 盡管如此,我還在循環中添加了定義直線顏色和樣式。它們在編譯時不會影響 MQL5 的通用性。

變量說明的默認參數被定義為 CGraphics 類的私有成員,並在類構造函數中以 EA 參數中的數值進行初始化。

//+------------------------------------------------------------------+
//|                                                     Graphics.mqh |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| Class for plotting graphic objects                               |
//+------------------------------------------------------------------+
class CGraphics
  {
   //--- Fields
private:
   // ...
   color             m_Fibo_Default_Color;
   ENUM_LINE_STYLE   m_Fibo_Default_Style;
   // ...
//+------------------------------------------------------------------+
//| Default constructor                                              |
//+------------------------------------------------------------------+
CGraphics::CGraphics(void)
  {
   //...
   m_Fibo_Default_Color = Fibo_Default_Color;
   m_Fibo_Default_Style = VFun_Levels_Style;
  }
   // ...

對於那些不關心兼容性的人,我還添加了該函數的一個覆蓋。 它允許采用函數參數中所傳遞的數組為每個級別設置參數。 我想代碼中的內容都很清楚。 如果您需要進一步的解說,請留下相應的評論。 在附帶的 zip 中啟用了函數覆蓋。

此處是另一個函數,可為任何斐波那契對象設置級別描述

//+------------------------------------------------------------------+
//| Sets descriptions of levels in any Fibonacci object              |
//|    _object_name - the name of the Fibonacci object               |
//|    _levels_descriptions[] - array of level descriptions          |
//+------------------------------------------------------------------+
void CGraphics::SetFiboDescriptions(
   string _object_name,                  // Object name
   const string &_levels_descriptions[]  // Array of descriptions
)
  {
   int i,                                                                  // Current level counter
       levels_count=(int)ObjectGetInteger(0,_object_name,OBJPROP_LEVELS),  // The real number of levels
       array_size=ArraySize(_levels_descriptions);                         // The number of received descriptions
//--- Loop  through all levels
   for(i=0; i<levels_count; i++)
     {
      if(array_size>0 && i<array_size) // Choose a description from the array
        {
         //--- and write it to the level
         ObjectSetString(0,_object_name,OBJPROP_LEVELTEXT,i,_levels_descriptions[i]);
        }
      else // If the descriptions are not enough,
        {
         ObjectSetString(0,_object_name,OBJPROP_LEVELTEXT,i,""); // leave the description empty
        }
     }
//--- Redraw the chart before finishing
   ChartRedraw(0);
  }

這里沒什麼複雜的。 唯一的條件是,在調用此函數時,必須已經設置了對象級別。 該函數只是簡單地遍曆這些級別,並將來自數組的相應值分配給每個級別的描述。 如果數組中的數據不足,某些級別將保持不變,且無需說明。

現在,在添加級別時變得更容易了,我們可以編寫添加斐波那契扇形的函數。

//+------------------------------------------------------------------+
//| Draws a Fibonacci fan from the nearest local extremum.           |
//+------------------------------------------------------------------+
void CGraphics::DrawVFan(void)
  {
//---
   double levels_values[];                 // Array of level values
   string levels_descriptions[] = {};      // Array of level descriptions
   int p1=0,                               // Bar number for the fan starting point
       p2=0;                               // Bar number for the fan ending point
   double price1=0,                        // First point price
          price2=0;                        // Second point price
   string fun_name =                       // Fan name
      CUtilites::GetCurrentObjectName(allPrefixes[3],OBJ_FIBOFAN),
      fun_0_name =
         CUtilites::GetCurrentObjectName(allPrefixes[3]+"0_",OBJ_TREND);

//--- Get data for the fan from the parameter string
   CUtilites::StringToDoubleArray(VFun_Levels,levels_values);

//--- Find the extreme points closest to the mouse
   if(CMouse::Below())     // If the mouse cursor is below the price
     {
      CUtilites::SetExtremumsBarsNumbers(false,p1,p2);
      price1=iLow(Symbol(),PERIOD_CURRENT,p1);
      price2=iLow(Symbol(),PERIOD_CURRENT,p2);
     }
   else
      if(CMouse::Above())  // If the mouse cursor is above the price
        {
         CUtilites::SetExtremumsBarsNumbers(true,p1,p2);
         price1=iHigh(Symbol(),PERIOD_CURRENT,p1);
         price2=iHigh(Symbol(),PERIOD_CURRENT,p2);
        }
//--- Create the fan object
   ObjectCreate(
      0,fun_name,OBJ_FIBOFAN,0,
      iTime(Symbol(),PERIOD_CURRENT,p1),
      price1,
      iTime(Symbol(),PERIOD_CURRENT,p2),
      price2
   );

//--- The zero ray of this object is denoted by a colored line (for compatibility with MT4)
   TrendCreate(
      0,
      fun_0_name,
      0,
      iTime(Symbol(),PERIOD_CURRENT,p1),
      price1,
      iTime(Symbol(),PERIOD_CURRENT,p2),
      price2,
      CUtilites::GetTimeFrameColor(CUtilites::GetAllLowerTimeframes()),
      0,1,false,true,true
   );

//--- Describe the fan levels
   SetFiboLevels(fun_name,levels_values);
   SetFiboDescriptions(fun_name, levels_descriptions);

//--- Set standard parameters (such as timeframes and selection after creation)
   CurrentObjectDecorate(fun_name,m_Fibo_Default_Color);
//--- Also make out the "substitute" ray
   CurrentObjectDecorate(
      fun_0_name,
      CUtilites::GetTimeFrameColor(
         CUtilites::GetAllLowerTimeframes()
      )
   );

//---
   ChartRedraw(0);
  }

我認為當形成扇形的射線具有不同的顏色時這會很方便。 為了在 MQL4 中實現此功能,我們必須像上一篇文章中那樣在扇形上繪制一條常規直線

在這種情況下,我們不需要級別標題,因此我簡單地用了一個空數組

數值數組是利用實用工具函數依據 EA 參數創建的

CUtilites::StringToDoubleArray(VFun_Levels,levels_values);

在第一篇文章中已介紹過將字符串轉換為數字數組的實用程序。

將扇形繪圖命令添加到命令定義列表之中:

//+------------------------------------------------------------------+
//|                                                   Shortcuts.mqhh |
//+------------------------------------------------------------------+

   //...
//--- Draw a Fibonacci fan (VFun)
         if(CUtilites::GetCurrentOperationChar(VFun_Key) == lparam)
           {
            m_graphics.DrawVFan();
           }
         break;
   //...

編譯並檢查結果。 打開終端並打開所需的圖表。

將鼠標從圖表的頂部或底部移動到基準極值的左側,然後按 “ F”。

斐波那契扇形 (VFun)

順便說一句,查看此特定扇形的配置,我假設價格很快就會下跌。

價格最終下跌。


斐波那契扇形 (future)

安德魯草叉

我使用 3 類草叉。

首先,我選擇所需的極值,並繪制“常規”草叉。 草叉的端點恰好處於極值價位。

“常規”安德魯草叉

安德魯斯描述的第二類草叉是席夫草叉。 此處,端點 1在趨勢方向上 1-2 距離的一半處。 相應地,中心線的斜率較小。 如果走勢與這些草叉相適,則走勢很可能是橫盤,故而價格正處於“調整”走勢當中。

希夫草叉

第三類是“反轉”草叉。 端點 1 逆勢方向上與 1-2 距離相同的偏移。 這種草叉可應對快速走勢。 通常,它們的時間較短,但它們之間的價格差距較大。

在實際分析中,我希望同時將所有三種類型的草叉都放在圖表上。 在這種情況下,價格走勢以及未來可能出現的極端現象的關鍵點就更加清晰了。

一套安德魯草叉

用兩個函數來繪制這樣的集合。 第一個是繪制一個任意類型草叉的函數

//+------------------------------------------------------------------+
//| Creates Andrews' pitchfork using specified coordinates            |
//| Parameters:                                                      |
//|    _name - the name of created pitchfork                         |
//|    _base - the structure containing coordinates of  basic points |
//|    _type - pitchfork type (SIMPLE,SHIFF,REVERCE)                        |
//+------------------------------------------------------------------+
void  CGraphics::MakePitchfork(
   string _name,           // The name of the created object
   PitchforkPoints &_base, // Structure describing pitchfork base points
   PitchforkType _type     // Pitchfork type (SIMPLE,SHIFF,REVERCE)
)
  {
//---
   double price_first;                 // The price of the first point (depends on the type)
   color pitchfork_color;              // Pitchfork color (depends on the type)
   int pitchfork_width;                // Line width (depends on the type)
   ENUM_LINE_STYLE pitchfork_style;    // Line style (depends on the type)
   double fibo_levels[] = {1};         // Add external levels (only for MQL5)
   string fibo_descriptions[] = {""};  // Level description (only for MQL5)

//--- Set type dependent parameters:
   if(_type == SHIFF)      // Schiff pitchfork
     {
      price_first = _base.shiffMainPointPrice;
      pitchfork_color = Pitchfork_Shiff_Color;
      pitchfork_width = Pitchfork_Shiff_Width;
      pitchfork_style = Pitchfork_Shiff_Style;
     }
   else
      if(_type == REVERCE) // "Reverse" pitchfork
        {
         price_first = _base.reverceMainPointPrice;
         pitchfork_color = Pitchfork_Reverce_Color;
         pitchfork_width = Pitchfork_Reverce_Width;
         pitchfork_style = Pitchfork_Reverce_Style;
        }
      else
        {
         // "classic" pitchfork
         price_first =_base.mainPointPrice;
         pitchfork_color = Pitchfork_Main_Color;
         pitchfork_width = Pitchfork_Main_Width;
         pitchfork_style = Pitchfork_Main_Style;
        }

//--- Draw
   ObjectCreate(0,_name,OBJ_PITCHFORK,0,
                _base.time1,price_first,
                _base.time2,_base.secondPointPrice,
                _base.time3,_base.thirdPointPrice
               );
//--- Set the parameters common for all graphical objects
   CurrentObjectDecorate(
      _name,
      pitchfork_color,
      pitchfork_width,
      pitchfork_style
   );
//--- If MQL5
#ifdef __MQL5__
//--- add external levels (early levels for Andrews' pitchfork)
   SetFiboLevels(_name,fibo_levels);
   SetFiboDescriptions(_name,fibo_descriptions);
#endif

//--- Update the chart picture
   ChartRedraw(0);
  }

第二個函數計算所創建草叉的點 1、2 和 3(基準)的坐標,並依次開始繪制所有三個對象。 基於此函數,調用上面的 CGraphics::MakePitchfork 函數繪制草叉。

//+------------------------------------------------------------------+
//| Draws set of Andrews' pitchforks on one base. The set includes    |
//|    three pitchfork types: regular, Schiff and reverse Schiff     |
//|    (aka "micmed channel")                                        |
//+------------------------------------------------------------------+
void CGraphics::DrawPitchforksSet(void)
  {
   bool up=true;                             // direction (mouse below or above the price)
   double dropped_price = CMouse::Price();   // "Starting point" price
   int dropped_bar = CMouse::Bar();          // Starting point bar number
   string name = "";                         // The name of the current object
   PitchforkPoints base;                     // Structure for the base coordinates
//---
   if(CMouse::Below())
     {
      up=false;
     }
   else
     {
      if(!CMouse::Above()) // If the mouse pointer is on the candlestick, do nothing
        {
         if(Print_Warning_Messages)
           {
            Print(DEBUG_MESSAGE_PREFIX,": Set a point above or below the bar extreme price");
           }
         return;
        }
     }
//--- Find extremum bar numbers
   int bar_first = CUtilites::GetNearestExtremumBarNumber(
                      dropped_bar,
                      true,
                      up,
                      Pitchfork_First_Point_Left_Bars,
                      Pitchfork_First_Point_Right_Bars
                   );
   int bar_second = CUtilites::GetNearestExtremumBarNumber(
                       bar_first-1,
                       true,
                       !up,
                       Pitchfork_Second_Point_Left_Bars,
                       Pitchfork_Second_Point_Right_Bars
                    );
   int bar_third = CUtilites::GetNearestExtremumBarNumber(
                      bar_second-1,
                      true,
                      up,
                      Pitchfork_Third_Point_Left_Bars,
                      Pitchfork_Third_Point_Right_Bars
                   );
//--- If not found, report an error
   if(bar_first<0||bar_second<0||bar_third<0)
     {
      if(Print_Warning_Messages)
        {
         Print(DEBUG_MESSAGE_PREFIX,": Could not find points that match all conditions.");
        }
      return;
     }

//--- Fill the structure for basic control points
   base.mainPointPrice = up ?                               // Price - first basic point
                         iHigh(Symbol(),PERIOD_CURRENT,bar_first)
                         : iLow(Symbol(),PERIOD_CURRENT,bar_first);
   base.secondPointPrice = up ?                             // Price - second basic point
                           iLow(Symbol(),PERIOD_CURRENT,bar_second)
                           : iHigh(Symbol(),PERIOD_CURRENT,bar_second);
   base.thirdPointPrice = up ?                              // Price - third basic point
                          iHigh(Symbol(),PERIOD_CURRENT,bar_third)
                          : iLow(Symbol(),PERIOD_CURRENT,bar_third);
   base.shiffMainPointPrice = base.mainPointPrice-          // Price - first point of Schiff pitchfork
                              (base.mainPointPrice-base.secondPointPrice)/2;
   base.reverceMainPointPrice = base.mainPointPrice+        // Price - first point of "reverse" pitchfork
                                (base.mainPointPrice-base.secondPointPrice)/2;
   base.time1 = iTime(Symbol(),PERIOD_CURRENT,bar_first);   // Time of the first point
   base.time2 = iTime(Symbol(),PERIOD_CURRENT,bar_second);  // Time of the second point
   base.time3 = iTime(Symbol(),PERIOD_CURRENT,bar_third);   // Time of the third point


//--- Draw "regular" pitchfork
   if(Pitchfork_Show_Main)
     {
      name =CUtilites::GetCurrentObjectName(allPrefixes[4]+"_main",OBJ_PITCHFORK);
      MakePitchfork(name,base,SIMPLE);
     }

//--- Draw Schiff pitchfork
   if(Pitchfork_Show_Shiff)
     {
      name =CUtilites::GetCurrentObjectName(allPrefixes[4]+"_shiff",OBJ_PITCHFORK);
      MakePitchfork(name,base,SHIFF);
     }

//--- Draw "reverse" pitchfork
   if(Pitchfork_Show_Reverce)
     {
      name =CUtilites::GetCurrentObjectName(allPrefixes[4]+"_reverce",OBJ_PITCHFORK);
      MakePitchfork(name,base,REVERCE);
     }
//---
//ChartRedraw(0); not needed here as it is called when drawing each object
  }

我用以下枚舉來定義草叉類型:

//+------------------------------------------------------------------+
//| Possible Andrews' pitchfork types                                 |
//+------------------------------------------------------------------+
   enum PitchforkType
     {
      SIMPLE,
      SHIFF,
      REVERCE
     };

我為這些端點添加了一個結構( PitchforkPoints base ;),以便在調用繪圖函數時向其傳遞更少的參數

//+------------------------------------------------------------------+
//|  Structure describing a "base" for the Andrews' pitchfork         |
//+------------------------------------------------------------------+
   struct PitchforkPoints
     {
      double            mainPointPrice;        // Price - first base point
      double            shiffMainPointPrice;   // Price - second base point
      double            reverceMainPointPrice; // Price - third base point
      double            secondPointPrice;      // Price - first point of Schiff pitchfork
      double            thirdPointPrice;       // Price - first point of "reverse" pitchfork
      datetime          time1;                 // Time of the first point
      datetime          time2;                 // Time of the second point
      datetime          time3;                 // Time of the third point
     };

最後,在 “Shortcuts.mqh” 文件中的控制鍵上加入對其反應的說明:

//+------------------------------------------------------------------+
//|                                                   Shortcuts.mqhh |
//+------------------------------------------------------------------+

   //...
//--- Draw Andrews' Pitchfork
         if(CUtilites::GetCurrentOperationChar(Pitchfork_Key) == lparam)
           {
            m_graphics.DrawPitchforksSet();
           }
         break;
   //...



編譯並檢查。

為了在圖表上顯示草叉,請按 “P” 鍵(Pitchfork)。


MetaTrader 中的趨勢線繪圖功能

通常,上述對象可用於任何圖形。 該功能支持直線、安德魯草叉、斐波那契扇形、水平和垂直級別。

與此類似,通過查找在鼠標右側或左側的極值點,我們可以繪制通道、水平斐波那契級別、等等。 如果您經常使用這些形狀,則可以輕松實現所需的功能。

對我來說,這個函數庫中最困難的部分涉及到那種一個端點在右邊,而第二個端點在未來的直線。

這樣的直線能非常方便地依據價格和時間標記顯著的級別。 作為規則,價格會注意到這些級別,並至少在附近某個位置形成局部極值,價格於該處經常反轉。

但事實證明,MetaTrader 中的直線繪制功能采用價格和時間。

當在星期五繪制直線,且其右側為星期一時,會出現第一個問題。

星期五,兩條自動繪制的直線

在星期五,MetaTrader 認為必須有星期日,但隨後在星期一才知道,該日期不能進行交易,因此必須丟棄兩天。 由此,依據時間坐標繪制的直線會更短。 在上圖中可以清晰地看到這一點。

如果我需要在圖表上測量一定數量的柱線,則此行為極不方便。

解決方案非常簡單:日期不必通過日曆計算,而是依據點位。 鼠標坐標在圖表上顯示一個點;燭條之間的距離始終可以計算(例如,如第一篇文章中“相鄰柱線之間的距離(以像素為單位)”章節所述),然後我們只需為所需數量的燭條進行計數,然後使用標準的 ChartXYToTimePrice 函數將屏幕坐標轉換為時間和價格。 但為了避免“星期日塌陷”,應該在星期一繪制這條直線,而不是在星期五。

該方法似乎不錯,但有一點瑕疵。 MetaTrader 可在其上畫線的空間大小是有限的。 如果您試圖畫一條長線,超出程序允許的空間(例如,非常靠近邊框,如左圖所示),則效果可能非常出乎意料。

右圖示意自動繪制的同一條線,但現在圖表向右偏移,以便顯示右邊框。 其下是本該在此尺度上的正常直線。 從上邊的直線屬性來看,它的右端點超前了將近六個月!

有時,加一條斜線,我能看到這條線是如何往相反方向逆轉的。 MetaTrader 無法將點位的坐標轉換為正確的日期,只能將其設置為 0(相應地,日期為 1970 年 1 月 1 日)。 如果線段是依據日期來繪制,則這種效果永遠不會發生。

結論:我們需要一個函數來計算尚未確定的未來日期,以便繪制直線。

因此,我們來創建這樣的函數。

獲取未來日期的函數

通常,現在或過去存在某些要測量的點(例如,某種極值)。 再加上,我們通常要麼知道以柱線為單位的偏移距離,要麼可以輕松地計算它。 如此,該函數最常見的任務是基於柱線圖的偏移來計算相對於某個點位的時間。 然而,我還是喜歡根據比例縮放級別的效果。 故此,有時我想讓函數依據點位而非柱線來計算時間。

點位的數量和柱線的數量都是整數,因此,該函數需要某種功能才能確切地理解如何去做。 我們從此功能開始。

//+------------------------------------------------------------------+
//|                                              GlobalVariables.mqh |
//+------------------------------------------------------------------+

//...
//+------------------------------------------------------------------+
//| The enumeration describes possible options for calculating the   |
//|   time of the next bar                                           |
//|      COUNT_IN_BARS - calculate date by the number of bars        |
//|      COUNT_IN_PIXELS - calculate date by the number of pixels    |
//+------------------------------------------------------------------+
enum ENUM_FUTURE_COUNT {
   COUNT_IN_BARS,    // By bars
   COUNT_IN_PIXELS   // By pixel
};
//...

枚舉和全局變量的所有描述都在 GlobalVariables.mqh 文件之中。 作為我們未來函數選擇間隔的可能選項,還應添加枚舉到此文件當中。

該函數本身不繪制任何東西,且與鼠標無關。 因此,它必須是一個實用工具。

//+------------------------------------------------------------------+
//|                                                     Utilites.mqh |
//+------------------------------------------------------------------+

//...
class CUtilites
  {
public:
//...
   //--- Calculates a date in the future relative to the start date with the _length interval, specified in pixels or bars
   static datetime          GetTimeInFuture(
      const datetime _start_time,                         // Reference time based on which the future bar is calculated
      const int _length,                                  // Interval length (in bars or pixels)
      const ENUM_FUTURE_COUNT _count_type=COUNT_IN_BARS   // Interval type (pixels or bars).
   );

//...

//+------------------------------------------------------------------+
//| The function tries to calculate date in the future using the     |
//|   screen x and y coordinates                                     |
//| If calculation is unsuccessful (time exceeds limits), calculates |
//|   time with an error: as a sum of dates excluding Sundays.       |
//| Parameters:                                                      |
//|   _current_time,              Source time,                       |
//|   _length,                    Interval length                    |
//|                                 (in bars or in pixels)           |
//|   _count_type=COUNT_IN_BARS   How interval length is measured.   |
//|      COUNT_IN_BARS - the interval is set in bars;                |
//|      COUNT_IN_PIXELS - the interval is set in pixels.            |
//| Returns:                                                         |
//|   Time in the future distant from the _current_time              |
//|      by an interval in pixels or bars (_length)                  |
//+------------------------------------------------------------------+
datetime CUtilites::GetTimeInFuture(
   const datetime _start_time,                         // Reference time based on which the future bar is calculated
   const int _length,                                  // Interval length (in bars or pixels)
   const ENUM_FUTURE_COUNT _count_type=COUNT_IN_BARS   // Interval type (pixels or bars).
)
  {
//---
   datetime
      future_time;      // Variable for result
   int
      bar_distance =  GetBarsPixelDistance(),   // Distance in pixels between two adjacent bars
      current_x,                                // The x coordinate of the starting point
      future_x,                                 // The x coordinate of the result
      current_y,                                // The y coordinate, does not affect the result; needed for the conversion function
      subwindow = 0;                            // Subwindow index
   double current_price;                        // Any initial price, does not affect the result
   

//--- Convert the time passed in parameters into the screen coordinate x
   ChartTimePriceToXY(0,subwindow,_start_time,CMouse::Price(),current_x,current_y);

//--- Calculate a point in the future in screen coordinates
   if(COUNT_IN_BARS == _count_type) // If the length is specified in bars,
     {
      // then the interval size should be converted to pixels.
      future_x = current_x + _length*bar_distance;
     }
   else // ... If the length is in pixels,
     {
      // use it as is
      future_x = current_x + _length;
     }

//--- Convert screen coordinates into time
   if(ChartGetInteger(0,CHART_WIDTH_IN_PIXELS)>=future_x) // If successful,
     {
      ChartXYToTimePrice(0,future_x,current_y,subwindow,future_time,current_price);  // convert the resulting value
     }
   else // Otherwise, if time cannot be calculated because it exceeds limits
     {
      future_time =        // Calculate time as usual, in seconds
         _start_time       // To the starting time
         +(                // add
            ((COUNT_IN_BARS == _count_type) ? _length : _length/bar_distance) // interval size in bars
            *PeriodSeconds()  // multiplied by the number of seconds in the current period
         );
     }
//--- Return the resulting value
   return future_time;
  }

然而,事實證明,先前版本中描述的函數並不總是會產生正確的結果。 這就是為什麼我不得不重寫它。 一切都變得簡單很多。

//+------------------------------------------------------------------+
//|                                                     Utilites.mqh |
//+------------------------------------------------------------------+
//...
//+------------------------------------------------------------------+
//| Calculates a distance in pixels between two adjacent bars        |
//+------------------------------------------------------------------+
int        CUtilites::GetBarsPixelDistance(void)
  {
//--- Calculate the distance
   return ((int)MathPow(2,ChartGetInteger(0,CHART_SCALE)));
  }
//...


受限的水平級別

我在上一章節中展示了這些級別。 它是一定長度的線段,理想情況下並不取決於您將鼠標指向何處。 它從鼠標光標指向的點位開始繪制。 因此,相比於扇形,選擇一個點位要更謹慎。

我希望這些級別是具有嚴格定義的長度(根據經驗),以像素為單位。 然後,該線段在不同比例下將覆蓋不同數量的柱線。

另外,我希望能夠編寫一個正常線段級別,和一個擴展的 - 都在相同的尺度上。

此處是我們的所得:

//+------------------------------------------------------------------+
//|                                                     Graphics.mqh |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Draws a horizontal level                                         |
//| Parameters:                                                      |
//|   _multiplicator - multiplier for determining the length         |
//|                of the larger level (how many times higher)       |
//+------------------------------------------------------------------+
//---
void CGraphics::DrawHorizontalLevel(
   double _multiplicator // Multiplier for the level length
)
  {
//--- Description of variables
   datetime p2_time;          // Time of point 2
   string Level_Name ="";     // Level name

//Color of the current line (equal to  the general color of the current time interval)
   color Level_Color=CUtilites::GetTimeFrameColor(CUtilites::GetAllLowerTimeframes());
   int window = 0;            // The index of the subwindow in which the line is drawn
   ENUM_LINE_STYLE Current_Style = STYLE_SOLID; // Line style
   int Current_Width=1;                         // Line width
   int level_length = 0;                        // Line length

//--- Get the length (in pixels)
   if(Short_Level_Length_In_Pixels)
     {
      // If EA parameters instruct to measure in pixels,
      level_length = Short_Level_Length_Pix; // ...Use the length from parameters
     }
   else
     {
      // Otherwise the number of candlesticks is specified in parameters
      level_length = Short_Level_Length * CUtilites::GetBarsPixelDistance();
     }

//--- Set level parameters
   if(_multiplicator>1) // If the level is extended
     {
      Level_Name = CUtilites::GetCurrentObjectName(allPrefixes[7]);
      Current_Style = Long_Level_Style;
      Current_Width = Long_Level_Width;
     }
   else                 // An if the level is short
     {
      Level_Name = CUtilites::GetCurrentObjectName(allPrefixes[6]);
      Current_Style = Short_Level_Style;
      Current_Width = Short_Level_Width;
     }

//--- Calculate real coordinates (price and time) for the second point
   p2_time = CUtilites::GetTimeInFuture(CMouse::Time(),level_length*_multiplicator,COUNT_IN_PIXELS);


//--- Draw a line using the known coordinates
   TrendCreate(0,
               Level_Name,
               0,
               CMouse::Time(),
               CMouse::Price(),
               p2_time,
               CMouse::Price(),
               Level_Color,
               Current_Style,
               Current_Width
              );
//---
   
   ChartRedraw(0);
  }

第一點位由鼠標指針確定。 在計算第二個點位時,程序首先 選擇線段大小是否應隨圖表比例的變化而變化,然後計算第二個點位的坐標(以像素為單位),並據其重新計算轉化為價格和時間。 (若您已有現成函數,計算並不會很困難)。

現在我們需要向 Shortcuts.mqh 文件中添加控制命令:

//+------------------------------------------------------------------+
//|                                                    Shortcuts.mqh |
//+------------------------------------------------------------------+

// ...

//--- Draw a short limited level
         if(CUtilites::GetCurrentOperationChar(Short_Level_Key) == lparam)
           {
            m_graphics.DrawHorizontalLevel(1);
           }
//--- Draw an extended limited level
         if(CUtilites::GetCurrentOperationChar(Long_Level_Key) == lparam)
           {
            m_graphics.DrawHorizontalLevel(Long_Level_Multiplicator);
           }
// ...

結果就是,若 Short_Level_Length_In_Pixels 參數為 true,則當按下 S Short)鍵,程序將繪制一個水平線段,其長度以 Short_Level_Length_Pix 參數中指定的像素為單位。

Short_Level_Length_In_Pixels == false,則級別長度以燭條數量度量,且其值取自 Short_Level_Length 參數。

若您按下 "L" (Long),則線段長度加倍 (會乘以 Long_Level_Multiplicator 參數內指定的數字)。



受限的趨勢線

我相信趨勢線可以承受雙倍負荷。

一方面,它顯示了價格變化率的限制(如果價格低於該趨勢線,則為“不快” ;如果價格低於該趨勢線,則為“不慢” , 價格高於上限)。

另一方面,如果直線受價格和時間的限制(不是射線),則可以作為級別指示(價格和時間兩者)。 當然,出於這些目的,我們可以使用矩形或其他形狀,但是我認為對角線更清晰。

因此,我修改了 Graphics::DrawTrendLine 函數。 首先,這條線現在會在有限時間內持續到未來,因此可指示估價。 其次,為清楚起見,我添加了通常的級別 - 水平和垂直。

看起來像這樣:

受限的趨勢線

當然,線段的長度(總長度大於起始點之間的距離的多少倍),極值的柱線數量以及直線的其他特征都在 EA 參數中配置。

//+------------------------------------------------------------------+
//|                                                     Graphics.mqh |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Draws a trend line using two nearest extreme points.             |
//|   Extremum length (number of bars on left and right) is set      |
//|   by parameters Fractal_Size_Left and Fractal_Size_Right         |
//|                                                                  |
//| There is a "Trend_Points" variable in the global parameters.     |
//|                                                                  |
//| If the variable value is equal to "TREND_DOTS_EXTREMUMS",        |
//|   end points of the straight line will lie strictly at extrema.  |
//| If the values is "TREND_DOTS_HALF", the line will be             |
//|   extended into the future by a distance of                      |
//|   (p2-p1)*Trend_Length_Coefficient                               |
//+------------------------------------------------------------------+
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(allPrefixes[0],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;   // a variable to store time



//--- 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 prices by Low
      price1=iLow(Symbol(),PERIOD_CURRENT,p1);
      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 prices by High
         price1=iHigh(Symbol(),PERIOD_CURRENT,p1);
         price2=iHigh(Symbol(),PERIOD_CURRENT,p2);
        }
      else
        {
         return;
        }
//--- The time of the first and second points does not depend on the direction
   time1=iTime(Symbol(),PERIOD_CURRENT,p1);
   time2=iTime(Symbol(),PERIOD_CURRENT,p2);

//--- If the line should be extended to the right
   if(Trend_Points == TREND_POINTS_HALF)
     {
      //--- Temporarily save the coordinates of point 2
      tmp_price = price2;
      tmp_time = time2;
      
      //--- Calculate the time of the second point
      time2 = CUtilites::GetTimeInFuture(time1,(p1-p2)*Trend_Length_Coefficient);

      //--- Calculate the price of the second point
      price2 = NormalizeDouble(price1 + (tmp_price - price1)*Trend_Length_Coefficient,Digits());

      //--- Draw boundary levels by price and time
      DrawSimple(OBJ_HLINE,time2,price2);
      DrawSimple(OBJ_VLINE,time2,price2);
     }

//--- 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
              );

//--- Redrawing the chart
   ChartRedraw(0);
  }

代碼中的其他修改以黃色高亮顯示。

其餘的很簡單。 點位之間的柱線數量等於(р1-р2)(請注意,柱線編號向右增加)。 系數能夠由間隔擴展多少來計算。 然後,即使沒有指定第三個參數,也可以簡單地調用實用工具函數,因為默認情況下它能夠以柱線為單位進行計算。

然後計算價格,使用先前講述的位於同一個類里的 DrawSimple 函數繪制級別,並繪制主線。

初學者可能會問:“函數如何“知道”應該在何處添加價格:向上還是向下? 如果該線段從上至下,則應減去價格,而從下至上,則應加上價格。”

請注意,鑒於對我們來說,鏈接到低點還是鏈接到高點並不重要(我們已經在函數開始處進行了檢查),因此方向由表達式 price1 + (tmp_price - price1) 唯一判定。

如果線段向下,則 price1 將大於第二個點位的價格,因此,表達式(tmp_price-price1)為負。 因此,所需的距離將從價格中 扣除

如果線向上,則定義第二個點位的價格將大於第一個點位,且括號中的表達式將為正,因此距離將被加上初始價格。

我想提一下此函數的另一個功能; 這是針對初學者的解釋。 如果函數計算價格,則必須將數據常規化。 也就是說,我們需要確保接收到的數字與圖表上的報價擁有相同的小數位數。 否則,將會發生錯誤。 NormalizeDouble 函數即用於規範價格。

無需在 Shortcuts.mqh 文件中進行任何修改。 按下 "T" 鍵 (Trend) 即可繪制該直線。 因此,應調用上述函數來畫線。

//+------------------------------------------------------------------+
//|                                                    Shortcuts.mqh |
//+------------------------------------------------------------------+

//...
//--- Draw a trend line
         if(CUtilites::GetCurrentOperationChar(Trend_Line_Key) == lparam)
           {
            m_graphics.DrawTrendLine();
           }
//...


繪制垂直級別

由於行情具有趨勢性,且價格走勢並非完全隨機,因此通常可以使用以下規則進行交易:價格總是傾向於按照剛過去的相同距離移動。 走勢的方向是一個單獨的問題。 通常,在突破之後,譬如尖峰柱線、或某些較大燭條的邊緣後,價格移動的距離與所測量柱線相同,然後反轉。

盡管如此,許多交易大戶(最終能判斷方向的那些人)更願意在達到 100% 級別之前提早平倉。 因此,價格經常不能達到眾所期待級別。

因此,我也使用局部級別進行交易。 最經常使用的級別是 7/8。 我們將在本文中研究的最後一個工具即設計用於在屏幕上顯示這些級別。

現在,繪制級別的函數應該很容易理解。

//+------------------------------------------------------------------+
//|                                                     Graphics.mqh |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Draws a vertical line at levels 7/8 and 14/8 of the              |
//|   current candlestick size                                       |
//+------------------------------------------------------------------+
void CGraphics::DrawVerticalLevels(void)
  {
//--- Description of variables
   string
   Current_Vertical_Name =   // The name of the basic vertical line
      CUtilites::GetCurrentObjectName(allPrefixes[5]),
      Current_Level_Name =          // The name of the current level
         CUtilites::GetCurrentObjectName(allPrefixes[5]+"7_8_");
   double
   Current_Line_Lenth,           // The length of the current line (level or vertical)
   Current_Extremum,             // Working extremum (High or Low, depending on the mouse position
   Level_Price,                  // Level price
   High = iHigh(Symbol(),PERIOD_CURRENT,CMouse::Bar()), // The High price of the current candlestick
   Low =  iLow(Symbol(),PERIOD_CURRENT,CMouse::Bar());  // The Low price of the current candlestick
   int
   direction=0;                  // Price increment sign
   long timeframes;                 // List of working timeframes
   datetime
   Current_Date =                // Time of the current bar
      iTime(Symbol(),PERIOD_CURRENT,CMouse::Bar()),
      Right_End_Time =              // Time of the right border of the level
         CUtilites::GetTimeInFuture(Current_Date,Short_Level_Length);

//--- Calculating candlestick length
   Current_Line_Lenth = (High-Low)*2;

//--- Initialization of the main variables depending on the desired drawing direction
   if(CMouse::Above()) // If the mouse is above
     {
      Current_Extremum = High;   // The main price is High
      direction = -1;            // Drawing direction - downward
     }
   else              // Otherwise
     {
      if(CMouse::Below()) // If the mouse is below
        {
         Current_Extremum = Low; // The main price is Low
         direction = 1;          // Drawing direction is upward
        }
      else         // If the mouse is in the middle of the candlestick, exit
        {
         return;
        }
     }

//--- Vertical line
   TrendCreate(0,
               Current_Vertical_Name,
               0,
               Current_Date,
               Current_Extremum,
               Current_Date,
               Current_Extremum+(Current_Line_Lenth*2)*direction,
               CUtilites::GetTimeFrameColor(CUtilites::GetAllLowerTimeframes()),
               Vertical_With_Short_Levels_Style,
               Vertical_With_Short_Levels_Width
              );
//--- First level (7/8)
   Level_Price = Current_Extremum+(Current_Line_Lenth*Vertical_Short_Level_Coefficient)*direction;
   TrendCreate(0,
               Current_Level_Name,
               0,
               Current_Date,
               Level_Price,
               Right_End_Time,
               Level_Price,
               CUtilites::GetTimeFrameColor(CUtilites::GetAllLowerTimeframes()),
               Short_Level_7_8_Style,
               Short_Level_7_8_Width
              );
//--- Second level (14/8)
   Current_Level_Name = CUtilites::GetCurrentObjectName(allPrefixes[5]+"14_8_");
   Level_Price = Current_Extremum+(Current_Line_Lenth*2*Vertical_Short_Level_Coefficient)*direction;
   TrendCreate(0,
               Current_Level_Name,
               0,
               Current_Date,
               Level_Price,
               Right_End_Time,
               Level_Price,
               CUtilites::GetTimeFrameColor(CUtilites::GetAllLowerTimeframes()),
               Short_Level_14_8_Style,
               Short_Level_14_8_Width
              );
  }

請注意兩點。 首先,此處這些級別的時間始終以柱線為單位計算。 所需的柱線數量取自 Short_Level_Length 變量,因此,我始終知道應測量多少根柱線。

其次,此處,您在計算價格時僅能基於一個點位。 因此,有必要設置方向相關參數,這樣您就不必每次都重複檢查,並編寫雙倍的代碼。 特別是,我們設置了 direction 參數,除第一個點位外,每項都要與該參數相乘。 因此,我仍然只有一個表達式來描述線段的行為,但該表達式中術語的符號取決於鼠標的位置:燭條上方或下方。

最終形狀如上圖所示。

將控制結構添加到 Shortcuts.mqh 文件之中:

//+------------------------------------------------------------------+
//|                                                    Shortcuts.mqh |
//+------------------------------------------------------------------+

//...
//--- Draw a vertical line with 7/8 levels
         if(CUtilites::GetCurrentOperationChar(Vertical_With_Short_Levels_Key)  == lparam)
           {
            m_graphics.DrawVerticalLevels();
           }
         break;
鍵盤是 V (Vertical)。

當前函數庫實現的按鍵

動作
 按鍵 含義
 依據主要的TFs (來自 TFs 面板) 向上改變時間幀  U  Up
 向下改變時間幀  D  Down
 改變圖表 Z 級別 (圖表是否位於所有對象之上)  Z  Z order
 基於最接近鼠標的兩個單向極端點繪制一條坡度趨勢線  T  Trend line
 切換新線的射線模式
 R 鍵  Ray
 繪制一條簡單垂線
 I(i) [僅可見垂直]
 繪制一條簡單水平線
 H  Horizontal
 繪制安德魯草叉
 P  Pitchfork
 繪制斐波那契扇形 (VFun)
 F key  Fun
 繪制一條短水平級別
 S  Short
 繪制一個擴展水平級別
 L key  Long
 繪制一個帶有級別標記的垂線
 V  Vertical

結束語

我希望這篇文章會有所幫助,但我不保證任何事情。 產生的工具包非常靈活,適合在任何行情上運用。 不過,如果文章讀者開始時以默認設置使用它,則行情可能會發生變化。 大概不會明顯,因為變化是行情的本質。

歡迎您分享您的見解和想法。

祝您穩定盈利!

分享到:
舉報財經168客戶端下載

全部回複

0/140

投稿 您想發表你的觀點和看法?

更多人氣分析師

  • 張亦巧

    人氣2208文章4145粉絲45

    暫無個人簡介信息

  • 張迎妤

    人氣1904文章3305粉絲34

    個人專注於行情技術分析,消息面解讀剖析,給予您第一時間方向...

  • 指導老師

    人氣1864文章4423粉絲52

    暫無個人簡介信息

  • 李冉晴

    人氣2320文章3821粉絲34

    李冉晴,專業現貸實盤分析師。

  • 梁孟梵

    人氣2184文章3177粉絲39

    qq:2294906466 了解群指導添加微信mfmacd

  • 王啟蒙現貨黃金

    人氣312文章3419粉絲8

    本人做分析師以來,並專注於貴金屬投資市場,尤其是在現貨黃金...

  • 金泰鉻J

    人氣2328文章3925粉絲51

    投資問答解咨詢金泰鉻V/信tgtg67即可獲取每日的實時資訊、行情...

  • 金算盤

    人氣2696文章7761粉絲125

    高級分析師,混過名校,廝殺於股市和期貨、證券市場多年,專注...

  • 金帝財神

    人氣4760文章8329粉絲119

    本文由資深分析師金帝財神微信:934295330,指導黃金,白銀,...

FX168財經

FX168財經學院

FX168財經

FX168北美