
Çizim Kanalları - İçeriden ve Dışarıdan Görünüm
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
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
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
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:
Ş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
Ç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





- Ücretsiz alım-satım uygulamaları
- İşlem kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Gizlilik ve Veri Koruma Politikasını ve MQL5.com Kullanım Şartlarını kabul edersiniz