English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 26): Geleceğe doğru (I)

Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 26): Geleceğe doğru (I)

MetaTrader 5Örnekler | 19 Mart 2024, 11:28
96 0
Daniel Jose
Daniel Jose

Giriş

Sistem sağlamlığını nasıl artıracağımızı gördüğümüz "Sıfırdan bir ticaret Uzman Danışmanı geliştirme" serisinin 24. ve 25. bölümlerindeki kod düzeltmelerine ve iyileştirmelere rağmen, birkaç ayrıntı hala kaldı. Daha az önemli olduklarından değil, aslında aynı derecede önemlidirler.

Şimdi, nasıl ticaret yapmak istediğimizle ilgili bazı çözülmesi gereken konulara odaklanacağız. Birçok yatırımcı sadece belirli bir fiyattan emir yerleştirir ve o seviyeden hareket ettirmez. Ne olursa olsun, bunun mükemmel bir giriş noktası olduğunu varsayar ve ona dokunmaz. Durma seviyelerini değiştirebilir veya hatta durma seviyelerini silebilir, ancak giriş noktasını değiştirmez.

Bu nedenle, kodda kalan kusurlar bu yatırımcıların gerçekte nasıl çalıştığını etkilemeyecektir. Hatta emir sisteminin kusurlar içerdiğini bile fark etmeyebilirler (bu makalede düzelteceğimiz kusurları). Ancak fiyatın peşinde koşmayı sevenler, her halükarda bir işleme girmeye çalışanlar, ancak direkt olarak piyasaya girmek istemeyenler, sistemde birçok hataya tanık olacaklardır. Bu hatalardan bazıları işlemleri etkileyip güvensiz hale getirebilir (en hafif durumda), diğerleri ise para kaybına neden olarak bu tür yatırımcıları piyasa karşısında çaresiz bırakabilir.


2.0. Uygulama

Bu makaledeki yolculuğumuza, Uzman Danışmanı gerçek bir para yok edici yapan bir kusuru düzelterek başlayalım. Yine, giriş seviyesini sürekli değiştirmiyorsanız, bu sorun sizi etkilemeyecektir. Ancak, her ihtimale karşı kodunuzu güncellemeyi düşünmenizi tavsiye ederim. Düzeltme makaleye eklenen kodda zaten uygulanmış olsa da, bunun Uzman Danışmana zarar vereceğini çünkü bir miktar performans kaybedeceğini düşünebilirsiniz, ki bu doğrudur. Ancak hangisi daha iyi: biraz performans kaybetmek mi, yoksa kötü bir girişle para kaybetme riskini almak mı?


2.0.1. Giriş seviyesi hatası

Bu hata düzelteceğimiz ilk şey, ancak tüm hataların bir şekilde düzeltilmesi gerekiyor. Ancak, bu hata hepsinden daha feci. Bu, örneğin Buy Stop gibi bir bekleyen emir yerleştirdiğimizde ve giriş seviyesini, emrin artık Buy Limit türünde olması için hareket ettirdiğimizde gerçekleşir. Burada bir sorun yok gibi görünüyor, ancak mevcut geliştirme aşamasındaki Uzman Danışman değişikliği doğru şekilde yapamayacağı için bu başarısızlık oldukça felaket olacaktır. Aslında, birçok Uzman Danışman bu değişikliği yapmak ister ve bu olursa, grafikte bilgi vardır, ancak sunucu başka bilgilere sahip olacaktır. Sistem yalnızca pozisyon açıldığında doğru şekilde güncellenecektir, o zamana kadar Uzman Danışmanın grafikte gösterdiği ile sunucudaki arasındaki veriler tutarsız olacaktır.

Bazı durumlarda sadece bu tutarsızlığı yaşarken, diğer durumlarda sorun tam bir faciayla sonuçlanacaktır. Bunu anlamak için makaleyi dikkatlice okuyun.

Bu hatayı ortadan kaldırmak için farklı şekillerde uygulanabilecek bir çözümümüz var. Ancak çalışma prensibi her zaman aynı olacaktır: emri emir defterinden kaldır, yeni bir konuma taşı, emir türünü değiştir ve emir defterine geri yerleştir. Yapılması gereken budur, ancak nasıl yapılacağı özel olarak uygulanma şekline bağlı olarak değişecektir.

Biz en temel çözümü uygulayacağız, ancak ideal olmadığı için bazı problemlerle uğraşmamız gerekecektir.

Çözüm, vurgulanan satırları ekleyerek aşağıdaki fonksiyonu değiştirmektir.

