English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Nokta ve Şekil Grafiği Oluşturma için Gösterge

Nokta ve Şekil Grafiği Oluşturma için Gösterge

MetaTrader 5Örnekler | 13 Ocak 2022, 09:44
432 0
Dmitriy Zabudskiy
Dmitriy Zabudskiy

Giriş

Mevcut piyasa durumuna dair bilgi sağlayan birçok grafik türü vardır. Bunlardan birçoğu, örneğin Nokta ve Şekil grafiği, uzak geçmişten mirastır.

Bu grafik türü XIX. yüzyılın sonundan beri bilinmektedir. İlk olarak 20 Temmuz 1901'de yazılan Wall Street Journal baş makalesinde, bunu "kitap" yöntemi olarak etiketleyen Charles Dow tarafından bahsedilmiştir. Ve "kitap" yöntemine ta 1886 yılına kadar atıfta bulunulsa da, Dow bugüne kadar bunun kullanımını resmi olarak belirleyen ilk kişiydi.

Dow bu yöntemi sadece baş makalelerde açıklamasına rağmen artık bu yöntemin ayrıntılarını sağlayan birçok kitap bulabilirsiniz. Acemi yatırımcılara tavsiye edebileceğim kitaplardan biri Thomas J. Dorsey'e ait şu kitaptır: "Point and Figure Charting: The Essential Application for Forecasting and Tracking Market Prices".

 

Açıklama

Nokta ve Şekil grafiği dikey sütunların bir kümesidir: X'lerin sütunları yükselen fiyatlardır ve O'ların sütunları ise düşen fiyatlardır. Bu, zamana değil, fiyat hareketi temelli olarak çizildiğinden benzersizdir. Dolayısıyla, grafik verilerinden bir değerin (zaman) çıkarılmasının ardından, 45 derecelik bir açı ile çizilmiş trend çizgilerine sahip grafikleri elde ederiz.

Nokta ve Şekil grafikleri iki önceden tanımlanmış değer kullanılarak çizilir:

  • Kutu Boyutu, bir X veya bir O eklemek için gereken fiyat hareketi miktarıdır (orijinal olarak değer, hisse başına dolar miktarı olarak ifade edilmiştir, ancak zaman içinde şu anda göstergemizde kullandığımız noktalar haline gelmiştir).
  • Ters Çevirme Miktarı, sütunları X'lerden O'lara veya bunun tam tersi şekilde değiştirmek için gereken Kutu Boyutu birimleri cinsinden ifade edilen fiyat ters çevirme miktarıdır (örneğin, 3 olan bir ters çevirme miktarı ve 10 noktalık bir kutu boyutu 30 noktaya karşılık gelecektir).

Böylece, bir başlangıç noktası seçeriz ve fiyat artışı için bir X ve düşüşü için bir O koyarız, bunun koşulu fiyatın Ters Çevirme Miktarı ile çarpılan Kutu Boyutuna eşit değer ile değiştirilmiş olmasıdır. Ayrıca, fiyat Kutu Boyutu kadar değişerek aynı yönde hareket etmeye devam ederse, sırasıyla bir artış için X sütununun üstüne bir X veya bir düşüş için O sütununun altına bir O ekleriz. Fiyat, Ters Çevirme Miktarı ile çarpılan Kutu Boyutu değeri ile zıt yönde hareket etmişse, fiyattaki bir artış için bir X veya fiyattaki bir düşüş için bir O koyarız, böylece sırasıyla X'lerin yeni bir sütununu veya O'ların yeni bir sütununu başlatırız.

Kolaylık açısından, Nokta ve Şekil grafiği genellikle damalı bir kağıda çizilir. Daha iyi anlamak için, Nokta ve Şekil grafiğinin küçük bir örneğini inceleyelim. Aşağıdaki verilere sahip olduğumuzu varsayalım:

Tarih Yüksek fiyat Düşük fiyat
07.03.2013 12:00 - 07.03.2013 20:00 1,3117 1,2989
07.03.2013 20:00 - 08.03.2013 04:00 1,3118 1,3093
08.03.2013 04:00 - 08.03.2013 12:00 1,3101 1,3080
08.03.2013 12:00 - 08.03.2013 20:00 1,3134 1,2955

