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

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

MetaTrader 5Ticaret | 26 Temmuz 2022, 11:46
254 0
Daniel Jose
Daniel Jose

Giriş

Programlamayı bilmeyen ama oldukça yaratıcı ve harika fikirleri olan birçok insan vardır. Ancak, programlama bilgisinin eksikliği, bu fikirleri hayata geçirmelerini engellemektedir. Bugün piyasa emirlerini göndermek veya bekleyen emirlerde kullanılan parametreleri ayarlamak için kendi ticaret arayüzümüzü oluşturacağız. Bunu programlama yapmadan, sadece Uzman Danışmanın içerisinde olacak fonksiyonları kullanarak gerçekleştireceğiz. Hepimiz merak ediyoruz, işte monitörlerimizde şu şekilde görünecek:


Şunu düşünüyor olabilirsiniz: "Fakat bunu nasıl yapacağım? Programlama hakkında hiçbir şey bilmiyorum ya da bildiklerim bunu yapmam için yeterli olmayacak." Yukarıdaki görüntüde gördüğünüz ticaret arayüzü MetaTrader 5 platformunun kendisinde oluşturuldu ve aşağıdaki görüntüde gösterildiği gibi tasarlandı:


Artık bu makalenin ne hakkında olduğunu bildiğimize göre, kendi ticaret arayüzümüzü oluşturmak için heves ve fikirlerle dolu olabiliriz. Her şeyin çalışır olması için bu amaçla birkaç adımı tamamlamayacağız. Yardımcı kod geliştirildikten sonra, ticaret arayüzü IDE'mizin tasarımının tek sınırlaması yaratıcılığımız olacaktır. Bu makale öncekilerin devamı niteliğindedir, dolayısıyla tam ve kapsamlı bir şekilde anlamak için bu makale serisinin önceki makalelerini okumanızı tavsiye ederim.

Öyleyse hadi başlayalım.


Planlama

Öncelikle, IDE olarak kullanacağınız grafiğin özelliklerini düzenlemelisiniz. Bu, olası yan etkileri azaltmak içindir. Mutlaka bir sorun olacağından değil, mesele şu ki, grafiği temiz hale getirerek, ticaret arayüzünü oluşturmak ve tasarlamak daha kolay olacaktır. Bu nedenle, grafiğin özelliklerini açın ve aşağıdaki görüntüde gösterildiği gibi ayarlayın.

     

Böylece, ekran tamamen temiz ve IDE'mizin gelişimini engelleyebilecek her şeyden arınmış olacaktır. Şimdi şuna dikkat edin. IDE'miz bir ayar dosyası olarak, yani bir şablon olarak kaydedilecektir, böylece MetaTrader 5 tarafından sağlanan herhangi biri nesneyi kullanabiliriz, ancak pratik nedenlerden dolayı sadece bazılarını kullanacağız. Mevcut tüm nesneler için lütfen MetaTrader 5'teki nesne türleri bölümüne bakın.

Nesne Konumlandırma için kullanılan koordinat türü IDE için kullanışlı mı? 
Metin Tarih ve fiyat  Hayır
Etiket X ve Y koordinatları  Evet
Düğme  X ve Y koordinatları  Evet
Grafik  X ve Y koordinatları  Evet
Bitmap  Tarih ve fiyat  Hayır
Bitmap etiketi  X ve Y koordinatları  Evet
Düzenle  X ve Y koordinatları  Evet
Olay  Sadece tarih kullanılır  Hayır
Dikdörtgen etiket X ve Y koordinatları  Evet

Ekranın herhangi bir yerine yerleştirilebilen bir sistem kullanacağımızdan dolayı, konumlandırma için X ve Y koordinat sistemini kullanmayan bir nesneyi sistemimizde kullanmak pratik değildir, çünkü bu tür nesneleri IDE'de kullanmak onun tamamen farklı görünmesine neden olabilir. Dolayısıyla, sistemi bir arayüz oluşturmak için fazlasıyla yeterli olacak altı nesneyle sınırlayacağız.