void SetPriceSelection(double price)
{
        char Pending;
                
        if (m_Selection.ticket == 0) return;
        Mouse.Show();
        if (m_Selection.ticket == def_IndicatorTicket0)
        {
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price,  price + m_Selection.tp - m_Selection.pr, price + m_Selection.sl - m_Selection.pr, m_Selection.bIsDayTrade);
                RemoveIndicator(def_IndicatorTicket0);
                return;
        }
        if ((Pending = GetInfosTradeServer(m_Selection.ticket)) == 0) return;
        m_TradeLine.SpotLight();
        switch (m_Selection.it)
        {
                case IT_TAKE:
                        if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, price, m_Selection.sl);
                        else ModifyPosition(m_Selection.ticket, price, m_Selection.sl);
                        break;
                case IT_STOP:
                        if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, m_Selection.tp, price);
                        else ModifyPosition(m_Selection.ticket, m_Selection.tp, price);
                        break;
                case IT_PENDING:
                        if (!ModifyOrderPendent(m_Selection.ticket, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr)))
                        {
                                MoveSelection(macroGetLinePrice(def_IndicatorGhost, IT_PENDING));
                                m_TradeLine.SpotLight();
                        }
                        break;
        }
        RemoveIndicator(def_IndicatorGhost);
}

Bu çözüm sorunu kısmen çözse de tamamen çözmez. Örneğin, Buy Stop ve Sell Stop emirleri için bu basit satırlar eklenerek sorun çözülür. Ancak Buy Limit ve Sell Limit için, giriş seviyesini değiştirmek için tıkladığımızda sunucu emri hemen yerine getirecektir. Burada daha da kötüsü, zarar oluşturan bir pozisyona girmiş olmamızdır. Emrin boş bir emir olarak yapılandırılması (kâr veya zarar seviyeleri ile) ve Zararı Durdur seviyesinin fiyat eşiklerinin dışında olması durumunda, sunucunun emri hemen gerçekleştireceği gerçeğine ek olarak, hemen ardından kapatacaktır, bu da işlem hesabımız için tam bir felaket anlamına gelecektir. Ticaret sistemlerinin geliştirilmesinin bu kadar zor olmasının nedeni budur. Bir demo hesapta birkaç test yaparız ve her şey çalışıyor gibi görünüyorsa bir gerçek hesaba geçeriz, işte bu aşamada gerçekten neler olup bittiğini bilmeden para kaybetmeye başlarız.

Bir kez daha tekrar ediyorum: hata, giriş seviyesinin bir kez yerleştirildiği ve hiç değiştirilmediği durumu ETKİLEMEZ. Sorun, yatırımcı seviyeyi hareket ettirdiğinde ortaya çıkar.

Aslında, Stop emirleri iyi çalışıyor. Şimdi Limit bekleyen emirleriyle ilgili sorunu çözmemiz gerekiyor. Bu sorunu çözmek kolay gibi görünse de, anlaşılması gereken bir şey var: mükemmel bi̇r çözüm yoktur ve si̇stem geli̇şti̇ri̇ci̇si̇ i̇çi̇n en i̇yi̇ olan çözüm si̇zi̇n i̇çi̇n uygun olmayabi̇li̇r.

Burada bu sorunun olası çözümlerinden birini göstereceğim. Çözüm, yukarıda gösterilen aynı fonksiyonda uygulanacaktır. İşte yeni kod:

void SetPriceSelection(double price)
{
        char Pending;
        double last;
        long orderType;
                                
        if (m_Selection.ticket == 0) return;
        Mouse.Show();
        if (m_Selection.ticket == def_IndicatorTicket0)
        {
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price,  price + m_Selection.tp - m_Selection.pr, price + m_Selection.sl - m_Selection.pr, m_Selection.bIsDayTrade);
                RemoveIndicator(def_IndicatorTicket0);
                return;
        }
        if ((Pending = GetInfosTradeServer(m_Selection.ticket)) == 0) return;
        m_TradeLine.SpotLight();
        switch (m_Selection.it)
        {
                case IT_TAKE:
                        if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, price, m_Selection.sl);
                        else ModifyPosition(m_Selection.ticket, price, m_Selection.sl);
                        break;
                case IT_STOP:
                        if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, m_Selection.tp, price);
                        else ModifyPosition(m_Selection.ticket, m_Selection.tp, price);
                        break;
                case IT_PENDING:
                        orderType = OrderGetInteger(ORDER_TYPE);
                        if ((orderType == ORDER_TYPE_BUY_LIMIT) || (orderType == ORDER_TYPE_SELL_LIMIT))
                        {
                                last = SymbolInfoDouble(Terminal.GetSymbol(), (m_Selection.bIsBuy ? SYMBOL_ASK : SYMBOL_BID));
                                if (((m_Selection.bIsBuy) && (price > last)) || ((!m_Selection.bIsBuy) && (price < last)))
                                {
                                        RemoveOrderPendent(m_Selection.ticket);
                                        RemoveIndicator(m_Selection.ticket);
                                        CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr), m_Selection.bIsDayTrade);
                                        break;
                                }
                        }
                        if (!ModifyOrderPendent(m_Selection.ticket, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr)))
                        {
                                MoveSelection(macroGetLinePrice(def_IndicatorGhost, IT_PENDING));
                                m_TradeLine.SpotLight();
                        }
                        break;
        }
        RemoveIndicator(def_IndicatorGhost);
}

