English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
MQL5 Cookbook: Fiyat Farklılığını Analiz Etmek İçin Çoklu Sembollü Bir Göstergenin Geliştirilmesi

MQL5 Cookbook: Fiyat Farklılığını Analiz Etmek İçin Çoklu Sembollü Bir Göstergenin Geliştirilmesi

MetaTrader 5Örnekler | 14 Ocak 2022, 10:23
79 0
Anatoli Kazharski
Anatoli Kazharski

Giriş

Bu yazıda, belirli bir zaman diliminde fiyat farklılaşmasını analiz etmek için çoklu sembollü bir göstergenin geliştirilmesini ele alacağız. Temel konular, çoklu para birimi göstergelerinin programlanmasıyla ilgili önceki makalede zaten tartışılmıştı MQL5 Yemek Kitabı: MQL5'te Çok Sembollü Bir Volatilite Göstergesi Geliştirme. Bu sefer sadece çarpıcı biçimde değiştirilmiş olan yeni özellikler ve işlevler üzerinde duracağız. Çoklu para birimi göstergelerinin programlanmasında yeniyseniz, önce bir önceki makaleyi okumanızı tavsiye ederim.

Bu makalesef aşağıdaki soruları ele alacağız:

  • Grafik özelliklerini değiştirme.
  • CHARTEVENT_OBJECT_DRAG (bir grafik nesnesini sürükleme) ve CHARTEVENT_CHART_CHANGE (grafiği yeniden boyutlandırma veya özellikler iletişim penceresini kullanarak grafik özelliklerini değiştirme) olaylarının işlenmesi.
  • Birden fazla renk kullanarak gösterge arabellekleri oluşturma.
  • Bir grafiği yüksek/düşük ayarlamak için görünürlük alanı içindeki gösterge arabelleklerindeki yüksek ve alçakları tanımlama.
  • Bir serinin ters çevrilmesi.

Göstergemiz için ortaya çıkan kod miktarı oldukça büyük, yaklaşık 1500 satır. Bu nedenle, tüm işlevleri ayrı dosyalar halinde dağıtacağız ve bunları ana proje dosyasına bağlayacağız. Harici dosyalar için üç işlev kategorisi olacaktır:

  • Checks.mqh - Çeşitli kontrolleri gerçekleştirme ve mevcut verileri indirme işlevleri.
  • Nesneler.mqh - Grafik nesnelerini yönetmeye yönelik işlevler.
  • Grafik.mqh - Grafik özelliklerini yönetmeye yönelik işlevler.

Yukarıdaki kategorilere ait olmayan tüm işlevler ana dosyada bırakılacaktır.


Göstergenin Geliştirilmesi

Ardından göstergenin programlanmasına geçin. Öncelikle yeni bir proje oluşturmamız gereklidir. Bunu yapmak için, Metatrader 5\\MQL5\\Indicators dizininde, bizim göstergemiz olarak adlandırılan klasör oluşturun ve bunun içinde, ekleme dosyalarını yerleştireceğimiz Dahil Et klasörünü oluşturun. Ardından, gösterge klasöründe ana dosyayı oluşturun. Bu, *.mq5 uzantılı bir metin dosyası oluşturarak veya şablona göre MQL5 Sihirbazı kullanılarak manuel olarak yapılabilir. OnInit(), OnDeinit() ve OnCalculate() programının temel işlevlerine ek olarak, OnChartEvent() ve OnTimer() de kullanacağız.

Tıpkı önceki makalede olduğu gibi, mevcut sembole ek olarak, harici parametrelerde belirtilen 5 sembol için veri görüntüleyeceğiz. Ancak bu sefer, bir formülle hesaplanan değerler yerine, grafikte ham fiyat verilerini çıkaracağız. Kullanıcı, açılır listeden harici parametrelerde veri gösterimi türünü seçmekte özgürdür: Çizgi, Çubuklar veya Mum Grafik.