Arayüzü oluştururken ki ana fikir şudur, nasıl bir şeyi ekranda çizerken bir sıraya göre çiziyoruz, benzer şekilde de nesneleri de mantıksal olarak sıraya göre düzenleyeceğiz. İlk önce arka planı oluşturuyoruz, sonrasında ilgili nesneleri arka planın üzerine yerleştiriyoruz, bunu tüm arayüz için yapıyoruz. İşte şu şekilde:

    

    

Her şey çok basit, bu yöntemi kullanarak kendi IDE'nizi tasarlama ve yaratma konusunda uzmanlaşmak için biraz pratik yapmanız yeterli. Buradaki düşünce, kod aracılığıyla kullanıcı arayüzü geliştirmenin çok karmaşık olabileceği durumlarda programlama arayüzleri oluşturmak adına kullanılan RAD programlarındaki düşünceye çok benzerdir. Doğrudan kod aracılığıyla bir arayüz oluşturamayacağımızdan değil. Bu yöntemin kullanımı, ileri modifikasyonları çok daha hızlı ve kolay hale getirir, bu da kendi stiline sahip bir arayüz isteyenler için idealdir.

Biz aşağıdaki gibi bir arayüz tasarlayacağız, ancak tabi ki siz çok daha havalı bir arayüz tasarlayabilirsiniz. Burada onları deneyebilmeniz için mümkün olduğunca çok nesne kullanmaya çalıştım. Siz kendi tercih ettiğiniz arayüzü oluşturabilirsiniz.

Bu, IDE'mizi oluştururken ki ilk adımdır. Şimdi bu arayüzü destekleyen ve onu işlevsel hale getiren bir kod oluşturmamız gerekiyor. Burada kendi kullanıcı arayüzünüz kodla somut hale gelecektir.

Bu amaçla ikinci adımımızda öncelikle bu arayüzü bir ayar dosyası olarak kaydedeceğiz. Böylece onu bir gösterge gibi görüntülemek adına önceki versiyondaki kodu kullanabiliriz. Bu, kaynak kodunda önemli değişiklikler yapmamız gerekmeyeceği anlamına gelir. Ancak, IDE'mize olay gönderme veya IDE'mizden olay alma yeteneklerini test edersek, bunların mümkün olmadığını görürüz. Ancak arayüz MetaTrader 5'teki nesneler kullanılarak oluşturulmuşsa, neden bu nesnelerden olay gönderip alamıyoruz? Bu sorunun cevabını göstermek, açıklamaktan daha kolaydır. Uzman Danışmanın orijinal koduna aşağıdaki kodu ekleyerek test edebiliriz.

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
        switch (id)
        {
                case CHARTEVENT_OBJECT_CLICK:
                        Print(sparam);
                        break;
// .... The rest of the code...
        }
}

Bu kod, tıklamayı alan ve olayı oluşturan nesnenin adını bildirir. Bu durumda olay CHARTEVENT_OBJECT_CLICK’tir. Ancak yazdırılan mesaj, IDE'deki nesnenin adı değil, Uzman Danışman tarafından oluşturulan nesnenin adı olacaktır. Bu, IDE'mizi kullanmayı imkansız kılan büyük bir sorun gibi görünebilir, ancak çok basit bir çözüm vardır: ayar dosyasını okuyoruz ve ardından bu dosyada belirtildiği gibi nesneleri oluşturuyoruz. Bu, tam olarak IDE'mizi grafik üzerinde oluşturacaktır. Ayar dosyasını (TPL) analiz ederek kullanmamız gereken verileri bulabiliriz.

Anahtar Açıklama
<chart> Ayar dosyasını başlatır
</chart> Ayar dosyasını sonlandırır
<window> Grafikte bulunan öğelerin yapısını başlatır
</window> Grafikte bulunan öğelerin yapısını sonlandırır
<indicator> Göstergelerle ilgili verileri sağlayan yapıyı başlatır
</indicator> Göstergelerle ilgili verileri sağlayan yapıyı sonlandırır
<object> Nesnelerle ilgili verileri sağlayan yapıyı başlatır
</object> Nesnelerle ilgili verileri sağlayan yapıyı sonlandırır

