English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
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

MetaTrader 5Örnekler | 5 Temmuz 2022, 08:46
169 0
Daniel Jose
Daniel Jose

Giriş

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. Bu modele göre birkaç farklı şey daha yapılabilir. Ancak adım adım gitmeliyiz çünkü bu makalelerin amaçlarından biri, fikirlerinize dayalı olarak kendi sistemlerinizi tasarlayabilmeniz için programlamayı öğrenmeye teşvik etmektir. Bu makalede, işlevselliği genişleteceğiz. Sistemin neler yapabiliyor olduğunu görmüş ve beğenmiş olan ve daha fazlasını yapabilmek isteyenler için bu ilgi çekici olabilir.


Planlama

Genellikle yeni bir sistem tasarlamaya başladığımızda, onu ne kadar geliştirebileceğimize dair gerçek bir fikrimiz yoktur, bu nedenle yeni bir projeye her zaman gelecekteki geliştirmelere nasıl tabi olabileceğini göz önünde bulundurarak başlamalıyız. Bu, projeye yeni başlamış olup planlamalar yapan ve gelecekteki genişlemeleri ve iyileştirmeleri hayal edenler için çok önemlidir.

Çekirdek kod hiç değişmedi, ki bu bir anlamda zaten bekleniyordu. Ancak nesne sınıfı kodu büyük ölçüde değişti. Bu değişiklikleri yeni özellikleri uygulamak ve kodun yeniden kullanımı daha da önemli hale geldiğinden daha esnek bir şekilde yeni iyileştirmeler yapabilmek için gerçekleştirdik (bu, nesne yönelimli programlamanın ana fikirlerinden biridir: her zaman yeniden kullanın, yalnızca gerektiğinde yenisini oluşturun). Şimdi yeni nesne sınıfına göz atalım. Daha kolay anlaşılması için değişiklikleri vurgulayacağım.

Özel sınıf değişkenlerinin yeni tanımlarıyla başlayalım.

struct st
{
        string  szObjName,
                szSymbol;
        int     width;
}m_Info[def_MaxTemplates];
int             m_IdSubWin,
                m_Counter,
                m_CPre,
                m_Aggregate;
long            m_Id,
                m_handle;
ENUM_TIMEFRAMES m_Period;

Kullanılan değişkenlerin sayısının önemli ölçüde arttığına dikkat edin. Bunun nedeni, yeni işlevselliği düzgün bir şekilde yönetebilmek için daha fazla veriye ihtiyacımız olmasıdır. Artık değişken sistemimiz bir yapıya sahip. Bu tür yapılar, birbiriyle ilişkili değişkenleri bir arada gruplandırmak için çok iyidir - verilerde değişiklik yaptığımızda, ona hızlıca ve kolay şekilde erişmemize olanak sağlarlar.

void SetBase(const string szSymbol, int iScale, int iSize)
{
#define macro_SetInteger(A, B) ObjectSetInteger(m_Id, m_Info[m_Counter].szObjName, A, B)
        if (m_IdSubWin < 0)
        {
                m_Id = ChartID();
                m_IdSubWin = (int)ChartGetInteger(m_Id, CHART_WINDOWS_TOTAL) - 1;
                m_Aggregate = 0;
        }
        m_Info[m_Counter].szObjName = __FILE__ + (string) MathRand() + (string) ObjectsTotal(m_Id, -1, OBJ_CHART);
        ObjectCreate(m_Id, m_Info[m_Counter].szObjName, OBJ_CHART, m_IdSubWin, 0, 0);
        ObjectSetString(m_Id, m_Info[m_Counter].szObjName, OBJPROP_SYMBOL, (m_Info[m_Counter].szSymbol = szSymbol));

// ....

        macro_SetInteger(OBJPROP_PERIOD, m_Period);
        m_handle = ObjectGetInteger(m_Id, m_Info[m_Counter].szObjName, OBJPROP_CHART_ID);
        m_Aggregate += iSize;
        m_Info[m_Counter].width = iSize;
        m_CPre += (iSize > 0 ? 1 : 0);
        m_Counter++;
#undef macro_SetInteger
};


