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

MetaTrader 5Örnekler | 20 Mart 2024, 16:29
174 0
Daniel Jose
Daniel Jose

Giriş

Emir sistemini geliştirmeye başlarken, Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 18): Yeni emir sistemi (I) makalesinden sonra, bu noktaya gelmenin bu kadar süreceği hakkında hiçbir fikrim yoktu. Çeşitli iyileştirmelerden, değişikliklerden, düzeltmelerden vs. geçtik. Size işaretlemeler yapmak veya sistemi daha anlaşılır hale getirmek gibi bazı özel şeylerin nasıl yapılacağını gösterdim. Ancak bu aşamada gösteremediğim şeyler de vardı çünkü yol tam olarak hazırlanmamıştı. Bu yolculuk, konsepti herkesin anlayabileceği ve sistemin nasıl çalıştığını bilebileceği şekilde oluşturmamızı sağladı.

Önceki tüm makalelerde, bu makaleye sistemin nasıl çalıştığına dair aynı düzeyde bir anlayışla gelmemiz için bir zemin hazırladım. Dolayısıyla, bu materyalin aşırı derecede kafa karıştırıcı veya karmaşık olmayacağını umuyorum. En başından beri bir konu vardı ve onu ayrıntılı olarak analiz etmekten kaçındım. Ancak daha deneyimli yatırımcılar için çok önemlidir. İlk bakışta bu aptalca görünebilir, ancak ticaret zamanı geldiğinde Uzman Danışmanda bir şeyleri kaçırdığımızı fark edeceğiz. O zaman kendimize "burada eksik olan ne?" diye soracağız. Herhangi bir nedenle silinen ve grafiğe geri yüklemek istediğimiz Kârı Al ve Zararı Durdur değerlerini geri getirmenin yolundan bahsediyorum.

Bunu daha önce denediyseniz, bunun oldukça zor ve yavaş bir görev olduğunu anlayabilirsiniz, çünkü her şeyin yolunda gitmesi için "belirli bir senaryoyu takip etmemiz" gerekir, aksi takdirde her zaman hata yaparız.

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. MetaTrader 5 sistemi mükemmel değildir; bazen geliştirmekte olduğumuz Uzman Danışmanı kullanmaktan daha yavaş ve hataya eğilimli olabilir.

Ancak şimdiye kadar, TP ve SL seviyeleri (Kârı Al ve Zararı Durdur) için değerlerin nasıl oluşturulacağını hiç açıklamadım. Durma seviyelerinin silinmesinin yeterince açık ve anlaşılır olduğunu düşünüyorum. Ancak bunu nasıl uygulayacağız, yani doğrudan grafik üzerinde durma seviyelerini ayarlamak veya geri getirmek için nasıl ilerlemeliyiz? Bu, beraberinde bazı sorunları ortaya çıkaran çok merak uyandırıcı bir şeydir ve elbette bu makaleyi oluşturmanın nedeni de budur: herhangi bir harici kaynağa başvurmadan, sadece Uzman Danışmanın emir sistemini kullanarak, durma seviyelerini doğrudan grafik üzerinde oluşturmanın birçok yolundan birini göstermek.


2.0. Başlarken: Uygulama

Öncelikle Uzman Danışmanı, geliştirildiği ilk günlerden bu yana uzun süredir yaptığı kontrolü durdurmaya zorlamamız gerekiyor. Bu kontrolü kaldırmak için, üzeri çizili tüm kodu kaldırmalı ve vurgulanan kodu eklemeliyiz:

inline double SecureChannelPosition(void)
{
        double Res = 0, sl, profit, bid, ask;
        ulong ticket;
                                
        bid = SymbolInfoDouble(Terminal.GetSymbol(), SYMBOL_BID);
        ask = SymbolInfoDouble(Terminal.GetSymbol(), SYMBOL_ASK);
        for (int i0 = PositionsTotal() - 1; i0 >= 0; i0--) if (PositionGetSymbol(i0) == Terminal.GetSymbol())
        {
                IndicatorAdd(ticket = PositionGetInteger(POSITION_TICKET));
                SetTextValue(ticket, IT_RESULT, PositionGetDouble(POSITION_VOLUME), Res += PositionGetDouble(POSITION_PROFIT), PositionGetDouble(POSITION_PRICE_OPEN));
                SetTextValue(ticket, IT_RESULT, PositionGetDouble(POSITION_VOLUME), profit = PositionGetDouble(POSITION_PROFIT), PositionGetDouble(POSITION_PRICE_OPEN));
                sl = PositionGetDouble(POSITION_SL);
                if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY)
                {
                        if (ask < sl) ClosePosition(ticket);
                }else
                {
                        if ((bid > sl) && (sl > 0)) ClosePosition(ticket);
                }
                Res += profit;
        }
        return Res;
};

