iRVI Street

Author: Copyright © 2021, Vladimir Karputov
Price Data Components
Series array that contains tick volumes of each bar Series array that contains open time of each bar
Miscellaneous
It issuies visual alerts to the screen
0 Views
0 Downloads
0 Favorites
iRVI Street
ÿþ//+------------------------------------------------------------------+

//|                                                  iRVI Street.mq5 |

//|                              Copyright © 2021, Vladimir Karputov |

//|                     https://www.mql5.com/ru/market/product/43516 |

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

#property copyright "Copyright © 2021, Vladimir Karputov"

#property link      "https://www.mql5.com/ru/market/product/43516"

#property version   "1.009"

#property description "---"

/*

   barabashkakvn Trading engine 3.154

*/

#include <Trade\PositionInfo.mqh>

#include <Trade\Trade.mqh>

#include <Trade\SymbolInfo.mqh>

#include <Trade\AccountInfo.mqh>

#include <Trade\DealInfo.mqh>

#include <Expert\Money\MoneyFixedMargin.mqh>

//---

CPositionInfo  m_position;                   // object of CPositionInfo class

CTrade         m_trade;                      // object of CTrade class

CSymbolInfo    m_symbol;                     // object of CSymbolInfo class

CAccountInfo   m_account;                    // object of CAccountInfo class

CDealInfo      m_deal;                       // object of CDealInfo class

CMoneyFixedMargin *m_money;                  // object of CMoneyFixedMargin class

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

//| Enum Trade Mode                                                  |

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

enum ENUM_TRADE_MODE

  {

   buy=0,      // Allowed only BUY positions

   sell=1,     // Allowed only SELL positions

   buy_sell=2, // Allowed BUY and SELL positions

  };

//--- input parameters

input group             "Trading settings"

input ENUM_TIMEFRAMES      InpWorkingPeriod              = PERIOD_CURRENT; // Working timeframe

input uint                 InpMinStep                    = 150;            // Minimum step between positions, in Points (1.00045-1.00055=10 points)

input double               InpMinProfit                  = 3;              // Minumum profit, in Money

input uint                 InpMaxSpread                  = 12;             // Maximum spread ('0' -> OFF)

input group             "Position size management (lot calculation)"

input double               InpLots                       = 0.01;           // Start Lots

input group             "Trade mode"

input ENUM_TRADE_MODE      InpTradeMode                  = buy_sell;       // Trade mode:

input group             "Martingale"

input double               InpMartinCoeff                = 3.0;            // Martingale coefficient

input group             "RVI"

input int                  Inp_RVI_ma_period             = 14;             // RVI: averaging period

input group             "RVI Arrow Intersection 2"

input uchar                InpCode                       = 174;            // Arrow code for style DRAW_ARROW (font Wingdings)

input int                  InpShift                      = 10;             // Vertical shift of arrows in pixels

input bool                 InpStrictControl              = true;           // Strict control

input group             "RVI Custom Levels"

input double               Inp_RVI_Level1                = 0.2;            // Value Level #1

input double               Inp_RVI_Level2                = -0.2;           // Value Level #2

input group             "Additional features"

input bool                 InpOnlyOne                    = false;          // Positions: Only one ('true' -> Martingale OFF)

input bool                 InpPrintLog                   = true;           // Print log

input uchar                InpFreezeCoefficient          = 1;              // Coefficient (if Freeze==0 Or StopsLevels==0)

input ulong                InpDeviation                  = 10;             // Deviation, in Points (1.00045-1.00055=10 points)

input ulong                InpMagic                      = 633294774;      // Magic number

//---

double   m_min_step                 = 0.0;      // Minimum step between positions, in Points -> double

double   m_max_spread               = 0.0;      // Maximum spread



int      handle_iRVI_Main;                      // variable for storing the handle of the iRVI indicator

int      handle_iRVI_SubWindow;                 // variable for storing the handle of the iRVI indicator



datetime m_prev_bars                = 0;        // "0" -> D'1970.01.01 00:00';

int      m_bar_current              = 0;

bool     m_need_close_buy           = false;    // close all buy positions

bool     m_need_close_sell          = false;    // close all sell positions

bool     m_init_error               = false;    // error on InInit

//--- the tactic is this: for positions we strictly monitor the result ***

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

//| Structure Positions                                              |

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

struct STRUCT_POSITION

  {

   ENUM_POSITION_TYPE pos_type;              // position type

   double            volume;                 // position volume (if "0.0" -> the lot is "Money management")

   double            lot_coefficient;        // lot coefficient

   bool              waiting_transaction;    // waiting transaction, "true" -> it's forbidden to trade, we expect a transaction

   ulong             waiting_order_ticket;   // waiting order ticket, ticket of the expected order

   bool              transaction_confirmed;  // transaction confirmed, "true" -> transaction confirmed

   //--- Constructor

                     STRUCT_POSITION()

     {

      pos_type                   = WRONG_VALUE;

      volume                     = 0.0;

      lot_coefficient            = 0.0;

      waiting_transaction        = false;

      waiting_order_ticket       = 0;

      transaction_confirmed      = false;

     }

  };

