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

MetaTrader 5Örnekler | 19 Mart 2024, 11:38
99 0
Daniel Jose
Daniel Jose

Giriş

Bir önceki makalede, Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 26): Geleceğe doğru (I), emir sisteminde var olan yıkıcı bir hatayı düzelttik. Yeni emir sisteminin işleyişini sağlayacak değişiklikleri de uygulamaya başladık. Uygulanan sistem oldukça ilginç olmasına rağmen, onu çalışamaz hale getiren bir kusura sahiptir. Bu kusurdan bir önceki makalenin sonunda bahsetmiştik. Bu kusur, diğer küçük problemlerin yanı sıra, emrin ya da pozisyonun ne zaman sona ereceğini seçemememizden kaynaklanıyordu. Sistem, işlem seansının veya mevcut günün sonunda kapatılması gereken bir emir veya pozisyon olarak ayarlandı. Ancak bazen daha uzun süreli işlemler yapmak isteriz, bu nedenle her şeyi olduğu gibi bırakmak gerçekten yardımcı olmaz.

Bu nedenle, bu makalede size bir çözüm göstereceğim. Her bir emrin ne olduğunu, nasıl işlendiğini ve ne tür bir hareket beklendiğini anında ve doğru bir şekilde belirleyebilmeniz için emir sistemini nasıl daha sezgisel hale getireceğimizi göreceğiz.

Bu sistem o kadar ilginç, basit ve anlaşılması kolay ki, bir kez işleyişini gördüğünüzde onsuz bir daha çalışmak istemeyeceksiniz. Bu makalede size göstereceğim şey, emir sisteminde uygulayabileceğiniz birçok olasılıktan sadece bir tanesidir. Belki daha sonra başka şeyler de göstereceğim, ancak bu makalede göreceklerimiz, kendi özel durumunuz için başka yararlı ve ilginç değişiklikler oluşturabilmeniz adına mükemmel bir temel sağlayabilir. Bu amaçla, bu makalelerdeki her şeyi mümkün olduğunca genel tutmaya çalışıyorum.


2.0. Anlaşılması kolay model

Şu ana kadar emirlerle aşağıdaki şekilde çalıştık:

Kârı Al ve Zararı Durdur göstergeleri oldukça açıklayıcı olan bir forma sahiptir: yeşil, hesabımıza ne kadar kazanç olacağını ve kırmızı ise hesabımızdan ne kadar zarar düşüleceğini göstermektedir. Her şey nettir. Aşağıda gösterildiği gibi bir durma göstergemiz varsa, Zararı Durdurun etkinleştirilmesinin ilgili miktarın hesabımıza eklenmesine neden olacağını belirtir. Başka bir deyişle, durma emri seviyeleri en azından şimdilik bizim çabamızı gerektirmiyor. Belki gelecekte içlerindeki bir şeyi değiştirmek isteyebilirsiniz, ancak şu anda kullanım için oldukça uygunlar.

Durma seviyelerini kullanmanın bu yolu, herhangi bir yatırımcının analiz etmesi için oldukça basit ve kullanışlıdır. Ancak elimizde çok net olmayan bir şey var. Birincisi, bekleyen emir giriş seviyesi göstergesidir.

Bu bekleyen emrin bir alış emri mi yoksa satış emri mi olduğunu bilebiliyor muyuz? Ve bir şey daha: bu bekleyen emrin gün sonunda kapatılıp kapatılmayacağını veya daha uzun süreli bir pozisyon açılıp açılmayacağını bilmek mümkün mü? Karmaşık, değil mi? Şimdi, halihazırda açık pozisyonlarımız olduğunu varsayalım, gösterge aşağıdaki gibi görünecektir:

Ve yine, bekleyen emir göstergelerinde olduğu gibi aynı sorunları yaşıyoruz. Grafiğe baktığınızda ve bu göstergeleri gördüğünüzde, pozisyonun gün sonunda kapatılıp kapatılmayacağını veya daha uzun süre devam edip etmeyeceğini kesin olarak söyleyemezsiniz. Gün sonunda kapanırsa, bunun için masraf ödemeniz gerekeceğinden, brokerın pozisyonu mecburi olarak durdurmasını istemezsiniz. Ve herhangi bir kriter olmadan emirleri kapatmak pek mantıklı bir şey değildir; MetaTrader araç kutusu bile bu bilgiyi göstermez, dolayısıyla gösterge aracılığıyla grafikte olması harikadır.

