English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
Bir grafikte birden fazla gösterge (Bölüm 02): Kodlamaya başlangıç

Bir grafikte birden fazla gösterge (Bölüm 02): Kodlamaya başlangıç

MetaTrader 5Örnekler | 4 Temmuz 2022, 16:29
165 0
Daniel Jose
Daniel Jose

Giriş

Bu makale serisinin bir önceki bölümünde, ekranı çok fazla ayrıntıyla doldurmadan bir grafikte birden fazla göstergenin nasıl kullanılabileceğinin kavramlarından ve temellerinden bahsettim. O yazının amacı sistemin kendisini tanıtmak, veritabanlarının nasıl oluşturulacağını ve bu veritabanlarından nasıl yararlanılacağını göstermekti, sistemin kaynak koduna değinmemiştim. Bu makalede kodu uygulamaya başlayacağız ve sonraki makalelerde de sistemin işlevselliğini genişleterek onu daha eksiksiz ve çok yönlü hale getireceğiz, çünkü bu sistem, büyük gelişme potansiyeline sahip, ilerleme vaat eden bir sistemdir.


Planlama

Anlama kolaylığı ama hepsinden önemlisi sistemi genişletilebilir kılmak için, ana kod OOP (Object Oriented Programming, Nesne Yönelimli Programlama) ilkeleri kullanılarak oluşturulmuş ve iki ayrı dosyaya bölünmüştür. Bütün bunlar sistemin sürdürülebilir, güvenli ve istikrarlı bir şekilde gelişmesini sağlar.

İlk adımda, gösterge kullanacağız, bu amaçla bir gösterge oluşturalım:

Neden başka bir dosya türü değil de gösterge kullanıyoruz? Bunun nedeni, göstergeyle alt pencere oluştururken ek dahili mantık uygulamamıza gerek olmamasıdır - göstergeye bu amaç doğrultusunda direkt olarak talimat verebiliyoruz, bu da bize zaman kazandırıyor ve sistemin geliştirilmesini hızlandırıyor. Göstergemizin headerı şu şekilde görünecek:

#property indicator_plots 0
#property indicator_separate_window


Sadece bu iki satırla sembol grafiği üzerinde bir alt pencere oluşturabiliriz (nasıl çalıştığını bilmeyenler için lütfen aşağıdaki tabloya bakınız):

Kod Açıklama
indicator_plots 0 Bu satır derleyiciye herhangi bir verinin oluşturulmayacağını söyler ve böylece derleyicinin uyarı mesajları yazdırmasını önler.
indicator_separate_window Bu satır, derleyiciye alt pencereyi oluşturmak için gerekli mantığı eklemesini söyler.

Basit, değil mi? Programlamaya aşina olmayanlar için, kaynak koddaki bazı şeyler garip görünebilir, ancak bunlar sadece tüm programlama topluluğu tarafından kabul edilen ve yaygın olarak kullanılan protokolleri takip ederler. MetaTrader 5, ufak farklılıklar dışında C++ ile neredeyse aynı olan MQL5'i kullandığından, C++'da kullandığımız programlama şeklinin aynısını burada da kullanabiliriz. Bu, işleri çok daha kolay hale getirmektedir. Dolayısıyla, bu gerçeği kullanarak, aşağıdaki C dili yönergesini kullanabiliriz:

 #include <Auxiliary\C_TemplateChart.mqh>

Bu yönerge, derleyiciye belirli bir konumda bulunan header dosyasını dahil etmesini (include) söyler. Ancak peki tam yol, Include\Auxiliary\C_TemplateChart.mqh şeklinde olmamalı mıydı? Evet, bu tam yoldur, ancak MQL5 herhangi bir header dosyasının 'Include' klasöründe bulunması gerektiğini zaten biliyor olduğundan ilk kısmı atlayabiliriz. Yol açılı parantez içine alınmışsa, mutlaktır, tırnak içine alınmışsa, görecelidir, yani <Auxiliary\C_TemplateChart.mqh>, "Auxiliary\C_TemplateChart.mqh" öğesinden farklıdır. Bu her şeyi değiştiren basit bir ayrıntıdır.

