English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
Çizim Kanalları - İçeriden ve Dışarıdan Görünüm

Çizim Kanalları - İçeriden ve Dışarıdan Görünüm

MetaTrader 5Göstergeler | 16 Aralık 2021, 14:30
66 0
Dmitriy Skub
Dmitriy Skub

Giriş

Kanalların piyasa analizi ve hareketli ortalamalardan sonra alım satım kararları almak için en popüler araç olduğunu söylersem sanırım abartmış olmam. Serinin kanallara adanan birinci makalesinde, istemci terminalinin ekranında üç uçdeğer tarafından ayarlanan bir kanalı çizen bir göstergenin matematiksel temelini ve teorik uygulamasını açıklayacağız.

İlk bakışta, ilkokulda öğretilen bir düz çizgi denklemine dayandığı için bir kanalın çizimi kolay bir görev gibi görünür. Bununla birlikte, istemci terminalinde pratik uygulaması doğrudan cevaplanamayan çok sayıda soru içerir.

Uçdeğerin ayarlanması ve bunların değişikliklerinin takip edilmesi en iyi şekilde nasıl düzenlenir? Orta kısmı eksik çubuklar üzerindeyse ne yapılır ve bir kanal nasıl çizilir? Bir kanalın sol uçdeğeri Cuma günündeyse ve sağdaki Pazartesi günündeyse çubukların olmadığı kapalı günler bunların arasında mı? Bir kanalın sınırlarının mevcut değerlerini nasıl alabiliriz?

Bunlar ve bazı başka sorular kanallar hakkındaki makale serisinin birinci makalesinde cevaplanmıştır. Buraya ayrıca standart sınıflar ve nesne yönelimli yaklaşım kullanılarak belirtilen üç uçdeğer yoluyla kanalların çiziminin uygulamasını bulabilirsiniz. Kanal çiziciyi bir gösterge formunda uygulayacağız.


Uçdeğerlerin Ayarlanması

Aslında, bir grafikte bir kanalın konumu en az üç uçdeğer tarafından belirlenir. Bir uçdeğere bir tanım verirsek şunu kabul edebiliriz: Bu, belirli bir aralıkta bir fonksiyonun maksimum veya minimum değeridir. Bir uçdeğere ulaşılan noktaya bir uçdeğer noktası denir. Sırasıyla, bir minimuma ulaşılırsa uçdeğer noktası bir minimum noktası olarak adlandırılır ve bir maksimuma ulaşılırsa bu bir maksimum noktası olarak adlandırılır.

Matematiksel analiz başka bir terimi tanımlar - bir yerel uçdeğer (sırasıyla, minimum ve maksimum uçdeğer). Maksimum (minimum) noktasında, fonksiyon değeri tüm bitişik noktaların değerlerinden daha büyüktür (daha küçüktür). Tanım, Wikipedia’dan (Rusçadan çevrilmiştir) alınmıştır.

Çizim kanalları amacıyla, yerel uçdeğerlere ihtiyacımız vardır. Matematiksel formüllere girmeden bunu grafiksel olarak gösterelim. Aşağıda bulunan şekil 1’de, kırmızı fiyat seviyeleriyle işaretlenmiş üç yerel uçdeğer vardır. Dikdörtgen noktaları, iki maksimum ve bir minimum gösterir:

Şekil 1. Yerel uçdeğerlerin örnekleri

Şekil 1. Yerel uçdeğerlerin örnekleri

Tüm mevcut uçdeğerler grafik üzerinde işaretlenmez, sadece en önemli olanlar vardır. Bir mum veya bir çubuk grafiği için uçdeğerleri tanımlamak adına “fraktal” terimini kullanmak uygundur - sola ve sağa doğru birkaç bitişik çubuk kesin şekilde indiğinde veya yükseldiğinde (bkz. şekil 1).

Otomatik bir kanal çizici oluşturma amacımız olmadığından uçdeğerlerin konumu zaman ve fiyat eksenlerindeki konum tarafından şekil 1’de gösterildiği gibi ayarlanacaktır. Bu amaç için en uygunu fiyat etiketleridir - MetaTrader 5 istemci terminalinin özel grafik nesneleri. Bir fiyat etiketi, bir grafikte bir uçdeğer noktasını kesin şekilde tanımlamayı sağlayan zaman ve fiyat koordinatı özelliklerine sahiptir.


Uçdeğerleri depolama nesnesi TExtremum sınıfıdır

Yapmamız gereken ilk şey uçdeğerleri depolamak için bir taşıyıcı sınıfı ve bir uçdeğer grubunu kullanmaya yönelik bir sınıf geliştirmektir. Terminale dahil edilen standart sınıfları mümkün olduğunca fazla kullanacağımız için TExtremum standart CObject sınıfından alınacaktır. Sınıfımızın açıklaması aşağıda verilmiştir:

class TExtremum : public CObject
{
private:
  datetime  extr_datetime;              // data/time in an extremum point
  double    extr_price;                 // price in an extremum point
        
protected:
  virtual int  Compare(const CObject* _node, int _mode = 0) const;

public:
  void      TExtremum();               // constructor
  void      ~TExtremum();              // destructor
  void      SetExtremum(datetime _time, double _price);  // change date/time and price in an extremum point
  void      SetDateTime(datetime _time);                 // change date/time in an extremum point
  void      SetPrice(double _price);  // change price in an extremum point

public:
  datetime  GetDateTime() const;      // get date/time in an extremum point
  double    GetPrice() const;         // get price in an extremum point

public:
  virtual bool  SaveExtremum(string _dt_name, string _p_name);  // save extremum
  virtual bool  LoadExtremum(string _dt_name, string _p_name);  // load extremum
  virtual bool  DeleteExtremum(string _dt_name, string _p_name);// delete extremum
};

