Multicurrency Staircase

Author: Copyright © 2019, Vladimir Karputov
Price Data Components
Series array that contains tick volumes of each bar
Orders Execution
Checks for the total of open orders
Miscellaneous
It issuies visual alerts to the screen
0 Views
0 Downloads
0 Favorites
Multicurrency Staircase
ÿþ//+------------------------------------------------------------------+

//|                                      Multicurrency Staircase.mq5 |

//|                              Copyright © 2019, Vladimir Karputov |

//|                                           http://wmua.ru/slesar/ |

//+------------------------------------------------------------------+

#property copyright "Copyright © 2019, Vladimir Karputov"

#property link      "http://wmua.ru/slesar/"

#property version   "1.000"

//---

#include <Trade\PositionInfo.mqh>

#include <Trade\Trade.mqh>

#include <Trade\SymbolInfo.mqh>  

CPositionInfo  ClassPosition;                    // trade position object

CTrade         ClassTrade;                       // trading object

CSymbolInfo    ClassSymbol;                      // symbol info object



#include <Arrays\ArrayObj.mqh>

CArrayObj      m_array_obj;                  // CArrayObj object

//+------------------------------------------------------------------+

//| Enum Lor or Risk                                                 |

//+------------------------------------------------------------------+

enum ENUM_LOT_OR_RISK

  {

   lot=0,   // Constant lot

   risk=1,  // Risk in percent for a deal

  };

//--- input parameters

input string   InpSymbols="EURUSD,USDJPY,USDCAD";     // Symbols

input ushort   InpChannel              = 150;         // Channel, in pips (1.00045-1.00055=1 pips)

input uchar    InpAllowablSpread       = 15;          // Allowable spread, in points (1.00045-1.00055=10 points)

input double   InpMinimumProfit        = 300;         // Minimum Profit

input ENUM_LOT_OR_RISK IntLotOrRisk    = risk;        // Money management: Lot OR Risk

input double   InpVolumeLotOrRisk      = 1.0;         // The value for "Money management"

input bool     InpTimeControl          = true;        // Use time control

input uchar    InpStartHour            = 6;           // Start hour

input uchar    InpEndHour              = 18;          // End hour

input bool     InpPrintLog             = false;       // Print log

input ulong    InpMagic                = 37012290;    // Magic number

//---

bool  ExtNeedCloseAll;

//+------------------------------------------------------------------+

//| Expert initialization function                                   |

//+------------------------------------------------------------------+

int OnInit()

  {

   ExtNeedCloseAll=false;

//---

   string to_split=InpSymbols;   // a string to split into substrings 

   StringTrimLeft(to_split);

   StringTrimRight(to_split);



   string sep=",";               // a separator as a character 

   ushort u_sep;                 // the code of the separator character 

   string result[];              // an array to get strings 

//--- get the separator code 

   u_sep=StringGetCharacter(sep,0);

//--- split the string to substrings 

   int k=StringSplit(to_split,u_sep,result);



   for(int i=0;i<k;i++)

     {

      if(!ClassSymbol.Name(result[i])) // sets symbol name

         return(INIT_FAILED);



      CMultiGrid *multi=new CMultiGrid;

      if(multi==NULL)

        {

         Print("Object CMultiGrid create error");

         return(INIT_FAILED);

        }

      m_array_obj.Add(multi);

      int init=multi.OnInit(result[i],

                            InpChannel,         // Channel, in pips (1.00045-1.00055=1 pips)

                            InpAllowablSpread,  // Allowable spread, in points (1.00045-1.00055=10 points)

                            InpMinimumProfit,   // Minimum Profit

                            IntLotOrRisk,       // Money management: Lot OR Risk

                            InpVolumeLotOrRisk, // The value for "Money management"

                            InpTimeControl,     // Use time control

                            InpStartHour,       // Start hour

                            InpEndHour,         // End hour

                            InpPrintLog,        // Print log

                            InpMagic,           // Magic number

                            10                  // Slippage

                            );

      if(init!=INIT_SUCCEEDED)

         return(init);

     }

//---

   ClassTrade.SetExpertMagicNumber(0);

   ClassTrade.SetMarginMode();

   ClassTrade.SetTypeFillingBySymbol(Symbol());

   ClassTrade.SetDeviationInPoints(10);

//---

   return(INIT_SUCCEEDED);

  }

//+------------------------------------------------------------------+

//| Expert deinitialization function                                 |

//+------------------------------------------------------------------+

void OnDeinit(const int reason)

  {

//---

   for(int i=0;i<m_array_obj.Total();i++)

     {

      CMultiGrid *multi=m_array_obj.At(i);

      if(multi==NULL)

        {

         //--- Error reading from array 

         Print("Object CMultiGrid create error");

         return;

        }

      multi.OnDeinit(reason);

     }

  }

//+------------------------------------------------------------------+

//| Expert tick function                                             |

//+------------------------------------------------------------------+