Aşağıdaki satırlarla kodu yazmaya devam edelim:

input string user01 = "" ;       //Used indicators
input string user02 = "" ;       //Assets to follow


Burada string tipi değerler girdi olarak girilebilir. Göstergenin açılışında hangi komutu kullanmak istediğinizi net olarak biliyorsanız, buraya varsayılan değeri belirtebilirsiniz. Örneğin, her zaman çizgi genişliği 3 olan RSI ve çizgi genişliği 2 olan MACD kullanmak istiyorsanız, bu komutların varsayılan olması için ilgili satırları aşağıdaki gibi belirtin:

input string user01 = "RSI:3;MACD:2" ;  //Used indicators
input string user02 = "" ;              //Assets to follow


Bu, daha sonra komutu değiştirmemizi engellemeyecektir, ancak varsayılan değer, komutu kullanmak için önceden yapılandırılmış olacağından gösterge açılırken kolaylık sağlar. Bir sonraki satır, tüm "ağır" kodu içeren nesne sınıfına erişebileceğimiz bir ikinci ad oluşturacaktır, bu, public fonksiyonlara erişmemize olanak sağlayacaktır.

C_TemplateChart SubWin;

Özel gösterge dosyasının içerisindeki kodumuz neredeyse hazır; her şeyi tam anlamıyla hazır ve çalışır hale getirmek için sadece 3 satır daha eklememiz gerekiyor. Nesne sınıfımızın hata içermediği elbette açık ama bu makalede bunu da kod tarafından değerlendireceğiz. Bu nedenle, gösterge dosyası üzerinde çalışmayı bitirmek için aşağıda gösterildiği gibi yeşil ile vurgulanan satırları eklememiz gerekecek:

 //+------------------------------------------------------------------+
int OnInit ()
{
         SubWin.AddThese(C_TemplateChart::INDICATOR, user01);
         SubWin.AddThese(C_TemplateChart::SYMBOL, user02);

         return INIT_SUCCEEDED ;
}
//+------------------------------------------------------------------+

//...... other lines are of no interest to us ......

//+------------------------------------------------------------------+
void OnChartEvent ( const int id,
                   const long &lparam,
                   const double &dparam,
                   const string &sparam)
{
         if (id == CHARTEVENT_CHART_CHANGE ) SubWin.Resize();
}
//+------------------------------------------------------------------+


Böylece özel gösterge dosyası hazır durumda. Şimdi nesne sınıfımızı içeren dosyanın kara kutusuna daha yakından bakmamız gerekiyor. Şu andan itibaren, dikkat iki fonksiyona odaklanmalıdır, ancak işleri kolaylaştırmak adına öncelikle nesne sınıfımızda bulunan fonksiyonlara bakalım ve her birinin ne için kullanıldığını görelim.

Fonksiyonlar Açıklama
SetBase Gösterge verilerini görüntülemek için gereken nesneyi oluşturur
decode Kendisine iletilen komutun kodunu çözer
AddTemplate Sunulan verinin türüne göre ayarlamalar yapar
C_Template Varsayılan sınıf oluşturucu
~ C_Template Sınıf yıkıcı
Resize Alt pencerenin ölçeğini değiştirir
AddThese Dahili nesnelere erişmek ve bunları oluşturmaktan sorumlu fonksiyon

Bu kadar. Özel göstergemizde Resize ve AddThese fonksiyonlarını kullandığımızı fark etmişsinizdir. Yalnızca bunlar şu anda nesnemizdeki public olan fonksiyonlardır, bu yüzden endişelenmemize gerek yok, çünkü diğer her şey nesnemizin içerisinde gizlidir, bu onların gereksiz yere değiştirilmemelerini garanti eder. Bu, son kodumuza yüksek derecede güvenilirlik sağlar. Aşağıdaki tanımla başlayan kodla devam edelim:

 #define def_MaxTemplates         6