Birazdan göreceğimiz ana değişiklik, varlık adını, nesne adını ve genişliğini saklamak için bir yapı kullandığımızdır. Artık, göstergenin alt pencerede sahip olacağı genişliği de belirtebiliriz. Ayrıca bunları sınıfın diğer bölümlerinde de kullanmak üzere not olarak alalım. Şimdi en çok değişen fonksiyona bakalım.

void Decode(string &szArg, int &iScale, int &iSize)
{
#define def_ScaleDefault 4
#define macro_GetData(A)                \
        b0 = false;                     \
        for (c0++; (c0 < max) && (szArg[c0] == ' '); c0++);     \
        for (i0 = 0, i1 = c0; (c0 < max) && (szArg[c0] != A); i0 = (szArg[c0] != ' ' ? c0 - i1 + 1 : i0), c0++);        \
        if (szArg[c0] == A) sz1 = StringSubstr(szArg, i1, i0); else sz1 = "";
                                                                
        string sz1;
        int i0, i1, c1 = StringLen(szArg);
        bool b0 = true;
        StringToUpper(szArg);
        iScale = def_ScaleDefault;
        m_Period = _Period;
        for (int c0 = 0, max = StringLen(szArg); c0 < max; c0++) switch (szArg[c0])
        {
                case ':':
                        b0 = false;
                        for (; (c0 < max) && ((szArg[c0] < '0') || (szArg[c0] > '9')); c0++);
                        iScale = (int)(szArg[c0] - '0');
                        iScale = ((iScale > 5) || (iScale < 0) ? def_ScaleDefault : iScale);
                        break;
                case ' ':
                        break;
                case '<':
                        macro_GetData('>');
                        if (sz1 == "1M") m_Period = PERIOD_M1; else

//....

                        if (sz1 == "1MES") m_Period = PERIOD_MN1;
                        break;
                case '[':
                        macro_GetData(']');
                        iSize = (int) StringToInteger(sz1);
                        break;
                default:
                        c1 = (b0 ? c0 : c1);
                        break;
        }
        szArg = StringSubstr(szArg, 0, c1 + 1);
#undef macro_GetData
#undef def_ScaleDefault
}


Yeşil ile vurgulananlar koda yapılan eklemelerdir. Sarı ile vurgulananlar kodda daha önce mevcut olup ancak pratik nedenlerle taşınmış olanlardır. Şimdi tüm bu eklemelerin kodda ne yaptığına ve daha da önemlisi orijinal sistemin işlevselliği açısından neleri iyileştirdiğine bakalım. Esasen, kullanıcının bazı belirli şeyleri özelleştirmesini sağlamak için bir araç oluşturuyoruz. Bunu mevcut sözdizimine yeni kurallar ekleyerek yapmaya çalışıyoruz (aşağıdaki tabloya bakın):

Ayırıcı İşlevsellik Örnek  Sonuç 
< > Grafiğin kullanılacak zaman dilimini belirtir  < 15m > Göstergenin zaman dilimini 15 dakikalık olarak sabitler. Orijinal grafik farklı bir zaman dilimi kullanabilir, ancak gösterge yalnızca 15 dakikalık veriler şeklinde görüntülenecektir.
 [ ] Göstergenin genişliğini belirtir  [ 350 ] Gösterge genişliğini 350 piksele sabitler. 

Grafiğin zaman dilimini sabitleyen ayırıcı, bunu yalnızca bulunduğu göstergede yapar ve kullanıcının yapabileceği değişiklikleri etkilemez. Diğer tüm göstergeler ve ana grafik, kullanıcı tarafından seçilen yeni zaman dilimine göre güncellenir, ancak sabitleştirilmiş gösterge yeni zaman dilimini takip etmez. Bazı durumlarda, aşağıdaki görüntüde gösterildiği gibi bu ilginç olabilir.

         