Üzeri çizili kodun varlığı sona ermeyecek, ancak başka bir anda geri gelecektir. Ancak, şu anda bir faydadan çok bir engel teşkil etmektedir. Bu yapıldıktan sonra, TP ve SL sistemini Uzman Danışman dışında herhangi bir kaynağın yardımı olmadan doğrudan grafik üzerinde nasıl uygulayacağımızı düşünmeye başlayabiliriz.

Her geliştiricinin bu sorunu çözmek için kendi fikri olacaktır: bazılarını bir yatırımcının anlaması daha kolay olurken, diğerleri daha zor olacaktır; bazılarını uygulamaya koymak daha zor olurken, diğerleri daha kolay olacaktır. Burada kullanacağım ve göstereceğim yöntemin en uygun ya da en kolay yöntem olduğunu söylemiyorum, ancak benim çalışma ve platformu kullanma şeklime en iyi uyarlanmış yöntem bu. Ayrıca, herhangi bir yeni öğe oluşturmam da gerekmeyecek. Sadece koddaki bazı şeyleri düzelteceğiz.


2.0.1. Sürükleme sisteminin modellenmesi

Uzman Danışman kodunun kendisi, mevcut geliştirme aşamasında, oluşturacağımız sistemi nasıl modellememiz gerektiğine dair bazı ipuçları sağlamaktadır. Aşağıdaki koda bakalım:

#define macroUpdate(A, B) if (B > 0) {                                                                  \
                if (b0 = (macroGetLinePrice(ticket, A) == 0 ? true : b0)) CreateIndicator(ticket, A);   \
                PositionAxlePrice(ticket, A, B);                                                        \
                SetTextValue(ticket, A, vol, (isBuy ? B - pr : pr - B));                                \
                                     } else RemoveIndicator(ticket, A);
                                                                        
                void UpdateIndicators(ulong ticket, double tp, double sl, double vol, bool isBuy)
                        {
                                double pr;
                                bool b0 = false;
                                
                                if (ticket == def_IndicatorGhost) pr = m_Selection.pr; else
                                {
                                        pr = macroGetLinePrice(ticket, IT_RESULT);
                                        if ((pr == 0) && (macroGetLinePrice(ticket, IT_PENDING) == 0))
                                        {
                                                CreateIndicator(ticket, IT_PENDING);
                                                PositionAxlePrice(ticket, IT_PENDING, m_Selection.pr);
                                                ChartRedraw();
                                        }
                                        pr = (pr > 0 ? pr : macroGetLinePrice(ticket, IT_PENDING));
                                        SetTextValue(ticket, IT_PENDING, vol);
                                }
                                if (m_Selection.tp > 0) macroUpdate(IT_TAKE, tp);
                                if (m_Selection.sl > 0) macroUpdate(IT_STOP, sl);
                                if (b0) ChartRedraw();
                        }
#undef macroUpdate

Vurgulanan satırlar, görevi yerine getirecek bir makro içermektedir. İhtiyacımız olan şeyi, yani durma seviyesi göstergesini uygulamak için gerekli yardımı sağlayacak şekilde değiştirmemiz gerekiyor. Makro kodunu daha yakından inceleyelim. Aşağıda gösterilmektedir:

#define macroUpdate(A, B){ if (B > 0) {                                                                 \
                if (b0 = (macroGetLinePrice(ticket, A) == 0 ? true : b0)) CreateIndicator(ticket, A);   \
                PositionAxlePrice(ticket, A, B);                                                        \
                SetTextValue(ticket, A, vol, (isBuy ? B - pr : pr - B));                                \
                                        } else RemoveIndicator(ticket, A); }