Bunlar, TPL dosyasının içerisinde şu şekilde görünür.

<chart>

.... DATA

<window>

... DATA

<indicator>

... DATA

</indicator>

<object>

... DATA

</object>

</window>
</chart>

İlgilendiğimiz kısım <object> ve </object> arasıdır. Her biri benzersiz bir nesneyi işaret eden bu türde birden çok yapı olabilir. Şimdi ise, dosyanın konumunu değiştirmemiz gerekiyor - onu okunabileceği bir yere eklemeliyiz. Bu Files klasörüdür. Kullandığım konumu değiştirebilirsiniz, ancak her durumda dosya Files klasörünün içerisinde olmalıdır.

Önemli bir ayrıntı: Sistem, IDE konfigürasyon dosyasını kullanırken grafiği temizleyecek şekilde düzenlenmiş olsa da, ideal olarak Profiles\Templates klasöründe aynı ada sahip temiz bir dosyaya da sahip olmalısınızdır. Bu, önceki makalelerde görüldüğü gibi, varsayılan şablonda bulunabilecek artıkları en aza indirir. Ana değişiklikler aşağıda vurgulanmaktadır:

#include <Auxiliar\Chart IDE\C_Chart_IDE.mqh>
//+------------------------------------------------------------------+
class C_TemplateChart : public C_Chart_IDE
{

 .... Other parts from code ....

//+------------------------------------------------------------------+
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(szTemplate, (type == INDICATOR ? _Symbol : szTemplate), scale, iSize);
        if (!ChartApplyTemplate(m_handle, szTemplate + ".tpl")) if (type == SYMBOL) ChartApplyTemplate(m_handle, "Default.tpl");
        if (szTemplate == "IDE") C_Chart_IDE::Create(m_IdSubWin);
        ChartRedraw(m_handle);
}
//+------------------------------------------------------------------+
void Resize(void)
{
#define macro_SetInteger(A, B) ObjectSetInteger(Terminal.Get_ID(), m_Info[c0].szObjName, A, B)
        int x0 = 0, x1, y = (int)(ChartGetInteger(Terminal.Get_ID(), CHART_HEIGHT_IN_PIXELS, m_IdSubWin));
        x1 = (int)((ChartGetInteger(Terminal.Get_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);
                if (m_Info[c0].szTemplate == "IDE") C_Chart_IDE::Resize(x0);
        }
        ChartRedraw();
#undef macro_SetInteger
}
//+------------------------------------------------------------------+

... The rest of the code

}

IDE arayüzünü yeni bir sınıf olarak eklediğimizi ve orijinal sınıfımızı kalıttığını unutmayın. Bu, orijinal sınıfın işlevselliğinin genişletileceği ve orijinal kodda herhangi bir yan etkiye neden olmayacağı anlamına gelir.

Şimdiye kadar bu kolay kısımdı. Şimdi IDE'mizi destekleyecek daha karmaşık bir şey yapmamız gerekiyor. Öncelikle sistemin kullanacağı bir mesaj protokolü oluşturalım. Bu protokol, sistemin aşağıda gösterildiği gibi çalışmasını mümkün kılacaktır:


Sistem verilerini değiştirebiliriz ama şu anda bu mümkün değildir, ancak bir mesajlaşma protokolü ekleyerek IDE'mizi işlevsel hale getirebiliriz. Bu amaçla, şunları tanımlayalım:

Mesaj Hedef
MSG_BUY_MARKET Piyasa alış emri gönderir
MSG_SELL_MARKET Piyasa satış emri gönderir
MSG_LEVERAGE_VALUE Kaldıraç verisi
MSG_TAKE_VALUE İşlemin kârı al verisi
MSG_STOP_VALUE İşlemin zararı durdur verisi
MSG_RESULT Açık pozisyonun mevcut sonucuna ilişkin veri
MSG_DAY_TRADE Günün sonunda işlemin kapanıp kapanmayacağını bildirir