Bu nedenle, neler olduğunu daha iyi anlamak için burada, özellikle pozisyon giriş seviyesini gösteren göstergelerde değişiklikler yapmamız gerekecektir.


2.0.1. Göstergelere yeni bilgiler nasıl eklenir?

Grafik üzerinde fazla yer kaplamadan yeni bilgiler eklemenin en kolay yolu, anlaşılması kolay ve oldukça açıklayıcı oldukları için bitmap kullanmaktır. Bu amaçla, herhangi bir ek kod eklemeden, Uzman Danışmana C_IndicatorTradeView sınıfında görülebilen dört yeni bitmap ekliyoruz.

#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"
#define def_BtnDayTrade         "Images\\NanoEA-SIMD\\Inf_DayTrade.bmp"
#define def_BtnSwing            "Images\\NanoEA-SIMD\\Inf_Swing.bmp"
#define def_BtnInfoBuy          "Images\\NanoEA-SIMD\\Inf_Buy.bmp"
#define def_BtnInfoSell         "Images\\NanoEA-SIMD\\Inf_Sell.bmp"
//+------------------------------------------------------------------+
#resource "\\" + def_BtnClose
#resource "\\" + def_BtnCheckEnabled
#resource "\\" + def_BtnCheckDisabled
#resource "\\" + def_BtnDayTrade
#resource "\\" + def_BtnSwing
#resource "\\" + def_BtnInfoBuy
#resource "\\" + def_BtnInfoSell

Buna ek olarak, emir sisteminde yalnızca iki yeni nesne uygulamamız gerekiyor.

//+------------------------------------------------------------------+
enum eIndicatorTrade {IT_NULL, IT_STOP= 65, IT_TAKE, IT_PENDING, IT_RESULT};
enum eEventType {EV_NULL, EV_GROUND = 65, EV_LINE, EV_CLOSE, EV_EDIT, EV_PROFIT, EV_MOVE, EV_CHECK, EV_TYPE, EV_DS};
//+------------------------------------------------------------------+
C_Object_BackGround     m_BackGround;
C_Object_TradeLine      m_TradeLine;
C_Object_BtnBitMap      m_BtnClose,
                        m_BtnCheck,
                        m_BtnInfoType,
                        m_BtnInfo_DS;
C_Object_Edit           m_EditInfo1,
                        m_EditInfo2;
C_Object_Label          m_BtnMove;

Yeni bir nesne ekleyeceğimiz zaman, nesneye bağlı bir olay da eklememiz gerekecektir, bu da nesnenin benzersiz bir ada sahip olmasını sağlayacaktır.

Şimdi programlamanın en ilginç kısmı geliyor. Yapmamız gereken ilk şey hayaletlerle ilgilenmek. İçlerinde bulunan bilgileri saklamaları için onları güncellememiz gerekiyor. Elbette silinebilir, ancak temel verileri saklamanın daha iyi olacağını düşünüyorum. Aşağıdaki koda bakalım:

#define macroSwapName(A, B) ObjectSetString(Terminal.Get_ID(), macroMountName(ticket, A, B), OBJPROP_NAME, macroMountName(def_IndicatorGhost, A, B));
                void CreateGhostIndicator(ulong ticket, eIndicatorTrade it)
                        {
                                if (GetInfosTradeServer(m_Selection.ticket = ticket) != 0)
                                {
                                        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, false);
                                        macroSwapName(it, EV_LINE);
                                        macroSwapName(it, EV_GROUND);
                                        macroSwapName(it, EV_MOVE);
                                        macroSwapName(it, EV_EDIT);
                                        macroSwapName(it, EV_CLOSE);
                                        if (it == IT_PENDING)
                                        {
                                                macroSwapName(it, EV_CHECK);
                                                macroSwapName(it, EV_TYPE);
                                                macroSwapName(it, EV_DS);
                                        }
                                        m_TradeLine.SetColor(macroMountName(def_IndicatorGhost, it, EV_LINE), def_IndicatorGhostColor);
                                        m_BackGround.SetColor(macroMountName(def_IndicatorGhost, it, EV_GROUND), def_IndicatorGhostColor);
                                        m_BtnMove.SetColor(macroMountName(def_IndicatorGhost, it, EV_MOVE), def_IndicatorGhostColor);
                                        ObjectDelete(Terminal.Get_ID(), macroMountName(def_IndicatorGhost, it, EV_CLOSE));
                                        m_TradeLine.SpotLight();
                                        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, true);
                                        m_Selection.it = it;
                                }else m_Selection.ticket = 0;
                        }
#undef macroSwapName