Yöntemlerin çoğu önemsizdir ve uygulamalarına dikkat etmek gerekmez. Üzerinde durmamız gereken şey TExtremum::Karşılaştırma yöntemidir. Bu yöntem CObject sınıfında belirlenir ve bir liste içinde sıralama yapmak için kullanılır. Aşağıdaki gibi uyguladık:

//---------------------------------------------------------------------
//  Comparing two extremums by time:
//---------------------------------------------------------------------
int TExtremum::Compare(const CObject* _node, int _mode = 0) const
{
  datetime  temp = ((TExtremum* )_node).GetDateTime();
  datetime  curr = GetDateTime();
  if(curr > temp)
  {
    return(_mode > 0 ? 1 : -1);
  }
  else if(curr < temp)
  {
    return(_mode > 0 ? -1 : 1);
  }

  return(0);
}

Buradaki _mode parametresi bir sıralama yönü ayarlamaya yöneliktir. Bu sıfırdan büyükse sıralama doğrudandır (artan), aksi halde bu tersidir (azalan).

Buna ek olarak, bir uçdeğeri kaydetmeye/yüklemeye yönelik iki yöntem vardır. Uçdeğerimizi global değişkenlerde depolayalım. Bu yöntemler buradadır.

//---------------------------------------------------------------------
//  Save extremum (date/time):
//---------------------------------------------------------------------
bool TExtremum::SaveExtremum(string _dt_name, string _p_name)
{
  datetime  dt_result = GlobalVariableSet(_dt_name, (double)extr_datetime);
  datetime  p_result = GlobalVariableSet(_p_name, (double) extr_price);
  if(dt_result != 0 && p_result != 0)
  {
    return(true);
  }

  return(false);
}

//---------------------------------------------------------------------
//  Load extremum (date/time):
//---------------------------------------------------------------------
bool TExtremum::LoadExtremum(string _dt_name, string _p_name)
{
  double  dt_temp, p_temp;
  bool    result = GlobalVariableGet(_dt_name, dt_temp);
  result &= GlobalVariableGet(_p_name, p_temp);
  if(result != false)
  {
    extr_datetime = (datetime)dt_temp;
    extr_price = p_temp;
    return(true);
  }

  return(false);
}

TExtremum::LoadExtremum ve TExtremum::SaveExtremum global değişkenlerinde okuma/yazmaya yönelik iki yöntem başarılı yürütme durumunda ‘doğru’ çıkar.


Uçdeğerleri Listesini Kullanma - TExtremumList Sınıfı

Zamanla hem uçdeğerleri depolama hem de sıralama gereksinimimiz olduğu için CList standart sınıfından TExtremumList sınıfını miras almamız gerekir. Bu miras ile sayı ve tiplerinde sınırlama olmaksızın uçdeğerlerin evrensel bir manipülatörünü elde ederiz. Bu çizilen kanalların sayısını daha fazla genişletmeyi sağlar. Örneğin, birkaç uçdeğerle doğrusal olmayan regresyon durumunda kanalın çizimini ekleyebiliriz.

Bu sınıfın açıklaması aşağıda verilmiştir:

class TExtremumList : public CList
{
private:
  string              channel_prefix;     // channel name (prefix)
  ENUM_TIMEFRAMES      chart_timeframe;    // current timeframe
  string              chart_symbol;       // work symbols of the chart

protected:
  string    MakeDTimeName(int _nmb);     // get name for saving/reading data/time of an extremum
  string    MakePriceName(int _nmb);     // get name for saving/reading price of an extremum

public:
  void      TExtremumList();             // конструктор
  void     ~TExtremumList();             // деструктор
  void     SetChannelParams(string _pref, string _symbol = NULL, ENUM_TIMEFRAMES _curr_tf = PERIOD_CURRENT);
  void     AddExtremum(datetime _time, double  _price);
  void     DeleteAllExtremum();
  void     SaveExtremumList();
  void     LoadExtremumList();
  int      FindExtremum(datetime _dt);  // search extremum by specified time

public:
  datetime GetDateTime(int _index);
  double   GetPrice(int _index);
};

Sınıfın ana yöntemi TExtremumList::AddExtremum’dur. Listeye yeni bir uçdeğer eklemeye yöneliktir. Listede uçdeğerlerin uçdeğer noktası zamanına göre sıralanması ekleme sonrasında gerçekleştirilir. Bu yöntemin kodu aşağıda verilmiştir:

void TExtremumList::AddExtremum(datetime _time, double  _price)
{
//  Create extremum:
  TExtremum*    extr = new TExtremum();
  extr.SetExtremum(_time, _price);

//  Add it in the list:
  Add(extr);

//  Sort:
  Sort(1);
}

Temel sınıfın aşağıdaki yöntemleri burada kullanılır: CList::Add - listeye yeni bir öğe eklemek için ve CList::Sort - listedeki öğeleri sıralamak için. TExtremum::Compare yöntemi CList::Sort içinde kullanılır.

TExtremumList::FindExtremum listesinde verilen süre ile bir uçdeğer arama yöntemine bir göz atalım. Yöntemin kodu aşağıda verilmiştir:

int TExtremumList::FindExtremum(datetime _dt)
{
  int           k = 0;
  TExtremum*    extr = (TExtremum*)(GetFirstNode());
  while(extr != NULL)
  {
    if(extr.GetDateTime() == _dt)
    {
      return(k);
    }
    extr = (TExtremum*)(GetNextNode());
  }
  return(-1);                     // extremum not found
}