Bu protokol çok önemli bir adımdır. Tanımlamalara dayalı olarak ayar dosyasında değişiklik yapılması gerekir. Ayar dosyasında nesneleri aşağıdaki gibi düzenlemelisiniz:

Lütfen şuna dikkat edin. Nesnelerin adları, kullanacağımız mesajların her biriyle eşleşir. Yukarıda tanımlamadığımız ancak arayüzdeki diğer nesnelerin adları önemli değildir, çünkü bunlar IDE'nin modellenmesine yardımcı olmak için kullanılacaktır, ancak tanımlanmış olan nesneler mesaj alacak ve gönderecektir. Daha fazla mesaj veya farklı türde mesajlar kullanmak istiyorsanız, ayar dosyasında ve sınıf kodunda gerekli değişiklikleri yapmanız yeterli, MetaTrader 5'in kendisi IDE ve Uzman Danışmanın kodu arasında mesaj alışverişini sağlayacaktır.

Ancak yine de nesne sınıfımızı nasıl oluşturacağımızı öğrenmek adına TPL dosyasını incelememiz gerekiyor. Şimdi nesnelerin TPL dosyası içinde nasıl bildirildiğini görelim. Terminal arayüzünün kendisi nesnelerin özelliklerine daha az erişim sağladığından, TPL dosyasında nesnelerin özelliklerine programlamadan daha az erişimimiz olacak. Ancak sahip olduğumuz erişim dahi IDE'mizin çalışması için yeterli olacak.

TPL dosyasının içerisinde ihtiyacımız olan yapıyı görüyoruz: <object>'den </object>'e olan bölge. Bu yapının dahilindeki verilerden ne tür bir nesne olduğunun nasıl anlaşılacağı belirsiz görünebilir. Ancak daha yakından bakarsanız, nesnenin türünün type değişkeni tarafından belirlendiğini görebilirsiniz. Nesnelerin her biri için farklı değerler mevcuttur. Aşağıdaki tablo kullanmak istediğimiz nesneleri göstermektedir:

type değişkeninin değeri İlgili nesne
102 OBJ_LABEL
103 OBJ_BUTTON
106 OBJ_BITMAP_LABEL
107  OBJ_EDIT
110  OBJ_RECTANGLE_LABEL

Sınıfımız şimdiden şekillenmeye başlıyor. İşte ilk fonksiyon kodu:

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);
        return true;
}

Lütfen yapılacak ilk şeyin dosyayı okuma modunda ve ikili dosya şeklinde açmak olduğunu unutmayın. Bu, hiçbir şeyi kaçırmamak için yapılır. HEXA düzenleyicisi kullanırken, TPL dosyası aşağıdaki gibi görünür. Çok ilginç bir değerle başladığına dikkat edin.

Kafa karıştırıcı mı geliyor? Aslında öyle değil. Dosya UTF-16 kodlamasını kullanıyor. Veriler satırlara göre düzenleniyor, dolayısıyla satırın tamamını bir kerede okumak adına bir fonksiyon oluşturalım. Bunu yapmak için şu kodu yazalım:

bool FileReadLine(void)
{
        int utf_16 = 0;
        bool b0 = false;
        m_szLine = m_szValue = "";
        for (int c0 = 0; c0 < 500; c0++)
        {
                utf_16 = FileReadInteger(m_fp, SHORT_VALUE);
                if (utf_16 == 0x000D) { FileReadInteger(m_fp, SHORT_VALUE); return true; } else
                if (utf_16 == 0x003D) b0 = true; else
                if (b0) m_szValue = StringFormat("%s%c", m_szValue, (char)utf_16); else m_szLine = StringFormat("%s%c", m_szLine, (char)utf_16);
                if (FileIsEnding(m_fp)) break;
        }
        return (utf_16 == 0x003E);
}