Verileri yalnızca tek renkli çizgiler olarak görüntülememiz gerekirse, gösterge özelliklerinde (#property) sembol sayısına eşit arabellek sayısını belirtmemiz yeterli olacaktır. Ancak, dizileri çizmek için çubuklar ve mum grafikler olarak iki mod olduğundan, iki renkli mod için daha fazla arabelleğe ihtiyacımız var: her seriyi oluşturmak için dört arabellek ve bir grafik serisindeki her öğenin (koşullara bağlı olarak) rengini ayarlamak için bir arabellek.

Program özellikleri bölümünde her seri için renklerin belirtilmesi gerekmektedir. Bunu yapmak için bunları virgülle ayırarak listelemeniz yeterlidir. Önce tek renk modunda kullanılan renk gelir. İki renkli modda, yukarı çubuklar/mum grafikler için kullanılır. İkinci renk, iki renkli modda yalnızca aşağı çubuklar/mum grafikler için kullanılacaktır.

Tüm bu parametrelerin kodları aşağıda verilmiştir:

#property indicator_chart_window // Indicator is in the main window
#property indicator_buffers 25   // Number of buffers for indicator calculation
#property indicator_plots   5    // Number of plotting series
//--- Indicator buffers colors
#property indicator_color1  clrDodgerBlue,C'0,50,100'
#property indicator_color2  clrLimeGreen,C'20,80,20'
#property indicator_color3  clrGold,C'160,140,0'
#property indicator_color4  clrAqua,C'0,140,140'
#property indicator_color5  clrMagenta,C'130,0,130'

#define yönergesi ile sabitleri bildirelim ve tuvalle çalışmak için #include komut satırını kullanarak, yukarıda zaten tanımlanmış olan işlevlere sahip dosyaları ve Standart kitaplıktan sınıfı dahil edelim:

//--- Constants 
#define RESET           0 // Returning the indicator recalculation command to the terminal
#define SYMBOLS_COUNT   5 // Number of symbols
//--- Include the class for working with the canvas
#include <Canvas\Canvas.mqh>
//--- Include the class for working with the canvas
#include "Include/Checks.mqh"
#include "Include/Chart.mqh"
#include "Include/Objects.mqh"

Harici parametrelerde fiyat verilerinin çizim türünü ve fiyat farklılık başlangıç noktasının modunu seçmeye izin veren açılır listeler oluşturmak için ENUM_DRAWTYPE ve ENUM_START_POINT numaralandırmalarını ekleyin:

//--- Drawing type of the price data
enum ENUM_DRAWTYPE
  {
   LINE   =0,  // Line
   BARS   =1,  // Bars
   CANDLES=2   // Candlesticks
  };
//--- Mode of the price divergence starting point
enum ENUM_START_POINT
  {
   VERTICAL_LINE=0,  // Vertical line
   MONTH        =1,  // Month
   WEEK         =2,  // Week
   DAY          =3,  // Day
   HOUR         =4   // Hour
  };

Veri oluşturma türleri yukarıda zaten açıklanmıştır, şimdi fiyat farklılık başlangıç noktasının ne anlama geldiğinden biraz daha bahsedelim.

Toplamda beş mod olacak: Dikey çizgi, Ay, Hafta, Gün ve Saat. Dikey çizgi modu için, grafikte gösterge yüklenirken dikey bir çizgi eklenecektir. Bu satırı sürükleyerek tüm sembollerin fiyatlarının tek bir noktada buluşacağı çubuğu belirlemiş olursunuz. Mevcut sembol için belirtilen çubuğun açık fiyatı bu buluşmanın referans noktası olarak kabul edilecektir. Diğer herhangi bir mod, programa fiyatların her seferinde belirtilen dönemin başında buluşması gerektiğini söyleyecektir. Yani her ayın başında, her haftanın başında, her günün başında veya her saat başında.

Aşağıda göstergenin giriş parametrelerinin listesini bulabilirsiniz:

//--- External parameters
input  ENUM_DRAWTYPE    DrawType             =CANDLES;       // Drawing type
input  ENUM_START_POINT StartPriceDivergence =VERTICAL_LINE; // Start of price divergence
input  bool             TwoColor             =false;         // Two-color bars/candlesticks
sinput string dlm01=""; //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
input  string           Symbol02             ="GBPUSD";      // Symbol 2
input  bool             Inverse02            =false;         // Inverse symbol 2
input  string           Symbol03             ="AUDUSD";      // Symbol 3
input  bool             Inverse03            =false;         // Inverse symbol 3
input  string           Symbol04             ="NZDUSD";      // Symbol 4
input  bool             Inverse04            =false;         // Inverse symbol 4
input  string           Symbol05             ="USDCAD";      // Symbol 5
input  bool             Inverse05            =false;         // Inverse symbol 5
input  string           Symbol06             ="USDCHF";      // Symbol 6
input  bool             Inverse06            =false;         // Inverse symbol 6

1, grafikteki geçerli sembol olduğundan, semboller 2'den başlayarak numaralandırılmıştır.

Dahil edilen her sembol için ters çevirme uygulanabilir. Ters çevirme, sembol verilerinin ters çevrileceği anlamına gelir. Bu, analiz edilen sembollerin listesi aynı para biriminin (örneğin ABD doları) hem temel hem de karşı para birimi olabileceği döviz çiftlerini içerdiğinde faydalı olabilir. Örneğin EURUSD döviz çiftinde ABD doları karşı dövizdir ve USDCHF döviz çiftinde temel dövizdir. Grafikteki mevcut sembol EURUSD ise USDCHF için inversiyonu açabilirsiniz; bu, fiyatların temsilini analiz için daha uygun hale getirecektir.

Aşağıda global değişkenlerin ve dizilerin listesi bulunmaktadır:

//--- Structure of the indicator buffers arrays
struct buffers
  {
   double            open[];   // Open prices buffer
   double            high[];   // High prices buffer
   double            low[];    // Low prices buffer
   double            close[];  // Close prices buffer
   double            icolor[]; // Buffer to determine the color of element
  };
buffers           buffer_data[SYMBOLS_COUNT];
//--- Load the class
CCanvas           canvas;
//--- Variables/arrays for copying data from OnCalculate()
int               OC_rates_total     =0; // Size of input time series
int               OC_prev_calculated =0; // Bars processed at the previous call
datetime          OC_time[];             // Opening time
double            OC_open[];             // Open prices
double            OC_high[];             // High prices
double            OC_low[];              // Low prices
double            OC_close[];            // Close prices
long              OC_tick_volume[];      // Tick volumes
long              OC_volume[];           // Real volumes
int               OC_spread[];           // Spread

//--- For the purpose of storing and checking the time of the first bar in the terminal
datetime          series_first_date[SYMBOLS_COUNT];
datetime          series_first_date_last[SYMBOLS_COUNT];
//--- Time array of the bar from which we will start drawing
datetime          limit_time[SYMBOLS_COUNT];
//--- Symbol names array
string            symbol_names[SYMBOLS_COUNT];
//--- Array of symbol inverse flags
bool              inverse[SYMBOLS_COUNT];
//--- Colors of indicator lines
color             line_colors[SYMBOLS_COUNT]={clrDodgerBlue,clrLimeGreen,clrGold,clrAqua,clrMagenta};
//--- String representing the lack of the symbol
string            empty_symbol="EMPTY";
//--- Chart properties
int               window_number              =WRONG_VALUE;               // Indicator window number
int               chart_width                =0;                         // Chart width
int               chart_height               =0;                         // Chart height
int               last_chart_width           =0;                         // Last saved chart width
int               last_chart_height          =0;                         // Last saved chart height
int               chart_center_x             =0;                         // Horizontal center of chart
int               chart_center_y             =0;                         // Vertical center of chart
color             color_bar_up               =clrRed;                    // Up bar color
color             color_bar_down             =C'100,0,0';                // Down bar color
string            indicator_shortname        ="MS_PriceDivergence";      // Short name of the indicator
string            prefix                     =indicator_shortname+"_";   // Prefix for objects
//--- Name of vertical line of the price divergence starting point
string            start_price_divergence=prefix+"start_price_divergence";
//--- Canvas properties
string            canvas_name             =prefix+"canvas";          // Canvas name
color             canvas_background       =clrBlack;                 // Canvas background color
uchar             canvas_opacity          =190;                      // Opacity
int               font_size               =16;                       // Font size
string            font_name               ="Calibri";                // Font
ENUM_COLOR_FORMAT clr_format              =COLOR_FORMAT_ARGB_RAW;    // Color components should be correctly set by the user
//--- Canvas messages
string            msg_prepare_data        ="Preparing data! Please wait...";
string            msg_not_synchronized    ="Unsynchronized data! Please wait...";
string            msg_load_data           ="";
string            msg_sync_update         ="";
string            msg_last                ="";
//---
ENUM_TIMEFRAMES   timeframe_start_point  =Period();    // Timeframe for the price divergence starting point
datetime          first_period_time      =NULL;        // Time of the first specified period on chart
double            divergence_price       =0.0;         // Price of the price divergence starting point
datetime          divergence_time        =NULL;        // Time of the price divergence starting point
double            symbol_difference[SYMBOLS_COUNT];    // Difference in price relative to the current symbol
double            inverse_difference[SYMBOLS_COUNT];   // Difference that is formed when calculating inversion

Ardından, gösterge başlatma sırasında kullanılan işlevleri ele alacağız. Genel olarak, önceki makaledeki OnInit() işleviyle karşılaştırıldığında önemli bir değişiklik yoktur.

İndikatörün kullanıldığı yere kontrol ekleyelim. Mesele şu ki, terminal geliştiricileri grafik özelliklerini kontrol etmenin tüm özelliklerini henüz Strateji Test Cihazına dahil etmedi, bu nedenle göstergemizi yalnızca Strateji Test Cihazı dışında kullanılacak şekilde kısıtlıyoruz. Bunu dahil etmek için basit bir işlev yazacağız - CheckTesterMode(). Checks.mqh dosyasında bulunacak:

//+------------------------------------------------------------------+
//| Checks if indicator is used in Strategy Tester                   |
//+------------------------------------------------------------------+
bool CheckTesterMode()
  {
//--- Report that indicator is not intended to be used in Strategy Tester
   if(MQLInfoInteger(MQL_TESTER) || 
      MQLInfoInteger(MQL_VISUAL_MODE) || 
      MQLInfoInteger(MQL_OPTIMIZATION))
     {
      Comment("Currently, the <- "+MQLInfoString(MQL_PROGRAM_NAME)+" -> indicator is not intended to be used in Strategy Tester!");
      return(false);
     }
//---
   return(true);
  }

Başka bir yeni işlev olan SetBarsColors(), geçerli sembolün çubukları/mum grafikleri için renkleri ayarlamayı amaçlar. Chart.mqh dosyasında bulunur.

//+------------------------------------------------------------------+
//| Sets colors for the current symbol bars                          |
//+------------------------------------------------------------------+
void SetBarsColors()
  {
//--- Color for the up bar, shadows and body borders of bull candlesticks
   ChartSetInteger(0,CHART_COLOR_CHART_UP,color_bar_up);
//--- Body color of a bull candlestick
   ChartSetInteger(0,CHART_COLOR_CANDLE_BULL,color_bar_up);
//--- Line chart color and color of "Doji" Japanese candlesticks
   ChartSetInteger(0,CHART_COLOR_CHART_LINE,color_bar_up);
//--- For two-color mode
   if(TwoColor)
     {
      //--- Color for the down bar, shadows and body borders of bear candlesticks
      ChartSetInteger(0,CHART_COLOR_CHART_DOWN,color_bar_down);
      //--- Body color of a bear candlestick
      ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,color_bar_down);
     }
//--- If two-color mode is turned off
   else
     {
      //--- Color for the down bar, shadows and body borders of bear candlesticks
      ChartSetInteger(0,CHART_COLOR_CHART_DOWN,color_bar_up);
      //--- Body color of a bear candlestick
      ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,color_bar_up);
     }
  }