Şunları yapıyoruz: Kârı Al veya Zararı Durdur olabilen B değeri 0'dan büyük olduğunda, göstergenin grafikte olup olmadığını kontrol ederiz. Değilse, oluştururuz, yerleştiririz ve görüntüleyeceği değeri ayarlarız. B değeri 0'a eşitse, göstergeyi grafikten tamamen kaldıracağız ve bunu makro kodunda vurgulanan kısımda yapacağız. Ancak, göstergeyi grafikten tamamen kaldırmak yerine, öğesini korursak ve bu öğe yapmak istediğimiz şey için yapılandırılabilirse (yani bir emir veya pozisyon için eksik durma seviyelerini oluşturabilirsek ve onu tekrar OCO türünde bir emir veya pozisyon haline getirebilirsek), bu yeterli olur muydu? EVET, bu yeterli olacaktır ve fikir de budur: durma seviyelerini hareket ettirmek ve eksik olan durma seviyelerini oluşturmak için kullanılan öğeyi/nesneyi bırakırız. Sadece bu öğeyi sürüklememiz gerekiyor ve böylece eşik oluşturulacaktır. Bu, sistemi inşa etmek için kullanacağımız teorik çerçevedir.

Ancak sadece bunu yaparak ihtiyacımız olan her şeyi elde edemeyiz. Yapılması gereken bir değişiklik daha var. Devam etmeden önce bunu yapacağız. Bu değişiklik aşağıdaki kodda vurgulanmıştır:

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

//... Internal code...

        m_Selection.tp = (valueTp == 0 ? 0 : m_Selection.pr + (bKeyBuy ? valueTp : (-valueTp)));
        m_Selection.sl = (valueSl == 0 ? 0 : m_Selection.pr + (bKeyBuy ? (-valueSl) : valueSl));

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

}

Ticaret arayüzü tarafından girilen başlangıç değerlerinin boş olup olmadığını kontrol ederiz. Eğer öyleyse, hiçbir gösterge oluşturulmayacak ve grafik sadece giriş seviyesini gösterecektir.

Bu, sistemin geri kalanında daha doğrusal bir çalışma sağlar. Herhangi bir durma seviyesi belirtilmezse, tüm emir modeli, grafiğe bir bekleyen emir yerleştireceğimiz zaman, değer en baştan belirtildiğinde olduğu gibi aynı davranışa sahip olacaktır.

Böylece tek bir yatırımcı bile merak etmeyecektir: emirde veya pozisyonda asılı olan bu rakamlar ne? Çünkü yatırımcı bunların grafik üzerinde hareket ettirilebilecek öğeleri temsil ettiğini bilecektir.

Ancak tüm bunlara rağmen, hala iki makroyu değiştireceğimiz küçük bir problemimiz var. Aşağıya bakın:

#define macroSetLinePrice(ticket, it, price)    ObjectSetDouble(Terminal.Get_ID(), macroMountName(ticket, it, EV_LINE), OBJPROP_PRICE, price)
#define macroGetLinePrice(ticket, it)           ObjectGetDouble(Terminal.Get_ID(), macroMountName(ticket, it, EV_LINE), OBJPROP_PRICE)
#define macroGetPrice(ticket, it, ev)           ObjectGetDouble(Terminal.Get_ID(), macroMountName(ticket, it, ev), OBJPROP_PRICE)

Bu değişiklik, inşa edeceğimiz sistemin geri kalanı için çok önemlidir. Ama neden üzeri çizgili satırları çıkarıyoruz? Bunun nedeni, sistemi daha da esnek hale getirmemiz gerektiğidir ve bunu başarmak için üzeri çizili kodu kaldırdık ve yerine vurgulanan satırı ekledik. Fiyata bir değer atamak için bir makromuz yoksa neden macroGetPrice'a ihtiyacımız var? Aslında, bu fiyat ayarlamasını yapan ve bunu grafik nesnesine yazan tek bir kısım vardır. Bu kısım aşağıdaki kodda görülebilir:

#define macroSetPrice(ticket, it, ev, price) ObjectSetDouble(Terminal.Get_ID(), macroMountName(ticket, it, ev), OBJPROP_PRICE, price)
//---

// ... Additional code inside the class....

//---
inline void PositionAxlePrice(ulong ticket, eIndicatorTrade it, double price)
                        {
                                int x, y, desl;
                                
                                ChartTimePriceToXY(Terminal.Get_ID(), 0, 0, price, x, y);
                                if (it != IT_RESULT) macroSetPrice(ticket, it, EV_MOVE, price);
                                macroSetPrice(ticket, it, EV_LINE, 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));
                        }

Dolayısıyla, makronun kodun diğer tüm yerlerinde görülebilmesi için nesneler üzerindeki fiyatı ayarlamasına gerek yoktur. Aslında şu anda bir makro olması bile gerekmiyor, ancak daha sonra bu kod değiştiğinde bir hata olasılığını azaltmak için olduğu gibi bırakacağım.