Temel sınıfın aşağıdaki yöntemleri burada kullanılır: CList::GetFirstNode - listenin ilk öğesini almak için (liste boşsa, bir sıfır işaretçisini döndürür) ve CList::GetNextNode - listenin sonraki öğesini almak için (bir sonraki öğe yoksa ve liste bittiyse, bir sıfır işaretçi döndürülür).

Not:

CList sınıf listesinin dahili verilerinde geçerli bir öğenin bir işaretçisi vardır. Bu işaretçi, listede taşıma (CList::GetFirstNode, CList::GetNextNode, CList::GetPrevNode, vb.) yöntemleri çağrılırken değiştirilir. Bu tür yöntemlerin hiçbiri daha önce çağrılmamışsa, geçerli bir öğenin işaretçisi ilkini işaret eder.

Belirli süreye sahip bir uçdeğerin başarıyla bulunması durumunda, bulunan öğenin TExtremumList::FindExtremum dizini yöntemi. Böyle bir öğe yoksa, -1’e döndürür.

TExtremum::MakeDTimeName ve TExtremum::MakePriceName yöntemleri yardımcıdır. Bunlar, uçdeğerleri kaydederken ve okurken kullanılan global değişkenlerin adlarını almak için tasarlanmıştır. Bu yöntemler aşağıdaki uygulamaya sahiptir:

string TExtremumList::MakeDTimeName(int _nmb)
{
  string    name;
  StringConcatenate(name, channel_prefix, "_", channel_symbol, "_", channel_timeframe, "_DTime_Extr", _nmb);
  return(name);
}

string TExtremumList::MakePriceName( int _nmb )
{
  string    name;
  StringConcatenate(name, channel_prefix, "_", channel_symbol, "_", channel_timeframe, "_Price_DTime_Extr", _nmb);
  return(name);
}

Elde edilen ada bir örnek: "MainChannel_EURUSD_5_DTime_Extr1". Bu ad, MainChannel kanalının geçici bir uçdeğer noktasına (geleneksel ad), EURUSD sembolüne, 5M zaman dilimine ve uçdeğer numara 1'e karşılık gelir. Bir uçdeğer için numara, 1'den başlayarak sürenin artan sırasına göre atanır. Pratik olarak, artan şekilde sıralanmış bir listede bu, 1'e kaydırılan dizindir.

Terminalde kaydedilen üç uçdeğerinin değerine bir örnek aşağıdaki şekilde gösterilir:

Şekil 2. Global değişkenlerde depolanan uçdeğerler

Şekil 2. Global değişkenlerde depolanan uçdeğerler

Yukarıda açıklanan sınıflar ExtremumClasses.mqh dosyasındaki makaleye eklenmiştir.


Uçdeğerleri Manuel Olarak Ayarlama Göstergesi - ExtremumHandSet

Pekala, ilk göstergeyi geliştirmek için gereken her şeye sahibiz, bunu kullanarak uçdeğerlerin konumunu manuel modda ayarlayacağız. Göstergenin kodu ExtremumHandSet.MQ5 dosyasındaki makaleye eklenmiştir. Çizimini ayrıntılı olarak analiz edelim.

Her şeyden önce, ekranda görmek istediklerimizi görsel olarak hayal edelim:

Şekil 3. Uçdeğerleri ayarlama göstergesi

Şekil 3. Uçdeğerleri ayarlama göstergesi

Sol fiyat etiketlerini kullanarak grafiğin zaman ve fiyat eksenleri üzerinde uçdeğerlerin konumlarını belirleriz. Gösterge, bu etiketlerin grafikteki konumunu belirlemeli, ekranda geçici uçdeğer noktalarını görüntülemeli ve bunları yukarıda açıklanan biçimde istemci terminalinin global değişkenlerine kaydetmelidir. Ek olarak, gösterge grafikteki fiyat etiketlerinin taşınmasını izlemeli ve yüklenen geçici uçdeğer noktalarını düzeltmelidir.

Grafikteki fiyat etiketlerinin taşınmasının izlenmesi saniyede bir kez gerçekleştirilecektir. Bu, sistemin tekliflerin gelmesinden ve çalışma/tatil günlerinden bağımsız olmasını sağlayacaktır.

Öncelikle, gerekli kitaplıkları bağlayalım:

//---------------------------------------------------------------------
//  Included libraries:
//---------------------------------------------------------------------
#include  <TextDisplay.mqh>
#include  <ExtremumClasses.mqh>

Birinci kitaplık, metin bilgilerinin ekranda görüntülenmesinin düzenlenmesine yönelik sınıfları içerir (bkz. "Standart Kitaplık Sınıflarını kullanarak kendi Market Saatinizi oluşturma" makalesi). Bunu kullanarak, geçici uçdeğer noktalarının değerlerini görüntüleyeceğiz.

Daha sonra göstergenin giriş parametrelerini ekliyoruz (sadece temel olanlar burada açıklanmaktadır):

input string  PrefixString = "MainChannel";
//---------------------------------------------------------------------
input color   ExtremumPointColor = Yellow;
//---------------------------------------------------------------------
input bool    ShowInfo = true;

Birinci parametre PrefixString bir uçdeğerini yazarken/okurken global değişkenlerin adlarını bestelemek için kullanılan bir önek ayarlar. Ayrıca, tek bir grafikte bu tür birkaç göstergeyi kullanma imkanı verir. Yapılacak tek şey bunlar için farklı önekler ayarlamaktır.

ExtremumPointColor parametresi, uçdeğerlerin konumunu belirleyen sol fiyat etiketleri için bir renk ayarlar. Fiyat etiketleri belirtilen renkte olmalıdır. Bu uygunluk göstergede kontrol edilir. Farklı parametrelere sahip etiketler yok sayılır.

