
MQL5 Tarif Defteri: Uzman Danışmanlarda Alım Satım Koşullarını Belirlemek için Göstergeleri Kullanma
Giriş
Bu makalede, Uzman Danışman göstergeler ile güçlendirilecektir, bu göstergelerin değerleri pozisyon açma koşullarını kontrol etmek için kullanılacaktır. Renk katmak için, üç alım satım göstergesinden birini seçebilmek için harici parametrelerde bir açılır liste oluşturacağız.
Unutursanız diye bir hatırlatma: MQL5 Tarif Defteri serisinin önceki makalelerinde üzerinde çalıştığımız Uzman Danışmanı değiştirmeye devam edeceğiz. Uzman Danışmanın son sürümü, "MQL5 Tarif Defteri: Pozisyon Özelliklerini Elde Etmek için İşlemler Geçmişi ve Fonksiyon Kitaplığı" adı makaleden indirilebilir.
Ayrıca bu makalede, alım satım işlemlerinin yapılıp yapılamayacağını kontrol etmek için oluşturacağımız bir fonksiyon da yer alacaktır. Pozisyon açma fonksiyonu, Uzman Danışmanın alım satım modunu belirlemesini sağlayacak şekilde değiştirilecektir (Anında Yürütme ve Piyasa Yürütmesi).
Uzman Danışman kodu, önceki makalelerde yapılan tüm geliştirmeler ve iyileştirmeleri takiben zaten 1.500 satırı aştığından, eklenen her yeni özellik ile daha az kullanışlı hale gelecektir. Bu yüzden mantıklı bir çözüm, bunu ayrı kitaplık dosyaları olarak birkaç kategoriye bölmektir. Artık hedefler belirlendiğine göre hadi başlayalım.
Uzman Danışman Geliştirme
Bir önceki makaledeki Uzman Danışman (*.mq5) kaynak kodunu ayrı bir klasör olan TestIndicatorConditions içine yerleştiriyoruz, burada Include alt klasörünü oluşturmamız gerekiyor. Bu, içerik dosyaları (*.mqh) oluşturacağımız klasördür. Bunlar, MQL5 Sihirbazını (Ctrl+N) kullanılarak oluşturulabilir veya standart metin dosyaları (*.txt) olarak gerekli dizinde manuel olarak oluşturarak daha sonra *.mqh olarak yeniden adlandırılabilir.
Aşağıda, oluşturulan tüm içerik dosyalarının adları ve yorumları yer almaktadır:
- Enums.mqh tüm numaralandırmaları içerecektir;
- InfoPanel.mqh bilgi panelinin ayarlanması, grafik nesnelerin oluşturulması ve silinmesi için özellikleri içerecektir;
- Errors.mqh hata kodları ve sonlandırma sebeplerini döndüren tüm fonksiyonları içerecektir;
- TradeSignals.mqh, dizileri fiyatlar ve gösterge değerleriyle ve ayrıca sinyal bloğuyla dolduran fonksiyonları içerecektir;
- Tradefonksiyonus.mqh alım satım fonksiyonlarını içerecektir;
- ToString.mqh sayısal değerleri dize değerlerine dönüştüren fonksiyonları içerecektir;
- Auxiliary.mqh diğer yardımcı fonksiyonlar için kullanılacaktır.
Bu kitaplıkları ana dosyaya dahil etmek için #include direktifini kullanırız. Uzman Danışmanın ana dosyası ve içerik dosya klasörü (Include) aynı klasörde bulunduğundan, dosya ekleme kodu aşağıdaki gibi olacaktır:
//--- Include custom libraries #include "Include\Enums.mqh" #include "Include\InfoPanel.mqh" #include "Include\Errors.mqh" #include "Include\TradeSignals.mqh" #include "Include\TradeFunctions.mqh" #include "Include\ToString.mqh" #include "Include\Auxiliary.mqh"
Ardından, bunları açıp değiştirebileceğiz ve Uzman Danışmanın ana dosyasından kaynak kodun bir kısmını taşıyabileceğiz.
Kodda doğru şekilde gezinmek için, bitişik başlık dosyalarına eklenecektir ve Uzman Danışmanın ana dosyasına yapılan referanslar her başlık dosyasına eklenecektir. Örneğin, alım satım fonksiyonları kitaplığımız TradeFunctions.mqh için şu şekilde görünecektir:
//--- Connection with the main file of the Expert Advisor #include "..\TestIndicatorConditions.mq5" //--- Include custom libraries #include "Enums.mqh" #include "InfoPanel.mqh" #include "Errors.mqh" #include "TradeSignals.mqh" #include "ToString.mqh" #include "Auxiliary.mqh"
Aynı yerleşim düzeyindeki dosyalar için sadece adı belirtmek yeterlidir. Bir seviye yukarı çıkmak için, yoldaki ters eğik çizgiden önce iki adet nokta koymanız gerekir.
Enums.mqh dosyasındaki göstergeler için numaralandırma ekleyelim. Örnekleme amacıyla, bu Uzman Danışmanda, iki standart gösterge (Hareketli Ortalama ve Emtia Kanalı İndisi) ve bir özel gösterge (MultiRange_PCH) kullanacağız. Numaralandırma aşağıdaki gibi olacaktır:
//--- Indicators enum ENUM_INDICATORS { MA = 0, // Moving Average CCI = 1, // CCI PCH = 2 // Price Channel };
Harici parametreler aşağıdaki şekilde değiştirilir:
//--- External parameters of the Expert Advisor sinput long MagicNumber=777; // Magic number sinput int Deviation=10; // Slippage input ENUM_INDICATORS Indicator=MA; // Indicator input int IndicatorPeriod=5; // Indicator period input int IndicatorSegments=2; // Number of one direction indicator segments input double Lot=0.1; // Lot input double VolumeIncrease=0.1; // Position volume increase input double VolumeIncreaseStep=10; // Step for volume increase input double StopLoss=50; // Stop Loss input double TakeProfit=100; // Take Profit input double TrailingStop=10; // Trailing Stop input bool Reverse=true; // Position reversal sinput bool ShowInfoPanel=true; // Display of the info panel
Yukarıda belirtildiği gibi, Gösterge parametresinin açılır listesindeki üç göstergeden birini seçebileceksiniz.
Gösterge döneminin ayarlanabileceği tüm göstergeler için geçerli olan tek bir parametre vardır: IndicatorPeriod. Uzman Danışmanın önceki sürümündeki NumberOfBars parametresi IndicatorSegments olarak yeniden adlandırılmıştır ve şimdi pozisyon açma koşulunu karşılamak için belirli bir göstergenin yukarı/aşağı gitmesi gereken çubuk sayısını göstermektedir.
Puan cinsinden hacim artışına yönelik adımı ayarlamak için kullanılabilen VolumeIncreaseStep adlı başka bir harici parametre daha ekledik.
AllowedNumberOfBars değişkeninin değeri (artık AllowedNumberOfSegments) önceden GetBarsData() özel fonksiyonunda ayarlanırdı. Şimdi ise bu, ayrı bir fonksiyona yerleştirilerek yalnızca başlatma sırasında çağrılacaktır.
Pozisyon açma koşulu artık gösterge değerleri kullanılarak kontrol edileceğinden, atanacak değer her zaman ikiden büyük olacaktır. Diğer bir deyişle, IndicatorSegments harici değişkenine 1 değeri atanırsa, tamamlanan çubuktaki gösterge değerinin önceki çubuktakinden daha büyük olması gerektiği koşulunu sağlamak için (örneğin ALIŞ için) AllowedNumberOfSegments değişkenine 3 değeri atanacaktır. Bunun için son üç gösterge değerini elde etmemiz gerekiyor.
Aşağıda, CorrectInputParameters() fonksiyon kodu yer almaktadır:
//+------------------------------------------------------------------+ //| Adjusting input parameters | //+------------------------------------------------------------------+ void CorrectInputParameters() { //--- Adjust the number of bars for the position opening condition if(AllowedNumberOfSegments<=0) { if(IndicatorSegments<=1) AllowedNumberOfSegments=3; // At least three bars are required if(IndicatorSegments>=5) AllowedNumberOfSegments=5; // but no more than 7 else AllowedNumberOfSegments=IndicatorSegments+1; // and always greater by two } }
Göstergelerle ilgilenmeye başlamadan önce, alım satıma izin verilip verilmediğini kontrol edecek bir fonksiyon oluşturalım: CheckTradingPermission(). Fonksiyonda listelenen nedenlerden herhangi biri nedeniyle alım satıma izin verilmezse, sıfır değeri döndürülür. Bu, bir sonraki denemenin bir sonraki çubukta yapılması gerektiği anlamına gelir.
//+------------------------------------------------------------------+ //| Checking if trading is allowed | //+------------------------------------------------------------------+ bool CheckTradingPermission() { //--- For real-time mode if(IsRealtime()) { //--- Checking server connection if(!TerminalInfoInteger(TERMINAL_CONNECTED)) return(1); //--- Permission to trade at the running program level if(!MQL5InfoInteger(MQL5_TRADE_ALLOWED)) return(2); //--- Permission to trade at the terminal level if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) return(3); //--- Permission to trade for the current account if(!AccountInfoInteger(ACCOUNT_TRADE_ALLOWED)) return(4); //--- Permission to trade automatically for the current account if(!AccountInfoInteger(ACCOUNT_TRADE_EXPERT)) return(5); } //--- return(0); }
Şimdi makalenin ana konusuna gelelim. Göstergenin değerlerine erişmek için ilk olarak işleyiciyi elde etmemiz gerekir. Bu da, adları göstergenin kısa adından ve önündeki "i" sembolünden oluşan özel fonksiyonlar kullanılarak yapılır.
Örneğin, Moving Average (Hareketli Ortalama) göstergesinde buna karşılık gelen iMA() fonksiyonu vardır. MetaTrader 5 terminalindeki tüm standart gösterge kolları bu fonksiyonlar kullanılarak elde edilebilir. Tam liste, Teknik Göstergeler adlı MQL5 Referansı bölümünde mevcuttur. Özel bir göstergenin bir işleyicisini elde etmek için, iCustom() fonksiyonunu kullanın.
GetIndicatorHandle() fonksiyonunu uygulayacağız, burada Indicator parametresinde seçilen göstergeye göre ilgili göstergenin işleyici değeri indicator_handle global değişkenine atanacaktır. Fonksiyon kodu, alım satım sinyali fonksiyonları kitaplığımızda (\Include\TradeSignals.mqh dosyası) bulunabilir, gösterge işleyicisine sahip değişken ise Uzman Danışmanın ana dosyasında bulunur.
//+------------------------------------------------------------------+ //| Getting the indicator handle | //+------------------------------------------------------------------+ void GetIndicatorHandle() { //--- If the Moving Average indicator is selected if(Indicator==MA) indicator_handle=iMA(_Symbol,Period(),IndicatorPeriod,0,MODE_SMA,PRICE_CLOSE); //--- If the CCI indicator is selected if(Indicator==CCI) indicator_handle=iCCI(_Symbol,Period(),IndicatorPeriod,PRICE_CLOSE); //--- If the MultiRange_PCH indicator is selected if(Indicator==PCH) indicator_handle=iCustom(_Symbol,Period(),"MultiRange_PCH",IndicatorPeriod); //--- If the indicator handle could not be obtained if(indicator_handle==INVALID_HANDLE) Print("Failed to get the indicator handle!"); }
Ayrıca, elde edilen gösterge işleyicilerini kullanarak değerlerini elde edebileceğimizGetDataIndicators() fonksiyonunu oluştururuz. Bu ise, aşağıdaki makalede değerlendirilen CopyTime(), CopyClose(), CopyOpen(), CopyHigh() ve CopyLow() fonksiyonlar kullanılarak elde çubuk değerlerinin elde edilmesine benzer bir şekilde CopyBuffer() fonksiyonu kullanılarak yapılır: "MQL5 Tarif Defteri: Pozisyon Parametrelerini MetaTrader 5 Strateji Test Cihazında Analiz Etme".
Gösterge birkaç tampona (değer satırları) sahip olabileceğinden, tampon indisi ikinci parametre olarak CopyBuffer() fonksiyonuna aktarılır. Standart göstergeler için tampon indisleri MQL5 Referansında bulunabilir. Özel göstergeler için, kaynak kodun mevcut olması koşuluyla, kodda tampon indisleri bulunabilir. Kod yoksa, Strateji Test Cihazının, görselleştirme modunda koşulların nasıl karşılandığını gözlemleyerek deneme yoluyla indisi bulmanız gerekecektir.
Ama bundan önce, Uzman Danışmanın ana dosyasındaki gösterge tampon değerleri için dinamik diziler oluşturmamız gerekiyor:
//--- Arrays for indicator values double indicator_buffer1[]; double indicator_buffer2[];
GetIndicatorsData() kodu aşağıda verilmektedir:
//+------------------------------------------------------------------+ //| Getting indicator values | //+------------------------------------------------------------------+ bool GetIndicatorsData() { //--- If the indicator handle has been obtained if(indicator_handle!=INVALID_HANDLE) { //--- For the Moving Average or CCI indicator if(Indicator==MA || Indicator==CCI) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer1,true); //--- Get indicator values if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); return(false); } } //--- For the MultiRange_PCH indicator if(Indicator==PCH) { //--- Reverse the indexing order (... 3 2 1 0) ArraySetAsSeries(indicator_buffer1,true); ArraySetAsSeries(indicator_buffer2,true); //--- Get indicator values if(CopyBuffer(indicator_handle,0,0,AllowedNumberOfSegments,indicator_buffer1)<AllowedNumberOfSegments || CopyBuffer(indicator_handle,1,0,AllowedNumberOfSegments,indicator_buffer2)<AllowedNumberOfSegments) { Print("Failed to copy the values ("+ _Symbol+"; "+TimeframeToString(Period())+") to the indicator_buffer1 or indicator_buffer2 array! Error ("+ IntegerToString(GetLastError())+"): "+ErrorDescription(GetLastError())); return(false); } } //--- return(true); } //--- If the indicator handle has not been obtained, retry else GetIndicatorHandle(); //--- return(false); }
GetTradingSignal() fonksiyonu büyük ölçüde değiştirilmiştir. Pozisyonun yokluğunda ve pozisyonun mevcut olduğu durumlarda koşullar farklıdır. Hareketli Ortalama ve CCI göstergeleri için koşullar aynıdır. MultiRange_PCH için bunlar ayrı bir blokta düzenlenir. Kodu daha okunabilir hale getirmek ve tekrarlardan kaçınmak için, böyle bir pozisyonun mevcut olması ve harici parametre tarafından ilgili eyleme izin verilmesi koşuluyla, pozisyon açma veya ters çevirme için bir sinyal döndüren GetSignal() adlı yardımcı bir fonksiyon oluşturuyoruz.
Aşağıda GetSignal() fonksiyon kodu yer almaktadır:
//+------------------------------------------------------------------+ //| Checking the condition and returning a signal | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE GetSignal() { //--- Check conditions for the Moving Average and CCI indicators if(Indicator==MA || Indicator==CCI) { //--- A Sell signal if(AllowedNumberOfSegments==3 && indicator_buffer1[1]<indicator_buffer1[2]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==4 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==5 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments==6 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4] && indicator_buffer1[4]<indicator_buffer1[5]) return(ORDER_TYPE_SELL); //--- if(AllowedNumberOfSegments>=7 && indicator_buffer1[1]<indicator_buffer1[2] && indicator_buffer1[2]<indicator_buffer1[3] && indicator_buffer1[3]<indicator_buffer1[4] && indicator_buffer1[4]<indicator_buffer1[5] && indicator_buffer1[5]<indicator_buffer1[6]) return(ORDER_TYPE_SELL); //--- A Buy signal if(AllowedNumberOfSegments==3 && indicator_buffer1[1]>indicator_buffer1[2]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==4 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==5 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments==6 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4] && indicator_buffer1[4]>indicator_buffer1[5]) return(ORDER_TYPE_BUY); //--- if(AllowedNumberOfSegments>=7 && indicator_buffer1[1]>indicator_buffer1[2] && indicator_buffer1[2]>indicator_buffer1[3] && indicator_buffer1[3]>indicator_buffer1[4] && indicator_buffer1[4]>indicator_buffer1[5] && indicator_buffer1[5]>indicator_buffer1[6]) return(ORDER_TYPE_BUY); } //--- Block that checks conditions for the MultiRange_PCH indicator if(Indicator==PCH) { //--- A Sell signal if(close_price[1]<indicator_buffer2[1] && open_price[1]>indicator_buffer2[1]) return(ORDER_TYPE_SELL); //--- A Buy signal if(close_price[1]>indicator_buffer1[1] && open_price[1]<indicator_buffer1[1]) return(ORDER_TYPE_BUY); } //--- No signal return(WRONG_VALUE); }
GetTradingSignal() fonksiyon kodu şimdi şu şekildedir:
//+------------------------------------------------------------------+ //| Determining trading signals | //+------------------------------------------------------------------+ ENUM_ORDER_TYPE GetTradingSignal() { //--- If there is no position if(!pos.exists) { //--- A Sell signal if(GetSignal()==ORDER_TYPE_SELL) return(ORDER_TYPE_SELL); //--- A Buy signal if(GetSignal()==ORDER_TYPE_BUY) return(ORDER_TYPE_BUY); } //--- If the position exists if(pos.exists) { //--- Get the position type GetPositionProperties(P_TYPE); //--- Get the last deal price GetPositionProperties(P_PRICE_LAST_DEAL); //--- Block that checks conditions for the Moving Average and CCI indicators if(Indicator==MA || Indicator==CCI) { //--- A Sell signal if(pos.type==POSITION_TYPE_BUY && GetSignal()==ORDER_TYPE_SELL) return(ORDER_TYPE_SELL); //--- if(pos.type==POSITION_TYPE_SELL && GetSignal()==ORDER_TYPE_SELL && close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_SELL); //--- A Buy signal if(pos.type==POSITION_TYPE_SELL && GetSignal()==ORDER_TYPE_BUY) return(ORDER_TYPE_BUY); //--- if(pos.type==POSITION_TYPE_BUY && GetSignal()==ORDER_TYPE_BUY && close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_BUY); } //--- Block that checks conditions for the MultiRange_PCH indicator if(Indicator==PCH) { //--- A Sell signal if(pos.type==POSITION_TYPE_BUY && close_price[1]<indicator_buffer2[1] && open_price[1]>indicator_buffer2[1]) return(ORDER_TYPE_SELL); //--- if(pos.type==POSITION_TYPE_SELL && close_price[1]<pos.last_deal_price-CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_SELL); //--- A Buy signal if(pos.type==POSITION_TYPE_SELL && close_price[1]>indicator_buffer1[1] && open_price[1]<indicator_buffer1[1]) return(ORDER_TYPE_BUY); //--- if(pos.type==POSITION_TYPE_BUY && close_price[1]>pos.last_deal_price+CorrectValueBySymbolDigits(VolumeIncreaseStep*_Point)) return(ORDER_TYPE_BUY); } } //--- No signal return(WRONG_VALUE); }
Şimdi, sadece sembol özelliklerinin parçası olan Anında Yürütme ve Piyasa Yürütmesi modlarını görmemiz ve OpenPosition() pozisyon açma fonksiyonunun kodunu buna göre değiştirmemiz gerekiyor. Adları kendilerini açıklayan modlar MQL5 Referansı içinde de bulunabilir:
- Anında Yürütme
- Piyasa Yürütmesi
Piyasa Yürütmesi modu ile uğraşırken, ayarlanmış Zarar Durdur ve Kâr Al seviyelerinde bir pozisyon açamayacağınızı lütfen unutmayın: İlk olarak bir pozisyon açmanız ve ardından seviyeleri ayarlayarak bunu değiştirmeniz gerekir.
Sembol özelliklerinin yapısına yürütme modunu ekleyelim:
//--- Symbol properties struct symbol_properties { int digits; // Number of decimal places in the price int spread; // Spread in points int stops_level; // Stops level double point; // Point value double ask; // Ask price double bid; // Bid price double volume_min; // Minimum volume for a deal double volume_max; // Maximum volume for a deal double volume_limit; // Maximum permissible volume for a position and orders in one direction double volume_step; // Minimum volume change step for a deal double offset; // Offset from the maximum possible price for a transaction double up_level; // Upper Stop level price double down_level; // Lower Stop level price ENUM_SYMBOL_TRADE_EXECUTION execution_mode; // Execution mode };
Buna göre, ENUM_SYMBOL_PROPERTIES numaralandırmasını
//--- Enumeration of position properties enum ENUM_SYMBOL_PROPERTIES { S_DIGITS = 0, S_SPREAD = 1, S_STOPSLEVEL = 2, S_POINT = 3, S_ASK = 4, S_BID = 5, S_VOLUME_MIN = 6, S_VOLUME_MAX = 7, S_VOLUME_LIMIT = 8, S_VOLUME_STEP = 9, S_FILTER = 10, S_UP_LEVEL = 11, S_DOWN_LEVEL = 12, S_EXECUTION_MODE = 13, S_ALL = 14 };
ve GetSymbolProperties() fonksiyonunu değiştirmemiz gerekir:
case S_EXECUTION_MODE: symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE); break; //--- case S_ALL : symb.digits=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS); symb.spread=(int)SymbolInfoInteger(_Symbol,SYMBOL_SPREAD); symb.stops_level=(int)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL); symb.point=SymbolInfoDouble(_Symbol,SYMBOL_POINT); symb.ask=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_ASK),symb.digits); symb.bid=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_BID),symb.digits); symb.volume_min=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); symb.volume_max=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX); symb.volume_limit=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_LIMIT); symb.volume_step=SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_STEP); symb.offset=NormalizeDouble(CorrectValueBySymbolDigits(lot_offset*symb.point),symb.digits); symb.up_level=NormalizeDouble(symb.ask+symb.stops_level*symb.point,symb.digits); symb.down_level=NormalizeDouble(symb.bid-symb.stops_level*symb.point,symb.digits); symb.execution_mode=(ENUM_SYMBOL_TRADE_EXECUTION)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_EXEMODE); break; //---
Bunun sonucunda, OpenPosition() fonksiyon kodu şimdi şu şekildedir:
//+------------------------------------------------------------------+ //| Opening a position | //+------------------------------------------------------------------+ void OpenPosition(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)); //--- The Instant Execution mode // A position can be opened with the Stop Loss and Take Profit levels set if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_INSTANT) { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } //--- The Market Execution mode // First open a position and only then set the Stop Loss and Take Profit levels // *** Starting with build 803, Stop Loss and Take Profit can be set upon position opening *** if(symb.execution_mode==SYMBOL_TRADE_EXECUTION_MARKET) { //--- If there is no position, first open a position and then set Stop Loss and Take Profit if(!pos.exists) { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,0,0,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); //--- Get the flag of presence/absence of the position pos.exists=PositionSelect(_Symbol); //--- If the position exists if(pos.exists) { //--- Set Stop Loss and Take Profit if(!trade.PositionModify(_Symbol,sl,tp)) Print("Error modifying the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } } //--- If the position exists, increase its volume and leave the Stop Loss and Take Profit levels unchanged else { //--- If the position failed to open, print the relevant message if(!trade.PositionOpen(_Symbol,order_type,lot,price,sl,tp,comment)) Print("Error opening the position: ",GetLastError()," - ",ErrorDescription(GetLastError())); } } }
Hala olay işleme fonksiyonlarına nihai, çok önemli bir dokunuş eklememiz gerekiyor:
- OnInit
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- Adjust the input parameters CorrectInputParameters(); //--- Get indicator handles GetIndicatorHandle(); //--- Initialize the new bar CheckNewBar(); //--- Get the properties GetPositionProperties(P_ALL); //--- Set the info panel SetInfoPanel(); //--- return(0); }
- OnDeinit
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Print the deinitialization reason to the journal Print(GetDeinitReasonText(reason)); //--- When deleting from the chart if(reason==REASON_REMOVE) { //--- Delete all objects relating to the info panel from the chart DeleteInfoPanel(); //--- Delete the indicator handle IndicatorRelease(indicator_handle); } }
- OnTick
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- If the bar is not new, exit if(!CheckNewBar()) { if(IsVisualMode() || IsRealtime()) { //--- Get the properties and update the values on the panel GetPositionProperties(P_ALL); //--- Set/update the info panel SetInfoPanel(); } return; } //--- If there is a new bar else { //--- If trading is allowed if(CheckTradingPermission()==0) { if(!GetIndicatorsData()) return; GetBarsData(); // Get bar data TradingBlock(); // Check the conditions and trade ModifyTrailingStop(); // Modify the Trailing Stop level } } //--- Get the properties GetPositionProperties(P_ALL); //--- Update the info panel SetInfoPanel(); }
Artık tüm fonksiyonlar hazır olduğuna göre parametreleri optimize edebiliriz. Kodu ana program dosyasından derlemeniz gerektiğini unutmayın.
Parametreleri Optimize Etme ve Uzman Danışmanı Test Etme
Strateji Test Cihazı aşağıda gösterildiği gibi ayarlanmalıdır:
Şekil 1. Strateji Test Cihazı ayarları.
Ayrıca, Optimizasyon için Uzman Danışmanın parametrelerini ayarlıyoruz (ayrıca ayarları içeren ekteki *.set dosyasına bakın):
Şekil 2. Uzman Danışmanın Ayarları.
Optimizasyon, çift çekirdekli bir işlemcide yaklaşık 40 dakika sürmüştür. Optimizasyon grafiği, kâr bölgesindeki sonuçlara dayalı olarak bir alım satım sisteminin kalitesini kısmen değerlendirmenize olanak sağlar:
Şekil 3. Optimizasyon grafiği.
Maksimum kurtarma faktörü test sonuçları aşağıdaki gibidir:
Şekil 4. Maksimum kurtarma faktörü test sonuçları
Sonuç
Uzman Danışmanın kaynak kodlarını içeren indirilebilir arşiv makaleye eklenmiştir. Çıkarıldıktan sonra \TestIndicatorConditions dosya klasörünü <Metatrader 5 terminal>\MQL5\Experts içine yerleştirmelisiniz. Uzman Danışmanın doğru çalışmasını sağlamak için MultiRange_PCH göstergesi indirilmeli ve <Metatrader 5 terminal>\MQL5\Indicators içine yerleştirilmelidir.
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/645





- Ü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