Bu satır, nesne sınıfımız için çok önemlidir - oluşturulabilecek maksimum işaretçi sayısını tanımlar. Daha fazla veya daha az eklemek istiyorsak, bu sayıyı değiştirmemiz yeterlidir. Bu basit çözümle dinamik bellek tahsisi elde ediyoruz ve gösterge sayısını sınırladığımız için de işler çok daha kolay hale geliyor. Muhtemelen, gerçekten değiştirmek isteyebileceğiniz tek yer burası, ancak çoğu insan ve kullandıkları monitörler için 6'nın uygun bir sayı olduğunu düşünüyorum.

Sonraki satır, programın bazı noktalarında verileri yönetmeyi kolaylaştıran numaralandırmadır:

 enum eTypeChart {INDICATOR, SYMBOL};

Bu satırın sınıfımızın içerisinde bulunması, farklı bir sınıfta da aynı isme sahip numaralandırma olabileceğinden, numaralandırma dahilinde belirtilen verilerin sadece bu nesne sınıfına ait olacağını garanti eder. Bu nedenle, bu numaralandırmaya doğru şekilde erişmek için özel gösterge dosyamızın OnInit fonksiyonunda sağlanan formu kullanmalıyız. Sınıf adı atlanırsa, sözdizimi hatası olarak kabul edilecek ve kod derlenmeyecektir. Sonraki satır ayrılmış kelimedir.

 private :


Bu satır, bundan sonraki her şeyin bu nesne sınıfına özel olacağını ve sınıfın dışından görünemeyeceğini belirtir. Yani, bu satırın devamındaki herhangi bir şeye erişim sınıfın içinde olmadığınız sürece imkansız olacaktır. Bu, sınıfa özel verileri başka hiçbir yerden erişilemez hale getirerek kod güvenliğini artırır. Aşağıdaki satırlar, sınıfımızın ilk gerçek fonksiyonuna ulaşana kadar bazı dahili ve özel değişkenleri bildirir.

 void SetBase( const string szSymbol, int scale)
{
#define macro_SetInteger(A, B) ObjectSetInteger (m_Id, m_szObjName[m_Counter], A, B)

...

         ObjectCreate (m_Id, m_szObjName[m_Counter], OBJ_CHART , m_IdSubWin, 0 , 0 );
         ObjectSetString (m_Id, m_szObjName[m_Counter], OBJPROP_SYMBOL , szSymbol);
        macro_SetInteger( OBJPROP_CHART_SCALE , scale);
...
        macro_SetInteger( OBJPROP_PERIOD , _Period );
        m_handle = ObjectGetInteger (m_Id, m_szObjName[m_Counter], OBJPROP_CHART_ID );
        m_Counter++;
#undef macro_SetInteger
};


Bu SetBase kod segmentini daha ayrıntılı olarak ele alalım. Makroyu bildirerek başlıyoruz - bu, derleyiciye makro adıyla basitleştirilmiş kodun nasıl yorumlanması gerektiğini söyler. Yani bir şeyi birkaç kez tekrarlamamız gerekiyorsa, daha basit olarak sonucu elde etmek için C dilinin bu özelliğini kullanabiliriz. Bir şeyi değiştirmek zorunda kalırsak da, bunu sadece makroda yaparız. Bu, işi büyük ölçüde hızlandırır ve yalnızca bir veya başka bir argümanın değiştirileceği kodlarda hata olasılığını azaltır.