Artık sistemimiz güncel olduğuna göre, bir sonraki konuya geçebilir ve her şeyin planlandığı gibi çalışmasını sağlayabiliriz.


2.0.2. Yeni güncelleme özelliği

Önceki bölümde bahsetmiştim: Uzman Danışman ilgili tüm sorunları çözerken bizim tek yapmamız gereken güncelleme fonksiyonunu yapılandırmaktır. Ana odak noktası yalnızca Kârı Al ve Zararı Durdur göstergeleri olduğundan ve bunlar makro içerisinde yürütüldüğünden, makroyu doğru şekilde ayarlamamız yeterlidir.

Ancak henüz çözüme kavuşturulmamış bir problem var. Taşıma düğmesini göstergenin geri kalanından bağımsız olarak oluşturmamız gerekiyor. Bunu yapmak için, düğme oluşturma kodunu izole edelim:

// ... class code ...

#define def_ColorLineTake       clrDarkGreen
#define def_ColorLineStop       clrMaroon

// ... class code ....

inline void CreateBtnMoveIndicator(ulong ticket, eIndicatorTrade it, color C = clrNONE)
                        {
                                string sz0 = macroMountName(ticket, it, EV_MOVE);

                                ObjectDelete(Terminal.Get_ID(), macroMountName(ticket, it, EV_MOVE));
                                m_BtnMove.Create(ticket, sz0, "Wingdings", "u", 17, (C == clrNONE ? (it == IT_TAKE ? def_ColorLineTake : def_ColorLineStop) : C));
                                m_BtnMove.Size(sz0, 21, 23);
                        }

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

Bu kod yalnızca taşıma düğmesini oluşturacak ve başka hiçbir şey oluşturmayacaktır. Çok basit ve anlaşılır. Bu kodu bir makro olarak bırakmayı bile düşündüm, ancak bir fonksiyon olarak yapmaya karar verdim. Yerleşik bir fonksiyon olarak bildirilir, bu nedenle derleyici ona bir makroya davrandığı gibi davranacaktır. Hayatı kolaylaştırmak için, aynı kod parçası iki yeni tanıma sahip, çünkü bir noktada sadece bir hareket düğmesi oluşturacağız ve bunun sistem genelinde kullanılan aynı renklere sahip olmasını istiyoruz. Sistemin benzer durumlarda farklı davranması veya farklı görünmesi arzu edilen bir durum değildir. Sorunları azaltmak için renkleri yukarıda gösterildiği gibi bırakıyoruz.

Şimdi güncelleme fonksiyonuna gidebiliriz; tam kodu aşağıda gösterilmiştir. Aşağıdaki sürüm ile makalenin önceki bölümünde sunulan sürüm arasındaki tek farkın vurgulanan kod olduğuna dikkat edin. Bu kod, güncelleme fonksiyonunun kendisi tarafından kullanılan bir makrodur.

#define macroUpdate(A, B){                                                                                                      \
                if (B == 0) {   if (macroGetPrice(ticket, A, EV_LINE) > 0) RemoveIndicator(ticket, A);                          \
                                if (macroGetPrice(ticket, A, EV_MOVE) == 0) CreateBtnMoveIndicator(ticket, A);                  \
                            } else if (b0 = (macroGetPrice(ticket, A, EV_LINE) == 0 ? true : b0)) CreateIndicator(ticket, A);   \
                PositionAxlePrice(ticket, A, (B == 0 ? pr : B));                                                                \
                SetTextValue(ticket, A, vol, (isBuy ? B - pr : pr - B));                                                        \
                        }
                                                                        
                void UpdateIndicators(ulong ticket, double tp, double sl, double vol, bool isBuy)
                        {
                                double pr;
                                bool b0 = false;
                                
                                if (ticket == def_IndicatorGhost) pr = m_Selection.pr; else
                                {
                                        pr = macroGetPrice(ticket, IT_RESULT, EV_LINE);
                                        if ((pr == 0) && (macroGetPrice(ticket, IT_PENDING, EV_MOVE) == 0))
                                        {
                                                CreateIndicator(ticket, IT_PENDING);
                                                PositionAxlePrice(ticket, IT_PENDING, m_Selection.pr);
                                                ChartRedraw();
                                        }
                                        pr = (pr > 0 ? pr : macroGetPrice(ticket, IT_PENDING, EV_MOVE));
                                        SetTextValue(ticket, IT_PENDING, vol);
                                }
                                macroUpdate(IT_TAKE, tp);
                                macroUpdate(IT_STOP, sl);
                                if (b0) ChartRedraw();
                        }