Nokta ve Şekil grafiğini, Kutu Boyutunun 10'a eşit olduğunu ve Ters Çevirme Miktarının 3'e eşit olduğunu düşünerek çizeceğiz:

  • İlk başta, fiyatta 1,2989'dan 1,3117'ye 128 puanlık bir artış görüyoruz, bu nedenle 12 X çiziyoruz.
  • Daha sonra fiyat, 1,3118'den 1,3093'e 25 puan düşüyor, ki bu ters çevirme için yeterli değil, bu yüzden bunu bu şekilde bırakıyoruz.
  • Ayrıca fiyatın 1,3080'e kadar düşmeye devam ettiğini görebiliyoruz. 1,3118'lik önceki değer göz önüne alındığında, şimdi 38 puanlık değişiklik oldu, bu nedenle iki O ekleyerek yeni bir sütun başlatabiliriz (fiyat hareketi üç Kutu Boyutu değerini aşmasına rağmen sonraki O'lar sütunu her zaman bir Kutu Boyutu daha düşük başladığı için sadece iki O koyarız).
  • Fiyat daha sonra 54 puan artarak 1,3080'den 1,3134'e yükseliyor ve ardından 1,2955'e 179 puan düşüyor. Dolayısıyla, bir sonraki sütun dört X'den oluşuyor ve bunu 16 O'dan oluşan bir O sütunu izliyor.

Aşağıda bunun nasıl gösterildiğine bakalım:

Şekil 1. Japon mum grafiği (sol) ve Nokta ve Şekil grafiği (sağ).

Şekil 1. Japon mum grafiği (sol) ve Nokta ve Şekil grafiği (sağ).

Yukarıdaki Nokta ve Şekil grafiği örneği oldukça kaba taslaktır ve burada yeni başlayanların konsepti daha iyi anlamalarına yardımcı olmak için sağlanmıştır.

 

Grafik Oluşturma İlkesi

Birkaç Nokta ve Şekil grafik tekniği vardır ve bunlardan biri halihazırda yukarıda açıklanmıştır. Bu grafik oluşturma teknikleri kullandıkları veriler bakımından farklılık gösterir. Örneğin, gün içi hareketleri dikkate almadan günlük verileri kullanabiliriz, bu nedenle üstünkörü bir çizim elde edebiliriz. Ya da daha ayrıntılı ve düzgün bir çizim elde etmek için gün içi fiyat hareketi verilerini de değerlendirebiliriz.

Daha düzgün ve daha doğru bir Nokta ve Şekil grafiği elde etmek için, bir dakikadaki fiyat hareketi çok anlamlı olmadığından ve genel olarak iki veya üç nokta nadir olmamak üzere altı noktaya kadar olduğundan hesaplamalar ve grafik oluşturma için dakikalık veriler kullanılmasına karar verilmiştir. Bu nedenle, her dakika çubuğundaki açılış fiyatı verilerini kullanacağız.

Grafik oluşturma ilkesi oldukça basittir:

  • Bir başlangıç noktası, diğer bir deyişle ilk dakika çubuğunun açılış fiyatını, alıyoruz.
  • Ayrıca, fiyat Ters Çevirme Miktarı ile çarpılan Kutu Boyutuna eşit mesafe kadar veya bundan daha fazla hareket ederse, ilgili sembolleri (aşağı yönlü hareket için O'lar ve yukarı yönlü hareket için X'ler) çiziyoruz. Son sembol fiyatındaki veriler daha sonraki grafikler için saklanır.
  • Fiyatın aynı yönde Kutu Boyutu kadar hareket etmesi durumunda, karşılık gelen bir sembol çizilir.
  • Ayrıca, fiyatın tersine dönmesi durumunda, hesaplama bu çiftin en yüksek fiyatı yerine son sembolün fiyatına göre yapılacaktır. Diğer bir deyişle, Kutu Boyutunun %50'sinden daha fazla değilse fiyat hareketi göz ardı edilir.

Şimdi Nokta ve Şekil grafik oluşturma stilini belirleyelim. MQL5 dili yedi gösterge çizim stilini destekler: çizgi, bölüm (segment), histogram, ok (sembol), doldurulan alan (doldurulan kanal), çubuklar ve Japon mumları.

Oklar (semboller), ideal görsel temsil için mükemmeldir; ancak bu stil değişen sayıda gösterge tamponu (bu da MQL5'te desteklenmemektedir) veya bir sütunda her bir X veya bir O çizilmesinin ayrı bir gösterge tamponu gerektirmesinden dolayı bunların devasa sayısını gerektirmektedir. Bu ise, bu stili kullanmaya karar vermeniz durumunda, volatilite tanımlamanız ve yeterli bellek kaynağına sahip olmanız gerektiği anlamına gelir.

Bu nedenle, grafik oluşturma stili olarak Japon mumları, daha özel olarak renkli Japon mumları kullanmaya karar verdik. X sütunlarını O'ların sütunlarından ayırt etmek için farklı renklerin kullanılması gerekir. Bu nedenle, göstergede yalnızca kullanılabilir kaynakların verimli kullanımına olanak sağlayacak şekilde beş tampon gereklidir.

Sütunlar yatay çizgiler kullanılarak Kutu Boyutlarına bölünür. Elde ettiğimiz sonuç oldukça iyidir:

Şekil 2. Günlük zaman çerçevesinde EURUSD için gösterge kullanarak grafik oluşturma.

Şekil 2. Günlük zaman aralığında EURUSD göstergesini kullanarak grafik oluşturma.

 

Gösterge Algoritması

İlk olarak, göstergenin giriş parametrelerini belirlememiz gerekiyor. Nokta ve Şekil grafiği zamanı hesaba katmadığından ve dakika çubuklarından çizim için verileri kullandığımızdan, sistem kaynaklarını gereksiz yere kullanmamak için işlenecek veri miktarını belirlememiz gerekiyor. Ayrıca, bir Nokta ve Şekil grafiğini bütün geçmişi kullanarak çizmenin anlamı yoktur. Bu yüzden ilk parametreyi uyguluyoruz: Tarih. Bu, hesaplama için dakika çubuklarının sayısını değerlendirmeye alacaktır.

Ayrıca, Kutu Boyutunu ve Ters Çevirme Miktarını belirlememiz gerekiyor. Bunun için, sırasıyla Cell ve CellForChange değişkenlerini uygulayacağız. Ayrıca X'ler için ColorUp, ve O'lar için ColorDown renk parametresini getireceğiz. Ve son olarak, son parametre çizgi renginde -LineColor- olacaktır.

// +++ Program start +++
//+------------------------------------------------------------------+
//|                                                         APFD.mq5 |
//|                                            Aktiniy ICQ:695710750 |
//|                                                    ICQ:695710750 |
//+------------------------------------------------------------------+
#property copyright "Aktiniy ICQ:695710750"
#property link      "ICQ:695710750"
#property version   "1.00"
//--- Indicator plotting in a separate window
#property indicator_separate_window
#property indicator_buffers 5
#property indicator_plots   1
//--- plot Label1
#property indicator_label1  "APFD"
#property indicator_type1   DRAW_COLOR_CANDLES
#property indicator_style1  STYLE_SOLID
#property indicator_color1  clrRed,clrGold
#property indicator_width1  1
//--- Set the input parameters
input int   History=10000;
input int   Cell=5;
input int   CellForChange=3;
input color ColorUp=clrRed;
input color ColorDown=clrGold;
input color LineColor=clrAqua;
//--- Declare indicator buffers
double CandlesBufferOpen[];
double CandlesBufferHigh[];
double CandlesBufferLow[];
double CandlesBufferClose[];
double CandlesBufferColor[];
//--- Array for copying calculation data from the minute bars
double OpenPrice[];
// Variables for calculations
double PriceNow=0;
double PriceBefore=0;
//--- Introduce auxiliary variables
char   Trend=0;      // Direction of the price trend
double BeginPrice=0; // Starting price for the calculation
char   FirstTrend=0; // Direction of the initial market trend
int    Columns=0;    // Variable for the calculation of columns
double InterimOpenPrice=0;
double InterimClosePrice=0;
double NumberCell=0; // Variable for the calculation of cells
double Tick=0;       // Tick size
double OldPrice=0;   // Value of the last calculation price
//--- Create arrays to temporary store data on column opening and closing prices
double InterimOpen[];
double InterimClose[];
// +++ Program start +++

Şimdi OnInit() fonksiyonunu değerlendirelim. Bu, gösterge tamponlarını tek boyutlu dizilere bağlayacaktır. Aynı zamanda, daha doğru bir görüntü için işlemeksizin gösterge değerini ayarlayacağız ve

hesaplamalar için yardımcı değişken Tik değerini (bir tik boyutu) hesaplayacağız. Ek olarak, renk düzenini ve indis oluşturma sırasını gösterge tamponlarında zaman serisi olarak ayarlayacağız. Bu, göstergenin değerlerini uygun bir şekilde hesaplamak için gereklidir.

// +++ The OnInit function +++
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,CandlesBufferOpen,INDICATOR_DATA);
   SetIndexBuffer(1,CandlesBufferHigh,INDICATOR_DATA);
   SetIndexBuffer(2,CandlesBufferLow,INDICATOR_DATA);
   SetIndexBuffer(3,CandlesBufferClose,INDICATOR_DATA);
   SetIndexBuffer(4,CandlesBufferColor,INDICATOR_COLOR_INDEX);
//--- Set the value of the indicator without rendering
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0);
//--- Calculate the size of one tick
   Tick=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE);