void OnTick()

  {

   if(ExtNeedCloseAll)

     {

      int total=0;

      for(int i=PositionsTotal()-1;i>=0;i--)

         if(ClassPosition.SelectByIndex(i)) // selects the position by index for further access to its properties

            if(ClassPosition.Magic()==InpMagic)

               total++;

      if(total==0)

         ExtNeedCloseAll=false;



      for(int i=0;i<m_array_obj.Total();i++)

        {

         CMultiGrid *multi=m_array_obj.At(i);

         if(multi==NULL)

           {

            //--- Error reading from array 

            Print("Object CMultiGrid create error");

            return;

           }

         multi.Pause(false);

        }

     }



   double profit=0.0;

   for(int i=PositionsTotal()-1;i>=0;i--)

      if(ClassPosition.SelectByIndex(i)) // selects the position by index for further access to its properties

         if(ClassPosition.Magic()==InpMagic)

            profit+=ClassPosition.Commission()+ClassPosition.Swap()+ClassPosition.Profit();



   if(profit>=InpMinimumProfit)

     {

      ExtNeedCloseAll=true;

      for(int i=0;i<m_array_obj.Total();i++)

        {

         CMultiGrid *multi=m_array_obj.At(i);

         if(multi==NULL)

           {

            //--- Error reading from array 

            Print("Object CMultiGrid create error");

            return;

           }

         multi.Pause(true);

        }

      for(int i=PositionsTotal()-1;i>=0;i--)

         if(ClassPosition.SelectByIndex(i)) // selects the position by index for further access to its properties

            if(ClassPosition.Magic()==InpMagic)

               ClassTrade.PositionClose(ClassPosition.Ticket());

      return;

     }



   for(int i=0;i<m_array_obj.Total();i++)

     {

      CMultiGrid *multi=m_array_obj.At(i);

      if(multi==NULL)

        {

         //--- Error reading from array 

         Print("Object CMultiGrid create error");

         return;

        }

      multi.OnTick();

     }

//---

  }

//+------------------------------------------------------------------+

//| TradeTransaction function                                        |

//+------------------------------------------------------------------+

void OnTradeTransaction(const MqlTradeTransaction &trans,

                        const MqlTradeRequest &request,

                        const MqlTradeResult &result)

  {

//--- 

   for(int i=0;i<m_array_obj.Total();i++)

     {

      CMultiGrid *multi=m_array_obj.At(i);

      if(multi==NULL)

        {

         //--- Error reading from array 

         Print("Object CMultiiMATrend create error");

         return;

        }

      multi.OnTradeTransaction(trans,request,result);

     }

  }

//+------------------------------------------------------------------+

//|                                                    MultiGrid.mqh |

//|                              Copyright © 2019, Vladimir Karputov |

//|                                           http://wmua.ru/slesar/ |

//+------------------------------------------------------------------+

#property copyright "Copyright © 2019, Vladimir Karputov"

#property link      "http://wmua.ru/slesar/"

#property version   "1.000"

//---

#include <Trade\PositionInfo.mqh>

#include <Trade\Trade.mqh>

#include <Trade\SymbolInfo.mqh>  

#include <Trade\AccountInfo.mqh>

#include <Trade\DealInfo.mqh>

#include <Trade\OrderInfo.mqh>

#include <Expert\Money\MoneyFixedMargin.mqh>

//+------------------------------------------------------------------+

//| Class CMultiGrid.                                                |

//| Appointment: Class Expert Advisor.                               |

//|              Derives from class CObject.                         |

//+------------------------------------------------------------------+

class CMultiGrid : public CObject

  {

protected:

   CPositionInfo     m_position;                   // trade position object

   CTrade            m_trade;                      // trading object

   CSymbolInfo       m_symbol;                     // symbol info object

   CAccountInfo      m_account;                    // account info wrapper

   CDealInfo         m_deal;                       // deals object

   COrderInfo        m_order;                      // pending orders object

   CMoneyFixedMargin *m_money;

   //---

   double            ExtChannel;                   // Channel, in pips (1.00045-1.00055=1 pips)

   uchar             ExtAllowablSpread;            // Allowable spread, in points (1.00045-1.00055=10 points)

   ENUM_LOT_OR_RISK  ExtLotOrRisk;                 // Money management: Lot OR Risk

   double            ExtVolumeLotOrRisk;           // The value for "Money management"

   bool              ExtTimeControl;               // Use time control

   uchar             ExtStartHour;                 // Start hour

   uchar             ExtEndHour;                   // End hour

   bool              ExtPrintLog;                  // Print log

   ulong             ExtMagic;                     // Magic number

   ulong             ExtSlippage;                  // Slippage

   double            ExtAdjustedPoint;             // point value adjusted for 3 or 5 points

   bool              ExtNeedOpenBuyStop;

   bool              ExtNeedOpenSellStop;

   bool              ExtNeedDeleteAllStop;

   bool              ExtPause;

   datetime          PrevBars;

   //--- Refreshes the symbol quotes data

   bool              RefreshRates(void);

   //--- Check the correctness of the position volume

   bool              CheckVolumeValue(double volume,string &error_description);

   //--- Check Freeze and Stops levels 

   bool              FreezeStopsLevels(double &level);

   //--- Place Orders     

   void              PlaceOrders(const ENUM_ORDER_TYPE order_type,const double level);

   //--- Pending order   

   bool              PendingOrder(ENUM_ORDER_TYPE order_type,double price,double sl,double tp);

   //--- Print CTrade result     

   void              PrintResultTrade(CTrade &trade,CSymbolInfo &symbol);

   //--- Close all positions  

   void              CloseAllPositions();

   //--- Calculate all pending orders      

   void              CalculateAllPendingOrders(int &count_buy_stops,int &count_sell_stops);

   //--- Is pendinf orders exists    

   bool              IsPendingOrdersExists(void);

   //--- Delete all pending orders    

   void              DeleteAllPendingOrders(const double level);

   //--- Is position exists  

   bool              IsPositionExists(void);

   //--- Calculate all volumes

   void              CalculateAllVolumes(double &volumne_buys,double &volumne_sells,

                                         double &volumne_buy_limits,double &volumne_sell_limits,

                                         double &volumne_buy_stops,double &volumne_sell_stops);

   //--- TimeControl  

   bool              TimeControl(void);



private:



public:

                     CMultiGrid();

                    ~CMultiGrid();

   //--- expert initialization function

   int               OnInit(string           EASymbolName,     // Symbol name

                            ushort           Channel,          // Channel, in pips (1.00045-1.00055=1 pips)

                            uchar            AllowablSpread,   // Allowable spread, in points (1.00045-1.00055=10 points)

                            double           MinimumProfit,    // Minimum Profit

                            ENUM_LOT_OR_RISK LotOrRisk,        // Money management: Lot OR Risk

                            double           VolumeLotOrRisk,  // The value for "Money management"

                            bool             TimeControl,      // Use time control

                            uchar            StartHour,        // Start hour

                            uchar            EndHour,          // End hour

                            bool             PrintLog,         // Print log

                            ulong            Magic,            // Magic number

                            ulong            Slippage          // Slippage

                            );

   //--- expert deinitialization function

   void              OnDeinit(const int reason);

   //--- expert tick function

   void              OnTick();

   //--- expert TradeTransaction function

   void              OnTradeTransaction(const MqlTradeTransaction &trans,

                                        const MqlTradeRequest &request,

                                        const MqlTradeResult &result);

   //--- pause

   void              Pause(const bool volume)      { ExtPause=volume;         }

   bool              Pause(void)                   { return(ExtPause);        }



  };