Başlatma sırasında StartPriceDivergence harici parametresinde hangi modun seçildiğini belirlememiz gerekiyor. Dikey çizgi seçilirse timeframe_start_point global değişkenine varsayılan değer, yani mevcut zaman dilimi atanacaktır. Aksi takdirde seçilen zaman dilimi uygulanacaktır. Bu amaçla InitStartPointTF() işlevini yazalım:

//+------------------------------------------------------------------+
//| Identifies timeframe for the price starting point mode           |
//+------------------------------------------------------------------+
void InitStartPointTF()
  {
//--- Exit if vertical line mode is selected
   if(StartPriceDivergence==VERTICAL_LINE)
      return;
//--- Otherwise define the timeframe
   switch(StartPriceDivergence)
     {
      case MONTH : timeframe_start_point=PERIOD_MN1; break;
      case WEEK  : timeframe_start_point=PERIOD_W1;  break;
      case DAY   : timeframe_start_point=PERIOD_D1;  break;
      case HOUR  : timeframe_start_point=PERIOD_H1;  break;
     }
  }

CheckInputParameters() işlevi, önceki makaledekinden farklı olarak şu anda şöyle görünüyor:

//+------------------------------------------------------------------+
//| Checks input parameters for correctness                          |
//+------------------------------------------------------------------+
bool CheckInputParameters()
  {
//--- For all other modes except the 'Vertical Line'
   if(StartPriceDivergence!=VERTICAL_LINE)
     {
      //--- If the current period is greater than or equal to the specified period of the price divergence starting point, report of it and exit
      if(PeriodSeconds()>=PeriodSeconds(timeframe_start_point))
        {
         Print("Current timeframe should be less than one specified in the Start Price Divergence parameter!");
         Comment("Current timeframe should be less than one specified in the Start Price Divergence parameter!");
         return(false);
        }
     }
//---
   return(true);
  }

Diziler, önceki makaledeki gibi başlatılır. Yalnızca dizilerin adları ve sayısı değiştirilmiştir.

//+------------------------------------------------------------------+
//| First initialization of arrays                                   |
//+------------------------------------------------------------------+
void InitArrays()
  {
   ArrayInitialize(limit_time,NULL);
   ArrayInitialize(symbol_difference,0.0);
   ArrayInitialize(inverse_difference,0.0);
   ArrayInitialize(series_first_date,NULL);
   ArrayInitialize(series_first_date_last,NULL);
//---
   for(int s=0; s<SYMBOLS_COUNT; s++)
     {
      ArrayInitialize(buffer_data[s].open,EMPTY_VALUE);
      ArrayInitialize(buffer_data[s].high,EMPTY_VALUE);
      ArrayInitialize(buffer_data[s].low,EMPTY_VALUE);
      ArrayInitialize(buffer_data[s].close,EMPTY_VALUE);
      ArrayInitialize(buffer_data[s].icolor,EMPTY_VALUE);
     }
  }
//+------------------------------------------------------------------+
//| Initializes array of symbols                                     |
//+------------------------------------------------------------------+
void InitSymbolNames()
  {
   symbol_names[0]=AddSymbolToMarketWatch(Symbol02);
   symbol_names[1]=AddSymbolToMarketWatch(Symbol03);
   symbol_names[2]=AddSymbolToMarketWatch(Symbol04);
   symbol_names[3]=AddSymbolToMarketWatch(Symbol05);
   symbol_names[4]=AddSymbolToMarketWatch(Symbol06);
  }
//+------------------------------------------------------------------+
//| Initializes array of inversions                                  |
//+------------------------------------------------------------------+
void InitInverse()
  {
   inverse[0]=Inverse02;
   inverse[1]=Inverse03;
   inverse[2]=Inverse04;
   inverse[3]=Inverse05;
   inverse[4]=Inverse06;
  }

