English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
preview
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 19): Yeni emir sistemi (II)

Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 19): Yeni emir sistemi (II)

MetaTrader 5Ticaret | 26 Haziran 2023, 14:57
350 0
Daniel Jose
Daniel Jose

Giriş

Bir önceki makalede (Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 18): Yeni emir sistemi (I)), hesap muhasebesinde farklılıklar olduğu için netting ve hedging hesaplarında farklı ticarete izin verecek bir sistem oluşturmayı amaçlayarak emir sisteminde bazı düzeltmeler, değişiklikler ve ayarlamalar uyguladık. Netting türünde, sistem bir varlık üzerinde yalnızca bir açık pozisyonumuz olacak şekilde ortalama bir fiyat oluşturur. Hedging hesaplarında ise her birinin ayrı eşikleri olan birden fazla açık pozisyonumuz olabilir. Aynı varlık aynı anda hem alınıp hem de satılabilir. Bu yalnızca hedging hesaplarında yapılabilir. Bu, opsiyon ticaretinin anlaşılabileceği temeldir.

Ancak şimdi emir sistemini tamamen görsel hale getirmenin zamanı geldi, böylece mesaj kutusunu ortadan kaldırabilir ve onsuz her pozisyonda hangi değerlerin olduğunu analiz edebiliriz. Bunu sadece yeni emir sistemine bakarak bile yapabiliriz. Bu, aynı anda birkaç şeyi ayarlamamıza olanak sağlayacaktır. Ayrıca, bir OCO türünde pozisyonun veya bir OCO türünde bekleyen emrin kâr ve zarar eşiklerini kolayca öğrenebileceğiz, çünkü Uzman Danışman herhangi bir ekstra hesaplama gerektirmeden ilgili bilgileri gerçek zamanlı olarak gösterecektir.

Bu, uygulamanın ilk kısmı olmasına rağmen sıfırdan başlamayacağız: ticaret yaptığımız varlığın grafiğine daha fazla nesne ve olay ekleyerek mevcut sistemi değiştireceğiz.


1.0. Planlama

Burada kullandığımız sistemin planlanması çok zor değildir: sadece emirleri grafikte görüntüleyen sistemi modifiye ederek mevcut sistemi değiştireceğiz. Oldukça basit görünen ana fikir budur. Ancak pratikte yüksek düzeyde yaratıcılık gerektirir, çünkü MetaTrader 5 platformunun tüm zor işleri bizim yerimize yapabilmesi için verileri manipüle edip modellememiz gerekecektir.

Verileri modellemenin, her birinin artıları ve eksileri olan çeşitli yolları mevcuttur.

  • İlk yol bir liste kullanmaktır. Döngüsel bir tekli, döngüsel bir ikili veya hatta bir karma sistem olabilir. Bu yaklaşımlardan herhangi birini kullanmanın avantajı, uygulanmasının kolay olmasıdır. Ancak dezavantajı, veri manipülasyonunu engellemesi veya emir sayısını sınırlamasıdır. Ayrıca, bu durumda, sadece listeyi kaydetmek için tüm ek mantığı oluşturmamız gerekecektir.
  • İkinci yol, bir sınıf dizisi oluşturmaktır; sınıf, yeni oluşturulan tüm nesneleri içerecek ve koruyacaktır. Bu durumda, dizi bir liste gibi çalışacaktır, ama daha az kod yazmamız gerekecektir, çünkü MQL5 zaten bir liste kullanmamız durumunda kodlamamız gereken birkaç şeyi desteklemektedir. Ancak, bu durumda da oldukça karmaşık olacak olay işleme gibi başka sorunlarımız ortaya çıkacaktır.
  • Üçüncü yol bizim kullanacağımız yoldur. MQL5'te oluşturulan kodu dinamik nesneleri desteklemeye zorlayacağız. Bu gerçek dışı bir şey gibi görünmektedir, ancak kullanılacak verilerin modellemesini doğru yaparsak, MQL5 dili, ekrandaki nesne sayısında herhangi bir kısıtlamanın olmayacağı bir sistem oluşturmamıza olanak sağlayacaktır. Ayrıca, tüm nesneler olay oluşturabilecek ve alabilecektir. Ve bireyselliklerine rağmen, platform onların hepsini bir listede veya bir dizi indeksindeymiş gibi bağlantılı bir şekilde görecektir.