//+------------------------------------------------------------------+

//| Constructor                                                      |

//+------------------------------------------------------------------+

double            ExtChannel;                   // Channel, in pips (1.00045-1.00055=1 pips)

uchar             ExtAllowablSpread;            // Allowable spread, in points (1.00045-1.00055=10 points)

ENUM_LOT_OR_RISK  ExtLotOrRisk;                 // Money management: Lot OR Risk

double            ExtVolumeLotOrRisk;           // The value for "Money management"

bool              ExtTimeControl;               // Use time control

uchar             ExtStartHour;                 // Start hour

uchar             ExtEndHour;                   // End hour

bool              ExtPrintLog;                  // Print log

ulong             ExtMagic;                     // Magic number

ulong             ExtSlippage;                  // Slippage

double            ExtAdjustedPoint;             // point value adjusted for 3 or 5 points

bool              ExtNeedOpenBuyStop;

bool              ExtNeedOpenSellStop;

bool              ExtPause;

//+------------------------------------------------------------------+

//|                                                                  |

//+------------------------------------------------------------------+

CMultiGrid::CMultiGrid(void) : ExtChannel(150),

                               ExtAllowablSpread(15),

                               ExtLotOrRisk(risk),

                               ExtVolumeLotOrRisk(1.0),

                               ExtTimeControl(true),

                               ExtStartHour(6),

                               ExtEndHour(18),

                               ExtPrintLog(false),

                               ExtMagic(0),

                               ExtSlippage(10),

                               ExtAdjustedPoint(0.0001),

                               ExtNeedOpenBuyStop(false),

                               ExtNeedOpenSellStop(false),

                               ExtNeedDeleteAllStop(false),

                               ExtPause(false),

                               PrevBars(0)

  {

  }

//+------------------------------------------------------------------+

//| Destructor                                                       |

//+------------------------------------------------------------------+

CMultiGrid::~CMultiGrid()

  {

  }

//+------------------------------------------------------------------+

//| Expert initialization function                                   |

//+------------------------------------------------------------------+

int CMultiGrid::OnInit(string             EASymbolName,     // Symbol name

                       ushort             Channel,          // Channel, in pips (1.00045-1.00055=1 pips)

                       uchar              AllowablSpread,   // Allowable spread, in points (1.00045-1.00055=10 points)

                       double             MinimumProfit,    // Minimum Profit

                       ENUM_LOT_OR_RISK   LotOrRisk,        // Money management: Lot OR Risk

                       double             VolumeLotOrRisk,  // The value for "Money management"

                       bool               TimeControl,      // Use time control

                       uchar              StartHour,        // Start hour

                       uchar              EndHour,          // End hour

                       bool               PrintLog,         // Print log

                       ulong              Magic,            // Magic number

                       ulong              Slippage          // Slippage

                       )

  {

//---

   if(!m_symbol.Name(EASymbolName)) // sets symbol name

      return(INIT_FAILED);

   RefreshRates();

//---

   m_trade.SetExpertMagicNumber(Magic);

   m_trade.SetMarginMode();

   m_trade.SetTypeFillingBySymbol(m_symbol.Name());

   m_trade.SetDeviationInPoints(Slippage);

//--- tuning for 3 or 5 digits

   int digits_adjust=1;

   if(m_symbol.Digits()==3 || m_symbol.Digits()==5)

      digits_adjust=10;

   ExtAdjustedPoint=m_symbol.Point()*digits_adjust;



   ExtChannel        = Channel  *ExtAdjustedPoint;

   ExtAllowablSpread = AllowablSpread;

   ExtLotOrRisk      = LotOrRisk;

   ExtVolumeLotOrRisk= VolumeLotOrRisk;

   ExtTimeControl    = TimeControl;

   ExtStartHour      = StartHour;

   ExtEndHour        = EndHour;

   ExtPrintLog       = PrintLog;

   ExtMagic          = Magic;

   ExtSlippage       = Slippage;

//--- check the input parameter "Lots"

   string err_text="";

   if(LotOrRisk==lot)

     {

      if(!CheckVolumeValue(ExtVolumeLotOrRisk,err_text))

        {

         //--- when testing, we will only output to the log about incorrect input parameters

         if(MQLInfoInteger(MQL_TESTER))

           {

            Print(__FUNCTION__,", ERROR: ",err_text);

            return(INIT_FAILED);

           }

         else // if the Expert Advisor is run on the chart, tell the user about the error

           {

            Alert(__FUNCTION__,", ERROR: ",err_text);

            return(INIT_PARAMETERS_INCORRECT);

           }

        }

     }

   else

     {

      if(m_money!=NULL)

         delete m_money;

      m_money=new CMoneyFixedMargin;

      if(m_money!=NULL)

        {

         if(!m_money.Init(GetPointer(m_symbol),Period(),m_symbol.Point()*digits_adjust))

            return(INIT_FAILED);

         m_money.Percent(ExtVolumeLotOrRisk);

        }

      else

        {

         Print(__FUNCTION__,", ERROR: Object CMoneyFixedMargin is NULL");

         return(INIT_FAILED);

        }

     }

//---

   return(INIT_SUCCEEDED);

  }