//--- Set the color scheme
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,ColorUp);
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,ColorDown);
//--- Set the indexing order in arrays as time series
   ArraySetAsSeries(CandlesBufferClose,true);
   ArraySetAsSeries(CandlesBufferColor,true);
   ArraySetAsSeries(CandlesBufferHigh,true);
   ArraySetAsSeries(CandlesBufferLow,true);
   ArraySetAsSeries(CandlesBufferOpen,true);
//--- Check the input parameter for correctness
   if(CellForChange<2)
      Alert("The CellForChange parameter must be more than 1 due to plotting peculiarities");
//---
   return(0);
  }
// +++ The OnInit function +++

Şimdi göstergenin tam "kalbine", hesaplamaların yapılacağı OnCalculate() fonksiyonuna geldik. Gösterge değerlerinin hesaplamaları OnCalculate() fonksiyonundan çağrılacak altı temel fonksiyona ayrılmıştır. Bunlara bir göz atalım:

1.  Veri kopyalama fonksiyonu

Bu fonksiyon, verileri hesaplamalar için dakika çubuklarından bir diziye kopyalar. İlk olarak, alıcı diziyi yeniden boyutlandırıyoruz ve ardından CopyOpen() fonksiyonunu kullanarak açılış fiyatlarını kopyalıyoruz.

//+------------------------------------------------------------------+
//| Function for copying data for the calculation                    |
//+------------------------------------------------------------------+
int FuncCopy(int HistoryInt)
  {
//--- Resize the array for copying calculation data
   ArrayResize(OpenPrice,(HistoryInt));
//--- Copy data from the minute bars to the array
   int Open=CopyOpen(Symbol(),PERIOD_M1,0,(HistoryInt),OpenPrice);
//---
   return(Open);
  }

2.  Sütun sayısını hesaplama fonksiyonu

Bu fonksiyon, Nokta ve Şekil grafiği için sütun sayısını hesaplar.

Hesaplamalar, yukarıdaki fonksiyondan kopyalanan dakika zaman aralığındaki çubuk sayısını yineleyen bir döngüde yapılır. Döngünün kendisi farklı trend türleri için üç ana bloktan oluşur:

  •  0 - belirsiz trend.
  •  1 - yükseliş trendi.
  • -1 - düşüş trendi.

Belirsiz trend, başlangıç fiyat hareketini belirlemek için yalnızca bir kez kullanılacaktır. Fiyat hareketinin yönü, mevcut piyasa ile başlangıç fiyatı arasındaki farkın mutlak değeri, Ters Çevirme Miktarı ile çarpılan Kutu Boyutu değerini aştığında belirlenir.

Aşağı yönlü bir kırılma olursa, başlangıç trendi bir düşüş trendi olarak tanımlanır ve Trend değişkenine karşılık gelen bir giriş yapılır. Bir yükseliş trendi ise bunun tam tersi şekilde tanımlanır. Ek olarak, sütun sayısı için değişken -ColumnsInt- değeri artırılacaktır.

Mevcut trendin belirlenmesinin ardından, her bir yön için iki koşul belirleyeceğiz. Fiyatın mevcut trend yönünde Kutu Boyutu kadar hareket etmeye devam etmesi durumunda, ColumnsInt değişken değeri değişmeden kalacaktır. Fiyatın Ters Çevirme Miktarı ile çarpılan Kutu Boyutu kadar ters çevrilmesi durumunda, yeni bir sütun görüntülenecektir ve ColumnsInt değişken değeri bir değer artacaktır.