Okumada mümkün olduğunca verimli olmaya çalışılır, bu amaçla eşittir işaretiyle ( = ) karşılaşıldığında, daha sonra ayırma yapmamak adına ayırma okuma sırasında yapılır. Döngü, dizgeyi maksimum 500 karakterle sınırlar, ancak bu değer isteğe bağlıdır ve gerekirse değiştirilebilir. Karşılaşılan her yeni dizgeyle, fonksiyon, analize devam edebilmemiz için bize dizgenin içeriğini sağlar.

Mesaj protokolünü desteklemek için belirli değişkenlere ihtiyacımız vardır. Bu değişkenler aşağıdaki kodda gösterilmektedir:

class C_Chart_IDE
{
        protected:
                enum eObjectsIDE {eRESULT, eBTN_BUY, eBTN_SELL, eCHECK_DAYTRADE, eBTN_CANCEL, eEDIT_LEVERAGE, eEDIT_TAKE, eEDIT_STOP};
//+------------------------------------------------------------------+
#define def_HeaderMSG "IDE_"
#define def_MaxObject eEDIT_STOP + 32
//+------------------------------------------------------------------+
        private :
                int             m_fp,
                                m_SubWindow,
                                m_CountObject;
                string          m_szLine,
                                m_szValue;
                bool            m_IsDayTrade;
                struct st0
                        {
                                string  szName;
                                int     iPosX;
                        }m_ArrObject[def_MaxObject];

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

def_MaxObject tanımı, tutabileceğimiz maksimum nesne sayısını belirtir. Bu sayı, mesaj sayısına ve kullanacağımız ek nesne sayısına göre elde edilir. Bizim durumumuzda maksimum 40 nesne olacak, ancak gerekirse değiştirilebilir. İlk 8 nesne, IDE ve MetaTrader 5 arasında mesaj göndermek için kullanılacaktır. Bu mesajların diğer adı eObjectsIDE numaralandırmasında görülebilir. Sistemi genişletmek veya başka bir şeye uyarlamak istemeniz durumunda bunu aklınızda tutmanız önemlidir.

Bu, destek sisteminin yalnızca ilk kısmıdır. Dikkat edilmesi gereken bir nokta daha var: mesaj sisteminde sabitler. MQL5'in sabitlerle çalışma şekli, C/C++ ile programlama yapanlar için biraz kafa karıştırıcı olabilir. C/C++'da sabit, değişken bildiriminin kendisinde bildirilir. MQL5'te oluşturulma şekli kodu biraz daha karmaşık hale getirebilir. Bununla birlikte, sabitler oldukça nadiren kullanıldığı için bu durumla yaşayabiliriz. Sabitlerin nasıl bildirileceği aşağıda vurgulanmış olarak gösterilmektedir.