//+------------------------------------------------------------------+

//| Expert deinitialization function                                 |

//+------------------------------------------------------------------+

void CMultiGrid::OnDeinit(const int reason)

  {

//---

   if(m_money!=NULL)

      delete m_money;

  }

//+------------------------------------------------------------------+

//| Expert tick function                                             |

//+------------------------------------------------------------------+

void CMultiGrid::OnTick()

  {

   if(Pause())

      return;

//--- need delete all stop orders

   if(ExtNeedDeleteAllStop)

     {

      if(IsPendingOrdersExists())

        {

         double level;

         if(FreezeStopsLevels(level))

            DeleteAllPendingOrders(level);

         return;

        }

      else

         ExtNeedDeleteAllStop=false;

     }

//--- need open Buy stop

   if(ExtNeedOpenBuyStop)

     {

      int count_buy_stops=0,count_sell_stops=0;

      CalculateAllPendingOrders(count_buy_stops,count_sell_stops);

      if(count_buy_stops==0)

        {

         double level;

         if(FreezeStopsLevels(level))

            PlaceOrders(ORDER_TYPE_BUY_STOP,level);

         return;

        }

      else

         ExtNeedOpenBuyStop=false;

     }

//--- ned open Sell stop

   if(ExtNeedOpenSellStop)

     {

      int count_buy_stops=0,count_sell_stops=0;

      CalculateAllPendingOrders(count_buy_stops,count_sell_stops);

      if(count_sell_stops==0)

        {

         double level;

         if(FreezeStopsLevels(level))

            PlaceOrders(ORDER_TYPE_SELL_STOP,level);

         return;

        }

      else

         ExtNeedOpenSellStop=false;

     }

//--- we work only at the time of the birth of new bar

   datetime time_0=iTime(m_symbol.Name(),Period(),0);

   if(time_0==PrevBars)

      return;

   PrevBars=time_0;

   if(!RefreshRates())

     {

      PrevBars=0;

      return;

     }

//---

   int count_buy_stops=0,count_sell_stops=0;

   CalculateAllPendingOrders(count_buy_stops,count_sell_stops);



   if(count_buy_stops+count_sell_stops==1 || count_buy_stops+count_sell_stops>2)

     {

      ExtNeedDeleteAllStop=true;

      PrevBars=0;

      return;

     }



   if(count_buy_stops==0)

      ExtNeedOpenBuyStop=true;

   if(count_sell_stops==0)

      ExtNeedOpenSellStop=true;



//---

  }

//+------------------------------------------------------------------+

//| TradeTransaction function                                        |

//+------------------------------------------------------------------+

void CMultiGrid::OnTradeTransaction(const MqlTradeTransaction &trans,

                                    const MqlTradeRequest &request,

                                    const MqlTradeResult &result)

  {

//--- get transaction type as enumeration value 

   ENUM_TRADE_TRANSACTION_TYPE type=trans.type;

//--- if transaction is result of addition of the transaction in history

   if(type==TRADE_TRANSACTION_DEAL_ADD)

     {

      long     deal_ticket       =0;

      long     deal_order        =0;

      long     deal_time         =0;

      long     deal_time_msc     =0;

      long     deal_type         =-1;

      long     deal_entry        =-1;

      long     deal_magic        =0;

      long     deal_reason       =-1;

      long     deal_position_id  =0;

      double   deal_volume       =0.0;

      double   deal_price        =0.0;

      double   deal_commission   =0.0;

      double   deal_swap         =0.0;

      double   deal_profit       =0.0;

      string   deal_symbol       ="";

      string   deal_comment      ="";

      string   deal_external_id  ="";

      if(HistoryDealSelect(trans.deal))

        {

         deal_ticket       =HistoryDealGetInteger(trans.deal,DEAL_TICKET);

         deal_order        =HistoryDealGetInteger(trans.deal,DEAL_ORDER);

         deal_time         =HistoryDealGetInteger(trans.deal,DEAL_TIME);

         deal_time_msc     =HistoryDealGetInteger(trans.deal,DEAL_TIME_MSC);

         deal_type         =HistoryDealGetInteger(trans.deal,DEAL_TYPE);

         deal_entry        =HistoryDealGetInteger(trans.deal,DEAL_ENTRY);

         deal_magic        =HistoryDealGetInteger(trans.deal,DEAL_MAGIC);

         deal_reason       =HistoryDealGetInteger(trans.deal,DEAL_REASON);

         deal_position_id  =HistoryDealGetInteger(trans.deal,DEAL_POSITION_ID);



         deal_volume       =HistoryDealGetDouble(trans.deal,DEAL_VOLUME);

         deal_price        =HistoryDealGetDouble(trans.deal,DEAL_PRICE);

         deal_commission   =HistoryDealGetDouble(trans.deal,DEAL_COMMISSION);

         deal_swap         =HistoryDealGetDouble(trans.deal,DEAL_SWAP);

         deal_profit       =HistoryDealGetDouble(trans.deal,DEAL_PROFIT);



         deal_symbol       =HistoryDealGetString(trans.deal,DEAL_SYMBOL);

         deal_comment      =HistoryDealGetString(trans.deal,DEAL_COMMENT);

         deal_external_id  =HistoryDealGetString(trans.deal,DEAL_EXTERNAL_ID);

        }

      else

         return;

      if(deal_symbol==m_symbol.Name() && deal_magic==ExtMagic)

         if(deal_entry==DEAL_ENTRY_IN)

            if(deal_type==DEAL_TYPE_BUY || deal_type==DEAL_TYPE_SELL)

              {

               ExtNeedDeleteAllStop=true;

              }

     }

  }