SetIndicatorProperties() işlevinde önemli değişiklikler yapıldı. Aslında, bu tamamen yeni bir işlevdir. Şimdi, hangi veri oluşturma modunun seçildiğine bağlı olarak, başlatma sırasında ilgili özellikler ayarlanır.

//+------------------------------------------------------------------+
//| Sets indicator properties                                        |
//+------------------------------------------------------------------+
void SetIndicatorProperties()
  {
//--- Set the short name
   IndicatorSetString(INDICATOR_SHORTNAME,indicator_shortname);
//--- Set the number of decimal digits
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
//---  In the 'Line' mode we need only one buffers that displays the open price
   if(DrawType==LINE)
     {
      for(int s=0; s<SYMBOLS_COUNT; s++)
         SetIndexBuffer(s,buffer_data[s].close,INDICATOR_DATA);
     }
//--- In other modes we use all prices for drawing 
//    bars/candlesticks and additional buffer for the two-color mode
   else if(DrawType==BARS || DrawType==CANDLES)
     {
      for(int s=0; s<SYMBOLS_COUNT; s++)
        {
         static int buffer_number=0;
         SetIndexBuffer(buffer_number,buffer_data[s].open,INDICATOR_DATA);
         buffer_number++;
         SetIndexBuffer(buffer_number,buffer_data[s].high,INDICATOR_DATA);
         buffer_number++;
         SetIndexBuffer(buffer_number,buffer_data[s].low,INDICATOR_DATA);
         buffer_number++;
         SetIndexBuffer(buffer_number,buffer_data[s].close,INDICATOR_DATA);
         buffer_number++;
         SetIndexBuffer(buffer_number,buffer_data[s].icolor,INDICATOR_COLOR_INDEX);
         buffer_number++;
        }
     }
//--- Set labels for the current timeframe
//    In the 'Line' mode only opening price is used
   if(DrawType==LINE)
     {
      for(int s=0; s<SYMBOLS_COUNT; s++)
         PlotIndexSetString(s,PLOT_LABEL,symbol_names[s]+",Close");
     }
//--- In other modes all prices of bars/candlesticks
//    ";" is used as a separator
   else if(DrawType==BARS || DrawType==CANDLES)
     {
      for(int s=0; s<SYMBOLS_COUNT; s++)
        {
         PlotIndexSetString(s,PLOT_LABEL,
                            symbol_names[s]+",Open;"+
                            symbol_names[s]+",High;"+
                            symbol_names[s]+",Low;"+
                            symbol_names[s]+",Close");
        }
     }
//--- Set the type of lines for indicator buffers
//--- Line
   if(DrawType==LINE)
      for(int s=0; s<SYMBOLS_COUNT; s++)
         PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_LINE);
//--- Bars
   if(DrawType==BARS)
      for(int s=0; s<SYMBOLS_COUNT; s++)
         PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_COLOR_BARS);
//--- Candlesticks
   if(DrawType==CANDLES)
      for(int s=0; s<SYMBOLS_COUNT; s++)
         PlotIndexSetInteger(s,PLOT_DRAW_TYPE,DRAW_COLOR_CANDLES);

//--- Set the type of lines for data of current symbol
//--- Line
   if(DrawType==LINE)
      ChartSetInteger(0,CHART_MODE,CHART_LINE);
//--- Bars
   if(DrawType==BARS)
      ChartSetInteger(0,CHART_MODE,CHART_BARS);
//--- Candlesticks
   if(DrawType==CANDLES)
      ChartSetInteger(0,CHART_MODE,CHART_CANDLES);

//--- Set the line width
   for(int s=0; s<SYMBOLS_COUNT; s++)
      PlotIndexSetInteger(s,PLOT_LINE_WIDTH,1);
//--- Set the line color for the 'Line' mode
   if(DrawType==LINE)
      for(int s=0; s<SYMBOLS_COUNT; s++)
         PlotIndexSetInteger(s,PLOT_LINE_COLOR,line_colors[s]);
//--- Display data in Data Window only for existing symbols
   for(int s=0; s<SYMBOLS_COUNT; s++)
     {
      if(symbol_names[s]!=empty_symbol)
         PlotIndexSetInteger(s,PLOT_SHOW_DATA,true);
      else
         PlotIndexSetInteger(s,PLOT_SHOW_DATA,false);
     }
//--- Empty value for plotting where nothing will be drawn
   for(int s=0; s<SYMBOLS_COUNT; s++)
      PlotIndexSetDouble(s,PLOT_EMPTY_VALUE,EMPTY_VALUE);
  }

Son olarak, OnInit() içinde kullanılacak yeni bir işlev SetDivergenceLine(). Dikey çizgi modunda fiyat farklılık başlangıç noktasını değiştirmek için dikey yeşil çizgiyi ayarlar.

//+------------------------------------------------------------------+
//| Sets vertical line for price divergence starting point           |
//+------------------------------------------------------------------+
void SetDivergenceLine()
  {
//--- If there is no vertical line yet, set it
   if(StartPriceDivergence==VERTICAL_LINE && ObjectFind(0,start_price_divergence)<0)
      //--- Place a vertical line on the true bar
      CreateVerticalLine(0,0,TimeCurrent()+PeriodSeconds(),start_price_divergence,
                         2,STYLE_SOLID,clrGreenYellow,true,true,false,"","\n");
//--- For all other modes except the 'Vertical Line'
   if(StartPriceDivergence!=VERTICAL_LINE)
      DeleteObjectByName(start_price_divergence);
  }

Aşağıda, yukarıda açıklanan her şeyin OnInit() işlevi içinde temsili yer almaktadır. Her şey ayrı işlevlere ve dosyalara bölündüğünde, program kodunu okumak çok pratik hale gelir.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- Check if indicator is currently being used in Strategy Tester
   if(!CheckTesterMode())
      return(INIT_FAILED);
//--- Set the color for bars/candlesticks
   SetBarsColors();
//--- Define the timeframe for the price divergence starting point
   InitStartPointTF();
//--- Check input parameters for correctness
   if(!CheckInputParameters())
      return(INIT_PARAMETERS_INCORRECT);
//--- Set the timer at 1-second intervals
   EventSetMillisecondTimer(1000);
//--- Set the font to be displayed on the canvas
   canvas.FontSet(font_name,font_size,FW_NORMAL);
//--- Initialization of arrays
   InitArrays();
//--- Initialize the array of symbols 
   InitSymbolNames();
//--- Initialize the array of inversions
   InitInverse();
//--- Set indicator properties
   SetIndicatorProperties();
//--- Set vertical line of the price divergence start
   SetDivergenceLine();
//--- Clear the comment
   Comment("");
//--- Refresh the chart
   ChartRedraw();
//--- Initialization completed successfully
   return(INIT_SUCCEEDED);
  }