Bu, şu şekilde yapılmaktadır: bir bekleyen emrin giriş seviyesini değiştireceğimiz zaman, emir defterindeki (Piyasa Derinliği) emrin Sell Limit veya Buy Limit türünde olup olmadığını kontrol ederiz. Değilse, yürütme akışı koddaki başka bir noktaya devam edecektir. Eğer öyleyse, mevcut varlık fiyatını hemen yakalarız ve şu kriterleri kullanırız: alış emri için, mevcut alış (Ask) değerini yakalarız; satış emri için de mevcut satış (Bid) değerini yakalarız. Bu, son (Last) değerini kullanan eski yöntemin yerini alacaktır, çünkü bazı piyasalarda kullanılmadığı için onu referans olarak kullanmayacağız. Ardından, emir defterindeki emrin geçersiz hale gelip gelmediğini veya yalnızca değiştirilip değiştirilmediğini kontrol ederiz.

Emir hala geçerliyse, sistem doğrulama kodunu yok sayacak ve emrin değiştirileceği kısma gidecektir. Ancak Piyasa Derinliğindeki emir geçersizse, sistem aşağıdaki kodu çalıştıracaktır:

RemoveOrderPendent(m_Selection.ticket);
RemoveIndicator(m_Selection.ticket);
CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr), m_Selection.bIsDayTrade);
break;

Ancak yukarıdaki kod yalnızca Sell Limit ve Buy Limit emirlerini sırasıyla Sell Stop ve Buy Stop olarak değiştirecektir. Peki ya bu türleri orijinallerine geri döndürmek ya da böyle bir değişikliği önlemek istersek?

Sistemin emrin türünü değiştirmesini istemiyorsak, vurgulanan parçayı aşağıdaki kodla değiştirmemiz yeterlidir:

if ((orderType == ORDER_TYPE_BUY_LIMIT) || (orderType == ORDER_TYPE_SELL_LIMIT))
{
        last = SymbolInfoDouble(Terminal.GetSymbol(), (m_Selection.bIsBuy ? SYMBOL_ASK : SYMBOL_BID));
        if (((m_Selection.bIsBuy) && (price > last)) || ((!m_Selection.bIsBuy) && (price < last)))
        {
                RemoveOrderPendent(m_Selection.ticket);
                RemoveIndicator(m_Selection.ticket);
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, (m_Selection.tp == 0 ? 0 : price + m_Selection.tp - m_Selection.pr), (m_Selection.sl == 0 ? 0 : price + m_Selection.sl - m_Selection.pr), m_Selection.bIsDayTrade);
                MoveSelection(macroGetLinePrice(def_IndicatorGhost, IT_PENDING));
                m_TradeLine.SpotLight();
                break;
        }
}

Bu kod, emir türünün değiştirilmesini engelleyecektir. Bir bekleyen emrin yerine getirileceği seviyeyi değiştirebilirsiniz, ancak bir Limit emrini bir Stop emrine veya tam tersine değiştiremezsiniz. Şimdi, fiyatı takip etmeye devam etmek ve belirli bir seviyede girişi zorlamak istiyorsak, aşağıda gösterilen kodu kullanmalıyız. Bu, Uzman Danışmanda kullanılacak olan koddur.

#define def_AdjustValue(A) (A == 0 ? 0 : price + A - m_Selection.pr)
#define macroForceNewType       {                                                                                                                                               \
                RemoveOrderPendent(m_Selection.ticket);                                                                                                                         \
                RemoveIndicator(m_Selection.ticket);                                                                                                                            \
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl), m_Selection.bIsDayTrade);      \
                break;                                                                                                                                                          \
                                }

                void SetPriceSelection(double price)
                        {
                                char Pending;
                                double last;
                                long orderType;
                                
                                if (m_Selection.ticket == 0) return;
                                Mouse.Show();
                                if (m_Selection.ticket == def_IndicatorTicket0)
                                {
                                        CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price,  price + m_Selection.tp - m_Selection.pr, price + m_Selection.sl - m_Selection.pr, m_Selection.bIsDayTrade);
                                        RemoveIndicator(def_IndicatorTicket0);
                                        return;
                                }
                                if (m_Selection.ticket == def_IndicatorFloat)
                                {
                                        CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, m_Selection.pr,  m_Selection.tp, m_Selection.sl, m_Selection.bIsDayTrade);
                                        RemoveIndicator(def_IndicatorFloat);
                                        return;
                                }
                                if ((Pending = GetInfosTradeServer(m_Selection.ticket)) == 0) return;
                                m_TradeLine.SpotLight();
                                switch (m_Selection.it)
                                {
                                        case IT_TAKE:
                                                if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, price, m_Selection.sl);
                                                else ModifyPosition(m_Selection.ticket, price, m_Selection.sl);
                                                break;
                                        case IT_STOP:
                                                if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, m_Selection.tp, price);
                                                else ModifyPosition(m_Selection.ticket, m_Selection.tp, price);
                                                break;
                                        case IT_PENDING:
                                                orderType = OrderGetInteger(ORDER_TYPE);
                                                if ((orderType == ORDER_TYPE_BUY_LIMIT) || (orderType == ORDER_TYPE_SELL_LIMIT))
                                                {
                                                        last = SymbolInfoDouble(Terminal.GetSymbol(), (m_Selection.bIsBuy ? SYMBOL_ASK : SYMBOL_BID));
                                                        if (((m_Selection.bIsBuy) && (price > last)) || ((!m_Selection.bIsBuy) && (price < last))) macroForceNewType;
                                                }
                                                if (!ModifyOrderPendent(m_Selection.ticket, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl))) macroForceNewType;
                                }
                                RemoveIndicator(def_IndicatorGhost);
                        }