//+------------------------------------------------------------------+

//| Refreshes the symbol quotes data                                 |

//+------------------------------------------------------------------+

bool CMultiGrid::RefreshRates(void)

  {

//--- refresh rates

   if(!m_symbol.RefreshRates())

     {

      Print("RefreshRates error");

      return(false);

     }

//--- protection against the return value of "zero"

   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)

      return(false);

//---

   return(true);

  }

//+------------------------------------------------------------------+

//| Check the correctness of the position volume                     |

//+------------------------------------------------------------------+

bool CMultiGrid::CheckVolumeValue(double volume,string &error_description)

  {

//--- minimal allowed volume for trade operations

   double min_volume=m_symbol.LotsMin();

   if(volume<min_volume)

     {

      if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian")

         error_description=StringFormat("1J5< <5=LH5 <8=8<0;L=> 4>?CAB8<>3> SYMBOL_VOLUME_MIN=%.2f",min_volume);

      else

         error_description=StringFormat("Volume is less than the minimal allowed SYMBOL_VOLUME_MIN=%.2f",min_volume);

      return(false);

     }

//--- maximal allowed volume of trade operations

   double max_volume=m_symbol.LotsMax();

   if(volume>max_volume)

     {

      if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian")

         error_description=StringFormat("1J5< 1>;LH5 <0:A8<0;L=> 4>?CAB8<>3> SYMBOL_VOLUME_MAX=%.2f",max_volume);

      else

         error_description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume);

      return(false);

     }

//--- get minimal step of volume changing

   double volume_step=m_symbol.LotsStep();

   int ratio=(int)MathRound(volume/volume_step);

   if(MathAbs(ratio*volume_step-volume)>0.0000001)

     {

      if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian")

         error_description=StringFormat("1J5< =5 :@0B5= <8=8<0;L=><C H03C SYMBOL_VOLUME_STEP=%.2f, 1;8609H89 ?@028;L=K9 >1J5< %.2f",

                                        volume_step,ratio*volume_step);

      else

         error_description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f",

                                        volume_step,ratio*volume_step);

      return(false);

     }

   error_description="Correct volume value";

   return(true);

  }

//+------------------------------------------------------------------+

//| Check Freeze and Stops levels                                    |

//+------------------------------------------------------------------+

bool CMultiGrid::FreezeStopsLevels(double &level)

  {

//--- check Freeze and Stops levels

/*

   Type of order/position  |  Activation price  |  Check

   ------------------------|--------------------|--------------------------------------------

   Buy Limit order         |  Ask               |  Ask-OpenPrice  >= SYMBOL_TRADE_FREEZE_LEVEL

   Buy Stop order          |  Ask	            |  OpenPrice-Ask  >= SYMBOL_TRADE_FREEZE_LEVEL

   Sell Limit order        |  Bid	            |  OpenPrice-Bid  >= SYMBOL_TRADE_FREEZE_LEVEL

   Sell Stop order	      |  Bid	            |  Bid-OpenPrice  >= SYMBOL_TRADE_FREEZE_LEVEL

   Buy position            |  Bid	            |  TakeProfit-Bid >= SYMBOL_TRADE_FREEZE_LEVEL 

                           |                    |  Bid-StopLoss   >= SYMBOL_TRADE_FREEZE_LEVEL

   Sell position           |  Ask	            |  Ask-TakeProfit >= SYMBOL_TRADE_FREEZE_LEVEL

                           |                    |  StopLoss-Ask   >= SYMBOL_TRADE_FREEZE_LEVEL

                           

   Buying is done at the Ask price                 |  Selling is done at the Bid price

   ------------------------------------------------|----------------------------------

   TakeProfit        >= Bid                        |  TakeProfit        <= Ask

   StopLoss          <= Bid	                     |  StopLoss          >= Ask

   TakeProfit - Bid  >= SYMBOL_TRADE_STOPS_LEVEL   |  Ask - TakeProfit  >= SYMBOL_TRADE_STOPS_LEVEL

   Bid - StopLoss    >= SYMBOL_TRADE_STOPS_LEVEL   |  StopLoss - Ask    >= SYMBOL_TRADE_STOPS_LEVEL

*/

   if(!RefreshRates() || !m_symbol.Refresh())

      return(false);

//--- FreezeLevel -> for pending order and modification

   double freeze_level=m_symbol.FreezeLevel()*m_symbol.Point();

   if(freeze_level==0.0)

      freeze_level=(m_symbol.Ask()-m_symbol.Bid())*3.0;

   freeze_level*=1.1;

//--- StopsLevel -> for TakeProfit and StopLoss

   double stop_level=m_symbol.StopsLevel()*m_symbol.Point();

   if(stop_level==0.0)

      stop_level=(m_symbol.Ask()-m_symbol.Bid())*3.0;

   stop_level*=1.1;



   if(freeze_level<=0.0 || stop_level<=0.0)

      return(false);



   level=(freeze_level>stop_level)?freeze_level:stop_level;

//---

   return(true);

  }

//+------------------------------------------------------------------+

//| Place Orders                                                     |

//+------------------------------------------------------------------+