        public  :
                static const string szMsgIDE[];

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

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

Tanımlanan sabitler, arayüzdeki nesne adlarında kullanılan değerlerle tamamen aynıdır. Sistem büyük/küçük harfe duyarsız şekilde tasarlanmıştır. İsterseniz bu davranışı değiştirebilirsiniz, ancak bunu yapmanızı önermiyorum.

Tüm bu adımları tamamladıktan sonra bir sonrakine geçebilirsiniz. TPL dosyasına geri dönelim ve dosyanın şu parçasına bakalım:


Kullanılacak nesnenin türünü tanımladıktan sonra, nesnenin ad, renk, konum, yazı tipi vb. özelliklerini gösteren bir dizi verimiz daha var. Bu özellikler dahili nesnelere iletilmelidir. Tekrarlayıcı olduğundan bunun için genel bir fonksiyon oluşturabiliriz. Şu şekilde olacaktır:

bool LoopCreating(ENUM_OBJECT type)
{
#define macro_SetInteger(A, B) ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[c0].szName, A, B)
#define macro_SetString(A, B) ObjectSetString(Terminal.Get_ID(), m_ArrObject[c0].szName, A, B)
        int c0;
        bool b0;
        string sz0 = m_szValue;
        while (m_szLine != "</object>") if (!FileReadLine()) return false; else
        {
                if (m_szLine == "name")
                {
                        b0 = false;
                        StringToUpper(m_szValue);
                        for(c0 = eRESULT; (c0 <= eEDIT_STOP) && (!(b0 = (m_szValue == szMsgIDE[c0]))); c0++);
                        c0 = (b0 ? c0 : m_CountObject);
                        m_ArrObject[c0].szName = StringFormat("%s%04s>%s", def_HeaderMSG, sz0, m_szValue);
                        ObjectDelete(Terminal.Get_ID(), m_ArrObject[c0].szName);
                        ObjectCreate(Terminal.Get_ID(), m_ArrObject[c0].szName, type, m_SubWindow, 0, 0);
                }
                if (m_szLine == "pos_x"                 ) m_ArrObject[c0].iPosX = (int) StringToInteger(m_szValue);
                if (m_szLine == "pos_y"                 ) macro_SetInteger(OBJPROP_YDISTANCE    , StringToInteger(m_szValue));
                if (m_szLine == "size_x"                ) macro_SetInteger(OBJPROP_XSIZE        , StringToInteger(m_szValue));
                if (m_szLine == "size_y"                ) macro_SetInteger(OBJPROP_YSIZE        , StringToInteger(m_szValue));
                if (m_szLine == "offset_x"              ) macro_SetInteger(OBJPROP_XOFFSET      , StringToInteger(m_szValue));
                if (m_szLine == "offset_y"              ) macro_SetInteger(OBJPROP_YOFFSET      , StringToInteger(m_szValue));
                if (m_szLine == "bgcolor"               ) macro_SetInteger(OBJPROP_BGCOLOR      , StringToInteger(m_szValue));
                if (m_szLine == "color"                 ) macro_SetInteger(OBJPROP_COLOR        , StringToInteger(m_szValue));
                if (m_szLine == "bmpfile_on"            ) ObjectSetString(Terminal.Get_ID()     , m_ArrObject[c0].szName, OBJPROP_BMPFILE, 0, m_szValue);
                if (m_szLine == "bmpfile_off"           ) ObjectSetString(Terminal.Get_ID()     , m_ArrObject[c0].szName, OBJPROP_BMPFILE, 1, m_szValue);
                if (m_szLine == "fontsz"                ) macro_SetInteger(OBJPROP_FONTSIZE     , StringToInteger(m_szValue));
                if (m_szLine == "fontnm"                ) macro_SetString(OBJPROP_FONT          , m_szValue);
                if (m_szLine == "descr"                 ) macro_SetString(OBJPROP_TEXT          , m_szValue);
                if (m_szLine == "readonly"              ) macro_SetInteger(OBJPROP_READONLY     , StringToInteger(m_szValue) == 1);
                if (m_szLine == "state"                 ) macro_SetInteger(OBJPROP_STATE        , StringToInteger(m_szValue) == 1);
                if (m_szLine == "border_type"           ) macro_SetInteger(OBJPROP_BORDER_TYPE  , StringToInteger(m_szValue));
        }
        m_CountObject += (b0 ? 0 : (m_CountObject < def_MaxObject ? 1 : 0));
        return true;
                        
#undef macro_SetString
#undef macro_SetInteger
}

Her nesneye bir ad verilecek ve uygun koordinatta saklanacak, ancak vurgulanan satır farklı bir şey ifade ediyor. Bir IDE oluşturduğumuzda, grafiğin sol üst köşesinden başlamalıdır, ancak ifade edilen X konumu mutlaka alt pencerenin sol üst köşesi değildir. Bu konum, IDE'nin bağlanacağı OBJ_CHART nesnesinin sol üst köşesine karşılık gelmelidir. Nesne, IDE şablonu yüklenirken belirtilir, dolayısıyla alt pencerenin içerisinde herhangi bir yerde olabilir. Bu düzeltilmezse, IDE doğru konumda görünmeyecektir. Bu nedenle, X değerini kaydediyoruz, onu daha sonra nesneyi doğru yerde görüntülemek için kullanacağız. IDE'yi doğru şekilde oluşturan fonksiyon aşağıda gösterilmektedir.

Nesnelerde kullanılan temel bilgiler zaten tanımlıdır, ancak başka bir bilgi eklemeniz gerekiyorsa, bunu komut kümesine ekleyin ve özelliği uygun değerle değiştirin.

void Resize(int x)
{
        for (int c0 = 0; c0 < m_CountObject; c0++)
                ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[c0].szName, OBJPROP_XDISTANCE, x + m_ArrObject[c0].iPosX);
};

