Files
2019-05-14 17:22:40 +02:00

932 lines
35 KiB
Plaintext

//
// Copyright 2018, Artur Zas
// https://www.az-invest.eu
// https://www.mql5.com/en/users/arturz
//
#ifdef __MQL5__
//--- class for performing trade operations
#include <Trade\Trade.mqh>
CTrade trade;
//--- class for working with orders
#include <Trade\OrderInfo.mqh>
COrderInfo orderinfo;
//--- class for working with positions
#include <Trade\PositionInfo.mqh>
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)
bool suppressLogOutput = false;
void SuppressGlobalLogOutput() { suppressLogOutput = true; };
#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;
bool _suppressLogOutput;
public:
CTradingChecks();
~CTradingChecks();
string GetCheckErrorToString();
void SuppressLogOutput() { _suppressLogOutput = true; };
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)
{
suppressLogOutput = false;
}
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
if(suppressLogOutput == 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
if(suppressLogOutput == 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";
if(suppressLogOutput == false)
{
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<max_allowed_orders);
}
#ifdef __MQL5__
//+------------------------------------------------------------------+
//| Return the size of position on the specified symbol |
//+------------------------------------------------------------------+
double PositionVolume(string symbol)
{
//--- try to select position by a symbol
bool selected=PositionSelect(symbol);
//--- there is a position
if(selected)
//--- return volume of the position
return(PositionGetDouble(POSITION_VOLUME));
else
{
//--- report a failure to select position
if(suppressLogOutput == false)
{
Print(__FUNCTION__," Failed to perform PositionSelect() for symbol ",
symbol," Error ",GetLastError());
}
return(-1);
}
}
//+------------------------------------------------------------------+
//| returns the volume of current pending order by a symbol |
//+------------------------------------------------------------------+
double PendingsVolume(string symbol)
{
double volume_on_symbol=0;
ulong ticket;
//--- get the number of all currently placed orders by all symbols
int all_orders=OrdersTotal();
//--- get over all orders in the loop
for(int i=0;i<all_orders;i++)
{
//--- get the ticket of an order by its position in the list
ticket = OrderGetTicket(i);
if((bool)ticket)
{
//--- if our symbol is specified in the order, add the volume of this order
if(symbol==OrderGetString(ORDER_SYMBOL))
volume_on_symbol+=OrderGetDouble(ORDER_VOLUME_INITIAL);
}
}
//--- return the total volume of currently placed pending orders for a specified symbol
return(volume_on_symbol);
}
//+------------------------------------------------------------------+
//| Return the maximum allowed volume for an order on the symbol |
//+------------------------------------------------------------------+
double NewOrderAllowedVolume(string symbol)
{
double allowed_volume=0;
//--- get the limitation on the maximal volume of an order
double symbol_max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX);
//--- get the limitation on the volume by a symbol
double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_LIMIT);
//--- get the volume of the open position by a symbol
double opened_volume=PositionVolume(symbol);
if(opened_volume>=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)
{
if(suppressLogOutput == false)
{
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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
if(suppressLogOutput == false)
{
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
if(suppressLogOutput == false)
{
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
if(suppressLogOutput == false)
{
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)
{
if(suppressLogOutput == false)
{
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
{
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
{
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
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 && suppressLogOutput == false)
PrintFormat("Order %s #%d cannot be modified",
EnumToString(type),ticket);
return(check);
}
break;
}
//--- order did not pass the check
return (false);
}