void CMultiGrid::PlaceOrders(const ENUM_ORDER_TYPE order_type,const double level)

  {

   if(m_symbol.Ask()-m_symbol.Bid()>ExtAllowablSpread*m_symbol.Point())

      return;

//--- check Freeze and Stops levels

/*

   Type of order/position  |  Activation price  |  Check

   ------------------------|--------------------|--------------------------------------------

   Buy Limit order         |  Ask               |  Ask-OpenPrice  >= SYMBOL_TRADE_FREEZE_LEVEL

   Buy Stop order          |  Ask	            |  OpenPrice-Ask  >= SYMBOL_TRADE_FREEZE_LEVEL

   Sell Limit order        |  Bid	            |  OpenPrice-Bid  >= SYMBOL_TRADE_FREEZE_LEVEL

   Sell Stop order	      |  Bid	            |  Bid-OpenPrice  >= SYMBOL_TRADE_FREEZE_LEVEL

   Buy position            |  Bid	            |  TakeProfit-Bid >= SYMBOL_TRADE_FREEZE_LEVEL 

                           |                    |  Bid-StopLoss   >= SYMBOL_TRADE_FREEZE_LEVEL

   Sell position           |  Ask	            |  Ask-TakeProfit >= SYMBOL_TRADE_FREEZE_LEVEL

                           |                    |  StopLoss-Ask   >= SYMBOL_TRADE_FREEZE_LEVEL

                           

   Buying is done at the Ask price                 |  Selling is done at the Bid price

   ------------------------------------------------|----------------------------------

   TakeProfit        >= Bid                        |  TakeProfit        <= Ask

   StopLoss          <= Bid	                     |  StopLoss          >= Ask

   TakeProfit - Bid  >= SYMBOL_TRADE_STOPS_LEVEL   |  Ask - TakeProfit  >= SYMBOL_TRADE_STOPS_LEVEL

   Bid - StopLoss    >= SYMBOL_TRADE_STOPS_LEVEL   |  StopLoss - Ask    >= SYMBOL_TRADE_STOPS_LEVEL

*/

//--- buy stop

   if(order_type==ORDER_TYPE_BUY_STOP)

     {

      double price=m_symbol.Ask()+ExtChannel/2.0;

      if(price-m_symbol.Ask()<level) // check price

         price=m_symbol.Ask()+level;



      double sl=price-(ExtChannel-MathRound((m_symbol.Ask()-m_symbol.Bid())/m_symbol.Point()));

      if(sl!=0.0 && (price-sl)/m_symbol.Point()<level)// check sl

         sl=price-level;



      PendingOrder(ORDER_TYPE_BUY_STOP,price,sl,0.0);

     }

//--- sell stop

   if(order_type==ORDER_TYPE_SELL_STOP)

     {

      double price=m_symbol.Bid()-ExtChannel/2.0;

      if(m_symbol.Bid()-price<level) // check price

         price=m_symbol.Bid()-level;



      double sl=price+(ExtChannel+MathRound((m_symbol.Ask()-m_symbol.Bid())/m_symbol.Point()));

      if(sl!=0.0 && (sl-price)/m_symbol.Point()<level)// check sl

         sl=price-level;



      PendingOrder(ORDER_TYPE_SELL_STOP,price,sl,0.0);

     }

//---

  }

//+------------------------------------------------------------------+

//| Pending order                                                    |

//+------------------------------------------------------------------+