Vurgulanan satırlar nesneleri hayalete iletir, bu çok basit ve açıktır. Bir başka basit kod da göstergeleri bekleyen durumdan yüzer duruma dönüştürür.

#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);
                                macroSwapAtFloat(IT_PENDING, EV_TYPE);
                                macroSwapAtFloat(IT_PENDING, EV_DS);
                                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

Vurgulanan satırlar nesneleri yüzer göstergeye dönüştürerek gerekli eylemleri daha sonra gerçekleştirmemize olanak tanır. Şimdi göstergeyi oluşturan kodda bazı değişiklikler yapmamız gerekiyor. Bu, hoşunuza gidene kadar test edeceğiniz ve ayarlayacağınız bir şeydir. Temel olarak, değişiklikler aşağıdaki kodda vurgulanan kısımlarda yapılmıştı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 ? 100 : (A == IT_PENDING ? 144 : 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);  }                                                                       \
                                                }
                                                                                                                
#define macroInfoBase(A)        {                                                                                               \
                m_BtnInfoType.Create(ticket, sz0 = macroMountName(ticket, A, EV_TYPE), def_BtnInfoBuy, def_BtnInfoSell);        \
                m_BtnInfoType.SetStateButton(sz0, m_Selection.bIsBuy);                                                          \
                m_BtnInfo_DS.Create(ticket, sz0 = macroMountName(ticket, A, EV_DS), def_BtnDayTrade, def_BtnSwing);             \
                m_BtnInfo_DS.SetStateButton(sz0, m_Selection.bIsDayTrade);                                                      \
                                }

                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);
                                                macroInfoBase(IT_PENDING);
                                                break;
                                        case IT_RESULT  :
                                                macroCreateIndicator(it, clrSlateBlue, clrSlateBlue, def_ColorVolumeResult);
                                                macroInfoBase(IT_RESULT);
                                                break;
                                }
                                m_BtnClose.Create(ticket, macroMountName(ticket, it, EV_CLOSE), def_BtnClose);
                        }
#undef macroInfoBase
#undef macroCreateIndicator

macroInfoBase'in göstergede kullanılan nesneleri oluşturduğunu, ancak bu nesnelerin yalnızca pozisyon açma ve pozisyon sonucu göstergelerinde oluşturulacağını, diğer göstergelerde bu nesneleri oluşturmaya gerek olmadığını unutmayın. Ancak nesneleri, onları oluşturduğumuz yerde konumlandırmadığımıza dikkat edin. Bu, daha sonra gösterilecek olan başka bir yerde yapılacaktır.

#define macroSetAxleY(A)                {                                                                               \
                m_BackGround.PositionAxleY(macroMountName(ticket, A, EV_GROUND), y);                                    \
                m_TradeLine.PositionAxleY(macroMountName(ticket, A, EV_LINE), y);                                       \
                m_BtnClose.PositionAxleY(macroMountName(ticket, A, EV_CLOSE), y);                                       \
                if (A != IT_RESULT)m_BtnMove.PositionAxleY(macroMountName(ticket, A, EV_MOVE), y, 1);                   \
                else m_EditInfo2.PositionAxleY(macroMountName(ticket, A, EV_PROFIT), y, 1);                             \
                m_EditInfo1.PositionAxleY(macroMountName(ticket, A, EV_EDIT), y, (A == IT_RESULT ? -1 : 0));            \
                if (A == IT_PENDING) m_BtnCheck.PositionAxleY(macroMountName(ticket, A, EV_CHECK), y);                  \
                if ((A == IT_PENDING) || (A == IT_RESULT))      {                                                       \
                        m_BtnInfoType.PositionAxleY(macroMountName(ticket, A, EV_TYPE), y + (A == IT_PENDING ? 0 : 8)); \
                        m_BtnInfo_DS.PositionAxleY(macroMountName(ticket, A, EV_DS), y - (A == IT_PENDING ? 0: 8));     \
                                                                }                                                       \
                                        }
                                                                        
