diff --git a/Include/AZ-INVEST/SDK/CommonSettings.mqh b/Include/AZ-INVEST/SDK/CommonSettings.mqh index 78656e0..858474d 100644 Binary files a/Include/AZ-INVEST/SDK/CommonSettings.mqh and b/Include/AZ-INVEST/SDK/CommonSettings.mqh differ diff --git a/Include/AZ-INVEST/SDK/Normailze.mqh b/Include/AZ-INVEST/SDK/Normailze.mqh new file mode 100644 index 0000000..9adb01f --- /dev/null +++ b/Include/AZ-INVEST/SDK/Normailze.mqh @@ -0,0 +1,52 @@ +// +// Copyright 2017-2018, Artur Zas +// https://www.az-invest.eu +// https://www.mql5.com/en/users/arturz +// +// Normalizing functions +// + +double NormalizeLots(string symbol, double InputLots) +{ + double lotsMin = SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN); + double lotsMax = SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX); + int lotsDigits = (int) - MathLog10(SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)); + + if(InputLots < lotsMin) + InputLots = lotsMin; + if(InputLots > lotsMax) + InputLots = lotsMax; + + return NormalizeDouble(InputLots, lotsDigits); +} + +double VtcNormalizeLots(string symbol, double lotsToNormalize) +{ + double lotsMin = SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN); + double lotsMax = SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX); + double lotsStep = SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP); + + if (lotsToNormalize == 0) + return lotsMin; + + int a = (int)(lotsToNormalize / lotsStep); + double Lots = a * lotsStep; + + if(Lots < lotsMin) + Lots = lotsMin; + if(Lots > lotsMax) + Lots = lotsMax; + + return Lots; +} + +double NormalizePrice(string symbol, double price, double tick = 0) +{ + double _tick = tick ? tick : SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE); + int _digits = (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); + + if (tick) + return NormalizeDouble(MathRound(price/_tick)*_tick,_digits); + else + return NormalizeDouble(price,_digits); +} \ No newline at end of file diff --git a/Include/AZ-INVEST/SDK/RangeBarSettings.mqh b/Include/AZ-INVEST/SDK/RangeBarSettings.mqh index 51ff6be..c4b4828 100644 --- a/Include/AZ-INVEST/SDK/RangeBarSettings.mqh +++ b/Include/AZ-INVEST/SDK/RangeBarSettings.mqh @@ -6,15 +6,38 @@ #ifdef SHOW_INDICATOR_INPUTS -input int barSizeInTicks = 100; // Range bar size (in points) -input ENUM_BOOL atrEnabled = false; // Enable ATR based bar size calculation - ENUM_TIMEFRAMES atrTimeFrame = PERIOD_D1; // Use ATR period -input int atrPeriod = 14; // ATR period -input int atrPercentage = 10; // Use percentage of ATR - ENUM_BOOL useRealVolume = false; // Use real volume ( false for FX ) - ENUM_TICK_PRICE_TYPE plotPrice = tickBid; // Build chart using -input int showNumberOfDays = 14; // Show history for number of days -input ENUM_BOOL resetOpenOnNewTradingDay = true; // Synchronize first bar's open on new day +#ifdef MQL5_MARKET_DEMO + int barSizeInTicks = 210; // Range bar size (in points) + ENUM_BOOL atrEnabled = false; // Enable ATR based bar size calculation + ENUM_TIMEFRAMES atrTimeFrame = PERIOD_D1; // Use ATR period + int atrPeriod = 14; // ATR period + int atrPercentage = 10; // Use percentage of ATR + ENUM_BOOL useRealVolume = false; // Use real volume ( false for FX ) + ENUM_TICK_PRICE_TYPE plotPrice = tickBid; // Build chart using + int showNumberOfDays = 7; // Show history for number of days + ENUM_BOOL resetOpenOnNewTradingDay = true; // Synchronize first bar's open on new day + + #ifdef USE_CUSTOM_SYMBOL + string customChartName = ""; // Override default custom chart name with + string applyTemplate = "default"; // Apply template to custom chart + #endif +#else + input int barSizeInTicks = 100; // Range bar size (in points) + input ENUM_BOOL atrEnabled = false; // Enable ATR based bar size calculation + ENUM_TIMEFRAMES atrTimeFrame = PERIOD_D1; // Use ATR period + input int atrPeriod = 14; // ATR period + input int atrPercentage = 10; // Use percentage of ATR + ENUM_BOOL useRealVolume = false; // Use real volume ( false for FX ) + ENUM_TICK_PRICE_TYPE plotPrice = tickBid; // Build chart using + input int showNumberOfDays = 14; // Show history for number of days + input ENUM_BOOL resetOpenOnNewTradingDay = true; // Synchronize first bar's open on new day + + #ifdef USE_CUSTOM_SYMBOL + input string customChartName = ""; // Override default custom chart name with + input string applyTemplate = "default"; // Apply template to custom chart + #endif +#endif + #ifndef USE_CUSTOM_SYMBOL input double TopBottomPaddingPercentage = 0.30; // Use padding top/bottom (0.0 - 1.0) @@ -30,7 +53,7 @@ input ENUM_BOOL resetOpenOnNewTradingDay = true; // Synch input color HighThresholdIndicatorColor = clrLime; // Bullish bar projection color input color LowThresholdIndicatorColor = clrRed; // Bearish bar projection color input ENUM_BOOL showCurrentBarOpenTime = true; // Display chart info and current bar's open time - input color InfoTextColor = clrWhite; // Current bar's open time info color + input color InfoTextColor = clrNONE; // Current bar's open time info color input ENUM_BOOL NewBarAlert = false; // Alert on new a bar input ENUM_BOOL ReversalBarAlert = false; // Alert on reversal bar @@ -56,7 +79,7 @@ input ENUM_BOOL resetOpenOnNewTradingDay = true; // Synch input ENUM_MA_METHOD_EXT MA3method = _VWAP_TICKVOL; // 3rd MA method input ENUM_APPLIED_PRICE MA3applyTo = PRICE_CLOSE; // 3rd MA apply to input int MA3shift = 0; // 3rd MA shift - input ENUM_CHANNEL_TYPE ShowChannel = None; // Show Channel + input ENUM_CHANNEL_TYPE ShowChannel = _None; // Show Channel input string Channel_Settings = "-------------------"; // Channel settings input int DonchianPeriod = 20; // Donchian Channel period input ENUM_APPLIED_PRICE BBapplyTo = PRICE_CLOSE; // Bollinger Bands apply to diff --git a/Include/AZ-INVEST/SDK/TradeFunctions.mqh b/Include/AZ-INVEST/SDK/TradeFunctions.mqh index af009e7..2d80d6e 100644 --- a/Include/AZ-INVEST/SDK/TradeFunctions.mqh +++ b/Include/AZ-INVEST/SDK/TradeFunctions.mqh @@ -1,11 +1,13 @@ -//+------------------------------------------------------------------+ -//| TradeFunctions.mqh | -//| Copyright 2017, AZ-iNVEST | -//| http://www.az-invest.eu | -//+------------------------------------------------------------------+ -#property copyright "Copyright 2017, AZ-iNVEST" -#property link "http://www.az-invest.eu" +// +// Copyright 2017-2018, Artur Zas +// https://www.az-invest.eu +// https://www.mql5.com/en/users/arturz +// + #include +#include +#include +CTradingChecks tradingChecks; #define POSITION_TYPE_NONE -1 @@ -15,40 +17,58 @@ struct CMarketOrderParameters { - bool m_async_mode; // trade mode - ulong m_magic; // expert magic number - ulong m_deviation; // deviation default + bool m_async_mode; // trade mode + ulong m_magic; // expert magic number + ulong m_deviation; // deviation default ENUM_ORDER_TYPE_FILLING m_type_filling; - int numberOfRetries; - int busyTimeout_ms; - int requoteTimeout_ms; - + int numberOfRetries; + int busyTimeout_ms; + int requoteTimeout_ms; }; class CMarketOrder { protected: - CTrade * ctrade; + CTrade *ctrade; - int numberOfRetries; - int busyTimeout_ms; - int requoteTimeout_ms; + bool initialized; + + int numberOfRetries; + int busyTimeout_ms; + int requoteTimeout_ms; public: + CMarketOrder(void); CMarketOrder(CMarketOrderParameters ¶ms); ~CMarketOrder(void); - bool Long(string symbol, double lots, uint stoploss = 0, uint takeprofit = 0); - bool Long(string symbol,double lots, double priceSL=0,double priceTP=0); - bool Short(string symbol,double lots, uint stoploss = 0, uint takeprofit = 0); - bool Short(string symbol,double lots, double priceSL=0,double priceTP=0); - bool Modify(ulong ticket, uint stoploss = 0, uint takeprofit = 0); + bool Initialize(CMarketOrderParameters ¶ms); + bool IsInitialized() {return initialized;}; + + bool Long(string symbol, double lots, uint stoploss = 0, uint takeprofit = 0,bool stopsInPips = true, string comment = ""); + bool Long(string symbol,double lots, double priceSL=0,double priceTP=0, string comment = ""); + bool Short(string symbol,double lots, uint stoploss = 0, uint takeprofit = 0,bool stopsInPips = true, string comment = ""); + bool Short(string symbol,double lots, double priceSL=0,double priceTP=0, string comment = ""); + + bool PendingLong(ENUM_ORDER_TYPE orderType, string symbol, double lots, double price, uint stoploss=0,uint takeprofit=0,bool stopsInPips = true, string comment = ""); + bool PendingLong(ENUM_ORDER_TYPE orderType, string symbol, double lots, double price, double priceSL=0, double priceTP=0, string comment = ""); + bool PendingShort(ENUM_ORDER_TYPE orderType, string symbol, double lots, double price, uint stoploss=0,uint takeprofit=0,bool stopsInPips = true, string comment = ""); + bool PendingShort(ENUM_ORDER_TYPE orderType, string symbol, double lots, double price, double priceSL=0, double priceTP=0, string comment = ""); + + bool Modify(ulong ticket, bool stopsInPips = true, int stoploss = -1, int takeprofit = -1); bool Modify(ulong ticket, double priceSL=0,double priceTP=0); + + bool ModifyPending(ulong ticket, double entry, bool stopsInPips = true, int stoploss = -1, int takeprofit = -1, ENUM_ORDER_TYPE_TIME orderTypeTime = ORDER_TIME_GTC, datetime expires = 0); + bool ModifyPending(ulong ticket, double entry, double priceSL=0, double priceTP=0, ENUM_ORDER_TYPE_TIME orderTypeTime = ORDER_TIME_GTC, datetime expires = 0); + bool Close(ulong ticket); bool ClosePartial(ulong ticket, double lots); + bool CloseAll(string symbol = ""); + bool Delete(ulong ticket); + bool Reverse(ulong ticket,double lots = 0, uint stoploss=0, uint takeprofit=0); bool Reverse(ulong ticket,double lots = 0, double priceSL=0,double priceTP=0); bool IsOpen(string symbol, ENUM_POSITION_TYPE type, long magicNumber = 0); @@ -57,8 +77,13 @@ class CMarketOrder bool IsOpen(ulong &ticket, string symbol, long magicNumber = 0); bool IsOpen(ulong &ticket, ENUM_POSITION_TYPE &type, string symbol, long magicNumber = 0); + bool GetPositionType(ulong ticket, ENUM_POSITION_TYPE &_pType); string PositionTypeToString(ENUM_POSITION_TYPE t); + string OrderTypeToString(ENUM_ORDER_TYPE t); + ENUM_ORDER_TYPE TradeBias(ENUM_ORDER_TYPE t); bool RetryOrderRequest(int retryNumber); + + void SetTradeId(ulong tradeId); private: @@ -68,19 +93,31 @@ class CMarketOrder }; +CMarketOrder::CMarketOrder(void) +{ + ctrade = new CTrade(); + this.initialized = false; +} + CMarketOrder::CMarketOrder(CMarketOrderParameters ¶ms) { ctrade = new CTrade(); + Initialize(params); +} +bool CMarketOrder::Initialize(CMarketOrderParameters ¶ms) +{ ctrade.SetExpertMagicNumber(params.m_magic); ctrade.SetDeviationInPoints(params.m_deviation); ctrade.SetTypeFilling(params.m_type_filling); ctrade.SetAsyncMode(params.m_async_mode); - this.numberOfRetries = (params.numberOfRetries == 0) ? 25 : params.numberOfRetries; - this.busyTimeout_ms = (params.busyTimeout_ms == 0) ? 1000 : params.busyTimeout_ms; - this.requoteTimeout_ms = (params.requoteTimeout_ms == 0) ? 250 : params.requoteTimeout_ms; + this.numberOfRetries = (params.numberOfRetries == 0) ? 25 : params.numberOfRetries; + this.busyTimeout_ms = (params.busyTimeout_ms == 0) ? 1000 : params.busyTimeout_ms; + this.requoteTimeout_ms = (params.requoteTimeout_ms == 0) ? 250 : params.requoteTimeout_ms; + this.initialized = true; + return this.initialized; } CMarketOrder::~CMarketOrder(void) @@ -89,7 +126,7 @@ CMarketOrder::~CMarketOrder(void) delete ctrade; } -bool CMarketOrder::Long(string symbol, double lots,uint stoploss=0,uint takeprofit=0) +bool CMarketOrder::Long(string symbol, double lots,uint stoploss=0,uint takeprofit=0,bool stopsInPips = true, string comment = "") { bool result = false; int counter = 0; @@ -97,14 +134,21 @@ bool CMarketOrder::Long(string symbol, double lots,uint stoploss=0,uint takeprof while(!IsStopped() && !result) { double price = SymbolInfoDouble(symbol,SYMBOL_ASK); - double _point = SymbolInfoDouble(symbol,SYMBOL_POINT); + double point = SymbolInfoDouble(symbol,SYMBOL_POINT); //calc SL + TP - double priceSL = (stoploss ? NormalizePrice(symbol,price - stoploss*_point) : 0.0); - double priceTP = (takeprofit ? NormalizePrice(symbol,price + takeprofit*_point) : 0.0); + double priceSL = (stoploss ? NormalizePrice(symbol,price - stoploss*point) : 0.0); + double priceTP = (takeprofit ? NormalizePrice(symbol,price + takeprofit*point) : 0.0); + + //do checks + if(!tradingChecks.OkToOpenPosition(symbol,ORDER_TYPE_BUY,lots,price,priceSL,priceTP)) + { + Alert("Unable to place trade: "+tradingChecks.GetCheckErrorToString()); + return false; + } //attempt to buy - result = ctrade.Buy(NormalizeLots(symbol,lots), symbol, price, priceSL, priceTP); + result = ctrade.Buy(NormalizeLots(symbol,lots), symbol, price, priceSL, priceTP, comment); if(result) { @@ -121,7 +165,7 @@ bool CMarketOrder::Long(string symbol, double lots,uint stoploss=0,uint takeprof return false; } -bool CMarketOrder::Long(string symbol, double lots,double priceSL=0,double priceTP=0) +bool CMarketOrder::Long(string symbol, double lots,double priceSL=0,double priceTP=0, string comment = "") { bool result = false; int counter = 0; @@ -130,8 +174,15 @@ bool CMarketOrder::Long(string symbol, double lots,double priceSL=0,double price { double price = SymbolInfoDouble(symbol,SYMBOL_ASK); + //do checks + if(!tradingChecks.OkToOpenPosition(symbol,ORDER_TYPE_BUY,lots,price,priceSL,priceTP)) + { + Alert("Unable to place trade: "+tradingChecks.GetCheckErrorToString()); + return false; + } + //attempt to buy - result = ctrade.Buy(NormalizeLots(symbol,lots), symbol, price, priceSL, priceTP); + result = ctrade.Buy(NormalizeLots(symbol,lots), symbol, price, priceSL, priceTP, comment); if(result) { @@ -148,7 +199,7 @@ bool CMarketOrder::Long(string symbol, double lots,double priceSL=0,double price return false; } -bool CMarketOrder::Short(string symbol, double lots,uint stoploss=0,uint takeprofit=0) +bool CMarketOrder::Short(string symbol, double lots,uint stoploss=0,uint takeprofit=0,bool stopsInPips = true, string comment = "") { bool result = false; int counter = 0; @@ -156,14 +207,21 @@ bool CMarketOrder::Short(string symbol, double lots,uint stoploss=0,uint takepro while(!IsStopped() && !result) { double price = SymbolInfoDouble(symbol,SYMBOL_BID); - double _point = SymbolInfoDouble(symbol,SYMBOL_POINT); + double point = SymbolInfoDouble(symbol,SYMBOL_POINT); //calc SL + TP - double priceSL = (stoploss ? NormalizePrice(symbol,price + stoploss*_point) : 0.0); - double priceTP = (takeprofit ? NormalizePrice(symbol,price - takeprofit*_point) : 0.0); + double priceSL = (stoploss ? NormalizePrice(symbol,price + stoploss*point) : 0.0); + double priceTP = (takeprofit ? NormalizePrice(symbol,price - takeprofit*point) : 0.0); + //do checks + if(!tradingChecks.OkToOpenPosition(symbol,ORDER_TYPE_SELL,lots,price,priceSL,priceTP)) + { + Alert("Unable to place trade: "+tradingChecks.GetCheckErrorToString()); + return false; + } + //attempt to sell - result = ctrade.Sell(NormalizeLots(symbol,lots), symbol, price, priceSL, priceTP); + result = ctrade.Sell(NormalizeLots(symbol,lots), symbol, price, priceSL, priceTP, comment); if(result) { @@ -180,7 +238,7 @@ bool CMarketOrder::Short(string symbol, double lots,uint stoploss=0,uint takepro return false; } -bool CMarketOrder::Short(string symbol, double lots,double priceSL=0,double priceTP=0) +bool CMarketOrder::Short(string symbol, double lots,double priceSL=0,double priceTP=0, string comment = "") { bool result = false; int counter = 0; @@ -189,8 +247,15 @@ bool CMarketOrder::Short(string symbol, double lots,double priceSL=0,double pric { double price = SymbolInfoDouble(symbol,SYMBOL_BID); + //do checks + if(!tradingChecks.OkToOpenPosition(symbol,ORDER_TYPE_SELL,lots,price,priceSL,priceTP)) + { + Alert("Unable to place trade: "+tradingChecks.GetCheckErrorToString()); + return false; + } + //attempt to sell - result = ctrade.Sell(NormalizeLots(symbol,lots), symbol, price, priceSL, priceTP); + result = ctrade.Sell(NormalizeLots(symbol,lots), symbol, price, priceSL, priceTP, comment); if(result) { @@ -207,24 +272,202 @@ bool CMarketOrder::Short(string symbol, double lots,double priceSL=0,double pric return false; } -bool CMarketOrder::Modify(ulong ticket, uint stoploss = 0, uint takeprofit = 0) + +bool CMarketOrder::PendingLong(ENUM_ORDER_TYPE orderType, string symbol, double lots, double price, uint stoploss=0,uint takeprofit=0,bool stopsInPips = true, string comment = "") +{ + bool result = false; + + while(!IsStopped() && !result) + { + double point = SymbolInfoDouble(symbol,SYMBOL_POINT); + + //calc SL + TP + double priceSL = (stoploss ? NormalizePrice(symbol,price - stoploss*point) : 0.0); + double priceTP = (takeprofit ? NormalizePrice(symbol,price + takeprofit*point) : 0.0); + + //do checks + if(!tradingChecks.OkToOpenPosition(symbol,orderType,lots,price,priceSL,priceTP)) + { + Alert("Unable to place trade: "+tradingChecks.GetCheckErrorToString()); + return false; + } + + //attempt to place buy + if(orderType == ORDER_TYPE_BUY_LIMIT) + result = ctrade.BuyLimit(NormalizeLots(symbol,lots),price,symbol,priceSL,priceTP,ORDER_TIME_GTC,0,comment); + else if(orderType == ORDER_TYPE_BUY_STOP) + result = ctrade.BuyStop(NormalizeLots(symbol,lots),price,symbol,priceSL,priceTP,ORDER_TIME_GTC,0,comment); + + if(result) + { + Sleep(500); + return true; + } + else + { + string err = ctrade.ResultRetcodeDescription(); + MessageBox(err,"Operation failed",MB_ICONEXCLAMATION); + return false; + } + } + + return false; +} + +bool CMarketOrder::PendingLong(ENUM_ORDER_TYPE orderType, string symbol, double lots, double price, double priceSL=0, double priceTP=0, string comment = "") +{ + bool result = false; + + while(!IsStopped() && !result) + { + //do checks + if(!tradingChecks.OkToOpenPosition(symbol,orderType,lots,price,priceSL,priceTP)) + { + Alert("Unable to place trade: "+tradingChecks.GetCheckErrorToString()); + return false; + } + + //attempt to buy + if(orderType == ORDER_TYPE_BUY_LIMIT) + result = ctrade.BuyLimit(NormalizeLots(symbol,lots),price,symbol,priceSL,priceTP,ORDER_TIME_GTC,0,comment); + else if(orderType == ORDER_TYPE_BUY_STOP) + result = ctrade.BuyStop(NormalizeLots(symbol,lots),price,symbol,priceSL,priceTP,ORDER_TIME_GTC,0,comment); + + if(result) + { + Sleep(500); + return true; + } + else + { + string err = ctrade.ResultRetcodeDescription(); + MessageBox(err,"Operation failed",MB_ICONEXCLAMATION); + return false; + } + } + + return false; +} + + +bool CMarketOrder::PendingShort(ENUM_ORDER_TYPE orderType, string symbol, double lots, double price, uint stoploss=0,uint takeprofit=0,bool stopsInPips = true, string comment = "") +{ + bool result = false; + + while(!IsStopped() && !result) + { + double point = SymbolInfoDouble(symbol,SYMBOL_POINT); + + //calc SL + TP + double priceSL = (stoploss ? NormalizePrice(symbol,price + stoploss*point) : 0.0); + double priceTP = (takeprofit ? NormalizePrice(symbol,price - takeprofit*point) : 0.0); + + //do checks + if(!tradingChecks.OkToOpenPosition(symbol,orderType,lots,price,priceSL,priceTP)) + { + Alert("Unable to place trade: "+tradingChecks.GetCheckErrorToString()); + return false; + } + + //attempt to sell + if(orderType == ORDER_TYPE_SELL_LIMIT) + result = ctrade.SellLimit(NormalizeLots(symbol,lots),price,symbol,priceSL,priceTP,ORDER_TIME_GTC,0,comment); + else if(orderType == ORDER_TYPE_SELL_STOP) + result = ctrade.SellStop(NormalizeLots(symbol,lots),price,symbol,priceSL,priceTP,ORDER_TIME_GTC,0,comment); + + if(result) + { + Sleep(500); + return true; + } + else + { + string err = ctrade.ResultRetcodeDescription(); + MessageBox(err,"Operation failed",MB_ICONEXCLAMATION); + return false; + } + } + + return false; +} + +bool CMarketOrder::PendingShort(ENUM_ORDER_TYPE orderType, string symbol, double lots, double price, double priceSL=0, double priceTP=0, string comment = "") +{ + bool result = false; + + while(!IsStopped() && !result) + { + //do checks + if(!tradingChecks.OkToOpenPosition(symbol,orderType,lots,price,priceSL,priceTP)) + { + Alert("Unable to place trade: "+tradingChecks.GetCheckErrorToString()); + return false; + } + + //attempt to sell + if(orderType == ORDER_TYPE_SELL_LIMIT) + result = ctrade.SellLimit(NormalizeLots(symbol,lots),price,symbol,priceSL,priceTP,ORDER_TIME_GTC,0,comment); + else if(orderType == ORDER_TYPE_SELL_STOP) + result = ctrade.SellStop(NormalizeLots(symbol,lots),price,symbol,priceSL,priceTP,ORDER_TIME_GTC,0,comment); + + if(result) + { + Sleep(500); + return true; + } + else + { + string err = ctrade.ResultRetcodeDescription(); + MessageBox(err,"Operation failed",MB_ICONEXCLAMATION); + return false; + } + } + + return false; +} + +bool CMarketOrder::Modify(ulong ticket, bool stopsInPips = true, int stoploss = -1, int takeprofit = -1) { if(!PositionSelectByTicket(ticket)) return false; string symbol = PositionGetString(POSITION_SYMBOL); - double price = PositionGetDouble(POSITION_PRICE_CURRENT); - double _point = SymbolInfoDouble(symbol,SYMBOL_POINT); + double price = PositionGetDouble(POSITION_PRICE_OPEN); + double point = SymbolInfoDouble(symbol,SYMBOL_POINT); double priceSL; double priceTP; - if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY){ - priceSL = (stoploss ? NormalizePrice(symbol,price - stoploss*_point) : PositionGetDouble(POSITION_SL)); - priceTP = (takeprofit ? NormalizePrice(symbol,price + takeprofit*_point) : PositionGetDouble(POSITION_TP)); + if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) + { + priceSL = (stoploss < 0) + ? PositionGetDouble(POSITION_SL) + : (stoploss == 0) + ? 0 + : NormalizePrice(symbol,price - stoploss*point); + + priceTP = (takeprofit < 0) + ? PositionGetDouble(POSITION_TP) + : (takeprofit == 0) + ? 0 + : NormalizePrice(symbol,price + takeprofit*point); +// priceSL = (stoploss ? NormalizePrice(symbol,price - stoploss*_point) : PositionGetDouble(POSITION_SL)); +// priceTP = (takeprofit ? NormalizePrice(symbol,price + takeprofit*_point) : PositionGetDouble(POSITION_TP)); } - else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL){ - priceSL = (stoploss ? NormalizePrice(symbol,price + stoploss*_point) : PositionGetDouble(POSITION_SL)); - priceTP = (takeprofit ? NormalizePrice(symbol,price - takeprofit*_point) : PositionGetDouble(POSITION_TP)); + else if (PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) + { +// priceSL = (stoploss ? NormalizePrice(symbol,price + stoploss*_point) : PositionGetDouble(POSITION_SL)); +// priceTP = (takeprofit ? NormalizePrice(symbol,price - takeprofit*_point) : PositionGetDouble(POSITION_TP)); + priceSL = (stoploss < 0) + ? PositionGetDouble(POSITION_SL) + : (stoploss == 0) + ? 0 + : NormalizePrice(symbol,price + stoploss*point); + + priceTP = (takeprofit < 0) + ? PositionGetDouble(POSITION_TP) + : (takeprofit == 0) + ? 0 + : NormalizePrice(symbol,price - takeprofit*point); } else return false; @@ -232,15 +475,25 @@ bool CMarketOrder::Modify(ulong ticket, uint stoploss = 0, uint takeprofit = 0) //there's no change in SL or TP - do nothing! if (priceSL == PositionGetDouble(POSITION_SL) && priceTP == PositionGetDouble(POSITION_TP)) - return true; + return false; bool result = false; int counter = 0; while(!IsStopped() && !result) { + //do checks + if(!tradingChecks.OkToModifyPosition(symbol,ticket,priceSL,priceTP)) + { + Alert("Unable to modify: "+tradingChecks.GetCheckErrorToString()); + return false; + } + //attempt to modify position - result = ctrade.PositionModify(symbol,priceSL,priceTP); + if(_IsNettingAccount()) + result = ctrade.PositionModify(symbol,priceSL,priceTP); + else + result = ctrade.PositionModify(ticket,priceSL,priceTP); if(result) { @@ -263,21 +516,167 @@ bool CMarketOrder::Modify(ulong ticket, double priceSL=0,double priceTP=0) return false; string symbol = PositionGetString(POSITION_SYMBOL); - double price = PositionGetDouble(POSITION_PRICE_CURRENT); - double _point = SymbolInfoDouble(symbol,SYMBOL_POINT); + double price = PositionGetDouble(POSITION_PRICE_OPEN); + //double point = SymbolInfoDouble(symbol,SYMBOL_POINT); //there's no change in SL or TP - do nothing! if (priceSL == PositionGetDouble(POSITION_SL) && priceTP == PositionGetDouble(POSITION_TP)) - return true; + return false; bool result = false; int counter = 0; while(!IsStopped() && !result) { + //do checks + if(!tradingChecks.OkToModifyPosition(symbol,ticket,priceSL,priceTP)) + { + Alert("Unable to modify: "+tradingChecks.GetCheckErrorToString()); + return false; + } + //attempt to modify position - result = ctrade.PositionModify(symbol,priceSL,priceTP); + if(_IsNettingAccount()) + result = ctrade.PositionModify(symbol,priceSL,priceTP); + else + result = ctrade.PositionModify(ticket,priceSL,priceTP); + + if(result) + { + Sleep(500); + return true; + } + else + { + if(!RetryOrderRequest(++counter)) + return false; + } + } + + return false; +} + +bool CMarketOrder::ModifyPending(ulong ticket, double entry, bool stopsInPips = true, int stoploss = -1, int takeprofit = -1, ENUM_ORDER_TYPE_TIME orderTypeTime = ORDER_TIME_GTC, datetime expires = 0) +{ + if(!OrderSelect(ticket)) + return false; + + string symbol = OrderGetString(ORDER_SYMBOL); + double point = SymbolInfoDouble(symbol,SYMBOL_POINT); + if(entry == 0) + entry = OrderGetDouble(ORDER_PRICE_OPEN); + + double priceSL; + double priceTP; + + if((OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY) || + (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_LIMIT) || + (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP) || + (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_BUY_STOP_LIMIT)) + { + priceSL = (stoploss < 0) + ? OrderGetDouble(ORDER_SL) + : (stoploss == 0) + ? 0 + : NormalizePrice(symbol,entry - stoploss*point); + + priceTP = (takeprofit < 0) + ? OrderGetDouble(ORDER_TP) + : (takeprofit == 0) + ? 0 + : NormalizePrice(symbol,entry + takeprofit*point); + } + else if((OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL) || + (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_LIMIT) || + (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP) || + (OrderGetInteger(ORDER_TYPE) == ORDER_TYPE_SELL_STOP_LIMIT)) + { + priceSL = (stoploss < 0) + ? OrderGetDouble(ORDER_SL) + : (stoploss == 0) + ? 0 + : NormalizePrice(symbol,entry + stoploss*point); + + priceTP = (takeprofit < 0) + ? OrderGetDouble(ORDER_TP) + : (takeprofit == 0) + ? 0 + : NormalizePrice(symbol,entry - takeprofit*point); + } + else + return false; + + //there's no change in parameters - do nothing! + if (priceSL == OrderGetDouble(ORDER_SL) + && priceTP == OrderGetDouble(ORDER_TP) + && entry == OrderGetDouble(ORDER_PRICE_OPEN) + && orderTypeTime == OrderGetInteger(ORDER_TYPE_TIME) + && expires == OrderGetInteger(ORDER_TIME_EXPIRATION)) + return false; + + bool result = false; + int counter = 0; + + while(!IsStopped() && !result) + { + //do checks + if(!tradingChecks.OkToModifyOrder(symbol,ticket,entry,priceSL,priceTP)) + { + Alert("Unable to modify: "+tradingChecks.GetCheckErrorToString()); + return false; + } + + //attempt to modify position + result = ctrade.OrderModify(ticket,entry,priceSL,priceTP,orderTypeTime,expires); + + if(result) + { + Sleep(500); + return true; + } + else + { + if(!RetryOrderRequest(++counter)) + return false; + } + } + + return false; +} + + +bool CMarketOrder::ModifyPending(ulong ticket, double entry, double priceSL=0, double priceTP=0, ENUM_ORDER_TYPE_TIME orderTypeTime = ORDER_TIME_GTC, datetime expires = 0) +{ + if(!OrderSelect(ticket)) + return false; + + string symbol = OrderGetString(ORDER_SYMBOL); + if(entry == 0) + entry = OrderGetDouble(ORDER_PRICE_OPEN); + + //there's no change in parameters - do nothing! + if (priceSL == OrderGetDouble(ORDER_SL) + && priceTP == OrderGetDouble(ORDER_TP) + && entry == OrderGetDouble(ORDER_PRICE_OPEN) + && orderTypeTime == OrderGetInteger(ORDER_TYPE_TIME) + && expires == OrderGetInteger(ORDER_TIME_EXPIRATION)) + return false; + + bool result = false; + int counter = 0; + + while(!IsStopped() && !result) + { + //do checks + if(!tradingChecks.OkToModifyOrder(symbol,ticket,entry,priceSL,priceTP)) + { + Alert("Unable to modify: "+tradingChecks.GetCheckErrorToString()); + return false; + } + + //attempt to modify position + result = ctrade.OrderModify(ticket,entry,priceSL,priceTP,orderTypeTime,expires); if(result) { @@ -350,6 +749,11 @@ bool CMarketOrder::ClosePartial(ulong ticket, double lots) return false; } +bool CMarketOrder::Delete(ulong ticket) +{ + return ctrade.OrderDelete(ticket); +} + bool CMarketOrder::Reverse(ulong ticket,double lots = 0, uint stoploss=0, uint takeprofit=0) { if(!PositionSelectByTicket(ticket)) @@ -420,6 +824,44 @@ bool CMarketOrder::IsOpen(ulong &ticket, string symbol, long magicNumber = 0) return this._IsOpen(ticket,symbol,magicNumber); } +bool CMarketOrder::CloseAll(string symbol = "") +{ + int positions=PositionsTotal(); + ulong ticketsToClose[]; + int ticketsToCloseCounter = 0; + + if(positions > 0) + ArrayResize(ticketsToClose,positions); + else + return false; + + for(int i=0;i= this.numberOfRetries) { PrintFormat("Giving up on maximum number of retries (%d)",this.numberOfRetries); @@ -575,37 +1061,16 @@ bool CMarketOrder::RetryOrderRequest(int retryNumber) break; default: + MessageBox(ctrade.ResultRetcodeDescription(),"Operation failed",MB_ICONEXCLAMATION); return false; } } -//+------------------------------------------------------------------+ -//| Normalizing | -//+------------------------------------------------------------------+ - -double NormalizeLots(string symbol, double InputLots) +void CMarketOrder::SetTradeId(ulong tradeId) { - double lotsMin = SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN); - double lotsMax = SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX); - int lotsDigits = (int) - MathLog10(SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP)); - - if(InputLots < lotsMin) - InputLots = lotsMin; - if(InputLots > lotsMax) - InputLots = lotsMax; - - return NormalizeDouble(InputLots, lotsDigits); + ctrade.SetExpertMagicNumber(tradeId); } -double NormalizePrice(string symbol, double price, double tick = 0) -{ - double _tick = tick ? tick : SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE); - int _digits = (int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); - - if (tick) - return NormalizeDouble(MathRound(price/_tick)*_tick,_digits); - else - return NormalizeDouble(price,_digits); -} + \ No newline at end of file diff --git a/Include/AZ-INVEST/SDK/TradingChecks.mqh b/Include/AZ-INVEST/SDK/TradingChecks.mqh new file mode 100644 index 0000000..b50f3b3 --- /dev/null +++ b/Include/AZ-INVEST/SDK/TradingChecks.mqh @@ -0,0 +1,890 @@ +// +// Copyright 2018, Artur Zas +// https://www.az-invest.eu +// https://www.mql5.com/en/users/arturz +// + +#ifdef __MQL5__ + //--- class for performing trade operations + #include + CTrade trade; + //--- class for working with orders + #include + COrderInfo orderinfo; + //--- class for working with positions + #include + CPositionInfo positioninfo; + + //--- introduce the predefined variables from MQL4 for versatility of the code + #define Ask SymbolInfoDouble(_symbol,SYMBOL_ASK) + #define Bid SymbolInfoDouble(_symbol,SYMBOL_BID) + +#endif + +#define _point SymbolInfoDouble(_symbol,SYMBOL_POINT) + +//--- redefine the order types from MQL5 to MQL4 for use in common code +#ifdef __MQL4__ +#define ORDER_TYPE_BUY OP_BUY +#define ORDER_TYPE_SELL OP_SELL +#define ORDER_TYPE_BUY_LIMIT OP_BUYLIMIT +#define ORDER_TYPE_SELL_LIMIT OP_SELLLIMIT +#define ORDER_TYPE_BUY_STOP OP_BUYSTOP +#define ORDER_TYPE_SELL_STOP OP_SELLSTOP +#endif + +enum ENUM_TC_ERROR +{ + tcErrorNONE = 0, + tcErrorNotEnoughMoney, + tcErrorInvalidStops, + tcErrorOrderLimitReached, + tcErrorFreezeLevel, + tcErrorNothingChanged, + tcErrorInvalidPrice, +}; + +class CTradingChecks +{ + private: + + ENUM_TC_ERROR _err; + + public: + + CTradingChecks(); + ~CTradingChecks(); + + string GetCheckErrorToString(); + + bool OkToOpenOrder(string _symbol,ENUM_ORDER_TYPE type, double lots, double entryPrice, double sl, double tp); + bool OkToModifyOrder(string _symbol,ulong ticket,double price, double sl, double tp); +#ifdef __MQL5__ + bool OkToOpenPosition(string _symbol,ENUM_ORDER_TYPE type, double lots, double entryPrice, double sl, double tp); + bool OkToModifyPosition(string _symbol,ulong ticket, double sl, double tp); +#endif +}; + +CTradingChecks::CTradingChecks(void) +{ +} + +CTradingChecks::~CTradingChecks(void) +{ +} + +string CTradingChecks::GetCheckErrorToString(void) +{ + switch(_err) + { + case tcErrorNONE: + return "No Error"; + case tcErrorNotEnoughMoney: + return "Not enough money (check previous message in Experts log)"; + case tcErrorInvalidStops: + return "Invalid stops (check previous message in Experts log)"; + case tcErrorOrderLimitReached: + return "Maximum order limit reached"; + case tcErrorFreezeLevel: + return "Freeze level (check previous message in Experts log)"; + case tcErrorNothingChanged: + return "Nothing to change"; + case tcErrorInvalidPrice: + return "Invalid entry price for this order type"; + + default: + return ""; + } +} + +bool CTradingChecks::OkToOpenOrder(string _symbol,ENUM_ORDER_TYPE type, double lots, double entryPrice,double sl, double tp) +{ + if(!IsNewPendingOrderAllowed()) + { + _err = tcErrorOrderLimitReached; + return false; + } + + if(!CheckStopLoss_Takeprofit(_symbol,type,entryPrice,sl,tp)) + { + _err = tcErrorInvalidStops; + return false; + } + + _err = tcErrorNONE; + return true; +} + +#ifdef __MQL5__ +bool CTradingChecks::OkToOpenPosition(string _symbol,ENUM_ORDER_TYPE type, double lots, double entryPrice,double sl, double tp) +{ +#ifdef __MQL5__ + if(!CheckMoneyForTrade(_symbol,lots,type)) + { + _err = tcErrorNotEnoughMoney; + return false; + } + // if(NewOrderAllowedVolume(_symbol) < lots) + // return false; +#else + if(!CheckMoneyForTrade(_symbol,lots,(int)type)) + { + _err = tcErrorNotEnoughMoney; + return false; + } + if(!IsNewPendingOrderAllowed()) + { + _err = tcErrorOrderLimitReached; + return false; + } +#endif + + if(!CheckStopLoss_Takeprofit(_symbol,type,entryPrice,sl,tp)) + { + _err = tcErrorInvalidStops; + return false; + } + + _err = tcErrorNONE; + return true; +} +#endif; + +bool CTradingChecks::OkToModifyOrder(string _symbol, ulong ticket,double price, double sl, double tp) +{ +#ifdef __MQL5__ + if(!OrderModifyCheck(ticket,price,sl,tp)) + { + _err = tcErrorNothingChanged; + return false; + } + if(!CheckOrderForFREEZE_LEVEL(_symbol,ticket)) + { + _err = tcErrorFreezeLevel; + return false; + } +#else + if(!OrderModifyCheck((int)ticket,price,sl,tp)) + { + _err = tcErrorNothingChanged; + return false; + } + if(!CheckOrderForFREEZE_LEVEL(_symbol,(int)ticket)) + { + _err = tcErrorFreezeLevel; + return false; + } +#endif + + if(!CheckPendingOrderEntryChange(_symbol,ticket,price)) + { + _err = tcErrorInvalidPrice; + return false; + } + + _err = tcErrorNONE; + return true; +} + +#ifdef __MQL5__ +bool CTradingChecks::OkToModifyPosition(string _symbol, ulong ticket,double sl,double tp) +{ + if(!PositionModifyCheck(ticket,sl,tp)) + { + _err = tcErrorNothingChanged; + return false; + } + if(!CheckPositionForFREEZE_LEVEL(_symbol,ticket)) + { + _err = tcErrorFreezeLevel; + return false; + } + + _err = tcErrorNONE; + return true; +} +#endif + +////////////////////////////////////////////////////////////////// +// +// Helper functions from https://www.mql5.com/en/articles/2555 +// +/////////////////////////////////////////////////////////////////// + +#ifdef __MQL5__ +bool CheckMoneyForTrade(string symb,double lots,ENUM_ORDER_TYPE type) + { +//--- Getting the opening price + MqlTick mqltick; + SymbolInfoTick(symb,mqltick); + double price=mqltick.ask; + if(type==ORDER_TYPE_SELL) + price=mqltick.bid; +//--- values of the required and free margin + double margin,free_margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE); + //--- call of the checking function + if(!OrderCalcMargin(type,symb,lots,price,margin)) + { + //--- something went wrong, report and return false + Print("Error in ",__FUNCTION__," code=",GetLastError()); + return(false); + } + //--- if there are insufficient funds to perform the operation + if(margin>free_margin) + { + //--- report the error and return false + Print("Not enough money for ",EnumToString(type)," ",lots," ",symb," Error code=",GetLastError()); + Print("Required margin:"+DoubleToString(margin,2)+"; free margin:"+DoubleToString(free_margin,2)); + return(false); + } +//--- checking successful + return(true); + } +#else +bool CheckMoneyForTrade(string symb, double lots,int type) + { + double free_margin=AccountFreeMarginCheck(symb,type, lots); + //-- if there is not enough money + if(free_margin<0) + { + string oper=(type==OP_BUY)? "Buy":"Sell"; + Print("Not enough money for ", oper," ",lots, " ", symb, " Error code=",GetLastError()); + return(false); + } + //--- checking successful + return(true); + } +#endif + + +//+------------------------------------------------------------------+ +//| Check if another order can be placed | +//+------------------------------------------------------------------+ +bool IsNewPendingOrderAllowed() + { +//--- get the number of pending orders allowed on the account + int max_allowed_orders=(int)AccountInfoInteger(ACCOUNT_LIMIT_ORDERS); + +//--- if there is no limitation, return true; you can send an order + if(max_allowed_orders==0) return(true); + +//--- if we passed to this line, then there is a limitation; find out how many orders are already placed + int orders=OrdersTotal(); + +//--- return the result of comparing + return(orders=0) + { + //--- if we have exhausted the volume + if(max_volume-opened_volume<=0) + return(0); + + //--- volume of the open position doesn't exceed max_volume + double orders_volume_on_symbol=PendingsVolume(symbol); + allowed_volume=max_volume-opened_volume-orders_volume_on_symbol; + if(allowed_volume>symbol_max_volume) allowed_volume=symbol_max_volume; + } + return(allowed_volume); + } +#endif + +//+------------------------------------------------------------------+ +//| Check the correctness of StopLoss and TakeProfit | +//+------------------------------------------------------------------+ +bool CheckStopLoss_Takeprofit(string _symbol, ENUM_ORDER_TYPE type,double price,double SL,double TP) + { +//--- get the SYMBOL_TRADE_STOPS_LEVEL level + int stops_level=(int)SymbolInfoInteger(_symbol,SYMBOL_TRADE_STOPS_LEVEL); + if(stops_level!=0) + { + PrintFormat("SYMBOL_TRADE_STOPS_LEVEL=%d: StopLoss and TakeProfit must"+ + " not be nearer than %d points from the closing price",stops_level,stops_level); + } +//--- + bool SL_check=false,TP_check=false; +//--- check the order type + switch(type) + { + //--- Buy operation + case ORDER_TYPE_BUY: + { + //--- check the StopLoss + SL_check= (SL==0) ? true : (Bid-SL>stops_level*_point); + if(!SL_check) + PrintFormat("For order %s StopLoss=%.5f must be less than %.5f"+ + " (Bid=%.5f - SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),SL,Bid-stops_level*_point,Bid,stops_level); + //--- check the TakeProfit + TP_check= (TP==0) ? true : (TP-Bid>stops_level*_point); + if(!TP_check) + PrintFormat("For order %s TakeProfit=%.5f must be greater than %.5f"+ + " (Bid=%.5f + SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),TP,Bid+stops_level*_point,Bid,stops_level); + //--- return the result of checking + return(SL_check&&TP_check); + } + //--- Sell operation + case ORDER_TYPE_SELL: + { + //--- check the StopLoss + SL_check= (SL==0) ? true : (SL-Ask>stops_level*_point); + if(!SL_check) + PrintFormat("For order %s StopLoss=%.5f must be greater than %.5f"+ + " (Ask=%.5f + SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),SL,Ask+stops_level*_point,Ask,stops_level); + //--- check the TakeProfit + TP_check= (TP==0) ? true : (Ask-TP>stops_level*_point); + if(!TP_check) + PrintFormat("For order %s TakeProfit=%.5f must be less than %.5f"+ + " (Ask=%.5f - SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),TP,Ask-stops_level*_point,Ask,stops_level); + //--- return the result of checking + return(TP_check&&SL_check); + } + break; + //--- BuyLimit pending order + case ORDER_TYPE_BUY_LIMIT: + { + //--- check the StopLoss + SL_check= (SL==0) ? true : ((price-SL)>stops_level*_point); + if(!SL_check) + PrintFormat("For order %s StopLoss=%.5f must be less than %.5f"+ + " (Open-StopLoss=%d points ==> SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),SL,price-stops_level*_point,(int)((price-SL)/_point),stops_level); + //--- check the TakeProfit + TP_check= (TP==0) ? true : ((TP-price)>stops_level*_point); + if(!TP_check) + PrintFormat("For order %s TakeProfit=%.5f must be greater than %.5f"+ + " (TakeProfit-Open=%d points ==> SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),TP,price+stops_level*_point,(int)((TP-price)/_point),stops_level); + //--- return the result of checking + return(SL_check&&TP_check); + } + //--- SellLimit pending order + case ORDER_TYPE_SELL_LIMIT: + { + //--- check the StopLoss + SL_check= (SL==0) ? true : ((SL-price)>stops_level*_point); + if(!SL_check) + PrintFormat("For order %s StopLoss=%.5f must be greater than %.5f"+ + " (StopLoss-Open=%d points ==> SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),SL,price+stops_level*_point,(int)((SL-price)/_point),stops_level); + //--- check the TakeProfit + TP_check= (TP==0) ? true : ((price-TP)>stops_level*_point); + if(!TP_check) + PrintFormat("For order %s TakeProfit=%.5f must be less than %.5f"+ + " (Open-TakeProfit=%d points ==> SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),TP,price-stops_level*_point,(int)((price-TP)/_point),stops_level); + //--- return the result of checking + return(TP_check&&SL_check); + } + break; + //--- BuyStop pending order + case ORDER_TYPE_BUY_STOP: + { + //--- check the StopLoss + SL_check= (SL==0) ? true : ((price-SL)>stops_level*_point); + if(!SL_check) + PrintFormat("For order %s StopLoss=%.5f must be less than %.5f"+ + " (Open-StopLoss=%d points ==> SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),SL,price-stops_level*_point,(int)((price-SL)/_point),stops_level); + //--- check the TakeProfit + TP_check= (TP==0) ? true : ((TP-price)>stops_level*_point); + if(!TP_check) + PrintFormat("For order %s TakeProfit=%.5f must be greater than %.5f"+ + " (TakeProfit-Open=%d points ==> SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),TP,price-stops_level*_point,(int)((TP-price)/_point),stops_level); + //--- return the result of checking + return(SL_check&&TP_check); + } + //--- SellStop pending order + case ORDER_TYPE_SELL_STOP: + { + //--- check the StopLoss + SL_check= (SL==0) ? true : ((SL-price)>stops_level*_point); + if(!SL_check) + PrintFormat("For order %s StopLoss=%.5f must be greater than %.5f"+ + " (StopLoss-Open=%d points ==> SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),SL,price+stops_level*_point,(int)((SL-price)/_point),stops_level); + //--- check the TakeProfit + TP_check= (TP==0) ? true : ((price-TP)>stops_level*_point); + if(!TP_check) + PrintFormat("For order %s TakeProfit=%.5f must be less than %.5f"+ + " (Open-TakeProfit=%d points ==> SYMBOL_TRADE_STOPS_LEVEL=%d points)", + EnumToString(type),TP,price-stops_level*_point,(int)((price-TP)/_point),stops_level); + //--- return the result of checking + return(TP_check&&SL_check); + } + break; + } + +//--- + return false; + } + +#ifdef __MQL5__ +//+------------------------------------------------------------------+ +//| Checking the new values of levels before order modification | +//+------------------------------------------------------------------+ +bool OrderModifyCheck(ulong ticket,double price,double sl,double tp) + { +//--- select order by ticket + if(orderinfo.Select(ticket)) + { + //--- point size and name of the symbol, for which a pending order was placed + string symbol=orderinfo.Symbol(); + double point=SymbolInfoDouble(symbol,SYMBOL_POINT); + int digits=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS); + //--- check if there are changes in the Open price + bool PriceOpenChanged=(MathAbs(orderinfo.PriceOpen()-price)>point); + //--- check if there are changes in the StopLoss level + bool StopLossChanged=(MathAbs(orderinfo.StopLoss()-sl)>point); + //--- check if there are changes in the Takeprofit level + bool TakeProfitChanged=(MathAbs(orderinfo.TakeProfit()-tp)>point); + //--- if there are any changes in levels + if(PriceOpenChanged || StopLossChanged || TakeProfitChanged) + return(true); // order can be modified + //--- there are no changes in the Open, StopLoss and Takeprofit levels + else + //--- notify about the error + PrintFormat("Order #%d already has levels of Open=%.5f SL=%.5f TP=%.5f", + ticket,orderinfo.PriceOpen(),orderinfo.StopLoss(),orderinfo.TakeProfit()); + } +//--- came to the end, no changes for the order + return(false); // no point in modifying + } +//+------------------------------------------------------------------+ +//| Checking the new values of levels before order modification | +//+------------------------------------------------------------------+ +bool PositionModifyCheck(ulong ticket,double sl,double tp) + { +//--- select order by ticket + if(positioninfo.SelectByTicket(ticket)) + { + //--- point size and name of the symbol, for which a pending order was placed + string symbol=positioninfo.Symbol(); + double point=SymbolInfoDouble(symbol,SYMBOL_POINT); + //--- check if there are changes in the StopLoss level + bool StopLossChanged=(MathAbs(positioninfo.StopLoss()-sl)>point); + //--- check if there are changes in the Takeprofit level + bool TakeProfitChanged=(MathAbs(positioninfo.TakeProfit()-tp)>point); + //--- if there are any changes in levels + if(StopLossChanged || TakeProfitChanged) + return(true); // position can be modified + //--- there are no changes in the StopLoss and Takeprofit levels + else + //--- notify about the error + PrintFormat("Order #%d already has levels of Open=%.5f SL=%.5f TP=%.5f", + ticket,orderinfo.PriceOpen(),orderinfo.StopLoss(),orderinfo.TakeProfit()); + } +//--- came to the end, no changes for the order + return(false); // no point in modifying + } +#else +//+------------------------------------------------------------------+ +//| Checking the new values of levels before order modification | +//+------------------------------------------------------------------+ +bool OrderModifyCheck(int ticket,double price,double sl,double tp) + { +//--- select order by ticket + if(OrderSelect(ticket,SELECT_BY_TICKET)) + { + //--- point size and name of the symbol, for which a pending order was placed + string symbol=OrderSymbol(); + double point=SymbolInfoDouble(symbol,SYMBOL_POINT); + //--- check if there are changes in the Open price + bool PriceOpenChanged=true; + int type=OrderType(); + if(!(type==OP_BUY || type==OP_SELL)) + { + PriceOpenChanged=(MathAbs(OrderOpenPrice()-price)>point); + } + //--- check if there are changes in the StopLoss level + bool StopLossChanged=(MathAbs(OrderStopLoss()-sl)>point); + //--- check if there are changes in the Takeprofit level + bool TakeProfitChanged=(MathAbs(OrderTakeProfit()-tp)>point); + //--- if there are any changes in levels + if(PriceOpenChanged || StopLossChanged || TakeProfitChanged) + return(true); // order can be modified + //--- there are no changes in the Open, StopLoss and Takeprofit levels + else + //--- notify about the error + PrintFormat("Order #%d already has levels of Open=%.5f SL=%.5f TP=%.5f", + ticket,OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit()); + } +//--- came to the end, no changes for the order + return(false); // no point in modifying + } +#endif + + +#ifdef __MQL5__ +//+------------------------------------------------------------------+ +//| Check the distance from opening price to activation price | +//+------------------------------------------------------------------+ +bool CheckOrderForFREEZE_LEVEL(string _symbol, ulong ticket) + { +//--- get the SYMBOL_TRADE_FREEZE_LEVEL level + int freeze_level=(int)SymbolInfoInteger(_symbol,SYMBOL_TRADE_FREEZE_LEVEL); + if(freeze_level!=0) + { + PrintFormat("SYMBOL_TRADE_FREEZE_LEVEL=%d: Cannot modify order"+ + " nearer than %d points from the activation price",freeze_level,freeze_level); + } +//--- select order for working + if(!OrderSelect(ticket)) + { + //--- failed to select order + return(false); + } +//--- get the order data + double price=OrderGetDouble(ORDER_PRICE_OPEN); + double sl=OrderGetDouble(ORDER_SL); + double tp=OrderGetDouble(ORDER_TP); + ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); +//--- result of checking + bool check=false; +//--- check the order type + switch(type) + { + //--- BuyLimit pending order + case ORDER_TYPE_BUY_LIMIT: + { + //--- check the distance from the opening price to the activation price + check=((Ask-price)>freeze_level*_point); + if(!check) + PrintFormat("Order %s #%d cannot be modified: Ask-Open=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + EnumToString(type),ticket,(int)((Ask-price)/_point),freeze_level); + return(check); + } + //--- BuyLimit pending order + case ORDER_TYPE_SELL_LIMIT: + { + //--- check the distance from the opening price to the activation price + check=((price-Bid)>freeze_level*_point); + if(!check) + PrintFormat("Order %s #%d cannot be modified: Open-Bid=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + EnumToString(type),ticket,(int)((price-Bid)/_point),freeze_level); + return(check); + } + break; + //--- BuyStop pending order + case ORDER_TYPE_BUY_STOP: + { + //--- check the distance from the opening price to the activation price + check=((price-Ask)>freeze_level*_point); + if(!check) + PrintFormat("Order %s #%d cannot be modified: Ask-Open=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + EnumToString(type),ticket,(int)((price-Ask)/_point),freeze_level); + return(check); + } + //--- SellStop pending order + case ORDER_TYPE_SELL_STOP: + { + //--- check the distance from the opening price to the activation price + check=((Bid-price)>freeze_level*_point); + if(!check) + PrintFormat("Order %s #%d cannot be modified: Bid-Open=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + EnumToString(type),ticket,(int)((Bid-price)/_point),freeze_level); + return(check); + } + break; + } +//--- order did not pass the check + return (false); + } +//+------------------------------------------------------------------+ +//| Check if the TP and SL are too close to activation price | +//+------------------------------------------------------------------+ +bool CheckPositionForFREEZE_LEVEL(string _symbol, ulong ticket) + { + +//--- get the SYMBOL_TRADE_FREEZE_LEVEL level + int freeze_level=(int)SymbolInfoInteger(_symbol,SYMBOL_TRADE_FREEZE_LEVEL); + if(freeze_level!=0) + { + PrintFormat("SYMBOL_TRADE_FREEZE_LEVEL=%d: Cannot modify order"+ + " nearer than %d points from the activation price",freeze_level,freeze_level); + } +//--- select position for working + if(!PositionSelectByTicket(ticket)) + { + //--- failed to select position + return(false); + } +//--- get the order data + ENUM_POSITION_TYPE pos_type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); + double sl=PositionGetDouble(POSITION_SL); + double tp=PositionGetDouble(POSITION_TP); +//--- result of checking StopLoss and TakeProfit + bool SL_check=false,TP_check=false; +//--- position type + switch(pos_type) + { + //--- buy + case POSITION_TYPE_BUY: + { + SL_check=(sl == 0) ? true: (Bid-sl>freeze_level*_point); + if(!SL_check) + PrintFormat("Position %s #%d cannot be modified: Bid-StopLoss=%d points"+ + " < SYMBOL_TRADE_FREEZE_LEVEL=%d points)", + EnumToString(pos_type),ticket,(int)((Bid-sl)/_point),freeze_level); + TP_check=(tp == 0) ? true: (tp-Bid>freeze_level*_point); + if(!TP_check) + PrintFormat("Position %s #%d cannot be modified: TakeProfit-Bid=%d points"+ + " < SYMBOL_TRADE_FREEZE_LEVEL=%d points)", + EnumToString(pos_type),ticket,(int)((tp-Bid)/_point),freeze_level); + //--- return the result of checking + return(SL_check&&TP_check); + } + break; + //--- sell + case POSITION_TYPE_SELL: + { + SL_check=(sl == 0) ? true: (sl-Ask>freeze_level*_point); + if(!SL_check) + PrintFormat("Position %s cannot be modified: StopLoss-Ask=%d points"+ + " < SYMBOL_TRADE_FREEZE_LEVEL=%d points)", + EnumToString(pos_type),(int)((sl-Ask)/_point),freeze_level); + TP_check=(tp == 0) ? true: (Ask-tp>freeze_level*_point); + if(!TP_check) + PrintFormat("Position %s cannot be modified: Ask-TakeProfit=%d points"+ + " < SYMBOL_TRADE_FREEZE_LEVEL=%d points)", + EnumToString(pos_type),(int)((Ask-tp)/_point),freeze_level); + //--- return the result of checking + return(SL_check&&TP_check); + } + break; + } +//--- position did not pass the check + return (false); + } +#else +bool CheckOrderForFREEZE_LEVEL(string _symbol,int ticket) + { +//--- get the SYMBOL_TRADE_FREEZE_LEVEL level + int freeze_level=(int)SymbolInfoInteger(_symbol,SYMBOL_TRADE_FREEZE_LEVEL); + if(freeze_level!=0) + { + PrintFormat("SYMBOL_TRADE_FREEZE_LEVEL=%d: Cannot modify order"+ + " nearer than %d points from the activation price",freeze_level,freeze_level); + } +//--- select order for working + if(!OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) + { + //--- failed to select order + return (false); + } +//--- get the order data + double price=OrderOpenPrice(); + double sl=OrderStopLoss(); + double tp=OrderTakeProfit(); + int type=OrderType(); +//--- result of checking + bool check=false; +//--- check the order type + switch(type) + { + //--- BuyLimit pending order + case OP_BUYLIMIT: + { + //--- check the distance from the opening price to the activation price + check=((Ask-price)>freeze_level*_point); + if(!check) + PrintFormat("Order OP_BUYLIMIT #%d cannot be modified: Ask-Open=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + ticket,(int)((Ask-price)/_point),freeze_level); + return(check); + } + //--- BuyLimit pending order + case OP_SELLLIMIT: + { + //--- check the distance from the opening price to the activation price + check=((price-Bid)>freeze_level*_point); + if(!check) + PrintFormat("Order OP_SELLLIMIT #%d cannot be modified: Open-Bid=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + ticket,(int)((price-Bid)/_point),freeze_level); + return(check); + } + break; + //--- BuyStop pending order + case OP_BUYSTOP: + { + //--- check the distance from the opening price to the activation price + check=((price-Ask)>freeze_level*_point); + if(!check) + PrintFormat("Order OP_BUYSTOP #%d cannot be modified: Ask-Open=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + ticket,(int)((price-Ask)/_point),freeze_level); + return(check); + } + //--- SellStop pending order + case OP_SELLSTOP: + { + //--- check the distance from the opening price to the activation price + check=((Bid-price)>freeze_level*_point); + if(!check) + PrintFormat("Order OP_SELLSTOP #%d cannot be modified: Bid-Open=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + ticket,(int)((Bid-price)/_point),freeze_level); + return(check); + } + break; + //--- checking opened Buy order + case OP_BUY: + { + //--- check TakeProfit distance to the activation price + bool TP_check=(tp == 0) ? true: (tp-Bid>freeze_level*_point); + if(!TP_check) + PrintFormat("Order OP_BUY %d cannot be modified: TakeProfit-Bid=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + ticket,(int)((tp-Bid)/_point),freeze_level); + //--- check TakeProfit distance to the activation price + bool SL_check=(sl == 0) ? true: (Bid-sl>freeze_level*_point); + if(!SL_check) + PrintFormat("Order OP_BUY %d cannot be modified: TakeProfit-Bid=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + ticket,(int)((Bid-sl)/_point),freeze_level); + return(SL_check&&TP_check); + } + break; + //--- checking opened Sell order + case OP_SELL: + { + //--- check TakeProfit distance to the activation price + bool TP_check=(tp == 0) ? true: (Ask-tp>freeze_level*_point); + if(!TP_check) + PrintFormat("Order OP_SELL %d cannot be modified: Ask-TakeProfit=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + ticket,(int)((Ask-tp)/_point),freeze_level); + //--- check TakeProfit distance to the activation price + bool SL_check=(sl == 0) ? true: (sl-Ask>freeze_level*_point); + if(!SL_check) + PrintFormat("Order OP_BUY %d cannot be modified: TakeProfit-Bid=%d points < SYMBOL_TRADE_FREEZE_LEVEL=%d points", + ticket,(int)((sl-Ask)/_point),freeze_level); + return(SL_check&&TP_check); + } + break; + } +//--- order did not pass the check + return (false); + } +#endif + +bool CheckPendingOrderEntryChange(string _symbol, ulong ticket, double newEntryPrice) + { +//--- select order for working + if(!OrderSelect(ticket)) + { + //--- failed to select order + return(false); + } +//--- get the order data + ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)OrderGetInteger(ORDER_TYPE); +//--- result of checking + bool check=false; +//--- check the order type + switch(type) + { + //--- BuyLimit pending order + case ORDER_TYPE_BUY_LIMIT: + { + //--- check the distance from the opening price to the activation price + check= (newEntryPrice < Ask); + if(!check) + PrintFormat("Order %s #%d cannot be modified", + EnumToString(type),ticket); + return(check); + } + //--- BuyLimit pending order + case ORDER_TYPE_SELL_LIMIT: + { + //--- check the distance from the opening price to the activation price + check=(newEntryPrice > Bid); + if(!check) + PrintFormat("Order %s #%d cannot be modified", + EnumToString(type),ticket); + return(check); + } + break; + //--- BuyStop pending order + case ORDER_TYPE_BUY_STOP: + { + //--- check the distance from the opening price to the activation price + check=(newEntryPrice > Ask); + if(!check) + PrintFormat("Order %s #%d cannot be modified", + EnumToString(type),ticket); + return(check); + } + //--- SellStop pending order + case ORDER_TYPE_SELL_STOP: + { + //--- check the distance from the opening price to the activation price + check=(newEntryPrice < Bid); + if(!check) + PrintFormat("Order %s #%d cannot be modified", + EnumToString(type),ticket); + return(check); + } + break; + } +//--- order did not pass the check + return (false); + } \ No newline at end of file