STRUCT_POSITION SPosition[];

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

//| Expert initialization function                                   |

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

int OnInit()

  {

   string main="RVI Arrow Intersection 2"+"("+IntegerToString(Inp_RVI_ma_period)+")";

   string sub_window="RVI Custom Levels("+IntegerToString(Inp_RVI_ma_period)+")";

   int windows_total=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL);

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

     {

      for(int j=ChartIndicatorsTotal(0,i)-1; j>=0; j--)

        {

         string name=ChartIndicatorName(0,i,j);

         if(name==main || name==sub_window)

            ChartIndicatorDelete(0,i,name);

        }

     }

//--- forced initialization of variables

   m_min_step                 = 0.0;      // Minimum step between positions, in Points -> double

   m_max_spread               = 0.0;      // Maximum spread

   m_prev_bars                = 0;        // "0" -> D'1970.01.01 00:00';

   m_bar_current              = 0;

   m_need_close_buy           = false;    // close all buy positions

   m_need_close_sell          = false;    // close all sell positions

   m_init_error               = false;    // error on InInit

//---

   ResetLastError();

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

     {

      Print(__FILE__," ",__FUNCTION__,", ERROR: CSymbolInfo.Name");

      return(INIT_FAILED);

     }

   RefreshRates();

//---

   m_trade.SetExpertMagicNumber(InpMagic);

   m_trade.SetMarginMode();

   m_trade.SetTypeFillingBySymbol(m_symbol.Name());

   m_trade.SetDeviationInPoints(InpDeviation);

//---

   m_min_step                 = InpMinStep                  * m_symbol.Point();

   m_max_spread               = InpMaxSpread                * m_symbol.Point();

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

   string err_text="";

   if(!CheckVolumeValue(InpLots,err_text))

     {

      if(MQLInfoInteger(MQL_TESTER)) // when testing, we will only output to the log about incorrect input parameters

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

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

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

      //---

      m_init_error=true;

      return(INIT_SUCCEEDED);

     }

   /*

   //--- input parameters

      input group             "RVI"

      input int      Inp_RVI_ma_period = 5;     // RVI: averaging period

      input group             "Arrow"

      input uchar    InpCode           = 174;   // Arrow code for style DRAW_ARROW (font Wingdings)

      input int      InpShift          = 10;    // Vertical shift of arrows in pixels

      input group             "Additional features"

      input bool     InpStrictControl  = true;  // Strict control

   */

//--- create handle of the indicator iCustom

   handle_iRVI_Main=iCustom(m_symbol.Name(),InpWorkingPeriod,"RVI Arrow Intersection 2",

                            "RVI",

                            Inp_RVI_ma_period,

                            "Arrow",

                            InpCode,

                            InpShift,

                            "Additional features",

                            InpStrictControl);

//--- if the handle is not created

   if(handle_iRVI_Main==INVALID_HANDLE)

     {

      //--- tell about the failure and output the error code

      PrintFormat("Failed to create handle of the iCustom ('RVI Arrow Intersection 2') indicator for the symbol %s/%s, error code %d",

                  m_symbol.Name(),

                  EnumToString(InpWorkingPeriod),

                  GetLastError());

      //--- the indicator is stopped early

      //---

      m_init_error=true;

      return(INIT_SUCCEEDED);

     }

   ChartIndicatorAdd(ChartID(),0,handle_iRVI_Main);

   /*

   //--- input parameters

      input group             "RVI"

      input int      Inp_RVI_ma_period    = 12;       // RVI: averaging period

      input group             "Levels"

      input double   Inp_RVI_Level1       = 0.2;      // Value Level #1

      input double   Inp_RVI_Level2       = -0.2;     // Value Level #2

   */

//--- create handle of the indicator iCustom

   handle_iRVI_SubWindow=iCustom(m_symbol.Name(),InpWorkingPeriod,"RVI Custom Levels",

                                 "RVI",

                                 Inp_RVI_ma_period,

                                 "Levels",

                                 Inp_RVI_Level1,

                                 Inp_RVI_Level2);

//--- if the handle is not created

   if(handle_iRVI_SubWindow==INVALID_HANDLE)

     {

      //--- tell about the failure and output the error code

      PrintFormat("Failed to create handle of the iCustom ('RVI Custom Levels') indicator for the symbol %s/%s, error code %d",

                  m_symbol.Name(),

                  EnumToString(InpWorkingPeriod),

                  GetLastError());

      //--- the indicator is stopped early

      //---

      m_init_error=true;

      return(INIT_SUCCEEDED);

     }

   windows_total=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL);

   ChartIndicatorAdd(0,windows_total,handle_iRVI_SubWindow);

