
MQL5 Yemek Kitabı - Çok Para Birimli Expert Advisor ve MQL5'te Bekleyen Talimatlarla Çalışma
Giriş
Bu sefer, bekleyen Satın Al Durdur ve Sat Durdur talimatlarıyla çalışmayı temel alan bir alım satım algoritmasına sahip çok para birimli bir Expert Advisor oluşturacağız. Oluşturacağımız formasyon gün içi alım satım/testler için tasarlanacaktır. Makale aşağıdaki konuları ele almaktadır:
- Belirli bir zaman aralığında alım satım. Alım satımın başlangıç ve bitiş zamanını ayarlamamızı sağlayacak bir özellik oluşturalım. Örneğin Avrupa veya Amerika alım satım seanslarının zamanı olabilir. Expert Advisor'ın parametrelerini optimize ederken elbette en uygun zaman aralığını bulma fırsatı olacaktır.
- Bekleyen talimatları yerleştirme/değiştirme/silme.
- Alım satım olaylarının işlenmesi: Son pozisyonun Kar Al veya Zarar Durdur'da kapatılıp kapatılmadığını kontrol etme ve her bir sembol için yatırımların geçmişi üzerinde kontrol.
Expert Advisor Geliştirme
MQL5 Yemek Kitabı: Çoklu Para Birimi Expert Advisor - Basit, Düzgün ve Hızlı yaklaşım makalesindeki kodu şablon olarak kullanacağız. Formasyonun temel yapısı aynı kalacak olsa da, bazı önemli değişiklikler yapılacaktır. Expert Advisor, gün içi alım satım için tasarlanacaktır ancak bu mod, ihtiyaç duyulduğunda kapatılabilir. Bu durumda, bir pozisyon kapatılmışsa bekleyen talimatlar her zaman hemen (Yeni Çubuk olayında) verilecektir.
Expert Advisor harici parametreleriyle başlayalım. İlk başta, Enums.mqh ekleme dosyasında yeni bir numaralandırma ENUM_HOURS oluşturacağız. Bu numaralandırmadaki tanımlayıcıların sayısı, bir gündeki saat sayısına eşittir:
//--- Hours Enumeration enum ENUM_HOURS { h00 = 0, // 00 : 00 h01 = 1, // 01 : 00 h02 = 2, // 02 : 00 h03 = 3, // 03 : 00 h04 = 4, // 04 : 00 h05 = 5, // 05 : 00 h06 = 6, // 06 : 00 h07 = 7, // 07 : 00 h08 = 8, // 08 : 00 h09 = 9, // 09 : 00 h10 = 10, // 10 : 00 h11 = 11, // 11 : 00 h12 = 12, // 12 : 00 h13 = 13, // 13 : 00 h14 = 14, // 14 : 00 h15 = 15, // 15 : 00 h16 = 16, // 16 : 00 h17 = 17, // 17 : 00 h18 = 18, // 18 : 00 h19 = 19, // 19 : 00 h20 = 20, // 20 : 00 h21 = 21, // 21 : 00 h22 = 22, // 22 : 00 h23 = 23 // 23 : 00 };
Ardından, harici parametreler listesinde bir zaman aralığında alım satımla ilgili dört parametre oluşturacağız:
- TradeInTimeRange modu etkinleştirme/devre dışı bırakma. Daha önce de belirtildiği gibi, Expert Advisor'ın çalışmasını sadece belirli bir zaman aralığında değil, aynı zamanda günün her saatinde yani sürekli modda mümkün kılacağız.
- 1>StartTrade - bir alım satım oturumunun başladığı saat. Sunucu süresi bu değere eşit olur olmaz, Expert Advisor, TradeInTimeRange modunun açık olması şartıyla bekleyen talimatları verecektir.
- StopOpenOrders - talimat vermenin bitiş saati. Sunucu süresi bu değere eşit olduğunda, bir pozisyon kapalıysa Expert Advisor bekleyen talimat vermeyi durdurur.
- EndTrade - bir alım satım seansının durduğu saat. Sunucu süresi bu değere eşit olduğunda, Expert Advisor alım satımı durdurur. Belirtilen sembol için açık bir pozisyon kapatılacak ve bekleyen talimatlar silinecektir.
Harici parametrelerin listesi aşağıda gösterildiği gibi görünecektir. Verilen örnek iki sembol içindir. PendingOrder parametresinde, mevcut fiyattan puan olarak bir mesafe belirledik.
//--- External parameters of the Expert Advisor sinput long MagicNumber = 777; // Magic number sinput int Deviation = 10; // Slippage //--- sinput string delimeter_00=""; // -------------------------------- sinput string Symbol_01 ="EURUSD"; // Symbol 1 input bool TradeInTimeRange_01 =true; // | Trading in a time range input ENUM_HOURS StartTrade_01 = h10; // | The hour of the beginning of a trading session input ENUM_HOURS StopOpenOrders_01 = h17; // | The hour of the end of placing orders input ENUM_HOURS EndTrade_01 = h22; // | The hour of the end of a trading session input double PendingOrder_01 = 50; // | Pending order input double TakeProfit_01 = 100; // | Take Profit input double StopLoss_01 = 50; // | Stop Loss input double TrailingStop_01 = 10; // | Trailing Stop input bool Reverse_01 = true; // | Position reversal input double Lot_01 = 0.1; // | Lot //--- sinput string delimeter_01=""; // -------------------------------- sinput string Symbol_02 ="AUDUSD"; // Symbol 2 input bool TradeInTimeRange_02 =true; // | Trading in a time range input ENUM_HOURS StartTrade_02 = h10; // | The hour of the beginning of a trading session input ENUM_HOURS StopOpenOrders_02 = h17; // | The hour of the end of placing orders input ENUM_HOURS EndTrade_02 = h22; // | The hour of the end of a trading session input double PendingOrder_02 = 50; // | Pending order input double TakeProfit_02 = 100; // | Take Profit input double StopLoss_02 = 50; // | Stop Loss input double TrailingStop_02 = 10; // | Trailing Stop input bool Reverse_02 = true; // | Position reversal input double Lot_02 = 0.1; // | Lot
Ayrıca, harici parametrelerin değerleriyle doldurulacak diziler listesinde ilgili değişiklikler yapılmalıdır:
//--- Arrays for storing external parameters string Symbols[NUMBER_OF_SYMBOLS]; // Symbol bool TradeInTimeRange[NUMBER_OF_SYMBOLS]; // Trading in a time range ENUM_HOURS StartTrade[NUMBER_OF_SYMBOLS]; // The hour of the beginning of a trading session ENUM_HOURS StopOpenOrders[NUMBER_OF_SYMBOLS]; // The hour of the end of placing orders ENUM_HOURS EndTrade[NUMBER_OF_SYMBOLS]; // The hour of the end of a trading session double PendingOrder[NUMBER_OF_SYMBOLS]; // Pending order double TakeProfit[NUMBER_OF_SYMBOLS]; // Take Profit double StopLoss[NUMBER_OF_SYMBOLS]; // Stop Loss double TrailingStop[NUMBER_OF_SYMBOLS]; // Trailing Stop bool Reverse[NUMBER_OF_SYMBOLS]; // Position Reversal double Lot[NUMBER_OF_SYMBOLS]; // Lot
Şimdi ters çevirme modunda (Ters parametre değeri doğru) bekleyen talimatlardan biri tetiklendiğinde karşıdaki bekleyen talimatın silinmesini ve yeniden verilmesini ayarlayacağız. Bekleyen talimatın fiyat seviyelerini (talimat fiyatı, Zararı Durdur, Kar Al) değiştirmesi durumunda yapacağımız gibi hacmini değiştiremeyiz. Bu nedenle, onu silmeli ve gerekli hacimde yeni bir bekleyen talimat vermeliyiz.
Ayrıca, aynı anda tersine çevirme modu etkinleştirilirse ve Takip Durdurma seviyesi ayarlanırsa, bekleyen talimat fiyatı takip eder. Bunun üzerine Zararı Durdur verilirse bekleyen talimata göre fiyat değeri hesaplanacak ve belirlenecektir.
Global kapsamda, bekleyen talimat yorumları için iki dize değişkeni oluşturalım:
//--- Pending order comments string comment_top_order ="top_order"; string comment_bottom_order ="bottom_order";
Expert Advisor yüklemesi sırasında OnInit() işlevindeki başlatmada, harici parametrelerin doğruluğunu kontrol edeceğiz. Değerlendirme kriterleri aşağıdaki gibidir. TradeInTimeRange modu etkinleştirildiğinde, bir alım satım seansının başlangıç saati, bekleyen talimatların verme bitiş saatinden bir saatten az olmamalıdır. Bekleyen talimat verme bitiş saati, bir alım satım seansının bitiş saatinden bir saattem daha az olmamalıdır. Böyle bir kontrolü yapacak CheckInputParameters() işlevini yazalım:
//+------------------------------------------------------------------+ //| Checks external parameters | //+------------------------------------------------------------------+ bool CheckInputParameters() { //--- Loop through the specified symbols for(int s=0; s<NUMBER_OF_SYMBOLS; s++) { //--- If there is no symbol and the TradeInTimeRange mode is disabled, move on to the following symbol. if(Symbols[s]=="" || !TradeInTimeRange[s]) continue; //--- Check the accuracy of the start and the end of a trade session time if(StartTrade[s]>=EndTrade[s]) { Print(Symbols[s], ": The hour of the beginning of a trade session("+IntegerToString(StartTrade[s])+") " "must be less than the hour of the end of a trade session"("+IntegerToString(EndTrade[s])+")!"); return(false); } //--- A trading session is to start no later that one hour before the hour of placing pending orders. // Pending orders are to be placed no later than one hour before the hour of the end of a trading session. if(StopOpenOrders[s]>=EndTrade[s] || StopOpenOrders[s]<=StartTrade[s]) { Print(Symbols[s], ": The hour of the end of placing orders ("+IntegerToString(StopOpenOrders[s])+") " "is to be less than the hour of the end ("+IntegerToString(EndTrade[s])+") and " "greater than the hour of the beginning of a trading session ("+IntegerToString(StartTrade[s])+")!"); return(false); } } //--- Parameters are correct return(true); }
Bu formasyonu uygulamak için alım satım ve bekleyen talimatlar vermek için belirtilen zaman aralıklarında kalmak amacıyla kontrolleri gerçekleştirecek işlevlere ihtiyacımız olacak. Bu işlevleri IsInTradeTimeRange() ve IsInOpenOrdersTimeRange() olarak adlandıracağız. İkisi de aynı şekilde çalışır, tek fark kontrol edilen aralığın üst sınırındadır. İleride bu işlevlerin nerede kullanılacağını göreceğiz.
//+------------------------------------------------------------------+ //| Checks if we are within the time range for trade | //+------------------------------------------------------------------+ bool IsInTradeTimeRange(int symbol_number) { //--- If TradeInTimeRange mode is enabled if(TradeInTimeRange[symbol_number]) { //--- Structure of the date and time MqlDateTime last_date; //--- Get the last value of the date and time data set TimeTradeServer(last_date); //--- Outside of the allowed time range if(last_date.hour<StartTrade[symbol_number] || last_date.hour>=EndTrade[symbol_number]) return(false); } //--- Within the allowed time range return(true); } //+------------------------------------------------------------------+ //| Checks if we are within the time range for placing orders | //+------------------------------------------------------------------+ bool IsInOpenOrdersTimeRange(int symbol_number) { //--- If the TradeInTimeRange mode if enabled if(TradeInTimeRange[symbol_number]) { //--- Structure of the date and time MqlDateTime last_date; //--- Get the last value of the date and time data set TimeTradeServer(last_date); //--- Outside the allowed time range if(last_date.hour<StartTrade[symbol_number] || last_date.hour>=StopOpenOrders[symbol_number]) return(false); } //--- Within the allowed time range return(true); }
Önceki makaleler, pozisyon, sembol ve yatırım geçmişi özelliklerini almak amacıyla işlevleri hali hazırda ele alınmıştı. Bu makalede, bekleyen bir talimatın özelliklerini almak için benzer bir işleve ihtiyacımız olacak. Enums.mqh ekleme dosyasında, bekleyen bir talimatın özelliklerini içeren bir numaralandırma oluşturacağız:
//--- Enumeration of the properties of a pending order enum ENUM_ORDER_PROPERTIES { O_SYMBOL = 0, O_MAGIC = 1, O_COMMENT = 2, O_PRICE_OPEN = 3, O_PRICE_CURRENT = 4, O_PRICE_STOPLIMIT = 5, O_VOLUME_INITIAL = 6, O_VOLUME_CURRENT = 7, O_SL = 8, O_TP = 9, O_TIME_SETUP = 10, O_TIME_EXPIRATION = 11, O_TIME_SETUP_MSC = 12, O_TYPE_TIME = 13, O_TYPE = 14, O_ALL = 15 };
Daha sonra, TradeFunctions.mqh ekleme dosyasında bekleyen bir talimatın özelliklerine sahip bir yapı yazmamız ve ardından onu başlatmamız gerekiyor:
//-- Properties of a pending order struct pending_order_properties { string symbol; // Symbol long magic; // Magic number string comment; // Comment double price_open; // Price specified in the order double price_current; // Current price of the order symbol double price_stoplimit; // Limit order price for the Stop Limit order double volume_initial; // Initial order volume double volume_current; // Current order volume double sl; // Stop Loss level double tp; // Take Profit level datetime time_setup; // Order placement time datetime time_expiration; // Order expiration time datetime time_setup_msc; // The time of placing an order for execution in milliseconds since 01.01.1970 datetime type_time; // Order lifetime ENUM_ORDER_TYPE type; // Position type }; //--- Variable of the order features pending_order_properties ord;
Bekleyen bir talimatın bir özelliğini veya hatta tüm özelliklerini almak için GetPendingOrderProperties() işlevini yazacağız. Bekleyen talimat seçildikten sonra talimatın özelliklerini almak için bu işlevi kullanabiliriz. Bunu yapmanın yolu aşağıda daha ayrıntılı olarak açıklanacaktır.
//+------------------------------------------------------------------+ //| Retrieves the properties of the previously selected pending order| //+------------------------------------------------------------------+ void GetPendingOrderProperties(ENUM_ORDER_PROPERTIES order_property) { switch(order_property) { case O_SYMBOL : ord.symbol=OrderGetString(ORDER_SYMBOL); break; case O_MAGIC : ord.magic=OrderGetInteger(ORDER_MAGIC); break; case O_COMMENT : ord.comment=OrderGetString(ORDER_COMMENT); break; case O_PRICE_OPEN : ord.price_open=OrderGetDouble(ORDER_PRICE_OPEN); break; case O_PRICE_CURRENT : ord.price_current=OrderGetDouble(ORDER_PRICE_CURRENT); break; case O_PRICE_STOPLIMIT : ord.price_stoplimit=OrderGetDouble(ORDER_PRICE_STOPLIMIT); break; case O_VOLUME_INITIAL : ord.volume_initial=OrderGetDouble(ORDER_VOLUME_INITIAL); break; case O_VOLUME_CURRENT : ord.volume_current=OrderGetDouble(ORDER_VOLUME_CURRENT); break; case O_SL : ord.sl=OrderGetDouble(ORDER_SL); break; case O_TP : ord.tp=OrderGetDouble(ORDER_TP); break; case O_TIME_SETUP : ord.time_setup=(datetime)OrderGetInteger(ORDER_TIME_SETUP); break; case O_TIME_EXPIRATION : ord.time_expiration=(datetime)OrderGetInteger(ORDER_TIME_EXPIRATION); break; case O_TIME_SETUP_MSC : ord.time_setup_msc=(datetime)OrderGetInteger(ORDER_TIME_SETUP_MSC); break; case O_TYPE_TIME : ord.type_time=(datetime)OrderGetInteger(ORDER_TYPE_TIME); break; case O_TYPE : ord.type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); break; case O_ALL : ord.symbol=OrderGetString(ORDER_SYMBOL); ord.magic=OrderGetInteger(ORDER_MAGIC); ord.comment=OrderGetString(ORDER_COMMENT); ord.price_open=OrderGetDouble(ORDER_PRICE_OPEN); ord.price_current=OrderGetDouble(ORDER_PRICE_CURRENT); ord.price_stoplimit=OrderGetDouble(ORDER_PRICE_STOPLIMIT); ord.volume_initial=OrderGetDouble(ORDER_VOLUME_INITIAL); ord.volume_current=OrderGetDouble(ORDER_VOLUME_CURRENT); ord.sl=OrderGetDouble(ORDER_SL); ord.tp=OrderGetDouble(ORDER_TP); ord.time_setup=(datetime)OrderGetInteger(ORDER_TIME_SETUP); ord.time_expiration=(datetime)OrderGetInteger(ORDER_TIME_EXPIRATION); ord.time_setup_msc=(datetime)OrderGetInteger(ORDER_TIME_SETUP_MSC); ord.type_time=(datetime)OrderGetInteger(ORDER_TYPE_TIME); ord.type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); break; //--- default: Print("Retrieved feature of the pending order was not taken into account in the enumeration "); return; } }
Şimdi bekleyen talimatları yerleştirmek, değiştirmek ve silmek için temel işlevleri yazacağız. SetPendingOrder() işlevi bekleyen bir talimat verir. Bekleyen talimat verilemediyse söz konusu işlev, bir hata kodunu ve açıklamasını günlüğe girecektir:
//+------------------------------------------------------------------+ //| Places a pending order | //+------------------------------------------------------------------+ void SetPendingOrder(int symbol_number, // Symbol number ENUM_ORDER_TYPE order_type, // Order type double lot, // Volume double stoplimit_price, // Level of the StopLimit order double price, // Price double sl, // Stop Loss double tp, // Take Profit ENUM_ORDER_TYPE_TIME type_time, // Order Expiration string comment) // Comment //--- Set magic number in the trade structure trade.SetExpertMagicNumber(MagicNumber); //--- If a pending order failed to be placed, print an error message if(!trade.OrderOpen(Symbols[symbol_number], order_type,lot,stoplimit_price,price,sl,tp,type_time,0,comment)) Print("Error when placing a pending order: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
ModifyPendingOrder() işlevi bekleyen bir talimatı değiştirir. Talimatın sadece fiyatını değil, hacmini de değiştirebileceğimiz ve işlevin son parametresi olarak geçebileceğimiz şekilde düzenleyeceğiz. Geçilen hacim değeri sıfırdan büyükse, bekleyen talimatın silinmesi ve gerekli hacim değerine sahip yeni bir talimatın verilmesi gerektiği anlamına gelir. Diğer tüm durumlarda, basitçe fiyat değerini değiştirerek mevcut talimatı değiştiririz.
//+------------------------------------------------------------------+ //| Modifies a pending order | //+------------------------------------------------------------------+ void ModifyPendingOrder(int symbol_number, //Symbol number ulong ticket, // Order ticket ENUM_ORDER_TYPE type, // Order type double price, // Order price double sl, // Stop Loss of the order double tp, // Take Profit of the order ENUM_ORDER_TYPE_TIME type_time, // Order expiration datetime time_expiration, // Order expiration time double stoplimit_price, // Price string comment, // Comment double volume) // Volume { //--- If the passed volume value is non-zero, delete the order and place it again if(volume>0) { //--- If the order failed to be deleted, exit if(!DeletePendingOrder(ticket)) return; //--- Place a pending order SetPendingOrder(symbol_number,type,volume,0,price,sl,tp,type_time,comment); //--- Adjust Stop Loss of position as related to the order CorrectStopLossByOrder(symbol_number,price,type); } //--- If the passed volume value is zero, modify the order else { //--- If the pending order failed to be modified, print a relevant message if(!trade.OrderModify(ticket,price,sl,tp,type_time,time_expiration,stoplimit_price)) Print("Error when modifying the pending order price: ", GetLastError()," - ",ErrorDescription(GetLastError())); //--- Otherwise adjust Stop Loss of position as related to the order else CorrectStopLossByOrder(symbol_number,price,type); } }
Yukarıdaki kodda vurgulanan iki yeni işlev DeletePendingOrder() ve CorrectStopLossByOrder(). İlki bekleyen bir talimatı siler, ikincisi ise bekleyen talimatla ilgili olarak pozisyonun Zararı Durdur'unu ayarlar.
//+------------------------------------------------------------------+ //| Deletes a pending order | //+------------------------------------------------------------------+ bool DeletePendingOrder(ulong ticket) { //--- If a pending order failed to get deleted, print a relevant message if(!trade.OrderDelete(ticket)) { Print("Error when deleting a pending order: ",GetLastError()," - ",ErrorDescription(GetLastError())); return(false); } //--- return(true); } //+------------------------------------------------------------------+ //| Modifies StopLoss of the position as related to the pending order| //+------------------------------------------------------------------+ void CorrectStopLossByOrder(int symbol_number, // Symbol number double price, // Order Price ENUM_ORDER_TYPE type) // Order Type { //--- If Stop Loss disabled, exit if(StopLoss[symbol_number]==0) return; //--- If Stop Loss enabled double new_sl=0.0; // New Stop Loss value //--- Get a Point value GetSymbolProperties(symbol_number,S_POINT); //--- Number of decimal places GetSymbolProperties(symbol_number,S_DIGITS); //--- Get Take Profit of position GetPositionProperties(symbol_number,P_TP); //--- Calculate as related to the order type switch(type) { case ORDER_TYPE_BUY_STOP : new_sl=NormalizeDouble(price+CorrectValueBySymbolDigits(StopLoss[symbol_number]*symb.point),symb.digits); break; case ORDER_TYPE_SELL_STOP : new_sl=NormalizeDouble(price-CorrectValueBySymbolDigits(StopLoss[symbol_number]*symb.point),symb.digits); break; } //--- Modify the position if(!trade.PositionModify(Symbols[symbol_number],new_sl,pos.tp)) Print("Error when modifying position: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
Bekleyen bir talimat vermeden önce, aynı yorumlara sahip bekleyen bir talimat olup olmadığını da kontrol etmek gerekir. Bu makalenin başında belirtildiği gibi, en üstteki Satın Almayı Durdur talimatını "top_order" yorumuyla ve Satışı Durdur talimatını "bottom_order" yorumuyla vereceğiz. Böyle bir kontrolü kolaylaştırmak için CheckPendingOrderByComment() adında bir işlev yazalım:
//+------------------------------------------------------------------+ //| Checks existence of a pending order by a comment | //+------------------------------------------------------------------+ bool CheckPendingOrderByComment(int symbol_number,string comment) { int total_orders =0; // Total number of pending orders string order_symbol =""; // Order Symbol string order_comment =""; // Order Comment //--- Get the total number of pending orders total_orders=OrdersTotal(); //--- Loop through the total orders for(int i=total_orders-1; i>=0; i--) { //---Select the order by the ticket if(OrderGetTicket(i)>0) { //--- Get the symbol name order_symbol=OrderGetString(ORDER_SYMBOL); //--- If the symbols are equal if(order_symbol==Symbols[symbol_number]) { //--- Get the order comment order_comment=OrderGetString(ORDER_COMMENT); //--- If the comments are equal if(order_comment==comment) return(true); } } } //--- Order with a specified comment not found return(false); }
Yukarıdaki kod, toplam talimat sayısının OrdersTotal() sistem işlevi kullanılarak elde edilebileceğini gösterir. Ancak, belirli bir sembol için toplam bekleyen talimat sayısını elde etmek için kullanıcı tanımlı bir işlev yazacağız. Adını OrdersTotalBySymbol() koyacağız:
//+------------------------------------------------------------------+ //| Returns the total number of orders for the specified symbol | //+------------------------------------------------------------------+ int OrdersTotalBySymbol(string symbol) { int count =0; // Order counter int total_orders =0; // Total number of pending orders //--- Get the total number of pending orders total_orders=OrdersTotal(); //--- Loop through the total number of orders for(int i=total_orders-1; i>=0; i--) { //--- If an order has been selected if(OrderGetTicket(i)>0) { //--- Get the order symbol GetOrderProperties(O_SYMBOL); //--- If the order symbol and the specified symbol are equal if(ord.symbol==symbol) //--- Increase the counter count++; } } //--- Return the total number of orders return(count); }
Bekleyen bir talimat vermeden önce bunun için bir fiyat ve gerekirse Zararı Durdur ve Kar Al seviyelerini hesaplamak gerekir. Geri dönüş modu etkinleştirilirse Takip Durdurma seviyelerini yeniden hesaplamak ve değiştirmek için ayrı kullanıcı tanımlı işlevlere ihtiyacımız olacaktır.
Bekleyen bir talimat fiyatını hesaplamak için CalculatePendingOrder() işlevini yazalım:
//+------------------------------------------------------------------+ //| Calculates the pending order level(price) | //+------------------------------------------------------------------+ double CalculatePendingOrder(int symbol_number,ENUM_ORDER_TYPE order_type) { //--- For the calculated pending order value double price=0.0; //--- If the value for SELL STOP order is to be calculated if(order_type==ORDER_TYPE_SELL_STOP) { //--- Calculate level price=NormalizeDouble(symb.bid-CorrectValueBySymbolDigits(PendingOrder[symbol_number]*symb.point),symb.digits); //--- Return calculated value if it is less than the lower limit of Stops level // If the value is equal or greater, return the adjusted value return(price<symb.down_level ? price : symb.down_level-symb.offset); } //--- If the value for BUY STOP order is to be calculated if(order_type==ORDER_TYPE_BUY_STOP) { //--- Calculate level price=NormalizeDouble(symb.ask+CorrectValueBySymbolDigits(PendingOrder[symbol_number]*symb.point),symb.digits); //--- Return the calculated value if it is greater than the upper limit of Stops level // If the value is equal or less, return the adjusted value return(price>symb.up_level ? price : symb.up_level+symb.offset); } //--- return(0.0); }
Aşağıda, bekleyen bir talimatta Zararı Durdur ve Kar Al seviyelerini hesaplamak için işlev kodu bulunmaktadır.
//+------------------------------------------------------------------+ //| Calculates Stop Loss level for a pending order | //+------------------------------------------------------------------+ double CalculatePendingOrderStopLoss(int symbol_number,ENUM_ORDER_TYPE order_type,double price) { //--- If Stop Loss is required if(StopLoss[symbol_number]>0) { double sl =0.0; // For the Stop Loss calculated value double up_level =0.0; // Upper limit of Stop Levels double down_level =0.0; // Lower limit of Stop Levels //--- If the value for BUY STOP order is to be calculated if(order_type==ORDER_TYPE_BUY_STOP) { //--- Define lower threshold down_level=NormalizeDouble(price-symb.stops_level*symb.point,symb.digits); //--- Calculate level sl=NormalizeDouble(price-CorrectValueBySymbolDigits(StopLoss[symbol_number]*symb.point),symb.digits); //--- Return the calculated value if it is less than the lower limit of Stop level // If the value is equal or greater, return the adjusted value return(sl<down_level ? sl : NormalizeDouble(down_level-symb.offset,symb.digits)); } //--- If the value for the SELL STOP order is to be calculated if(order_type==ORDER_TYPE_SELL_STOP) { //--- Define the upper threshold up_level=NormalizeDouble(price+symb.stops_level*symb.point,symb.digits); //--- Calculate the level sl=NormalizeDouble(price+CorrectValueBySymbolDigits(StopLoss[symbol_number]*symb.point),symb.digits); //--- Return the calculated value if it is greater than the upper limit of the Stops level // If the value is less or equal, return the adjusted value. return(sl>up_level ? sl : NormalizeDouble(up_level+symb.offset,symb.digits)); } } //--- return(0.0); } //+------------------------------------------------------------------+ //| Calculates the Take Profit level for a pending order | //+------------------------------------------------------------------+ double CalculatePendingOrderTakeProfit(int symbol_number,ENUM_ORDER_TYPE order_type,double price) { //--- If Take Profit is required if(TakeProfit[symbol_number]>0) { double tp =0.0; // For the calculated Take Profit value double up_level =0.0; // Upper limit of Stop Levels double down_level =0.0; // Lower limit of Stop Levels //--- If the value for SELL STOP order is to be calculated if(order_type==ORDER_TYPE_SELL_STOP) { //--- Define lower threshold down_level=NormalizeDouble(price-symb.stops_level*symb.point,symb.digits); //--- Calculate the level tp=NormalizeDouble(price-CorrectValueBySymbolDigits(TakeProfit[symbol_number]*symb.point),symb.digits); //--- Return the calculated value if it is less than the below limit of the Stops level // If the value is greater or equal, return the adjusted value return(tp<down_level ? tp : NormalizeDouble(down_level-symb.offset,symb.digits)); } //--- If the value for the BUY STOP order is to be calculated if(order_type==ORDER_TYPE_BUY_STOP) { //--- Define the upper threshold up_level=NormalizeDouble(price+symb.stops_level*symb.point,symb.digits); //--- Calculate the level tp=NormalizeDouble(price+CorrectValueBySymbolDigits(TakeProfit[symbol_number]*symb.point),symb.digits); //--- Return the calculated value if it is greater than the upper limit of the Stops level // If the value is less or equal, return the adjusted value return(tp>up_level ? tp : NormalizeDouble(up_level+symb.offset,symb.digits)); } } //--- return(0.0); }
Ters çevrilmiş bekleyen bir talimatın Durdurma seviyesini (fiyatını) hesaplamak ve onu yukarı çekmek için aşağıdaki CalculateReverseOrderTrailingStop() ve ModifyPendingOrderTrailingStop() işlevlerini yazacağız. İşlevlerin kodlarını aşağıda bulabilirsiniz.
CalculateReverseOrderTrailingStop() işlevinin kodu:
//+----------------------------------------------------------------------------+ //| Calculates the Trailing Stop level for the reversed order | //+----------------------------------------------------------------------------+ double CalculateReverseOrderTrailingStop(int symbol_number,ENUM_POSITION_TYPE position_type) { //--- Variables for calculation double level =0.0; double buy_point =low[symbol_number].value[1]; // Low value for Buy double sell_point =high[symbol_number].value[1]; // High value for Sell //--- Calculate the level for the BUY position if(position_type==POSITION_TYPE_BUY) { //--- Bar's low minus the specified number of points level=NormalizeDouble(buy_point-CorrectValueBySymbolDigits(PendingOrder[symbol_number]*symb.point),symb.digits); //--- If the calculated level is lower than the lower limit of the Stops level, // the calculation is complete, return the current value of the level if(level<symb.down_level) return(level); //--- If it is not lower, try to calculate based on the bid price else { level=NormalizeDouble(symb.bid-CorrectValueBySymbolDigits(PendingOrder[symbol_number]*symb.point),symb.digits); //--- If the calculated level is lower than the limit, return the current value of the level // otherwise set the nearest possible value return(level<symb.down_level ? level : symb.down_level-symb.offset); } } //--- Calculate the level for the SELL position if(position_type==POSITION_TYPE_SELL) { // Bar's high plus the specified number of points level=NormalizeDouble(sell_point+CorrectValueBySymbolDigits(PendingOrder[symbol_number]*symb.point),symb.digits); //--- If the calculated level is higher than the upper limit of the Stops level, // then the calculation is complete, return the current value of the level if(level>symb.up_level) return(level); //--- If it is not higher, try to calculate based on the ask price else { level=NormalizeDouble(symb.ask+CorrectValueBySymbolDigits(PendingOrder[symbol_number]*symb.point),symb.digits); //--- If the calculated level is higher than the limit, return the current value of the level // Otherwise set the nearest possible value return(level>symb.up_level ? level : symb.up_level+symb.offset); } } //--- return(0.0); }
ModifyPendingOrderTrailingStop() işlevinin kodu:
//+------------------------------------------------------------------+ //| Modifying the Trailing Stop level for a pending order | //+------------------------------------------------------------------+ void ModifyPendingOrderTrailingStop(int symbol_number) { //--- Exit, if the reverse position mode is disabled and Trailing Stop is not set if(!Reverse[symbol_number] || TrailingStop[symbol_number]==0) return; //--- double new_level =0.0; // For calculating a new level for a pending order bool condition =false; // For checking the modification condition int total_orders =0; // Total number of pending orders ulong order_ticket =0; // Order ticket string opposite_order_comment =""; // Opposite order comment ENUM_ORDER_TYPE opposite_order_type =WRONG_VALUE; // Order type //--- Get the flag of presence/absence of a position pos.exists=PositionSelect(Symbols[symbol_number]); //--- If a position is absent if(!pos.exists) return; //--- Get a total number of pending orders total_orders=OrdersTotal(); //--- Get the symbol properties GetSymbolProperties(symbol_number,S_ALL); //--- Get the position properties GetPositionProperties(symbol_number,P_ALL); //--- Get the level for Stop Loss new_level=CalculateReverseOrderTrailingStop(symbol_number,pos.type); //--- Loop through the orders from the last to the first one for(int i=total_orders-1; i>=0; i--) { //--- If the order selected if((order_ticket=OrderGetTicket(i))>0) { //--- Get the order symbol GetPendingOrderProperties(O_SYMBOL); //--- Get the order comment GetPendingOrderProperties(O_COMMENT); //--- Get the order price GetPendingOrderProperties(O_PRICE_OPEN); //--- Depending on the position type, check the relevant condition for the Trailing Stop modification switch(pos.type) { case POSITION_TYPE_BUY : //---If the new order value is greater than the current value plus set step then condition fulfilled condition=new_level>ord.price_open+CorrectValueBySymbolDigits(TrailingStop[symbol_number]*symb.point); //--- Define the type and comment of the reversed pending order for check. opposite_order_type =ORDER_TYPE_SELL_STOP; opposite_order_comment =comment_bottom_order; break; case POSITION_TYPE_SELL : //--- If the new value for the order if less than the current value minus a set step then condition fulfilled condition=new_level<ord.price_open-CorrectValueBySymbolDigits(TrailingStop[symbol_number]*symb.point); //--- Define the type and comment of the reversed pending order for check opposite_order_type =ORDER_TYPE_BUY_STOP; opposite_order_comment =comment_top_order; break; } //--- If condition fulfilled, the order symbol and positions are equal // and order comment and the reversed order comment are equal if(condition && ord.symbol==Symbols[symbol_number] && ord.comment==opposite_order_comment) { double sl=0.0; // Stop Loss double tp=0.0; // Take Profit //--- Get Take Profit and Stop Loss levels sl=CalculatePendingOrderStopLoss(symbol_number,opposite_order_type,new_level); tp=CalculatePendingOrderTakeProfit(symbol_number,opposite_order_type,new_level); //--- Modify order ModifyPendingOrder(symbol_number,order_ticket,opposite_order_type,new_level,sl,tp, ORDER_TIME_GTC,ord.time_expiration,ord.price_stoplimit,ord.comment,0); return; } } } }
Bazen bir pozisyonun Zararı Durdur veya Kar Al'da kapatılıp kapatılmadığını öğrenmek gerekebilir. Bu özel durumda böyle bir gereksinimle karşılaşacağız. Bu nedenle son yatırım yorumu ile bu olayı tanımlayacak işlevleri yazalım. Belirtilen bir sembol için son yatırım yorumunu almak için GetLastDealComment() adında ayrı bir işlev yazacağız:
//+------------------------------------------------------------------+ //| Returns a the last deal comment for a specified symbol | //+------------------------------------------------------------------+ string GetLastDealComment(int symbol_number) { int total_deals =0; // Total number of deals in the selected history string deal_symbol =""; // Deal symbol string deal_comment =""; // Deal comment //--- If the deals history retrieved if(HistorySelect(0,TimeCurrent())) { //--- Receive the number of deals in the retrieved list total_deals=HistoryDealsTotal(); //--- Loop though the total number of deals in the retrieved list from the last deal to the first one. for(int i=total_deals-1; i>=0; i--) { //--- Receive the deal comment deal_comment=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_COMMENT); //--- Receive the deal symbol deal_symbol=HistoryDealGetString(HistoryDealGetTicket(i),DEAL_SYMBOL); //--- If the deal symbol and the current symbol are equal, stop the loop if(deal_symbol==Symbols[symbol_number]) break; } } //--- return(deal_comment); }
Belirtilen sembol için son pozisyonun kapanma nedenini belirleyecek işlevleri yazmak artık çok kolay. IsClosedByTakeProfit() ve IsClosedByStopLoss() işlevlerinin kodları aşağıdadır:
//+------------------------------------------------------------------+ //| Returns the reason for closing position at Take Profit | //+------------------------------------------------------------------+ bool IsClosedByTakeProfit(int symbol_number) { string last_comment=""; //--- Get the last deal comment for the specified symbol last_comment=GetLastDealComment(symbol_number); //--- If the comment contain a string "tp" if(StringFind(last_comment,"tp",0)>-1) return(true); //--- If the comment does not contain a string "tp" return(false); } //+------------------------------------------------------------------+ //| Returns the reason for closing position at Stop Loss | //+------------------------------------------------------------------+ bool IsClosedByStopLoss(int symbol_number) { string last_comment=""; //--- Get the last deal comment for the specified symbol last_comment=GetLastDealComment(symbol_number); //--- If the comment contains the string "sl" if(StringFind(last_comment,"sl",0)>-1) return(true); //--- If the comment does not contain the string "sl" return(false); }
Geçmişteki son yatırımın gerçekten belirtilen sembol için bir yatırım olup olmadığını belirlemek için başka bir kontrol yapacağız. Son yatırım biletini hafızada tutmak istiyoruz. Bunu başarmak için global kapsamda bir dizi ekleyeceğiz:
//--- Array for checking the ticket of the last deal for each symbol. ulong last_deal_ticket[NUMBER_OF_SYMBOLS];
Son yatırım biletini kontrol etmek için IsLastDealTicket() işlevi aşağıdaki kodda gösterildiği gibi görünecektir:
//+------------------------------------------------------------------+ //| Returns the event of the last deal for the specified symbol | //+------------------------------------------------------------------+ bool IsLastDealTicket(int symbol_number) { int total_deals =0; // Total number of deals in the selected history list string deal_symbol =""; // Deal symbol ulong deal_ticket =0; // Deal ticket //--- If the deal history was received if(HistorySelect(0,TimeCurrent())) { //--- Get the total number of deals in the received list total_deals=HistoryDealsTotal(); //--- Loop through the total number of deals from the last deal to the first one for(int i=total_deals-1; i>=0; i--) { //--- Get deal ticket deal_ticket=HistoryDealGetTicket(i); //--- Get deal symbol deal_symbol=HistoryDealGetString(deal_ticket,DEAL_SYMBOL); //--- If deal symbol and the current one are equal, stop the loop if(deal_symbol==Symbols[symbol_number]) { //--- If the tickets are equal, exit if(deal_ticket==last_deal_ticket[symbol_number]) return(false); //--- If the tickets are not equal report it else { //--- Save the last deal ticket last_deal_ticket[symbol_number]=deal_ticket; return(true); } } } } //--- return(false); }
Mevcut zaman belirtilen alım satım aralığının dışındaysa pozisyon zararda veya kârda olsa da kapanmaya zorlanacaktır. Bir pozisyonu kapatmak için ClosePosition() işlevini yazalım:
//+------------------------------------------------------------------+ //| Closes position | //+------------------------------------------------------------------+ void ClosePosition(int symbol_number) { //--- Check if position exists pos.exists=PositionSelect(Symbols[symbol_number]); //--- If there is no position, exit if(!pos.exists) return; //--- Set the slippage value in points trade.SetDeviationInPoints(CorrectValueBySymbolDigits(Deviation)); //--- If the position was not closed, print the relevant message if(!trade.PositionClose(Symbols[symbol_number])) Print("Error when closing position: ",GetLastError()," - ",ErrorDescription(GetLastError())); }
Bir pozisyon alım satım zaman aralığının dışına çıkarak kapatıldığında, bekleyen tüm talimatlar silinmelidir. Yazmak üzere olduğumuz DeleteAllPendingOrders() işlevi, belirtilen sembol için bekleyen tüm talimatları silecektir:
//+------------------------------------------------------------------+ //| Deletes all pending orders | //+------------------------------------------------------------------+ void DeleteAllPendingOrders(int symbol_number) { int total_orders =0; // Total number of pending orders ulong order_ticket =0; // Order ticket //--- Get the total number of pending orders total_orders=OrdersTotal(); //--- Loop through the total number of pending orders for(int i=total_orders-1; i>=0; i--) { //--- If the order selected if((order_ticket=OrderGetTicket(i))>0) { //--- Get the order symbol GetOrderProperties(O_SYMBOL); //--- If the order symbol and the current symbol are equal if(ord.symbol==Symbols[symbol_number]) //--- Delete the order DeletePendingOrder(order_ticket); } } }
Şimdi yapısal şema için gerekli tüm işlevlere sahibiz. Bazı önemli değişikliklerden geçen tanıdık TradingBlock() işlevine ve bekleyen talimatları yönetecek olan yeni ManagePendingOrders() işlevine bir göz atalım. Bekleyen talimatlarla ilgili mevcut durum üzerinde tam kontrol yapılacaktır.
Geçerli formasyon için TradingBlock() işlevi aşağıdaki gibi görünür:
//+------------------------------------------------------------------+ //| Trade block | //+------------------------------------------------------------------+ void TradingBlock(int symbol_number) { double tp=0.0; // Take Profit double sl=0.0; // Stop Loss double lot=0.0; // Volume for position calculation in case of reversed position double order_price=0.0; // Price for placing the order ENUM_ORDER_TYPE order_type=WRONG_VALUE; // Order type for opening position //--- If outside of the time range for placing pending orders if(!IsInOpenOrdersTimeRange(symbol_number)) return; //--- Find out if there is an open position for the symbol pos.exists=PositionSelect(Symbols[symbol_number]); //--- If there is no position if(!pos.exists) { //--- Get symbol properties GetSymbolProperties(symbol_number,S_ALL); //--- Adjust the volume lot=CalculateLot(symbol_number,Lot[symbol_number]); //--- If there is no upper pending order if(!CheckPendingOrderByComment(symbol_number,comment_top_order)) { //--- Get the price for placing a pending order order_price=CalculatePendingOrder(symbol_number,ORDER_TYPE_BUY_STOP); //--- Get Take Profit and Stop Loss levels sl=CalculatePendingOrderStopLoss(symbol_number,ORDER_TYPE_BUY_STOP,order_price); tp=CalculatePendingOrderTakeProfit(symbol_number,ORDER_TYPE_BUY_STOP,order_price); //--- Place a pending order SetPendingOrder(symbol_number,ORDER_TYPE_BUY_STOP,lot,0,order_price,sl,tp,ORDER_TIME_GTC,comment_top_order); } //--- If there is no lower pending order if(!CheckPendingOrderByComment(symbol_number,comment_bottom_order)) { //--- Get the price for placing the pending order order_price=CalculatePendingOrder(symbol_number,ORDER_TYPE_SELL_STOP); //--- Get Take Profit and Stop Loss levels sl=CalculatePendingOrderStopLoss(symbol_number,ORDER_TYPE_SELL_STOP,order_price); tp=CalculatePendingOrderTakeProfit(symbol_number,ORDER_TYPE_SELL_STOP,order_price); //--- Place a pending order SetPendingOrder(symbol_number,ORDER_TYPE_SELL_STOP,lot,0,order_price,sl,tp,ORDER_TIME_GTC,comment_bottom_order); } } }
Bekleyen talimatları yönetmek için ManagePendingOrders() işlevinin kodu:
//+------------------------------------------------------------------+ //| Manages pending orders | //+------------------------------------------------------------------+ void ManagePendingOrders() { //--- Loop through the total number of symbols for(int s=0; s<NUMBER_OF_SYMBOLS; s++) { //--- If trading this symbol is forbidden, go to the following one if(Symbols[s]=="") continue; //--- Find out if there is an open position for the symbol pos.exists=PositionSelect(Symbols[s]); //--- If there is no position if(!pos.exists) { //--- If the last deal on current symbol and // position was exited on Take Profit or Stop Loss if(IsLastDealTicket(s) && (IsClosedByStopLoss(s) || IsClosedByTakeProfit(s))) //--- Delete all pending orders for the symbol DeleteAllPendingOrders(s); //--- Go to the following symbol continue; } //--- If there is a position ulong order_ticket =0; // Order ticket int total_orders =0; // Total number of pending orders int symbol_total_orders =0; // Number of pending orders for the specified symbol string opposite_order_comment =""; // Opposite order comment ENUM_ORDER_TYPE opposite_order_type =WRONG_VALUE; // Order type //--- Get the total number of pending orders total_orders=OrdersTotal(); //--- Get the total number of pending orders for the specified symbol symbol_total_orders=OrdersTotalBySymbol(Symbols[s]); //--- Get symbol properties GetSymbolProperties(s,S_ASK); GetSymbolProperties(s,S_BID); //--- Get the comment for the selected position GetPositionProperties(s,P_COMMENT); //--- If the position comment belongs to the upper order, // then the lower order is to be deleted, modified/placed if(pos.comment==comment_top_order) { opposite_order_type =ORDER_TYPE_SELL_STOP; opposite_order_comment =comment_bottom_order; } //--- If the position comment belongs to the lower order, // then the upper order is to be deleted/modified/placed if(pos.comment==comment_bottom_order) { opposite_order_type =ORDER_TYPE_BUY_STOP; opposite_order_comment =comment_top_order; } //--- If there are no pending orders for the specified symbol if(symbol_total_orders==0) { //--- If the position reversal is enabled, place a reversed order if(Reverse[s]) { double tp=0.0; // Take Profit double sl=0.0; // Stop Loss double lot=0.0; // Volume for position calculation in case of reversed positio double order_price=0.0; // Price for placing the order //--- Get the price for placing a pending order order_price=CalculatePendingOrder(s,opposite_order_type); //---Get Take Profit и Stop Loss levels sl=CalculatePendingOrderStopLoss(s,opposite_order_type,order_price); tp=CalculatePendingOrderTakeProfit(s,opposite_order_type,order_price); //--- Calculate double volume lot=CalculateLot(s,pos.volume*2); //--- Place the pending order SetPendingOrder(s,opposite_order_type,lot,0,order_price,sl,tp,ORDER_TIME_GTC,opposite_order_comment); //--- Adjust Stop Loss as related to the order CorrectStopLossByOrder(s,order_price,opposite_order_type); } return; } //--- If there are pending orders for this symbol, then depending on the circumstances delete or // modify the reversed order if(symbol_total_orders>0) { //--- Loop through the total number of orders from the last one to the first one for(int i=total_orders-1; i>=0; i--) { //--- If the order chosen if((order_ticket=OrderGetTicket(i))>0) { //--- Get the order symbol GetPendingOrderProperties(O_SYMBOL); //--- Get the order comment GetPendingOrderProperties(O_COMMENT); //--- If order symbol and position symbol are equal, // and order comment and the reversed order comment are equal if(ord.symbol==Symbols[s] && ord.comment==opposite_order_comment) { //--- If position reversal is disabled if(!Reverse[s]) //--- Delete order DeletePendingOrder(order_ticket); //--- If position reversal is enabled else { double lot=0.0; //--- Get the current order properties GetPendingOrderProperties(O_ALL); //--- Get the current position volume GetPositionProperties(s,P_VOLUME); //--- If the order has been modified already, exit the loop. if(ord.volume_initial>pos.volume) break; //--- Calculate double volume lot=CalculateLot(s,pos.volume*2); //--- Modify (delete and place again) the order ModifyPendingOrder(s,order_ticket,opposite_order_type, ord.price_open,ord.sl,ord.tp, ORDER_TIME_GTC,ord.time_expiration, ord.price_stoplimit,opposite_order_comment,lot); } } } } } } }
Şimdi ana program dosyasında sadece küçük ayarlamalar yapacağız. Alım satım olayları işleyicisi OnTrade()'i ekleyeceğiz. Alım satım olayına karşı bekleyen talimatlarla ilgili mevcut durumun değerlendirilmesi bu işlevde gerçekleştirilecektir.
//+------------------------------------------------------------------+ //| Processing of trade events | //+------------------------------------------------------------------+ void OnTrade() { //--- Check the state of pending orders ManagePendingOrders(); }
ManagePendingOrders() işlevi, OnChartEvent() kullanıcı olay işleyicisinde de kullanılacaktır:
//+------------------------------------------------------------------+ //| User events and chart events handler | //+------------------------------------------------------------------+ void OnChartEvent(const int id, // Event identifier const long &lparam, // Parameter of long event type const double &dparam, // Parameter of double event type const string &sparam) // Parameter of string event type { //--- If it is a user event if(id>=CHARTEVENT_CUSTOM) { //--- Exit, if trade is prohibited if(CheckTradingPermission()>0) return; //--- If it is a tick event if(lparam==CHARTEVENT_TICK) { //--- Check the state of pending orders ManagePendingOrders(); //--- Check signals and trade according to them CheckSignalsAndTrade(); return; } } }
CheckSignalsAndTrade() işlevinde de bazı değişiklikler yapıldı. Aşağıdaki kodda, bu makalede ele alınan yeni işlevleri içeren dizeler vurgulanmıştır.
//+------------------------------------------------------------------+ //| Checks signals and trades based on New Bar event | //+------------------------------------------------------------------+ void CheckSignalsAndTrade() { //--- Loop through all specified signals for(int s=0; s<NUMBER_OF_SYMBOLS; s++) { //--- If trading this symbol is prohibited, exit if(Symbols[s]=="") continue; //--- If the bar is not new, move on to the following symbol if(!CheckNewBar(s)) continue; //--- If there is a new bar else { //--- If outside the time range if(!IsInTradeTimeRange(s)) { //--- Close position ClosePosition(s); //--- Delete all pending orders DeleteAllPendingOrders(s); //--- Move on to the following symbol continue; } //--- Get bars data GetBarsData(s); //--- Check conditions and trade TradingBlock(s); //--- If position reversal if enabled if(Reverse[s]) //--- Pull up Stop Loss for pending order ModifyPendingOrderTrailingStop(s); //--- If position reversal is disabled else //--- Pull up Stop Loss ModifyTrailingStop(s); } }
Artık her şey hazır ve bu çoklu para birimi Expert Advisor'ın parametrelerini optimize etmeyi deneyebiliriz. Strateji test cihazını aşağıda gösterildiği gibi ayarlayalım:
Şek. 1 - Parametre optimizasyonu için test cihazı ayarları.
Önce EURUSD para birimi çifti için parametreleri optimize edeceğiz, sonra da AUDUSD için. Aşağıdaki ekran görüntüsü EURUSD optimizasyonu için hangi parametreleri seçeceğimizi gösteriyor:
Şek. 2 - Çoklu para birimi Expert Advisor optimizasyonu için parametrelerin ayarlanması
EURUSD döviz çiftinin parametreleri optimize edildikten sonra, aynı parametreler AUDUSD için optimize edilmelidir. Aşağıda, birlikte test edilen her iki sembolün sonucu verilmiştir. Sonuçlar maksimum geri kazanım faktörüne göre seçilmiştir. Test için lot değeri her iki sembol için 1 olarak ayarlanmıştır.
Şek. 3 - iki sembolün birlikte test sonucu.
Sonuç
Hepsi bu kadar. Elinizin altındaki hazır işlevlerle, alıms atım kararları verme fikrini geliştirmeye odaklanabilirsiniz. Bu durumda, değişikliklerin TradingBlock() ve ManagePendingOrders() işlevlerinde uygulanması gerekecektir. Yakın zamanda MQL5 öğrenmeye başlayanlar için daha fazla sembol ekleme alıştırması yapmalarını ve alım satım algoritması şemasını değiştirmelerini öneririz.
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/755





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