Ve tüm sütunlar tanımlanana kadar bu şekilde devam eder. 

Döngüdeki hücrelerin sayısını yuvarlamak için, ortaya çıkan değerleri en yakın tam sayılara yuvarlamamıza olanak sağlayan MathRound() fonksiyonunu kullanacağız. İsteğe bağlı olarak bu fonksiyon, gerekli çizime göre MathFloor() fonksiyonu (en yakın alt tam sayıya yuvarlama) veya MathCeil() fonksiyonu (en yakın üst tam sayıya yuvarlama) ile değiştirilebilir.

//+------------------------------------------------------------------+
//| Function for calculating the number of columns                   |
//+------------------------------------------------------------------+
int FuncCalculate(int HistoryInt)
  {
   int ColumnsInt=0;

//--- Zero out auxiliary variables
   Trend=0;                 // Direction of the price trend
   BeginPrice=OpenPrice[0]; // Starting price for the calculation
   FirstTrend=0;            // Direction of the initial market trend
   Columns=0;               // Variable for the calculation of columns
   InterimOpenPrice=0;
   InterimClosePrice=0;
   NumberCell=0;            // Variable for the calculation of cells
//--- Loop for the calculation of the number of main buffers (column opening and closing prices)
   for(int x=0; x<HistoryInt; x++)
     {
      if(Trend==0 && (Cell*CellForChange)<fabs((BeginPrice-OpenPrice[x])/Tick))
        {
         //--- Downtrend
         if(((BeginPrice-OpenPrice[x])/Tick)>0)
           {
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimOpenPrice=BeginPrice;
            InterimClosePrice=BeginPrice-(NumberCell*Cell*Tick);
            InterimClosePrice=NormalizeDouble(InterimClosePrice,Digits());
            Trend=-1;
           }
         //--- Uptrend
         if(((BeginPrice-OpenPrice[x])/Tick)<0)
           {
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimOpenPrice=BeginPrice;
            InterimClosePrice=BeginPrice+(NumberCell*Cell*Tick);
            InterimClosePrice=NormalizeDouble(InterimClosePrice,Digits());
            Trend=1;
           }
         BeginPrice=InterimClosePrice;
         ColumnsInt++;
         FirstTrend=Trend;
        }
      //--- Determine further actions in case of the downtrend
      if(Trend==-1)
        {
         if(((BeginPrice-OpenPrice[x])/Tick)>0 && (Cell)<fabs((BeginPrice-OpenPrice[x])/Tick))
           {
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimClosePrice=BeginPrice-(NumberCell*Cell*Tick);
            InterimClosePrice=NormalizeDouble(InterimClosePrice,Digits());
            Trend=-1;
            BeginPrice=InterimClosePrice;
           }
         if(((BeginPrice-OpenPrice[x])/Tick)<0 && (Cell*CellForChange)<fabs((BeginPrice-OpenPrice[x])/Tick))
           {
            ColumnsInt++;
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimOpenPrice=BeginPrice+(Cell*Tick);
            InterimClosePrice=BeginPrice+(NumberCell*Cell*Tick);
            InterimClosePrice=NormalizeDouble(InterimClosePrice,Digits());
            Trend=1;
            BeginPrice=InterimClosePrice;
           }
        }
      //--- Determine further actions in case of the uptrend
      if(Trend==1)
        {
         if(((BeginPrice-OpenPrice[x])/Tick)>0 && (Cell*CellForChange)<fabs((BeginPrice-OpenPrice[x])/Tick))
           {
            ColumnsInt++;
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimOpenPrice=BeginPrice-(Cell*Tick);
            InterimClosePrice=BeginPrice-(NumberCell*Cell*Tick);
            InterimClosePrice=NormalizeDouble(InterimClosePrice,Digits());
            Trend=-1;
            BeginPrice=InterimClosePrice;
           }
         if(((BeginPrice-OpenPrice[x])/Tick)<0 && (Cell)<fabs((BeginPrice-OpenPrice[x])/Tick))
           {
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimClosePrice=BeginPrice+(NumberCell*Cell*Tick);
            InterimClosePrice=NormalizeDouble(InterimClosePrice,Digits());
            Trend=1;
            BeginPrice=InterimClosePrice;
           }
        }
     }
//---
   return(ColumnsInt);
  }

3.  Sütunları renklendirme fonksiyonu

Bu fonksiyon, önceden ayarlanmış renk düzenini kullanarak sütunların gerektiği şekilde renklendirilmesine yöneliktir. Bunun için, sütun sayısı üzerinde yinelenen bir döngü yazacağız ve başlangıç trend değerini (ilk sütun) dikkate alarak çift sayılı ve tek sayılı sütunlara uygun renkler ayarlayacağız.

//+------------------------------------------------------------------+
//| Function for coloring columns                                    |
//+------------------------------------------------------------------+
int FuncColor(int ColumnsInt)
  {
   int x;
//--- Fill the buffer of colors for drawing
   for(x=0; x<ColumnsInt; x++)
     {
      if(FirstTrend==-1)
        {
         if(x%2==0) CandlesBufferColor[x]=1; // All even buffers of color 1
         if(x%2>0) CandlesBufferColor[x]=0;  // All odd buffers of color 0
        }
      if(FirstTrend==1)
        {
         if(x%2==0) CandlesBufferColor[x]=0; // All odd buffers of color 0
         if(x%2>0) CandlesBufferColor[x]=1;  // All even buffers of color 1
        }
     }
//---
   return(x);
  }