Bunu yaparken, CHART türünde bir nesne oluşturuyoruz. Bu garip görünebilir. Bir şeyleri değiştirmek için değiştirilemeyecek bir şeyi mi kullanacağız? Evet öyle. Bir sonraki adım, kullanılacak varlığın bildirilmesidir. Buradaki ilk nokta: grafik ayarları kaydedildiği sırada herhangi bir varlık mevcut değilse, nesnenin ilişkilendirildiği varlık, kullanılacak varlık olacaktır. Grafik ayarları kaydedildiği sırada varlık mevcutsa, ilgili varlık kullanılacaktır. Önemli detay: farklı bir varlık belirleyebilir ve onu genel ayarlarla kullanabilirsiniz, ancak bunu bir sonraki makalede daha ayrıntılı olarak açıklayacağım. Çünkü şu anda mümkün olmayan şeyleri yapabilmek için bu kodda bazı iyileştirmeler uygulayacağız. Ardından, OBJPROP_CHART_SCALE özelliğinde belirtilen veri yoğunluğu seviyesi mevcuttur. Burada, 0 ile 5 arasındaki değerleri kullanacağız. Bu aralığın dışındaki değerleri kullanabiliriz ancak yine de bu aralıkta kalmak daha iyidir.

Dikkat edilmesi gereken bir sonraki şey OBJPROP_PERIOD özelliğidir. Lütfen mevcut grafiğin zaman dilimini kullandığımızı ve onu değiştirirsek bunun da değişeceğini unutmayın. Gelecekte, onu sabitleyecek bazı değişiklikler yapacağız. Ancak denemek isterseniz, MetaTrader 5’te tanımlı zaman dilimini kullanabilirsiniz, örneğin, verilerin 10 dakikalık zaman diliminde görüntülenmesini sağlayan PERIOD_M10. Ancak bunu daha sonra geliştireceğiz. Sonrasında alt gösterge sayısını birer birer artırıp makroyu yok ediyoruz. Yani artık bir temsili olmayacak ve başka bir yerde kullanılmak üzere yeniden tanımlanması gerekecek. Bir şeyi unutmadım mı! Evet, bu satır belki de bu kod parçasının en önemli kısmı.

m_handle = ObjectGetInteger (m_Id, m_szObjName[m_Counter], OBJPROP_CHART_ID );

Bu satır, aslında işaretçi olmasa da, işaretçi olarak kabul edilebilecek bir şey yakalar, bu, oluşturduğumuz OBJ_CHART nesnesi üzerinde bazı ekstra ayarlamalar yapmamıza olanak sağlar. Nesnenin içerisinde bazı ayarları uygulayabilmek için bu değere ihtiyacımız var. Daha önce oluşturduğumuz ayarlar dosyasında bulunurlar. Koda devam edelim, aşağıda tam halde görülebilen fonksiyondayız:

 void AddTemplate( const eTypeChart type, const string szTemplate, int scale)
{
	if (m_Counter >= def_MaxTemplates) return ;
	if (type == SYMBOL) SymbolSelect (szTemplate, true );
	SetBase((type == INDICATOR ? _Symbol : szTemplate), scale);
	ChartApplyTemplate (m_handle, szTemplate + ".tpl" );
	ChartRedraw (m_handle);
}


İlk önce yeni bir gösterge eklemenin mümkün olup olmadığını kontrol ediyoruz. Mümkünse, SYMBOL olup olmadığını kontrol ediyoruz, eğer öyleyse, SYMBOL, Piyasa Gözlemi penceresinde bulunması gerektiğinden onun varlığını denetliyoruz. Bunu dayalı olarak bilgi alacak bir nesne oluşturuyoruz. Şablon yürütüldükten sonra OBJ_CHART'a uygulanır ve işte sihir o zaman gerçekleşir: nesneyi tekrar çağırırız, ancak şimdi nesne, OBJ_CHART'ı tanımlamak için kullanılan ayarlar dosyasında bulunan tanımlara göre verileri içerecektir. Basit, güzel ve anlaşılır.

Bu iki fonksiyonu kullanarak çok şey yapılabilir. Ancak en az bir fonksiyona daha ihtiyacımız var - tam kodu aşağıda gösterilmektedir:

 void Resize( void )
{
         int x0 = 0 , x1 = ( int )( ChartGetInteger (m_Id, CHART_WIDTH_IN_PIXELS , m_IdSubWin) / (m_Counter > 0 ? m_Counter : 1 ));
         for ( char c0 = 0 ; c0 < m_Counter; c0++, x0 += x1)
        {
                 ObjectSetInteger (m_Id, m_szObjName[c0], OBJPROP_XDISTANCE , x0);
                 ObjectSetInteger (m_Id, m_szObjName[c0], OBJPROP_XSIZE , x1);
                 ObjectSetInteger (m_Id, m_szObjName[c0], OBJPROP_YSIZE , ChartGetInteger (m_Id, CHART_HEIGHT_IN_PIXELS , m_IdSubWin));
        }
         ChartRedraw ();
}