Mesajların nasıl işlendiğine bakmadan önce, eşit derecede önemli diğer iki fonksiyona göz atalım. Sistem, başlatma sırasında Uzman Danışmandan değerler alabilir. Bu değerler doğru bir şekilde sunulmalı ve ayarlanmalıdır, böylece ticaret arayüzünü kullanılırken, emirler Uzman Danışmana başvurmak zorunda kalmadan piyasa emri veya bekleyen emir göndermek üzere doğrudan ticaret arayüzünden yapılandırılabilir. Her iki fonksiyon da aşağıda gösterilmektedir:

void UpdateInfos(bool bSwap = false)
{
        int nContract, FinanceTake, FinanceStop;

        nContract       = (int) StringToInteger(ObjectGetString(Terminal.Get_ID(), m_ArrObject[eEDIT_LEVERAGE].szName, OBJPROP_TEXT));
        FinanceTake = (int) StringToInteger(ObjectGetString(Terminal.Get_ID(), m_ArrObject[eEDIT_TAKE].szName, OBJPROP_TEXT));
        FinanceStop = (int) StringToInteger(ObjectGetString(Terminal.Get_ID(), m_ArrObject[eEDIT_STOP].szName, OBJPROP_TEXT));
        m_IsDayTrade = (bSwap ? (m_IsDayTrade ? false : true) : m_IsDayTrade);
        ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eCHECK_DAYTRADE].szName, OBJPROP_STATE, m_IsDayTrade);
        NanoEA.Initilize(nContract, FinanceTake, FinanceStop, clrNONE, clrNONE, clrNONE, m_IsDayTrade);
}
//+------------------------------------------------------------------+
void InitilizeChartTrade(int nContracts, int FinanceTake, int FinanceStop, color cp, color ct, color cs, bool b1)
{
        NanoEA.Initilize(nContracts, FinanceTake, FinanceStop, cp, ct, cs, b1);
        if (m_CountObject < eEDIT_STOP) return;
        ObjectSetString(Terminal.Get_ID(), m_ArrObject[eEDIT_LEVERAGE].szName, OBJPROP_TEXT, IntegerToString(nContracts));
        ObjectSetString(Terminal.Get_ID(), m_ArrObject[eEDIT_TAKE].szName, OBJPROP_TEXT, IntegerToString(FinanceTake));
        ObjectSetString(Terminal.Get_ID(), m_ArrObject[eEDIT_STOP].szName, OBJPROP_TEXT, IntegerToString(FinanceStop));
        ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eCHECK_DAYTRADE].szName, OBJPROP_STATE, m_IsDayTrade = b1);
}