4.  Sütun boyutunu belirleme fonksiyonu

Kullanılacak sütun sayısını belirlemenin ve gerekli renkleri ayarlamanın ardından, sütunların yüksekliğini belirlememiz gerekiyor. Bunun için, içinde her bir sütun için açılış ve kapanış fiyatlarını saklayacağımız InterimOpen[] ve InterimClose[] geçici dizilerini oluşturacağız. Bu dizilerin boyutu sütun sayısına eşit olacaktır.

Ardından, FuncCalculate() fonksiyonundan döngüyle neredeyse tamamen aynı olan bir döngümüz olacak; bunun farkı, yukarıdakiler dışında aynı zamanda sütunlardan her biri için açılış ve kapanış fiyatlarını saklamasıdır. Bu ayrım, grafikteki sütun sayısını önceden bilmek için uygulanır. Teorik olarak, başlangıçta dizi belleği tahsisi için kasıtlı olarak daha yüksek sayıda sütun ayarlayabiliriz ve bunu yalnızca bir döngü ile yapabiliriz. Ancak bu durumda bellek kaynaklarını daha fazla kullanırız.

Şimdi sütun yüksekliğini belirlemeye daha detaylı bir göz atalım. Fiyatın gerekli Kutu Boyutu sayısına eşit mesafeyi hareket etmesinin ardından, bunların sayılarını hesaplayarak en yakın tamsayıya yuvarlıyoruz. Daha sonra, mevcut sütunun Kutu Boyutlarının toplam sayısını sütun açılış fiyatına ekliyoruz ve böylece son kullanılan fiyat da olan sütun kapanış fiyatını elde ediyoruz. Bu, diğer tüm eylemlerde de bulunacaktır.

//+------------------------------------------------------------------+
//| Function for determining the column size                         |
//+------------------------------------------------------------------+
int FuncDraw(int HistoryInt)
  {
//--- Determine the sizes of temporary arrays
   ArrayResize(InterimOpen,Columns);
   ArrayResize(InterimClose,Columns);
//--- Zero out auxiliary variables
   Trend=0;                 // Direction of the price trend
   BeginPrice=OpenPrice[0]; // Starting price for the calculation
   NumberCell=0;            // Variable for the calculation of cells
   int z=0;                 // Variable for indices of temporary arrays
//--- Loop for filling the main buffers (column opening and closing prices)
   for(int x=0; x<HistoryInt; x++)
     {
      if(Trend==0 && (Cell*CellForChange)<fabs((BeginPrice-OpenPrice[x])/Tick))
        {
         //--- Downtrend
         if(((BeginPrice-OpenPrice[x])/Tick)>0)
           {
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimOpen[z]=BeginPrice;
            InterimClose[z]=BeginPrice-(NumberCell*Cell*Tick);
            InterimClose[z]=NormalizeDouble(InterimClose[z],Digits());
            Trend=-1;
           }
         //--- Uptrend
         if(((BeginPrice-OpenPrice[x])/Tick)<0)
           {
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimOpen[z]=BeginPrice;
            InterimClose[z]=BeginPrice+(NumberCell*Cell*Tick);
            InterimClose[z]=NormalizeDouble(InterimClose[z],Digits()); // Normalize the number of decimal places
            Trend=1;
           }
         BeginPrice=InterimClose[z];
        }
      //--- Determine further actions in case of the downtrend
      if(Trend==-1)
        {
         if(((BeginPrice-OpenPrice[x])/Tick)>0 && (Cell)<fabs((BeginPrice-OpenPrice[x])/Tick))
           {
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimClose[z]=BeginPrice-(NumberCell*Cell*Tick);
            InterimClose[z]=NormalizeDouble(InterimClose[z],Digits());
            Trend=-1;
            BeginPrice=InterimClose[z];
           }
         if(((BeginPrice-OpenPrice[x])/Tick)<0 && (Cell*CellForChange)<fabs((BeginPrice-OpenPrice[x])/Tick))
           {
            z++;
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimOpen[z]=BeginPrice+(Cell*Tick);
            InterimClose[z]=BeginPrice+(NumberCell*Cell*Tick);
            InterimClose[z]=NormalizeDouble(InterimClose[z],Digits());
            Trend=1;
            BeginPrice=InterimClose[z];
           }
        }
      //--- Determine further actions in case of the uptrend
      if(Trend==1)
        {
         if(((BeginPrice-OpenPrice[x])/Tick)>0 && (Cell*CellForChange)<fabs((BeginPrice-OpenPrice[x])/Tick))
           {
            z++;
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimOpen[z]=BeginPrice-(Cell*Tick);
            InterimClose[z]=BeginPrice-(NumberCell*Cell*Tick);
            InterimClose[z]=NormalizeDouble(InterimClose[z],Digits());
            Trend=-1;
            BeginPrice=InterimClose[z];
           }
         if(((BeginPrice-OpenPrice[x])/Tick)<0 && (Cell)<fabs((BeginPrice-OpenPrice[x])/Tick))
           {
            NumberCell=fabs((BeginPrice-OpenPrice[x])/Tick)/Cell;
            NumberCell=MathRound(NumberCell);
            InterimClose[z]=BeginPrice+(NumberCell*Cell*Tick);
            InterimClose[z]=NormalizeDouble(InterimClose[z],Digits());
            Trend=1;
            BeginPrice=InterimClose[z];
           }
        }
     }
//---
   return(z);
  }

5.  Dizi tersine çevirme fonksiyonu

