English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
Bir grafikte birden fazla gösterge (Bölüm 06): MetaTrader 5'i bir RAD sistemine dönüştürme (II)

Bir grafikte birden fazla gösterge (Bölüm 06): MetaTrader 5'i bir RAD sistemine dönüştürme (II)

MetaTrader 5Ticaret sistemleri | 16 Ağustos 2022, 10:46
197 0
Daniel Jose
Daniel Jose

Giriş

Bir önceki makalemde size MetaTrader 5 nesnelerini kullanarak bir ticaret arayüzünün nasıl oluşturulacağını ve böylelikle platformun bir RAD sistemine nasıl dönüştürüleceğini göstermiştim. Sistem çok iyi çalışıyor, şüphesiz birçok okuyucu önerilen sistemde daha fazla işlevselliğe sahip olmak için bir kütüphane oluşturmayı düşünmüştür. Böylece, daha hoş ve kullanımı daha kolay bir arayüze sahip daha sezgisel bir Uzman Danışman geliştirmek mümkün olacaktır.

Buradaki fikir o kadar iyi ki, size adım adım nasıl işlevsellik ekleyeceğinizi göstermek adına beni harekete geçirdi. Burada iki yeni ve ana özelliği uygulayacağım (bu bilgiler, diğer özellikleri ihtiyaç duyulan ve istenilen şekilde uygulamak için bir temel teşkil edecektir). Öğeler çok çeşitli şekillerde kullanılabileceğinden, yeni özellikler eklerken ki tek sınır yaratıcılığımız olacaktır.


Planlama

IDE üzerindeki değişikliklerimiz aşağıda gösterildiği gibi olacaktır:

         

Gördüğünüz gibi, tasarımın kendisinde küçük değişiklikler mevcut. İki yeni alan eklendi: birinde varlığın adı olacak, diğerindeyse günlük birikmiş değer olacak. Bunlar onlar olmadan da yaşayabileceğimiz şeyler ve kararlarımızı etkilemeyecekler. Ancak kullanışlılığı artıracaklar. Size IDE'mize işlevsellik eklemenin en basit ve doğru yolunu göstereceğim. Bu amaçla, yeni arayüzdeki nesne listesini açın. Aşağıdaki gibi görünecektir:


İşaretli iki nesnenin kendileriyle ilişkili olayları yoktur, bu da onların IDE'de çalışmadıkları anlamına gelir. Diğer tüm nesneler halihazırda belirli olaylarla ilişkilendirilmiştir ve MetaTrader 5 bu olayları Uzman Danışmanda meydana geldiklerinde doğru şekilde yürütmeye zorlayabilir. Yani IDE arayüzünü istediğimiz gibi değiştirebiliriz, ancak işlevsellik uygulanmadıysa MetaTrader 5, nesneyi grafikte göstermekten başka bir şey yapmayacaktır. Şimdi, ticaret yapılan varlığın adını göstermek için Edit 00 nesnesine ihtiyacımız var ve bu ad nesnenin ortasında görünmelidir. Edit 01 nesnesi ise, belirli bir süre için olan birikmiş değeri gösterecektir. Gün içinde kârda mı yoksa zararda mı olduğumuzu bilmek için günlük dönemi kullanacağız. Değer negatifse bir renk, pozitif ise başka bir renk kullanılacaktır.

Tabi ki her iki değer de kullanıcı tarafından değiştirilmeyecektir, bu nedenle aşağıdaki görüntüde gösterildiği gibi özelliklerini salt okunur olarak bırakabilirsiniz.


Ancak, içerecekleri bilgilerin nasıl sunulacağını belirtmenin imkansız olduğunu, yani metni nesnenin ortasında görünecek şekilde hizalayamayacağımızı unutmayın. İstenirse, bu, metni merkeze ayarlayarak hizalayan bir özellik var olduğu için kod kullanılarak yapılabilir. Daha fazla ayrıntı için "Nesne özellikleri"ne bakın. Lütfen tablodaki ENUM_ALIGN_MODE'a dikkat edin — metnin ne şekilde hizalanacağıyla ilgili tanımlayıcıları içermektedir.