Yukarıdaki fonksiyonun yaptığı, her şeyi bulunduğu yere koyması ve verileri her zaman alt pencere alanı içerisinde tutmasıdır. Bu fonksiyon için başka söyleyecek bir şey yok. Böylece her şeyin kusursuz çalışması için gerekli tüm kodları bitirdik. Peki ya diğer fonksiyonlar?! İçiniz rahat olsun, fonksiyonların geri kalanına aslında hiç gerek yok, yalnızca komut satırlarının yorumlanmasını desteklerler. Şimdi, gelecekte bu kodu değiştirmek isteyen herkes için önemli olan şeye bakalım. Nesne sınıfı kodumuzda bulunan ayrılmış kelime:

 public   :

Bu kelime, buradan itibaren ki tüm verilere ve fonksiyonlara nesne sınıfının bir parçası olmasalar bile kodun diğer bölümleri tarafından erişilip görüntülenebilmesini sağlar. Yani burada diğer nesneler tarafından gerçekte neyin değiştirilebileceğini veya erişilebileceğini bildiriyoruz. Aslında, iyi bir nesne yönelimli kodun davranışı, nesnenin verilerine asla doğrudan erişime izin vermez. İyi tasarlanmış bir kodda, yalnızca metotlara erişimimiz olur. Bunun nedeni basit - güvenlik. Harici kodun sınıf içerisindeki verileri değiştirmesine izin verdiğimizde, verilerin nesnenin beklediğiyle eşleşmeme riskini alırız ve bu, tutarsızlıkları veya kusurları çözmeye çalışırken her şey doğru görünmesine rağmen birçok soruna ve baş ağrısına neden olur. İşte yıllardır C++ ile programlama yapan biri olarak verebileceğim bazı tavsiyeler: Harici nesnelerin, oluşturduğunuz sınıftaki verileri değiştirmesine veya doğrudan erişmesine ASLA izin vermeyin. Verilere erişilebilmesi için fonksiyonlar veya kod parçaları sağlayın, ancak verilere doğrudan erişime asla izin vermeyin ve fonksiyonların ve kod parçalarının, oluşturduğunuz sınıfın beklediği şekilde verileri işlediğinden emin olun. Bunu akılda tutarak, biri public (AddThese) ve diğeri private (Decode) olan son iki fonksiyona geçelim. Bunları aşağıda tam halde görebilirsiniz:

void Decode( string &szArg, int &iScale)
{
#define def_ScaleDefault 4
         StringToUpper (szArg);
        iScale = def_ScaleDefault;
         for ( int c0 = 0 , c1 = 0 , max = StringLen (szArg); c0 < max; c0++) switch (szArg[c0])
        {
                 case ':' :
                         for (; (c0 < max) && ((szArg[c0] < '0' ) || (szArg[c0] > '9' )); c0++);
                        iScale = ( int )(szArg[c0] - '0' );
                        iScale = ((iScale > 5 ) || (iScale < 0 ) ? def_ScaleDefault : iScale);
                        szArg = StringSubstr (szArg, 0 , c1 + 1 );
                         return ;
                 case ' ' :
                         break ;
                 default :
                        c1 = c0;
                         break ;
        }
#undef def_ScaleDefault
}
//+------------------------------------------------------------------+
// ... Codes not related to this part...
//+------------------------------------------------------------------+
void AddThese( const eTypeChart type, string szArg)
{
         string szLoc;
         int i0;
         StringToUpper (szArg);
         StringAdd (szArg, ";" );
         for ( int c0 = 0 , c1 = 0 , c2 = 0 , max = StringLen (szArg); c0 < max; c0++) switch (szArg[c0])
        {
                 case ';' :
                         if (c1 != c2)
                        {
                                szLoc = StringSubstr (szArg, c1, c2 - c1 + 1 );
                                Decode(szLoc, i0);
                                AddTemplate(type, szLoc, i0);
                        }
                        c1 = c2 = (c0 + 1 );
                         break ;
                 case ' ' :
                        c1 = (c1 >= c2 ? c0 + 1 : c1);
                         break ;
                 default :
                        c2 = c0;
                         break ;
        }
}