Fonksiyon, grafiği programlı bir şekilde sağdan sola daha fazla görüntülemek için elde edilen sütun dizisi verilerini tersine çevirir. Dizi tersine çevirme işlemi, mumlara atanan High ve Low değerler ile bir döngüde gerçekleştirilir. Bu, göstergenin yalnızca tüm gösterge tamponu değerlerinin sıfıra eşit olmadığı mumlar için görüntülenmesi nedeniyle yapılır.

//+------------------------------------------------------------------+
//| Function for array reversal                                      |
//+------------------------------------------------------------------+
int FuncTurnArray(int ColumnsInt)
  {
//--- Variable for array reversal
   int d=ColumnsInt;
   for(int x=0; x<ColumnsInt; x++)
     {
      d--;
      CandlesBufferOpen[x]=InterimOpen[d];
      CandlesBufferClose[x]=InterimClose[d];
      if(CandlesBufferClose[x]>CandlesBufferOpen[x])
        {
         CandlesBufferHigh[x]=CandlesBufferClose[x];
         CandlesBufferLow[x]=CandlesBufferOpen[x];
        }
      if(CandlesBufferOpen[x]>CandlesBufferClose[x])
        {
         CandlesBufferHigh[x]=CandlesBufferOpen[x];
         CandlesBufferLow[x]=CandlesBufferClose[x];
        }
     }
//---
   return(d);
  }

6.  Yatay çizgiler çizme fonksiyonu

Bu fonksiyon, yatay çizgileri (nesneleri) kullanarak bir "kutular" ızgarası oluşturur. Fonksiyonun başında, hesaplama verileri dizisinden maksimum ve minimum fiyat değerlerini belirleriz. Bu değerler ayrıca, başlangıç noktasından yukarıya ve aşağıya çizgileri kademeli olarak çizmek için kullanılır.

//+------------------------------------------------------------------+
//| Function for drawing horizontal lines                            |
//+------------------------------------------------------------------+
int FuncDrawHorizontal(bool Draw)
  {
   int Horizontal=0;
   if(Draw==true)
     {
      //--- Create horizontal lines (lines for separation of columns)
      ObjectsDeleteAll(0,ChartWindowFind(),OBJ_HLINE); // Delete all old horizontal lines
      int MaxPriceElement=ArrayMaximum(OpenPrice);     // Determine the maximum price level
      int MinPriceElement=ArrayMinimum(OpenPrice);     // Determine the minimum price level
      for(double x=OpenPrice[0]; x<=OpenPrice[MaxPriceElement]+(Cell*Tick); x=x+(Cell*Tick))
        {
         ObjectCreate(0,DoubleToString(x,Digits()),OBJ_HLINE,ChartWindowFind(),0,NormalizeDouble(x,Digits()));
         ObjectSetInteger(0,DoubleToString(x,Digits()),OBJPROP_COLOR,LineColor);
         ObjectSetInteger(0,DoubleToString(x,Digits()),OBJPROP_STYLE,STYLE_DOT);
         ObjectSetInteger(0,DoubleToString(x,Digits()),OBJPROP_SELECTED,false);
         ObjectSetInteger(0,DoubleToString(x,Digits()),OBJPROP_WIDTH,1);
         Horizontal++;
        }
      for(double x=OpenPrice[0]-(Cell*Tick); x>=OpenPrice[MinPriceElement]; x=x-(Cell*Tick))
        {
         ObjectCreate(0,DoubleToString(x,Digits()),OBJ_HLINE,ChartWindowFind(),0,NormalizeDouble(x,Digits()));
         ObjectSetInteger(0,DoubleToString(x,Digits()),OBJPROP_COLOR,LineColor);
         ObjectSetInteger(0,DoubleToString(x,Digits()),OBJPROP_STYLE,STYLE_DOT);
         ObjectSetInteger(0,DoubleToString(x,Digits()),OBJPROP_SELECTED,false);
         ObjectSetInteger(0,DoubleToString(x,Digits()),OBJPROP_WIDTH,1);
         Horizontal++;
        }
      ChartRedraw();
     }
//---
   return(Horizontal);
  }

Artık tüm temel fonksiyonları açıkladığımıza göre, bunların OnCalculate() fonksiyonunda çağrılma sırasını görelim:

  • Hesaplamalar (henüz hesaplanan çubuk olmaması koşuluyla) için veri kopyalama fonksiyonunu başlatın.
  • Sütun sayısını hesaplama fonksiyonunu çağırın.
  • Sütun renklerini belirleyin.
  • Sütun boyutlarını belirleyin.
  • Dizilerde veri ters çevirme fonksiyonunu çağırın.
  • Sütunları "kutulara" bölecek yatay çizgileri çizme fonksiyonunu çağırın.
// +++ Main calculations and plotting +++
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
//--- Reverse the array to conveniently get the last price value
   ArraySetAsSeries(close,true);
//---
   if(prev_calculated==0)
     {
      //--- Start the function for copying data for the calculation
      int ErrorCopy=FuncCopy(History);
      //--- In case of error, print the message
      if(ErrorCopy==-1)
        {
         Alert("Failed to copy. Data is still loading.");
         return(0);
        }
      //--- Call the function for calculating the number of columns
      Columns=FuncCalculate(History);
      //--- Call the function for coloring columns
      int ColorCalculate=FuncColor(Columns);
      //--- Call the function for determining column sizes
      int z=FuncDraw(History);
      //--- Start the function for array reversal
      int Turn=FuncTurnArray(Columns);
      //--- Start the function for drawing horizontal lines
      int Horizontal=FuncDrawHorizontal(true);
      //--- Store the value of the last closing price in the variable
      OldPrice=close[0];
     }
//--- If the price is one box size different from the previous one, 
//--- the indicator is recalculated
   if(fabs((OldPrice-close[0])/Tick)>Cell)
      return(0);