OnCalculate() işlevinde, program kodu hemen hemen değişmeden kaldı. Önceki makalede, verilerin kullanılabilirliği ile ilgili tüm kontroller yapıldıktan sonra, program önce yardımcı dizileri doldurdu ve ancak bundan sonra gösterge arabelleklerini hazırlanan verilerle doldurdu. Bu sefer her şeyi tek bir döngüde düzenlemeye çalışacağız.

Verileri doğrulama ve yükleme işlevlerini daha katı hale getirdim. Artık almak istediğiniz her değer belirtilen sayıda denemeden geçer. Değer elde edilirse döngü durdurulur. Artık bir dönemin başlangıcını (ay, hafta, gün, saat) belirlememiz gereken modlarımız olduğu için, o zaman döneminin başlangıç zamanını daha yüksek zaman dilimi aracılığıyla alacağız. Bu nedenle, benzer bir LoadAndFormDataHighTF() işlevine benzer bir isme sahip LoadAndFormData() işlevine benzer bir ek işlev oluşturdum. Kodu orijinaline çok benziyor, bu yüzden burada yayınlamayacağım.

Mevcut ve daha yüksek zaman dilimleri için veri kullanılabilirliğinin doğrulanması tek bir işlevde uygulandı CheckAvailableData():

//+------------------------------------------------------------------+
//| Checks the amount of available data for all symbols              |
//+------------------------------------------------------------------+
bool CheckAvailableData()
  {
   int attempts=100;
   
//---
   for(int s=0; s<SYMBOLS_COUNT; s++)
     {
      //--- If this symbol is available
      if(symbol_names[s]!=empty_symbol)
        {
datetime time[];                    // Array for checking the number of bars
   int      total_period_bars   =0;    // Number of bars of the current period
   datetime terminal_first_date =NULL; // First date of the current time frame data available in the terminal
         //--- Get the first date of the current time frame data in the terminal
         terminal_first_date=(datetime)SeriesInfoInteger(symbol_names[s],Period(),SERIES_TERMINAL_FIRSTDATE);
         //--- Get the number of available bars from the date specified
         total_period_bars=Bars(symbol_names[s],Period(),terminal_first_date,TimeCurrent());
         //--- Check the readiness of bar data
         for(int i=0; i<attempts; i++)
           {
            //--- Copy the specified amount of data
            if(CopyTime(symbol_names[s],Period(),0,total_period_bars,time))
              {
               //--- If the required amount has been copied, terminate the loop
               if(ArraySize(time)>=total_period_bars)
                  break;
              }
           }
         //--- If the amount of data copied is not sufficient, one more attempt is required
         if(ArraySize(time)==0 || ArraySize(time)<total_period_bars)
           {
            msg_last=msg_prepare_data;
            ShowCanvasMessage(msg_prepare_data);
            OC_prev_calculated=0;
            return(false);
           }
        }
     }
//--- Exit if current mode is vertical line of the price divergence starting point
   if(StartPriceDivergence==VERTICAL_LINE)
      return(true);
   else
     {
      datetime time[];                    // Array for checking the number of bars
      int      total_period_bars   =0;    // Number of bars of the current period
      datetime terminal_first_date =NULL; // First date of the current time frame data available in the terminal
      //--- Get the first date of the current time frame data in the terminal
      for(int i=0; i<attempts; i++)
         if((terminal_first_date=(datetime)SeriesInfoInteger(Symbol(),Period(),SERIES_FIRSTDATE))>0)
            break;
      //--- Get the number of available bars from the date specified
      for(int i=0; i<attempts; i++)
         if((total_period_bars=(int)SeriesInfoInteger(Symbol(),timeframe_start_point,SERIES_BARS_COUNT))>0)
            break;
      //--- Check the readiness of bar data
      for(int i=0; i<attempts; i++)
         //--- Copy the specified amount of data
         if(CopyTime(Symbol(),timeframe_start_point,
            terminal_first_date+PeriodSeconds(timeframe_start_point),TimeCurrent(),time)>0)
            break;
      //--- If the amount of data copied is not sufficient, one more attempt is required
      if(ArraySize(time)<=0 || total_period_bars<=0)
        {
         msg_last=msg_prepare_data;
         ShowCanvasMessage(msg_prepare_data);
         OC_prev_calculated=0;
         return(false);
        }
     }
//---
   return(true);
  }

FillIndicatorBuffers() işlevi, mevcut görev için önemli ölçüde karmaşıktır. Bunun nedeni, şimdi birkaç modun olması ve her birinin kendi eylemlerini gerektirmesidir. Aslında, her şey dört adıma ayrılabilir.

  • Belirtilen sembol için veri alınıyor.
  • Daha yüksek zaman dilimi için veri almak ve tüm sembollerin fiyatlarının buluştuğu zaman ve fiyat seviyesini belirlemek.
  • Değerlerin hesaplanması ve gösterge arabelleğinin doldurulması.
  • Hesaplanan değerlerin doğrulanması.

İşlev kodu, değerlendirmeniz için ayrıntılı yorumlarla birlikte verilir:

//+------------------------------------------------------------------+
//| Fills indicator buffers                                          |
//+------------------------------------------------------------------+
void FillIndicatorBuffers(int i,int s,datetime const &time[])
  {
   MqlRates    rates[];             // Data structure
   double      period_open[];       // Opening price for bar at the price divergence starting point
   datetime    period_time[];       // Time of the price divergence starting point
   int         attempts=100;        // Number of copying attempts
   datetime    high_tf_time=NULL;   // Time of higher timeframe's bar

//--- Exit if we are out of "true" bars zone
   if(time[i]<limit_time[s])
      return;
//--- Reset the last error
   ResetLastError();
//--- Get data of current bar for the specified symbol
   for(int j=0; j<attempts; j++)
      if(CopyRates(symbol_names[s],Period(),time[i],1,rates)==1)
        { ResetLastError(); break; }
//--- Exit if failed to get data
   if(ArraySize(rates)<1 || GetLastError()!=0)
      return;
//--- If the current time is before the first timeframe's time or
//    bar time is not equal to the bar time of the current symbol or
//    empty values are fetched
   if(rates[0].time==NULL || 
      time[i]!=rates[0].time || 
      time[i]<first_period_time || 
      rates[0].low==EMPTY_VALUE || 
      rates[0].open==EMPTY_VALUE ||
      rates[0].high==EMPTY_VALUE ||
      rates[0].close==EMPTY_VALUE)
     {
      //--- Write empty value
      if(DrawType!=LINE)
        {
         buffer_data[s].low[i]   =EMPTY_VALUE;
         buffer_data[s].open[i]  =EMPTY_VALUE;
         buffer_data[s].high[i]  =EMPTY_VALUE;
        }
      buffer_data[s].close[i]=EMPTY_VALUE;
      return;
     }
//--- If current mode is vertical line of the price divergence starting point
   if(StartPriceDivergence==VERTICAL_LINE)
     {
      //--- Get the time of the line
      divergence_time=(datetime)ObjectGetInteger(0,start_price_divergence,OBJPROP_TIME);
      //--- Get the time of the first bar
      first_period_time=time[0];
     }
//--- For all other modes, we will keep track the beginning of period
   else
     {
      //--- If we are here for the first time, store data of the first bar of higher timeframe
      if(divergence_time==NULL)
        {
         ResetLastError();
         //--- Get opening time of the first bar of higher timeframe
         for(int j=0; j<attempts; j++)
            if(CopyTime(Symbol(),timeframe_start_point,time[0]+PeriodSeconds(timeframe_start_point),1,period_time)==1)
              { ResetLastError(); break; }
         //--- Exit if failed to get price/time
         if(ArraySize(period_time)<1 || GetLastError()!=0)
            return;
         //--- Otherwise store time of the first bar of higher timeframe
         else
            first_period_time=period_time[0];
        }
      //--- If current bar's time on the current timeframe is before the first bar's time on higher timeframe
      if(time[i]<first_period_time)
         high_tf_time=first_period_time;
      //--- Otherwise we will receive data of the last bar of the higher timeframe with respect to the current bar on the current timeframe
      else
         high_tf_time=time[i];
      //--- Reset the last error
      ResetLastError();
      //--- Get the opening price of the first bar of the higher timeframe
      for(int j=0; j<attempts; j++)
         if(CopyOpen(Symbol(),timeframe_start_point,high_tf_time,1,period_open)==1)
           { ResetLastError(); break; }
      //--- Get opening time of the first bar of higher timeframe
      for(int j=0; j<attempts; j++)
         if(CopyTime(Symbol(),timeframe_start_point,high_tf_time,1,period_time)==1)
           { ResetLastError(); break; }
      //--- Exit if failed to get price/time
      if(ArraySize(period_open)<1 || ArraySize(period_time)<1 || GetLastError()!=0)
         return;
      //--- If the current timeframe's time is before the first period's time or
      //    time of specified period is not equal to the one in memory
      if(time[i]<first_period_time || divergence_time!=period_time[0])
        {
         symbol_difference[s]  =0.0; // Zero out difference in symbol prices
         inverse_difference[s] =0.0; // Zero our difference of inversion
         //--- Store time of the price divergence starting point
         divergence_time=period_time[0];
         //--- Store price of the price divergence starting point
         divergence_price=period_open[0];
         //--- Set vertical line in the beginning of the price divergence start
         CreateVerticalLine(0,0,period_time[0],start_price_divergence+"_"+TimeToString(divergence_time),
                            2,STYLE_SOLID,clrWhite,false,false,true,TimeToString(divergence_time),"\n");
        }
     }
//--- If current mode is 'Vertical Line' and bar's time is less than line's time
   if(StartPriceDivergence==VERTICAL_LINE && time[i]<divergence_time)
     {
      //--- Keep zero values of difference
      symbol_difference[s]  =0.0;
      inverse_difference[s] =0.0;
      //--- For the 'Line' drawing mode only opening price is used
      if(DrawType==LINE)
         buffer_data[s].close[i]=rates[0].close-symbol_difference[s];
      //--- For all other modes all prices are used
      else
        {
         buffer_data[s].low[i]   =rates[0].low-symbol_difference[s];
         buffer_data[s].open[i]  =rates[0].open-symbol_difference[s];
         buffer_data[s].high[i]  =rates[0].high-symbol_difference[s];
         buffer_data[s].close[i] =rates[0].close-symbol_difference[s];
         //--- Set color for the current element of indicator buffer
         SetBufferColorIndex(i,s,rates[0].close,rates[0].open);
        }
     }
//--- For all other modes
   else
     {
      //--- If inversion of symbol data is required
      if(inverse[s])
        {
         //--- If new period has started, recalculate variables
         if(symbol_difference[s]==0.0)
           {
            //--- For the 'Vertical Line' mode
            if(StartPriceDivergence==VERTICAL_LINE)
              {
               //--- Calculate the difference
               symbol_difference[s]  =rates[0].open-OC_open[i];
               inverse_difference[s] =OC_open[i]-(-OC_open[i]);
              }
            //--- For all other modes
            else
              {
               //--- Calculate the difference
               symbol_difference[s]  =rates[0].open-divergence_price;
               inverse_difference[s] =divergence_price-(-divergence_price);
              }
           }
         //--- In the 'Line' mode only opening price is used
         if(DrawType==LINE)
            buffer_data[s].close[i]=-(rates[0].close-symbol_difference[s])+inverse_difference[s];
         //--- For all other modes all prices are used
         else
           {
            buffer_data[s].low[i]   =-(rates[0].low-symbol_difference[s])+inverse_difference[s];
            buffer_data[s].open[i]  =-(rates[0].open-symbol_difference[s])+inverse_difference[s];
            buffer_data[s].high[i]  =-(rates[0].high-symbol_difference[s])+inverse_difference[s];
            buffer_data[s].close[i] =-(rates[0].close-symbol_difference[s])+inverse_difference[s];
            //--- Set color for the current element of indicator buffer
            SetBufferColorIndex(i,s,rates[0].close,rates[0].open);
           }
        }
      //--- If inversion is not used, then we need to calculate only the difference between symbol prices at the beginning of period
      else
        {
         //--- If new period has started
         if(symbol_difference[s]==0.0)
           {
            //--- For the 'Vertical Line' mode
            if(StartPriceDivergence==VERTICAL_LINE)
               symbol_difference[s]=rates[0].open-OC_open[i];
            //--- For all other modes
            else
               symbol_difference[s]=rates[0].open-divergence_price;
           }
         //--- For the 'Line' drawing mode only opening price is used
         if(DrawType==LINE)
            buffer_data[s].close[i]=rates[0].close-symbol_difference[s];
         //--- For all other modes all prices are used
         else
           {
            buffer_data[s].low[i]   =rates[0].low-symbol_difference[s];
            buffer_data[s].open[i]  =rates[0].open-symbol_difference[s];
            buffer_data[s].high[i]  =rates[0].high-symbol_difference[s];
            buffer_data[s].close[i] =rates[0].close-symbol_difference[s];
            //--- Set color for the current element of indicator buffer
            SetBufferColorIndex(i,s,rates[0].close,rates[0].open);
           }
        }
     }
//--- Verification of the calculated values
//    In the 'Line' mode only opening price is used
   if(DrawType==LINE)
     {
      //--- If the current time is before the first timeframe's time or
      //    bar time is not equal to the bar time, write empty value
      if(time[i]!=rates[0].time || time[i]<first_period_time)
         buffer_data[s].close[i]=EMPTY_VALUE;
     }
//--- For all other modes all prices are used
   else
     {
      //--- If the current time is before the first timeframe's time or
      //    bar time is not equal to the bar time of the current symbol or
      //    empty values are fetched
      if(rates[0].time==NULL || 
         time[i]!=rates[0].time || 
         time[i]<first_period_time || 
         rates[0].low==EMPTY_VALUE || 
         rates[0].open==EMPTY_VALUE ||
         rates[0].high==EMPTY_VALUE ||
         rates[0].close==EMPTY_VALUE)
        {
         //--- Write empty value
         buffer_data[s].low[i]   =EMPTY_VALUE;
         buffer_data[s].open[i]  =EMPTY_VALUE;
         buffer_data[s].high[i]  =EMPTY_VALUE;
         buffer_data[s].close[i] =EMPTY_VALUE;
        }
     }
  }

