MQL5 Tarif Defteri: Aşırı Öğrenme Etkisini Azaltma ve Kotasyon Eksikliğini Ele Alma
Giriş
Pek çok yatırımcının, alım satım sistemleri için en uygun parametrelere dair defalarca kafasının karıştığına inanıyorum. Gerçekten de, tek başına bir alım satım algoritması yeterli değildir. Bunun nasıl başka şekilde kullanılabileceğini görmek gerekir. Hangi alım satım stratejisini kullanırsanız kullanın, ister basit ister karmaşık olsun, ister tek ister birden fazla enstrümanla olsun, gelecekte kâr sağlamak için hangi parametreleri seçeceğiniz sorusundan kaçamazsınız.
Alım satım sistemlerini, optimizasyon döneminde (geriye dönük test) ve sonraki dönemde (ileriye dönük test) iyi sonuçlar gösteren parametreler ile kontrol etme eğilimindeyiz. İleriye dönük testler aslında çok da gerekli değildir. İlgili sonuçlar geçmiş veriler kullanılarak elde edilebilir.
Bu yöntem, kesin bir cevap verilemeyen devasa bir soruya yol açar: Bir alım satım sistemini optimize etmek için ne kadar geçmiş veri kullanılmalıdır? Mesele şu ki, birçok seçenek var. Her şey, yararlanmayı umduğunuz fiyat dalgalanmalarının aralığına bağlı.
Optimizasyon için gereken geçmiş miktarına geri dönersek, mevcut verilerin saat içi alım satım için yeterli olabileceği sonucuna varıyoruz. Bu, daha uzun zaman aralıkları için her zaman doğru değildir. Tutarlı bir modelin tekrar sayısı ne kadar fazla olursa, yani ne kadar çok alım satımınız olursa, gelecekte görmeyi bekleyebileceğimiz test edilmiş alım satım sisteminin performansı o kadar doğru olur.
Ya belirli bir enstrümanın fiyat verileri yeterli sayıda tekrar elde etmek ve daha emin olabilmek için yeterli değilse? Cevap: Mevcut tüm cihazlardan gelen verileri kullanın.
NeuroShell DayTrader Professional'dan Örnek
MetaTrader 5'te programlamaya geçmeden önce NeuroShell DayTrader Professional'daki bir örneği inceleyelim. Birçok sembol için bir alım satım sisteminin (bir oluşturucu ile derlenmiş) parametrelerini optimize etmek için harika özellikler sunar. Alım satım modülü ayarlarında gerekli parametreleri ayarlayabilir, her bir sembol için parametreleri ayrı ayrı optimize edebilir veya tüm semboller için en uygun parametre setini tek seferde bulabilirsiniz. Bu seçenek Optimizasyon sekmesinde bulunabilir:
Şekil 1. NeuroShell DayTrader Professional'daki alım satım modülündeki Optimizasyon sekmesi
Bizim durumumuzda, sadece iki optimizasyon yönteminin sonuçlarını karşılaştırmamız gerektiğinden herhangi bir basit alım satım sistemi iş görecektir, bu nedenle sistem seçimi şu anda çok az önem taşımaktadır.
NeuroShell DayTrader Professional'da alım satım stratejilerini nasıl derleyebileceğinize dair bilgiyi, blogumun diğer makalelerinde bulabilirsiniz (ilgili bilgiyi bulmak için arama yapabilir veya etiketler kullanabilirsiniz). Ayrıca, NeuroShell DayTrader Professional ile uyumlu biçimde MetaTrader 5'ten kotasyonları bir betik kullanarak nasıl indirebileceğinizi açıklayan ve gösteren "Diğer Uygulamalar için MetaTrader 5 Kotasyonları Nasıl Hazırlanır?" başlıklı makaleyi okumanızı öneririm.
Bu testi yapmak için 2000 yılından Ocak 2013'e kadar sekiz sembol için günlük çubuklardan elde ettiğim verileri hazırladım:
Şekil 2. NeuroShell DayTrader Professional'da bir test için semboller listesi
Aşağıdaki şekil iki optimizasyon sonucunu göstermektedir. Üst kısım, her sembolün kendi parametrelerini elde ettiği optimizasyonun sonucunu gösterirken alt kısım, parametrelerin tüm semboller için ortak olduğu sonucu gösterir.
Şekil 3. İki parametre optimizasyon modunun sonuçlarının karşılaştırması
Ortak parametreleri gösteren sonuç, parametrelerin her bir sembol için farklı olduğu sonuç kadar iyi görünmüyor. Yine de, alım satım sistemi tüm semboller için aynı parametreler ile çeşitli fiyat davranış modellerinden (volatilite, trend/flat sayısı) geçtiğinden daha fazla güven uyandırıyor.
Aynı konudan devam edersek, mantıksal olarak daha fazla miktarda veri kullanarak optimizasyon lehine başka bir argüman bulabiliriz. Belli bir döviz çiftinin, örneğin EURUSD, fiyat davranışının daha sonrasında (iki, beş veya on yıl içinde) oldukça farklı olması da mümkündür. Örneğin, GBPUSD fiyat trendleri, EURUSD'nin geçmiş fiyat davranışına benzer olacaktır ve bunun tersi de geçerlidir. Buna hazır olmalısınız, çünkü bu herhangi bir enstrüman için geçerlidir.
MetaTrader 5'ten Bir Örnek
Şimdi MetaTrader 5'te hangi parametre optimizasyon modlarının sunulduğunu görelim. Aşağıda, optimizasyon modlarının açılır listesindeki bir ok ile işaretlenmiş Piyasa İzlemede Seçilen Tüm Semboller optimizasyon modunu görebilirsiniz.
Şekil 4. MetaTrader 5 Strateji Test Cihazındaki optimizasyon modları
Bu mod, yalnızca bir EA'yı her bir semboldeki mevcut parametrelerle tek tek test etmenize olanak sağlar. Testte kullanılan semboller, Piyasa İzleme penceresinde halihazırda seçili olan sembollerdir. Diğer bir deyişle, parametre optimizasyonu bu durumda gerçekleştirilmez. Ancak, MetaTrader 5 ve MQL5 bu fikri kendi başınıza uygulamanıza olanak sağlar.
Şimdi, böyle bir EA'nın nasıl uygulanacağını görmemiz gerekiyor. Sembol listesi bir metin dosyasında (*.txt) sağlanacaktır. Ayrıca, birkaç sembol listesi setini saklama imkanını uygulayacağız. Her set, bir bölüm numarası içeren kendi başlığına sahip ayrı bir bölümde yer alacaktır. Sayılar, görsel kontrolü kolaylaştırmak için gereklidir.
Uzman Danışmanın sembol dizisini doldururken doğru veri setini almasına olanak sağlamak için sayının önünde # işaretinin bulunmasının önemli olduğunu unutmayın. Genel olarak başlık herhangi bir sembol içerebilir, ancak her defasında # işareti olmalıdır. Sayı işareti, Uzman Danışmanın bölümleri belirleyeceği/sayacağı başka bir sembol ile değiştirilebilir. Bu durumda, değiştirmenin koda yansıtılması gerekecektir.
Aşağıda, test için üç sembol setini içeren SymbolsList.txt dosyasını görebilirsiniz. Gösterilen bu dosya, yöntemi test ederken daha fazla kullanılacaktır.
Şekil 5. Test için bir metin dosyasında sağlanan birkaç sembol seti
Harici parametrelere, Uzman Danışmanın mevcut testte kullanması gereken sembollerin setini belirtmek için bir başka parametre SectionOfSymbolList ekleyeceğiz. Bu parametre, sembol setini tanımlayan değeri (sıfırdan büyük) alır. Değer mevcut set sayısını aşarsa, Uzman Danışman günlüğe karşılık gelen bir giriş yazar ve test sadece mevcut sembol üzerinde yapılır.
SymbolsList.txt, Metatrader 5\MQL5\Files konumu altında yerel terminal dizininde yer almalıdır. Ortak klasöre de yerleştirilebilir, ancak bu durumda MQL5 Cloud Network içinde parametre optimizasyonu için kullanılabilir olmayacaktır. Ayrıca, test için dosyaya ve ilgili özel göstergelere erişime olanak sağlamak amacıyla, dosyanın başına aşağıdaki satırları yazmamız gerekir:
//--- Allow access to the external file and indicator for optimization in the cloud #property tester_file "SymbolsList.txt" #property tester_indicator "EventsSpy.ex5"
Uzman Danışmanımız, aşağıdaki makalede içerilen hazır, çok para birimli Uzman Danışman temelli olacaktır: "MQL5 Tarif Defteri: Sınırsız Sayıda Parametre ile Çok Para Birimli bir Uzman Danışman Geliştirme" Temeldeki alım satım stratejisi oldukça basittir, ancak yöntemin etkinliğini test etmek yeterli olacaktır. Gereksiz kısımları çıkartıp ihtiyacımız olanları ekleyeceğiz ve mevcut ilgili kodu düzelteceğiz. Uzman Danışmanımızı aşağıdaki serinin önceki makalesinde kapsamlı olarak açıklanan rapor kaydetme özelliği ile kesin olarak geliştireceğiz: "MQL5 Tarif Defteri: Excel'de Her Sembol için İşlemlerin Geçmişini Bir Dosyaya Yazma ve Denge Grafikleri Oluşturma. Değerlendirilen yöntemin etkinliğini değerlendirmek için tüm semboller için denge grafikleri de gerekecektir.
Uzman Danışmanın harici parametrelerinin ayarları aşağıdaki şekilde değiştirilmelidir:
//--- External parameters of the Expert Advisor sinput int SectionOfSymbolList = 1; // Section number in the symbol lists sinput bool UpdateReport = false; // Report update sinput string delimeter_00=""; // -------------------------------- sinput long MagicNumber = 777; // Magic number sinput int Deviation = 10; // Slippage sinput string delimeter_01=""; // -------------------------------- input int IndicatorPeriod = 5; // Indicator period input double TakeProfit = 100; // Take Profit input double StopLoss = 50; // Stop Loss input double TrailingStop = 10; // Trailing Stop input bool Reverse = true; // Position reversal input double Lot = 0.1; // Lot input double VolumeIncrease = 0.1; // Position volume increase input double VolumeIncreaseStep = 10; // Volume increase step
Harici parametrelerle ilişkili tüm diziler, ihtiyaç duyulmayacağından silinmeli ve tüm kod boyunca harici değişkenler ile değiştirilmelidir. Yalnızca, boyutu SymbolsList.txt dosyasındaki setlerden birinden kullanılan sembollerin sayısına bağlı olacak olan dinamik sembol dizisini - InputSymbols [] - bırakmalıyız. Uzman Danışman Strateji Test Cihazı dışında kullanılırsa, bu dizinin boyutu, gerçek zamanlı modda Uzman Danışman yalnızca bir sembol ile çalışacağından 1'e eşit olacaktır.
İlgili değişiklikler, dizi başlatma dosyası InitializeArrays.mqh içinde de yapılmalıdır. Yani, harici değişken dizilerinin başlatılmasından sorumlu tüm fonksiyonlar silinmelidir. InitializeArraySymbols() fonksiyonu şimdi aşağıdaki gibi görünür:
//+------------------------------------------------------------------+ //| Filling the array of symbols | //+------------------------------------------------------------------+ void InitializeArraySymbols() { int strings_count =0; // Number of strings in the symbol file string checked_symbol =""; // To check the accessibility of the symbol on the trade server //--- Test mode message string message_01="<--- All symbol names in the <- SymbolsList.txt -> file are incorrect ... --->\n" "<--- ... or the value of the \"Section of List Symbols\" parameter is greater, " "than the number of file sections! --->\n" "<--- Therefore we will test only the current symbol. --->"; //--- Real-time mode message string message_02="<--- In real-time mode, we only work with the current symbol. --->"; //--- If in real-time mode if(!IsRealtime()) { //--- Get the number of strings from the specified symbol set in the file and fill the temporary array of symbols strings_count=ReadSymbolsFromFile("SymbolsList.txt"); //--- Iterate over all symbols from the specified set for(int s=0; s<strings_count; s++) { //--- If the correct string is returned following the symbol check if((checked_symbol=GetSymbolByName(temporary_symbols[s]))!="") { //--- increase the counter SYMBOLS_COUNT++; //--- set/increase the array size ArrayResize(InputSymbols,SYMBOLS_COUNT); //--- index with the symbol name InputSymbols[SYMBOLS_COUNT-1]=checked_symbol; } } } //--- If all symbol names were not input correctly or if currently working in real-time mode if(SYMBOLS_COUNT==0) { //--- Real-time mode message if(IsRealtime()) Print(message_02); //--- Test mode message if(!IsRealtime()) Print(message_01); //--- We will work with the current symbol only SYMBOLS_COUNT=1; //--- set the array size and ArrayResize(InputSymbols,SYMBOLS_COUNT); //--- index with the current symbol name InputSymbols[0]=_Symbol; } }
ReadSymbolsFromFile() fonksiyon kodu da değiştirilmelidir. Önceden tüm sembol listesini okuyabilirken, şimdi sadece belirtilen sembol setini okumasını istiyoruz. Aşağıda, değiştirilmiş fonksiyon kodu yer almaktadır:
//+------------------------------------------------------------------+ //| Returning the number of strings (symbols) from the specified | //| set in the file and filling the temporary array of symbols | //+------------------------------------------------------------------+ //--- When preparing the file, symbols in the list should be separated with a line break int ReadSymbolsFromFile(string file_name) { ulong offset =0; // Offset for determining the position of the file pointer string delimeter ="#"; // Identifier of the section start string read_line =""; // For the check of the read string int limit_count =0; // Counter limiting the number of the possibly open charts int strings_count =0; // String counter int sections_count =-1; // Section counter //--- Message 01 string message_01="<--- The <- "+file_name+" -> file has not been prepared appropriately! --->\n" "<--- The first string does not contain the section number identifier ("+delimeter+")! --->"; //--- Message 02 string message_02="<--- The <- "+file_name+" -> file has not been prepared appropriately! --->\n" "<--- There is no line break identifier in the last string, --->\n" "<--- so only the current symbol will be involved in testing. --->"; //--- Message 03 string message_03="<--- The <- "+file_name+" -> file could not be found! --->" "<--- Only the current symbol will be involved in testing. --->"; //--- Open the file (get the handle) for reading in the local directory of the terminal int file_handle=FileOpen(file_name,FILE_READ|FILE_ANSI,'\n'); //--- If the file handle has been obtained if(file_handle!=INVALID_HANDLE) { //--- Read until the current position of the file pointer // reaches the end of the file or until the program is deleted while(!FileIsEnding(file_handle) || !IsStopped()) { //--- Read until the end of the string or until the program is deleted while(!FileIsLineEnding(file_handle) || !IsStopped()) { //--- Read the whole string read_line=FileReadString(file_handle); //--- If the section number identifier has been found if(StringFind(read_line,delimeter,0)>-1) //--- Increase the section counter sections_count++; //--- If the section has been read, exit the function if(sections_count>SectionOfSymbolList) { FileClose(file_handle); // Close the file return(strings_count); // Return the number of strings in the file } //--- If this is the first iteration and the first string does not contain the section number identifier if(limit_count==0 && sections_count==-1) { PrepareArrayForOneSymbol(strings_count,message_01); //--- Close the file FileClose(file_handle); //--- Return the number of strings in the file return(strings_count); } //--- Increase the counter limiting the number of the possibly open charts limit_count++; //--- If the limit has been reached if(limit_count>=CHARTS_MAX) { PrepareArrayForOneSymbol(strings_count,message_02); //--- Close the file FileClose(file_handle); //--- Return the number of strings in the file return(strings_count); } //--- Get the position of the pointer offset=FileTell(file_handle); //--- If this is the end of the string if(FileIsLineEnding(file_handle)) { //--- Go to the next string if this is not the end of the file // For this purpose, increase the offset of the file pointer if(!FileIsEnding(file_handle)) offset++; //--- move it to the next string FileSeek(file_handle,offset,SEEK_SET); //--- If we are not in the specified section of the file, exit the loop if(sections_count!=SectionOfSymbolList) break; //--- Otherwise, else { //--- if the string is not empty if(read_line!="") { //--- increase the string counter strings_count++; //--- increase the size of the array of strings, ArrayResize(temporary_symbols,strings_count); //--- write the string to the current index temporary_symbols[strings_count-1]=read_line; } } //--- Exit the loop break; } } //--- If this is the end of the file, terminate the entire loop if(FileIsEnding(file_handle)) break; } //--- Close the file FileClose(file_handle); } else PrepareArrayForOneSymbol(strings_count,message_03); //--- Return the number of strings in the file return(strings_count); }
Yukarıdaki koddaki bazı dizelerin vurgulandığını görebilirsiniz. Bu dizeler, bir hata durumunda bir (mevcut) sembol için bir dizi hazırlayan PrepareArrayForOneSymbol() fonksiyonunu içerir.
//+------------------------------------------------------------------+ //| Preparing an array for one symbol | //+------------------------------------------------------------------+ void PrepareArrayForOneSymbol(int &strings_count,string message) { //--- Print the message to the log Print(message); //--- Array size strings_count=1; //--- Set the size of the array of symbols ArrayResize(temporary_symbols,strings_count); //--- Write the string with the current symbol name to the current index temporary_symbols[0]=_Symbol; }
Artık parametre optimizasyon yöntemini test etmek için her şey hazır. Ancak teste geçmeden önce rapora bir veri serisi daha ekleyelim. Daha önce, rapor dosyası, tüm sembollerin dengelerine ek olarak, yüzde olarak ifade edilen yerel maksimum değerlerden tüm düşüşleri içeriyordu. Artık rapor para cinsinden tüm düşüşleri de kapsayacak. Aynı zamanda, raporun oluşturulduğunu CreateSymbolBalanceReport() fonksiyonunu da değiştireceğiz.
CreateSymbolBalanceReport() fonksiyon kodu aşağıda verilmektedir:
//+------------------------------------------------------------------+ //| Creating test report on deals in .csv format | //+------------------------------------------------------------------+ void CreateSymbolBalanceReport() { int file_handle =INVALID_HANDLE; // File handle string path =""; // File path //--- If an error occurred when creating/getting the folder, exit if((path=CreateInputParametersFolder())=="") return; //--- Create a file to write data in the common folder of the terminal file_handle=FileOpen(path+"\\LastTest.csv",FILE_CSV|FILE_WRITE|FILE_ANSI|FILE_COMMON); //--- If the handle is valid (file created/opened) if(file_handle>0) { int digits =0; // Number of decimal places in the price int deals_total =0; // Number of deals in the specified history ulong ticket =0; // Deal ticket double drawdown_max =0.0; // Drawdown double balance =0.0; // Balance string delimeter =","; // Delimiter string string_to_write =""; // To generate the string for writing static double percent_drawdown =0.0; // Drawdown expressed as percentage static double money_drawdown =0.0; // Drawdown in monetary terms //--- Generate the header string string headers="TIME,SYMBOL,DEAL TYPE,ENTRY TYPE,VOLUME," "PRICE,SWAP($),PROFIT($),DRAWDOWN(%),DRAWDOWN($),BALANCE"; //--- If more than one symbol is involved, modify the header string if(SYMBOLS_COUNT>1) { for(int s=0; s<SYMBOLS_COUNT; s++) StringAdd(headers,","+InputSymbols[s]); } //--- Write the report headers FileWrite(file_handle,headers); //--- Get the complete history HistorySelect(0,TimeCurrent()); //--- Get the number of deals deals_total=HistoryDealsTotal(); //--- Resize the array of balances according to the number of symbols ArrayResize(symbol_balance,SYMBOLS_COUNT); //--- Resize the array of deals for each symbol for(int s=0; s<SYMBOLS_COUNT; s++) ArrayResize(symbol_balance[s].balance,deals_total); //--- Iterate in a loop and write the data for(int i=0; i<deals_total; i++) { //--- Get the deal ticket ticket=HistoryDealGetTicket(i); //--- Get all the deal properties GetHistoryDealProperties(ticket,D_ALL); //--- Get the number of digits in the price digits=(int)SymbolInfoInteger(deal.symbol,SYMBOL_DIGITS); //--- Calculate the overall balance balance+=deal.profit+deal.swap+deal.commission; //--- Calculate the max drawdown from the local maximum TesterDrawdownMaximum(i,balance,percent_drawdown,money_drawdown); //--- Generate a string for writing using concatenation StringConcatenate(string_to_write, deal.time,delimeter, DealSymbolToString(deal.symbol),delimeter, DealTypeToString(deal.type),delimeter, DealEntryToString(deal.entry),delimeter, DealVolumeToString(deal.volume),delimeter, DealPriceToString(deal.price,digits),delimeter, DealSwapToString(deal.swap),delimeter, DealProfitToString(deal.symbol,deal.profit),delimeter, DrawdownToString(percent_drawdown),delimeter, DrawdownToString(money_drawdown),delimeter, DoubleToString(balance,2)); //--- If more than one symbol is involved, write their balance values if(SYMBOLS_COUNT>1) { //--- Iterate over all symbols for(int s=0; s<SYMBOLS_COUNT; s++) { //--- If the symbols are equal and the deal result is non-zero if(deal.symbol==InputSymbols[s] && deal.profit!=0) { //--- Display the deal in the balance for the corresponding symbol // Take into consideration swap and commission symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1]+ deal.profit+ deal.swap+ deal.commission; //--- Add to the string StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2)); } //--- Otherwise write the previous value else { //--- If the deal type is "Balance" (the first deal) if(deal.type==DEAL_TYPE_BALANCE) { //--- the balance is the same for all symbols symbol_balance[s].balance[i]=balance; StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2)); } //--- Otherwise write the previous value to the current index else { symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1]; StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2)); } } } } //--- Write the generated string FileWrite(file_handle,string_to_write); //--- Mandatory zeroing out of the variable for the next string string_to_write=""; } //--- Close the file FileClose(file_handle); } //--- If the file could not be created/opened, print the appropriate message else Print("Error creating the file! Error: "+IntegerToString(GetLastError())+""); }
DrawdownMaximumToString() fonksiyonunda düşüşleri hesaplıyorduk. Bu işlem artık TesterDrawdownMaximum() fonksiyonu ile gerçekleştirilirken düşüş değeri, temel DrawdownToString() fonksiyonu kullanılarak bir dizeye dönüştürülür.
TesterDrawdownMaximum() fonksiyon kodu aşağıdaki gibidir:
//+------------------------------------------------------------------+ //| Returning the max drawdown from the local maximum | //+------------------------------------------------------------------+ void TesterDrawdownMaximum(int deal_number, double balance, double &percent_drawdown, double &money_drawdown) { ulong ticket =0; // Deal ticket string str =""; // The string to be displayed in the report //--- To calculate the local maximum and drawdown static double max =0.0; static double min =0.0; //--- If this is the first deal if(deal_number==0) { //--- There is no drawdown yet percent_drawdown =0.0; money_drawdown =0.0; //--- Set the initial point as the local maximum max=balance; min=balance; } else { //--- If the current balance is greater than in the memory, then... if(balance>max) { //--- Calculate the drawdown using the previous values: // in monetary terms money_drawdown=max-min; // expressed as percentage percent_drawdown=100-((min/max)*100); //--- Update the local maximum max=balance; min=balance; } //--- Otherwise else { //--- Return zero value of the drawdown money_drawdown=0.0; percent_drawdown=0.0; //--- Update the minimum min=fmin(min,balance); //--- If the deal ticket by its position in the list has been obtained, then... if((ticket=HistoryDealGetTicket(deal_number))>0) { //--- ...get the deal comment GetHistoryDealProperties(ticket,D_COMMENT); //--- Flag of the last deal static bool last_deal=false; //--- The last deal in the test can be identified by the "end of test" comment if(deal.comment=="end of test" && !last_deal) { //--- Set the flag last_deal=true; //--- Update the drawdown values: // in monetary terms money_drawdown=max-min; // expressed as percentage percent_drawdown+=100-((min/max)*100); } } } } }
DrawdownToString() fonksiyonu kodu aşağıda verilmektedir:
//+------------------------------------------------------------------+ //| Converting drawdown to a string | //+------------------------------------------------------------------+ string DrawdownToString(double drawdown) { return((drawdown<=0) ? "" : DoubleToString(drawdown,2)); }
Uzman Danışmanın test edilmesi ve sonuçların analizi için artık her şey hazır. Makalenin başlarında hazır dosya örneğini gördük. Aşağıdakileri yapalım: ikinci setteki semboller (üç sembol vardır: EURUSD, AUDUSD ve USDCHF) için parametreleri optimize edelim ve optimizasyonun ardından, verileri parametre optimizasyonunda yer almayan sembollerin sonuçlarını görmek için üçüncü setteki tüm sembolleri (toplamda yedi sembol) kullanarak testi çalıştıralım.
Parametreleri Optimize Etme ve Uzman Danışmanı Test Etme
Strateji Test Cihazı aşağıda gösterildiği gibi ayarlanmalıdır:
Şekil 6. Optimizasyon için Strateji Test Cihazı ayarları
Parametre optimizasyonu için Uzman Danışman ayarları aşağıda sağlanmaktadır:
Şekil 7. Parametre optimizasyonu için Uzman Danışman ayarları
Optimizasyon üç sembol içerdiğinden ve bunlardan her biri için pozisyon hacmi artışı etkinleştirildiğinden, pozisyon açmak ve pozisyon hacmini artırmak amacıyla minimum lotu belirledik. Bizim durumumuzda değer 0,01'dir.
Optimizasyonun ardından, maksimum kurtarma faktörü ile en üstteki sonucu seçiyoruz ve lot için VolumeIncrease parametresini 0,1 olarak ayarlıyoruz. Sonuç aşağıda gösterilmektedir:
Şekil 8. MetaTrader 5'te test sonucu
Aşağıda, Excel 2010'da gösterildiği şekliyle sonucu görebilirsiniz:
Şekil 9. Excel 2010'da gösterildiği şekliyle üç sembol için test sonuçları
Para cinsinden düşüş, ikinci (yardımcı) ölçek açısından alt grafikte yeşil işaretler olarak görüntülenir.
Excel 2010'daki grafik oluşturma sınırlarının da farkında olmanız gerekir (şartnamelerin ve sınırların tam listesi, Microsoft Office web sitesinin Excel şartnameleri ve sınırları sayfasında bulunabilir).
Şekil 10. Excel 2010'daki grafik oluşturma şartnameleri ve sınırları
Tablo, testi aynı anda 255 sembol için çalıştırabileceğimizi ve tüm sonuçları grafikte görüntüleyebileceğimizi gösterir. Tek sınırımız bilgisayar kaynaklarıdır.
Şimdi mevcut parametrelerl ile üçüncü setten yedi sembol için testi çalıştıralım ve sonucu kontrol edelim:
Şekil 11. Excel 2010'da gösterildiği şekliyle yedi sembol için test sonuçları
Değerlendirilen yedi sembol ile 6901 işlemimiz vardır. Grafikteki veriler Excel 2010'da oldukça hızlı bir şekilde güncellenir.
Sonuç
Uygulanan yöntemin, kullandığımız gibi basit bir alım satım stratejisinin bile iyi sonuçlar vermesi nedeniyle dikkate değer olduğuna inanıyorum. Burada optimizasyonun yedi sembolden sadece üçü için gerçekleştirildiğini unutmamalıyız. Tüm semboller için parametreleri tek seferde optimize ederek sonucu iyileştirmeye çalışabiliriz. Ancak, her şeyden önce, alım satım sistemini iyileştirmeyi ve daha da iyisi, çeşitli alım satım sistemlerinden oluşan bir portföy elde etmeyi hedeflemeliyiz. Bu düşünceye daha sonra döneceğiz.
Neredeyse hepsi bu. Çok para birimli alım satım stratejilerinin sonuçlarını incelemek için oldukça kullanışlı bir aracımız var. Aşağıda, değerlendirmeniz için Uzman Danışmanın dosyalarının bulunduğu indirilebilir zip dosyası yer almaktadır.
Dosyaları çıkardıktan sonra, ReduceOverfittingEA klasörünü MetaTrader 5\MQL5\Experts dizinine yerleştirin. Ayrıca EventsSpy.mq5 göstergesi MetaTrader 5\MQL5\Indicators içine yerleştirilmelidir. SymbolsList.txt MetaTrader 5\MQL5\Files içine yerleştirilmelidir.
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/652
- Ücretsiz ticaret 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