#define macroSetAxleX(A, B)             {                                                                                               \
                m_BackGround.PositionAxleX(macroMountName(ticket, A, EV_GROUND), B);                                                    \
                m_TradeLine.PositionAxleX(macroMountName(ticket, A, EV_LINE), B);                                                       \
                m_BtnClose.PositionAxleX(macroMountName(ticket, A, EV_CLOSE), B + 3);                                                   \
                m_EditInfo1.PositionAxleX(macroMountName(ticket, A, EV_EDIT), B + 21);                                                  \
                if (A != IT_RESULT) m_BtnMove.PositionAxleX(macroMountName(ticket, A, EV_MOVE), B + 80 + (A == IT_PENDING ? 52 : 0));   \
                else m_EditInfo2.PositionAxleX(macroMountName(ticket, A, EV_PROFIT), B + 21);                                           \
                if (A == IT_PENDING) m_BtnCheck.PositionAxleX(macroMountName(ticket, A, EV_CHECK), B + 82);                             \
                if ((A == IT_PENDING) || (A == IT_RESULT))      {                                                                       \
                        m_BtnInfoType.PositionAxleX(macroMountName(ticket, A, EV_TYPE), B + (A == IT_PENDING ? 100 : 82));              \
                        m_BtnInfo_DS.PositionAxleX(macroMountName(ticket, A, EV_DS), B + (A == IT_PENDING ? 118 : 82));                 \
                                                                }                                                                       \
                                        }
//---
        void ReDrawAllsIndicator(void)
                        {
                                C_IndicatorTradeView::st00 Local;
                                int             max = ObjectsTotal(Terminal.Get_ID(), -1, OBJ_EDIT);
                                ulong           ticket;
                                eIndicatorTrade it;
                                eEventType ev;
                                
                                Local = m_Selection;
                                m_Selection.ticket = 0;
                                for (int c0 = 0; c0 <= max; c0++)
                                   if (GetIndicatorInfos(ObjectName(Terminal.Get_ID(), c0, -1, OBJ_EDIT), ticket, it, ev))
                                      if ((it == IT_PENDING) || (it == IT_RESULT))
                                      {
                                        PositionAxlePrice(ticket, IT_STOP, macroGetLinePrice(ticket, IT_STOP));
                                        PositionAxlePrice(ticket, IT_TAKE, macroGetLinePrice(ticket, IT_TAKE));
                                        PositionAxlePrice(ticket, it, macroGetLinePrice(ticket, it));
                                        }
                                m_Selection = Local;
                                ChartRedraw();
                        }
//---
inline void PositionAxlePrice(ulong ticket, eIndicatorTrade it, double price)
                        {
                                int x, y, desl;
                                
                                ChartTimePriceToXY(Terminal.Get_ID(), 0, 0, price, x, y);
                                macroSetLinePrice(ticket, it, price);
                                macroSetAxleY(it);
                                switch (it)
                                {
                                        case IT_TAKE: desl = 160; break;
                                        case IT_STOP: desl = 270; break;
                                        default: desl = 0;
                                }
                                macroSetAxleX(it, desl + (int)(ChartGetInteger(Terminal.Get_ID(), CHART_WIDTH_IN_PIXELS) * 0.2));
                        }
#undef macroSetAxleX
#undef macroSetAxleY

Kodda köklü ve radikal değişiklikler yapmaktan hoşlanmadığımı da vurgulamak isterim. Temel olarak, tek değişiklik yukarıdaki kodda vurgulanmıştır.


2.0.2. Görünürdeki sorunlar

Her şey mükemmel çalışıyor olsa da, bir sorunumuz var. Tüm MQL5 dokümantasyonunu araştırdım, ancak bu sorunu basit bir şekilde çözmenin bir yolunu bulamadım. Sorun, yeni açılan bir pozisyonun günlük işlem (aynı gün içinde kısa süreli işlemler) mi yoksa swing işlemi (daha uzun süreli işlemler) mi olduğunu nasıl bileceğinizdir. Bir gün önce açılan daha eski bir pozisyon söz konusu olduğunda, bu tür bir analiz yapmak oldukça basittir, çünkü mevcut gün ile pozisyonun açılış gününü karşılaştırmak yeterli olacaktır: eğer farklılarsa, pozisyon bir swing işlemidir. Peki ya Uzman Danışman kapalıysa ve pozisyonun açıldığı gün başlatırsanız? Bu durumda, pozisyonun günlük işlem mi yoksa swing işlemi mi olduğunu bilmenin bir yolu yoktur.

Bu sorun bekleyen emirler için mevcut değildir, çünkü bunu kontrol etmenin bir yolu vardır. ORDER_TYPE_TIME parametresi kullanılarak OrderGetInteger çağrıldığında, emrin günlük işlem mi yoksa swing işlemi mi olduğunu gösteren ENUM_ORDER_TYPE_TIME numaralandırmasından bir değer geri döndürülür. Ancak aynı şey pozisyonlar için geçerli değildir.