Yukarıdaki işlevi incelerken başka bir SetBufferColorIndex() özel işlevine dikkat etmelisiniz. Bu işlev, gösterge renk arabelleğindeki rengi ayarlar.

//+------------------------------------------------------------------+
//| Sets the color for buffer element by condition                   |
//+------------------------------------------------------------------+
void SetBufferColorIndex(int i,int symbol_number,double close,double open)
  {
//--- For two-color mode, check condition
   if(TwoColor)
     {
      //--- If the closing price is more than the opening price, this is up bar, so we use the first color
      if(close>open)
         buffer_data[symbol_number].icolor[i]=0;
      //--- otherwise it is down bar, so we use the second color
      else
         buffer_data[symbol_number].icolor[i]=1;
     }
//--- For one-color mode we use the first color for all bars/candlesticks
   else
      buffer_data[symbol_number].icolor[i]=0;
  }

Gösterge arabellekleri doldurulduktan sonra, grafik penceresinde şu anda görünen tüm değerlerden maksimum ve minimumu belirlememiz gerekir. MQL5, bir grafik penceresindeki ilk görünür çubuğu ve görünür çubuk sayısını almayı sağlar. Bu özelliklerden başka bir CorrectChartMaxMin() özel işlevden yararlanacağız. İşlevdeki kod akışı birkaç adıma ayrılabilir:

  • İlk ve son görünen çubukların numaralarının belirlenmesi.
  • Mevcut sembol için maksimum ve minimum görünür çubukların belirlenmesi.
  • Tüm sembol dizileri arasında maksimum ve minimumun belirlenmesi.
  • Grafik özelliklerinde maksimum ve minimumu ayarlama.

Chart.mqh dosyasında bulunan CorrectChartMaxMin() işlevinin kodu aşağıdadır.

//+------------------------------------------------------------------+
//| Corrects chart's high/low with respect to all buffers            |
//+------------------------------------------------------------------+
void CorrectChartMaxMin()
  {
   double low[];                  // Array of lows
   double high[];                 // Array of highs
   int    attempts          =10;  // Number of attempts
   int    array_size        =0;   // Array size for drawing
   int    visible_bars      =0;   // Number of visible bars
   int    first_visible_bar =0;   // Number of the first visible bar
   int    last_visible_bar  =0;   // Number of the last visible bar
   double max_price         =0.0; // Highest price
   double min_price         =0.0; // Lowest price
   double offset_max_min    =0.0; // Offset from chart's high/low
//--- Reset the last error
   ResetLastError();
//--- Number of visible bars
   visible_bars=(int)ChartGetInteger(0,CHART_VISIBLE_BARS);
//--- Number of the first visible bar
   first_visible_bar=(int)ChartGetInteger(0,CHART_FIRST_VISIBLE_BAR);
//--- Number of the last visible bar
   last_visible_bar=first_visible_bar-visible_bars;
//--- Exit in case of error
   if(GetLastError()!=0)
      return;
//--- Fix incorrect value
   if(last_visible_bar<0)
      last_visible_bar=0;
//--- Get the current symbol high/low in visible area of chart
   for(int i=0; i<attempts; i++)
      if(CopyHigh(Symbol(),Period(),last_visible_bar,visible_bars,high)==visible_bars)
         break;
   for(int i=0; i<attempts; i++)
      if(CopyLow(Symbol(),Period(),last_visible_bar,visible_bars,low)==visible_bars)
         break;
//--- Exit if failed to get data
   if(ArraySize(high)<=0 || ArraySize(low)<=0)
      return;
//--- If succeeded to get data, identify high and low in the current symbol arrays
   else
     {
      min_price=low[ArrayMinimum(low)];
      max_price=high[ArrayMaximum(high)];
     }
//--- Get high and low prices in all price arrays
   for(int s=0; s<SYMBOLS_COUNT; s++)
     {
      //--- If current symbol is not present, go to the next one
      if(symbol_names[s]==empty_symbol)
         continue;
      //---
      datetime time[];         // Time array
      int      bars_count=0; // Number of bars for calculation
      //--- Set zero size for arrays
      ArrayResize(high,0);
      ArrayResize(low,0);
      //--- Get the time of the first bar visible on chart
      for(int i=0; i<attempts; i++)
         if(CopyTime(Symbol(),Period(),last_visible_bar,visible_bars,time)==visible_bars)
            break;
      //--- Exit if the amount of data is less than number of visible bars on chart
      if(ArraySize(time)<visible_bars)
         return;
      //--- If time of the first "true" bar is greater than
      //    time of the first visible bar on the chart, then
      //    get available number of bars of the current symbol in loop
      if(limit_time[s]>time[0])
        {
         //--- Get the array size
         array_size=ArraySize(time);
         //--- Get the number of bars from the first "true" one
         if((bars_count=Bars(Symbol(),Period(),limit_time[s],time[array_size-1]))<=0)
            return;
        }
      //--- Else get number of visible bars on chart
      else
         bars_count=visible_bars;
      //--- Index elements in indicator buffers as timeseries
      ArraySetAsSeries(low,true);
      ArraySetAsSeries(high,true);
      //--- Copy data from the indicator buffer
      //    All modes except 'Line'
      if(DrawType!=LINE)
        {
         ArrayCopy(low,buffer_data[s].low);
         ArrayCopy(high,buffer_data[s].high);
        }
      //--- For the 'Line' mode
      else
        {
         ArrayCopy(low,buffer_data[s].close);
         ArrayCopy(high,buffer_data[s].close);
        }
      //--- Get the array size
      array_size=ArraySize(high);
      //--- Fill empty values,
      //    so they are not considered when calculating high/low
      for(int i=0; i<array_size; i++)
        {
         if(high[i]==EMPTY_VALUE)
            high[i]=max_price;
         if(low[i]==EMPTY_VALUE)
            low[i]=min_price;
        }
      //--- Get high/low with respect to inversion
      if(inverse[s])
        {
         //--- If no errors occur, store values
         if(ArrayMaximum(high,last_visible_bar,bars_count)>=0 && 
            ArrayMinimum(low,last_visible_bar,bars_count)>=0)
           {
            max_price=fmax(max_price,low[ArrayMaximum(low,last_visible_bar,bars_count)]);
            min_price=fmin(min_price,high[ArrayMinimum(high,last_visible_bar,bars_count)]);
           }
        }
      else
        {
         //--- If no errors occur, store values
         if(ArrayMinimum(low,last_visible_bar,bars_count)>=0 && 
            ArrayMaximum(high,last_visible_bar,bars_count)>=0)
           {
            min_price=fmin(min_price,low[ArrayMinimum(low,last_visible_bar,bars_count)]);
            max_price=fmax(max_price,high[ArrayMaximum(high,last_visible_bar,bars_count)]);
           }
        }
     }
//--- Calculate offset (3%) form chart's top and bottom
   offset_max_min=((max_price-min_price)*3)/100;
//--- Turn on the fixed chart scale mode.
   ChartSetInteger(0,CHART_SCALEFIX,true);
//--- Set high/low
   ChartSetDouble(0,CHART_FIXED_MAX,max_price+offset_max_min);
   ChartSetDouble(0,CHART_FIXED_MIN,min_price-offset_max_min);
//--- Refresh the chart
   ChartRedraw();
  }