Dolayısıyla, ne tür bir değişiklik uygulayacak olursak olalım, yapmamız gereken ilk şey bir plan hazırlamaktır: yeni özellikler neler olacak, nasıl sunulacaklar ve kullanıcı onlarla nasıl etkileşime girebilecek. Bu, doğru nesnenin seçilmesine ve mümkün olduğunca MetaTrader 5'in kendi arayüzünü kullanarak yapılandırılmasına olanak sağlayacaktır. Sonuç olarak, elimizde hazır bir IDE olacak ve IDE'nin %100 işlevsel hale gelmesi için onu sadece MQL5 kodu üzerinden ayarlamamız gerekecek. Öyleyse, değişikliklere geçelim.


Değişiklikler

Kodun gerçek bir Frankenstein olmasını önlemek adına, kodda hangi özelliklerin zaten mevcut olduğunu ve hangilerinin gerçekten uygulanması gerektiğini kontrol etmek için kendimizi mümkün olduğunca organize etmeliyiz. Çoğu durumda, mevcut kodda küçük düzenlemeler yapıp yenisini almak ve test etmek yeterli olacaktır. Bu amaçla, önceki oluşturduğumuz kodu kullanılacağız, böylece test etmemiz gereken tek şey yeni işlevsellikler oluşturmak için ekleyeceğimiz küçük kontrol fonksiyonları olacak. İyi programcılar her zaman bunu yapar: var olan kodu ona kesme noktaları ekleyerek bir şekilde yeniden kullanmaya çalışırlar.


Değişiklik 1. Varlık adını ekleme

Bu kısmı uygulamak için büyük düzenlemelere ihtiyacımız yok, ancak ilgili düzenlemelerin doğru yerlerde uygulanması gerekiyor. İlk olarak, numaralandırmaya yeni bir değer ekleyelim, kaynak kodu aşağıda gösterilmektedir:

enum eObjectsIDE {eRESULT, eBTN_BUY, eBTN_SELL, eCHECK_DAYTRADE, eBTN_CANCEL, eEDIT_LEVERAGE, eEDIT_TAKE, eEDIT_STOP};



Yeni kod aşağıdadır; vurgulanan kısım eklenen alandır. Lütfen yeni değeri numaralandırmanın başına veya sonuna eklemediğime dikkat edin. Bu, halihazırda mevcut olup çalışan diğer kod parçalarıyla uğraşmak zorunda kalmamak için yapılır.

enum eObjectsIDE {eRESULT, eLABEL_SYMBOL, eBTN_BUY, eBTN_SELL, eCHECK_DAYTRADE, eBTN_CANCEL, eEDIT_LEVERAGE, eEDIT_TAKE, eEDIT_STOP};



Yeni değeri numaralandırmanın başına veya sonuna eklerseniz, bu sınırların kullanıldığı tüm yerleri bulmanız ve değiştirmeniz gerekecektir. Bunu yaparken çoğu durumda unutkanlık nedeniyle ihmaller meydana gelebilir, bu da bulunması zor olabilecek hatalara yol açabilir. Hatalar, aslında unutkanlıktan kaynaklanıyor olsa da, sanki yeni eklemelerden kaynaklanıyor gibi görünecektir. Bu nedenle, değişiklikleri uç değerler arasına ekleriz.

Hemen ardından sisteme bir mesaj eklememiz gerekiyor aksi halde RunTime hatası alabiliriz. Bu amaçla aşağıdaki satırı kaynak kodumuza ekliyoruz.

static const string C_Chart_IDE::szMsgIDE[] = {
                                                "MSG_RESULT",
                                                "MSG_NAME_SYMBOL",
                                                "MSG_BUY_MARKET",
                                                "MSG_SELL_MARKET",
                                                "MSG_DAY_TRADE",
                                                "MSG_CLOSE_POSITION",
                                                "MSG_LEVERAGE_VALUE",
                                                "MSG_TAKE_VALUE",
                                                "MSG_STOP_VALUE"
                                              };