//---

   m_bar_current=1;

//---

   return(INIT_SUCCEEDED);

  }

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

//| Expert deinitialization function                                 |

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

void OnDeinit(const int reason)

  {

   string main="RVI Arrow Intersection 2"+"("+IntegerToString(Inp_RVI_ma_period)+")";

   string sub_window="RVI Custom Levels("+IntegerToString(Inp_RVI_ma_period)+")";

   int windows_total=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL);

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

     {

      for(int j=ChartIndicatorsTotal(0,i)-1; j>=0; j--)

        {

         string name=ChartIndicatorName(0,i,j);

         if(name==main || name==sub_window)

            ChartIndicatorDelete(0,i,name);

        }

     }

//---

   if(m_money!=NULL)

      delete m_money;

  }

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

//| Expert tick function                                             |

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

void OnTick()

  {

   if(m_init_error)

      return;

//---

   if(m_need_close_buy || m_need_close_sell)

     {

      int      count_buys           = 0;

      double   volume_buys          = 0.0;

      double   volume_biggest_buys  = 0.0;

      int      count_sells          = 0;

      double   volume_sells         = 0.0;

      double   volume_biggest_sells = 0.0;

      CalculateAllPositions(count_buys,volume_buys,volume_biggest_buys,

                            count_sells,volume_sells,volume_biggest_sells,

                            false);

      //--- close all buy positions

      if(m_need_close_buy)

        {

         if(count_buys>0)

           {

            ClosePositions(POSITION_TYPE_BUY);

            return;

           }

         else

           {

            m_need_close_buy=false;

           }

        }

      //--- close all sell positions

      if(m_need_close_sell)

        {

         if(count_sells>0)

           {

            ClosePositions(POSITION_TYPE_SELL);

            return;

           }

         else

           {

            m_need_close_sell=false;

           }

        }

     }

//---

   int size_need_position=ArraySize(SPosition);

   if(size_need_position>0)

     {

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

        {

         if(SPosition[i].waiting_transaction)

           {

            if(!SPosition[i].transaction_confirmed)

              {

               if(InpPrintLog)

                  Print(__FILE__," ",__FUNCTION__,", OK: ","transaction_confirmed: ",SPosition[i].transaction_confirmed);

               return;

              }

            else

               if(SPosition[i].transaction_confirmed)

                 {

                  ArrayRemove(SPosition,i,1);

                  return;

                 }

           }

         //---

         int      count_buys           = 0;

         double   volume_buys          = 0.0;

         double   volume_biggest_buys  = 0.0;

         int      count_sells          = 0;

         double   volume_sells         = 0.0;

         double   volume_biggest_sells = 0.0;

         CalculateAllPositions(count_buys,volume_buys,volume_biggest_buys,

                               count_sells,volume_sells,volume_biggest_sells,

                               false);

         //---

         if(SPosition[i].pos_type==POSITION_TYPE_BUY)

           {

            if(count_sells>0)

              {

               ClosePositions(POSITION_TYPE_SELL);

               return;

              }

            SPosition[i].waiting_transaction=true;

            OpenPosition(i);

            return;

           }

         if(SPosition[i].pos_type==POSITION_TYPE_SELL)

           {

            if(count_buys>0)

              {

               ClosePositions(POSITION_TYPE_BUY);

               return;

              }

            SPosition[i].waiting_transaction=true;

            OpenPosition(i);

            return;

           }

        }

     }

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

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

   if(time_0==m_prev_bars)

      return;

   m_prev_bars=time_0;

//--- search for trading signals

   if(!RefreshRates())

      return;

   if(!SearchTradingSignals())

      return;

//---

  }

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

//| TradeTransaction function                                        |

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

void 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)

     {

      ResetLastError();

      if(HistoryDealSelect(trans.deal))

         m_deal.Ticket(trans.deal);

      else

        {

         Print(__FILE__," ",__FUNCTION__,", ERROR: ","HistoryDealSelect(",trans.deal,") error: ",GetLastError());

         return;

        }

      if(m_deal.Symbol()==m_symbol.Name() && m_deal.Magic()==InpMagic)

        {

         if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL)

           {

            if(m_deal.Entry()==DEAL_ENTRY_IN || m_deal.Entry()==DEAL_ENTRY_INOUT)

              {

              }

            int size_need_position=ArraySize(SPosition);

            if(size_need_position>0)

              {

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

                 {

                  if(SPosition[i].waiting_transaction)

                     if(SPosition[i].waiting_order_ticket==m_deal.Order())

                       {

                        Print(__FUNCTION__," Transaction confirmed");

                        SPosition[i].transaction_confirmed=true;

                        break;

                       }

                 }

              }

           }

        }

     }

  }

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