ShowInfo parametresi, ekranda belirtilen uçdeğer noktaları hakkındaki metin bilgilerinin görüntülenmesini kontrol eder.

Ardından, bilgilerin görüntülenmesi ve uçdeğerlerin manipüle edilmesi için nesneleri oluşturalım:

TableDisplay    TitlesDisplay;    // displaying information on the screen
//---------------------------------------------------------------------
TExtremumList*  PrevExtr_List;    // list of previous extremums
TExtremumList*  CurrExtr_List;    // list of current extremums
TExtremumList*  NewExtr_List;     // list of new extremums

Bu nesneler aşağıdakilerde başlatılır:

PrevExtr_List = new TExtremumList();
PrevExtr_List.SetChannelParams(PrefixString, Symbol(), Period());
PrevExtr_List.LoadExtremumList();

CurrExtr_List = PrevExtr_List;

NewExtr_List = new TExtremumList();
NewExtr_List.SetChannelParams(PrefixString, Symbol(), Period());

PrevExtr_List listesinde TExtremumList::LoadExtremumListyöntemini kullanarak global değişkenlerden uçdeğerler yüklüyoruz. Bu liste, uçdeğerleri yenileriyle karşılaştırmak için saklayacak ve bunlar da ekrandaki fiyat etiketlerini sürüklerken bir grafikten okunacaktır.

CurrExtr_List listesi geçerli bir liste olarak kullanılır, geçerli uçdeğerleri depolar. Başlangıçta sadece global değişkenlerden okunan uçdeğerlere sahip olduğumuz için, bunlar gerçek olanlar olarak alınır.

NewExtr_List listesinde grafikte bulunan yeni uçdeğerler yazacağız.

Göstergede kullanılan temel fonksiyonlara bir göz atalım. Birinci fonksiyon FindExtremumPoints, uçdeğerlerin konumunu belirleyen fiyat etiketlerinin parametrelerini okumak ve denetlemek için kullanılır:

bool FindExtremumPoints(long _chart_id)
{
  string  name;

//  1. Search for the total number of objects with specified parameters and write them to the list:
  int total_objects = ObjectsTotal(_chart_id, -1, OBJ_ARROW_LEFT_PRICE);
  if(total_objects <= 0)
  {
    return(false);
  }

  NewExtr_List.Clear();
  for(int i = 0; i < total_objects; i++)
  {
    name = ObjectName(_chart_id, i, -1, OBJ_ARROW_LEFT_PRICE);

    if( IsGraphicObjectGood(_chart_id, name, OBJ_ARROW_LEFT_PRICE, ExtremumPointColor) == true)
    {
      NewExtr_List.AddExtremum(ObjectGetInteger( _chart_id, name, OBJPROP_TIME),
                               ObjectGetDouble(_chart_id, name, OBJPROP_PRICE));
    }
  }

//  2. If three extremums are found, we can try to draw a channel:
  if(NewExtr_List.Total() == 3)
  {

//  Save the list of new extremums:
    NewExtr_List.SaveExtremumList();
    return(true);
  }

  NewExtr_List.Clear();
  return(false);
}

Her şeyden önce, NewExtr_List listesi TExtremumList::Clear yöntemi çağrılarak temizlenir ve daha sonra belirtilen parametrelere sahip tüm uçdeğer noktaları eklenir. Bulunan nokta sayısı üç ise, liste global değişkenlere kaydedilir ve fonksiyon ‘doğru’ çıkar.

Diğer CheakExtremumMoving fonksiyonu grafikteki uçdeğer noktalarının hareketini izler. En az bir nokta grafiğin zaman ekseni boyunca taşınırsa, bu fonksiyon ‘doğru’ çıkar.

Kodu aşağıda verilmiştir:

//---------------------------------------------------------------------
//  Check whether extremums have been moved on the screen:
//---------------------------------------------------------------------
bool CheakExtremumMoving()
{
  if(FindExtremumLines(0) == true)
  {
    int  count = NewExtr_List.Total();
    int  index;
    for(int i = 0; i < count; i++)
    {
      index = CurrExtr_List.FindExtremum(NewExtr_List.GetDateTime(i));

//  If a new extremum is found:
      if(index == -1)
      {
        PrevExtr_List = CurrExtr_List;
        CurrExtr_List = NewExtr_List;
        return(true);
      }
    }
    CurrExtr_List = PrevExtr_List;
  }

  return(false);
}

Manuel modda uçdeğer noktalarını ayarlamanın yolunu göz önünde bulundurduk. Bu süreci kontrol etmeyi ve noktaları global değişkenlere yazmayı sağlayan hazır göstergeye sahibiz. Göstergenin tam kodu ekli ExtremumHandSet.mq5 dosyasındadır. Şimdi ana kısma geçebiliriz - bir kanal çizme.


Kanal Çizme - Bazı Teoriler

Doğrusal bir kanal, kesinlikle uçdeğer noktalarından geçen iki paralel çizgiden oluşur. Buna ek olarak, bir çizgi iki noktadan geçmeli ve diğeri ilk çizgiye paralel olarak bırakılandan geçmelidir. Bu, basit bir resimde gösterilebilir:

Üç uçdeğer noktası kullanarak bir kanal çizme

Şekil 4. Üç uçdeğer noktası kullanarak bir kanal çizme

Geometriden bildiğimiz gibi, iki noktadan sadece bir düz çizgi çizilebilir. Bu çizgi Şekil 4’te kırmızı renktedir. Bu, aşağıdaki koordinatlara - (T1, P1) ve (T2, P2) - sahip iki noktadan gider; noktalar A ve B harfleriyle işaretlenmiştir. Bu çizginin denklemi şöyledir:

(1)   P(t) = P1 + (t - T1)*(P2 - P1) / (T2 - T1); P(t) burada 't' zamanında hesaplanan fiyattır.


C noktası (üçüncü uçdeğer) üzerinden, ilkine paralel başka bir düz çizgi çizmeliyiz. Bu çizgi Şekil 3’te yeşil renktedir. T1 ve T2 noktaları her iki çizgi için de aynı olduğundan, P1' ve P2' değerlerini bulmalıyız (bkz. şekil 4).

İlerlemeden önce önemli bir açıklama yapmamız gerekiyor. Terminal grafiği zaman "deliklerini" görüntülemez. Örneğin, tekliflerin terminale gelmediği tatil günleri fiyatların kırılması olarak görüntülenmelidir. Ve bunların böyle olmaması kötüdür. Boş bir grafiğe bakmanın ne anlamı var? Ancak, yukarıdaki denklemde mutlak zamanı kullanırsak, yanlış bir kanal elde ederiz.

Neyse ki, durum umutsuz değildir. Mutlak zamanı bir çubuğun göreli numarasına değiştirirsek, çubukların numaralandırmasında kırılmalar olamayacağından (pratik olarak, bu, bir fiyat dizisindeki bir dizindir) bu koordinatları bir kanal çizmek için kullanabiliriz.

Daha da ileri gider ve Şekil 4'teki A noktasının daima zaman ekseninin sıfır koordinatı (sıfır çubuğu) üzerinde yattığını varsayarsak, denklemimiz daha da kolaylaşacaktır. Dolayısıyla, T1=0, T3=B3,Т2=В2’dir. В3 ve В2 burada Т1 noktasına (yani sıfır noktası) göre bir çubuğun numaralarıdır. Bu varsayımın çizginin eğimine yol açmadığı açıktır. Daha sonra A ve B noktalarından geçen düz bir çizginin aşağıdaki denklemini elde ederiz:

(2)   P(n) = P1 + n * (P2-P1) / B2, burada P(n), 'n' numarasına sahip bir çubuk için hesaplanan fiyattır.


Yani, P1, P2, P3 ve B2, B3 değerlerini biliyoruz. Şimdi P1' ve P2 değerlerini bulmamız gerekiyor. İki denklemi birleştirip bunları çözerek, bilinmeyen değerleri bulabileceğimiz aşağıdaki formülleri elde ederiz:

(3)   P1' = P3 - B3 * (P2 - P1) / B2

(4)   P2' = P2 - P1 + P1'


P1' değerini bulup (4) formülüne ikame ettiğimizde P2' değerini alacağız. Şimdi bir kanal çizmenin teorik temellerine sahibiz. Bunu uygulamaya başlayalım.


Çizim Kanalı Sınırları - TChannelBorderObject Sınıfı

Bu sınıf standart CChartObjectTrend sınıfından türetilmiştir. Amacı, bir kanalın sınırlarıyla bağlantılı tüm parametreleri depolamanın yanı sıra sınır çizgilerini çizmek/silmek ve bu çizgilerin grafik parametrelerini kontrol etmektir.

Bu sınıfın açıklaması aşağıda verilmiştir:

class TChannelBorderObject : public CChartObjectTrend
{
//  General properties of a border:
private:
  bool             is_created;       // whether the graphical object is created on the screen
  long             chart_id;         // identifier of the chart window
  int              window;           // identifier of the subwindow

//  Parameters of a border line:
private:
  string           border_name;      // name of the border line
  color            border_color;     // color of the border line
  int              border_width;     // thickness of the border line
  ENUM_LINE_STYLE   border_style;     // style of the border line

//  Coordinates of a border:
private:
  datetime         point_left;       // time of the left point (T1)
  datetime         point_right;      // time of the right point (T2)
  double           price_left;       // price of the left point (P1)
  double           price_right;      // price of the right point (P2)

public:
  void     TChannelBorderObject();  // constructor
  void    ~TChannelBorderObject();  // destructor
  bool     IsCreated();             // check whether the line is created

//  Creating/deleting a line:
public:
  bool     CreateBorder(long _chart_id, int _window, string _name, datetime _t_left, datetime _t_right, 
                           double _p_left, double _p_right, color _color, int _width, ENUM_LINE_STYLE _style);
  bool     CreateBorder(long _chart_id, int _window, string _name, datetime _t_left, datetime _t_right, 
                           double _p_left, double _p_right);
  bool     CreateBorder(datetime _t_left, datetime _t_right, double _p_left, double _p_right);
  bool     RemoveBorder();          // delete line from the chart

//  Setting parameters of the line:
public:
  void     SetCommonParams(long _chart_id, int _window, string _name);
  bool     SetBorderParams(color _color, int _width, ENUM_LINE_STYLE _style);
  bool     SetBorderColor(color _color);
  bool     SetBorderWidth(int _width);
  bool     SetBorderStyle(ENUM_LINE_STYLE _style);

//  Getting values on the line:
  double   GetPrice(datetime _dt); // get price value in the specified position of the border line
};

Bu sınıfın bazı özel yorumlara gereksinimi yoktur.

Sadece belirtilen bir noktada sınır fiyatını alma yöntemine dikkat edelim:

//---------------------------------------------------------------------
//  Get price value in the specified position of the border line:
//---------------------------------------------------------------------
double TChannelBorderObject::GetPrice(datetime _dt)
{
//  If the graphical object is created:
  if(is_created == true)
  {
    return(ObjectGetValueByTime( chart_id, border_name, _dt));
  }
  return(0.0);
}