#undef def_AdjustValue
#undef macroForceNewType

Önemli not: ForceNewType makrosu nedeniyle bu kodla çalışırken dikkatli olun. Bu makro, çalıştırıldığında kodun 'case' bloğundan çıkmasına neden olacak bir break içeriyor. Bu nedenle, bu bloğu değiştirirken son derece dikkatli olmalısınız.

Sistem artık giriş seviyesini taşırken hata vermeyecektir, ancak sırada çözmemiz gereken başka sorunlarımız daha vardır. Emirde değişiklik yaparak ya da aynısını koruyarak sorunu düzeltmenin yolunu gösterdim - size en uygun olanı seçin. Bu çözümlerin her birinin artıları ve eksileri olduğunu unutmayın. Ancak ayrıntıya girmeyeceğim. Ben sadece sistemin nasıl düzeltileceğini ve uygulanacağını gösteriyorum.

Bu değişikliklerin sonucu aşağıdaki videoda görülebilir:



2.0.2. Gelecek için hazırlanma

Yukarıdaki değişiklik sorunu çözmektedir, ancak yapılabilecek daha fazla şey vardır. Burada bu değişimin başlangıcını göstereceğim. Uzman Danışmanın emir sistemine bakıldığında, iyileştirme için hala çok yer var. Gerekli birkaç değişiklik var ve bunları açıklamak istiyorum, böylece hangi yolun size en uygun olduğunu seçebilirsiniz, çünkü her yatırımcının piyasada kendi davranış tarzı vardır. Size göstereceğim sistemi kullanmak zorunda hissetmenizi istemiyorum. Bunun yerine, herkesin özel bir Uzman Danışman geliştirebilmesi için bir temel oluşturmak istiyorum.

Öyleyse, bir sonraki gerçeğe geçelim: 18. bölümden başlayarak, belirli bir varlığın ticaretini yapanlar için kullanımı kolay bir emir sisteminin nasıl geliştirileceğini gösteriyorum. Ancak 20. bölümde, emir sistemi görsel öğelere sahip oldu, çünkü bir noktada ticaret arayüzü ticaret için gereksiz hale gelecektir, çünkü her şey emir sisteminin kendisi tarafından gösterilecektir, böylece her şeyi doğrudan grafik üzerinde değiştirebilecek ve ayarlayabileceksiniz. Bu noktaya ulaşmak için bir yerden başlamamız gerekiyor ve bunu hemen şimdi yapacağız.

Emri grafikten kaldırmak, ticaret arayüzünden hacmi değiştirmek ve ardından emri grafiğe yeniden yerleştirmek zorunda kalmadan işlem hacmini doğrudan emirden değiştirmeye ne dersiniz? İlginç, değil mi? Bu özelliği şimdi hayata geçireceğiz. Çeşitli senaryolarda çok yardımcı olabilir, ancak sistemi nasıl kullanacağınızı öğrenmeli ve anlamalısınız çünkü başka hiçbir platformda bulamazsınız. Dürüst olmak gerekirse, böyle bir işlevselliğe sahip bir Uzman Danışman hiç görmedim. Herhangi bir Uzman Danışmanda bu işlevselliğe sahip olmak için neler yapabileceğinizi görelim.

İlk olarak, yeni bir gösterge indeksi tanımlayalım.

#define def_IndicatorFloat      3

Bir bekleyen emir bu değeri fiş olarak aldığında, tamamen farklı bir şekilde işlenebilir. Daha önce var olan her şey emir sisteminde kalırken, biz sadece yeni bir indeks ekliyoruz.

Devamında sisteme yeni bir nesne ekleyeceğiz:

C_Object_BackGround     m_BackGround;
C_Object_TradeLine      m_TradeLine;
C_Object_BtnBitMap      m_BtnClose,
                        m_BtnCheck;
C_Object_Edit           m_EditInfo1,
                        m_EditInfo2;
C_Object_Label          m_BtnMove;

Bu nesne, emir bekleyen türde olduğu sürece çeşitli şeyler yapmamıza izin verecektir.

Şimdi düzenlemek için C_Object_BitMap sınıfına geçiyoruz. Bazı tanımlar ekleyelim:

#define def_BtnClose            "Images\\NanoEA-SIMD\\Btn_Close.bmp"
#define def_BtnCheckEnabled     "Images\\NanoEA-SIMD\\CheckBoxEnabled.bmp"
#define def_BtnCheckDisabled    "Images\\NanoEA-SIMD\\CheckBoxDisabled.bmp"
//+------------------------------------------------------------------+
#resource "\\" + def_BtnClose
#resource "\\" + def_BtnCheckEnabled
#resource "\\" + def_BtnCheckDisabled