//| Refreshes the symbol quotes data                                 |

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

bool RefreshRates()

  {

//--- refresh rates

   if(!m_symbol.RefreshRates())

     {

      Print(__FILE__," ",__FUNCTION__,", ERROR: ","RefreshRates error");

      return(false);

     }

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

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

     {

      Print(__FILE__," ",__FUNCTION__,", ERROR: ","Ask == 0.0 OR Bid == 0.0");

      return(false);

     }

//---

   return(true);

  }

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

//| Check the correctness of the position volume                     |

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

bool 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);

  }

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

//| Lot Check                                                        |

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

double LotCheck(double lots,CSymbolInfo &symbol)

  {

//--- calculate maximum volume

   double volume=NormalizeDouble(lots,2);

   double stepvol=symbol.LotsStep();

   if(stepvol>0.0)

      volume=stepvol*MathFloor(volume/stepvol);

//---

   double minvol=symbol.LotsMin();

   if(volume<minvol)

      volume=0.0;

//---

   double maxvol=symbol.LotsMax();

   if(volume>maxvol)

      volume=maxvol;

//---

   return(volume);

  }

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

//| Check Freeze and Stops levels                                    |

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

void FreezeStopsLevels(double &freeze,double &stops)

  {

//--- check Freeze and Stops levels

   /*

   SYMBOL_TRADE_FREEZE_LEVEL shows the distance of freezing the trade operations

      for pending orders and open positions in points

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

   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

   ------------------------------------------------------------------------------------------



   SYMBOL_TRADE_STOPS_LEVEL determines the number of points for minimum indentation of the

      StopLoss and TakeProfit levels from the current closing price of the open position

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

   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

   ------------------------------------------------------------------------------------------

   */

   double coeff=(double)InpFreezeCoefficient;

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

      return;

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

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

   if(freeze_level==0.0)

      if(InpFreezeCoefficient>0)

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

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

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

   if(stop_level==0.0)

      if(InpFreezeCoefficient>0)

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

//---

   freeze=freeze_level;

   stops=stop_level;

//---

   return;

  }

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

//| Open position                                                    |

//|   double stop_loss                                               |

//|      -> pips * m_adjusted_point (if "0.0" -> the m_stop_loss)    |

//|   double take_profit                                             |

//|      -> pips * m_adjusted_point (if "0.0" -> the m_take_profit)  |

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