Bu nedenle, bu durum için benim çözümüm, diğer bilgilerden bağımsız olarak Uzman Danışmanın işlemin süresini bilmesini sağlamak için emre veya pozisyona bir şey eklemektir. Ancak bu mükemmel bir çözüm değildir, çünkü sorunu birkaç durumda çözer, ancak hepsinde çözmez. Çünkü yatırımcı, değerlendirme için gereken süreden önce işlemin swing veya günlük işlem olup olmadığını belirlemek için Uzman Danışman tarafından kullanılan sistemi değiştirebilir.

Daha iyi anlamak için çözümün nasıl uygulandığını görelim.

inline char GetInfosTradeServer(ulong ticket)
{
        long info;
                                
        if (ticket == 0) return 0;
        if (OrderSelect(ticket))
        {
                if (OrderGetString(ORDER_SYMBOL) != Terminal.GetSymbol()) return 0;
                info = OrderGetInteger(ORDER_TYPE);
                m_Selection.bIsBuy = ((info == ORDER_TYPE_BUY_LIMIT) || (info == ORDER_TYPE_BUY_STOP) || (info == ORDER_TYPE_BUY_STOP_LIMIT) || (info == ORDER_TYPE_BUY));
                m_Selection.pr = OrderGetDouble(ORDER_PRICE_OPEN);
                m_Selection.tp = OrderGetDouble(ORDER_TP);
                m_Selection.sl = OrderGetDouble(ORDER_SL);
                m_Selection.vol = OrderGetDouble(ORDER_VOLUME_CURRENT);
                m_Selection.bIsDayTrade = ((ENUM_ORDER_TYPE_TIME)OrderGetInteger(ORDER_TYPE_TIME) == ORDER_TIME_DAY);
                                        
                return -1;
        }
        if (PositionSelectByTicket(ticket))
        {
                if (PositionGetString(POSITION_SYMBOL) != Terminal.GetSymbol()) return 0;
                m_Selection.bIsBuy = PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY;
                m_Selection.pr = PositionGetDouble(POSITION_PRICE_OPEN);
                m_Selection.tp = PositionGetDouble(POSITION_TP);
                m_Selection.sl = PositionGetDouble(POSITION_SL);
                m_Selection.vol = PositionGetDouble(POSITION_VOLUME);
                if (macroGetDate(PositionGetInteger(POSITION_TIME)) == macroGetDate(TimeTradeServer()))
                        m_Selection.bIsDayTrade = PositionGetString(POSITION_COMMENT) == def_COMMENT_TO_DAYTRADE;
                else m_Selection.bIsDayTrade = false;
                                        
                return 1;
        }
        return 0;
}

Yukarıda belirtildiği gibi, bekleyen emirler söz konusu olduğunda, OrderGetInteger'ı çağırmak ve ihtiyacımız olan değeri almak yeterlidir. Pozisyonlar söz konusu olduğunda durum biraz daha karmaşıktır. Şu şekilde çalışır: pozisyonun açılış günü ve işlem sunucusunun geçerli günü kontrol edilir. Her ikisi de aynıysa, emirdeki yorum kontrol edilir. Yorum, pozisyon açıldığında bunun günlük işlem olacağını belirtmek için C_Router sınıfında kullanılan dizgeyi gösteriyorsa, Uzman Danışman bunu değerlendirecek ve pozisyon göstergesinde görüntüleyecektir. Ancak yorum gün sonuna kadar değişmemelidir, çünkü değişirse, Uzman Danışman günlük işlem pozisyonunun aslında bir swing işlemi olduğunu bildirebilir, bu durumda bu Uzman Danışmanın hatası değildir, yatırımcı yorumu çok erken değiştirmiştir.

Bu çözümün dezavantajı budur, ancak sadece pozisyon verilerine bakarak pozisyonun günlük işlem olup olmadığının nasıl belirlenebileceğine dair bir fikri olan varsa, lütfen yorumlarda paylaşın.

Bekleyen emirler söz konusu olduğunda nasıl göründüğü aşağıdaki videoda gösterilmektedir:


Artık neredeyse her şey hazır, sadece Uzman Danışmanın kullanışlılığını artırmak için koda biraz daha ekleme yapmamız gerekiyor.


2.0.3. Platform mesajlarına yanıt verme

Tüm emir sistemimiz MetaTrader 5 tarafından gönderilen mesajlara dayanmaktadır, böylece Uzman Danışman neyin yapılması veya yapılmaması gerektiğini bilebilir. Bu nedenle mesaj sisteminin nasıl uygulandığını bilmek çok önemlidir.