//--- return value of prev_calculated for next call
   return(rates_total);
  }
// +++ Main calculations and plotting +++

Burası göstergenin temel kodunun sonudur. Ancak, karmaşık diziler içermesi bakımından dezavantajları olduğu için, göstergenin bazen yeniden yüklenmesi gerekir.

Bunu gerçekleştirmek için,  "С" tuşuna basma - temizle ve  "R" tuşuna basma - yeniden çiz olaylarını işleyen OnChartEvent() fonksiyonunu kullanacağız. Temizlemek için, gösterge tamponlarından birine sıfır değeri atanır. Grafiği yeniden çizme fonksiyonu, önceki hesaplamaların ve değerlerin gösterge tamponlarına atanmasının bir tekrarını temsil eder.

// +++ Secondary actions for the "С" key - clear and the "R" key - redraw +++
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---
   if(id==CHARTEVENT_KEYDOWN)
     {
      //--- 67 - The "C" key code clears the indicator buffer
      if(lparam==67)
        {
         for(int x=0; x<Bars(Symbol(),PERIOD_CURRENT); x++)
            CandlesBufferOpen[x]=0;
         ChartRedraw();
        }
      // 82 - The "R" key code redraws the indicator
      if(lparam==82)
        {
         //--- Start the copying function
         int ErrorCopy=FuncCopy(History);
         //--- In case of error, print the message
         if(ErrorCopy==-1)
            Alert("Failed to copy data.");
         //--- Call the function for calculating the number of columns
         Columns=FuncCalculate(History);
         //--- Call the function for coloring columns
         int ColorCalculate=FuncColor(Columns);
         //--- Call the function for determining column sizes
         int z=FuncDraw(History);
         //--- Start the function for array reversal
         int Turn=FuncTurnArray(Columns);
         //--- Start the function for drawing horizontal lines
         int Horizontal=FuncDrawHorizontal(true);
        }
     }
  }
//+------------------------------------------------------------------+
// +++ Secondary actions for the "С" key - clear and the "R" key - redraw +++

Algoritma ve gösterge kodunun açıklamasını bitirdiğimize göre derin bir nefes alabiliriz ve alım satımların yürütülmesi için sinyaller oluşturan bazı Nokta ve Şekil grafik modellerine göz atmaya devam edebiliriz.

 

Standart Sinyaller

Alım satımda ve Nokta ve Şekil grafiklerinin analiz edilmesinde iki yaklaşım vardır: modeller temelli ve destek ve direnç çizgileri temelli. İkincisi, destek ve direnç çizgilerinin 45 derecelik bir açıyla çizilmesi bakımından özeldir (bu durum tasarlanmış bir göstergede her zaman bu şekilde değildir, çünkü boyutu, açı bozulmasına yol açabilecek şekilde ana grafiğin boyutuna göre değişen Japon mumları kullanılarak çizilir).