Bu iki fonksiyon tam olarak yukarıda açıkladığım şeyi yapar: Tutarsız verilerin sınıfın dahili verilerinin bir parçası olmasını önleyerek nesne sınıfının içerisinde veri bütünlüğünü garanti ederler. Bir komut satırı alırlar ve önceden tanımlanmış sözdizimini izleyerek onu çözerler. Ancak alınan komutta bir hata olduğunu söyleyemezler, çünkü bu onların amacı değildir. Amaçları, tutarsız verilerin nesneye girmemesini sağlayarak tespit edilmesi ve düzeltilmesi zor olabilecek yan etkilere neden olmalarını önlemektir.

Nihai sonuç aşağıdaki gibi olacaktır:



Sonuç

Umarım bu kod size ilham verir! Ben, güzel ve heyecan verici olduğu için programlamayla ilgilenmeye başlamıştım. Bazen bazı özel sonuçlar elde etmeye çalışırken, çok fazla baş ağrısı meydana gelebiliyor. Ancak çoğu zaman buna değer. Bir sonraki makalede, tüm bunları nasıl daha da ilginç hale getireceğimizi anlatacağım. Bu makalenin ekinde, göstergenin bu ve önceki makalede açıklandığı gibi kullanılabilecek tam kodu bulunmaktadır.


MetaQuotes Ltd tarafından Portekizceden çevrilmiştir.
Orijinal makale: https://www.mql5.com/pt/articles/10230

Bir grafikte birden fazla gösterge (Bölüm 03): Özel tanımlar geliştirme Bir grafikte birden fazla gösterge (Bölüm 03): Özel tanımlar geliştirme
Bugün gösterge sisteminin işlevselliğini ilk kez güncelleyeceğiz. Bir önceki makalede, bir grafik alt penceresinde birden fazla göstergenin kullanılmasına olanak sağlayan kodu ele aldık. Ancak sunulan şey, çok daha büyük bir sistemin yalnızca başlangıç temeliydi.
Bollinger Bands göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? Bollinger Bands göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
Bu makalede, ticaret dünyasının en popüler göstergelerinden biri olan Bollinger Bands’ten bahsedeceğiz. Teknik analizi ele alacağız ve Bollinger Bands göstergesine dayalı bir algoritmik ticaret sisteminin nasıl geliştirileceğini öğreneceğiz.
Envelopes göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? Envelopes göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
Bu makalede, bantlarla ticaret yapma konseptinde kullanılan başka bir aracı sizlerle paylaşacağım. Bu kez Envelopes göstergesini ele alacağız ve Envelopes göstergesine dayalı stratejiler oluşturmanın ne kadar kolay olduğunu göreceğiz.
Bir grafikte birden fazla gösterge (Bölüm 01): Kavramları anlama Bir grafikte birden fazla gösterge (Bölüm 01): Kavramları anlama
Bugün, ayrı bir alan işgal etmeyecek şekilde grafiğe nasıl birkaç gösterge ekleyebileceğinizi inceleyeceğiz. Ticaret işlemi gerçekleştirirken, birçok yatırımcı aynı anda birden fazla göstergeyi (örneğin, RSI, STOCHASTIC, MACD, ADX vb.) ve hatta bazı durumlarda endeksi oluşturan farklı varlıkları takip ettiklerinde kendilerini daha güvende hissederler.