Mesajlaşma ile ilgili kodun tamamı aşağıda gösterilmiştir:

#define macroGetDataIndicatorFloat      {                                                                                                               \
                m_Selection.vol = m_EditInfo1.GetTextValue(macroMountName(def_IndicatorFloat, IT_PENDING, EV_EDIT)) * Terminal.GetVolumeMinimal();      \
                m_Selection.bIsBuy = m_BtnInfoType.GetStateButton(macroMountName(def_IndicatorFloat, IT_PENDING, EV_TYPE));                             \
                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.bIsDayTrade = m_BtnInfo_DS.GetStateButton(macroMountName(def_IndicatorFloat, IT_PENDING, EV_DS));                           \
                                        }
                                                                                                
                void DispatchMessage(int id, long lparam, double dparam, string sparam)
                        {
                                ulong   ticket;
                                double  price;
                                bool   	bKeyBuy,
                                        bKeySell,
                                        bEClick;
                                datetime dt;
                                uint     mKeys;
                                char     cRet;
                                eIndicatorTrade  it;
                                eEventType       ev;
                                
                                static bool bMounting = false;
                                static double valueTp = 0, valueSl = 0, memLocal = 0;
                                
                                switch (id)
                                {
                                        case CHARTEVENT_MOUSE_MOVE:
                                                Mouse.GetPositionDP(dt, price);
                                                mKeys   = Mouse.GetButtonStatus();
                                                bEClick  = (mKeys & 0x01) == 0x01;    //Left mouse click
                                                bKeyBuy  = (mKeys & 0x04) == 0x04;    //SHIFT pressed
                                                bKeySell = (mKeys & 0x08) == 0x08;    //CTRL pressed
                                                if (bKeyBuy != bKeySell)
                                                {
                                                        if (!bMounting)
                                                        {
                                                                m_Selection.bIsDayTrade = Chart.GetBaseFinance(m_Selection.vol, valueTp, valueSl);
                                                                valueTp = Terminal.AdjustPrice(valueTp * Terminal.GetAdjustToTrade() / m_Selection.vol);
                                                                valueSl = Terminal.AdjustPrice(valueSl * Terminal.GetAdjustToTrade() / m_Selection.vol);
                                                                m_Selection.it = IT_PENDING;
                                                                m_Selection.pr = price;
                                                        }
                                                        m_Selection.tp = m_Selection.pr + (bKeyBuy ? valueTp : (-valueTp));
                                                        m_Selection.sl = m_Selection.pr + (bKeyBuy ? (-valueSl) : valueSl);
                                                        m_Selection.bIsBuy = bKeyBuy;
                                                        m_BtnInfoType.SetStateButton(macroMountName(def_IndicatorTicket0, IT_PENDING, EV_TYPE), bKeyBuy);
                                                        if (!bMounting)
                                                        {
                                                                IndicatorAdd(m_Selection.ticket = def_IndicatorTicket0);
                                                                bMounting = true;
                                                        }
                                                        MoveSelection(price);
                                                        if ((bEClick) && (memLocal == 0)) SetPriceSelection(memLocal = price);
                                                }else if (bMounting)
                                                {
                                                        RemoveIndicator(def_IndicatorTicket0);
                                                        memLocal = 0;
                                                        bMounting = false;
                                                }else if ((!bMounting) && (bKeyBuy == bKeySell) && (m_Selection.ticket > def_IndicatorGhost))
                                                {
                                                        if (bEClick) SetPriceSelection(price); else MoveSelection(price);
                                                }
                                                break;
                                        case CHARTEVENT_OBJECT_DELETE:
                                                if (GetIndicatorInfos(sparam, ticket, it, ev))
                                                {
                                                        if (GetInfosTradeServer(ticket) == 0) break;
                                                        CreateIndicator(ticket, it);
                                                        if ((it == IT_PENDING) || (it == IT_RESULT))
                                                                PositionAxlePrice(ticket, it, m_Selection.pr);
                                                        ChartRedraw();
                                                        m_TradeLine.SpotLight();
                                                        m_Selection.ticket = 0;
                                                        UpdateIndicators(ticket, m_Selection.tp, m_Selection.sl, m_Selection.vol, m_Selection.bIsBuy);
                                                }
                                                break;
                                        case CHARTEVENT_OBJECT_ENDEDIT:
                                                macroGetDataIndicatorFloat;
                                                m_Selection.ticket = 0;
                                                UpdateIndicators(def_IndicatorFloat, m_Selection.tp, m_Selection.sl, m_Selection.vol, m_Selection.bIsBuy);
                                                break;
                                        case CHARTEVENT_CHART_CHANGE:
                                                ReDrawAllsIndicator();
                                                break;
                                        case CHARTEVENT_OBJECT_CLICK:
                                                if (GetIndicatorInfos(sparam, ticket, it, ev)) switch (ev)
                                                {
                                                        case EV_TYPE:
                                                                if (ticket == def_IndicatorFloat)
                                                                {
                                                                        macroGetDataIndicatorFloat;
                                                                        m_Selection.tp = (m_Selection.tp == 0 ? 0 : m_Selection.pr + (MathAbs(m_Selection.tp - m_Selection.pr) * (m_Selection.bIsBuy ? 1 : -1)));
                                                                        m_Selection.sl = (m_Selection.sl == 0 ? 0 : m_Selection.pr + (MathAbs(m_Selection.sl - m_Selection.pr) * (m_Selection.bIsBuy ? -1 : 1)));
                                                                        m_Selection.ticket = 0;
                                                                        UpdateIndicators(def_IndicatorFloat, m_Selection.tp, m_Selection.sl, m_Selection.vol, m_Selection.bIsBuy);
                                                                } else m_BtnInfoType.SetStateButton(sparam, !m_BtnInfoType.GetStateButton(sparam));
                                                                break;
                                                        case EV_DS:
                                                                if (ticket != def_IndicatorFloat) m_BtnInfo_DS.SetStateButton(sparam, !m_BtnInfo_DS.GetStateButton(sparam));
                                                                break;
                                                        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)
                                                                        {
                                                                                macroGetDataIndicatorFloat;
                                                                                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
                                                                {
                                                                        macroGetDataIndicatorFloat;
                                                                        m_Selection.ticket = def_IndicatorTicket0;
                                                                        m_Selection.it = IT_PENDING;
                                                                        SetPriceSelection(m_Selection.pr);
                                                                        RemoveIndicator(def_IndicatorFloat);
                                                                }
                                                                break;
                                                }
                                                break;
                                }
                        }
