TF-altProjekte/Experts/5022/Combination1/Trade.mqh

1258 lines
94 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:31:33 +02:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Trade.mqh |
//| Copyright 2017, Alexander Fedosov |
//| https://www.mql5.com/en/users/alex2356 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, Alexander Fedosov"
#property link "https://www.mql5.com/en/users/alex2356"
#property version "2.0"
//--- Enumeration for lot calculation options
enum MarginMode
{
FREEMARGIN=0, //MM Free Margin
BALANCE, //MM Balance
LOT //Constant Lot
};
//--- Enumeration of basic lot options
enum LotType
{
MINLOT=0,
BASELOT
};
//+------------------------------------------------------------------+
//| The library of trading operations |
//+------------------------------------------------------------------+
class CTradeBase
{
private:
//--- Selection of basic lot calculation options
MarginMode m_mm_lot;
LotType m_type_lot;
double m_base_lot;
//--- Slippage
uint m_deviation;
ENUM_ACCOUNT_MARGIN_MODE m_margin_mode;
//-- Expert Advisor name
string m_ea_name;
//-- Language for error messages
string m_lang;
//--- Lot calculation for positions opened with lot_margin
double GetLotForOpeningPos(string symbol,ENUM_POSITION_TYPE direction,double lot_margin);
//--- Return the fill type
ENUM_ORDER_TYPE_FILLING GetFilling(void);
//---
int GetDig(string symbol);
//--- Correction of a lot size to the nearest acceptable value
bool LotCorrect(string symbol,ENUM_POSITION_TYPE trade_operation);
//--- Limitation of a lot size by a deposit capacity
bool LotFreeMarginCorrect(string symbol,ENUM_POSITION_TYPE trade_operation);
//--- Lot calculation
double LotCount(string symbol,ENUM_POSITION_TYPE directon,double base_lot);
//--- Correction of a pending order size to an acceptable value
int StopCorrect(string symbol,int Stop);
bool dStopCorrect(string symbol,double &dStopLoss,double &dTakeprofit,ENUM_POSITION_TYPE trade_operation);
//--- Returning a trade operation string result by its code
string ResultRetcodeDescription(int retcode);
//--- Selecting a position with the specified index
bool SelectByIndex(const int index);
//--- position select depending on netting or hedging
bool SelectPosition(const string symbol,int MagicNumber);
//---
bool IsHedging(void) const { return(m_margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); }
public:
CTradeBase(void);
~CTradeBase(void);
//--- Setting lot calculation option
void SetMM(const MarginMode MM) { m_mm_lot=MM; }
//--- Setting lot option
void SetLotType(const LotType Lot) { m_type_lot=Lot; }
//--- Setting Expert Advisor name
void SetNameEA(const string NameEA) { m_ea_name=NameEA; }
//--- Setting language for the errors
void SetLanguage(const string Lang) { m_lang=Lang; }
//--- Setting slippage
void SetDeviation(const uint Dev) { m_deviation=Dev; }
//--- Opening a long position, stop levels in points
bool BuyPositionOpen(const string symbol,double Lot,int StopLoss,int Takeprofit,int MagicNumber,string TradeComm);
//--- Opening a long position, stop levels in price units
bool BuyPositionOpen(const string symbol,double Lot,double dStopLoss,double dTakeprofit,int MagicNumber,string TradeComm);
//--- Opening a short position, stop levels in points
bool SellPositionOpen(const string symbol,double Lot,int StopLoss,int Takeprofit,int MagicNumber,string TradeComm);
//--- Opening a short position, stop levels in price units
bool SellPositionOpen(const string symbol,double Lot,double dStopLoss,double dTakeprofit,int MagicNumber,string TradeComm);
//--- Modification of a long position in points
bool BuyPositionModify(const string symbol,int StopLoss,int Takeprofit);
//--- Modification of a long position in price units
bool BuyPositionModify(const string symbol,double dStopLoss,double dTakeprofit);
//--- Modification of a short position in points
bool SellPositionModify(const string symbol,int StopLoss,int Takeprofit);
//--- Modification of a short position in price units
bool SellPositionModify(const string symbol,double dStopLoss,double dTakeprofit);
//--- Closing a position by type
bool ClosePositionByType(const string symbol,ENUM_POSITION_TYPE PosType,int MagicNumber);
//--- Checking open positions with the magic number
bool IsOpenedByMagic(int MagicNumber);
//--- Checking open position types with the magic number
bool IsOpenedByType(ENUM_POSITION_TYPE PosType,int MagicNumber);
//--- Checking open positions on the symbol with the magic number
bool IsOpenedBySymbol(string symbol,int MagicNumber);
//--- Checking allowable symbol spread
bool MaxSpread(string symbol,int MaxLevelSpread);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CTradeBase::CTradeBase(void): m_mm_lot(LOT),
m_type_lot(MINLOT),
m_ea_name("EA"),
m_lang("en"),
m_deviation(20)
{
m_margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CTradeBase::~CTradeBase(void)
{
}
//+------------------------------------------------------------------+
//| Opening a long position, stop levels in points |
//+------------------------------------------------------------------+
bool CTradeBase::BuyPositionOpen
(
const string symbol, // deal trading pair
double Lot, // MM
int StopLoss, // stop loss in points
int Takeprofit, // take profit in points
int MagicNumber, // magic number
string TradeComm="" // comments
)
{
//---
ENUM_POSITION_TYPE PosType=POSITION_TYPE_BUY;
//----
double volume=LotCount(symbol,PosType,Lot);
if(volume<=0)
{
Print(__FUNCTION__,"(): Invalid volume for the trade request structure");
return(false);
}
//---- Declare structures of trade request and result of trade request
MqlTradeRequest request;
MqlTradeResult result;
//---- Declaration of the structure of a trade request checking result
MqlTradeCheckResult check;
//---- nulling the structures
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
long digit;
double point,Ask;
//----
if(!SymbolInfoInteger(symbol,SYMBOL_DIGITS,digit))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_ASK,Ask))
return(true);
//---- Initializing structure of the MqlTradeRequest to open BUY position
request.type = ORDER_TYPE_BUY;
request.price = Ask;
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = volume;
request.magic = MagicNumber;
request.comment= TradeComm;
request.deviation=m_deviation;
request.type_filling=GetFilling();
//---- Determine distance to Stop Loss (in price chart units)
if(StopLoss!=0)
{
StopLoss=StopCorrect(symbol,StopLoss);
if(StopLoss==0)
return(false);
double dStopLoss=StopLoss*point*GetDig(symbol);
request.sl=NormalizeDouble(request.price-dStopLoss,int(digit));
}
else
request.sl=0.0;
//---- Determine distance to Take Profit (in price chart units)
if(Takeprofit!=0)
{
Takeprofit=StopCorrect(symbol,Takeprofit);
if(Takeprofit==0)
return(false);
double dTakeprofit=Takeprofit*point*GetDig(symbol);
request.tp=NormalizeDouble(request.price+dTakeprofit,int(digit));
}
else
request.tp=0.0;
//---- Checking correctness of a trade request
if(!OrderCheck(request,check))
{
Print(__FUNCTION__,"(): Incorrect data structure for trade request!");
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(check.retcode));
return(false);
}
string comment="";
StringConcatenate(comment,m_ea_name,": Opening Buy position to ",symbol,"");
Print(comment);
//---- Open BUY position and check the result of trade request
if(!OrderSend(request,result) || result.retcode!=TRADE_RETCODE_DONE)
{
Print(__FUNCTION__,"(): You can not make a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
return(false);
}
else if(result.retcode==TRADE_RETCODE_DONE)
{
comment="";
StringConcatenate(comment,m_ea_name,": Buy position to ",symbol," opened.");
Print(comment);
}
else
{
Print(__FUNCTION__,"(): You can not make a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
}
//----
return(true);
}
//+------------------------------------------------------------------+
//| Opening a long position, stop levels in price units |
//+------------------------------------------------------------------+
bool CTradeBase::BuyPositionOpen
(
const string symbol, // deal trading pair
double Lot, // MM
double dStopLoss, // stop loss in price chart units
double dTakeprofit, // take profit in price chart units
int MagicNumber, //magic number
string TradeComm="" // comments
)
{
//---
ENUM_POSITION_TYPE PosType=POSITION_TYPE_BUY;
//---- Declare structures of trade request and result of trade request
MqlTradeRequest request;
MqlTradeResult result;
//---- Declaration of the structure of a trade request checking result
MqlTradeCheckResult check;
//---- nulling the structures
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
long digit;
double point,Ask;
//----
if(!SymbolInfoInteger(symbol,SYMBOL_DIGITS,digit))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_ASK,Ask))
return(true);
//---- correcting the distances for stop loss and take profit (in price chart units)
if(!dStopCorrect(symbol,dStopLoss,dTakeprofit,PosType))
return(false);
//----
double volume=LotCount(symbol,PosType,Lot);
if(volume<=0)
{
Print(__FUNCTION__,"(): Invalid volume for the trade request structure");
return(false);
}
//---- Initializing structure of the MqlTradeRequest to open BUY position
request.type = ORDER_TYPE_BUY;
request.price = Ask;
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = volume;
request.sl=dStopLoss;
request.tp=dTakeprofit;
request.deviation=m_deviation;
request.magic=MagicNumber;
request.comment=TradeComm;
request.type_filling=GetFilling();
//---- Checking correctness of a trade request
if(!OrderCheck(request,check))
{
Print(__FUNCTION__,"(): Incorrect data structure for trade request!");
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(check.retcode));
return(false);
}
string comment="";
StringConcatenate(comment,"Open Buy position to ",symbol);
Print(comment);
//---- Open BUY position and check the result of trade request
if(!OrderSend(request,result) || result.retcode!=TRADE_RETCODE_DONE)
{
Print(__FUNCTION__,"(): You can not make a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
return(false);
}
else if(result.retcode==TRADE_RETCODE_DONE)
{
comment="";
StringConcatenate(comment,m_ea_name,": Buy position to ",symbol," opened.");
Print(comment);
}
else
{
Print(__FUNCTION__,"(): You can not make a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
}
//----
return(true);
}
//+------------------------------------------------------------------+
//| Opening a short position, stop levels in points |
//+------------------------------------------------------------------+
bool CTradeBase::SellPositionOpen
(
const string symbol, // deal trading pair
double Lot, // MM
int StopLoss, // stop loss in points
int Takeprofit, // take profit in points
int MagicNumber, // magic number
string TradeComm="" // comments
)
{
//---
ENUM_POSITION_TYPE PosType=POSITION_TYPE_SELL;
//----
double volume=LotCount(symbol,PosType,Lot);
if(volume<=0)
{
Print(__FUNCTION__,"(): Invalid volume for the trade request structure");
return(false);
}
//---- Declare structures of trade request and result of trade request
MqlTradeRequest request;
MqlTradeResult result;
//---- Declaration of the structure of a trade request checking result
MqlTradeCheckResult check;
//---- nulling the structures
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
long digit;
double point,Bid;
//----
if(!SymbolInfoInteger(symbol,SYMBOL_DIGITS,digit)) return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point)) return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_BID,Bid)) return(true);
//---- Initializing structure of the MqlTradeRequest to open SELL position
request.type = ORDER_TYPE_SELL;
request.price = Bid;
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = volume;
request.magic=MagicNumber;
request.comment=TradeComm;
request.deviation=m_deviation;
request.type_filling=GetFilling();
//---- Determine distance to Stop Loss (in price chart units)
if(StopLoss!=0)
{
StopLoss=StopCorrect(symbol,StopLoss);
if(StopLoss==0)
return(false);
double dStopLoss=StopLoss*point*GetDig(symbol);
request.sl=NormalizeDouble(request.price+dStopLoss,int(digit));
}
else
request.sl=0.0;
//---- Determine distance to Take Profit (in price chart units)
if(Takeprofit!=0)
{
Takeprofit=StopCorrect(symbol,Takeprofit);
if(Takeprofit==0)
return(false);
double dTakeprofit=Takeprofit*point*GetDig(symbol);
request.tp=NormalizeDouble(request.price-dTakeprofit,int(digit));
}
else
request.tp=0.0;
//---- Checking correctness of a trade request
if(!OrderCheck(request,check))
{
Print(__FUNCTION__,"(): Incorrect data structure for trade request!");
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(check.retcode));
return(false);
}
string comment="";
StringConcatenate(comment,m_ea_name,": Opening Sell position to ",symbol,"");
Print(comment);
//---- Open SELL position and check the result of trade request
if(!OrderSend(request,result) || result.retcode!=TRADE_RETCODE_DONE)
{
Print(__FUNCTION__,"(): You can not make a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
return(false);
}
else if(result.retcode==TRADE_RETCODE_DONE)
{
comment="";
StringConcatenate(comment,m_ea_name,": Sell position to ",symbol," opened.");
Print(comment);
}
else
{
Print(__FUNCTION__,"(): You can not make a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
}
//----
return(true);
}
//+------------------------------------------------------------------+
//| Open a short position |
//+------------------------------------------------------------------+
bool CTradeBase:: SellPositionOpen
(
const string symbol, // deal trading pair
double Lot, // MM
double dStopLoss, // stop loss in price chart units
double dTakeprofit, // take profit in price chart units
int MagicNumber, //magic number
string TradeComm="" // comments
)
{
//---
ENUM_POSITION_TYPE PosType=POSITION_TYPE_SELL;
//---- Declare structures of trade request and result of trade request
MqlTradeRequest request;
MqlTradeResult result;
//---- Declaration of the structure of a trade request checking result
MqlTradeCheckResult check;
//---- nulling the structures
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
long digit;
double point,Bid;
//----
if(!SymbolInfoInteger(symbol,SYMBOL_DIGITS,digit))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_BID,Bid))
return(true);
//---- correcting the distances for stop loss and take profit (in price chart units)
if(!dStopCorrect(symbol,dStopLoss,dTakeprofit,PosType))
return(false);
//----
double volume=LotCount(symbol,PosType,Lot);
if(volume<=0)
{
Print(__FUNCTION__,"(): Invalid volume for the trade request structure");
return(false);
}
//---- Initializing structure of the MqlTradeRequest to open SELL position
request.type = ORDER_TYPE_SELL;
request.price = Bid;
request.action = TRADE_ACTION_DEAL;
request.symbol = symbol;
request.volume = volume;
request.sl=dStopLoss;
request.tp=dTakeprofit;
request.deviation=m_deviation;
request.magic=MagicNumber;
request.comment=TradeComm;
request.type_filling=GetFilling();
//---- Checking correctness of a trade request
if(!OrderCheck(request,check))
{
Print(__FUNCTION__,"(): Incorrect data structure for trade request!");
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(check.retcode));
return(false);
}
string comment="";
StringConcatenate(comment,m_ea_name,": Opening Sell position to ",symbol);
Print(comment);
//---- Open SELL position and check the result of trade request
if(!OrderSend(request,result) || result.retcode!=TRADE_RETCODE_DONE)
{
Print(__FUNCTION__,"(): You can not make a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
return(false);
}
else if(result.retcode==TRADE_RETCODE_DONE)
{
comment="";
StringConcatenate(comment,m_ea_name,": Sell position to ",symbol," opened.");
Print(comment);
}
else
{
Print(__FUNCTION__,"(): You can not make a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
}
//----
return(true);
}
//+------------------------------------------------------------------+
//| Modifying a long position |
//+------------------------------------------------------------------+
bool CTradeBase::BuyPositionModify(const string symbol,int StopLoss,int Takeprofit)
{
//---
ENUM_POSITION_TYPE PosType=POSITION_TYPE_BUY;
//---- Checking, if there is an open position
if(!PositionSelect(symbol))
return(true);
//---- Declare structures of trade request and result of trade request
MqlTradeRequest request;
MqlTradeResult result;
//---- Declaration of the structure of a trade request checking result
MqlTradeCheckResult check;
//---- nulling the structures
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
long digit;
double point,Ask;
//----
if(!SymbolInfoInteger(symbol,SYMBOL_DIGITS,digit))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_ASK,Ask))
return(true);
//---- Initializing structure of the MqlTradeRequest to open BUY position
request.type = ORDER_TYPE_BUY;
request.action = TRADE_ACTION_SLTP;
request.symbol = symbol;
request.type_filling=GetFilling();
request.deviation=m_deviation;
//---- Determine distance to Stop Loss (in price chart units)
if(StopLoss)
{
StopLoss=StopCorrect(symbol,StopLoss);
double dStopLoss=StopLoss*point*GetDig(symbol);
request.sl=NormalizeDouble(PositionGetDouble(POSITION_PRICE_OPEN)-dStopLoss,int(digit));
}
else
request.sl=PositionGetDouble(POSITION_SL);
//---- Determine distance to Take Profit (in price chart units)
if(Takeprofit)
{
Takeprofit=StopCorrect(symbol,Takeprofit);
double dTakeprofit=Takeprofit*point*GetDig(symbol);
request.tp=NormalizeDouble(PositionGetDouble(POSITION_PRICE_OPEN)+dTakeprofit,int(digit));
}
else
request.tp=PositionGetDouble(POSITION_TP);
//----
if(request.tp==PositionGetDouble(POSITION_TP) && request.sl==PositionGetDouble(POSITION_SL))
return(true);
//---- Checking correctness of a trade request
if(!OrderCheck(request,check))
{
Print(__FUNCTION__,"(): Incorrect data structure for trade request!");
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(check.retcode));
return(false);
}
string comment="";
StringConcatenate(comment,"Modify Buy position to ",symbol);
Print(comment);
//---- Modifying SELL position and checking the result of a trade request
if(!OrderSend(request,result) || result.retcode!=TRADE_RETCODE_DONE)
{
Print(__FUNCTION__,"(): You can not modify a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
return(false);
}
else
if(result.retcode==TRADE_RETCODE_DONE)
{
comment="";
StringConcatenate(comment,"Buy position to ",symbol," modified.");
Print(comment);
}
else
{
Print(__FUNCTION__,"(): You can not modify a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
}
//----
return(true);
}
//+------------------------------------------------------------------+
//| Close specified opened position |
//+------------------------------------------------------------------+
bool CTradeBase::ClosePositionByType(const string symbol,ENUM_POSITION_TYPE PosType,int MagicNumber)
{
//---- Declare structures of trade request and result of trade request
MqlTradeRequest request;
MqlTradeResult result;
//---- Declaration of the structure of a trade request checking result
MqlTradeCheckResult check;
bool partial_close=false;
int retry_count=10;
uint retcode=TRADE_RETCODE_REJECT;
//---- nulling the structures
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
do
{
if(SelectPosition(symbol,MagicNumber))
{
if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY &&
PosType==POSITION_TYPE_BUY
)
{
request.type =ORDER_TYPE_SELL;
request.price=SymbolInfoDouble(symbol,SYMBOL_BID);
}
else if((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL &&
PosType==POSITION_TYPE_SELL
)
{
request.type =ORDER_TYPE_BUY;
request.price=SymbolInfoDouble(symbol,SYMBOL_ASK);
}
}
else
{
//--- position not found
result.retcode=retcode;
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(result.retcode));
return(false);
}
//--- setting request
request.action =TRADE_ACTION_DEAL;
request.symbol =symbol;
request.volume =PositionGetDouble(POSITION_VOLUME);
request.magic =MagicNumber;
request.deviation=m_deviation;
request.type_filling=GetFilling();
//--- hedging? just send order
if(IsHedging())
{
request.position=PositionGetInteger(POSITION_TICKET);
return(OrderSend(request,result));
}
//--- check volume
double max_volume=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
if(request.volume>max_volume)
{
request.volume=max_volume;
partial_close=true;
}
else
partial_close=false;
//--- order send
if(!OrderSend(request,result))
{
if(--retry_count!=0) continue;
if(retcode==TRADE_RETCODE_DONE_PARTIAL)
result.retcode=retcode;
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
return(false);
}
retcode=TRADE_RETCODE_DONE_PARTIAL;
if(partial_close)
Sleep(1000);
}
while(partial_close);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Modifying a short position in points |
//+------------------------------------------------------------------+
bool CTradeBase::SellPositionModify
(
const string symbol, // deal trading pair
int StopLoss, // Stop loss in points
int Takeprofit // Take profit in points
)
{
//---
ENUM_POSITION_TYPE PosType=POSITION_TYPE_SELL;
//---- Checking, if there is an open position
if(!PositionSelect(symbol))
return(true);
//---- Declare structures of trade request and result of trade request
MqlTradeRequest request;
MqlTradeResult result;
//---- Declaration of the structure of a trade request checking result
MqlTradeCheckResult check;
//---- nulling the structures
ZeroMemory(request);
ZeroMemory(result);
ZeroMemory(check);
//----
long digit;
double point,Bid;
//----
if(!SymbolInfoInteger(symbol,SYMBOL_DIGITS,digit))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point))
return(true);
if(!SymbolInfoDouble(symbol,SYMBOL_BID,Bid))
return(true);
//---- Initializing structure of the MqlTradeRequest to open BUY position
request.position=PositionGetInteger(POSITION_TICKET);
request.type = ORDER_TYPE_SELL;
request.action = TRADE_ACTION_SLTP;
request.symbol = symbol;
request.deviation=m_deviation;
request.type_filling=GetFilling();
//---- Determine distance to Stop Loss (in price chart units)
if(StopLoss!=0)
{
StopLoss=StopCorrect(symbol,StopLoss);
double dStopLoss=StopLoss*point*GetDig(symbol);
request.sl=NormalizeDouble(PositionGetDouble(POSITION_PRICE_OPEN)+dStopLoss,int(digit));
}
else
request.sl=PositionGetDouble(POSITION_SL);
//---- Determine distance to Take Profit (in price chart units)
if(Takeprofit!=0)
{
Takeprofit=StopCorrect(symbol,Takeprofit);
double dTakeprofit=Takeprofit*point*GetDig(symbol);
request.tp=NormalizeDouble(PositionGetDouble(POSITION_PRICE_OPEN)-dTakeprofit,int(digit));
}
else
request.tp=PositionGetDouble(POSITION_TP);
//----
if(request.tp==PositionGetDouble(POSITION_TP) && request.sl==PositionGetDouble(POSITION_SL))
return(true);
//---- Checking correctness of a trade request
if(!OrderCheck(request,check))
{
Print(__FUNCTION__,"(): Incorrect data structure for trade request!");
Print(__FUNCTION__,"(): OrderCheck(): ",ResultRetcodeDescription(check.retcode));
return(false);
}
string comment="";
StringConcatenate(comment,"Modify Sell position to ",symbol);
Print(comment);
//---- Modifying SELL position and checking the result of a trade request
if(!OrderSend(request,result) || result.retcode!=TRADE_RETCODE_DONE)
{
Print(__FUNCTION__,"(): You can not modify a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
return(false);
}
else
if(result.retcode==TRADE_RETCODE_DONE)
{
comment="";
StringConcatenate(comment,"Sell position to ",symbol," modified.");
Print(comment);
}
else
{
Print(__FUNCTION__,"(): You can not modify a deal!");
Print(__FUNCTION__,"(): OrderSend(): ",ResultRetcodeDescription(result.retcode));
}
//----
return(true);
}
//+------------------------------------------------------------------+
//| Checking open positions with the magic number |
//+------------------------------------------------------------------+
bool CTradeBase:: IsOpenedByMagic(int MagicNumber)
{
int pos=0;
uint total=PositionsTotal();
//---
for(uint i=0; i<total; i++)
{
if(SelectByIndex(i))
if(PositionGetInteger(POSITION_MAGIC)==MagicNumber)
pos++;
}
return((pos>0)?true:false);
}
//+------------------------------------------------------------------+
//| Checking open position types with the magic number |
//+------------------------------------------------------------------+
bool CTradeBase:: IsOpenedByType(ENUM_POSITION_TYPE PosType,int MagicNumber)
{
int pos=0;
uint total=PositionsTotal();
//---
for(uint i=0; i<total; i++)
{
if(SelectByIndex(i))
if(PositionGetInteger(POSITION_TYPE)==PosType && PositionGetInteger(POSITION_MAGIC)==MagicNumber)
pos++;
}
return((pos>0)?true:false);
}
//+------------------------------------------------------------------+
//| Checking open positions on the symbol with the magic number |
//+------------------------------------------------------------------+
bool CTradeBase::IsOpenedBySymbol(string symbol,int MagicNumber)
{
int pos=0;
uint total=PositionsTotal();
//---
for(uint i=0; i<total; i++)
{
if(SelectByIndex(i))
if(PositionGetString(POSITION_SYMBOL)==symbol && PositionGetInteger(POSITION_MAGIC)==MagicNumber)
pos++;
}
return((pos>0)?true:false);
}
//+------------------------------------------------------------------+
//| Checking spread |
//+------------------------------------------------------------------+
bool CTradeBase::MaxSpread(string symbol,int MaxLevelSpread)
{
if(MaxLevelSpread>0)
{
return ((SymbolInfoInteger(symbol,SYMBOL_SPREAD)>MaxLevelSpread)?true:false);
}
else
return (false);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CTradeBase::GetDig(string symbol)
{
long digits=SymbolInfoInteger(symbol,SYMBOL_DIGITS);
return((digits==5 || digits==3 || digits==1)?10:1);
}
//+------------------------------------------------------------------+
//| lot calculation to open a position with the margin lot_margin |
//+------------------------------------------------------------------+
double CTradeBase::GetLotForOpeningPos(string symbol,ENUM_POSITION_TYPE direction,double lot_margin)
{
//----
double price=0.0,n_margin;
double LotStep,MaxLot,MinLot;
if(direction==POSITION_TYPE_BUY)
if(!SymbolInfoDouble(symbol,SYMBOL_ASK,price))
return(0);
if(direction==POSITION_TYPE_SELL)
if(!SymbolInfoDouble(symbol,SYMBOL_BID,price))
return(0);
if(!price)
return(NULL);
if(!OrderCalcMargin(ENUM_ORDER_TYPE(direction),symbol,1,price,n_margin) || !n_margin)
return(0);
double lot=lot_margin/n_margin;
//---- getting trade constants
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP,LotStep))
return(0);
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX,MaxLot))
return(0);
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN,MinLot))
return(0);
//---- normalizing the lot size to the nearest standard value
lot=LotStep*MathFloor(lot/LotStep);
//---- checking the lot for the minimum allowable value
if(lot<MinLot)
lot=MinLot;
//---- checking the lot for the maximum allowable value
if(lot>MaxLot)
lot=MaxLot;
//----
return(lot);
}
//+------------------------------------------------------------------+
//| Returns the fill type |
//+------------------------------------------------------------------+
ENUM_ORDER_TYPE_FILLING CTradeBase::GetFilling(void)
{
uint filling=(uint)SymbolInfoInteger(_Symbol,SYMBOL_FILLING_MODE);
if(filling==1)
return(ORDER_FILLING_FOK);
else if(filling==2)
return(ORDER_FILLING_IOC);
return(false);
}
//+------------------------------------------------------------------+
//| Lot size calculation |
//+------------------------------------------------------------------+
double CTradeBase:: LotCount(string symbol,ENUM_POSITION_TYPE directon,double base_lot)
{
//----
double margin=0.0,Lot=0.0,MinLot=0.0;
switch(m_type_lot)
{
case 0:
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN,MinLot))
return(false);
Lot=MinLot;
break;
case 1:
Lot=base_lot;
break;
}
//--- LOT SIZE CALCULATION FOR OPENING A POSITION
if(base_lot<0)
m_base_lot=MathAbs(base_lot);
else
switch(m_mm_lot)
{
//---- Lot calculation considering account free funds
case 0:
margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE)*Lot;
m_base_lot=GetLotForOpeningPos(symbol,directon,margin);
break;
//---- Lot calculation considering account balance
case 1:
margin=AccountInfoDouble(ACCOUNT_BALANCE)*Lot;
m_base_lot=GetLotForOpeningPos(symbol,directon,margin);
break;
//---- Lot calculation should be unchanged
case 2:
{
m_base_lot=MathAbs(base_lot);
break;
}
//---- Lot calculation considering account free funds by default
default:
{
margin=AccountInfoDouble(ACCOUNT_MARGIN_FREE)*Lot;
m_base_lot=GetLotForOpeningPos(symbol,directon,margin);
}
}
//---- normalizing the lot size to the nearest standard value
if(!LotCorrect(symbol,directon)) return(-1);
//----
return(m_base_lot);
}
//+------------------------------------------------------------------+
//| Correction of a lot size to the nearest acceptable value |
//+------------------------------------------------------------------+
bool CTradeBase::LotCorrect(string symbol,ENUM_POSITION_TYPE trade_operation)
{
//---- getting calculation data
double Step,MaxLot,MinLot;
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP,Step)) return(false);
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX,MaxLot)) return(false);
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN,MinLot)) return(false);
//---- normalizing the lot size to the nearest standard value
m_base_lot=Step*MathFloor(m_base_lot/Step);
//---- checking the lot for the minimum allowable value
if(m_base_lot<MinLot)
m_base_lot=MinLot;
//---- checking the lot for the maximum allowable value
if(m_base_lot>MaxLot)
m_base_lot=MaxLot;
//---- checking the funds sufficiency
if(!LotFreeMarginCorrect(symbol,trade_operation))return(false);
//----
return(true);
}
//+------------------------------------------------------------------+
//| limitation of a lot size by a deposit capacity |
//+------------------------------------------------------------------+
bool CTradeBase::LotFreeMarginCorrect(string symbol,ENUM_POSITION_TYPE trade_operation)
{
//---- checking the funds sufficiency
double freemargin=AccountInfoDouble(ACCOUNT_MARGIN_FREE);
if(freemargin<=0) return(false);
//---- getting calculation data
double Step,MaxLot,MinLot;
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP,Step)) return(false);
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX,MaxLot)) return(false);
if(!SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN,MinLot)) return(false);
double ExtremLot=GetLotForOpeningPos(symbol,trade_operation,freemargin);
//---- normalizing the lot size to the nearest standard value
ExtremLot=Step*MathFloor(ExtremLot/Step);
if(ExtremLot<MinLot)
return(false); // funds are insufficient even for a minimum lot!
if(m_base_lot>ExtremLot)
m_base_lot=ExtremLot; // cutting the lot size down to the deposit capacity!
if(m_base_lot>MaxLot)
m_base_lot=MaxLot; // cutting the lot size down to the maximum permissible one
//----
return(true);
}
//+------------------------------------------------------------------+
//| Correction of a pending order size to an acceptable value |
//+------------------------------------------------------------------+
int CTradeBase::StopCorrect(string symbol,int Stop)
{
//----
long Extrem_Stop;
if(!SymbolInfoInteger(symbol,SYMBOL_TRADE_STOPS_LEVEL,Extrem_Stop)) return(false);
if(Stop<Extrem_Stop)
Stop=int(Extrem_Stop);
//----
return(Stop);
}
//+------------------------------------------------------------------+
//| Correction of a pending order size to an acceptable value |
//+------------------------------------------------------------------+
bool CTradeBase::dStopCorrect(string symbol,double &dStopLoss,double &dTakeprofit,ENUM_POSITION_TYPE trade_operation)
{
//----
if(!dStopLoss && !dTakeprofit)
return(true);
if(dStopLoss<0)
{
Print(__FUNCTION__,"(): A negative value stoploss!");
return(false);
}
if(dTakeprofit<0)
{
Print(__FUNCTION__,"(): A negative value takeprofit!");
return(false);
}
//----
int Stop=0;
long digit;
double point,dStop,ExtrStop,ExtrTake;
//---- getting the minimum distance to a pending order
Stop=StopCorrect(symbol,Stop);
//----
if(!SymbolInfoInteger(symbol,SYMBOL_DIGITS,digit))
return(false);
if(!SymbolInfoDouble(symbol,SYMBOL_POINT,point))
return(false);
dStop=Stop*point;
//---- correction of a pending order size for a long position
if(trade_operation==POSITION_TYPE_BUY)
{
double Ask;
if(!SymbolInfoDouble(symbol,SYMBOL_ASK,Ask))
return(false);
ExtrStop=NormalizeDouble(Ask-dStop,int(digit));
ExtrTake=NormalizeDouble(Ask+dStop,int(digit));
if(dStopLoss>ExtrStop && dStopLoss)
dStopLoss=ExtrStop;
if(dTakeprofit<ExtrTake && dTakeprofit)
dTakeprofit=ExtrTake;
}
//---- correction of a pending order size for a short position
if(trade_operation==POSITION_TYPE_SELL)
{
double Bid;
if(!SymbolInfoDouble(symbol,SYMBOL_BID,Bid))
return(false);
ExtrStop=NormalizeDouble(Bid+dStop,int(digit));
ExtrTake=NormalizeDouble(Bid-dStop,int(digit));
if(dStopLoss<ExtrStop && dStopLoss)
dStopLoss=ExtrStop;
if(dTakeprofit>ExtrTake && dTakeprofit)
dTakeprofit=ExtrTake;
}
//----
return(true);
}
//+------------------------------------------------------------------+
//| Returning a trade operation string result by its code |
//+------------------------------------------------------------------+
string CTradeBase::ResultRetcodeDescription(int retcode)
{
string str;
//----
if(m_lang=="en")
{
switch(retcode)
{
case TRADE_RETCODE_REQUOTE: str="Requote"; break;
case TRADE_RETCODE_REJECT: str="Request rejected"; break;
case TRADE_RETCODE_CANCEL: str="Request canceled by trader"; break;
case TRADE_RETCODE_PLACED: str="Order placed"; break;
case TRADE_RETCODE_DONE: str="Request completed"; break;
case TRADE_RETCODE_DONE_PARTIAL: str="Only part of the request was completed"; break;
case TRADE_RETCODE_ERROR: str="Request processing error"; break;
case TRADE_RETCODE_TIMEOUT: str="Request canceled by timeout";break;
case TRADE_RETCODE_INVALID: str="Invalid request"; break;
case TRADE_RETCODE_INVALID_VOLUME: str="Invalid volume in the request"; break;
case TRADE_RETCODE_INVALID_PRICE: str="Invalid price in the request"; break;
case TRADE_RETCODE_INVALID_STOPS: str="Invalid stops in the request"; break;
case TRADE_RETCODE_TRADE_DISABLED: str="Trade is disabled"; break;
case TRADE_RETCODE_MARKET_CLOSED: str="Market is closed"; break;
case TRADE_RETCODE_NO_MONEY: str="There is not enough money to complete the request"; break;
case TRADE_RETCODE_PRICE_CHANGED: str="Prices changed"; break;
case TRADE_RETCODE_PRICE_OFF: str="There are no quotes to process the request"; break;
case TRADE_RETCODE_INVALID_EXPIRATION: str="Invalid order expiration date in the request"; break;
case TRADE_RETCODE_ORDER_CHANGED: str="Order state changed"; break;
case TRADE_RETCODE_TOO_MANY_REQUESTS: str="Too frequent requests"; break;
case TRADE_RETCODE_NO_CHANGES: str="No changes in request"; break;
case TRADE_RETCODE_SERVER_DISABLES_AT: str="Autotrading disabled by server"; break;
case TRADE_RETCODE_CLIENT_DISABLES_AT: str="Autotrading disabled by client terminal"; break;
case TRADE_RETCODE_LOCKED: str="Request locked for processing"; break;
case TRADE_RETCODE_FROZEN: str="Order or position frozen"; break;
case TRADE_RETCODE_INVALID_FILL: str="Invalid order filling type"; break;
case TRADE_RETCODE_CONNECTION: str="No connection with the trade server"; break;
case TRADE_RETCODE_ONLY_REAL: str="Operation is allowed only for live accounts"; break;
case TRADE_RETCODE_LIMIT_ORDERS: str="The number of pending orders has reached the limit"; break;
case TRADE_RETCODE_LIMIT_VOLUME: str="The volume of orders and positions for the symbol has reached the limit"; break;
default: str="Unknown result";
}
}
else if(m_lang=="ru")
{
switch(retcode)
{
case TRADE_RETCODE_REQUOTE: str=" 5:2>B0"; break;
case TRADE_RETCODE_REJECT: str="0?@>A >B25@3=CB"; break;
case TRADE_RETCODE_CANCEL: str="0?@>A >B<5=5= B@5945@><"; break;
case TRADE_RETCODE_PLACED: str="@45@ @07<5I5="; break;
case TRADE_RETCODE_DONE: str="0O2:0 2K?>;=5=0"; break;
case TRADE_RETCODE_DONE_PARTIAL: str="0O2:0 2K?>;=5=0 G0AB8G=>"; break;
case TRADE_RETCODE_ERROR: str="H81:0 >1@01>B:8 70?@>A0"; break;
case TRADE_RETCODE_TIMEOUT: str="0?@>A >B<5=5= ?> 8AB5G5=8N 2@5<5=8";break;
case TRADE_RETCODE_INVALID: str="5?@028;L=K9 70?@>A"; break;
case TRADE_RETCODE_INVALID_VOLUME: str="5?@028;L=K9 >1J5< 2 70?@>A5"; break;
case TRADE_RETCODE_INVALID_PRICE: str="5?@028;L=0O F5=0 2 70?@>A5"; break;
case TRADE_RETCODE_INVALID_STOPS: str="5?@028;L=K5 AB>?K 2 70?@>A5"; break;
case TRADE_RETCODE_TRADE_DISABLED: str="">@3>2;O 70?@5I5=0"; break;
case TRADE_RETCODE_MARKET_CLOSED: str=" K=>: 70:@KB"; break;
case TRADE_RETCODE_NO_MONEY: str="5B 4>AB0B>G=KE 45=56=KE A@54AB2 4;O 2K?>;=5=8O 70?@>A0"; break;
case TRADE_RETCODE_PRICE_CHANGED: str="&5=K 87<5=8;8AL"; break;
case TRADE_RETCODE_PRICE_OFF: str="BACBAB2CNB :>B8@>2:8 4;O >1@01>B:8 70?@>A0"; break;
case TRADE_RETCODE_INVALID_EXPIRATION: str="525@=0O 40B0 8AB5G5=8O >@45@0 2 70?@>A5"; break;
case TRADE_RETCODE_ORDER_CHANGED: str="!>AB>O=85 >@45@0 87<5=8;>AL"; break;
case TRADE_RETCODE_TOO_MANY_REQUESTS: str="!;8H:>< G0ABK5 70?@>AK"; break;
case TRADE_RETCODE_NO_CHANGES: str=" 70?@>A5 =5B 87<5=5=89"; break;
case TRADE_RETCODE_SERVER_DISABLES_AT: str="2B>B@5948=3 70?@5I5= A5@25@><"; break;
case TRADE_RETCODE_CLIENT_DISABLES_AT: str="2B>B@5948=3 70?@5I5= :;85=BA:8< B5@<8=0;><"; break;
case TRADE_RETCODE_LOCKED: str="0?@>A 701;>:8@>20= 4;O >1@01>B:8"; break;
case TRADE_RETCODE_FROZEN: str="@45@ 8;8 ?>78F8O 70<>@>65=K"; break;
case TRADE_RETCODE_INVALID_FILL: str="#:070= =5?>445@68205<K9 B8? 8A?>;=5=8O >@45@0 ?> >AB0B:C "; break;
case TRADE_RETCODE_CONNECTION: str="5B A>548=5=8O A B>@3>2K< A5@25@><"; break;
case TRADE_RETCODE_ONLY_REAL: str="?5@0F8O @07@5H5=0 B>;L:> 4;O @50;L=KE AG5B>2"; break;
case TRADE_RETCODE_LIMIT_ORDERS: str=">AB83=CB ;8<8B =0 :>;8G5AB2> >B;>65==KE >@45@>2"; break;
case TRADE_RETCODE_LIMIT_VOLUME: str=">AB83=CB ;8<8B =0 >1J5< >@45@>2 8 ?>78F89 4;O 40==>3> A8<2>;0"; break;
default: str="58725AB=K9 @57C;LB0B";
}
}
//----
return(str);
}
//+------------------------------------------------------------------+
//| Select a position on the index |
//+------------------------------------------------------------------+
bool CTradeBase::SelectByIndex(const int index)
{
ENUM_ACCOUNT_MARGIN_MODE margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE);
//---
if(margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
ulong ticket=PositionGetTicket(index);
if(ticket==0)
return(false);
}
else
{
string name=PositionGetSymbol(index);
if(name=="")
return(false);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Position select depending on netting or hedging |
//+------------------------------------------------------------------+
bool CTradeBase::SelectPosition(const string symbol,int MagicNumber)
{
bool res=false;
//---
if(IsHedging())
{
uint total=PositionsTotal();
for(uint i=0; i<total; i++)
{
string position_symbol=PositionGetSymbol(i);
if(position_symbol==symbol && MagicNumber==PositionGetInteger(POSITION_MAGIC))
{
res=true;
break;
}
}
}
else
res=PositionSelect(symbol);
//---
return(res);
}
//+------------------------------------------------------------------+