Şimdi modelleri şu şekilde değerlendirelim:

  1. "İkili Tepe (Double Top)" ve "İkili Dip (Double Bottom)" modelleri.

    "İkili Tepe" fiyat yükseldiğinde meydana gelir, ardından düşerek belirgin bir O'lar sütunu oluşturur ve yeniden yükselerek X'lerin önceki sütununu bir Kutu Boyutu kadar aşar. Bu model bir alış sinyalidir.

    "İkili Dip", "İkili Tepe" modelinin tam zıddıdır. Belirli bir fiyat düşüşü (bir O'lar sütunu) ve ardından bir X'ler sütunu ve önceki O'lar sütununun bir kutu altına düşen bir diğer O'lar sütunu vardır ve böylece bir satış sinyali oluşturulur.

    Şekil 3. "İkili Tepe" ve "İkili Dip" modelleri.

    Şekil 3. "İkili Tepe" ve "İkili Dip" modelleri.

  2. "Üçlü Tepe" ve "Üçlü Dip" modelleri.

    Bu desenler daha seyrektir, ancak oldukça güçlü sinyalleri temsil eder. Esas olarak bunlar, "İkili Tepe" ve "İkili Dip" modellerine benzer ve bunların devamıdır. Bunlar, bir sinyal iletmeden önce, yukarıdaki iki modelin hareketlerini tekrarlar.

    Bir "Üçlü Tepe", fiyat aynı fiyat seviyesine iki kez geldiğinde ve ardından bu seviye üzerinde kırıldığında meydana gelerek bir alış sinyalini temsil eder.

    "Üçlü Dip" modeli, "Üçlü Tepe" modelinin zıddıdır ve fiyat iki kez aynı seviyeye düştüğünde ve ardından bu seviyenin altında kırıldığında meydana gelerek bir satış sinyali iletir.

    Şekil 4. "Üçlü Tepe" ve "Üçlü Dip" modelleri.

    Şekil 4. "Üçlü Tepe" ve "Üçlü Dip" modelleri.

  3. "Simetrik Üçgen Kırılması" modelleri: yukarı yönlü ve aşağı yönlü.

    Teknik analiz modellerini hepimiz hatırlıyoruz. "Simetrik Üçgen Kırılması" modeli teknik analizdeki "Simetrik Üçgen"e benzerdir. Bir yukarı yönlü kırılma (aşağıda soldaki şekilde gösterildiği gibi) bir alış sinyalidir. Tam tersine, aşağı yönlü bir kırılma bir satış sinyalidir (sağdaki şekil).

    Şekil 5. "Simetrik Üçgen Kırılması": yukarı yönlü ve aşağı yönlü.

    Şekil 5. "Simetrik Üçgen Kırılması": yukarı yönlü ve aşağı yönlü.

  4. "Yukarı Yönlü Mancınık" ve "Aşağı Yönlü Mancınık" modelleri.

    "Mancınıklar", bir anlamda teknik analizin "Yükselen Üçgen" ve "Alçalan Üçgen" modellerine benzerdir. Bunların sinyalleri temelde benzerdir - fiyat üçgenin paralel tarafının üstünde veya altında kırılır kırılmaz, sırasıyla bir alış veya satış sinyali oluşur. "Yukarı Yönlü Mancınık" durumunda, fiyat bunun üstünde kırılır, bu da bir alış sinyalidir (soldaki şekil); ve "Aşağı Yönlü Mancınık" durumunda, fiyat bunun altında kırılır, bu da bir satış sinyalidir (sağdaki şekil).

    Şekil 6. "Yukarı Yönlü Mancınık" ve "Aşağı Yönlü Mancınık" modelleri.

    Şekil 6. "Yukarı Yönlü Mancınık" ve "Aşağı Yönlü Mancınık" modelleri.

  5. "45 Derece Trend Çizgisi" modeli.

    "45 Derece Trend Çizgisi" modeli bir destek veya direnç çizgisi oluşturur. Bu çizginin bir kırılması meydana gelirse, bir satış sinyali (sağdaki şekilde gösterildiği gibi) veya bir alış sinyali (soldaki şekilde olduğu gibi) elde ederiz.

    Şekil 7. "45 Derece Trend Çizgisi" modeli.

    Şekil 7. "45 Derece Trend Çizgisi" modeli.

Standart Nokta ve Şekil grafik modellerini ve sinyallerini gözden geçirdik. Şimdi bunlardan bazılarını makalenin başında sağlanan gösterge grafiğinde bulalım:

Şekil 8. Nokta ve Şekil grafiğinde modelleri tanımlama.

Şekil 8. Nokta ve Şekil grafiğinde modelleri tanımlama.

 

Sonuç

Makalenin son aşamasına gelmiş bulunuyoruz. Burada Nokta ve Şekil grafiğinin zamanla kaybolmadığını ve hala etkin olarak kullanıldığını ve değerini bir kez daha kanıtladığını belirtmek isterim.

Geliştirilen gösterge, normal X'ler ve O'lar yerine blok grafik oluşturma ve Strateji Test Cihazında test edilememesi (daha doğrusu yanlış işlem) gibi dezavantajlar içerse de, oldukça doğru grafik sonuçları sağlamaktadır.

Ayrıca, hafif değiştirilmiş bir sürümünde bu algoritmanın potansiyel olarak Renko grafiği ve her iki grafik türünün menü seçenekleri ile tek bir koda entegre edilerek uygun şekilde seçim yapmanıza olanak sağlamak için kullanılabileceğini belirtmek isterim. Grafiği doğrudan ana pencere üzerinde çizme imkanını da dışlamıyorum, bu da yine küçük bir kod değişikliği gerektirecektir.

Genel itibarıyla, bu makalenin amacı gösterge geliştirmeye dair fikirlerimi paylaşmaktı. Bu benim ilk makalem olduğu için, yorumlarınızı ve geri bildirimlerinizi çok isterim. Makaleme gösterdiğiniz ilgi için teşekkür ederim!

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

Ekli dosyalar |
apfd.mq5 (18.85 KB)
MQL5 Cloud Network: Hala Hesaplıyor musunuz? MQL5 Cloud Network: Hala Hesaplıyor musunuz?
Yakında MQL5 Cloud Network'ün piyasaya sürülmesinden bu yana bir buçuk yıl geçmiş olacak. Bu öncü olay, yeni bir algoritmik alım satım çağını başlattı - şimdi birkaç tıklamayla, yatırımcıların emrinde alım satım stratejilerinin optimizasyonu için yüzlerce ve binlerce bilgi işlem çekirdeği olabilir.
MQL5 Programlarında Hata Ayıklama MQL5 Programlarında Hata Ayıklama
Bu makale öncelikle dili öğrenmiş, ancak henüz program geliştirme konusunda tam olarak uzmanlaşmamış programcılara yöneliktir. Bazı hata ayıklama tekniklerini açıklar ve yazar ile diğer birçok programcının birleşik tecrübesini sunar.
MQL5 Tarif Defteri: Tipik Grafik Olaylarını İşleme MQL5 Tarif Defteri: Tipik Grafik Olaylarını İşleme
Bu makale, tipik grafik olaylarını değerlendirir ve bunların işlenme örneklerini içerir. Fare olayları, tuş vuruşları, bir grafik nesnesinin oluşturulması/değiştirilmesi/kaldırılması, bir grafik üzerinde ve bir grafik nesnesi üzerinde fare tıklaması, bir grafik nesnesinin fare ile hareket ettirilmesi, bir metin alanındaki metnin düzenlemesinin tamamlanmasının yanı sıra grafik değişiklik olaylarına odaklanacağız. Değerlendirilen her olay türü için bir MQL5 programı örneği sağlanmıştır.
MQL5 Tarif Defteri: Aşırı Öğrenme Etkisini Azaltma ve Kotasyon Eksikliğini Ele Alma MQL5 Tarif Defteri: Aşırı Öğrenme Etkisini Azaltma ve Kotasyon Eksikliğini Ele Alma
Hangi alım satım stratejisini kullanırsanız kullanın, gelecekteki kârları sağlamak için hangi parametreleri seçeceğinize dair her zaman bir soru olacaktır. Bu makale, aynı anda birçok sembol parametresini optimize etme imkanına sahip bir Uzman Danışman örneği sağlar. Bu yöntemin, aşırı öğrenme parametrelerin etkisini azaltması ve çalışma için tek bir sembolden elde edilen verilerin yeterli olmadığı durumları ele alması amaçlanır.