#undef macroGetDataIndicatorFloat

Bu kod sizi korkutmasın. Fazla ve karmaşık görünmesine rağmen aslında oldukça basittir. Mesaj işleme kodundaki yenilikleri açıklamak için vurgulanan kısımlara odaklanacağım.

İlk yeni şey CHARTEVENT_OBJECT_ENDEDIT olay işleme kodundadır. EDIT nesnesinde bulunan içeriği düzenlemeyi her bitirdiğimizde MetaTrader 5 tarafından tetiklenir. Bu ne anlama geliyor? Bu çok önemlidir, çünkü bu olayı işlemezsek ve kaldıraç değerini düzenledikten sonra durma seviyesi göstergelerinin verilerini değiştirmeye çalışırsak, değerlerde bir uyumsuzluk olacaktır. Uzman Danışman değeri orijinal değerine döndürmeye zorlayacak olsa da, bu olayı kodda gösterildiği gibi işlersek, bu sorun olmayacak ve kaldıraç verisiyle sorunsuz bir şekilde ticaret yapabileceğiz. Uzman Danışmandan bu ayarlamaları yapmanıza izin vermesini istediğinizde, aslında işleme daha fazla veya daha az kaldıraçlı girmenin iyi bir fikir olup olmadığını kontrol etmek isteyeceğinizi unutmayın. Bu şekilde herhangi bir risk almadan kontrol edebilirsiniz, çünkü Uzman Danışman emri sunucuya yalnızca bunu yapmasını istediğinizde gönderecektir ve bunun gerçekleştiği an onay kutusunun etkinleştirildiği andır.

Şimdi CHARTEVENT_OBJECT_CLICK olayına daha yakından bakalım. Bunun için önceki kodda vurgulanan parçayı alıyoruz.