void OpenPosition(const int index)

  {

   double freeze=0.0,stops=0.0;

   FreezeStopsLevels(freeze,stops);

   double max_levels=(freeze>stops)?freeze:stops;

   /*

   SYMBOL_TRADE_STOPS_LEVEL determines the number of points for minimum indentation of the

      StopLoss and TakeProfit levels from the current closing price of the open position

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

   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

   if(SPosition[index].pos_type==POSITION_TYPE_BUY)

     {

      OpenBuy(index);

      return;

     }

//--- sell

   if(SPosition[index].pos_type==POSITION_TYPE_SELL)

     {

      OpenSell(index);

      return;

     }

  }

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

//| Open Buy position                                                |

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

void OpenBuy(const int index)

  {

   double sl=0.0;

   double tp=0.0;

   double long_lot=InpLots;

   if(SPosition[index].volume>0.0)

      long_lot=SPosition[index].volume;

//---

   if(SPosition[index].lot_coefficient>0.0)

     {

      long_lot=LotCheck(long_lot*SPosition[index].lot_coefficient,

                        m_symbol);

      if(long_lot==0)

        {

         ArrayRemove(SPosition,index,1);

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", ERROR: ","LotCheck returned the 0.0");

         return;

        }

     }

   if(m_symbol.LotsLimit()>0.0)

     {

      int      count_buys           = 0;

      double   volume_buys          = 0.0;

      double   volume_biggest_buys  = 0.0;

      int      count_sells          = 0;

      double   volume_sells         = 0.0;

      double   volume_biggest_sells = 0.0;

      CalculateAllPositions(count_buys,volume_buys,volume_biggest_buys,

                            count_sells,volume_sells,volume_biggest_sells,

                            true);

      if(volume_buys+volume_sells+long_lot>m_symbol.LotsLimit())

        {

         ArrayRemove(SPosition,index,1);

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", ERROR: ","#0 Buy, Volume Buy (",DoubleToString(volume_buys,2),

                  ") + Volume Sell (",DoubleToString(volume_sells,2),

                  ") + Volume long (",DoubleToString(long_lot,2),

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

         return;

        }

     }

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

   double free_margin_check=m_account.FreeMarginCheck(m_symbol.Name(),

                            ORDER_TYPE_BUY,

                            long_lot,

                            m_symbol.Ask());

   double margin_check=m_account.MarginCheck(m_symbol.Name(),

                       ORDER_TYPE_BUY,

                       long_lot,

                       m_symbol.Ask());

   if(free_margin_check>margin_check)

     {

      if(m_trade.Buy(long_lot,m_symbol.Name(),

                     m_symbol.Ask(),sl,tp)) // CTrade::Buy -> "true"

        {

         if(m_trade.ResultDeal()==0)

           {

            if(m_trade.ResultRetcode()==10009) // trade order went to the exchange

              {

               SPosition[index].waiting_transaction=true;

               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();

              }

            else

              {

               SPosition[index].waiting_transaction=false;

               if(InpPrintLog)

                  Print(__FILE__," ",__FUNCTION__,", ERROR: ","#1 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),

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

              }

            if(InpPrintLog)

               PrintResultTrade(m_trade,m_symbol);

           }

         else

           {

            if(m_trade.ResultRetcode()==10009)

              {

               SPosition[index].waiting_transaction=true;

               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();

              }

            else

              {

               SPosition[index].waiting_transaction=false;

               if(InpPrintLog)

                  Print(__FILE__," ",__FUNCTION__,", OK: ","#2 Buy -> true. Result Retcode: ",m_trade.ResultRetcode(),

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

              }

            if(InpPrintLog)

               PrintResultTrade(m_trade,m_symbol);

           }

        }

      else

        {

         SPosition[index].waiting_transaction=false;

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", ERROR: ","#3 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(),

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

         if(InpPrintLog)

            PrintResultTrade(m_trade,m_symbol);

        }

     }

   else

     {

      ArrayRemove(SPosition,index,1);

      if(InpPrintLog)

         Print(__FILE__," ",__FUNCTION__,", ERROR: ","Free Margin Check (",DoubleToString(free_margin_check,2),") <= Margin Check (",DoubleToString(margin_check,2),")");

      return;

     }

//---

  }

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

//| Open Sell position                                               |

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

void OpenSell(const int index)

  {

   double sl=0.0;

   double tp=0.0;

   double short_lot=InpLots;

   if(SPosition[index].volume>0.0)

      short_lot=SPosition[index].volume;

//---

   if(SPosition[index].lot_coefficient>0.0)

     {

      short_lot=LotCheck(short_lot*SPosition[index].lot_coefficient,m_symbol);

      if(short_lot==0)

        {

         ArrayRemove(SPosition,index,1);

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", ERROR: ","LotCheck returned the 0.0");

         return;

        }

     }

   if(m_symbol.LotsLimit()>0.0)

     {

      int      count_buys           = 0;

      double   volume_buys          = 0.0;

      double   volume_biggest_buys  = 0.0;

      int      count_sells          = 0;

      double   volume_sells         = 0.0;

      double   volume_biggest_sells = 0.0;

      CalculateAllPositions(count_buys,volume_buys,volume_biggest_buys,

                            count_sells,volume_sells,volume_biggest_sells,

                            true);

      if(volume_buys+volume_sells+short_lot>m_symbol.LotsLimit())

        {

         ArrayRemove(SPosition,index,1);

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", ERROR: ","#0 Buy, Volume Buy (",DoubleToString(volume_buys,2),

                  ") + Volume Sell (",DoubleToString(volume_sells,2),

                  ") + Volume short (",DoubleToString(short_lot,2),

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

         return;

        }

     }

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

   double free_margin_check=m_account.FreeMarginCheck(m_symbol.Name(),

                            ORDER_TYPE_SELL,

                            short_lot,

                            m_symbol.Bid());

   double margin_check=m_account.MarginCheck(m_symbol.Name(),

                       ORDER_TYPE_SELL,

                       short_lot,

                       m_symbol.Bid());

   if(free_margin_check>margin_check)

     {

      if(m_trade.Sell(short_lot,m_symbol.Name(),

                      m_symbol.Bid(),sl,tp)) // CTrade::Sell -> "true"

        {

         if(m_trade.ResultDeal()==0)

           {

            if(m_trade.ResultRetcode()==10009) // trade order went to the exchange

              {

               SPosition[index].waiting_transaction=true;

               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();

              }

            else

              {

               SPosition[index].waiting_transaction=false;

               if(InpPrintLog)

                  Print(__FILE__," ",__FUNCTION__,", ERROR: ","#1 Sell -> false. Result Retcode: ",m_trade.ResultRetcode(),

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

              }

            if(InpPrintLog)

               PrintResultTrade(m_trade,m_symbol);

           }

         else

           {

            if(m_trade.ResultRetcode()==10009)

              {

               SPosition[index].waiting_transaction=true;

               SPosition[index].waiting_order_ticket=m_trade.ResultOrder();

              }

            else

              {

               SPosition[index].waiting_transaction=false;

               if(InpPrintLog)

                  Print(__FILE__," ",__FUNCTION__,", OK: ","#2 Sell -> true. Result Retcode: ",m_trade.ResultRetcode(),

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

              }

            if(InpPrintLog)

               PrintResultTrade(m_trade,m_symbol);

           }

        }

      else

        {

         SPosition[index].waiting_transaction=false;

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", ERROR: ","#3 Sell -> false. Result Retcode: ",m_trade.ResultRetcode(),

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

         if(InpPrintLog)

            PrintResultTrade(m_trade,m_symbol);

        }

     }

   else

     {

      ArrayRemove(SPosition,index,1);

      if(InpPrintLog)

         Print(__FILE__," ",__FUNCTION__,", ERROR: ","Free Margin Check (",DoubleToString(free_margin_check,2),") <= Margin Check (",DoubleToString(margin_check,2),")");

      return;

     }

//---

  }

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

//| Print CTrade result                                              |

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

void PrintResultTrade(CTrade &trade,CSymbolInfo &symbol)

  {

   Print(__FILE__," ",__FUNCTION__,", Symbol: ",symbol.Name()+", "+

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

         "Code of request result as a string: "+trade.ResultRetcodeDescription(),

         "Trade execution mode: "+symbol.TradeExecutionDescription());

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

         "Order ticket: "+IntegerToString(trade.ResultOrder())+", "+

         "Order retcode external: "+IntegerToString(trade.ResultRetcodeExternal())+", "+

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

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

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

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

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

  }

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

//| Get value of buffers                                             |

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

bool iGetArray(const int handle,const int buffer,const int start_pos,

               const int count,double &arr_buffer[])

  {

   bool result=true;

   if(!ArrayIsDynamic(arr_buffer))

     {

      if(InpPrintLog)

         PrintFormat("ERROR! EA: %s, FUNCTION: %s, this a no dynamic array!",__FILE__,__FUNCTION__);

      return(false);

     }

   ArrayFree(arr_buffer);

//--- reset error code

   ResetLastError();

//--- fill a part of the iBands array with values from the indicator buffer

   int copied=CopyBuffer(handle,buffer,start_pos,count,arr_buffer);

   if(copied!=count)

     {

      //--- if the copying fails, tell the error code

      if(InpPrintLog)

         PrintFormat("ERROR! EA: %s, FUNCTION: %s, amount to copy: %d, copied: %d, error code %d",

                     __FILE__,__FUNCTION__,count,copied,GetLastError());

      //--- quit with zero result - it means that the indicator is considered as not calculated

      return(false);

     }

   return(result);

  }

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

//| Close positions                                                  |

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

void ClosePositions(const ENUM_POSITION_TYPE pos_type)

  {

   double freeze=0.0,stops=0.0;

   FreezeStopsLevels(freeze,stops);

   /*

   SYMBOL_TRADE_FREEZE_LEVEL shows the distance of freezing the trade operations

      for pending orders and open positions in points

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

   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

   ------------------------------------------------------------------------------------------

   */

   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()==InpMagic)

            if(m_position.PositionType()==pos_type)

              {

               if(m_position.PositionType()==POSITION_TYPE_BUY)

                 {

                  bool take_profit_level=((m_position.TakeProfit()!=0.0 && m_position.TakeProfit()-m_position.PriceCurrent()>=freeze) || m_position.TakeProfit()==0.0);

                  bool stop_loss_level=((m_position.StopLoss()!=0.0 && m_position.PriceCurrent()-m_position.StopLoss()>=freeze) || m_position.StopLoss()==0.0);

                  if(take_profit_level && stop_loss_level)

                     if(!m_trade.PositionClose(m_position.Ticket())) // close a position by the specified m_symbol

                        if(InpPrintLog)

                           Print(__FILE__," ",__FUNCTION__,", ERROR: ","BUY PositionClose ",m_position.Ticket(),", ",m_trade.ResultRetcodeDescription());

                 }

               if(m_position.PositionType()==POSITION_TYPE_SELL)

                 {

                  bool take_profit_level=((m_position.TakeProfit()!=0.0 && m_position.PriceCurrent()-m_position.TakeProfit()>=freeze) || m_position.TakeProfit()==0.0);

                  bool stop_loss_level=((m_position.StopLoss()!=0.0 && m_position.StopLoss()-m_position.PriceCurrent()>=freeze) || m_position.StopLoss()==0.0);

                  if(take_profit_level && stop_loss_level)

                     if(!m_trade.PositionClose(m_position.Ticket())) // close a position by the specified m_symbol

                        if(InpPrintLog)

                           Print(__FILE__," ",__FUNCTION__,", ERROR: ","SELL PositionClose ",m_position.Ticket(),", ",m_trade.ResultRetcodeDescription());

                 }

              }

  }

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