#undef macroUpdate

Tam olarak ne olduğunu anlamak için bu makroyu daha ayrıntılı inceleyelim. Onu anlamak, sistemi kullanırken ortaya çıkabilen bazı sorunları çözebilmek için gereklidir. Henüz hazır değil ve bazı değişiklikler daha yapmamız gerekiyor.

İlk adımda, şu davranışa sahibiz: durma emirlerinden birini (Kârı Al veya Zararı Durdur) kaldırırken, ilgili göstergeyi sembol grafiğinden hemen kaldıracağız. Bunu yapmak için, göstergenin varlığını ifade eden bir çizgi olup olmadığını kontrol ederiz. Sonra bu göstergenin bir hareket nesnesi olup olmadığını kontrol ederiz. Eğer mevcut değilse, oluştururuz. Dolayısıyla, grafikte göstergeye sahip olmayacağız, ancak hareket nesnesi şeklinde grafikte hala mevcut olan bir kalıntısına sahip olacağız.

İkinci adım, bir durma seviyesi oluşturulması durumunda gerçekleşir: sunucudaki emir, grafikte görünmesi gereken bir durma seviyesine sahip olacaktır. Bu durumda, hareketi temsil eden nesne kaldırılacak ve mevcut durma seviyesinin (Kârı Al veya Zararı Durdur) nerede olacağını gösteren eksiksiz bir gösterge oluşturulacak ve uygun yere yerleştirilecektir.

Son adımda, göstergeyi doğru seviyeye konumlandırıyoruz. İlginç bir ayrıntı: eğer durma seviyesi göstergesi sadece hareket olasılığını temsil eden bir nesne ise, o zaman yerleştirileceği seviye tam olarak emrin veya pozisyonun fiyatı olacaktır. Başka bir deyişle, Kârı Al ve Zararı Durdur oluşturmaya izin veren hareket nesnesi, ait olduğu emir veya pozisyonun fiyat çizgisine bağlanacaktır. Böylece, emir veya pozisyonda durma seviyelerinden birinin eksik olup olmadığını fark etmek kolay olacaktır.

Temel olarak yapmamız gereken şey şudur: hareketi gösteren nesneye tıkladığımızda, her zamanki gibi bir hayalet oluşturulur ve aynı zamanda tüm göstergenin bir temsili de oluşturulur. Bu, herhangi bir kod eklemeden veya değiştirmeden yapılır. Şu andan itibaren, tıpkı daha önce olduğu gibi durma seviyelerini normal şekilde hareket ettirebilir ve ayarlayabiliriz. Ancak belirli bir seviyeye tıklayana kadar, durma emri mevcut olmayacaktır. Bu, sistemin bir gerçek hesapta nasıl çalıştığını gösterdiğim, makalenin sonundaki videoda açıkça gösterilmektedir.

Her şey yolunda gibi görünse de, burada bizi bazı noktalarda kod oluşturmaya veya daha doğrusu değiştirmeye zorlayan bazı tutarsızlıklarımız var. Bunu bir sonraki bölümde göreceğiz.


2.0.3. Yüzer göstergelerin yarattığı rahatsızlığı çözme

Rahatsızlıklardan ilki, yüzer gösterge modundayken ortaya çıkar: grafiktedir ancak sunucuda değildir. Daha fazla bilgi için, kayar göstergenin nasıl çalıştığını ve uygulandığını gösterdiğim serinin 26. ve 27. makalelerine bakın. Bu göstergeler yararlıdır ve bu nedenle Uzman Danışmandan çıkarılmayacaktır. Ancak yukarıda gördüğümüz sisteme uymazlar çünkü işleyişleri, işlem sunucusunda mevcut olan emirleri ve pozisyonları gerçekten temsil eden göstergelerden farklıdır. Yüzer bir gösterge kullanırken ortaya çıkan sorunları çözmek için, DispatchMessage fonksiyonuna gitmemiz ve aşağıda gösterildiği gibi orada bir şeyler ayarlamamız gerekecektir.