ObjectGetValueByTime terminalinin fonksiyonu burada kullanılır; belirtilen bir süre için fiyat değerini döndürür. Matematiksel bir formül kullanarak değeri hesaplamak yerine terminal olasılıklarını kullanmak uygundur.


Kanal Çizme - TSlideChannelObject Sınıfı

Bu sınıf standart CList sınıfından türetilmiştir. Amacı aşağıdaki gibidir:

  • TChannelBorderObject sınıfının nesnelerini depolama ve bunlarla farklı eylemler gerçekleştirme;
  • kanal oluşturan gerekli çizgileri çizmek için noktaları hesaplama;
  • bir kanalın parametrelerini depolama ve değiştirme;
  • çizilmiş bir kanalı tanımlayan hesaplanan değerleri alma (yüksekliği, sınırlardaki fiyat değerleri vb.);

Bu sınıfı tanımlayan kod burada tamamen gösterilemeyecek kadar büyüktür. İsteyenler bunu makaleye iliştirilmiş SlideChannelClasses.mqh dosyasında görebilir. Bunun bazı ana kısımlarını analiz edelim.

Her şeyden önce, sırasıyla T2 ve T3 noktalarında B2 ve B3 değerlerini alıyor (bkz. şekil 4). Aşağıdaki kod kullanılır:

//  Get relative shifts in bars relatively to the extremum points:
  total_bars = Bars(symbol, time_frame);     // total number of bars in history
  if(total_bars == 0)
  {
    return(false);                           // channel cannot be drawn
  }
  double  B2 = Bars(symbol, time_frame, point_left, point_right);
  double  B3 = Bars(symbol, time_frame, point_left, point_middle);

Olmayan çubukları çağırma durumunu önlemek için, belirtilen bir sembol ve nokta için geçmişteki çubukların numarasını veren Çubuklar terminal fonksiyonunu kullanırız. Bilgiler henüz oluşturulmamışsa, fonksiyon bir sıfır değerini verir; bu, kontrol etmek için kullanılır.

Fonksiyon bir sıfır olmayan değer verirse, В2 ve В3 değerlerini alabiliriz. Aynı Çubuklar fonksiyonu kullanılarak, fakat bunu başka formda çağırarak yapılır. Zaman sınırları belirler ve bu aralıktaki çubuk sayısını alırız. Sol sınırımız aynı olduğundan, Т2 ve Т3 noktaları için çubuklarda kayma elde ederiz. Т1 noktasının kayması her zaman sıfıra eşittir.

Artık kanal çizgilerinin tüm noktalarını hesaplayabiliriz. Kanalımız orta çizgiyi ve sınırların ve orta çizginin etrafındaki yüzde bölgelerinin çizgilerini (üst ve alt sınırlara ek olarak) görüntüleyeceği için, bunlardan maksimum dokuz tane olabilir.


Hesaplamanın ana kısmını analiz edelim. Hesaplamanın tamamı TSlideChannelObject::CalcChannelyöntemindedir.

//  Coefficient of the line inclination:
  koeff_A = (price_right - price_left) / B2;

//  Price value on the AB line in the point T3:
  double  P3_AB = price_left + B3 * koeff_A;

// Determine the channel type - 2MAX_1MIN или 1MAX_2MIN:
  if(P3_AB > price_middle)              // 2MAX_1MIN
  {
    channel_type = CHANNEL_2MAX_1MIN;

    left_prices[BORDER_UP_INDEX] = price_left;
    right_prices[BORDER_UP_INDEX] = price_right;
        
    left_prices[BORDER_DN_INDEX] = price_middle - B3 * koeff_A;
    right_prices[BORDER_DN_INDEX] = left_prices[BORDER_DN_INDEX] + (price_right - price_left);
  }
  else if(P3_AB < price_middle)         // 1MAX_2MIN
  {
    channel_type = CHANNEL_1MAX_2MIN;

    left_prices[BORDER_DN_INDEX] = price_left;
    right_prices[BORDER_DN_INDEX] = price_right;
        
    left_prices[BORDER_UP_INDEX] = price_middle - B3 * koeff_A;
    right_prices[BORDER_UP_INDEX] = left_prices[BORDER_UP_INDEX] + (price_right - price_left);
  }
  else
  {
    return( false );                      // channel cannot be drawn (all extremums are on the same line)
  }

Buradaki left_prices ve right_prices kanalın çizgisinin fiyat koordinatlarını depolayan dizilerdir. Kanalın tüm çizgilerinin zaman koordinatı zaten bilinmektedir.