//| Calculate all positions                                          |

//|  'lots_limit=true' - only for 'if(m_symbol.LotsLimit()>0.0)'     |

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

void CalculateAllPositions(int &count_buys,double &volume_buys,double &volume_biggest_buys,

                           int &count_sells,double &volume_sells,double &volume_biggest_sells,

                           bool lots_limit=false)

  {

   count_buys  = 0;

   volume_buys   = 0.0;

   volume_biggest_buys  = 0.0;

   count_sells = 0;

   volume_sells  = 0.0;

   volume_biggest_sells = 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() && (lots_limit || (!lots_limit && m_position.Magic()==InpMagic)))

           {

            if(m_position.PositionType()==POSITION_TYPE_BUY)

              {

               count_buys++;

               volume_buys+=m_position.Volume();

               if(m_position.Volume()>volume_biggest_buys)

                  volume_biggest_buys=m_position.Volume();

               continue;

              }

            else

               if(m_position.PositionType()==POSITION_TYPE_SELL)

                 {

                  count_sells++;

                  volume_sells+=m_position.Volume();

                  if(m_position.Volume()>volume_biggest_sells)

                     volume_biggest_sells=m_position.Volume();

                 }

           }

  }

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

//| Calculate all positions                                          |

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

void CalculateAllPositions_1(double &price_lowest_buy,double &volume_lowest_buy,double &volume_last_buy,double &profit_buys,

                             double &price_highest_sell,double &volume_highest_sell,double &volume_last_sell,double &profit_sells)

  {

//--- auxiliary variables

   price_lowest_buy     = DBL_MAX;

   volume_lowest_buy    = 0.0;

   volume_last_buy      = 0.0;

   profit_buys          = 0.0;

   price_highest_sell   = DBL_MIN;

   volume_highest_sell  = 0.0;

   volume_last_sell     = 0.0;

   profit_sells         = 0.0;

//---

   datetime time_last_buy  = 0; // "0" -> D'1970.01.01 00:00';

   datetime time_last_sell = 0; // "0" -> D'1970.01.01 00:00';

//---

   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()==InpMagic)

           {

            if(m_position.PositionType()==POSITION_TYPE_BUY)

              {

               if(m_position.PriceOpen()<price_lowest_buy) // the lowest position of "BUY" is found

                 {

                  price_lowest_buy=m_position.PriceOpen();

                  volume_lowest_buy=m_position.Volume();

                 }

               profit_buys=profit_buys+m_position.Commission()+m_position.Swap()+m_position.Profit();

               if(m_position.Time()>time_last_buy)

                 {

                  volume_last_buy=m_position.Volume();

                  time_last_buy=m_position.Time();

                 }

              }

            else

              {

               if(m_position.PositionType()==POSITION_TYPE_SELL)

                 {

                  if(m_position.PriceOpen()>price_highest_sell) // the highest position of "SELL" is found

                    {

                     price_highest_sell=m_position.PriceOpen();

                     volume_highest_sell=m_position.Volume();

                    }

                  profit_sells=profit_buys+m_position.Commission()+m_position.Swap()+m_position.Profit();

                  if(m_position.Time()>time_last_sell)

                    {

                     volume_last_sell=m_position.Volume();

                     time_last_sell=m_position.Time();

                    }

                 }

              }

           }

  }

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