void DispatchMessage(int id, long lparam, double dparam, string sparam)
{
        ulong   ticket;
        double  price;

// ... Internal code...
                        
        switch (id)
        {

// ... Internal code...

                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)
                                        {
                                                macroGetDataIndicatorFloat;
                                                RemoveIndicator(def_IndicatorFloat, it);
                                                if (it != IT_PENDING) UpdateIndicators(def_IndicatorFloat, (it == IT_TAKE ? 0 : m_Selection.tp), (it == IT_STOP ? 0 : m_Selection.sl), m_Selection.vol, m_Selection.bIsBuy);
                                        }else if ((cRet = GetInfosTradeServer(ticket)) != 0) switch (it)

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

Yukarıda vurgulanan değişiklikleri yaparak, yüzer göstergelerin yapılandırılmasıyla ilgili diğer tüm sorunları pratik olarak ortadan kaldırıyoruz, çünkü artık yüzer gösterge verilerini ve işlem sunucusunda bulunan verileri ayarlamak için aynı yönteme sahibiz. Ancak bu sorunlarımızı tamamen çözmüyor. Uzun süredir devam eden bir başka sıkıntıyı daha çözmemiz gerekiyor. Bunu tartışmak için bir sonraki bölüme geçelim, çünkü ayrı bir başlık altında incelenmeyi hak ediyor.


2.0.4. Negatif Kârı Al değerinin dezavantajı

Bu makalede tartışacağımız son dezavantaj, Kârı Al değerinin çoğunlukla negatif olacak şekilde yapılandırılabilmesidir ve bu oldukça uzun bir süredir gerçekleşmektedir. Ancak bu, ticaret sistemi için hiçbir anlam ifade etmez: değeri sunucuya göndermeye çalışırsanız, bir hata mesajı geri döndürülür. Bu nedenle, bunu düzeltmemiz ve ayrıca bir bekleyen emrin durma değerinin pozitif olarak değiştirilebilmesi olan başka bir problemi çözmemiz gerekiyor.

Uzman Danışman artık bunu yapmaya izin veriyor ve daha da kötüsü, emir sistemi bu değerin sunucuda olduğunu gösterirken, aslında sunucu bir hata geri döndürüyor ve Uzman Danışman bunu görmezden geliyor. Bekleyen emirler söz konusu olduğunda sorun daha karmaşıktır, çünkü pozisyonlar söz konusu olduğunda davranış farklı olmalıdır ve bu hata henüz düzeltilmemiştir. Durma seviyelerini doğrudan grafik üzerinde tanımlama yeteneğine sahip olur olmaz, bu dezavantaj ortadan kalkmalıdır.

Burada, açık bir pozisyon durumunda pozitif değerli bir Zararı Durdur seçeneğine sahip olabileceğimizi belirtmek gerekir ve bu, Zararı Durdur tetiklenirse, ilgili değerin hesabımıza yatırılacağını ifade eder. Ancak bir bekleyen emir için bu, sunucunun doğru bir emir oluşturmasını engelleyecek bir hata olacaktır. Bu sorunu çözmek için, Kârı Al değerini kontrol etmeliyiz: 0'a eşit veya 0'dan küçük olduğunda, daha küçük bir değere değişmesini önlemeliyiz. Ayrıca, bekleyen emirler için Zararı Durdurun 0'dan büyük olmasına izin vermemeliyiz. Aslında, 0 koşulu karşılandığında Uzman Danışmanı izin verilen minimum değeri kullanmaya zorlarız. Bu durumda, emir veya pozisyon ticaret sistemi için bir anlam ifade edecektir, ancak açılış fiyatına eşit Zararı Durdur veya Kârı Al ile bir pozisyon açmanın bir anlamı yoktur.

Bunu mümkün olduğunca kolaylaştırmak için sistemde aşağıda görülebilecek bir değişken oluşturmamız gerekiyor:

struct st00
{
        eIndicatorTrade it;
        bool            bIsBuy,
                        bIsDayTrade;
        ulong           ticket;
        double          vol,
                        pr,
                        tp,
                        sl,
                        MousePrice;
}m_Selection;

Neden sadece fare satırındaki fiyat kısmını değiştirmiyoruz? Bunun nedeni, fareyi doğru bir şekilde manipüle etmek için bir sistem çağrısı kullanmak, yani fare konum değerlerini Windows API aracılığıyla manipüle etmek gerekir ve bu bizi harici dll'leri kullanmaya zorlar ve ben bunu yapmak istemiyorum. Bu şekilde Uzman Danışman içerisinde yerel bir değer oluşturmak daha kolaydır ve vurgulanan veriler bu değeri bizim için saklayacaktır.

Bu değer üç farklı yerde kullanılacaktır. İlk yer hareket fonksiyonundadır. Aşağıdaki kod bunun tam olarak nerede gerçekleştiğini göstermektedir:

void MoveSelection(double price)
{
        if (m_Selection.ticket == 0) return;
        switch (m_Selection.it)
        {
                case IT_TAKE:
                        UpdateIndicators(m_Selection.ticket, price, m_Selection.sl, m_Selection.vol, m_Selection.bIsBuy);
                        break;
                case IT_STOP:
                        UpdateIndicators(m_Selection.ticket, m_Selection.tp, price, m_Selection.vol, m_Selection.bIsBuy);
                        break;
                case IT_PENDING:
                        PositionAxlePrice(m_Selection.ticket, IT_PENDING, price);
                        UpdateIndicators(m_Selection.ticket, (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.vol, m_Selection.bIsBuy);
                        m_Selection.MousePrice = price;
                        break;
        }
        if (Mouse.IsVisible())
        {
                m_TradeLine.SpotLight(macroMountName(m_Selection.ticket, m_Selection.it, EV_LINE));
                Mouse.Hide();
        }
}

Durma emri seviyelerini hareket ettirmekten sorumlu olduğu için neden her şeyi yukarıdaki fonksiyona koymuyoruz? Bunun nedeni, Kârı Al veya Zararı Durdur seviyelerini doğru bir şekilde ayarlamak için bazı hesaplamalar yapmamız gerektiğidir ve bunu farklı bir noktada yapmak çok daha kolaydır. Bu değeri başka bir yerde de değiştirmemiz gerekiyor, bu nedenle değerin referans alındığı ikinci yer burasıdır:

void DispatchMessage(int id, long lparam, double dparam, string sparam)
{
        ulong   ticket;
        double  price;
        bool    bKeyBuy,

// ... Internal code ....      
                                
        switch (id)
        {
                case CHARTEVENT_MOUSE_MOVE:
                        Mouse.GetPositionDP(dt, price);
                        mKeys   = Mouse.GetButtonStatus();
                        bEClick  = (mKeys & 0x01) == 0x01;    //Left mouse button 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 = (valueTp == 0 ? 0 : m_Selection.pr + (bKeyBuy ? valueTp : (-valueTp)));
                                m_Selection.sl = (valueSl == 0 ? 0 : 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(m_Selection.MousePrice); else MoveSelection(price);
                        }
                        break;

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

Bu sayede sistemde öngörülebilir davranışlara sahip oluyoruz. Değerin referans alındığı başka bir nokta daha var, ancak karmaşıklık nedeniyle değişiklik yapmaya karar verdim, böylece makro artık var olmayacaktır. Şimdi bir fonksiyon olacaktır. Böylece, yeni güncelleme fonksiyonu aşağıda görülebilir:

void UpdateIndicators(ulong ticket, double tp, double sl, double vol, bool isBuy)
{
        double pr;
        bool b0, bPen = true;
                                
        if (ticket == def_IndicatorGhost) pr = m_Selection.pr; else
        {
                bPen = (pr = macroGetPrice(ticket, IT_RESULT, EV_LINE)) == 0;
                if (bPen && (macroGetPrice(ticket, IT_PENDING, EV_MOVE) == 0))
                {
                        CreateIndicator(ticket, IT_PENDING);
                        PositionAxlePrice(ticket, IT_PENDING, m_Selection.pr);
                        ChartRedraw();
                }
                pr = (pr > 0 ? pr : macroGetPrice(ticket, IT_PENDING, EV_MOVE));
                SetTextValue(ticket, IT_PENDING, vol);
        }
        b0 = UpdateIndicatorsLimits(ticket, IT_TAKE, tp, vol, pr, isBuy, bPen);
        b0 = (UpdateIndicatorsLimits(ticket, IT_STOP, sl, vol, pr, isBuy, bPen) ? true : b0);
        if (b0) ChartRedraw();
}

Vurgulanan kısımlar önceki makronun yerini almaktadır, ancak dediğim gibi gerekli kod çok daha karmaşıktır, bu yüzden üçüncü ve son yerin aslında nerede bulunduğunu görelim. Yukarıdaki kodda, Kârı Al ve Zararı Durdur göstergeleri arasında hiçbir fark yoktur: her ikisi de aynı şekilde işlenir. Aşağıdaki koda göz atalım.

inline bool UpdateIndicatorsLimits(ulong ticket, eIndicatorTrade it, double price, double vol, double pr, bool isBuy, bool isPen)
{
        bool b0 = false;
        double d1 = Terminal.GetPointPerTick();
                
        if (
    price  == 0)
        {
                if (macroGetPrice(ticket, it, EV_LINE) > 0) RemoveIndicator(ticket, it);
                if (macroGetPrice(ticket, it, EV_MOVE) == 0) CreateBtnMoveIndicator(ticket, it);
        } else if (b0 = (macroGetPrice(ticket, it, EV_LINE) == 0 ? true : b0)) CreateIndicator(ticket, it);
        switch (it)
        {
                case IT_TAKE:
                        price = (price == 0 ? 0 : (((isBuy ? price - pr : pr - price) > 0) ? price : (isBuy ? pr + d1 : pr - d1)));
                        break;
                case IT_STOP:
                        price = (price == 0 ? 0 : (isPen ? (((isBuy ? price - pr : pr - price) < 0) ? price : (isBuy ? pr - d1 : pr + d1)) : price));
                        break;
        }
        if (m_Selection.it == it) m_Selection.MousePrice = price;
        PositionAxlePrice(ticket, it, (price == 0 ? pr : price));
        SetTextValue(ticket, it, vol, (isBuy ? price - pr : pr - price));
                        
        return b0;
}

Şu andan itibaren, bir bekleyen emrin Kârı Al değeri, izin verilen değerlere yönelik sınırımız olduğu için yanlış olamaz. Bir bekleyen alış emri yerleştirmek ve ardından Kârı Alı negatif bir değere (yani giriş seviyesinin altına) taşımak artık mümkün değildir, çünkü Kârı Al göstergesinin hesaplanması bunu engeller. Kodu bu şekilde yazmanın avantajı, ister emir ister pozisyon olsun, Kârı Al değerinin asla negatif olamayacağıdır, çünkü Uzman Danışmanın kendisi buna izin vermez.

Şimdi, Zararı Durdur söz konusu olduğunda, neyi yönettiğimize (emir veya pozisyon) bağlı olarak biraz farklı bir hesaplama yöntemi vardır. Eğer bu bir emirse, Zararı Durdur değeri asla pozitif olmayacaktır ve eğer bu bir pozisyonsa, Uzman Danışman diğer koşulları göz ardı edecektir. Bu durumda Uzman Danışman, yatırımcı tarafından belirtilen değeri kabul etmelidir. Artık pozitif bir Zararı Durdura sahip olabiliriz, ancak yalnızca pozisyonlar söz konusu olduğunda, emir sistemi kodunun geri kalanına herhangi bir hasar vermeden ve bu şekilde Uzman Danışman, gönderilen veriler reddedilmeden işlem sunucusuyla nihayet etkileşime girecektir.


Sonuç

Sonunda, birkaç makaleden sonra hedefe ulaştık ve şimdi neredeyse tamamlanmış ve çeşitli durumlara ve piyasa koşullarına oldukça uyarlanabilir bir emir sistemine sahibiz. Şu andan itibaren, piyasa analizinizin yanı sıra fare ve klavyeyi kullanarak işlemlere girmek veya çıkmak için tamamen grafiksel bir sistemle ticaret yapabileceğiz.

Yeni gelenler ve sistemin nasıl işlediğini veya şu anki gelişim aşamasında neye benzediğini görmek isteyenler için lütfen aşağıdaki videoyu izleyin. Şimdiye kadar bu makale serisini takip eden herkese teşekkür ederim. Ancak iş henüz bitmedi ve bu Uzman Danışman unutulmaz bir şey haline gelene kadar yapacak çok işimiz var. Bir sonraki makalede görüşmek üzere! 👍



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

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.
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.
Ticaret için kombinatorik ve olasılık teorisi (Bölüm IV): Bernoulli mantığı Ticaret için kombinatorik ve olasılık teorisi (Bölüm IV): Bernoulli mantığı
Bu makalede, iyi bilinen Bernoulli şemasını vurgulamaya ve ticaretle ilgili veri dizilerini tanımlamak için nasıl kullanılabileceğini göstermeye karar verdim. Tüm bunlar daha sonra kendi kendini uyarlayan bir ticaret sistemi oluşturmak için kullanılacaktır. Ayrıca, özel bir durumu Bernoulli formülü olan daha genel bir algoritma arayacağız ve bunun için bir uygulama bulacağız.
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.