Bu sınıfta neler olup bittiğini bilmemiz gerekiyor. Bu yüzden, aşağıdaki fonksiyonları ekleyelim:

bool GetStateButton(string szObjectName) const
{
        return (bool) ObjectGetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_STATE);
}
//+------------------------------------------------------------------+
inline void SetStateButton(string szObjectName, bool bState)
{
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_STATE, bState);
}

GetStateButton, düğmenin durumunu geri döndürür. MetaTrader 5 durumu değiştirir, bu nedenle ek adımlar uygulamamıza gerek yoktur, yalnızca düğme değerinin true veya false olup olmadığını öğreniriz. Ancak durum bizim istediğimiz şeyi yansıtmıyor olabilir. Bu nedenle, durumu işlem sunucusu ve Uzman Danışman tarafından görülen mevcut durumu yansıtacak şekilde ayarlamak için SetStateButton'ı kullanacağız.

Bir başka basit değişiklik de C_Object_Edit sınıfındadır:

inline void SetOnlyRead(string szObjectName, bool OnlyRead)
{
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_READONLY, OnlyRead);
}

Değerin düzenlenip düzenlenemeyeceğini gösterir. Ticaret arayüzünü kullanmadan emir hacimlerini doğrudan grafik üzerinde değiştirebilmek istiyoruz. Oluşturulan herhangi bir bekleyen emir her zaman salt okunur modda olacaktır, ancak bunu değiştirecek bir sistem oluşturacağız.

Şimdi C_IndicatorTradeView'e geri dönelim ve birkaç değişiklik daha uygulayalım. Sistem için yeni bir fonksiyon oluşturacağız. Aşağıdaki gibidir:

#define macroSwapAtFloat(A, B) ObjectSetString(Terminal.Get_ID(), macroMountName(ticket, A, B), OBJPROP_NAME, macroMountName(def_IndicatorFloat, A, B));
                bool PendingAtFloat(ulong ticket)
                        {
                                eIndicatorTrade it;
                                
                                if (macroGetLinePrice(def_IndicatorFloat, IT_PENDING) > 0) return false;
                                macroSwapAtFloat(IT_PENDING, EV_CHECK);
                                for (char c0 = 0; c0 < 3; c0++)
                                {
                                        switch(c0)
                                        {
                                                case 0: it = IT_PENDING;        break;
                                                case 1: it = IT_STOP;           break;
                                                case 2: it = IT_TAKE;           break;
                                                default:
                                                        return false;
                                        }
                                        macroSwapAtFloat(it, EV_CLOSE);
                                        macroSwapAtFloat(it, EV_MOVE);
                                        macroSwapAtFloat(it, EV_EDIT);
                                        macroSwapAtFloat(it, EV_GROUND);
                                        macroSwapAtFloat(it, EV_LINE);
                                        m_EditInfo1.SetOnlyRead(macroMountName(def_IndicatorFloat, IT_PENDING, EV_EDIT), false);
                                }
                                return true;
                        }
#undef macroSwapAtFloat

Bu fonksiyon çağrıldığında, tüm gösterge nesneleri yeniden adlandırılır, yani emir fişine karşılık gelen değer başka bir değerle değiştirilir. Bu durumda, bu gösterge bu bölümün başında ele aldığımız göstergedir. Ancak bir problemimiz var. Gösterge nesnelerinin listesini tutmak için herhangi bir yapı kullanmıyoruz, bunu farklı bir şekilde yapıyoruz. Bu şekilde MetaTrader 5'in bu listeyi bizim için yönetmesine izin veriyoruz. Ancak bu nedenle, sınırsız yüzer emir oluşturamıyoruz çünkü yalnızca bir yüzer emre sahip olmakla sınırlı kalacağız. Bu, aşağıdaki satır kullanılarak kontrol edilebilir:

if (macroGetLinePrice(def_IndicatorFloat, IT_PENDING) > 0) return false;

Buradaki kontrol basittir: gösterge çizgisi bir yerde bulunuyorsa, makro 0'dan farklı bir değer geri döndürecektir, böylece ayrılmış fişi kullanan bir göstergenin halihazırda var olduğunu biliriz. Bu, daha sonra Uzman Danışmanın talebi reddedilen göstergenin verilerini geri yüklemesi için önemli olacaktır. MetaTrader 5, bitmap nesnesinin durumunu otomatik olarak değiştirir, dolayısıyla çağrıyı yapanı başarısızlık hakkında bilgilendirmemiz gerekir.

Bir sonraki gerekli değişiklik, göstergeleri oluşturan fonksiyondadır:

#define macroCreateIndicator(A, B, C, D)        {                                                                               \
                m_TradeLine.Create(ticket, sz0 = macroMountName(ticket, A, EV_LINE), C);                                        \
                m_BackGround.Create(ticket, sz0 = macroMountName(ticket, A, EV_GROUND), B);                                     \
                m_BackGround.Size(sz0, (A == IT_RESULT ? 84 : (A == IT_PENDING ? 108 : 92)), (A == IT_RESULT ? 34 : 22));       \
                m_EditInfo1.Create(ticket, sz0 = macroMountName(ticket, A, EV_EDIT), D, 0.0);                                   \
                m_EditInfo1.Size(sz0, 60, 14);                                                                                  \
                if (A != IT_RESULT)     {                                                                                       \
                        m_BtnMove.Create(ticket, sz0 = macroMountName(ticket, A, EV_MOVE), "Wingdings", "u", 17, C);            \
                        m_BtnMove.Size(sz0, 21, 23);                                                                            \
                                        }else                   {                                                               \
                        m_EditInfo2.Create(ticket, sz0 = macroMountName(ticket, A, EV_PROFIT), clrNONE, 0.0);                   \
                        m_EditInfo2.Size(sz0, 60, 14);  }                                                                       \
                                                }
                void CreateIndicator(ulong ticket, eIndicatorTrade it)
                        {
                                string sz0;
                                
                                switch (it)
                                {
                                        case IT_TAKE    : macroCreateIndicator(it, clrForestGreen, clrDarkGreen, clrNONE); break;
                                        case IT_STOP    : macroCreateIndicator(it, clrFireBrick, clrMaroon, clrNONE); break;
                                        case IT_PENDING:
                                                macroCreateIndicator(it, clrCornflowerBlue, clrDarkGoldenrod, def_ColorVolumeEdit);
                                                m_BtnCheck.Create(ticket, sz0 = macroMountName(ticket, it, EV_CHECK), def_BtnCheckEnabled, def_BtnCheckDisabled);
                                                m_BtnCheck.SetStateButton(sz0, true);
                                                break;
                                        case IT_RESULT  : macroCreateIndicator(it, clrDarkBlue, clrDarkBlue, def_ColorVolumeResult); break;
                                }
                                m_BtnClose.Create(ticket, macroMountName(ticket, it, EV_CLOSE), def_BtnClose);
                        }
#undef macroCreateIndicator

Vurgulanan tüm parçalar yeni sistemimizi desteklemek üzere eklendi. Temel olarak, burada her zaman true olarak ayarlanacak bir onay kutusu oluşturuyoruz, bu da emrin hemen emir defterine yerleştirileceği anlamına geliyor. Bu ticaret yöntemini değiştirmek istemedim, ancak emirlerin doğrudan yerleştirilmesini engelleyecek olan, onay kutusunun değerini 'true'dan 'false'a değiştirmek değildir. Bu değişiklik daha da derin başka değişiklikler yapılmasını gerektirecektir ve sorun şu ki, bir noktada emir yerleştirirken onay kutusunu işaretlemeyi unutabilirsiniz. Giriş seviyesi kaçırılacak ve Uzman Danışmanın kusurlu olduğunu düşüneceksiniz, oysa aslında hepsi unutkanlıktan kaynaklanmıştır. Dolayısıyla, bundan kaçınmak için, varsayılan olarak bekleyen emirler doğrudan emir defterine gidecektir, bu nedenle durumlarını açıkça değiştirmeniz gerekecektir.

Bir sonraki gerçekten önemli fonksiyon aşağıda gösterilmektedir:

#define def_AdjustValue(A) (A == 0 ? 0 : price + A - m_Selection.pr)
#define macroForceNewType       {                                                                                                                                               \
                RemoveOrderPendent(m_Selection.ticket);                                                                                                                         \
                RemoveIndicator(m_Selection.ticket);                                                                                                                            \
                CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl), m_Selection.bIsDayTrade);      \
                break;                                                                                                                                                          \
                                }

                void SetPriceSelection(double price)
                        {
                                char Pending;
                                double last;
                                long orderType;
                                
                                if (m_Selection.ticket == 0) return;
                                Mouse.Show();
                                if (m_Selection.ticket == def_IndicatorTicket0)
                                {
                                        CreateOrderPendent(m_Selection.vol, m_Selection.bIsBuy, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl), m_Selection.bIsDayTrade);
                                        RemoveIndicator(def_IndicatorTicket0);
                                        return;
                                }
                                if (m_Selection.ticket == def_IndicatorFloat)
                                {
                                        switch(m_Selection.it)
                                        {
                                                case IT_STOP   : m_Selection.sl = price; break;
                                                case IT_TAKE   : m_Selection.tp = price; break;
                                                case IT_PENDING:
                                                        m_Selection.sl = def_AdjustValue(m_Selection.sl);
                                                        m_Selection.tp = def_AdjustValue(m_Selection.tp);
                                                        m_Selection.pr = price;
                                                        break;
                                        }
                                        m_Selection.ticket = 0;
                                        m_TradeLine.SpotLight();
                                        return;
                                }
                                if ((Pending = GetInfosTradeServer(m_Selection.ticket)) == 0) return;
                                m_TradeLine.SpotLight();
                                switch (m_Selection.it)
                                {
                                        case IT_TAKE:
                                                if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, price, m_Selection.sl);
                                                else ModifyPosition(m_Selection.ticket, price, m_Selection.sl);
                                                break;
                                        case IT_STOP:
                                                if (Pending < 0) ModifyOrderPendent(m_Selection.ticket, m_Selection.pr, m_Selection.tp, price);
                                                else ModifyPosition(m_Selection.ticket, m_Selection.tp, price);
                                                break;
                                        case IT_PENDING:
                                                orderType = OrderGetInteger(ORDER_TYPE);
                                                if ((orderType == ORDER_TYPE_BUY_LIMIT) || (orderType == ORDER_TYPE_SELL_LIMIT))
                                                {
                                                        last = SymbolInfoDouble(Terminal.GetSymbol(), (m_Selection.bIsBuy ? SYMBOL_ASK : SYMBOL_BID));
                                                        if (((m_Selection.bIsBuy) && (price > last)) || ((!m_Selection.bIsBuy) && (price < last))) macroForceNewType;
                                                }
                                                if (!ModifyOrderPendent(m_Selection.ticket, price, def_AdjustValue(m_Selection.tp), def_AdjustValue(m_Selection.sl))) macroForceNewType;
                                }
                                RemoveIndicator(def_IndicatorGhost);
                        }