Gördüğünüz gibi, düzeni korumak adına aynı yere ekledik. Ancak şu anda sabit herhangi bir noktaya eklenebilir, sadece mesajı hangi nesnenin alacağını kontrol etmek için kullanılıyor olduğundan herhangi bir fark oluşturmayacaktır. Düzen açısından ikinci mesaj olarak ekledik.

Şimdi MetaTrader 5'e geri dönelim ve aşağıdaki değişiklikleri yapalım:

         

Artık MetaTrader 5, IDE'mizdeki nesneyi mesajı alacak nesne olarak tanıyacak, şimdi ise mesajın gönderilmesi için bir prosedür oluşturmak gerekiyor. Mesaja metin bir grafik için yalnızca bir kez ekleneceğinden, MetaTrader 5 IDE'mizi grafiğe yerleştirir yerleştirmez mesajı gönderilebilir. Bu, nesne sınıfımızın Create fonksiyonunun sonuna gerekli kodu ekleyerek yapılabilir. Ancak yine de kodun düzeltmelerle dolu bir Frankenstein'a dönüşmemesi adına yeni kodu DispatchMessage fonksiyonunun içine ekleyeceğiz. Orijinal fonksiyon şu şekilde görünmektedir:

void DispatchMessage(int iMsg, string szArg, double dValue = 0.0)
{
        if (m_CountObject < eEDIT_STOP) return;
        switch (iMsg)
        {
                case CHARTEVENT_CHART_CHANGE:
                        if (szArg == szMsgIDE[eRESULT])
                        {
                                ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eRESULT].szName, OBJPROP_BGCOLOR, (dValue < 0 ? clrLightCoral : clrLightGreen));
                                ObjectSetString(Terminal.Get_ID(), m_ArrObject[eRESULT].szName, OBJPROP_TEXT, DoubleToString(dValue, 2));
                        }
                        break;
                case CHARTEVENT_OBJECT_CLICK:

// ... The rest of the code...

        }
}



İlgili değişikliklerden sonra kod aşağıdaki gibi olacaktır:

void DispatchMessage(int iMsg, string szArg, double dValue = 0.0)
{
        if (m_CountObject < eEDIT_STOP) return;
        switch (iMsg)
        {
                case CHARTEVENT_CHART_CHANGE:
                        if (szArg == szMsgIDE[eRESULT])
                        {
                                ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eRESULT].szName, OBJPROP_BGCOLOR, (dValue < 0 ? clrLightCoral : clrLightGreen));
                                ObjectSetString(Terminal.Get_ID(), m_ArrObject[eRESULT].szName, OBJPROP_TEXT, DoubleToString(dValue, 2));
                        }else if (szArg == szMsgIDE[eLABEL_SYMBOL])
                        {
                                ObjectSetString(Terminal.Get_ID(), m_ArrObject[eLABEL_SYMBOL].szName, OBJPROP_TEXT, Terminal.GetSymbol());
                                ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eLABEL_SYMBOL].szName, OBJPROP_ALIGN, ALIGN_CENTER);
                        }
                        break;
                case CHARTEVENT_OBJECT_CLICK:

// ... The rest of the code

        }
}



Gönderme fonksiyonunu oluşturduktan sonra mesajı göndereceğimiz noktayı seçebiliriz. En iyi yer aslında nesne sınıfımızın Create fonksiyonun sonudur, böylece kod şu şekilde görünecektir:

bool Create(int nSub)
{
        m_CountObject = 0;
        if ((m_fp = FileOpen("Chart Trade\\IDE.tpl", FILE_BIN | FILE_READ)) == INVALID_HANDLE) return false;
        FileReadInteger(m_fp, SHORT_VALUE);
                                
        for (m_CountObject = eRESULT; m_CountObject <= eEDIT_STOP; m_CountObject++) m_ArrObject[m_CountObject].szName = "";
        m_SubWindow = nSub;
        m_szLine = "";
        while (m_szLine != "</chart>")
        {
                if (!FileReadLine()) return false;
                if (m_szLine == "<object>")
                {
                        if (!FileReadLine()) return false;
                        if (m_szLine == "type")
                        {
                                if (m_szValue == "102") if (!LoopCreating(OBJ_LABEL)) return false;
                                if (m_szValue == "103") if (!LoopCreating(OBJ_BUTTON)) return false;
                                if (m_szValue == "106") if (!LoopCreating(OBJ_BITMAP_LABEL)) return false;
                                if (m_szValue == "107") if (!LoopCreating(OBJ_EDIT)) return false;
                                if (m_szValue == "110") if (!LoopCreating(OBJ_RECTANGLE_LABEL)) return false;
                        }
                }
        }
        FileClose(m_fp);
        DispatchMessage(CHARTEVENT_CHART_CHANGE, szMsgIDE[eLABEL_SYMBOL]);
        return true;
}


Eklenen parça yeşil renkle vurgulanmaktadır. Hemen hemen hiçbir düzenleme yapmadan, %100 olarak uygulanmış bir mesaj akışına sahip olmuş olduk. Şimdi ise uygulanması gereken bir sonraki mesaja geçelim.


Değişiklik 2. Günlük birikmiş değerin eklenmesi

Yine varlık adını eklerken ki mantığı izliyoruz, yeni kod şu şekilde görünecektir:

enum eObjectsIDE {eRESULT, eLABEL_SYMBOL, eROOF_DIARY, eBTN_BUY, eBTN_SELL, eCHECK_DAYTRADE, eBTN_CANCEL, eEDIT_LEVERAGE, eEDIT_TAKE, eEDIT_STOP};

// ... Rest of the code

static const string C_Chart_IDE::szMsgIDE[] = {
                                                "MSG_RESULT",
                                                "MSG_NAME_SYMBOL",
                                                "MSG_ROOF_DIARY",
                                                "MSG_BUY_MARKET",
                                                "MSG_SELL_MARKET",
                                                "MSG_DAY_TRADE",
                                                "MSG_CLOSE_POSITION",
                                                "MSG_LEVERAGE_VALUE",
                                                "MSG_TAKE_VALUE",
                                                "MSG_STOP_VALUE"
                                              };



Sonrasında, IDE'yi yeni mesajla değiştirelim:

         

Yeni IDE'miz hazır. Şimdi günlük birikmiş değeri içeren mesajı oluşturacak kodu uygulayacağız. Öncelikle bu özelliğin hangi sınıfta uygulanacağına karar vermeliyiz. Birçok kişi muhtemelen bu fonksiyonu burada, C_Chart_IDE sınıfında oluşturmayı düşünür, ancak daha düzenli olması amacıyla, onu emirlerle çalışan fonksiyonlarla bir araya getirmek daha iyi olacaktır. Dolayısıyla kodu, C_OrderView sınıfında uygulayacağız. Kod aşağıda gösterilmektedir:

double UpdateRoof(void)
{
        ulong   ticket;
        int     max;
        string  szSymbol = Terminal.GetSymbol();
        double  Accumulated = 0;
                                
        HistorySelect(macroGetDate(TimeLocal()), TimeLocal());
        max = HistoryDealsTotal();
        for (int c0 = 0; c0 < max; c0++) if ((ticket = HistoryDealGetTicket(c0)) > 0)
                if (HistoryDealGetString(ticket, DEAL_SYMBOL) == szSymbol)
                        Accumulated += HistoryDealGetDouble(ticket, DEAL_PROFIT);
                                                
        return Accumulated;
}



Kod uygulandı, şimdi mesajı sisteme eklememiz gerekiyor. Size kolaylık olması için kodu ekledim. İşte burada:

void DispatchMessage(int iMsg, string szArg, double dValue = 0.0)
{
        static double AccumulatedRoof = 0.0;
        bool    b0;
        double  d0;

        if (m_CountObject < eEDIT_STOP) return;
        switch (iMsg)
        {
                case CHARTEVENT_CHART_CHANGE:
                        if ((b0 = (szArg == szMsgIDE[eRESULT])) || (szArg == szMsgIDE[eROOF_DIARY]))
                        {
                                if (b0)
                                {
                                        ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eRESULT].szName, OBJPROP_BGCOLOR, (dValue < 0 ? clrLightCoral : clrLightGreen));
                                        ObjectSetString(Terminal.Get_ID(), m_ArrObject[eRESULT].szName, OBJPROP_TEXT, DoubleToString(dValue, 2));
                                }else
                                {
                                        AccumulatedRoof = dValue;
                                        dValue = 0;
                                }
                                d0 = AccumulatedRoof + dValue;
                                ObjectSetString(Terminal.Get_ID(), m_ArrObject[eROOF_DIARY].szName, OBJPROP_TEXT, DoubleToString(MathAbs(d0), 2));
                                ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eROOF_DIARY].szName, OBJPROP_BGCOLOR, (d0 >= 0 ? clrForestGreen : clrFireBrick));
                        }else   if (szArg == szMsgIDE[eLABEL_SYMBOL])
                        {
                                ObjectSetString(Terminal.Get_ID(), m_ArrObject[eLABEL_SYMBOL].szName, OBJPROP_TEXT, Terminal.GetSymbol());
                                ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eLABEL_SYMBOL].szName, OBJPROP_ALIGN, ALIGN_CENTER);
                        }
                        break;
                case CHARTEVENT_OBJECT_CLICK:

// .... The rest of the code....

        }
}



Vurgulanan kısımlar yukarıda açıklandığı gibi sistemi desteklemektedir. Eğer uygulama bu şekilde yapılmasaydı, bilgileri doğru bir şekilde güncellemek için sisteme iki mesaj göndermemiz gerekecekti. Ancak yukarıdaki uygulama şeklini kullanarak hem açık pozisyonun sonucunu hem de günün sonucunu tek bir mesajla takip edebiliyoruz.

Uzman Danışmana yapılacak bir başka değişiklik ise, OnTrade fonksiyonuyla ilgilidir. Bu aşağıda görünmektedir:

void OnTrade()
{
        SubWin.DispatchMessage(CHARTEVENT_CHART_CHANGE, C_Chart_IDE::szMsgIDE[C_Chart_IDE::eROOF_DIARY], NanoEA.UpdateRoof());
        NanoEA.UpdatePosition();
}



Sistem çalışmasına rağmen, OnTrade fonksiyonunun (ya da OnTick fonksiyonunun) yürütme süresi konusunda Uzman Danışmanın performansını düşürebileceğinden dikkatli olmalıyız. Kodun OnTick’te bulunması durumunda, bu durumun etrafından dolaşmanın bir yolu yoktur, burada optimizasyon çok kritiktir. Ancak OnTrade ile bu daha basittir, çünkü pozisyonda bir değişiklik olduğunda fonksiyon çağrılacaktır. Bunu bilerek şu iki alternatife sahibiz. Birincisi, yürütme süresini sınırlamak adına UpdateRoof fonksiyonunu değiştirmek. Diğeriyse, OnTrade fonksiyonun kendisini değiştirmektir. Pratik nedenlerden dolayı, Update Roof fonksiyonunu değiştireceğiz ve böylece açık pozisyonumuz olduğunda yürütme süresini en azından biraz iyileştireceğiz. Yeni fonksiyon aşağıdaki gösterilmektedir:

double UpdateRoof(void)
{
        ulong           ticket;
        string  szSymbol = Terminal.GetSymbol();
        int             max;
        static int      memMax = 0;
        static double   Accumulated = 0;
                
        HistorySelect(macroGetDate(TimeLocal()), TimeLocal());
        max = HistoryDealsTotal();
        if (memMax == max) return Accumulated; else memMax = max;
        for (int c0 = 0; c0 < max; c0++) if ((ticket = HistoryDealGetTicket(c0)) > 0)
                if (HistoryDealGetString(ticket, DEAL_SYMBOL) == szSymbol)
                        Accumulated += HistoryDealGetDouble(ticket, DEAL_PROFIT);
                                                
        return Accumulated;
}


Vurgulanan satırlar, orijinal fonksiyona eklenen kodu göstermektedir. Pek bir fark yaratmamış gibi görünseler de, çok şey fark ediyorlar. Nedenine bakalım. Koda ilk kez erişildiğinde, hem memMax statik değişkeni hem de Accumulated sıfıra ayarlanacak. Belirtilen dönem için emir geçmişinde hiçbir değer yoksa test bu değeri yansıtacak ve fonksiyon geri dönecek, ancak test edilecek herhangi bir veri varsa, hem memMax hem de Accumulated yeni durumu yansıtacak. Bu değişkenlerin statik olması, değerlerinin çağrılar arasında sabit tutulduğu anlamına gelir. Dolayısıyla , varlığın doğal hareketinin sonucu olarak pozisyonun değeri değiştiğinde, MetaTrader 5 OnTrade fonksiyonunu çağıracak bir olay oluşturur. Bu noktada UpdateRoof fonksiyonunun yeni bir çağrısına sahip oluruz, eğer pozisyon kapatılmamışsa fonksiyon kontrol noktasına geri döner ve böylece değerlerin geri döndürülme süreci hızlanmış olur.


Sonuç

Bu makalede, RAD sistemine nasıl yeni işlevler ekleneceğini gördük. İncelediğimiz bu bilgiler, bir etkileşim ve kontrol arayüzü oluştururken çok daha basit ve daha az hataya sahip olacak şekilde sistemi IDE arayüzü için ideal hale getirecek bir kütüphaneyi oluşturmamıza olanak sağlar. Şu andan itibaren, tek gerçek sınırlama sizin yaratıcılığınız olacaktır, çünkü burada yalnızca MQL5 ile çalışmayı düşündük, ancak aynı fikri harici kütüphanelere de entegre edebilirsiniz, böylece bir IDE oluşturma olanaklarını büyük ölçüde genişletebilirsiniz.


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

Ekli dosyalar |
EA_1.05.zip (3274.9 KB)
MACD göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? MACD göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
Makale serimizin bu bölümünde de en popüler teknik göstergelerden biri olan Moving Average Convergence Divergence (MACD) göstergesine dayalı bir ticaret sisteminin nasıl tasarlanacağını öğreneceğiz.
CCI göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? CCI göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
Ticaret sistemlerinin nasıl tasarlanacağını öğrenmeye yönelik makale serimizin bu yeni makalesinde, Commodities Channel Index’i (CCI) sunacak, özelliklerini açıklayacak ve bu göstergeye dayalı bir ticaret sisteminin nasıl oluşturulacağını sizlerle paylaşacağım.
Stochastic Oscillator göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? Stochastic Oscillator göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
Öğrenme serimize devam ediyoruz - temel bilgilerimizde yeni bir blok daha oluşturmak adına bu sefer de diğer bir popüler ve kullanışlı gösterge olan Stochastic Oscillator’ı inceleyeceğiz ve onu kullanarak bir ticaret sisteminin nasıl tasarlanacağını öğreneceğiz.
Uzman Danışmanların Neden Başarısız Olduğunun Bir Analizi Uzman Danışmanların Neden Başarısız Olduğunun Bir Analizi
Bu makalede, uzman danışmanların neden zamanın bazı bölgelerinde iyi performans, bazı bölgelerinde kötü performans gösterebildiğini daha iyi anlamak adına döviz çiftleriyle ilgili verileri analiz edeceğiz.