MQL5 Tarif Defteri: Çok Para Birimli Uzman Danışman - Basit, Sade ve Hızlı Yaklaşım
Giriş
Bu makale, çok para birimli bir Uzman Danışman için uygun olan basit bir yaklaşımın uygulamasını açıklayacaktır. Bu, aynı koşullar altında, ancak her bir sembol için farklı parametreler ile test/alım satım için Uzman Danışmanı kurabileceğiniz anlamına gelir. Örnek olarak, gerekirse kodda küçük değişiklikler yaparak ek semboller eklenebilecek şekilde iki sembol için bir model oluşturacağız.
Çok para birimli bir model MQL5'te birçok şekilde uygulanabilir:
Bir Uzman Danışmanın zamana göre yönlendirildiği ve OnTimer() fonksiyonunda belirtilen zaman aralıklarında daha doğru kontroller gerçekleştirebildiği bir model kullanabiliriz.
Alternatif olarak, serinin önceki makalelerinde tanıtılan Uzman Danışmanların tamamında olduğu gibi OnTick() fonksiyonunda kontrol gerçekleştirilebilir, bu durumda Uzman Danışman üzerinde çalıştığı mevcut sembol için tiklere bağlı olacaktır. Bu nedenle, başka bir sembol üzerinde tamamlanmış bir çubuk varsa ve mevcut sembol için henüz bir tik işareti yoksa, Uzman Danışman yalnızca mevcut sembol için yeni bir tik işareti olduğunda bir kontrol gerçekleştirecektir.
Ancak yazarı Konstantin Gruzdev (Lizar) tarafından öne sürülen ilginç bir seçenek daha vardır. OnChartEvent() fonksiyonundan yararlanan bir olay modeli kullanılır; bir Uzman Danışman, test/alım satıma katılan sembol grafiklerinde yer alan gösterge aracıları tarafından çoğaltılan olayları alır. Gösterge aracıları, yeni çubuk üretebilir ve bağlı oldukları sembollerin olaylarını işaretleyebilir. Bu gösterge türü (EventsSpy.mq5) makalenin sonundan indirilebilir. Uzman Danışmanın çalışması için buna ihtiyacımız olacak.
Uzman Danışman Geliştirme
"MQL5 Tarif Defteri: Uzman Danışmanlarda Alım Satım Koşullarını Belirlemek için Göstergeleri Kullanma" makalesinde içerilen Uzman Danışman bir şablon görevi görecektir. Bilgi paneliyle ilgili her şeyi zaten sildim ve ayrıca aşağıdaki başlığa sahip önceki makalede uygulanan pozisyon açma koşullarını basitleştirdim: "MQL5 Tarif Defteri: Üçlü Ekran Stratejisine Dayalı Bir Alım Satım Sistemi Çerçevesi Geliştirme". İki sembol için bir Uzman Danışman oluşturmayı amaçladığımızdan, bunların her birinin kendi harici parametre setine ihtiyacı olacaktır:
//--- External parameters of the Expert Advisor sinput long MagicNumber = 777; // Magic number sinput int Deviation = 10; // Slippage //--- sinput string delimeter_00=""; // -------------------------------- sinput string Symbol_01 = "EURUSD"; // Symbol 1 input int IndicatorPeriod_01 = 5; // | Indicator period input double TakeProfit_01 = 100; // | Take Profit input double StopLoss_01 = 50; // | Stop Loss input double TrailingStop_01 = 10; // | Trailing Stop input bool Reverse_01 = true; // | Position reversal input double Lot_01 = 0.1; // | Lot input double VolumeIncrease_01 = 0.1; // | Position volume increase input double VolumeIncreaseStep_01 = 10; // | Volume increase step //--- sinput string delimeter_01=""; // -------------------------------- sinput string Symbol_02 = "NZDUSD"; // Symbol 2 input int IndicatorPeriod_02 = 5; // | Indicator period input double TakeProfit_02 = 100; // | Take Profit input double StopLoss_02 = 50; // | Stop Loss input double TrailingStop_02 = 10; // | Trailing Stop input bool Reverse_02 = true; // | Position reversal input double Lot_02 = 0.1; // | Lot input double VolumeIncrease_02 = 0.1; // | Position volume increase input double VolumeIncreaseStep_02 = 10; // | Volume increase step
Harici parametreler, boyutları kullanılan sembollerin sayısına bağlı olacak dizilere yerleştirilecektir. Uzman Danışmanda kullanılan sembol sayısı, dosyanın başında oluşturmamız gereken NUMBER_OF_SYMBOLS sabitinin değeri ile belirlenecektir:
//--- Number of traded symbols #define NUMBER_OF_SYMBOLS 2 //--- Name of the Expert Advisor #define EXPERT_NAME MQL5InfoString(MQL5_PROGRAM_NAME)
Harici parametreleri saklamak için gerekli olacak dizileri oluşturalım:
//--- Arrays for storing external parameters string Symbols[NUMBER_OF_SYMBOLS]; // Symbol int IndicatorPeriod[NUMBER_OF_SYMBOLS]; // Indicator period double TakeProfit[NUMBER_OF_SYMBOLS]; // Take Profit double StopLoss[NUMBER_OF_SYMBOLS]; // Stop Loss double TrailingStop[NUMBER_OF_SYMBOLS]; // Trailing Stop bool Reverse[NUMBER_OF_SYMBOLS]; // Position reversal double Lot[NUMBER_OF_SYMBOLS]; // Lot double VolumeIncrease[NUMBER_OF_SYMBOLS]; // Position volume increase double VolumeIncreaseStep[NUMBER_OF_SYMBOLS]; // Volume increase step
Dizi başlatma fonksiyonları InitArrays.mqh içerik dosyasına yerleştirilecektir. Symbols[] dizisini başlatmak için GetSymbol() fonksiyonunu oluşturacağız. Sembol adını harici parametrelerden alacak ve bu sembol sunucudaki sembol listesinde varsa Piyasa İzleme penceresinde seçilecektir. Veya gerekli sembol sunucuda bulunamazsa, fonksiyon boş bir dize döndürecek ve Uzman Danışmanlar Günlüğü buna göre güncellenecektir.
Aşağıda GetSymbol() fonksiyon kodu yer almaktadır:
//+------------------------------------------------------------------+ //| Adding the specified symbol to the Market Watch window | //+------------------------------------------------------------------+ string GetSymbolByName(string symbol) { string symbol_name=""; // Symbol name on the server //--- If an empty string is passed, return the empty string if(symbol=="") return(""); //--- Iterate over the list of all symbols on the server for(int s=0; s<SymbolsTotal(false); s++) { //--- Get the symbol name symbol_name=SymbolName(s,false); //--- If the required symbol is available on the server if(symbol==symbol_name) { //--- Select it in the Market Watch window SymbolSelect(symbol,true); //--- Return the symbol name return(symbol); } } //--- If the required symbol cannot be found, return the empty string Print("The "+symbol+" symbol could not be found on the server!"); return(""); }
Symbols[] dizisi GetSymbols() fonksiyonunda başlatılacaktır:
//+------------------------------------------------------------------+ //| Filling the array of symbols | //+------------------------------------------------------------------+ void GetSymbols() { Symbols[0]=GetSymbolByName(Symbol_01); Symbols[1]=GetSymbolByName(Symbol_02); }
Ek olarak, bunu, belirli bir sembolün harici parametrelerindeki boş bir değerin, ilgili bloğun test/alım satıma dahil olmayacağını belirtecek şekilde uygulayacağız. Bu, her bir sembol için parametreleri ayrı ayrı optimize ederken geri kalanı tamamen dışarıda tutmak için gereklidir.
Diğer tüm harici parametre dizileri aynı şekilde başlatılır. Diğer bir deyişle, her dizi için ayrı bir fonksiyon oluşturmamız gerekir. Tüm bu fonksiyonların kodları aşağıda verilmektedir:
//+------------------------------------------------------------------+ //| Filling the indicator period array | //+------------------------------------------------------------------+ void GetIndicatorPeriod() { IndicatorPeriod[0]=IndicatorPeriod_01; IndicatorPeriod[1]=IndicatorPeriod_02; } //+------------------------------------------------------------------+ //| Filling the Take Profit array | //+------------------------------------------------------------------+ void GetTakeProfit() { TakeProfit[0]=TakeProfit_01; TakeProfit[1]=TakeProfit_02; } //+------------------------------------------------------------------+ //| Filling the Stop Loss array | //+------------------------------------------------------------------+ void GetStopLoss() { StopLoss[0]=StopLoss_01; StopLoss[1]=StopLoss_02; } //+------------------------------------------------------------------+ //| Filling the Trailing Stop array | //+------------------------------------------------------------------+ void GetTrailingStop() { TrailingStop[0]=TrailingStop_01; TrailingStop[1]=TrailingStop_02; } //+------------------------------------------------------------------+ //| Filling the Reverse array | //+------------------------------------------------------------------+ void GetReverse() { Reverse[0]=Reverse_01; Reverse[1]=Reverse_02; } //+------------------------------------------------------------------+ //| Filling the Lot array | //+------------------------------------------------------------------+ void GetLot() { Lot[0]=Lot_01; Lot[1]=Lot_02; } //+------------------------------------------------------------------+ //| Filling the VolumeIncrease array | //+------------------------------------------------------------------+ void GetVolumeIncrease() { VolumeIncrease[0]=VolumeIncrease_01; VolumeIncrease[1]=VolumeIncrease_02; } //+------------------------------------------------------------------+ //| Filling the VolumeIncreaseStep array | //+------------------------------------------------------------------+ void GetVolumeIncreaseStep() { VolumeIncreaseStep[0]=VolumeIncreaseStep_01; VolumeIncreaseStep[1]=VolumeIncreaseStep_02; }
Şimdi tüm harici parametre dizilerini tek seferde uygun şekilde başlatmamıza yardımcı olacak bir fonksiyon oluşturalım: InitializeInputParameters() fonksiyonu:
//+------------------------------------------------------------------+ //| Initializing external parameter arrays | //+------------------------------------------------------------------+ void InitializeInputParameters() { GetSymbols(); GetIndicatorPeriod(); GetTakeProfit(); GetStopLoss(); GetTrailingStop(); GetReverse(); GetLot(); GetVolumeIncrease(); GetVolumeIncreaseStep(); }
Harici parametre dizilerinin başlatılmasının ardından ana kısma geçebiliriz. Gösterge işleyicilerinin, bunların değerlerinin ve fiyat bilgilerinin elde edilmesi, yeni çubuğun kontrol edilmesi vb. gibi bazı prosedürler her bir sembol için döngüler halinde ardışık olarak gerçekleştirilecektir. Bu nedenle harici parametre değerleri dizilerde düzenlenmiştir. Böylece her şey döngülerde aşağıdaki gibi yapılacaktır:
//--- Iterate over all symbols for(int s=0; s<NUMBER_OF_SYMBOLS; s++) { //--- If trading for this symbol is allowed if(Symbols[s]!="") { //--- The rest of the code } }
Ancak mevcut fonksiyonları değiştirmeye ve yenilerini oluşturmaya başlamadan önce, bu modelde gerekli olacak dizileri de oluşturalım.
Gösterge işleyiciler için iki diziye ihtiyacımız olacak:
//--- Array of indicator agent handles int spy_indicator_handles[NUMBER_OF_SYMBOLS]; //--- Array of signal indicator handles int signal_indicator_handles[NUMBER_OF_SYMBOLS];
Bu iki dizi ilk olarak geçersiz değerlerle başlatılacaktır:
//+------------------------------------------------------------------+ //| Initializing arrays of indicator handles | //+------------------------------------------------------------------+ void InitializeArrayHandles() { ArrayInitialize(spy_indicator_handles,INVALID_HANDLE); ArrayInitialize(signal_indicator_handles,INVALID_HANDLE); }
Fiyat verilerinin ve gösterge değerlerinin dizilerine yapılar kullanılarak erişilecektir:
//--- Data arrays for checking trading conditions struct PriceData { double value[]; }; PriceData open[NUMBER_OF_SYMBOLS]; // Opening price of the bar PriceData high[NUMBER_OF_SYMBOLS]; // High price of the bar PriceData low[NUMBER_OF_SYMBOLS]; // Low price of the bar PriceData close[NUMBER_OF_SYMBOLS]; // Closing price of the bar PriceData indicator[NUMBER_OF_SYMBOLS]; // Array of indicator values
Şimdi, listedeki ilk sembolün son tamamlanan çubuğundaki gösterge değerini elde etmemiz gerekiyorsa, şöyle bir şey yazmalısınız:
double indicator_value=indicator[0].value[1];
Daha önce CheckNewBar() fonksiyonunda kullanılan değişkenler yerine de diziler oluşturmamız gerekiyor:
//--- Arrays for getting the opening time of the current bar struct Datetime { datetime time[]; }; Datetime lastbar_time[NUMBER_OF_SYMBOLS]; //--- Array for checking the new bar for each symbol datetime new_bar[NUMBER_OF_SYMBOLS];
İşte dizileri düzenledik. Şimdi yukarıda yapılan değişikliklere göre birçok fonksiyonu değiştirmemiz gerekiyor. GetIndicatorHandles() fonksiyonu ile başlayalım:
//+------------------------------------------------------------------+ //| Getting indicator handles | //+------------------------------------------------------------------+ void GetIndicatorHandles() { //--- Iterate over all symbols for(int s=0; s<NUMBER_OF_SYMBOLS; s++) { //--- If trading for this symbol is allowed if(Symbols[s]!="") { //--- If the handle is yet to be obtained if(signal_indicator_handles[s]==INVALID_HANDLE) { //--- Get the indicator handle signal_indicator_handles[s]=iMA(Symbols[s],_Period,IndicatorPeriod[s],0,MODE_SMA,PRICE_CLOSE); //--- If the indicator handle could not be obtained if(signal_indicator_handles[s]==INVALID_HANDLE) Print("Failed to get the indicator handle for the symbol "+Symbols[s]+"!"); } } } }
Şimdi, test/alım satımda kullanılan sembollerin sayısından bağımsız olarak, fonksiyon kodu aynı kalacaktır.
Benzer şekilde, diğer sembollerden tikleri aktaran gösterge aracılarının işleyicilerini elde etmek için bir başka fonksiyon oluşturacağız:GetSpyHandles(). Ancak bundan önce, Enums.mqh dosyasında bayraklar olarak düzenlenen ENUM_CHART_EVENT_SYMBOL sembolü ile tüm olayların bir başka numaralandırmasını ekleyeceğiz:
//+------------------------------------------------------------------+ //| New bar and tick events from all symbols and time frames | //+------------------------------------------------------------------+ enum ENUM_CHART_EVENT_SYMBOL { CHARTEVENT_NO = 0, // Events are disabled - 0 CHARTEVENT_INIT = 0, // Initialization event - 0 //--- CHARTEVENT_NEWBAR_M1 = 0x00000001, // New bar event on a minute chart (1) CHARTEVENT_NEWBAR_M2 = 0x00000002, // New bar event on a 2-minute chart (2) CHARTEVENT_NEWBAR_M3 = 0x00000004, // New bar event on a 3-minute chart (4) CHARTEVENT_NEWBAR_M4 = 0x00000008, // New bar event on a 4-minute chart (8) //--- CHARTEVENT_NEWBAR_M5 = 0x00000010, // New bar event on a 5-minute chart (16) CHARTEVENT_NEWBAR_M6 = 0x00000020, // New bar event on a 6-minute chart (32) CHARTEVENT_NEWBAR_M10 = 0x00000040, // New bar event on a 10-minute chart (64) CHARTEVENT_NEWBAR_M12 = 0x00000080, // New bar event on a 12-minute chart (128) //--- CHARTEVENT_NEWBAR_M15 = 0x00000100, // New bar event on a 15-minute chart (256) CHARTEVENT_NEWBAR_M20 = 0x00000200, // New bar event on a 20-minute chart (512) CHARTEVENT_NEWBAR_M30 = 0x00000400, // New bar event on a 30-minute chart (1024) CHARTEVENT_NEWBAR_H1 = 0x00000800, // New bar event on an hour chart (2048) //--- CHARTEVENT_NEWBAR_H2 = 0x00001000, // New bar event on a 2-hour chart (4096) CHARTEVENT_NEWBAR_H3 = 0x00002000, // New bar event on a 3-hour chart (8192) CHARTEVENT_NEWBAR_H4 = 0x00004000, // New bar event on a 4-hour chart (16384) CHARTEVENT_NEWBAR_H6 = 0x00008000, // New bar event on a 6-hour chart (32768) //--- CHARTEVENT_NEWBAR_H8 = 0x00010000, // New bar event on a 8-hour chart (65536) CHARTEVENT_NEWBAR_H12 = 0x00020000, // New bar event on a 12-hour chart (131072) CHARTEVENT_NEWBAR_D1 = 0x00040000, // New bar event on a daily chart (262144) CHARTEVENT_NEWBAR_W1 = 0x00080000, // New bar event on a weekly chart (524288) //--- CHARTEVENT_NEWBAR_MN1 = 0x00100000, // New bar event on a monthly chart (1048576) CHARTEVENT_TICK = 0x00200000, // New tick event (2097152) //--- CHARTEVENT_ALL = 0xFFFFFFFF // All events are enabled (-1) };
Bu numaralandırma, aşağıda kodu sağlanan GetSpyHandles() fonksiyonunda özel gösterge EventsSpy.mq5 (dosya makaleye eklenmiştir) ile çalışmak için gereklidir:
//+------------------------------------------------------------------+ //| Getting agent handles by the specified symbols | //+------------------------------------------------------------------+ void GetSpyHandles() { //--- Iterate over all symbols for(int s=0; s<NUMBER_OF_SYMBOLS; s++) { //--- If trading for this symbol is allowed if(Symbols[s]!="") { //--- If the handle is yet to be obtained if(spy_indicator_handles[s]==INVALID_HANDLE) { //--- Get the indicator handle spy_indicator_handles[s]=iCustom(Symbols[s],_Period,"EventsSpy.ex5",ChartID(),0,CHARTEVENT_TICK); //--- If the indicator handle could not be obtained if(spy_indicator_handles[s]==INVALID_HANDLE) Print("Failed to install the agent on "+Symbols[s]+""); } } } }
Lütfen iCustom() fonksiyonundaki son parametreye dikkat edin: bu durumda CHARTEVENT_TICK tanımlayıcısı tik olaylarını elde etmek için kullanılmıştır. Ancak gerekirse, yeni çubuk olaylarını alacak şekilde değiştirilebilir. Örneğin aşağıda gösterildiği gibi bir çizgi kullanırsanız Uzman Danışman dakikalık (M1) ve saatlik (H1) zaman aralıklarında yeni çubuk olaylarını alacaktır:
handle_event_indicator[s]=iCustom(Symbols[s],_Period,"EventsSpy.ex5",ChartID(),0,CHARTEVENT_NEWBAR_M1|CHARTEVENT_NEWBAR_H1);
Tüm olayları (tüm zaman aralıklarında tik ve çubuk olayları) elde etmek için CHARTEVENT_ALL tanımlayıcısını belirtmelisiniz.
Tüm diziler, OnInit() fonksiyonunda başlatılır:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ void OnInit() { //--- Initialization of arrays of external parameters InitializeInputParameters(); //--- Initialization of arrays of indicator handles InitializeArrayHandles(); //--- Get agent handles GetSpyHandles(); //--- Get indicator handles GetIndicatorHandles(); //--- Initialize the new bar InitializeArrayNewBar(); }
Makalenin daha başında bahsedildiği gibi gösterge aracılarından olaylar OnChartEvent() fonksiyonunda alınır. Aşağıda, bu fonksiyonda kullanılacak kod yer almaktadır:
//+------------------------------------------------------------------+ //| Chart events handler | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // Event identifier const long &lparam, // Long type event parameter const double &dparam, // Double type event parameter const string &sparam) // String type event parameter { //--- If this is a custom event if(id>=CHARTEVENT_CUSTOM) { //--- Exit if trading is not allowed if(CheckTradingPermission()>0) return; //--- If there was a tick event if(lparam==CHARTEVENT_TICK) { //--- Check signals and trade on them CheckSignalsAndTrade(); return; } } }
CheckSignalAndTrade() fonksiyonunda (yukarıdaki kodda vurgulanmış çizgi), tüm sembollerin daha önce OnTick() fonksiyonu uygulandığı gibi değişimli olarak yeni çubuk olayı ve alım satım sinyalleri için kontrol edildiği bir döngümüz olacak:
//+------------------------------------------------------------------+ //| Checking signals and trading based on the new bar event | //+------------------------------------------------------------------+ void CheckSignalsAndTrade() { //--- Iterate over all specified symbols for(int s=0; s<NUMBER_OF_SYMBOLS; s++) { //--- If trading for this symbol is allowed if(Symbols[s]!="") { //--- If the bar is not new, proceed to the next symbol if(!CheckNewBar(s)) continue; //--- If there is a new bar else { //--- Get indicator data. If there is no data, proceed to the next symbol if(!GetIndicatorsData(s)) continue; //--- Get bar data GetBarsData(s); //--- Check the conditions and trade TradingBlock(s); //--- Trailing Stop ModifyTrailingStop(s); } } } }
Sembol ve gösterge verilerinin yanı sıra harici parametreleri kullanan tüm fonksiyonların, yukarıdaki tüm değişikliklere göre değiştirilmesi gerekir. Bunun için, ilk parametre olarak sembol sayısını eklemeli ve fonksiyondaki tüm değişkenleri ve dizileri yukarıda açıklanan yeni diziler ile değiştirmeliyiz.
Gösterim amacıyla CheckNewBar(), TradingBlock() ve OpenPosition() fonksiyonlarının gözden geçirilmiş kodları aşağıda verilmiştir.
CheckNewBar() fonksiyon kodu:
//+------------------------------------------------------------------+ //| Checking for the new bar | //+------------------------------------------------------------------+ bool CheckNewBar(int number_symbol) { //--- Get the opening time of the current bar // If an error occurred when getting the time, print the relevant message if(CopyTime(Symbols[number_symbol],Period(),0,1,lastbar_time[number_symbol].time)==-1) Print(__FUNCTION__,": Error copying the opening time of the bar: "+IntegerToString(GetLastError())); //--- If this is a first function call if(new_bar[number_symbol]==NULL) { //--- Set the time new_bar[number_symbol]=lastbar_time[number_symbol].time[0]; Print(__FUNCTION__,": Initialization ["+Symbols[number_symbol]+"][TF: "+TimeframeToString(Period())+"][" +TimeToString(lastbar_time[number_symbol].time[0],TIME_DATE|TIME_MINUTES|TIME_SECONDS)+"]"); return(false); } //--- If the time is different if(new_bar[number_symbol]!=lastbar_time[number_symbol].time[0]) { //--- Set the time and exit new_bar[number_symbol]=lastbar_time[number_symbol].time[0]; return(true); } //--- If we have reached this line, then the bar is not new, so return false return(false); }
TradingBlock() fonksiyon kodu:
//+------------------------------------------------------------------+ //| Trading block | //+------------------------------------------------------------------+ void TradingBlock(int symbol_number) { ENUM_ORDER_TYPE signal=WRONG_VALUE; // Variable for getting a signal string comment="hello :)"; // Position comment double tp=0.0; // Take Profit double sl=0.0; // Stop Loss double lot=0.0; // Volume for position calculation in case of position reversal double position_open_price=0.0; // Position opening price ENUM_ORDER_TYPE order_type=WRONG_VALUE; // Order type for opening a position ENUM_POSITION_TYPE opposite_position_type=WRONG_VALUE; // Opposite position type //--- Find out if there is a position pos.exists=PositionSelect(Symbols[symbol_number]); //--- Get the signal signal=GetTradingSignal(symbol_number); //--- If there is no signal, exit if(signal==WRONG_VALUE) return; //--- Get symbol properties GetSymbolProperties(symbol_number,S_ALL); //--- Determine values for trade variables switch(signal) { //--- Assign values to variables for a BUY case ORDER_TYPE_BUY : position_open_price=symb.ask; order_type=ORDER_TYPE_BUY; opposite_position_type=POSITION_TYPE_SELL; break; //--- Assign values to variables for a SELL case ORDER_TYPE_SELL : position_open_price=symb.bid; order_type=ORDER_TYPE_SELL; opposite_position_type=POSITION_TYPE_BUY; break; } //--- Get the Take Profit and Stop Loss levels sl=CalculateStopLoss(symbol_number,order_type); tp=CalculateTakeProfit(symbol_number,order_type); //--- If there is no position if(!pos.exists) { //--- Adjust the volume lot=CalculateLot(symbol_number,Lot[symbol_number]); //--- Open a position OpenPosition(symbol_number,lot,order_type,position_open_price,sl,tp,comment); } //--- If the position exists else { //--- Get the position type GetPositionProperties(symbol_number,P_TYPE); //--- If the position is opposite to the signal and the position reversal is enabled if(pos.type==opposite_position_type && Reverse[symbol_number]) { //--- Get the position volume GetPositionProperties(symbol_number,P_VOLUME); //--- Adjust the volume lot=pos.volume+CalculateLot(symbol_number,Lot[symbol_number]); //--- Reverse the position OpenPosition(symbol_number,lot,order_type,position_open_price,sl,tp,comment); return; } //--- If the signal is in the direction of the position and the volume increase is enabled, increase the position volume if(!(pos.type==opposite_position_type) && VolumeIncrease[symbol_number]>0) { //--- Get the Stop Loss of the current position GetPositionProperties(symbol_number,P_SL); //--- Get the Take Profit of the current position GetPositionProperties(symbol_number,P_TP); //--- Adjust the volume lot=CalculateLot(symbol_number,VolumeIncrease[symbol_number]); //--- Increase the position volume OpenPosition(symbol_number,lot,order_type,position_open_price,pos.sl,pos.tp,comment); return; } } }
OpenPosition() fonksiyon kodu:
//+------------------------------------------------------------------+ //| Opening a position | //+------------------------------------------------------------------+ void OpenPosition(int symbol_number, double lot, ENUM_ORDER_TYPE order_type, double price, double sl, double tp, string comment) { //--- Set the magic number in the trading structure trade.SetExpertMagicNumber(MagicNumber); //--- Set the slippage in points trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); //--- Instant Execution and Market Execution mode // *** Starting with build 803, Stop Loss and Take Profit *** // *** can be set upon opening a position in the SYMBOL_TRADE_EXECUTION_MARKET mode *** if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT || symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET) { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(Symbols[symbol_number],order_type,lot,price,sl,tp,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } }
Bu şekilde, her bir fonksiyon artık sembol numarasını (symbol_number) alır. Lütfen Yapı 803'te uygulanan değişikliğe dikkat edin:
Diğer fonksiyonların gözden geçirilmiş kodları ekteki dosyalarda bulunabilir. Şimdi tek yapmamız gereken parametreleri optimize etmek ve test yapmak.
Parametreleri Optimize Etme ve Uzman Danışmanı Test Etme
İlk olarak birinci sembol ve ardından ikinci sembol için parametreleri optimize edeceğiz. EURUSD ile başlayalım.
Aşağıda Strateji Test Cihazının ayarları yer almaktadır:
Şekil 1. Strateji Test Cihazı ayarları.
Uzman Danışmanın ayarlarının aşağıda gösterildiği gibi yapılması gerekmektedir (kolaylık olması açısından her bir sembol için ayarları içeren .set dosyaları makaleye eklenmiştir). Belirli bir sembolü optimizasyondan çıkarmak için sembol adı parametre alanını boş bırakmanız yeterlidir. Her sembol için ayrı ayrı gerçekleştirilen parametrelerin optimizasyonu optimizasyon sürecini de hızlandıracaktır.
Şekil 2. Parametre optimizasyonu için Uzman Danışman ayarları: EURUSD.
Optimizasyon, çift çekirdekli bir işlemcide yaklaşık bir saat sürecektir. Maksimum kurtarma faktörü test sonuçları aşağıda gösterildiği gibidir:
Şekil 3. EURUSD için maksimum kurtarma faktörü test sonuçları.
Şimdi NZDUSD'yi ikinci sembol olarak ayarlayalım. Optimizasyon için, ilk parametre bloğunun sembol adını içeren satırı boş bırakın.
NZDUSD için sonuçlar aşağıdaki şekilde görünmektedir:
Şekil 4. NZDUSD için maksimum kurtarma faktörü test sonuçları.
Şimdi iki sembolü birlikte test edebiliriz. Strateji Test Cihazı ayarlarında, sonuçlar aynı olacağından, Uzman Danışmanın başlatıldığı herhangi bir sembolü ayarlayabilirsiniz. Hatta bu, alım satım/teste dahil olmayan bir sembol bile olabilir.
Aşağıda birlikte test edilen iki sembolün sonuçları verilmiştir:
Şekil 5. İki sembol için test sonuçları: EURUSD ve NZDUSD.
Sonuç
Neredeyse hepsi bu. Kaynak kodları aşağıya eklenmiştir ve yukarıdakilerin daha ayrıntılı bir incelemesi için indirilebilir. Alıştırma için, bir veya daha fazla sembol seçmeyi veya diğer göstergeleri kullanarak pozisyon açma koşullarını değiştirmeyi deneyin.
Dosyaları arşivden çıkardıktan sonra, MultiSymbolExpert klasörünü MetaTrader 5\MQL5\Experts dizisine yerleştirin. Ayrıca EventsSpy.mq5 göstergesi MetaTrader 5\MQL5\Indicators dizinine yerleştirilmelidir.
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/648
- Ü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