bool CMultiGrid::PendingOrder(ENUM_ORDER_TYPE order_type,double price,double sl,double tp)

  {

   sl=m_symbol.NormalizePrice(sl);

   tp=m_symbol.NormalizePrice(tp);

//--- check volume before OrderSend to avoid "not enough money" error (CTrade)

   ENUM_ORDER_TYPE check_order_type=-1;

   switch(order_type)

     {

      case  ORDER_TYPE_BUY:

         check_order_type=ORDER_TYPE_BUY;

         break;

      case ORDER_TYPE_SELL:

         check_order_type=ORDER_TYPE_SELL;

         break;

      case ORDER_TYPE_BUY_LIMIT:

         check_order_type=ORDER_TYPE_BUY;

         break;

      case ORDER_TYPE_SELL_LIMIT:

         check_order_type=ORDER_TYPE_SELL;

         break;

      case ORDER_TYPE_BUY_STOP:

         check_order_type=ORDER_TYPE_BUY;

         break;

      case ORDER_TYPE_SELL_STOP:

         check_order_type=ORDER_TYPE_SELL;

         break;

      default:

         return(false);

         break;

     }

//---

   double long_lot=0.0;

   double short_lot=0.0;

   if(ExtLotOrRisk==risk)

     {

      bool error=false;

      long_lot=m_money.CheckOpenLong(m_symbol.Ask(),sl);

      if(ExtPrintLog)

         Print("sl=",DoubleToString(sl,m_symbol.Digits()),

               ", CheckOpenLong: ",DoubleToString(long_lot,2),

               ", Balance: ",    DoubleToString(m_account.Balance(),2),

               ", Equity: ",     DoubleToString(m_account.Equity(),2),

               ", FreeMargin: ", DoubleToString(m_account.FreeMargin(),2));

      if(long_lot==0.0)

        {

         if(ExtPrintLog)

            Print(__FUNCTION__,", ERROR: method CheckOpenLong returned the value of \"0.0\"");

         error=true;

        }

      //---

      short_lot=m_money.CheckOpenShort(m_symbol.Bid(),sl);

      if(ExtPrintLog)

         Print("sl=",DoubleToString(sl,m_symbol.Digits()),

               ", CheckOpenLong: ",DoubleToString(short_lot,2),

               ", Balance: ",    DoubleToString(m_account.Balance(),2),

               ", Equity: ",     DoubleToString(m_account.Equity(),2),

               ", FreeMargin: ", DoubleToString(m_account.FreeMargin(),2));

      if(short_lot==0.0)

        {

         if(ExtPrintLog)

            Print(__FUNCTION__,", ERROR: method CheckOpenShort returned the value of \"0.0\"");

         error=true;

        }

      //---

      if(error)

         return(false);

     }

   else if(ExtLotOrRisk==lot)

     {

      long_lot=ExtVolumeLotOrRisk;

      short_lot=ExtVolumeLotOrRisk;

     }

   else

      return(false);

//--- check volume before OrderSend to avoid "not enough money" error (CTrade)

   double check_price=0;

   double check_lot=0;

   if(check_order_type==ORDER_TYPE_BUY)

     {

      check_price=m_symbol.Ask();

      check_lot=long_lot;

     }

   else

     {

      check_price=m_symbol.Bid();

      check_lot=short_lot;

     }

//---

   if(m_symbol.LotsLimit()>0.0)

     {

      double volume_buys        = 0.0;   double volume_sells       = 0.0;

      double volume_buy_limits  = 0.0;   double volume_sell_limits = 0.0;

      double volume_buy_stops   = 0.0;   double volume_sell_stops  = 0.0;

      CalculateAllVolumes(volume_buys,volume_sells,

                          volume_buy_limits,volume_sell_limits,

                          volume_buy_stops,volume_sell_stops);

      if(volume_buys+volume_sells+

         volume_buy_limits+volume_sell_limits+

         volume_buy_stops+volume_sell_stops+check_lot>m_symbol.LotsLimit())

        {

         if(ExtPrintLog)

            Print("#0 ,",EnumToString(order_type),", ",

                  "Volume Buy's (",DoubleToString(volume_buys,2),")",

                  "Volume Sell's (",DoubleToString(volume_sells,2),")",

                  "Volume Buy limit's (",DoubleToString(volume_buy_limits,2),")",

                  "Volume Sell limit's (",DoubleToString(volume_sell_limits,2),")",

                  "Volume Buy stops's (",DoubleToString(volume_buy_stops,2),")",

                  "Volume Sell stops's (",DoubleToString(volume_sell_stops,2),")",

                  "Check lot (",DoubleToString(check_lot,2),")",

                  " > Lots Limit (",DoubleToString(m_symbol.LotsLimit(),2),")");

         return(false);

        }

     }

//---

   double free_margin_check=m_account.FreeMarginCheck(m_symbol.Name(),check_order_type,check_lot,check_price);

   if(free_margin_check>0.0)

     {

      if(m_trade.OrderOpen(m_symbol.Name(),order_type,check_lot,0.0,

         m_symbol.NormalizePrice(price),m_symbol.NormalizePrice(sl),m_symbol.NormalizePrice(tp),ORDER_TIME_DAY))

        {

         if(m_trade.ResultOrder()==0)

           {

            if(ExtPrintLog)

               Print("#1 ",EnumToString(order_type)," -> false. Result Retcode: ",m_trade.ResultRetcode(),

                     ", description of result: ",m_trade.ResultRetcodeDescription());

            if(ExtPrintLog)

               PrintResultTrade(m_trade,m_symbol);

            return(false);

           }

         else

           {

            if(ExtPrintLog)

               Print("#2 ",EnumToString(order_type)," -> true. Result Retcode: ",m_trade.ResultRetcode(),

                     ", description of result: ",m_trade.ResultRetcodeDescription());

            if(ExtPrintLog)

               PrintResultTrade(m_trade,m_symbol);

            return(true);

           }

        }

      else

        {

         if(ExtPrintLog)

            Print("#3 ",EnumToString(order_type)," -> false. Result Retcode: ",m_trade.ResultRetcode(),

                  ", description of result: ",m_trade.ResultRetcodeDescription());

         if(ExtPrintLog)

            PrintResultTrade(m_trade,m_symbol);

         return(false);

        }

     }

   else

     {

      if(ExtPrintLog)

         Print(__FUNCTION__,", ERROR: method CAccountInfo::FreeMarginCheck returned the value ",DoubleToString(free_margin_check,2));

      return(false);

     }

//---

   return(false);

  }

//+------------------------------------------------------------------+

//| Print CTrade result                                              |

//+------------------------------------------------------------------+

void CMultiGrid::PrintResultTrade(CTrade &trade,CSymbolInfo &symbol)

  {

   Print("File: ",__FILE__,", symbol: ",symbol.Name());

   Print("Code of request result: "+IntegerToString(trade.ResultRetcode()));

   Print("code of request result as a string: "+trade.ResultRetcodeDescription());

   Print("Deal ticket: "+IntegerToString(trade.ResultDeal()));

   Print("Order ticket: "+IntegerToString(trade.ResultOrder()));

   Print("Volume of deal or order: "+DoubleToString(trade.ResultVolume(),2));

   Print("Price, confirmed by broker: "+DoubleToString(trade.ResultPrice(),symbol.Digits()));

   Print("Current bid price: "+DoubleToString(symbol.Bid(),symbol.Digits())+" (the requote): "+DoubleToString(trade.ResultBid(),symbol.Digits()));

   Print("Current ask price: "+DoubleToString(symbol.Ask(),symbol.Digits())+" (the requote): "+DoubleToString(trade.ResultAsk(),symbol.Digits()));

   Print("Broker comment: "+trade.ResultComment());

   int d=0;

  }

//+------------------------------------------------------------------+

//| Close all positions                                              |

//+------------------------------------------------------------------+

void CMultiGrid::CloseAllPositions()

  {

   for(int i=PositionsTotal()-1;i>=0;i--) // returns the number of current positions

      if(m_position.SelectByIndex(i))     // selects the position by index for further access to its properties

         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==ExtMagic)

            m_trade.PositionClose(m_position.Ticket()); // close a position by the specified symbol

  }

//+------------------------------------------------------------------+

//| Calculate all pending orders                                     |

//+------------------------------------------------------------------+

void CMultiGrid::CalculateAllPendingOrders(int &count_buy_stops,int &count_sell_stops)

  {

   count_buy_stops   = 0;

   count_sell_stops  = 0;



   for(int i=OrdersTotal()-1;i>=0;i--) // returns the number of current orders

      if(m_order.SelectByIndex(i))     // selects the pending order by index for further access to its properties

         if(m_order.Symbol()==m_symbol.Name() && m_order.Magic()==ExtMagic)

           {

            if(m_order.OrderType()==ORDER_TYPE_BUY_STOP)

               count_buy_stops++;

            else if(m_order.OrderType()==ORDER_TYPE_SELL_STOP)

               count_sell_stops++;

           }

  }