//| Search trading signals                                           |

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

bool SearchTradingSignals(void)

  {

   double rvi_buffer[],rvi_color[];

   ArraySetAsSeries(rvi_buffer,true);

   ArraySetAsSeries(rvi_color,true);

   int start_pos=0,count=3;

   if(!iGetArray(handle_iRVI_Main,0,start_pos,count,rvi_buffer) || !iGetArray(handle_iRVI_Main,1,start_pos,count,rvi_color))

      return(false);

   int size_need_position=ArraySize(SPosition);

   if(size_need_position>0)

      return(true);

//--- BUY Signal

   if(rvi_buffer[m_bar_current]!=0.0 && rvi_color[m_bar_current]==0.0)

     {

      double spread=m_symbol.Ask()-m_symbol.Bid();

      if(m_max_spread>0.0 && spread>m_max_spread)

        {

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY ... but spread (",IntegerToString(int(spread/m_symbol.Point())),") > 'Maximum spread'");

         return(true);

        }

      //---

      double price_lowest_buy    = DBL_MAX;

      double volume_lowest_buy   = 0.0;

      double volume_last_buy     = 0.0;

      double profit_buys         = 0.0;

      double price_highest_sell  = DBL_MIN;

      double volume_highest_sell = 0.0;

      double volume_last_sell    = 0.0;

      double profit_sells        = 0.0;

      CalculateAllPositions_1(price_lowest_buy,volume_lowest_buy,volume_last_buy,profit_buys,

                              price_highest_sell,volume_highest_sell,volume_last_sell,profit_sells);

      //--- if there is a BUY position and you can have only one position

      if(InpOnlyOne && price_lowest_buy!=DBL_MAX)

        {

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY ... but 'Positions: Only one' is 'true'");

         return(true);

        }

      //--- if SELL profit is less than zero

      if(profit_sells<InpMinProfit && price_highest_sell!=DBL_MIN)

        {

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY ... but profit sells (",DoubleToString(profit_sells,3),") < 'Minumum profit'");

         return(true);

        }

      //---

      if((price_lowest_buy==DBL_MAX) || (price_lowest_buy!=DBL_MAX && price_lowest_buy-m_symbol.Ask()>m_min_step))

        {

         if(InpTradeMode!=sell) // 'Allowed only BUY positions' || 'Allowed BUY and SELL positions'

           {

            ArrayResize(SPosition,size_need_position+1);

            SPosition[size_need_position].pos_type=POSITION_TYPE_BUY;

            if(volume_last_buy>0.0)

              {

               SPosition[size_need_position].volume=volume_last_buy;

               SPosition[size_need_position].lot_coefficient=InpMartinCoeff;

               if(InpPrintLog)

                  Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY ... Martin");

               return(true);

              }

            if(InpPrintLog)

               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY");

            return(true);

           }

         else // 'Allowed only SELL positions'

           {

            if(InpPrintLog)

               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY ... but 'Allowed only SELL positions' -> close all sell positions");

            m_need_close_sell=true;

            return(true);

           }

        }

      else

        {

         if(price_lowest_buy!=DBL_MAX && price_lowest_buy-m_symbol.Ask()<=m_min_step)

           {

            if(InpPrintLog)

               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY ... but price_lowest_buy-Ask <= m_min_step (",DoubleToString(m_min_step,m_symbol.Digits()),")");

           }

         return(true);

        }

     }

//--- SELL Signal

   if(rvi_buffer[m_bar_current]!=0.0 && rvi_color[m_bar_current]==1.0)

     {

      double spread=m_symbol.Ask()-m_symbol.Bid();

      if(m_max_spread>0.0 && spread>m_max_spread)

        {

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL ... but spread (",IntegerToString(int(spread/m_symbol.Point())),") > 'Maximum spread'");

         return(true);

        }

      //---

      double price_lowest_buy    = DBL_MAX;

      double volume_lowest_buy   = 0.0;

      double volume_last_buy     = 0.0;

      double profit_buys         = 0.0;

      double price_highest_sell  = DBL_MIN;

      double volume_highest_sell = 0.0;

      double volume_last_sell    = 0.0;

      double profit_sells        = 0.0;

      CalculateAllPositions_1(price_lowest_buy,volume_lowest_buy,volume_last_buy,profit_buys,

                              price_highest_sell,volume_highest_sell,volume_last_sell,profit_sells);

      //--- if there is a SELL position and you can have only one position

      if(InpOnlyOne && price_highest_sell!=DBL_MIN)

        {

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL ... but 'Positions: Only one' is 'true'");

         return(true);

        }

      //--- if BUY profit is less than zero

      if(profit_buys<InpMinProfit && price_lowest_buy!=DBL_MAX)

        {

         if(InpPrintLog)

            Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL ... but profit buys (",DoubleToString(profit_buys,3),") < 'Minumum profit'");

         return(true);

        }

      //---

      if((price_highest_sell==DBL_MIN) || (price_highest_sell!=DBL_MIN && m_symbol.Bid()-price_highest_sell>m_min_step))

        {

         if(InpTradeMode!=buy) // 'Allowed only SELL positions' || 'Allowed BUY and SELL positions'

           {

            ArrayResize(SPosition,size_need_position+1);

            SPosition[size_need_position].pos_type=POSITION_TYPE_SELL;

            if(volume_last_sell>0.0)

              {

               SPosition[size_need_position].volume=volume_last_sell;

               SPosition[size_need_position].lot_coefficient=InpMartinCoeff;

               if(InpPrintLog)

                  Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL ... Martin");

               return(true);

              }

            if(InpPrintLog)

               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL");

            return(true);

           }

         else // 'Allowed only BUY positions'

           {

            if(InpPrintLog)

               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL ... but 'Allowed only BUY positions' -> close all buy positions");

            m_need_close_buy=true;

            return(true);

           }

        }

      else

        {

         if(price_highest_sell!=DBL_MIN && m_symbol.Bid()-price_highest_sell<=m_min_step)

           {

            if(InpPrintLog)

               Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL ... but Bid-price_highest_sell <= m_min_step (",DoubleToString(m_min_step,m_symbol.Digits()),")");

           }

         return(true);

        }

     }

//---

   return(true);

  }

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

Comments