#undef def_AdjustValue
#undef macroForceNewType

Vurgulanan kod parçaları ilginç bir şey yapar: yalnızca seçicide kullanılacak değerleri günceller, ancak bu değerler aslında göstergenin kendisinde saklanır. Sistemi daha genel bir şekilde hareket ettiriyor da olabiliriz, bu nedenle konum hesaplamalarını gerçekleştiren fonksiyonun doğru değerleri belirtmesi için bu değerlerin seçicide belirtilmesi gerekir.

Bu fonksiyonda mantıklı gelmeyebilecek bir şey var. Bir bekleyen emrin verilerini oluşturmaktan ve değiştirmekten sorumludur, ancak ona bakarsanız, bekleyen emrin emir defterine geri yerleştirileceği herhangi bir nokta görmezsiniz. Emri doğrudan grafik üzerinde taşıyabilir, değiştirebilir ve hacmini ayarlayabilirsiniz, ancak grafiğe nasıl döneceğini göremezsiniz.

Bu bir gerçektir. Bekleyen emirleri değiştirmek ve oluşturmak için tüm sistem yukarıdaki fonksiyonda uygulanmaktadır. Garip bir şekilde, bu fonksiyon emri sadece biz istediğimiz için değil, aşağıda gösterildiği gibi gerçekten bir talepte bulunduğu için emir defterine geri yerleştirir. Karmaşıklaştırmamak adına, yalnızca Piyasa Derinliğinde emir yerleştirme talebinden sorumlu kısmı göstereceğim.