Yukarıda açıklanan işlev, dikey çizgiyi sürükleme olayı işlenirken (ve elbette OnCalculate içindeki gösterge değerleri hesaplanırken) kullanılacaktır:

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//--- Event of dragging a graphical object
   if(id==CHARTEVENT_OBJECT_DRAG)
     {
      //--- If current mode is vertical line for the price divergence starting point, then update indicator buffers
      if(StartPriceDivergence==VERTICAL_LINE)
         OnCalculate(OC_rates_total,
                     0,
                     OC_time,
                     OC_open,
                     OC_high,
                     OC_low,
                     OC_close,
                     OC_tick_volume,
                     OC_volume,
                     OC_spread);
     }
//--- Event of resizing the chart or modifying the chart properties using the properties dialog window.
   if(id==CHARTEVENT_CHART_CHANGE)
      //--- Correct the maximum and minimum of chart with respect to the indicator buffers' values
      CorrectChartMaxMin();
  }

Tüm fonksiyonlar hazır. Bu makaleye tüm yorumlarıyla beraber eklenmiş kodu inceleyebilirsiniz.

Neticede ne elde ettiğimizi gösterelim. Varsayılan GBPUSD, AUDUSD, NZDUSD, USDCAD, USDCHF sembolleri harici parametrelerde belirtilir. Aşağıdaki ekran görüntüsünde, ters çevirme devre dışı bırakılmış Dikey çizgi modunda EURUSD için haftalık grafiği görebilirsiniz:

"Dikey çizgi" modunda haftalık zaman dilimi

Şek. 1 - "Dikey çizgi" modunda haftalık zaman dilimi

Aşağıdaki ekran görüntüsünde Gün modunda M30 zaman dilimini görebilirsiniz ancak bu sefer temel para birimi olarak USD olan semboller için tersine çevirme etkinleştirilmiştir. Bizim durumumuzda bunlar USDCAD (açık mavi mum grafikler) ve USDCHF (mor mum grafikler).

"Gün" modunda M30 zaman dilimi

Şek. 2 - "Gün" modunda M30 zaman dilimi


Sonuç

Fiyat farklılığının çoklu para birimi analizi için oldukça ilginç ve bilgilendirici bir araç oluşturduğumuzu düşünüyorum. Bu gösterge sonsuza kadar geliştirilebilir.

Zaman ayırdığınız için teşekkür ederim!

MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/754

Ekli dosyalar |
MQL5 Yemek Kitabı - Çok Para Birimli Expert Advisor ve MQL5'te Bekleyen Talimatlarla Çalışma MQL5 Yemek Kitabı - Çok Para Birimli Expert Advisor ve MQL5'te Bekleyen Talimatlarla Çalışma
Bu sefer, bekleyen Satın Al Durdur ve Sat Durdur talimatlarıyla çalışmayı temel alan bir alım satım algoritmasına sahip çok para birimli bir Expert Advisor oluşturacağız. Bu makale şu konuları ele almaktadır: belirli bir zaman aralığında alım satım yapma, bekleyen talimatları verme/değiştirme/silme, son pozisyonun Kar Al veya Zarar Durdur'da kapatılıp kapatılmadığını kontrol etme ve her bir sembol için yatırım geçmişinin kontrolü.
MQL5 Programlama Temelleri: Listeler MQL5 Programlama Temelleri: Listeler
Alım satım stratejisi geliştirme için programlama dilinin yeni sürümü olan MQL [MQL5], önceki versiyona [MQL4] kıyasla daha güçlü ve etkili özellikler sunar. Avantaj, esasen nesne yönelimli programlama özelliklerinde yatmaktadır. Bu makale, düğümler ve listeler gibi karmaşık özel veri türleri kullanma olasılığını inceler. Ayrıca MQL5'te pratik programlamada listelerin kullanımına bir örnek sağlar.
Renko grafiği için gösterge Renko grafiği için gösterge
Makale, Renko grafiğinin bir örneğini ve bunun bir gösterge olarak MQL5'teki uygulamasını açıklamaktadır. Bu göstergenin modifikasyonları, onu klasik bir grafikten ayırır. Hem gösterge penceresinde hem de ana grafikte oluşturulabilir. Üstelik ZigZag göstergesi var. Grafik uygulamasının birkaç örneğini bulabilirsiniz.
Ekonometrik EURUSD Bir Adım İlerisi Tahmini Ekonometrik EURUSD Bir Adım İlerisi Tahmini
Makale, EViews yazılımının kullanılması ile, EURUSD için bir adım ilerisi tahminine ve EViews'teki programları kullanarak tahmin sonuçlarının daha fazla değerlendirilmesine odaklanır. Tahmin, regresyon modellerini içerir ve MetaTrader 4 için geliştirilmiş bir Uzman Danışman aracılığıyla değerlendirilir.