
MQL5 Tarif Defteri: Üçlü Ekran Stratejisine Dayalı Bir Alım Satım Sistemi Çerçevesi Geliştirme
Giriş
Alım satım sistemleri ararken veya geliştirirken, birçok yatırımcı Dr. Alexander Elder tarafından tanıtılan Üçlü Ekran Stratejisini duymuştur. İnternette bu stratejiyle ilgili düşüncesi olumsuz olan birçok insan var. Bununla birlikte, birçok insan bunun kâr edilmesine yardımcı olabileceğine inanıyor. Her iki görüşe de güvenmek zorunda değilsiniz. Her şey her zaman ilk elden kontrol edilmelidir. Programlama eğitimi alıyorsanız, geriye dönük test kullanarak alım satım stratejisi performansını kontrol edebileceğiniz için her şey sizin elinizde.
Bu makalede, MQL5'te Üçlü Ekran stratejisine dayalı bir alım satım sistemi için bir çerçeve geliştireceğiz. Uzman Danışman sıfırdan geliştirilmeyecektir. Bunun yerine, "MQL5 Tarif Defteri: Uzman Danışmanlarda Alım Satım Koşullarını Belirlemek için Göstergeleri Kullanma" önceki makalesinden programı değiştireceğiz. Böylelikle makale aynı zamanda hazır programların modellerini nasıl kolay bir şekilde değiştirebileceğinizi gösterecektir.
Bir önceki makaledeki Uzman Danışman, karşı sinyalde Zarar Durdur/Kâr Al ve İz-süren Stop seviyelerini etkinleştirme/devre dışı bırakma, pozisyon hacmini artırma ve pozisyon ters çevirme imkanına zaten sahiptir. Gerekli tüm fonksiyonlar yerine yerleştirilmiştir. Bu nedenle görevimiz, ek seçenekler ekleyerek ve mevcut bazı fonksiyonları değiştirerek harici parametrelerin listesini değiştirmeye odaklanmıştır.
Örnekleme amacıyla, Hareketli Ortalama göstergesini kullanarak oluşturulacak üç zaman aralığında sinyaller düzenleyeceğiz. Daha sonra, geliştirilen çerçeve üzerinde denemeye devam ederek ve kodu biraz değiştirerek başka herhangi bir göstergeyi de kullanabileceksiniz. Ayrıca her ekran için zaman aralıkları belirleme imkanını da uygulayacağız. Gösterge periyodundan sorumlu parametrenin değeri sıfır ise, bu ilgili ekranın kullanılmadığını gösterir. Diğer bir deyişle, sistem bir veya iki zaman aralığına sahip olacak şekilde ayarlanabilir.
Başlamadan önce, önceki makaledeki Uzman Danışman dosyalarının bulunduğu klasörün bir kopyasını alın ve yeniden adlandırın.
Uzman Danışman Geliştirme
Harici parametrelerle başlayalım. Aşağıda güncellenen listenin kodu yer almaktadır. Yeni çizgiler seçilir. Zaman aralıkları, ENUM_TIMEFRAMES numaralandırma türüyle bildirilir. Açılır listeden herhangi bir zaman aralığını seçebileceksiniz.
//--- External parameters of the Expert Advisor sinput long MagicNumber=777; // Magic number sinput int Deviation=10; // Slippage //--- input ENUM_TIMEFRAMES Screen01TimeFrame=PERIOD_W1; // Time frame of the first screen input int Screen01IndicatorPeriod=14; // Indicator period of the first screen //--- input ENUM_TIMEFRAMES Screen02TimeFrame=PERIOD_D1; // Time frame of the second screen input int Screen02IndicatorPeriod=24; // Indicator period of the second screen //--- input ENUM_TIMEFRAMES Screen03TimeFrame=PERIOD_H4; // Time frame of the third screen input int Screen03IndicatorPeriod=44; // Indicator period of the third screen //--- input double Lot=0.1; // Lot input double VolumeIncrease=0.1; // Position volume increase input double VolumeIncreaseStep=10; // Step for position volume increase input double StopLoss=50; // Stop Loss input double TakeProfit=100; // Take Profit input double TrailingStop=10; // Trailing Stop input bool Reverse=true; // Position reversal sinput bool ShowInfoPanel=true; // Display of the info panel
Örneği basitleştirmek için IndicatorSegments parametresinin yanı sıra AllowedNumberOfSegments değişkeni ve CorrectInputParameters() fonksiyonu kaldırılmıştır. Bu durumla ilgilenenleriniz bunu kendi başına uygulamaya çalışabilir. Bu Uzman Danışman yalnızca bir gösterge kullanacağından, Enums.mqh dosyasındaki göstergelerin numaralandırmasını da kaldırmalısınız.
Her zaman aralığında ayrı bir gösterge olacağından, göstergelerin her birini ele almak için ayrı bir değişkene ihtiyacımız olacak:
//--- Indicator handles int Screen01IndicatorHandle=INVALID_HANDLE; // Indicator handle on the first screen int Screen02IndicatorHandle=INVALID_HANDLE; // Indicator handle on the second screen int Screen03IndicatorHandle=INVALID_HANDLE; // Indicator handle on the third screen
Yeni çubuk, minimum zaman aralığı kullanılarak kontrol edilecektir. Harici parametrelerde minimum zaman aralığını ayarlarken, maksimum, orta, minimum gibi belirli bir sıra izlememiz gerekmez. Ters sıra ve esas olarak herhangi bir sıra iş görür. Bu nedenle, belirtilen tüm zaman aralıklarından minimum zaman aralığını belirleyecek bir fonksiyona ihtiyacımız var.
Uzman Danışman, bir veya iki zaman aralığının yanı sıra üç zaman aralığında çalışacak şekilde ayarlanabildiğinden, minimum zaman aralığını belirlenirken tüm seçeneklerin dikkate alınması gerekiyor. Aşağıda, GetMinimumTimeframe() fonksiyonunun kodu yer almaktadır:
//+------------------------------------------------------------------+ //| Determining the minimum time frame for the new bar check | //+------------------------------------------------------------------+ ENUM_TIMEFRAMES GetMinimumTimeframe(ENUM_TIMEFRAMES timeframe1,int period1, ENUM_TIMEFRAMES timeframe2,int period2, ENUM_TIMEFRAMES timeframe3,int period3) { //--- Default minimum time frame value ENUM_TIMEFRAMES timeframe_min=PERIOD_CURRENT; //--- Convert time frame values to seconds for calculations int t1= PeriodSeconds(timeframe1); int t2= PeriodSeconds(timeframe2); int t3= PeriodSeconds(timeframe3); //--- Check for incorrect period values if(period1<=0 && period2<=0 && period3<=0) return(timeframe_min); //--- Conditions for a single time frame if(period1>0 && period2<=0 && period3<=0) return(timeframe1); if(period2>0 && period1<=0 && period3<=0) return(timeframe2); if(period3>0 && period1<=0 && period2<=0) return(timeframe3); //--- Conditions for two time frames if(period1>0 && period2>0 && period3<=0) { timeframe_min=(MathMin(t1,t2)==t1) ? timeframe1 : timeframe2; return(timeframe_min); } if(period1>0 && period3>0 && period2<=0) { timeframe_min=(MathMin(t1,t3)==t1) ? timeframe1 : timeframe3; return(timeframe_min); } if(period2>0 && period3>0 && period1<=0) { timeframe_min=(MathMin(t2,t3)==t2) ? timeframe2 : timeframe3; return(timeframe_min); } //--- Conditions for three time frames if(period1>0 && period2>0 && period3>0) { timeframe_min=(int)MathMin(t1,t2)==t1 ? timeframe1 : timeframe2; int t_min=PeriodSeconds(timeframe_min); timeframe_min=(int)MathMin(t_min,t3)==t_min ? timeframe_min : timeframe3; return(timeframe_min); } return(WRONG_VALUE); }
Minimum zaman aralığı değerini kaydetmek için başka bir global kapsam değişkeni oluşturacağız:
//--- Variable for determining the minimum time frame ENUM_TIMEFRAMES MinimumTimeframe=WRONG_VALUE;
OnInit() fonksiyonunda Uzman Danışman başlatılırken GetMinimumTimeframe() fonksiyonunun çağrılması gerekiyor.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Determine the minimum time frame for the new bar check MinimumTimeframe=GetMinimumTimeframe(Screen01TimeFrame,Screen01IndicatorPeriod, Screen02TimeFrame,Screen02IndicatorPeriod, Screen03TimeFrame,Screen03IndicatorPeriod); //--- Get indicator handles GetIndicatorHandles(); //--- Initialize the new bar CheckNewBar(); //--- Get the properties GetPositionProperties(P_ALL); //--- Set the info panel SetInfoPanel(); //--- return(0); }
MinimumTimeframe değişken değeri daha sonra CheckNewBar() ve GetBarsData() fonksiyonlarında kullanılır.
GetIndicatorHandle() fonksiyonu artık aşağıda gösterildiği gibi görünüyor. Her gösterge için dönem ve zaman aralığı belirlenir.
//+------------------------------------------------------------------+ //| Getting indicator handles | //+------------------------------------------------------------------+ void GetIndicatorHandles() { //--- Get handles of the indicators specified in the parameters if(Screen01IndicatorPeriod>0) Screen01IndicatorHandle=iMA(_Symbol,Screen01TimeFrame,Screen01IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE); if(Screen02IndicatorPeriod>0) Screen02IndicatorHandle=iMA(_Symbol,Screen02TimeFrame,Screen02IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE); if(Screen03IndicatorPeriod>0) Screen03IndicatorHandle=iMA(_Symbol,Screen03TimeFrame,Screen03IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE); //--- If the indicator handle for the first time frame could not be obtained if(Screen01IndicatorHandle==INVALID_HANDLE) Print("Failed to get the indicator handle for Screen 1!"); //--- If the indicator handle for the second time frame could not be obtained if(Screen01IndicatorHandle==INVALID_HANDLE) Print("Failed to get the indicator handle for Screen 2!"); //--- If the indicator handle for the third time frame could not be obtained if(Screen01IndicatorHandle==INVALID_HANDLE) Print("Failed to get the indicator handle for Screen 3!"); }
Ayrıca, gösterge değerlerini elde edecek diziler (her zaman aralığı için ayrı ayrı) eklememiz gerekiyor:
//--- Arrays for values of the indicators double indicator_buffer1[]; double indicator_buffer2[]; double indicator_buffer3[];
Gösterge değerlerini elde etmek için GetIndicatorsData() fonksiyonu şimdi aşağıda gösterildiği gibi görünüyor. Elde edilen işleyiciler doğruluk açısından kontrol edilir ve her şey yolundaysa diziler gösterge değerleriyle doldurulur.
//+------------------------------------------------------------------+ //| Getting indicator values | //+------------------------------------------------------------------+ bool GetIndicatorsData() { //--- Number of indicator buffer values for determining the trading signal int NumberOfValues=3; //--- If indicator handles have not been obtained if((Screen01IndicatorPeriod>0 && Screen01IndicatorHandle==INVALID_HANDLE) || (Screen02IndicatorPeriod>0 && Screen02IndicatorHandle==INVALID_HANDLE) || (Screen03IndicatorPeriod>0 && Screen03IndicatorHandle==INVALID_HANDLE)) //--- try to get them again GetIndicatorHandles(); //--- If the time frame of the first screen is used and the indicator handle has been obtained if(Screen01TimeFrame>0 && Screen01IndicatorHandle!=INVALID_HANDLE) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer1,true); //--- Get indicator values if(CopyBuffer(Screen01IndicatorHandle,0,0,NumberOfValues,indicator_buffer1)<NumberOfValues) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); //--- return(false); } } //--- If the time frame of the second screen is used and the indicator handle has been obtained if(Screen02TimeFrame>0 && Screen02IndicatorHandle!=INVALID_HANDLE) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer2,true); //--- Get indicator values if(CopyBuffer(Screen02IndicatorHandle,0,0,NumberOfValues,indicator_buffer2)<NumberOfValues) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer2 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); //--- return(false); } } //--- If the time frame of the third screen is used and the indicator handle has been obtained if(Screen03TimeFrame>0 && Screen03IndicatorHandle!=INVALID_HANDLE) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer3,true); //--- Get indicator values if(CopyBuffer(Screen03IndicatorHandle,0,0,NumberOfValues,indicator_buffer3)<NumberOfValues) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer3 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); //--- return(false); } } //--- return(true); }
GetTradingSignal() ve GetSignal() fonksiyonları elimizdeki işe göre değiştirilmelidir. Aşağıda, değerlendirmeniz için bu fonksiyonların kodu yer almaktadır.
//+------------------------------------------------------------------+ //| Determining trading signals | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE GetTradingSignal() { //--- If there is no position if(!pos.exists) { //--- A Sell signal if(GetSignal()==ORDER_TYPE_SELL) return(ORDER_TYPE_SELL); //--- A Buy signal if(GetSignal()==ORDER_TYPE_BUY) return(ORDER_TYPE_BUY); } //--- If the position exists if(pos.exists) { //--- Get the position type GetPositionProperties(P_TYPE); //--- Get the last deal price GetPositionProperties(P_PRICE_LAST_DEAL); //--- A Sell signal if(pos.type==POSITION_TYPE_BUY && GetSignal()==ORDER_TYPE_SELL) return(ORDER_TYPE_SELL); if(pos.type==POSITION_TYPE_SELL && GetSignal()==ORDER_TYPE_SELL && close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_SELL); //--- A Buy signal if(pos.type==POSITION_TYPE_SELL && GetSignal()==ORDER_TYPE_BUY) return(ORDER_TYPE_BUY); if(pos.type==POSITION_TYPE_BUY && GetSignal()==ORDER_TYPE_BUY && close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_BUY); } //--- No signal return(WRONG_VALUE); }
GetSignal() fonksiyonu, tıpkı minimum zaman aralığını belirlemede olduğu gibi, pozisyon açma koşullarıyla ilgili tüm olası harici parametre varyantlarını değerlendirir. Fonksiyon kodu aşağıda verilmektedir:
//+------------------------------------------------------------------+ //| Checking the condition and returning a signal | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE GetSignal() { //--- A SELL SIGNAL: the current value of the indicators on completed bars is lower than on the previous bars //--- Conditions for a single time frame if(Screen01IndicatorPeriod>0 && Screen02IndicatorPeriod<=0 && Screen03IndicatorPeriod<=0) { if(indicator_buffer1[1]<indicator_buffer1[2]) return(ORDER_TYPE_SELL); } if(Screen01IndicatorPeriod<=0 && Screen02IndicatorPeriod>0 && Screen03IndicatorPeriod<=0) { if(indicator_buffer2[1]<indicator_buffer2[2]) return(ORDER_TYPE_SELL); } //--- if(Screen01IndicatorPeriod<=0 && Screen02IndicatorPeriod<=0 && Screen03IndicatorPeriod>0) { if(indicator_buffer3[1]<indicator_buffer3[2]) return(ORDER_TYPE_SELL); } //--- Conditions for two time frames if(Screen01IndicatorPeriod>0 && Screen02IndicatorPeriod>0 && Screen03IndicatorPeriod<=0) { if(indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer2[1]<indicator_buffer2[2]) return(ORDER_TYPE_SELL); } if(Screen01IndicatorPeriod<=0 && Screen02IndicatorPeriod>0 && Screen03IndicatorPeriod>0) { if(indicator_buffer2[1]<indicator_buffer2[2] && indicator_buffer3[1]<indicator_buffer3[2]) return(ORDER_TYPE_SELL); } if(Screen01IndicatorPeriod>0 && Screen02IndicatorPeriod<=0 && Screen03IndicatorPeriod>0) { if(indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer3[1]<indicator_buffer3[2]) return(ORDER_TYPE_SELL); } //--- Conditions for three time frames if(Screen01IndicatorPeriod>0 && Screen02IndicatorPeriod>0 && Screen03IndicatorPeriod>0) { if(indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer2[1]<indicator_buffer2[2] && indicator_buffer3[1]<indicator_buffer3[2] ) return(ORDER_TYPE_SELL); } //--- A BUY SIGNAL: the current value of the indicators on completed bars is higher than on the previous bars //--- Conditions for a single time frame if(Screen01IndicatorPeriod>0 && Screen02IndicatorPeriod<=0 && Screen03IndicatorPeriod<=0) { if(indicator_buffer1[1]>indicator_buffer1[2]) return(ORDER_TYPE_BUY); } if(Screen01IndicatorPeriod<=0 && Screen02IndicatorPeriod>0 && Screen03IndicatorPeriod<=0) { if(indicator_buffer2[1]>indicator_buffer2[2]) return(ORDER_TYPE_BUY); } if(Screen01IndicatorPeriod<=0 && Screen02IndicatorPeriod<=0 && Screen03IndicatorPeriod>0) { if(indicator_buffer3[1]>indicator_buffer3[2]) return(ORDER_TYPE_BUY); } //--- Conditions for two time frames if(Screen01IndicatorPeriod>0 && Screen02IndicatorPeriod>0 && Screen03IndicatorPeriod<=0) { if(indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer2[1]>indicator_buffer2[2]) return(ORDER_TYPE_BUY); } if(Screen01IndicatorPeriod<=0 && Screen02IndicatorPeriod>0 && Screen03IndicatorPeriod>0) { if(indicator_buffer2[1]>indicator_buffer2[2] && indicator_buffer3[1]>indicator_buffer3[2]) return(ORDER_TYPE_BUY); } if(Screen01IndicatorPeriod>0 && Screen02IndicatorPeriod<=0 && Screen03IndicatorPeriod>0) { if(indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer3[1]>indicator_buffer3[2]) return(ORDER_TYPE_BUY); } //--- Conditions for three time frames if(Screen01IndicatorPeriod>0 && Screen02IndicatorPeriod>0 && Screen03IndicatorPeriod>0) { if(indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer2[1]>indicator_buffer2[2] && indicator_buffer3[1]>indicator_buffer3[2] ) return(ORDER_TYPE_BUY); } //--- No signal return(WRONG_VALUE); }
Şimdi sadece OnInit() ve OnDeinit() fonksiyonlarında küçük değişiklikler yapmamız gerekiyor. Aşağıdaki kodda vurgulanan değişiklikleri görebilirsiniz:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Determine the minimum time frame for the new bar check MinimumTimeframe=GetMinimumTimeframe(Screen01TimeFrame,Screen01IndicatorPeriod, Screen02TimeFrame,Screen02IndicatorPeriod, Screen03TimeFrame,Screen03IndicatorPeriod); //--- Get indicator handles GetIndicatorHandles(); //--- Initialize the new bar CheckNewBar(); //--- Get the properties GetPositionProperties(P_ALL); //--- Set the info panel SetInfoPanel(); //--- return(0); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Print the deinitialization reason to the journal Print(GetDeinitReasonText(reason)); //--- When deleting from the chart if(reason==REASON_REMOVE) { //--- Delete all objects relating to the info panel from the chart DeleteInfoPanel(); //--- Delete the indicator handles IndicatorRelease(Screen01IndicatorHandle); IndicatorRelease(Screen02IndicatorHandle); IndicatorRelease(Screen03IndicatorHandle); } }
Üçlü Ekran stratejisine dayalı alım satım sistemleri için çerçeve hazır. Bu, göstergeleri değiştirerek veya gerekirse bazı ek koşullar ekleyerek herhangi bir zamanda değiştirilebilir.
Parametreleri Optimize Etme ve Uzman Danışmanı Test Etme
Parametre optimizasyonuna geçelim ve sonuçları kontrol edelim. Strateji Test Cihazı aşağıda gösterildiği gibi ayarlanır (üç zaman aralığından en düşük olanı belirttiğinizden emin olun):
Şekil 1. Strateji Test Cihazı ayarları.
Optimizasyon için Uzman Danışman parametreleri aşağıda gösterildiği gibi ayarlanmıştır. Optimizasyon için zaman aralıkları ayarlanabilir, ancak ben bunları manuel olarak ayarlamayı tercih ediyorum.
Şekil 2. Uzman Danışmanın Ayarları.
Optimizasyon, çift çekirdekli bir işlemcide yaklaşık 30 dakikada tamamlanmıştır. Optimizasyon Grafiği aşağıda verilmektedir:
Şekil 3. Optimizasyon Grafiği.
Maksimum denge testi sonuçları, maksimum geri kazanım faktörü test sonuçlarından daha az düşüş gösterir, bu nedenle maksimum denge testi sonuçları gösterim amacıyla kullanılır:
Şekil 4. Maksimum denge test sonuçları.
Şekil 5. Maksimum denge testi grafiği.
Sonuç
Makale, ana fonksiyonlar mevcutsa Uzman Danışmanın oldukça hızlı bir şekilde değiştirilebileceğini göstermiştir. Sadece sinyal bloğunu ve göstergeleri değiştirerek yeni bir alım satım sistemine sahip olabilirsiniz. Makaleye ek olarak, daha fazla bireysel çalışmanız için yukarıda açıklanan Uzman Danışmanın kaynak kodlarını ve ayrıca giriş parametresi ayarlarını içeren bir set dosyasını içeren indirilebilir bir arşiv bulunmaktadır.
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/647





- Ücretsiz alım-satım uygulamaları
- İşlem kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Gizlilik ve Veri Koruma Politikasını ve MQL5.com Kullanım Şartlarını kabul edersiniz