MQL5 Tarif Defteri Excel'de Her Sembol için İşlemlerin Geçmişini Bir Dosyaya Yazma ve Denge Grafikleri Oluşturma
Giriş
Çeşitli forumlarda iletişim kurarken, sık sık Microsoft Excel grafiklerinin ekran görüntüsü olarak görüntülenen test sonuçlarımın örneklerini kullandım. Bu tür grafiklerin nasıl oluşturulabileceğini açıklamam birçok kez istendi. Excel, grafik oluşturmak için birçok özellik sunar ve bu konuda çok sayıda kitap vardır. Bir kitapta gerekli bilgileri bulmak için hepsini okumak gerekebilir. Şimdi, bu makalede her şeyi açıklamak için biraz zamanım var.
Önceki iki makalede MQL5 Tarif Defteri: Çok Para Birimli Uzman Danışman - Hızlı, Sade ve Hızlı Yaklaşım ve MQL5 Tarif Defteri: Sınırsız Sayıda Parametre ile Çok Para Birimli bir EA Geliştirme, MQL5'te çok para birimine sahip EA'ların geliştirilmesi ile ilgilendik. MetaTrader 5'teki test sonuçlarının genel bir Denge/Eşitlik eğrisi olarak görüntülendiğini biliyoruz, yani her sembolün sonuçlarını ayrı ayrı görüntülemeniz gerekiyorsa, sonuçları gerekli olan semboller dışındaki tüm sembolleri devre dışı bırakmak için Uzman Danışmanın harici parametrelerine tekrar tekrar gitmeli ve ardından testi tekrar çalıştırmalısınız. Bu hiç de kullanışlı değil.
Bu yüzden bugün size sadece birkaç tıklamayla tek bir Excel diyagramında çok para birimli bir Uzman Danışmanın kümülatif sonucuyla birlikte tüm semboller için denge grafiklerini nasıl elde edebileceğinize dair basit bir yöntem göstereceğim. Örneği yeniden oluşturmak için, önceki makaleden çok para birimli Uzman Danışmanı alacağız. Test tamamlandıktan sonra bu Uzman Danışman, tüm semboller için işlemlerin ve denge eğrilerinin geçmişini bir .csv dosyasına yazacak bir fonksiyon ile geliştirilecektir. Ayrıca, tüm yerel maksimum değerlerinden düşüşleri göstermek için rapora başka bir sütun ekleyeceğiz.
Veri dosyasını bağlayabilmek için bir Excel kitabı oluşturalım. Kitap her zaman açılabilir, dolayısıyla başka bir test yapmadan önce kapatılması gerekmez. Test tamamlandıktan sonra, rapordaki ve grafikteki değişiklikleri görebilmek için yalnızca belirli bir tuşa basarak verileri yenilemeniz gerekir.
Uzman Danışman Geliştirme
EA'mızda önemli bir değişiklik olmayacak, sadece birkaç fonksiyon ekleyeceğiz. Ana dosyaya sembol dengeleri için yapıyı ve diziyi ekleyerek başlayalım.
//--- Arrays for balances struct Balance { double balance[]; }; //--- Array of balances for all symbols Balance symbol_balance[];
Ardından, test raporları oluşturan fonksiyonlar için ayrı Report.mqh içerik dosyasını oluştururuz ve bunu Uzman Danışmanın ana dosyasına ekleriz (aşağıdaki kodda vurgulanan satıra bakın):
//--- Include custom libraries #include "Include/Auxiliary.mqh" #include "Include/Enums.mqh" #include "Include/Errors.mqh" #include "Include/FileFunctions.mqh" #include "Include/InitializeArrays.mqh" #include "Include/Report.mqh" #include "Include/ToString.mqh" #include "Include/TradeFunctions.mqh" #include "Include/TradeSignals.mqh"
İlk olarak pozisyon ve sembol özellikleri için projede zaten sahip olduğumuz gibi bir işlem özelliği yapısı oluşturalım. Bunun için, Enums.mqh dosyasına özellik tanımlayıcılarının numaralandırmasını ekleriz:
//+------------------------------------------------------------------+ //| Enumeration of deal properties | //+------------------------------------------------------------------+ enum ENUM_DEAL_PROPERTIES { D_SYMBOL = 0, // Deal symbol D_COMMENT = 1, // Deal comment D_TYPE = 2, // Deal type D_ENTRY = 3, // Deal entry - entry in, entry out, reverse D_PRICE = 4, // Deal price D_PROFIT = 5, // Deal result (profit/loss) D_VOLUME = 6, // Deal volume D_SWAP = 7, // Cumulative swap on close D_COMMISSION = 8, // Deal commission D_TIME = 9, // Deal time D_ALL = 10 // All of the above mentioned deal properties };
Ayrıca, Report.mqh dosyasında, işlem özelliği yapısını ve bir işlem özelliği döndüren GetHistoryDealProperties() fonksiyonunu oluştururuz. Fonksiyon iki parametreyi kabul eder: işlem bileti ve özellik tanımlayıcısı.
Aşağıda yapının ve GetHistoryDealProperties() fonksiyonunun kodunu görebilirsiniz:
//--- Deal properties in the history struct HistoryDealProperties { string symbol; // Symbol string comment; // Comment ENUM_DEAL_TYPE type; // Deal type ENUM_DEAL_ENTRY entry; // Direction double price; // Price double profit; // Profit/Loss double volume; // Volume double swap; // Swap double commission; // Commission datetime time; // Time }; //--- Variable of deal properties HistoryDealProperties deal; //+------------------------------------------------------------------+ //| Gets deal properties by ticket | //+------------------------------------------------------------------+ void GetHistoryDealProperties(ulong ticket_number,ENUM_DEAL_PROPERTIES history_deal_property) { switch(history_deal_property) { case D_SYMBOL : deal.symbol=HistoryDealGetString(ticket_number,DEAL_SYMBOL); break; case D_COMMENT : deal.comment=HistoryDealGetString(ticket_number,DEAL_COMMENT); break; case D_TYPE : deal.type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket_number,DEAL_TYPE); break; case D_ENTRY : deal.entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_number,DEAL_ENTRY); break; case D_PRICE : deal.price=HistoryDealGetDouble(ticket_number,DEAL_PRICE); break; case D_PROFIT : deal.profit=HistoryDealGetDouble(ticket_number,DEAL_PROFIT); break; case D_VOLUME : deal.volume=HistoryDealGetDouble(ticket_number,DEAL_VOLUME); break; case D_SWAP : deal.swap=HistoryDealGetDouble(ticket_number,DEAL_SWAP); break; case D_COMMISSION : deal.commission=HistoryDealGetDouble(ticket_number,DEAL_COMMISSION); break; case D_TIME : deal.time=(datetime)HistoryDealGetInteger(ticket_number,DEAL_TIME); break; case D_ALL : deal.symbol=HistoryDealGetString(ticket_number,DEAL_SYMBOL); deal.comment=HistoryDealGetString(ticket_number,DEAL_COMMENT); deal.type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket_number,DEAL_TYPE); deal.entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_number,DEAL_ENTRY); deal.price=HistoryDealGetDouble(ticket_number,DEAL_PRICE); deal.profit=HistoryDealGetDouble(ticket_number,DEAL_PROFIT); deal.volume=HistoryDealGetDouble(ticket_number,DEAL_VOLUME); deal.swap=HistoryDealGetDouble(ticket_number,DEAL_SWAP); deal.commission=HistoryDealGetDouble(ticket_number,DEAL_COMMISSION); deal.time=(datetime)HistoryDealGetInteger(ticket_number,DEAL_TIME); break; //--- default: Print("The passed deal property is not listed in the enumeration!"); return; } }
Ayrıca, bazı işlem özelliklerini dize değerlerine dönüştürecek birkaç fonksiyona ihtiyacımız olacak. Bu basit fonksiyonlar, aktarılan değer boş veya sıfırsa bir tire ("-") döndürür. Bunları ToString.mqh dosyasına yazalım:
//+------------------------------------------------------------------+ //| Returns the symbol name, otherwise - dash | //+------------------------------------------------------------------+ string DealSymbolToString(string deal_symbol) { return(deal_symbol=="" ? "-" : deal_symbol); } //+------------------------------------------------------------------+ //| Converts deal type to string | //+------------------------------------------------------------------+ string DealTypeToString(ENUM_DEAL_TYPE deal_type) { string str=""; //--- switch(deal_type) { case DEAL_TYPE_BUY : str="buy"; break; case DEAL_TYPE_SELL : str="sell"; break; case DEAL_TYPE_BALANCE : str="balance"; break; case DEAL_TYPE_CREDIT : str="credit"; break; case DEAL_TYPE_CHARGE : str="charge"; break; case DEAL_TYPE_CORRECTION : str="correction"; break; case DEAL_TYPE_BONUS : str="bonus"; break; case DEAL_TYPE_COMMISSION : str="commission"; break; case DEAL_TYPE_COMMISSION_DAILY : str="commission daily"; break; case DEAL_TYPE_COMMISSION_MONTHLY : str="commission monthly"; break; case DEAL_TYPE_COMMISSION_AGENT_DAILY : str="commission agent daily"; break; case DEAL_TYPE_COMMISSION_AGENT_MONTHLY : str="commission agent monthly"; break; case DEAL_TYPE_INTEREST : str="interest"; break; case DEAL_TYPE_BUY_CANCELED : str="buy canceled"; break; case DEAL_TYPE_SELL_CANCELED : str="sell canceled"; break; //--- Unknown deal type default : str="unknown"; } //--- return(str); } //+------------------------------------------------------------------+ //| Converts direction of deal to string | //+------------------------------------------------------------------+ string DealEntryToString(ENUM_DEAL_ENTRY deal_entry) { string str=""; //--- switch(deal_entry) { case DEAL_ENTRY_IN : str="in"; break; case DEAL_ENTRY_OUT : str="out"; break; case DEAL_ENTRY_INOUT : str="in/out"; break; case DEAL_ENTRY_STATE : str="status record"; break; //--- Unknown direction type default : str="unknown"; } //--- return(str); } //+------------------------------------------------------------------+ //| Converts volume to string | //+------------------------------------------------------------------+ string DealVolumeToString(double deal_volume) { return(deal_volume<=0 ? "-" : DoubleToString(deal_volume,2)); } //+------------------------------------------------------------------+ //| Converts price to string | //+------------------------------------------------------------------+ string DealPriceToString(double deal_price,int digits) { return(deal_price<=0 ? "-" : DoubleToString(deal_price,digits)); } //+------------------------------------------------------------------+ //| Converts deal result to string | //+------------------------------------------------------------------+ string DealProfitToString(string deal_symbol,double deal_profit) { return((deal_profit==0 || deal_symbol=="") ? "-" : DoubleToString(deal_profit,2)); } //+------------------------------------------------------------------+ //| Converts swap to string | //+------------------------------------------------------------------+ string DealSwapToString(double deal_swap) { return(deal_swap<=0 ? "-" : DoubleToString(deal_swap,2)); }
Rapor için verileri hazırlayan ve bunları LastTest.csv dosyasına yazan CreateSymbolBalanceReport() fonksiyonunu yazmak için artık her şey hazır. Bu oldukça basit: İlk olarak başlığı yazıyoruz (test birden fazla sembol için çalıştırıldıysa dizenin nasıl ayarlandığını not edin), ardından rapor için gerekli işlem özellikleri ardışık olarak daha sonra dosyaya yazılacak dizeye birleştirilecektir.
Aşağıda CreateSymbolBalanceReport() fonksiyonunun kodu yer almaktadır:
//+------------------------------------------------------------------+ //| Creates the 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 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; // Maximum drawdown double balance =0.0; // Balance //--- string delimeter =","; // Delimiter string string_to_write =""; // To generate the string for writing //--- Generate the header string string headers="TIME,SYMBOL,DEAL TYPE,ENTRY TYPE,VOLUME,PRICE,SWAP($),PROFIT($),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; //--- Generate a string for writing via 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, MaxDrawdownToString(i,balance,max_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 file: "+IntegerToString(GetLastError())+""); }
Yukarıdaki kodda vurgulanan MaxDrawdownToString() fonksiyonu, yerel maksimum değerlerinden tüm düşüşleri hesaplar ve yeni yerel maksimum değerinin zamanının bir dize temsilini döndürür. Diğer tüm durumlarda fonksiyon "-" (bir tire) içeren bir dize döndürür.
//+------------------------------------------------------------------+ //| Returns the maximum drawdown from the local maximum | //+------------------------------------------------------------------+ string MaxDrawdownToString(int deal_number,double balance,double &max_drawdown) { //--- The string to be displayed in the report string str=""; //--- 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) { //--- No drawdown yet max_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 if(balance>max) { //--- calculate the drawdown using the previous values max_drawdown=100-((min/max)*100); //--- update the local maximum max=balance; min=balance; } else { //--- Return zero value of the drawdown max_drawdown=0.0; //--- Update the minimum min=fmin(min,balance); } } //--- Determine the string for the report if(max_drawdown==0) str="-"; else str=DoubleToString(max_drawdown,2); //--- Return result return(str); }
Böylece tüm rapor oluşturma fonksiyonları hazırdır. Sadece yukarıdakilerin hepsini nasıl kullanmamız gerektiğini görmemiz gerekir. Bu ise, testin tamamlanması üzerine çağrılan OnTester() fonksiyonunu gerektirir. MQL5 Referansında bu fonksiyonun ayrıntılı açıklamasını kontrol ettiğinizden emin olun.
Raporun ne zaman oluşturulacağı koşulunu belirtmek için OnTester() fonksiyonunun gövdesine birkaç satır kod yazmanız yeterlidir. İlgili kod parçası aşağıda verilmektedir:
//+------------------------------------------------------------------+ //| Handler of the event of testing completion | //+------------------------------------------------------------------+ double OnTester() { //--- Write the report only after testing if(IsTester() && !IsOptimization() && !IsVisualMode()) //--- Generate the report and write it to the file CreateSymbolBalanceReport(); //--- return(0.0); }
Şimdi, Strateji Test Cihazında Uzman Danışmanı çalıştırırsanız, test sonunda C:\ProgramData\MetaQuotes\Terminal\Common\Filesortak terminaller klasöründe oluşturulan Uzman Danışmanın bir klasörünü görürsünüz. Ve Uzman Danışman klasöründe LastTest.csv rapor dosyası oluşturulur. Dosyayı Not Defteri ile açarsanız şöyle bir şey görürsünüz:
Şekil 1. .csv biçiminde rapor dosyası.
Excel'de Grafik Oluşturma
Oluşturulan dosyayı Excel'de açabilir ve her veri türünün ayrı bir sütunda olduğunu görebiliriz. Bu şekilde, verilerin görüntülenmesi çok daha uygun görünür. Bu noktada, grafikler oluşturmak ve dosyası *.xlsx biçiminde Excel kitabı olarak kaydetmek için teknik olarak hazırız. Bununla birlikte, daha sonra testi çalıştırır ve kitabı tekrar açarsak, eski verileri görmeye devam ederiz.
Verileri yenilemeye çalışırsak, LastTest.csv dosyası Excel'de halihazırda kullanımda ise, başka bir uygulama tarafından kullanılırken Uzman Danışman bunu yazma için açamayacağından dosya güncelleştirilmez.
Şekil 2. Excel 2010'da .csv biçiminde rapor dosyası.
Bizim durumumuzda kullanılabilecek bir çözüm vardır. İlk olarak istediğiniz herhangi bir klasörde *.xlsx biçiminde bir Excel kitabı oluşturun. Ardından bunu açın ve Veri sekmesine gidin.
Şekil 3. Excel 2010'daki Veri sekmesi.
Bu etiketin şeridinde Metinden seçeneğini seçin. Metin Dosyasını İçe Aktar iletişim kutusu çıkacaktır, buradan "LastTest.csv" dosyasını seçmelisiniz. Dosyayı seçin ve Aç düğmesine tıklayın. Metin İçe Aktarma Sihirbazı - Adım 1/3 iletişim kutusu aşağıda gösterildiği gibi açılacaktır:
Şekil 4. "Metin İçe Aktarma Sihirbazı - Adım 1/3" iletişim kutusu.
Yukarıda gösterilen ayarları ayarlayın ve Next > seçeneğine tıklayın. Burada, (Adım 2/3) veri dosyasında kullanılan ayırıcıyı belirtmelisiniz. Bizim dosyamızda bu "," (Virgül) işaretidir.
Şekil 5. "Metin İçe Aktarma Sihirbazı - Adım 2/3" iletişim kutusu.
Metin İçe Aktarma Sihirbazı - Adım 3/3'e ilerlemek için Sonraki > seçeneğine tıklayın. Burada, tüm sütunlar için veri biçimini Genel olarak bırakın. Biçimi daha sonra değiştirebilirsiniz.
Şekil 6. "Metin İçe Aktarma Sihirbazı - Adım 3 / 3" iletişim kutusu.
Tamamla düğmesine tıkladıktan sonra Veri İçe Aktarma penceresi görünecektir, burada veri içe aktarma için çalışma sayfasını ve hücreyi belirtmelisiniz.
Şekil 7. Excel 2010'da veri içe aktarma için hücre seçme.
Genel olarak A1 sol üst hücresini seçeriz. TAMAM düğmesine tıklamadan önce, harici veri aralığı özelliklerini ayarlamak için Özellikler... düğmesine tıklayın. Aşağıda gösterildiği gibi bir iletişim kutusu göreceksiniz.
Şekil 8. Excel 2010'da metin dosyalarından veri içe aktarırken Harici Veri Aralığı Özellikleri.
Ayarları tam olarak yukarıda gösterildiği gibi ayarlayın ve mevcut ve sonraki pencerede Tamam seçeneğine tıklayın.
Bunun sonucunda, verileriniz basitçe .csv dosyasını yüklemiş gibi görünecektir. Ancak artık Excel kitabını kapatmak zorunda kalmadan MetaTrader 5'te tekrarlanan testler çalıştırabilirsiniz. Testi çalıştırdıktan sonra yapmanız gereken tek şey, Ctrl+Alt+F5 kısayolunu veya Veri sekmesi şeridindeki Tümünü Yenile düğmesini kullanarak verileri yenilemektir.
Giriş sekmesi şeridindeki Koşullu Biçimlendirme seçeneklerini kullanarak, veri gösterimi için gerekli görsel özellikleri ayarlayabilirsiniz.
Şekil 9. Excel 2010'da Koşullu Biçimlendirme.
Şimdi verileri Excel grafiklerinde görüntülememiz gerekiyor. Bir grafik tüm denge grafiklerini gösterir ve diğeri yerel maksimum değerlerinden düşüşleri histogram olarak görüntüler.
İlk olarak denge grafikleri için bir diyagram oluşturalım. Tüm denge başlıklarını ve tüm veri dizisini yukarıdan aşağıya seçin (Shift tuşunu basılı tutarken Bitir tuşuna ve ardından Aşağı Ok tuşuna basın). Şimdi Ekle sekmesinden, istenilen grafik türünü seçin.
Şekil 10. Excel 2010'da grafik türü seçme.
Bunun sonucunda, kolaylık sağlamak için başka bir çalışma sayfasına taşınabilecek grafik oluşturulur. Bunun için, sadece bunu seçin ve Ctrl+X (Kes) tuşuna basın. Ardından yeni oluşturulmuş çalışma sayfasına gidin ve A1 hücresini seçin ve Ctrl+V (Yapıştır) tuşuna basın.
Varsayılan ayarlara sahip oluşturulan grafik aşağıdaki resimde gösterilir:
Şekil 11. Varsayılan ayarlar ile grafiğin görünümü ve kullanımı.
Grafiğin herhangi bir öğesini özelleştirebilirsiniz: boyutunu, rengini, stilini değiştirme vb.
Yukarıdaki resimde, yatay eksen işlem sayısını gösterir. Bunu, bunun yerine tarihleri görüntüleyecek şekilde değiştirelim. Bunun için, grafiğe sağ tıklayın ve içerik menüsünden Verileri Seç seçeneğini seçin. Veri Kaynağını Seç iletişim kutusu çıkacaktır. Düzenle düğmesine tıklayın, ardından ZAMAN sütunundan gereli veri aralığını seçin ve Tamam tuşuna tıklayın.
Şekil 12. "Veri Kaynağını Seç" iletişim kutusu.
Düşüşler grafiğini kendi başınıza oluşturmaya çalışın ve ilk grafiğin altına yerleştirin. Artık gerekirse görsel özellikleri özelleştirilebilir. Şahsen, genellikle bunu yaparım:
Şekil 13. Excel 2010'da özelleştirilmiş grafikler.
Sonuç
Artık oldukça iyi görünen test sonuçlarına sahip Excel grafiklerimiz var. Gelecekteki makalelerimden birinde, size daha da bilgilendirici raporların nasıl oluşturulacağını göstereceğim. Uzman Danışmanın dosyalarını içeren indirilebilir arşiv değerlendirmeniz için makaleye eklenmiştir.
Dosyaları arşivden çıkardıktan sonra, bunları MetaTrader 5\MQL5\Experts dizinindeki ReportInExcelklasörüne 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/651
- Ü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