void DispatchMessage(int id, long lparam, double dparam, string sparam)
{

// ... Internal code...

        case CHARTEVENT_OBJECT_CLICK:
                if (GetIndicatorInfos(sparam, ticket, it, ev)) switch (ev)
                {
                        case EV_CLOSE:
                                if (ticket == def_IndicatorFloat) RemoveIndicator(def_IndicatorFloat, it);
                                else if ((cRet = GetInfosTradeServer(ticket)) != 0) switch (it)
                                {
                        case IT_PENDING:
                        case IT_RESULT:
                                if (cRet < 0) RemoveOrderPendent(ticket); else ClosePosition(ticket);
                                break;
                        case IT_TAKE:
                        case IT_STOP:
                                m_Selection.ticket = ticket;
                                m_Selection.it = it;
                                SetPriceSelection(0);
                        break;
                }
                break;
        case EV_MOVE:
                if (ticket == def_IndicatorFloat)
                {
                        m_Selection.ticket = ticket;
                        m_Selection.it = it;
                }else   CreateGhostIndicator(ticket, it);
                break;
        case EV_CHECK:
                if (ticket != def_IndicatorFloat)
                {
                        if (PendingAtFloat(ticket)) RemoveOrderPendent(ticket);
                        else m_BtnCheck.SetStateButton(macroMountName(ticket, IT_PENDING, EV_CHECK), true);
                } else
                {
                        m_Selection.ticket = def_IndicatorTicket0;
                        m_Selection.it = IT_PENDING;
                        m_Selection.pr = macroGetLinePrice(def_IndicatorFloat, IT_PENDING);
                        m_Selection.sl = macroGetLinePrice(def_IndicatorFloat, IT_STOP);
                        m_Selection.tp = macroGetLinePrice(def_IndicatorFloat, IT_TAKE);
                        m_Selection.bIsBuy = (m_Selection.pr < m_Selection.tp) || (m_Selection.sl < m_Selection.pr);
                        m_Selection.bIsDayTrade = true;
                        m_Selection.vol = m_EditInfo1.GetTextValue(macroMountName(def_IndicatorFloat, IT_PENDING, EV_EDIT)) * Terminal.GetVolumeMinimal();
                        SetPriceSelection(m_Selection.pr);
                        RemoveIndicator(def_IndicatorFloat);
                }

// ... Rest of the code...

Sistemin kendini nasıl inşa ettiğine bakın: sistem büyüdükçe daha az programlıyoruz.

Vurgulanan kodun, bölümün başında oluşturduğumuz gösterge ile bir ilgisi vardır. Her şey iyi çalışıyor gibi görünse de, daha sonra değiştirilecek bazı şeylere sahibiz çünkü yüzer emir, emir defterine geri yerleştirildiğinde, sona erme zamanı bugün olarak bir dezavantaja sahip olacaktır, yani gün sonunda kapatılacaktır. Daha sonra değiştirilecektir, ancak bunun farkında olmalısınız. Şimdi tüm bunlar kafanızı karıştırmış olabilir ve onay kutusuna tıkladığımızda bekleyen emrin gerçekte emir defterine nasıl girip çıktığını hala anlamamış olabilirsiniz. Aşağıdaki diyagrama bakın:

Tüm çağrıların aynı yerden geldiğini görüyoruz. Piyasa Derinliğinden kaldırılmış bir emrimiz var, ancak grafikte yer almaya devam edecektir. Tüm manipülasyonlar önceki makalelerde gösterildiği gibi gerçekleştirilir. Ancak emrin Piyasa Derinliğine geri yerleştirileceği belirli bir zamanı bulmaya çalışırsanız, kodda biraz kaybolabilirsiniz. Şimdi diyagrama bakarsanız, çağrının DispatchMessage fonksiyonundan geldiğini görebilirsiniz, çünkü SetPriceSelection fonksiyonunu çağıran tek yer burasıdır. Ancak SetPriceSelection fonksiyonuna bakarsak, yüzer sistemde kullanılan indeks ile bir emir oluşturma referansı yoktur. Ama bir şeye dikkat edin. İndeks 0'a göre emir oluşturuyoruz ve tam olarak bunu kullanıyoruz. Emir fişini değiştiriyoruz ve bunun indeks 0 fişi olacağını bildiriyoruz - bu şekilde emir oluşturulacaktır. Bunun nasıl çalıştığını anlamak için aşağıdaki koda bakın.

m_Selection.ticket = def_IndicatorTicket0;
m_Selection.it = IT_PENDING;
m_Selection.pr = macroGetLinePrice(def_IndicatorFloat, IT_PENDING);
m_Selection.sl = macroGetLinePrice(def_IndicatorFloat, IT_STOP);
m_Selection.tp = macroGetLinePrice(def_IndicatorFloat, IT_TAKE);
m_Selection.bIsBuy = (m_Selection.pr < m_Selection.tp) || (m_Selection.sl < m_Selection.pr);
m_Selection.bIsDayTrade = true;
m_Selection.vol = m_EditInfo1.GetTextValue(macroMountName(def_IndicatorFloat, IT_PENDING, EV_EDIT)) * Terminal.GetVolumeMinimal();
SetPriceSelection(m_Selection.pr);
RemoveIndicator(def_IndicatorFloat);

Vurgulanan satır dışında kod mükemmel. Şu anda bunu düzeltmenin bir yolu yok. Sınıfın kendisinde bazı değişiklikler yapmamız gerekeceğinden, bu bir sonraki makalede yapılacaktır.

Aşağıdaki video değişikliklerin sonucunu göstermektedir. Hacmin nasıl değiştirildiğine ve belirtilen seviyede yeni bir emrin nasıl gönderildiğine dikkat edin. Uzman Danışmanın kullanımı artık çok daha kolay.



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

Ekli dosyalar |
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 27): Geleceğe doğru (II) Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 27): Geleceğe doğru (II)
Doğrudan grafik üzerinde daha eksiksiz bir emir sistemine geçiş yapıyoruz. Bu makalede, emir sistemini düzeltmenin, daha doğrusu daha kolay anlaşılır hale getirmenin bir yolunu göreceğiz.
Fractals göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? Fractals göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
En popüler teknik göstergelere dayalı ticaret sistemleri tasarladığımız serimizin yeni makalesindeyiz. Bu makalede Fractals göstergesini ve ona dayalı olarak MetaTrader 5 terminalinde yürütülecek bir ticaret sisteminin nasıl geliştirileceğini öğreneceğiz.
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 28): Geleceğe doğru (III) Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 28): Geleceğe doğru (III)
Emir sistemimizin hala yapamadığı bir görev var, ancak bunu nihayet çözeceğiz. MetaTrader 5, emir değerlerinin oluşturulmasına ve düzeltilmesine olanak tanıyan bir fiş sistemi sağlar. Fikir, aynı fiş sistemini daha hızlı ve daha verimli hale getirecek bir Uzman Danışmana sahip olmaktır.
Popülasyon optimizasyon algoritmaları: İstilacı yabancı ot optimizasyonu (Invasive Weed Optimization, IWO) Popülasyon optimizasyon algoritmaları: İstilacı yabancı ot optimizasyonu (Invasive Weed Optimization, IWO)
Yabancı otların çok çeşitli koşullarda hayatta kalma konusundaki şaşırtıcı yeteneği, güçlü bir optimizasyon algoritması için bir fikir haline gelmiştir. IWO, daha önce incelenenler arasındaki en iyi algoritmalardan biridir.