Başlangıçta, çizgi eğiminin katsayısını belirleyin (bkz. formül (2)) koeff_A. Daha sonra T3 noktasında AB çizgisinin fiyat değerini hesaplıyoruz (bkz. şekil 4). Çizim için hangi kanal türünün çizim için belirtildiğini belirlemek için - iki maksimum ve bir minimum veya iki minimum ve bir maksimum ile - yapılır. Fiyat ekseninde hangi noktanın daha yüksek olduğunu kontrol ediyoruz - C noktası veya (P3', T3) koordinatlarına sahip nokta. Konumlarına bağlı olarak, kanalın birinci veya ikinci türe sahip olup olmadığını belirleriz.

Kanalın iki ana çizgisinin koordinatları (üst ve alt) belirlenir belirlenmez, diğer yedi çizginin koordinatlarının hesaplanması zor bir şey değildir. Örneğin, kanalın üst ve alt sınırlarının koordinatlarını kullanarak orta çizginin koordinatlarını aşağıdaki şekilde hesaplarız:

  left_prices[BORDER_MD_INDEX] = (left_prices[BORDER_DN_INDEX] + left_prices[BORDER_UP_INDEX ]) / 2.0;
  right_prices[BORDER_MD_INDEX] = (right_prices[BORDER_DN_INDEX] + right_prices[BORDER_UP_INDEX]) / 2.0;

Kanalın üst ve alt sınırlarından ortalama değeri almak yeterlidir.


Belirtilen Uçdeğerlere Göre Kanal Çizme Göstergesi - SlideChannel

Pekala, bir kanal çizmek için zaten sınıfımız var. Şimdi global değişkenlerden uçdeğerlerin parametrelerini okuyacak ve bir grafikte bir kanal çizecek bir gösterge yazalım. Aşağıdaki gibi görünecektir:

Şekil 5. Uçdeğerler kullanılarak çizilen bir kanal örneği

Şekil 5. Uçdeğerler kullanılarak çizilen bir kanal örneği

Çizilen kanalla ilgili bilgiler de burada görüntülenir - genişliği, mevcut fiyattan kanal sınırlarına ve orta çizgiye doğru olan noktalardaki mesafesi.

Gerekli kitaplıkları bağlayalım:

#include  <TextDisplay.mqh>
#include  <SlideChannelClasses.mqh>

Birinci kitaplık, metin bilgilerinin ekranda görüntülenmesinin düzenlenmesine yönelik sınıfları içerir (bkz. "Standart Kitaplık Sınıflarını kullanarak kendi Market Saatinizi oluşturma" makalesi). Bunu kullanarak, geçici uçdeğer noktalarının değerlerini görüntüleyeceğiz.

Ardından göstergenin giriş parametrelerini ekleyin (sadece temel olanlar burada açıklanmaktadır):

input string          PrefixString = "MainChannel";
//---------------------------------------------------------------------
input ENUM_TIMEFRAMES  ExtremumTimeFrame = PERIOD_CURRENT;
//---------------------------------------------------------------------
input bool            ShowInfo = true;

İlk parametre PrefixString, ExtremumHandSet göstergesinde olduğu gibi, uçdeğerleri okurken global değişkenlerin adını besteleme için kullanılan bir önek ayarlar. Ayrıca, tek bir grafikte bu tür birkaç göstergeyi kullanma imkanı verir. Yapılacak tek şey bunlar için farklı önekler ayarlamaktır.

ExtremumTimeFrame parametresi, global değişkenlerden uçdeğer noktalarını okumak için kullanılacak bir zaman dilimi ayarlar. Çok kullanışlı bir parametredir. Farklı zaman dilimlerinde senkron kanallar çizmeyi sağlar. Örneğin, uçdeğerleri H1'den ayarlarsanız, aynı kanalı M5 zaman diliminde çizebilirsiniz. Bunu yapmak için, sadece M5 grafiğine kanal çizme göstergemizi ekleyin ve tüm değişiklikleri senkronize bir şekilde görüntüleyecektir.

ShowInfo parametresi, kanalın parametreleri hakkındaki metin bilgilerinin ekranda görüntülenmesini kontrol eder.

Ardından, bilgileri görüntülemek ve kanalı çizmek için nesneler oluşturun:

TableDisplay         ChannalDisplay;  // displaying of general information about a channel on the screen
TableDisplay         BordersDisplay;  // displaying information about the borders of a channel on the screen
//---------------------------------------------------------------------
TSlideChannelObject  Channel;         // drawing of a channel

Kanal çizme nesnesi aşağıdaki şekilde başlatılır:

  Channel.CreateChannel(PrefixString, 0, 0, Symbol(), period_current, curr_left_point, curr_middle_point, 
                        curr_right_point, curr_left_price, curr_middle_price, curr_right_price);
  Channel.SetBorderWidth(BorderWidth );
  Channel.SetmiddleWidth(middleLineWidth);
  Channel.SetUpBorderColor(UpBorderColor);
  Channel.SetDnBorderColor(DnBorderColor);
  Channel.SetmiddleColor(middleLineColor );
  Channel.ShowBorderZone(ShowBorderPercentageLines);
  Channel.BorderZonePercentage( PercentageZoneSize);
  Channel.Showmiddle(ShowmiddleLine);
  Channel.ShowmiddleZone( ShowmiddlePercentageLines);
  Channel.middleZonePercentage(PercentagemiddleZoneSize);

Burada ilk başta, TSlideChannelObject::CreateChannel yöntemini çağırarak bir kanal oluşturuyoruz ve ardından kanal çizgisinin gerekli parametrelerini ayarlıyoruz. Ayar sırası önemli değildir, tam tersini yapabilirsiniz - parametreleri ayarlayın ve sonra kanalı oluşturun.

period_current parametresi, global değişkenlerden uçdeğerleri okurken kullanılan dönemdir. Geçerli bir grafiğin döneminden farklı olabilir.

Göstergede kullanılan temel fonksiyonlara bir göz atalım. Birinci fonksiyon GetExtremums, uçdeğerlerin konumunu okumak ve kanalı elde edilen değerlere göre yenilemek için kullanılır:

void GetExtremums()
{
  double  temp;
  string  name;

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr1");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_left_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr2");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_middle_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr3");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_right_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_Price_Extr1");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_left_price = temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol( ), "_", period_current, "_Price_Extr2");
  if( GlobalVariableGet(name, temp) != false )
  {
    curr_middle_price = temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_Price_Extr3");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_right_price = temp;
  }

//  Update the position of channel:
  Channel.SetExtremums(curr_left_point, curr_middle_point, curr_right_point, 
                       curr_left_price, curr_middle_price, curr_right_price);
}