Bu, aynı varlığın farklı zaman dilimlerine sahip grafiklerini ticaret ekranında görünür tutmamız gereken çeşitli ayar türlerini büyük ölçüde kolaylaştırır. Grafik genişliğini sabitleyen ayırıcı da, bu süreci daha da kolaylaştıracaktır. Başka bir makalede inceleyeceğimiz çok büyük bir kullanımı daha vardır, ancak şimdilik gösterge genişliğini kontrol etmek için kullanabilirsiniz.

Spesifik kurallar olmadığından, tüm ayırıcıların bir kombinasyonunu veya göstergede gerçekten ihtiyacınız olanı kullanabilirsiniz. Tek kural, göstergenin adının her şeyden önce yerleştirilmesi gerektiğidir. Kodları açıklamaya geri dönelim. Aşağıdaki satırlara bakalım:

#define macro_GetData(A)                \
        b0 = false;                     \
        for (c0++; (c0 < max) && (szArg[c0] == ' '); c0++);     \
        for (i0 = 0, i1 = c0; (c0 < max) && (szArg[c0] != A); i0 = (szArg[c0] != ' ' ? c0 - i1 + 1 : i0), c0++);        \
        if (szArg[c0] == A) sz1 = StringSubstr(szArg, i1, i0); else sz1 = "";
           
//....                                                     
                case '<':
                        macro_GetData('>');


Birçok kişiye garip gelebilecek bir şey tanımlıyoruz. Ancak adı burada yardımcı olabilir: macro_GetData(A), bu makro olan bir kod parçası oluşturur. Derleyici kodda bu tanımı bulduğunda, bildirimi makro koduyla değiştirir. Belirli bir kod bölümünü birkaç yerde, ancak bir bildirim ve diğer bildirim arasında minimum değişiklikle tekrarlayacaksak, bu çok yararlı olacaktır. Yukarıdaki örnekteki yeşille vurgulanmış satır derleyici tarafından değiştirilerek şu kod parçası oluşturulacaktır:

case '<':
	b0 = false;
        for (c0++; (c0 < max) && (szArg[c0] == ' '); c0++);
        for (i0 = 0, i1 = c0; (c0 < max) && (szArg[c0] != '>'); i0 = (szArg[c0] != ' ' ? c0 - i1 + 1 : i0), c0++);
        if (szArg[c0] == A) sz1 = StringSubstr(szArg, i1, i0); else sz1 = "";
//....

Bu gibi şeyler, OOP’nin ana fikrinin en doğru ifadesidir: mümkün olduğunca çok yeniden kullanın, mümkün olduğunca az yeni yazın. Şimdi sözdizimini daha anlaşılır hale getirmek istiyorsak nelerin değiştirilebileceğine bakalım. Bu küçük bir detay, ancak kişisel tarzınıza göre uyarlanırsa çok daha güzel olabilir. Aşağıdaki satıra bakalım:

//.....

if (sz1 == "1M") m_Period = PERIOD_M1; else

//.....

Vurgulanan bilgi önemli bir ayrıntıdır. Kullandığım modele göre, kullanıcı 1 dakikalık zaman dilimini kullanmak istiyorsa bunu şu sözdizimini kullanarak belirtmelidir: MIN_1. Kişisel bir stile sahip olmak istiyorsanız, bunu kendiniz ayarlayabilirsiniz. Ancak harfler büyük ve boşluksuz olmalıdır. Örneğin, seçili parça "1MIN", "MIN_1", "1_MINUTE" veya daha fazla ayrıntı içerecek şekilde, örneğin, "LOCK_IN_1_MIN" veya kendi dilinizde ”1_DK_OLARAK_SABITLE” şeklinde değiştirilebilir - bu, kelimeler arasında boşluk olmadığı sürece çalışacaktır. Aslında bu boşluk kısıtlaması kaldırılabilir ancak şahsen buna gerek yok. Programlamayı bilmenin ne kadar güzel olduğunu görüyorsunuz - kendi tarzınıza göre şeyler kullanabilirsiniz. Değiştirdiğim bir sonraki kod varsayılan yıkıcıdır.

