Çok Para Birimli, Çok Sistemli bir Uzman Danışman Oluşturma
Giriş
Birden fazla alım satım sembolü ile alım satım yapan ve birçok strateji kullanan oldukça fazla yatırımcı olduğuna inanıyorum. Bu yaklaşım, potansiyel olarak kârınızı artırmanıza olanak sağlamakla kalmaz, aynı zamanda etkili para yönetimi ile önemli düşüş riskini de minimum düzeye indirir. Bir Uzman Danışman oluştururken, program stratejisinin etkinliğini kontrol etmede ilk doğal adım, en iyi giriş parametrelerini belirlemek için optimizasyondur.
Parametre değerleri tanımlandığında, Uzman Danışmanlar teknik olarak alım satıma hazır olmaktadır. Ancak, yanıtlanmamış önemli bir soru kalmaktadır. Bir yatırımcı tek bir Uzman Danışmanda tüm stratejilerini bir araya getirebilseydi test sonuçları nasıl olurdu? Birkaç semboldeki veya stratejideki düşüşün bir noktada çakışabileceği ve korkunç bir toplam düşüş ve hatta teminat çağrısı ile sonuçlanabileceğinin bilincinde olunması bazen kötü bir sürpriz olabilir.
Bu makale, bu önemli soruya bir yanıt bulmamıza olanak sağlayacak çok para birimli, çok sistemli bir Uzman Danışman oluşturma kavramını tanıtmaktadır.
1. Uzman Danışmanın yapısı
Genel itibarıyla Uzman Danışman yapısı aşağıdaki gibidir:
Şekil 1. Çok para birimli, çok sistemli Uzman Danışman yapısı
Gördüğünüz gibi program, bir for döngüsüne dayanmaktadır. Her bir strateji, her bir yinelemenin ayrı olarak her bir sembolün alınıp satılmasından sorumlu olduğu bir döngüde düzenlenir. Burada, döngülerde sınırsız sayıda strateji düzenleyebilirsiniz. Böyle bir programı "işlemek" için bilgisayarınızda yeterli kaynakların olması önemlidir.
MetaTrader 5'te alım satımı yapılan her bir sembol için yalnızca bir pozisyon olabileceğini unutmamalısınız. Bu pozisyon, daha önce yürütülen Alışlar ve Satışlar lotlarının toplamını temsil eder. Dolayısıyla, bir sembol için çok stratejili test sonucu, aynı sembol için aynı stratejilerin ayrı test sonuçlarının toplamı ile aynı olmayacaktır.
Uzman Danışmanın yapısının daha yakından değerlendirilmesi için, her biri iki sembol için alım satım yapan 2 strateji ele alacağız:
Strateji A:
- Alış: Ask (satış) fiyatı, Low (Düşük) fiyata göre hesaplanan Bollinger Bantları göstergesinin alt bandına ulaşır.
Kapanış: Bid (alış) fiyatı, High (Yüksek) fiyata göre hesaplanan Bollinger Bantları göstergesinin alt bandına ulaşır. - Satış: Bid (alış) fiyatı, High (Yüksek) fiyata göre hesaplanan Bollinger Bantları göstergesinin üst bandına ulaşır.
Kapanış: Ask (satış) fiyatı, Low (Düşük) fiyata göre hesaplanan Bollinger Bantları göstergesinin üst bandına ulaşır. - Kısıtlama: Verilen herhangi bir çubukta yalnızca bir işlem yürütülebilir.
Strateji B:
- Alış: Önceki çubuk aşağı yönlüdür (kapanış < açılış) ve Ask fiyatı önceki çubuğun yüksek değerine ulaşır.
Kapanış: Zarar Durdur veya Kâr Al. - Satış: Önceki çubuk yukarı yönlüdür (kapanış > açılış) ve Bid fiyatı önceki çubuğun düşük değerine ulaşır.
Kapanış: Zarar Durdur veya Kâr Al. - Kısıtlama: Verilen herhangi bir çubukta yalnızca bir işlem yürütülebilir.
Uzman danışmanın üzerinde test edileceği veya alım satım yapacağı bir sembol için yeni tiklerden bağımsız olarak, çok para birimli modda alım satım için OnTimer() fonksiyonunun kullanılması tavsiye edilir.
Bu amaçla, Uzman Danışmanı başlatırken, EventSetTimer() fonksiyonunu kullanarak bir program hesaplaması olayı oluşturma frekansını belirtiriz ve sonlandırma üzerine, terminale olay oluşturmayı durdurmasını söylemek için EventKillTimer() fonksiyonunu kullanırız:
// Include standard libraries // Create external parameters // Create arrays, variables, indicator handles, etc. //--- Initialization of the Expert Advisor int OnInit() { //--- Set event generation frequency EventSetTimer(1); // 1 second // ... return(0); } void OnTimer() { // ... } //--- Deinitialization of the Expert Advisor void OnDeinit(const int reason) { //--- Stop event generation EventKillTimer(); // ... }
EventSetTimer() yerine, frekansın milisaniye değerine ayarlandığı EventSetMillisecondTimer() fonksiyonunu kullanabilirsiniz, ancak çok sık program hesaplama çağrısı ile bunu aşırı kullanmamalısınız.
Hesaba, pozisyon ve sembol ayarlarına ve alım satım fonksiyonlarına erişim için, sırasıyla CAccountInfo, CPositionInfo, CSymbolInfo ve CTrade sınıflarını kullanacağız. Bunları Uzman Danışmana ekleyelim:
//--- Include standard libraries #include <Trade\AccountInfo.mqh> #include <Trade\PositionInfo.mqh> #include <Trade\SymbolInfo.mqh> #include <Trade\Trade.mqh>
Uzman Danışman for döngüleri tabanlı olduğu için, bunun harici parametreleri için diziler oluşturmamız gerekecektir. İlk olarak, her bir strateji için sembol sayısına eşit sabitler oluşturalım:
//--- Number of traded symbols for each strategy #define Strategy_A 2 #define Strategy_B 2
Daha sonra harici parametreleri bildiririz: Sabitleri kullanarak bunların kopyalanacağı dizilerin boyutlarını belirleriz. Ayrıca gösterge işleyicileri ve diğer global değişkenleri oluştururuz.
Strateji A'nın bir sembolünün bir örneği aşağıda verilmiştir:
//------------------- External parameters of strategy A input string Data_for_Strategy_A="Strategy A -----------------------"; //--- Symbol 0 input string Symbol_A0 = "EURUSD"; // Symbol input bool IsTrade_A0 = true; // Permission for trading //--- Bollinger Bands (BB) parameters input ENUM_TIMEFRAMES Period_A0 = PERIOD_H1; // ВВ period input uint BBPeriod_A0 = 20; // Period for calculation of the moving average of BB input int BBShift_A0 = 0; // Horizontal shift of ВВ input double BBDeviation_A0 = 2.0; // Number of standard deviations of BB //... //--- General parameters of strategy A input double DealOfFreeMargin_A = 1.0; // Percent of free margin for a deal input uint MagicNumber_A = 555; // Magic number input uint Slippage_A = 100; // Permissible slippage for a deal //... //------------- Set variables of strategy A ----- //--- Arrays for external parameters string Symbol_A[Strategy_A]; bool IsTrade_A[Strategy_A]; ENUM_TIMEFRAMES Period_A[Strategy_A]; int BBPeriod_A[Strategy_A]; int BBShift_A[Strategy_A]; double BBDeviation_A[Strategy_A]; //--- Arrays for global variables double MinLot_A[Strategy_A],MaxLot_A[Strategy_A]; double Point_A[Strategy_A],ContractSize_A[Strategy_A]; uint DealNumber_A[Strategy_A]; datetime Locked_bar_time_A[Strategy_A],time_arr_A[]; //--- Indicator handles int BB_handle_high_A[Strategy_A]; int BB_handle_low_A[Strategy_A]; //--- Arrays for indicator values double BB_upper_band_high[],BB_lower_band_high[]; double BB_upper_band_low[],BB_lower_band_low[]; //--- Class CTrade Trade_A; //... //--- Set global variables for all strategies long Leverage; //--- Classes CAccountInfo AccountInfo; CPositionInfo PositionInfo; CSymbolInfo SymbolInfo;
Belirli bir sembol için alım satımı devre dışı bırakma imkanına sahip olmak için, for döngülerinin en başına yerleştirilecek bir IsTrade_A0 Boolean değişkeni oluşturduk.
2. Uzman Danışmanı Başlatma
İlk olarak, örneğin kaldıraç olmak üzere tüm stratejiler için gerekli değerleri elde edelim. Kaldıraç alım satım hesabına uygulanmadığından ve bir strateji veya bir sembol ile hiçbir alakası olmadığında, bunun değerini dizilere kopyalamaya gerek yoktur.
//--- Get the leverage for the account
Leverage=AccountInfo.Leverage();
Daha sonra harici parametreleri dizilere kopyalarız.
//--- Copy external variables to arrays Symbol_A[0] =Symbol_A0; IsTrade_A[0] =IsTrade_A0; Period_A[0] =Period_A0; BBPeriod_A[0] =(int)BBPeriod_A0; BBShift_A[0] =BBShift_A0; BBDeviation_A[0]=BBDeviation_A0;
Herhangi bir harici parametre bir diğer parametreye dönüşüm gerektirecek tür ile tanımlanıyorsa, bu, dizilere kopyalama yapılırken daha uygun bir şekilde gerçekleştirilebilir.
Bu durumda, BBPeriod_A0 öğesinin, kullanıcının bir negatif değer ayarlanmasını engellemek için uint olarak oluşturulduğunu görebiliriz. Burada, bunu int öğesine dönüştürürüz ve bunu int olarak oluşturulan diziye kopyalarız. Diğer şekilde derleyici, gösterge işleyiciye uint türünde parametre eklemeye çalışıp çalışmadığınıza dair bir uyarı verecektir.
Ayrıca, alım satımı yapılan sembolün Piyasa İzlemede mevcut olup olmadığını ve bunun bir strateji içinde birkaç kez kullanılıp kullanılmadığına bakalım:
//--- Check for the symbol in the Market Watch for(int i=0; i<Strategy_A; i++) { if(IsTrade_A[i]==false) continue; if(IsSymbolInMarketWatch(Symbol_A[i])==false) { Print(Symbol_A[i]," could not be found on the server!"); ExpertRemove(); } } //--- Check whether the symbol is used more than once if(Strategy_A>1) { for(int i=0; i<Strategy_A-1; i++) { if(IsTrade_A[i]==false) continue; for(int j=i+1; j<Strategy_A; j++) { if(IsTrade_A[j]==false) continue; if(Symbol_A[i]==Symbol_A[j]) { Print(Symbol_A[i]," is used more than once!"); ExpertRemove(); } } } } //--- The IsSymbolInMarketWatch() function bool IsSymbolInMarketWatch(string f_Symbol) { for(int s=0; s<SymbolsTotal(false); s++) { if(f_Symbol==SymbolName(s,false)) return(true); } return(false); }
Semboller doğru bir şekilde seçildiyse, bunlardan her biri için giriş parametrelerinde hataları kontrol edin, gösterge işleyiciler oluşturun, lot hesaplaması için gerekli verileri elde edin ve gerekiyorsa belirli strateji ile tanımlanan diğer şeyleri yapın.
Yukarıda bahsedilen eylemleri bir for döngüsüne uygulayacağız.
//--- General actions for(int i=0; i<Strategy_A; i++) { if(IsTrade_A[i]==false) continue; //--- Check for errors in input parameters //... //--- Set indicator handles BB_handle_high_A[i]=iBands(Symbol_A[i],Period_A[i],BBPeriod_A[i],BBShift_A[i],BBDeviation_A[i], PRICE_HIGH); if(BB_handle_high_A[i]<0) { Print("Failed to create a handle for Bollinger Bands based on High prices for ",Symbol_A[i]," . Handle=",INVALID_HANDLE, "\n Error=",GetLastError()); ExpertRemove(); } //... //--- Calculate data for the Lot //--- set the name of the symbol for which the information will be obtained SymbolInfo.Name(Symbol_A[i]); //--- minimum and maximum volume size in trading operations MinLot_A[i]=SymbolInfo.LotsMin(); MaxLot_A[i]=SymbolInfo.LotsMax(); //--- point value Point_A[i]=SymbolInfo.Point(); //--- contract size ContractSize_A[i]=SymbolInfo.ContractSize(); //--- Set some additional parameters }
Daha sonra, CTrade sınıfının Trade_A nesnesini kullanarak strateji A'nın alım sayım işlemlerine yönelik parametreleri ayarlayacağız.
//--- Set parameters for trading operations //--- set the magic number Trade_A.SetExpertMagicNumber(MagicNumber_A); //--- set the permissible slippage in points upon deal execution Trade_A.SetDeviationInPoints(Slippage_A); //--- order filling mode, use the mode that is allowed by the server Trade_A.SetTypeFilling(ORDER_FILLING_RETURN); //--- logging mode, it is advisable not to call this method as the class will set the optimal mode by itself Trade_A.LogLevel(1); //--- the function to be used for trading: true - OrderSendAsync(), false - OrderSend(). Trade_A.SetAsyncMode(true);
Aynı prosedür her bir strateji için tekrarlanır, yani:
- Harici parametreleri dizilere kopyala;
- Sembollerin doğru şekilde seçilip seçilmediğini kontrol et;
- Hataları kontrol et, gösterge işleyiciler oluştur, lot için ve belirli bir strateji için gereken her şey için verileri hesapla;
- Alım satım işlemleri için parametreleri ayarla.
Son olarak, birkaç stratejide bir ve aynı sembolün kullanılıp kullanılmadığını kontrol etmek iyi olacak (iki strateji için bir örnek aşağıda verilmiştir):
//--- Check whether one and the same symbol is used in several strategies for(int i=0; i<Strategy_A; i++) { if(IsTrade_A[i]==false) continue; for(int j=0; j<Strategy_B; j++) { if(IsTrade_B[j]==false) continue; if(Symbol_A[i]==Symbol_B[j]) { Print(Symbol_A[i]," is used in several strategies!"); ExpertRemove(); } } }
3. "For" Döngüleri ile Alım Satım
OnTimer() fonksiyonu içinde for döngülerinin çerçevesi aşağıdaki gibidir:
void OnTimer() { //--- Check if the terminal is connected to the trade server if(TerminalInfoInteger(TERMINAL_CONNECTED)==false) return; //--- Section A: Main loop of the FOR operator for strategy A ----------- for(int A=0; A<Strategy_A; A++) { //--- A.1: Check whether the symbol is allowed to be traded if(IsTrade_A[A]==false) continue; // terminate the current FOR iteration } //--- Section В: Main loop of the FOR operator for strategy В ----------- for(int B=0; B<Strategy_B; B++) { //--- B.1: Check whether the symbol is allowed to be traded if(IsTrade_B[B]==false) continue; // terminate the current FOR iteration } }
Tek bir stratejiye dayalı tek sembollü bir Uzman Danışman, sonraki tüm işlemlerin durdurulması gerektiği koşuluna sahipse, geri dön (return) işlecini kullanırız. Bizim durumumuzda, sadece mevcut yinelemeyi durdurmamız ve sonraki sembol yinelemelerine ilerlememiz gerekiyor. Bunun için en iyisi devam et (continue) işlecini kullanmaktır.
Sonraki tüm hesaplamaların durdurulması koşulunu içeren bir for döngüsü ile bir strateji ekleyerek çok stratejili Uzman Danışmanınızı geliştirmek isterseniz, aşağıdaki modeli kullanabilirsiniz:
//--- Section N: Main loop of the FOR operator for strategy N ----------- for(int N=0; N<Strategy_N; N++) { //... bool IsInterrupt=false; for(int i=0; i<Number; i++) { if(...) // terminate all calculations { IsInterrupt=true; break; } } if(IsInterrupt=true) continue; // terminate the current FOR iteration //... }
for döngülerinin çerçevesini oluşturduktan sonra, bunu diğer EA'ların kodlarına ekliyoruz ve ardından bazı değişkenleri dizi öğeleri ile değiştiriyoruz.
Örneğin önceden tanımlanmış _Symbol değişkenini Symbol_A[i] ile veya _Point değişkenini Point_A[i] ile değiştiriyoruz. Bu değişkenlerin değerleri, belirli sembol için tipiktir ve bu yüzden başlatma üzerine dizilere kopyalanmıştır.
Örneğin gösterge değerini bulalım:
//--- A.3: Lower band of BB calculated based on High prices if(CopyBuffer(BB_handle_high_A[A],LOWER_BAND,BBShift_A[A],1,BB_lower_band_high)<=0) continue; // terminate the current FOR iteration ArraySetAsSeries(BB_lower_band_high,true);
Bir alış pozisyonunun kapatılmasını uygulamak için aşağıdaki kodu yazacağız:
//--- A.7.1: Calculate the current Ask and Bid prices SymbolInfo.Name(Symbol_A[A]); SymbolInfo.RefreshRates(); double Ask_price=SymbolInfo.Ask(); double Bid_price=SymbolInfo.Bid(); if(PositionSelect(Symbol_A[A])) { //--- A.7.2: Closing a BUY position if(PositionInfo.PositionType()==POSITION_TYPE_BUY) { if(Bid_price>=BB_lower_band_high[0] || DealNumber_A[A]==0) { if(!Trade_A.PositionClose(Symbol_A[A])) { Print("Failed to close the Buy ",Symbol_A[A]," position. Code=",Trade_A.ResultRetcode(), " (",Trade_A.ResultRetcodeDescription(),")"); continue; // terminate the current FOR iteration } else { Print("The Buy ",Symbol_A[A]," position closed successfully. Code=",Trade_A.ResultRetcode(), " (",Trade_A.ResultRetcodeDescription(),")"); continue; // terminate the current FOR iteration } } } //... }
Bir Alış pozisyonu açma:
//--- A.9.1: for a Buy if(Ask_price<=BB_lower_band_low[0]) { //... //--- A.9.1.3: Execute a deal if(!Trade_A.Buy(OrderLot,Symbol_A[A])) { Print("The Buy ",Symbol_A[A]," has been unsuccessful. Code=",Trade_A.ResultRetcode(), " (",Trade_A.ResultRetcodeDescription(),")"); continue; // terminate the current FOR iteration } else { Print("The Buy ",Symbol_A[A]," has been successful. Code=",Trade_A.ResultRetcode(), " (",Trade_A.ResultRetcodeDescription(),")"); continue; // terminate the current FOR iteration } }
Zamanlayıcı olayı oluşturmayı durdurmayı ve sonlandırmada gösterge işleyicilerini silmeyi unutmayın.
4. Test Sonuçları
Uzman Danışman hazır olduğunda, her bir stratejiyi ve her bir sembolü ayrı olarak test ederiz ve test sonuçlarını tüm stratejilerin ve sembollerin eş zamanlı olarak alım satım yaptığındaki test modunda elde edilenler ile karşılaştırırız.
Kullanıcının halihazırda giriş parametreleri için optimum değerleri tanımladığı varsayılır.
Aşağıda Strateji Test Cihazının ayarları yer almaktadır:
Şekil 2. Strateji Test Cihazı ayarları
Strateji A, EURUSD için sonuçlar:
Şekil 3. Strateji A, EURUSD için test sonuçları
Strateji A, GBPUSD için sonuçlar
Şekil 4. Strateji A, GBPUSD için test sonuçları
Strateji B, AUDUSD için sonuçlar
Şekil 5. Strateji B, AUDUSD için test sonuçları
Strateji B, EURJPY için sonuçlar:
Şekil 6. Strateji B, EURJPY için test sonuçları
Tüm stratejiler ve semboller için test sonuçları:
Şekil 7. Tüm stratejiler ve semboller için test sonuçları
Sonuç
Bunun sonucunda, stratejilerinizden herhangi birini ekleyebileceğiniz çok para birimli, çok sistemli Uzman Danışmanın uygun ve basit bir yapısını elde ettik.
Böyle bir Uzman Danışman, tüm stratejilerinizi kullanarak alım satım verimliliğinizi daha iyi değerlendirmenize olanak sağlar. Belirli bir hesapta yalnızca bir Uzman Danışmanın çalışmasına izin verildiği durumda da faydalı olduğu gösterilebilir. Uzman Danışmanın kaynak kodu, yukarıdaki bilgilerin çalışılmasını kolaylaştırmak için makaleye eklenmiştir.
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/770
- Ü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