Ekrandaki kanalı yenilemek için TSlideChannelObject::SetExtremums yöntemini kullanıyoruz. Bu yöntem, kanal çizgilerinin koordinatlarını yeniden hesaplar ve ekrandaki kanalı yeniden çizer.

Aşağıdaki videoda farklı zaman dilimlerinde bir kanal çizme örneği gösterilmiştir:


Başlangıç göstergelerinin sırası gerçekten önemli değildir, ancak ilk başta ExtremumHandSet göstergesini başlatmak, ardından sarı rengin üç sol fiyat etiketini eklemek (etiketlerin rengi gösterge parametrelerinde ayarlanır, sarı renk varsayılan olarak ayarlanır) ve kanalı belirtilen uçdeğerlerle çizen SlideChannel göstergesini başlatmak mantıklıdır.

Bir kanalın birinci grafiğin uçdeğerleriyle eş zamanlı olarak çizilmesi için, SlideChannel göstergesinin ExtremumTimeFrame parametresinde zaman dilimini uçdeğerlerin ayarlandığı grafiğinkiyle aynı şekilde ayarlamanız gerekir.

Bu, kanalın uçdeğer noktalarını ayarlama fonksiyonunu terminal ekranındaki çiziminin fonksiyonundan ayırmanın sonucudur.


Sonuç

Ekrandaki bir kanalın konumunu ayarlamaktan çizimine kadar tüm döngüyü göz önünde bulundurduk. Özellikle standart sınıfları OOP'yi kullanırken her şeyin o kadar da karmaşık olmadığı ortaya çıktı.

Ancak bir arayış vardır: kanalları piyasada çalışmak için nasıl kullanmalıyız. İlk olarak, bir finansal aracın mevcut durumunun teknik analizi için gereklidirler. İkincisi, analizden sonra, bunlar karar vermek için gereklidirler. Kanallar bu konuda çok yardımcı olabilir.

Bir pozisyonu açmak veya kapatmak için bir kanalın sınırlarını analiz edecek yarı otomatik bir Uzman Danışman (EA) geliştirmek mümkündür. Hem bir sınırı aşarak hem de sınırdan geri dönerek çalışabilir. Bu bir sonraki makalenin konusu olacaktır - Kanalla Çalışma Yöntemleri - Geri Alma ve Aşma.

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

Ekli dosyalar |
extremumclasses.mqh (12.58 KB)
extremumhandset.mq5 (11.89 KB)
slidechannel.mq5 (13.7 KB)
textdisplay.mqh (15.21 KB)
Alım Satım Modellerine Dayalı Çoklu Uzman Danışmanlar Oluşturma Alım Satım Modellerine Dayalı Çoklu Uzman Danışmanlar Oluşturma
MQL5'te nesne yönelimli yaklaşımı kullanmak, çoklu para birimli/çoklu sistemli/çoklu zaman dilimli Uzman Danışmanların oluşturulmasını büyük ölçüde basitleştirir. Tek bir EA ile birkaç düzine alım satım stratejisinde, mevcut tüm araçlarda ve olası tüm zaman dilimlerinde işlem yapabildiğini hayal edin! Buna ek olarak, EA test edicide kolayca test edilir ve bileşimine dâhil edilen tüm stratejiler için bir veya birkaç para yönetimi çalışma sistemine sahiptir.
MetaTrader 5’te Paralel Hesaplamalar MetaTrader 5’te Paralel Hesaplamalar
İnsanlık tarihi boyunca zaman büyük bir değer olmuştur ve bunu gereksiz şekilde israf etmemeye çalışıyoruz. Bu makale, bilgisayarınız çok çekirdekli bir işlemciye sahipse Uzman Danışmanınızın (EA) çalışmasını nasıl hızlandıracağınızı açıklayacaktır. Ayrıca, önerilen yöntemin uygulaması MQL5 dışında başka hiçbir dilin bilinmesini gerektirmez.
Mikro, Orta ve Ana Eğilimlerin Göstergeleri Mikro, Orta ve Ana Eğilimlerin Göstergeleri
Bu makalenin amacı, James Hyerczyk'in “Pattern, Price & Time: Use Gann Theory in Trading Systems” (Model, Fiyat ve Zaman: Alım Satım Sistemlerinde Gann Teorisini Kullanmak) adlı kitabında göstergelere ve Uzman Danışmanlara yönelik verilen bazı fikirler doğrultusunda alım satım otomasyonunun olanaklarını ve analizini araştırmaktır. Kapsamlı bir makale olmamakla birlikte burada sadece Gann teorisinin ilk bölümünü, yani Modeli araştırıyoruz.
CChartObject sınıfına dayalı yeni GUI pencere öğelerinin tasarlanması ve uygulanması CChartObject sınıfına dayalı yeni GUI pencere öğelerinin tasarlanması ve uygulanması
GUI arayüzlü yarı otomatik Uzman Danışman (EA) üzerine önceki makaleyi yazdıktan sonra arayüzün daha karmaşık göstergeler ve Uzman Danışman (EA) için bazı yeni işlevlerle geliştirilmesinin istendiği ortaya çıktı. MQL5 standart kitaplık sınıfları ile tanıştıktan sonra yeni pencere öğelerini uyguladım. Bu makale, göstergelerde ve Uzman Danışmanlarda (EA) kullanılabilecek yeni MQL5 GUI pencere öğelerini tasarlamaya ve uygulamaya yönelik bir işlemi açıklamaktadır. Makalede sunulan pencere öğeleri CChartObjectSpinner, CChartObjectProgressBar ve CChartObjectEditTable’dır.