Bunun uygulanmasının kolay olmadığını düşünüyorsanız, C_HLineTrade sınıfının aşağıdaki kod parçasına bakalım:

inline void SetLineOrder(ulong ticket, double price, eHLineTrade hl, bool select)
{
        string sz0 = def_NameHLineTrade + (string)hl + (string)ticket, sz1;
                                
        ObjectCreate(Terminal.Get_ID(), sz0, OBJ_HLINE, 0, 0, 0);

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

Vurgulanan kısım, tam olarak istediğimiz kadar yatay çizgi oluşturabileceğimizi ve olayları tamamen bağımsız bir şekilde alacaklarını göstermektedir. Yapmamız gereken tek şey, adlar benzersiz olacağından, her bir satırın sahip olacağı ada dayalı olarak olayları uygulamaktır. MetaTrader 5 platformu gerisini halledecektir. Sonuç şuna benzer bir şey olacaktır:


Bu halihazırda ideal bir şey gibi görünse de, bu modelleme gerçekten ihtiyacımız olan sonucu elde etmek için yeterli olmayacaktır. Fikir hayata geçirilebilir. Ancak Uzman Danışmanda şu anda mevcut olan veri modellemesi uygun değildir, çünkü tek bir ada dayalı sınırsız sayıda nesneye sahip olamayız. Oldukça derin bir kod değişikliği gerektiren bazı değişiklikler yapmamız gerekmektedir.

Şimdi bu yeni veri modelleme yöntemini uygulamaya başlayacağız, ancak tüm kodu stabil tutmak amacıyla bunun için yalnızca gerekli olanları değiştireceğiz, çünkü kod mümkün olduğunca istikrarlı bir şekilde çalışmaya devam etmelidir. Tüm işler MetaTrader 5 platformu tarafından gerçekleştirilecektir, biz sadece platformun modellememizi nasıl anlaması gerektiğini belirteceğiz.


2.0. Uygulama

İlk değişiklik, C_HLineTrade sınıfının yeni C_ObjectsTrade sınıfına dönüştürülmesidir. Bu yeni sınıf, ihtiyacımız olan şeyi, yani sınırsız sayıda nesneyi birbirine bağlamanın yolunu destekleyecektir.

Aşağıdaki kodda görülebilen orijinal tanımlara bakarak başlayalım.

class C_ObjectsTrade
{
//+------------------------------------------------------------------+
#define def_NameObjectsTrade 	"SMD_OT"
#define def_SeparatorInfo       '*'
#define def_IndicatorTicket0    1
//+------------------------------------------------------------------+
        protected:
                enum eIndicatorTrade {IT_NULL, IT_STOP= 65, IT_TAKE, IT_PRICE};
//+------------------------------------------------------------------+

// ... The rest of the class code

Burada, uygulayacağımız ilk temele sahibiz. Gelecekte genişleteceğiz, ancak şimdilik sistemi değiştirirken ve yeni veri modellemesini uygularken bu şekilde kalmasını istiyorum.

Yine de protected bildirimin içerisinde aşağıdaki fonksiyonlara sahibiz:

inline double GetLimitsTake(void) const { return m_Limits.TakeProfit; }
//+------------------------------------------------------------------+
inline double GetLimitsStop(void) const { return m_Limits.StopLoss; }
//+------------------------------------------------------------------+
inline bool GetLimitsIsBuy(void) const { return m_Limits.IsBuy; }
//+------------------------------------------------------------------+
inline void SetLimits(double take, double stop, bool isbuy)
{
        m_Limits.IsBuy = isbuy;
        m_Limits.TakeProfit = (m_Limits.TakeProfit < 0 ? take : (isbuy ? (m_Limits.TakeProfit > take ? m_Limits.TakeProfit : take) : (take > m_Limits.TakeProfit ? m_Limits.TakeProfit : take)));
        m_Limits.StopLoss = (m_Limits.StopLoss < 0 ? stop : (isbuy ? (m_Limits.StopLoss < stop ? m_Limits.StopLoss : stop) : (stop < m_Limits.StopLoss ? m_Limits.StopLoss : stop)));
}
//+------------------------------------------------------------------+
inline int GetBaseFinanceLeveRange(void) const { return m_BaseFinance.Leverange; }
//+------------------------------------------------------------------+
inline int GetBaseFinanceIsDayTrade(void) const { return m_BaseFinance.IsDayTrade; }
//+------------------------------------------------------------------+
inline int GetBaseFinanceTakeProfit(void) const { return m_BaseFinance.FinanceTake; }
//+------------------------------------------------------------------+
inline int GetBaseFinanceStopLoss(void) const { return m_BaseFinance.FinanceStop; }

Şu anda bu fonksiyonlar, gelecekte uygulayacağımız başka bir şema için sadece bir güvenlik önlemi olarak hizmet vermektedir. Verileri ve gerçekleştirilen ayrıştırmayı başka bir yerde uygulayabilsek de, bazı şeyleri kalıtım zincirinde mümkün olduğunca aşağıda bırakmak iyidir. Geri dönüş değerleri yalnızca türetilmiş sınıflar tarafından kullanılacak olsa dahi, buna doğrudan izin vermek istemiyorum: yani, türetilmiş sınıfın bu C_ObjectsTrade nesne sınıfındaki değerlere basitçe erişmesini istemiyorum, çünkü bu, nesne sınıfını kapsülleme fikrini bozacaktır ve türetilmiş sınıf, bir prosedür çağrısı yoluyla uygun değişiklikleri yapmadan temel sınıfın değerini değiştirdiğinde, gelecekteki değişiklikleri veya hata düzeltmelerini zorlaştıracaktır.

Çağrı çakışmasını mümkün olduğunca en aza indirmek için tüm fonksiyonlar satır içi olarak bildirilir: bu, çalıştırılabilir dosyanın boyutunu biraz artırır, ancak daha güvenli bir sistemle sonuçlanır.

Şimdi private bildirimlere geldik.

//+------------------------------------------------------------------+
        private :
                string  m_SelectObj;
                struct st00
                {
                        double  TakeProfit,
                                StopLoss;
                        bool    IsBuy;
                }m_Limits;
                struct st01
                {
                        int     FinanceTake,
                                FinanceStop,
                                Leverange;
                        bool    IsDayTrade;
                }m_BaseFinance;
//+------------------------------------------------------------------+
                string MountName(ulong ticket, eIndicatorTrade it)
                {
                        return StringFormat("%s%c%c%c%d", def_NameObjectsTrade, def_SeparatorInfo, (char)it, def_SeparatorInfo, ticket);
                }
//+------------------------------------------------------------------+

Buradaki en önemli kısım, nesnelerin isimlerini modelleyecek olan vurgulanan parçadır. Şimdilik hala sistemde mevcut olan temel bilgileri tutuyorum. Bunun nedeni, önce modellemeyi oluşturmamız ve değiştirmemizdir ve bunu yaparken sistemi stabil tutmak istiyoruz. Daha sonra yeni nesneler ekleyeceğiz, ancak bu oldukça kolay ve hızlı bir şekilde yapılacaktır. Ayrıca, halihazırda sağlanmış olan stabiliteyi de koruyacağız.

Kod, burada gösterilenden çok daha fazla değişikliğe uğramış olsa da, bu andan itibaren yalnızca yeni fonksiyonlara ve önceki kodlara kıyasla önemli olan değişikliklere odaklanacağım.

İlk fonksiyon aşağıda gösterilmektedir:

inline string CreateIndicatorTrade(ulong ticket, eIndicatorTrade it, bool select)
{
        string sz0 = MountName(ticket, it);
                                
        ObjectCreate(Terminal.Get_ID(), sz0, OBJ_HLINE, 0, 0, 0);
        ObjectSetInteger(Terminal.Get_ID(), sz0, OBJPROP_COLOR, (it == IT_PRICE ? clrBlue : (it == IT_STOP ? clrFireBrick : clrForestGreen)));
        ObjectSetInteger(Terminal.Get_ID(), sz0, OBJPROP_WIDTH, 1);
        ObjectSetInteger(Terminal.Get_ID(), sz0, OBJPROP_STYLE, STYLE_DASHDOT);
        ObjectSetInteger(Terminal.Get_ID(), sz0, OBJPROP_SELECTABLE, select);
        ObjectSetInteger(Terminal.Get_ID(), sz0, OBJPROP_SELECTED, false);
        ObjectSetInteger(Terminal.Get_ID(), sz0, OBJPROP_BACK, true);
        ObjectSetString(Terminal.Get_ID(), sz0, OBJPROP_TOOLTIP, (string)ticket + " "+StringSubstr(EnumToString(it), 3, 10));
                                
        return sz0;
}

Şimdilik sadece yatay bir çizgi oluşturacaktır. Ad oluşturma koduna dikkat edin; ayrıca renklerin artık kullanıcı tarafından değil dahili olarak kod tarafından tanımlanacağını unutmayın.

Ardından, aşağıda görülebileceği gibi aynı fonksiyona overload yaparız.

inline string CreateIndicatorTrade(ulong ticket, double price, eIndicatorTrade it, bool select)
{
        if (price <= 0)
        {
                RemoveIndicatorTrade(ticket, it);
                return NULL;
        }
        string sz0 = CreateIndicatorTrade(ticket, it, select);
        ObjectMove(Terminal.Get_ID(), sz0, 0, 0, price);
                                
        return sz0;
}

Bu iki fonksiyonu birbirine karıştırmayın, çünkü aynı gibi görünseler de aslında farklıdırlar. Overload oldukça yaygındır: basit bir fonksiyon oluştururuz ve daha sonra belirli bir modelleme türünü biriktirmek için ona yeni parametreler ekleriz. Bunu overload yoluyla uygulamasaydık, aynı kod sekansını zaman zaman tekrarlamak zorunda kalırdık. Bu tehlikelidir, çünkü bir şeyi bildirmeyi unutabiliriz. Ayrıca, çok da pratik değildir, dolayısıyla birkaç çağrı yerine bir çağrı yapmak adına fonksiyona overload yaparız.

Burada belirtilmesi gereken bir husus, bu ikinci versiyonda vurgulanan kısımdır. Onu burada oluşturmaya gerek yoktur, başka bir yerde de yapabiliriz. Ancak, görülebileceği gibi, sıfır fiyatla bir nesne oluşturmaya çalıştığımızda, aslında yok edilmesi gerekecektir.

Bunun gerçekleştiği anı gerçekten görmek için aşağıdaki koda bir göz atalım:

class C_Router : public C_ObjectsTrade
{

// ... Internal class code ....

                void UpdatePosition(int iAdjust = -1)
                        {

// ... Internal function code ...

                                for(int i0 = p; i0 >= 0; i0--) if(PositionGetSymbol(i0) == Terminal.GetSymbol())
                                {
                                        ul = PositionGetInteger(POSITION_TICKET);
                                        m_bContainsPosition = true;
                                        CreateIndicatorTrade(ul, PositionGetDouble(POSITION_PRICE_OPEN), IT_PRICE, false);
                                        CreateIndicatorTrade(ul, take = PositionGetDouble(POSITION_TP), IT_TAKE, true);
                                        CreateIndicatorTrade(ul, stop = PositionGetDouble(POSITION_SL), IT_STOP, true);

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

Uzman Danışman, OnTrade olayını her aldığında, yukarıdaki fonksiyonu yürütecek ve seçilen noktalarda bir gösterge oluşturmaya çalışacaktır, ancak kullanıcı eşiği kaldırırsa, sıfır olacaktır. Bu nedenle, çağrıldığında, aslında göstergeyi grafikten silerek bizi bellekteki gereksiz nesnelerden kurtaracaktır. Böylece bazı noktalarda avantaj elde ediyoruz, çünkü kontrol tam oluşturma anında gerçekleştirilecektir.

Ancak overload konusunda hala bir sorunumuz vardır, çünkü bazı insanlar bunun gerçek kodda nasıl kullanıldığını tam olarak anlayamayabilir. Bunu anlamak için aşağıdaki iki kod parçasına bakalım:

class C_OrderView : public C_Router
{
        private  :
//+------------------------------------------------------------------+
        public   :
//+------------------------------------------------------------------+
                void InitBaseFinance(int nContracts, int FinanceTake, int FinanceStop, bool b1)
                        {                       
                                SetBaseFinance(nContracts, FinanceTake, FinanceStop, b1);
                                CreateIndicatorTrade(def_IndicatorTicket0, IT_PRICE, false);
                                CreateIndicatorTrade(def_IndicatorTicket0, IT_TAKE, false);
                                CreateIndicatorTrade(def_IndicatorTicket0, IT_STOP, false);
                        }
//+------------------------------------------------------------------+

// ... Rest of the code...
class C_Router : public C_ObjectsTrade
{

// ... Class code ...

                void UpdatePosition(int iAdjust = -1)
                        {
// ... Function code ....
                                for(int i0 = p; i0 >= 0; i0--) if(PositionGetSymbol(i0) == Terminal.GetSymbol())
                                {
                                        ul = PositionGetInteger(POSITION_TICKET);
                                        m_bContainsPosition = true;
                                        CreateIndicatorTrade(ul, PositionGetDouble(POSITION_PRICE_OPEN), IT_PRICE, false);

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

Her iki durumda da kullanılan fonksiyonun adının aynı olduğuna dikkat edin. Ayrıca, her ikisi de aynı C_ObjectsTrade sınıfının bir parçasıdır. Ancak, bu durumda bile derleyici parametre sayısı nedeniyle bunları birbirinden ayırt edebilir. Yakından bakarsanız, tek farkın ek bir fiyat parametresi olduğunu göreceksiniz, ancak daha birçok parametre de olabilir. Gördüğünüz gibi, overload versiyonlardan birinde bulunan tüm kodu kopyalamak için yalnızca tek bir çağrı kullanmak çok daha basittir, bu sayede sonuçta bakımı daha kolay olan daha temiz bir koda sahip oluruz.

Şimdi C_ObjectsTrade sınıfına geri dönelim. Anlaşılması gereken bir sonraki fonksiyon şudur:

bool GetInfosOrder(const string &sparam, ulong &ticket, double &price, eIndicatorTrade &it)
{
        string szRet[];
        char szInfo[];
                                
        if (StringSplit(sparam, def_SeparatorInfo, szRet) < 2) return false;
        if (szRet[0] != def_NameObjectsTrade) return false;
        StringToCharArray(szRet[1], szInfo);
        it = (eIndicatorTrade)szInfo[0];
        ticket = (ulong) StringToInteger(szRet[2]);
        price = ObjectGetDouble(Terminal.Get_ID(), sparam, OBJPROP_PRICE);
                                
        return true;
}

Aslında bu, tüm yeni sistemin kalbi, zihni ve bedenidir. Oldukça basit görünmesine rağmen, tüm Uzman Danışmanın yeni modelleme sistemimizin gerektirdiği şekilde çalışması için gerekli olan son derece önemli bir işi yapmaktadır.

Vurgulanan koda, özellikle de StringSplit fonksiyonuna çok dikkat edin. MQL5'te mevcut olmasaydı, onu kodlamamız gerekirdi. Neyse ki MQL5'te bulunmaktadır, bu yüzden bu fonksiyonu sonuna kadar kullanacağız. Yaptığı şey, nesnenin adını gerekli verilere ayrıştırmaktır. Nesne adı, oluşturulurken çok spesifik bir şekilde modellenir, böylece bu kodlama modelini geri alabiliriz, yani StringSplit, StringFormat fonksiyonun yaptığı şeyi geri alacaktır.

Fonksiyonun geri kalanı, nesne adında bulunan verileri yakalar, böylece onu test edebilir ve daha sonra kullanabiliriz. Diğer bir deyişle, MetaTrader 5 bizim için verileri üretir, ne olduğunu bilmek için onları ayrıştırırız ve ardından da MetaTrader 5'e hangi adımları atması gerektiğini söyleriz. Amacımız MetaTrader 5'in bizim için çalışmasını sağlamaktır. Sıfırdan bir platform oluşturmuyoruz; bunun yerine arayüzü ve Uzman Danışmanı sıfırdan modelliyoruz. Bu nedenle harici bir çözüm aramak yerine MetaTrader 5'in sunduğu destekten faydalanmalıyız.

Aşağıdaki kodda yukarıda yaptığımıza çok benzer bir şey yapacağız:

inline void RemoveAllsIndicatorTrade(bool bFull)
{
        string sz0, szRet[];
        int i0 = StringLen(def_NameObjectsTrade);
                                
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, false);
        for (int c0 = ObjectsTotal(Terminal.Get_ID(), -1, -1); c0 >= 0; c0--)
        {
                sz0 = ObjectName(Terminal.Get_ID(), c0, -1, -1);
                if (StringSubstr(sz0, 0, i0) == def_NameObjectsTrade)
                {
                        if (!bFull)
                        {
                                StringSplit(sz0, def_SeparatorInfo, szRet);
                                if (StringToInteger(szRet[2]) == def_IndicatorTicket0) continue;
                        }
                }else continue;                                         
                ObjectDelete(Terminal.Get_ID(), sz0);
        }
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, true);
}

İster kapatılacak bir pozisyon ister kaldırılacak bir eşik seviyesi olsun, grafikten bir çizgiyi her kaldırdığımızda, tıpkı Uzman Danışmanın grafikten kaldırıldığında olduğu gibi, ilgili nesnenin de kaldırılması gerekir. Nesneleri kaldırmamız gerekiyor, ancak gerçekten gerekli olmadıkça kaldırılmaması gereken birkaç çizgimiz de vardır: bu Ticket0’dır ve çok gerekli olmadıkça kaldırılmamalıdır. Bundan kaçınmak için, vurgulanan kodu kullanacağız. Bu kod olmadan, bu Ticket0'ı her seferinde yeniden oluşturmamız gerekirdi, çünkü bu fiş daha sonra tartışacağımız başka bir kod bölümünde çok önemlidir.

Diğer zamanlarda oldukça spesifik bir şeyi kaldırmamız gerekiyor. Bu amaçla aşağıda gösterilen başka bir kaldırma fonksiyonunu kullanacağız.

inline void RemoveIndicatorTrade(ulong ticket, eIndicatorTrade it = IT_NULL)
{
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, false);
        if ((it != NULL) && (it != IT_PRICE))
                ObjectDelete(Terminal.Get_ID(), MountName(ticket, it));
        else
        {
                ObjectDelete(Terminal.Get_ID(), MountName(ticket, IT_PRICE));
                ObjectDelete(Terminal.Get_ID(), MountName(ticket, IT_TAKE));
                ObjectDelete(Terminal.Get_ID(), MountName(ticket, IT_STOP));
        }
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, true);
}

Bir sonraki yeni fonksiyon aşağıdadır:

inline void PositionAxlePrice(double price, ulong ticket, eIndicatorTrade it, int FinanceTake, int FinanceStop, int Leverange, bool isBuy)
{
        double ad = Terminal.GetAdjustToTrade() / (Leverange * Terminal.GetVolumeMinimal());
        ObjectMove(Terminal.Get_ID(), MountName(ticket, it), 0, 0, price);
        if (it == IT_PRICE)
        {
                ObjectMove(Terminal.Get_ID(), MountName(ticket, IT_TAKE), 0, 0, price + Terminal.AdjustPrice(FinanceTake * (isBuy ? ad : (-ad))));
                ObjectMove(Terminal.Get_ID(), MountName(ticket, IT_STOP), 0, 0, price + Terminal.AdjustPrice(FinanceStop * (isBuy ? (-ad) : ad)));
        }
}

Nesneleri fiyat eksenine yerleştirecektir. Ancak ona fazla bağlanmayın, çünkü yakında çeşitli nedenlerle varlığına son verilecektir. Bunlar arasında, bu serinin bir başka makalesinde ele aldığımız bir tanesi de bulunmaktadır: Bir grafikte birden fazla gösterge (Bölüm 05): MetaTrader 5'i bir RAD sistemine dönüştürme (I). Bu makalede, konumlandırma için kartezyen koordinatları (X ve Y) kullanabilen nesneleri gösteren bir tablo mevcuttur. Fiyat ve zaman koordinatları, bazı durumlarda kullanışlı olmasına rağmen, her zaman uygun değildir: ekranda belirli noktalarda konumlandırılması gereken nesneleri konumlandırmak istediğimizde, fiyat ve zaman koordinatlarını kullanarak bir şeyler geliştirmek daha hızlı olsa da, X ve Y sisteminden çok daha zordur.

Bir dahaki sefere değişiklikler yapacağız, ancak şu anda hedefimiz şimdiye kadar kullanılana alternatif bir sistem oluşturmaktır.

Sırada, C_ObjectsTrade sınıfındaki son önemli fonksiyon vardır. Aşağıdaki kodda gösterilmektedir:

inline double GetDisplacement(const bool IsBuy, const double Vol, eIndicatorTrade it) const
{
        int i0 = (it == IT_TAKE ? m_BaseFinance.FinanceTake : m_BaseFinance.FinanceStop),
            i1 = (it == IT_TAKE ? (IsBuy ? 1 : -1) : (IsBuy ? -1 : 1));
        return (Terminal.AdjustPrice(i0 * (Vol / m_BaseFinance.Leverange) * Terminal.GetAdjustToTrade() / Vol) * i1);
}

Bu fonksiyon, yerleştirilecek bir bekleyen emir veya piyasa fiyatından açılacak bir pozisyon için ticaret arayüzünde belirtilen değerler arasında dönüşüm yapacaktır.

Tüm bu değişiklikler, C_HLineTrade fonksiyonunu C_ObjectsTrade fonksiyonuna dönüştürmek için uygulanmıştır. Ancak bu değişiklikler başka bazı değişiklikleri de gerektirmiştir. Örneğin, aynı zamanda bir diğer önemli ölçüde değişen de C_ViewOrder sınıfıdır. Bu sınıfın bazı bölümleri, artık var olmalarının bir anlamı olmadığı için basitçe ortadan kaldırılmıştır, kalan fonksiyonlar ise değiştirilmiştir. Özel ilgiyi hak eden fonksiyonlar aşağıda vurgulanmaktadır.

İlki, ticaret arayüzünden gelen verileri başlatma fonksiyonudur.

void InitBaseFinance(int nContracts, int FinanceTake, int FinanceStop, bool b1)
{                       
        SetBaseFinance(nContracts, FinanceTake, FinanceStop, b1);
        CreateIndicatorTrade(def_IndicatorTicket0, IT_PRICE, false);
        CreateIndicatorTrade(def_IndicatorTicket0, IT_TAKE, false);
        CreateIndicatorTrade(def_IndicatorTicket0, IT_STOP, false);
}

Vurgulanan kısımlar Ticket0'ın gerçekte oluşturulduğu yerlerdir. Bu fiş, fare ve klavye kullanarak bir bekleyen emir yerleştirmek için kullanılır: Alış için (SHIFT), satış için (CTRL). Önceden, bu noktada çizgiler oluşturuluyor ve bu çizgiler daha sonra emrin nerede bulunacağını belirtmek için kullanılıyordu. Artık işler çok daha basittir: yerleştirilecek bir emir gördüğümüz gibi, bir bekleyen emir veya bir açık pozisyon da göreceğiz. Bu, sistemi her zaman kontrol edeceğimiz anlamına geliyor. Bu tıpkı bir aracı monte ederken frenlerini kontrol etmeniz ve böylece gerçekten kullanmanız gerektiğinde nasıl davranacağını bilmeniz gibidir.

Uzun bir kodla ilgili en büyük sorun, fonksiyon oluşturduğumuzda, yalnızca gerçekten kullanıldığı zaman çalıştığını bilebilmemizdir. Ancak şimdi sistem her zaman kontrol ediliyor - tüm fonksiyonları kullanmasak bile, kodun farklı yerlerde yeniden kullanılması nedeniyle sürekli kontrol ediliyorlar.

Bu makalede bahsedeceğim son fonksiyon aşağıda gösterilmektedir. Bekleyen bir emir yerleştirecektir. Önceki makalelerdeki aynı fonksiyona kıyasla son derece kompakt hale geldiğine dikkat edin.

inline void MoveTo(uint Key)
{
        static double local = 0;
        datetime dt;
        bool    bEClick, bKeyBuy, bKeySell, bCheck;
        double  take = 0, stop = 0, price;
                                
        bEClick  = (Key & 0x01) == 0x01;    //Let mouse button click
        bKeyBuy  = (Key & 0x04) == 0x04;    //Pressed SHIFT
        bKeySell = (Key & 0x08) == 0x08;    //Pressed CTRL  
        Mouse.GetPositionDP(dt, price);
        if (bKeyBuy != bKeySell)
        {
                Mouse.Hide();
                bCheck = CheckLimits(price);
        } else Mouse.Show();
        PositionAxlePrice((bKeyBuy != bKeySell ? price : 0), def_IndicatorTicket0, IT_PRICE, (bCheck ? 0 : GetBaseFinanceTakeProfit()), (bCheck ? 0 : GetBaseFinanceStopLoss()), GetBaseFinanceLeveRange(), bKeyBuy);
        if((bEClick) && (bKeyBuy != bKeySell) && (local == 0)) CreateOrderPendent(bKeyBuy, local = price);
        local = (local != price ? 0 : local);
}

Bunun nedeni, artık sistemde yeni bir kural olacak olması, dolayısıyla fonksiyonun ‘biraz ağırlık kaybetmesi’ ve daha kompakt hale gelmesidir.


Sonuç

Bir sonraki makalede kullanılacak bazı değişiklikleri burada sundum. Tüm bunların amacı onları daha basit hale getirmek ve farklı zamanlarda farklı olabilecek şeyleri göstermektir. Burada, ticarette size yardımcı olacak bir Uzman Danışmanı nasıl programlayacağınızı öğrenmenizi istiyorum, bu yüzden sadece bitmiş ve kullanıma hazır bir sistem sunmuyorum, böylece süreci adım adım takip edip analiz ederek bu konuda çok daha başarılı olabileceksiniz. Çözülmesi gereken sorunlar olduğunu ve geliştirme sırasında ortaya çıkan bu soruları ve sorunları çözmek için nasıl bir yol izlediğimi size göstermek istiyorum. Umarım bu noktayı anlamışsınızdır. Çünkü fikir bir sistem oluşturmak ve bitmiş bir ürün olarak sunmak olsaydı, onu yapar ve satardım, ama niyetim bu değildir.

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

Ekli dosyalar |
EA.zip (12023.87 KB)
Force Index göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? Force Index göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
En popüler teknik göstergelere dayalı ticaret sistemlerini nasıl tasarlayacağımızı öğrendiğimiz serimizin yeni makalesine hoş geldiniz. Bu makalede, yeni bir teknik göstergeyi, Force Index göstergesini kullanarak bir ticaret sisteminin nasıl oluşturulacağını öğreneceğiz.
Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 18): Yeni emir sistemi (I) Sıfırdan bir ticaret Uzman Danışmanı geliştirme (Bölüm 18): Yeni emir sistemi (I)
Bu makale, yeni emir sisteminin ilk kısmıdır. Uzman Danışmanımızı makalelerimizde belgelemeye başladığımızdan beri, çeşitli değişiklikler ve iyileştirmelerden geçti, ancak aynı grafik üzeri emir sistemi modelini korudu. Artık yeni bir emir sistemine ihtiyacımız vardır.
Bear’s Power göstergesine dayalı bir ticaret sistemi nasıl geliştirilir? Bear’s Power göstergesine dayalı bir ticaret sistemi nasıl geliştirilir?
En popüler teknik göstergelere dayalı ticaret sistemlerinin nasıl geliştirileceğine ilişkin serimizin yeni makalesine hoş geldiniz. Bu makalemizde Bear’s Power teknik göstergesine odaklanacağız.
Popülasyon optimizasyon algoritmaları: Parçacık sürüsü optimizasyonu (Particle Swarm Optimization, PSO) Popülasyon optimizasyon algoritmaları: Parçacık sürüsü optimizasyonu (Particle Swarm Optimization, PSO)
Bu makalede, popüler parçacık sürüsü optimizasyonu (Particle Swarm Optimization, PSO) algoritmasını ele alacağız. Bir önceki makalede, optimizasyon algoritmalarının yakınsama, yakınsama oranı, kararlılık, ölçeklenebilirlik gibi önemli özelliklerini tartıştık, ayrıca bir test ortamı geliştirdik ve en basit RNG algoritmasını inceledik.