case CHARTEVENT_OBJECT_CLICK:
        if (GetIndicatorInfos(sparam, ticket, it, ev)) switch (ev)
        {
                case EV_TYPE:
                        if (ticket == def_IndicatorFloat)
                        {
                                macroGetDataIndicatorFloat;
                                m_Selection.tp = (m_Selection.tp == 0 ? 0 : m_Selection.pr + (MathAbs(m_Selection.tp - m_Selection.pr) * (m_Selection.bIsBuy ? 1 : -1)));
                                m_Selection.sl = (m_Selection.sl == 0 ? 0 : m_Selection.pr + (MathAbs(m_Selection.sl - m_Selection.pr) * (m_Selection.bIsBuy ? -1 : 1)));
                                m_Selection.ticket = 0;
                                UpdateIndicators(def_IndicatorFloat, m_Selection.tp, m_Selection.sl, m_Selection.vol, m_Selection.bIsBuy);
                        } else m_BtnInfoType.SetStateButton(sparam, !m_BtnInfoType.GetStateButton(sparam));
                        break;
                case EV_DS:
                        if (ticket != def_IndicatorFloat) m_BtnInfo_DS.SetStateButton(sparam, !m_BtnInfo_DS.GetStateButton(sparam));
                        break;

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

Bu kod aslında ne yapıyor? Bir fikriniz var mı? Bu makaledeki videolar bunu gösteriyor, ancak bu tür bir şeyin nasıl yapıldığını anlayabiliyor musunuz? Birçok kişi bunun son derece karmaşık bir kod olduğunu düşünebilir, ancak işte orada, hemen yukarıda.

Yapmamız gereken iki şey var. Birincisi, bir bitmap nesnesine tıklandığında, durumu değişir ve fişin sunucuda zaten var olan bir şeyden mi yoksa yalnızca grafikte bulunan bir şeyden mi olduğunu kontrol etmemiz gerekir. Bu, yeşil renkle vurgulanan kısımlar tarafından yapılır. Fiş sunucuda mevcutsa, durum değişikliği geri alınmalıdır, ardından Uzman Danışman gerekli değişikliği yaparak bunu düzeltecektir.

Şimdi sarı renkle vurgulanan kısma göz atalım. Fikir şuna dayanmaktadır: grafikte zaten mevcutsa ve sadece yönü tersine çevirmek istiyorsam, neden grafikte başka bir emir daha vermeliyim? (Yani başka bir deyişle, eğer alış ise, şimdi satış olmasını istiyoruz veya tam tersi.) Sarı kısım tam da bunu yapar: alış mı yoksa satış mı yaptığımızdan sorumlu bitmap tıklandığında, yön otomatik olarak değişir. Bir ayrıntı: bu yalnızca yüzer bir emir için yapılabilir; sunucuda halihazırda bulunan emirler için yapılamaz.

Tüm bu değişikliklerle birlikte göstergeler artık şu şekilde görünmektedir:

Bekleyen emir türleri

 

Pozisyon göstergesi:

Bir bekleyen emrin veya açık pozisyonun ne yaptığını belirlemek artık çok daha kolay, çünkü beklenen hareketi veya pozisyon ömrünü tam olarak bilebiliriz. Yukarı bakan yeşil ok alış pozisyonunu, aşağı bakan kırmızı ok ise satış pozisyonunu gösterir. D harfi, gün sonunda kapanacak olan bir günlük işlemi ifade eder. Eğer S ise, bu bir swing işlemidir ve işlem gün sonunda illa ki kapatılmayacaktır.

Bir sonraki videoda yeni emir sisteminin nasıl çalıştığı gösterilmektedir. Bekleyen emirlere odaklandım çünkü pozisyon göstergeleri değiştirilemezken bunlar ilave değişikliklere uğrayabilir. Yalnızca pozisyonla ilgili olarak sunucu tarafından sağlanan verileri göstereceklerdir. Gerçek bir hesapta denemeden önce her şeyin nasıl çalıştığına daha yakından bakın; sistem pratiktir, ancak işlevselliğinden en iyi şekilde yararlanmak için ona aşina olmanız gerekir.




Sonuç

Emir sistemimiz artık oldukça kullanışlı. Birçok şey yapabilir ve bize çok yardımcı olabilir, ancak bir sonraki makalede uygulanacak olan önemli bir ayrıntı hala eksiktir. Bu yüzden, gelecek makalede görüşmek üzere...


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

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.
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)
Bugün emir sistemimizi bir üst seviyeye taşıyacağız. Ancak önce üzerinde durmamız gereken birkaç şey var. Şimdi, nasıl ticaret yapmak istediğimizle ilgili bazı çözülmesi gereken konulara odaklanacağız.
Piyasa ve global modellerinin fiziği Piyasa ve global modellerinin fiziği
Bu makalede, piyasayı az da olsa anlayan herhangi bir sistemin global ölçekte faaliyet gösterebileceği varsayımını test etmeye çalışacağım. Herhangi bir teori veya model icat etmeyeceğim, sadece bilinen gerçekleri kullanacağım ve bu gerçekleri kademeli olarak matematiksel analiz diline çevireceğim.
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.