Lütfen IDE'nin emir sistemine bağlı olduğunu, bu nedenle sistemde yapılan değişikliklerin emir sistemine yansıtılacağını unutmayın. Bu şekilde daha önce yaptığımız gibi Uzman Danışmandaki verileri değiştirmek zorunda kalmayacağız. Bunu doğrudan IDE'den veya ticaret arayüzümüzden yapabileceğiz - bu, mesajlaşma sistemiyle bağlantılı olan yukarıda belirtilen iki fonksiyonla gerçekleştirilir.

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:
                        if (StringSubstr(szArg, 0, StringLen(def_HeaderMSG)) != def_HeaderMSG) return;
                        szArg = StringSubstr(szArg, 9, StringLen(szArg));
                        StringToUpper(szArg);
                        if ((szArg == szMsgIDE[eBTN_SELL]) || (szArg == szMsgIDE[eBTN_BUY])) NanoEA.OrderMarket(szArg == szMsgIDE[eBTN_BUY]);
                        if (szArg == szMsgIDE[eBTN_CANCEL])
                        {
                                NanoEA.ClosePosition();
                                ObjectSetInteger(Terminal.Get_ID(), m_ArrObject[eBTN_CANCEL].szName, OBJPROP_STATE, false);
                        }
                        if (szArg == szMsgIDE[eCHECK_DAYTRADE]) UpdateInfos(true);
                        break;
                case CHARTEVENT_OBJECT_ENDEDIT:
                        UpdateInfos();
                        break;
        }
}

Ve şu soru ortaya çıkıyor: Hepsi bu kadar mı? Evet, MetaTrader 5 platformunun IDE ile iletişim kurmasını sağlayan mesaj sistemi bu. Oldukça basit olduğunu itiraf etmeliyim, ancak bu fonksiyon olmasaydı IDE çalışamazdı ve sistem kurulamazdı. Bunun bir Uzman Danışmanda nasıl çalıştırılacağı biraz karmaşık görünebilir, ancak aslında öyle değil, OOP sayesinde Uzman Danışman kodu süper şekilde basit kalacak. Biraz zor olacak olan, IDE'de görünecek sonuç değerini güncellemektir. Değerler OnTick fonksiyonunda güncellenir, ancak kolaylaştırmak adına MetaTrader 5 tarafından sağlanan verileri kullandım, böylece fonksiyon şu şekilde görünüyor. Bu kısım en önemlisidir — bu fonksiyon hepsinden en çok talep edilenidir, dolayısıyla aynı zamanda en hızlısı olmalıdır.

void OnTick()
{
        SubWin.DispatchMessage(CHARTEVENT_CHART_CHANGE, C_Chart_IDE::szMsgIDE[C_Chart_IDE::eRESULT], NanoEA.CheckPosition());
}

Başka bir deyişle, her yeni tikle sınıfa mesaj gönderilir ve ticaret arayüzünde gözüken sonuç değeri, elde edilen değerle güncellenir. Ancak lütfen bu fonksiyonun iyi optimize edilmesi gerektiğini unutmayın, aksi takdirde ciddi problemler yaşayabilirsiniz.


Sonuç

Bazen bazı şeyleri yapmak imkansız gibi görünür ama ben zorluklara meydan okumayı seviyorum. Başlangıçta bunun için tasarlanmamış olan bir platformda bir RAD sisteminin nasıl oluşturulacağını sunmak benim için oldukça ilginç bir deneyimdi. Umarım basit olarak başlayan bu sistem, çok az insanın cesaret edebileceği yeni şeyleri keşfetmeye sizi motive edebilir.

Yakında bu Uzman Danışmana yeni şeyler ekleyeceğim, takipte kalın!



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

Ekli dosyalar |
EA_1.04.zip (3275.47 KB)
RSI göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? RSI göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
Bu makalede, ticaret dünyasının en popüler göstergelerden biri olan RSI'ı sizlerle paylaşacağım. Bu göstergeyi kullanarak bir ticaret sisteminin nasıl tasarlayacağını öğreneceğiz.
Bir grafikte birden fazla gösterge (Bölüm 04): Uzman Danışmanla çalışma Bir grafikte birden fazla gösterge (Bölüm 04): Uzman Danışmanla çalışma
Önceki makalelerimde, özel gösterge kullanarak birden fazla göstergenin nasıl oluşturulacağından bahsetmiştim. Bu sefer ise Uzman Danışmana nasıl birden fazla göstergenin ekleneceğini inceleyeceğ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.
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.