//+------------------------------------------------------------------+

//| Is pendinf orders exists                                         |

//+------------------------------------------------------------------+

bool CMultiGrid::IsPendingOrdersExists(void)

  {

   for(int i=OrdersTotal()-1;i>=0;i--) // returns the number of current orders

      if(m_order.SelectByIndex(i))     // selects the pending order by index for further access to its properties

         if(m_order.Symbol()==m_symbol.Name() && m_order.Magic()==ExtMagic)

            return(true);

//---

   return(false);

  }

//+------------------------------------------------------------------+

//| Delete all pending orders                                        |

//+------------------------------------------------------------------+

void CMultiGrid::DeleteAllPendingOrders(const double level)

  {

   for(int i=OrdersTotal()-1;i>=0;i--) // returns the number of current orders

      if(m_order.SelectByIndex(i))     // selects the pending order by index for further access to its properties

         if(m_order.Symbol()==m_symbol.Name() && m_order.Magic()==ExtMagic)

           {

            if(m_order.OrderType()==ORDER_TYPE_BUY_LIMIT)

              {

               if(m_symbol.Ask()-m_order.PriceOpen()>=level)

                  m_trade.OrderDelete(m_order.Ticket());

               continue;

              }

            if(m_order.OrderType()==ORDER_TYPE_BUY_STOP)

              {

               if(m_order.PriceOpen()-m_symbol.Ask()>=level)

                  m_trade.OrderDelete(m_order.Ticket());

               continue;

              }

            if(m_order.OrderType()==ORDER_TYPE_SELL_LIMIT)

              {

               if(m_order.PriceOpen()-m_symbol.Bid()>=level)

                  m_trade.OrderDelete(m_order.Ticket());

               continue;

              }

            if(m_order.OrderType()==ORDER_TYPE_SELL_STOP)

              {

               if(m_symbol.Bid()-m_order.PriceOpen()>=level)

                  m_trade.OrderDelete(m_order.Ticket());

               continue;

              }

           }

  }

//+------------------------------------------------------------------+

//| Is position exists                                               |

//+------------------------------------------------------------------+

bool CMultiGrid::IsPositionExists(void)

  {

   for(int i=PositionsTotal()-1;i>=0;i--)

      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties

         if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==ExtMagic)

            return(true);

//---

   return(false);

  }

//+------------------------------------------------------------------+

//| Calculate all volumes                                            |

//+------------------------------------------------------------------+

void CMultiGrid::CalculateAllVolumes(double &volumne_buys,double &volumne_sells,

                                     double &volumne_buy_limits,double &volumne_sell_limits,

                                     double &volumne_buy_stops,double &volumne_sell_stops)

  {

   volumne_buys         = 0.0;   volumne_sells        = 0.0;

   volumne_buy_limits   = 0.0;   volumne_sell_limits  = 0.0;

   volumne_buy_stops    = 0.0;   volumne_sell_stops   = 0.0;



   for(int i=PositionsTotal()-1;i>=0;i--)

      if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties

         if(m_position.Symbol()==m_symbol.Name())

           {

            if(m_position.PositionType()==POSITION_TYPE_BUY)

               volumne_buys+=m_position.Volume();

            else if(m_position.PositionType()==POSITION_TYPE_SELL)

               volumne_sells+=m_position.Volume();

           }



   for(int i=OrdersTotal()-1;i>=0;i--) // returns the number of current orders

      if(m_order.SelectByIndex(i)) // selects the pending order by index for further access to its properties

         if(m_order.Symbol()==m_symbol.Name())

           {

            if(m_order.OrderType()==ORDER_TYPE_BUY_LIMIT)

               volumne_buy_limits+=m_order.VolumeInitial();

            else if(m_order.OrderType()==ORDER_TYPE_SELL_LIMIT)

               volumne_sell_limits+=m_order.VolumeInitial();

            else if(m_order.OrderType()==ORDER_TYPE_BUY_STOP)

               volumne_buy_stops+=m_order.VolumeInitial();

            else if(m_order.OrderType()==ORDER_TYPE_SELL_STOP)

               volumne_sell_stops+=m_order.VolumeInitial();

           }

  }

//+------------------------------------------------------------------+

//| TimeControl                                                      |

//+------------------------------------------------------------------+

bool CMultiGrid::TimeControl(void)

  {

   if(!InpTimeControl)

      return(true);

   MqlDateTime STimeCurrent;

   datetime time_current=TimeCurrent();

   if(time_current==D'1970.01.01 00:00')

      return(false);

   TimeToStruct(time_current,STimeCurrent);

   if(InpStartHour<InpEndHour) // intraday time interval

     {

/*

Example:

input uchar    InpStartHour      = 5;        // Start hour

input uchar    InpEndHour        = 10;       // End hour

0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15

_  _  _  _  _  +  +  +  +  +  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  _  +  +  +  +  +  _  _  _  _  _  _

*/

      if(STimeCurrent.hour>=InpStartHour && STimeCurrent.hour<InpEndHour)

         return(true);

     }

   else if(InpStartHour>InpEndHour) // time interval with the transition in a day

     {

/*

Example:

input uchar    InpStartHour      = 10;       // Start hour

input uchar    InpEndHour        = 5;        // End hour

0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15 16 17 18 19 20 21 22 23 0  1  2  3  4  5  6  7  8  9  10 11 12 13 14 15

_  _  _  _  _  _  _  _  _  _  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  +  _  _  _  _  _  +  +  +  +  +  +

*/

      if(STimeCurrent.hour>=InpStartHour || STimeCurrent.hour<InpEndHour)

         return(true);

     }

   else

      return(false);

//---

   return(false);

  }

//+------------------------------------------------------------------+

Comments