~C_TemplateChart() 
{
        for (char c0 = 0; c0 < m_Counter; c0++)
        {
                ObjectDelete(m_Id, m_Info[c0].szObjName);
                SymbolSelect(m_Info[c0].szSymbol, false);
        }
}

Vurgulanan satır şu durum için eklendi: bir varlık ayrı bir pencerede açık değilse, artık Piyasa Gözleminde görünmemelidir. Bu, kullanılmayan varlıkların orada kalmasını, yer kaplamasını ve dolayısıyla pencereyi kirletmesini önler. Şimdi bir önceki makalede anlatacağıma söz verdiğim şeye bakalım. Bu orijinal kodda yoktu, ancak gelecekte kodun bir parçası olacak.

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

Vurgulanan satır, gözlemlenen tüm varlıklar aynı ayarları kullanıyorsa varsayılan ayarlar dosyasının kullanılmasını mümkün kılar. İşler beklendiği gibi gitmezse nasıl davranılması gerektiğini bilmeden bir şeyler yapmak iyi değildir. Ayarlar TAMAMEN aynıysa neden aynı ayarları kullanmayalım? Belirtilen varlık için ayar dosyası bulunamazsa, Profiles\Template klasöründeki DEFAULT.TPL dosyasında tanımlanan varsayılan MetaTrader 5 ayarlarını kullanmak istediğiniz anlaşılacaktır. Ama önce önemli bir şeyi anlamamız gerekiyor. ChartApplyTemplate fonksiyonunda neden bir klasör belirtmedim? Bunun nedeni MetaTrader 5'in belirli bir mantıkla arama yapmasıdır. Bu mantığın nasıl çalıştığını bilmek, durumlarla daha farklı ve daha az stresli yollarla başa çıkmanıza yardımcı olabilir.

Vurgulanan satırı şununla değiştirdiğimiz aşağıdaki senaryoyu ele alalım:

if (!ChartApplyTemplate(m_handle, "MyTemplates\\" + szTemplate + ".tpl")) if (type == SYMBOL) ChartApplyTemplate(m_handle, ""MyTemplates\\Default.tpl");

MetaTrader 5 ilk olarak, özel gösterge yürütülebilir dosyasının bulunduğu dizinin MYTEMPLATES alt klasöründe ayarlar dosyasını arayacaktır, yani, birden fazla gösterge oluşturmak için kullandığımız yürütülebilir dosya ile aynı klasörde bir MYTEMPLATES klasörü varsa, MetaTrader 5 ihtiyacımız olan dosyayı orada arayacaktır. Ancak, orada hiçbir şey bulunamazsa, aynı dosyayı MQL5\Profiles\Templates\MyTemplates klasöründe arayacaktır, bu yüzden bunu daha önce göstermedim. Ama sadece bu değil. Aynı kod için başka bir ayrıntı daha var:

if (!ChartApplyTemplate(m_handle, "\\MyTemplates\\" + szTemplate + ".tpl")) if (type == SYMBOL) ChartApplyTemplate(m_handle, ""\\MyTemplates\\Default.tpl");

Her şeyi değiştiren küçük bir ayrıntı: şimdi MetaTrader 5 önce ihtiyacımız olan dosyayı MQL5\MyTemplates klasöründe arayacak, eğer dosyayı bulamazsa yukarıda anlatılan adımları izleyecektir. Bu bilgiyi ChartApplyTemplate dokümantasyonunda bulabilirsiniz, çünkü MetaTrader 5'in nasıl çalıştığını bilmeyenlerin onun nasıl çalıştığına dair yanlış bir izlenim vererek kafalarını karıştırmak istemiyorum. Ancak artık aramanın nasıl yapıldığını anladığınıza göre, varyasyonlar oluşturabilir ve dosyaları nereye koymanız gerektiğini bilebilirsiniz.

Sınıfımızda önemli değişikliklere uğrayan bir sonraki fonksiyon ise aşağıda gösterilmektedir:

void Resize(void)
{
#define macro_SetInteger(A, B) ObjectSetInteger(m_Id, m_Info[c0].szObjName, A, B)
        int x0 = 0, x1, y = (int)(ChartGetInteger(m_Id, CHART_HEIGHT_IN_PIXELS, m_IdSubWin));
        x1 = (int)((ChartGetInteger(m_Id, CHART_WIDTH_IN_PIXELS, m_IdSubWin) - m_Aggregate) / (m_Counter > 0 ? (m_CPre == m_Counter ? m_Counter : (m_Counter - m_CPre)) : 1));
        for (char c0 = 0; c0 < m_Counter; x0 += (m_Info[c0].width > 0 ? m_Info[c0].width : x1), c0++)
        {
                macro_SetInteger(OBJPROP_XDISTANCE, x0);
                macro_SetInteger(OBJPROP_XSIZE, (m_Info[c0].width > 0 ? m_Info[c0].width : x1));
                macro_SetInteger(OBJPROP_YSIZE, y);
        }
        ChartRedraw();
#undef macro_SetInteger
}

Vurgulanan satırlar bu fonksiyondaki en önemli hesaplamalardır. Pencereleri kullanıcının isteğine göre ayarlarlar, ancak sabit bir boyuta ayarlanmış pencereler, geri kalanların tanımlı boyutlara sahip olacağı serbest bir alan oluşturur. Eğer ana pencerenin genişliği azaltılırsa, mavi vurgulu hesaplama, sabit boyutlu pencerelerin genişliklerini azaltmaya izin vermeyecektir, bu da bir soruna neden olabilir. Ancak, sabit genişlikli pencerelerin gelecekte daha iyi keşfedilecek başka faydaları da olduğu için şimdilik olduğu gibi bırakalım. Ve sınıfımızdaki son değişiklik ise şu şekilde:

void AddThese(const eTypeChart type, string szArg)
{
        string szLoc;
        int i0, iSize;
//....
        Decode(szLoc, i0, iSize);
        AddTemplate(type, szLoc, i0, iSize);
//....
}

Vurgulanmış olan değişikliklerin pratikte özel bir anlamı yoktur.


Sonuç

Umarım bu makale, diğerleriyle birlikte, yapılandırılmış programlamanın ne kadar kullanışlı olabileceğini göstermiştir. Birkaç ince ayar yaparak gönül rahatlığıyla sisteme birçok işlevsellik ekleyebiliriz. Kodun yeniden kullanımı, bakımını çok daha kolay hale getirir, çünkü bitmiş kodu ne kadar çok kullanırsak, hata içerme olasılığı da o kadar azalır. Bir sonraki makalede, bu sistemi birçok kişi için daha ilginç olabileceği başka yerlere götüreceğiz, böylece, programlama hakkında daha fazla bilgi edinmenizi sağlayacağız. Görüşmek dileğiyle...



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

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 02): Kodlamaya başlangıç Bir grafikte birden fazla gösterge (Bölüm 02): Kodlamaya başlangıç
Bu makale serisinin bir önceki bölümünde, bir grafikte birden fazla göstergenin nasıl kullanılabileceğinin kavramlarından ve temellerinden bahsettim. Bu yazımda da kaynak kodunu detaylı olarak sunacağım ve anlatacağım.
Momentum göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? Momentum göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
Bir önceki makalemde trend tespitinin yani fiyat hareketinin yönünü belirlemenin öneminden bahsetmiştim. Bu makalede de, bu konuda ticarette önemli bir araç olan Momentum göstergesinden bahsedeceğim. Ve Momentum göstergesine dayalı ticaret sisteminin nasıl geliştirileceğini sizlerle paylaşacağım.
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.