//+------------------------------------------------------------------+
//|                                              CS_Volty_EA_New.mq4 |
//|                        Copyright 2022, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict

//#include <MQL_Easy/MQL_Easy.mqh> // This is for production environment
//#include <MQL_Easy_Example.mqh> // Only for demostration purposes

enum Signal {sigBuy=0, sigSell=1, sigBuyStop=2, sigSellStop=3, sigBuyLimit=4, sigSellLimit=5,};
enum TypeOP {NoOrder, LimitOrder, BuyLimitOrder, SellLimitOrder};

//--- input parameters
input TypeOP            InpOrder          = NoOrder;        // Initial Trades, trigger
input double            InpLotPercent     = 1.5;            // Lot %, if 0 then use Lot
input double            InpLots           = 0.1;            // Lot
input double            InpTakeProfit     = 129.0;           // Take Profit
input double            InpDistanceLimit  = 50;              // AddPips to pending level
input double            InpAddPips        = 3;              // AddPips to pending level
input int               InpSlippage       = 10;            // Slippage
input double            InpMaxSpread      = 6.0;            // Max Spread we allowed
input bool              InpOrdModOnEvent  = true; // Work TimeFrame
input int               InpMagic          = 234;            // magic number
input bool              InpUseMartingale  = true;           // martingale
input double            InpMartiFactor    = 2.0;            // Martingale factor
input bool              HideRectangle     = false;          // Hide Rectangle
input bool              ShowTrendLine     = true;          // Show Price Label
input bool              ShowPriceLabel    = true;          // Show TrendLine
//---
/*
//-- Object that execute trades
CExecute    execute(_Symbol, InpMagic);
//-- Object that manage trades
CPosition   position(_Symbol, InpMagic, GROUP_POSITIONS_ALL);
COrder      order(_Symbol, InpMagic, GROUP_ORDERS_ALL);
CUtilities  utils(_Symbol);
CPrinter    printer;
CError      error;
//---
*/
//define
#define  EA_NAME "CS_Volty_EA"

// V A R I A B L E S
//ulong m_slippage=10;                // slippage
double   ExtDistLimit=0.0;
double   ExtAddPips=0.0;
double   ExtTakeProfit=0.0;
double   ExtFirstTP=0.0;
double   ExtMaxSpread=0.0;
double   dAsk, dBid;
double   PointX;            // point value adjusted for 3 or 5 points
bool     m_init_error   = false;    // error on InInit
double   LongPrice, ShortPrice, LongStop, LongTake, ShortStop, ShortTake;
double   MaxBrokerSpread, MaxSpreadDisplay, BrokerSpread;
//int      totalPositions;
//int      totalOrders;
int      count_buy, count_sell, count_buystop, count_sellstop, count_buylimit, count_selllimit ;
int      count_positions, count_orders, count_all_orders ;
double   buy_op, sell_op, buystop_op, sellstop_op, buylimit_op, selllimit_op ;
double   buy_sl, sell_sl, buystop_sl, sellstop_sl, buylimit_sl, selllimit_sl;
double   buy_tp, sell_tp, buystop_tp, sellstop_tp, buylimit_tp, selllimit_tp;
double   buy_lot, sell_lot, buystop_lot, sellstop_lot, buylimit_lot, selllimit_lot;
double   buy_profit, sell_profit;
int      buy_ticket=-1, buystop_ticket=-1, buylimit_ticket=-1;
int      sell_ticket=-1, sellstop_ticket=-1, selllimit_ticket=-1;
double   NextLot;
double   balans, InitialLot;
int      LevelOP;
datetime t_start_cycle;
double   tempLongPrice, tempLongStop, tempLongTake;
double   tempShortPrice, tempShortStop, tempShortTake;

//indicators
bool     m_close_all=false;
double   BuyLevel=0.0;
double   SellLevel=0.0;
double   BuySL=0.0;
double   SellSL=0.0;
int      copied;
string   csvfname;
double   freeze_level;
double   stop_level;
double   ExtPoint;
//string msg;

//Graphics
string   prefix=_Symbol+"_";
string   sLongRectangle       = prefix+"LongRectangle";
string   sLongRectTLPrice     = prefix+"LongRectTLPrice";
string   sLongRectTLSL        = prefix+"LongRectTLSL";
string   sLongRectLabelPrice  = prefix+"LongRectLabelPrice";
string   sLongRectLabelSL     = prefix+"LongRectLabelSL";

string   sShortRectangle      = prefix+"ShortRectangle";
string   sShortRectTLPrice    = prefix+"ShortRectTLPrice";
string   sShortRectTLSL       = prefix+"ShortRectTLSL";
string   sShortRectLabelPrice = prefix+"ShortRectLabelPrice";
string   sShortRectLabelSL    = prefix+"ShortRectLabelSL";

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
color    cLongRectColor = (!HideRectangle) ? clrNavy : clrBlack;
color    cShortRectColor = (!HideRectangle) ? clrFireBrick : clrBlack;
color    BuyColor = clrDodgerBlue;
color    SellColor = clrDeepPink;
double   LongRectHigh, LongRectLow,
         ShortRectHigh, ShortRectLow;
datetime LeftTimeLongRect, LeftTimeShortRect,
         RightTimeLongRect, RightTimeShortRect,
         LeftTimeMyRect, RightTimeMyRect;
datetime t1, t0;
double   pLongHigh, pLongLow, pShortHigh, pShortLow;

//miscelanous
double temp=0.0;
double test=0.0;
string message;
datetime tempHighestBarTime, tempLowestBarTime,
         recentHighestBarTime, recentLowestBarTime;
int      firstSize;
int      newSize;
datetime prev_bars,
         last_signal;
int      bar_index;
datetime time_0;
datetime currentTime;
datetime leftTime;
bool opThisBar = false;

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//---
   OnInitTestVisual();

   RefreshRates();

   MqlTick lasttick;
   SymbolInfoTick(_Symbol, lasttick);
   dAsk = lasttick.ask;
   dBid = lasttick.bid;
   BrokerSpread = dAsk-dBid;
//--- tuning for 3 or 5 digits
   int digits_adjust=1;
   if(_Digits==3 || _Digits==5)
      digits_adjust=10;
   PointX=_Point*digits_adjust;

   balans         = AccountInfoDouble(ACCOUNT_BALANCE);
   InitialLot     = (InpLotPercent>0) ? InpLotPercent*balans/100/1000 : InpLots;
   ExtDistLimit   = InpDistanceLimit * PointX;
   ExtAddPips     = InpAddPips      * PointX;
   ExtTakeProfit  = InpTakeProfit   * PointX;
   ExtMaxSpread   = InpMaxSpread    * PointX;

   rectangleCreate();
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
   if (  reason==REASON_PROGRAM || reason==REASON_REMOVE ||
         reason==REASON_CHARTCLOSE || reason==REASON_TEMPLATE ||
         reason==REASON_INITFAILED) {

      ObjectsDeleteAll(0);
   }
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//---
   OrdersInformation();
   rectangleCreate();
   dynamicObjects();
   ManageOrders();

   Comment(
      "----------------- BUY -----------------------","\n",
      "Long Price : ", DoubleToString(LongPrice, _Digits),"\n",
      "Long StopLoss : ", DoubleToString(LongStop, _Digits),"\n",
      "Long TakeProfit : ", DoubleToString(LongTake, _Digits),"\n",
      "----------------- SELL -----------------------","\n",
      "Short Price : ", DoubleToString(ShortPrice, _Digits),"\n",
      "Short StopLoss : ", DoubleToString(ShortStop, _Digits),"\n",
      "Short TakeProfit : ", DoubleToString(ShortTake, _Digits)
   );

}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // Event identifier
                  const long& lparam,   // Event parameter of long type
                  const double& dparam, // Event parameter of double type
                  const string& sparam  // Event parameter of string type
                 )
{
//--- the left mouse button has been pressed on the chart
   if(id==CHARTEVENT_OBJECT_DRAG) {
      if(sparam == sShortRectangle || sparam == sLongRectangle) {
         dynamicObjects();
         if(InpOrdModOnEvent)
            ModifyOrders();
      }
      /*
      if(sparam == sLongRectangle) {

         Comment ("Rectangle Low : ", DoubleToString(LongRectLow, _Digits), "\n",
                  "Rectangle High : ", DoubleToString(LongRectHigh, _Digits), "\n",
                  "SellLimit Price : ", DoubleToString(ObjectGetDouble(0, sLongRectLabelPrice, OBJPROP_PRICE, 0), _Digits), "\n",
                  "SellLimit SL : ", DoubleToString(ObjectGetDouble(0, sLongRectLabelSL, OBJPROP_PRICE, 0), _Digits)
                 );
      }
      if(sparam == sShortRectangle) {

         Comment ("Rectangle High : ", DoubleToString(ShortRectHigh, _Digits), "\n",
                  "Rectangle Low : ", DoubleToString(ShortRectLow, _Digits), "\n",
                  "BuyLimit Price : ", DoubleToString(ObjectGetDouble(0, sShortRectLabelPrice, OBJPROP_PRICE, 0), _Digits), "\n",
                  "BuyLimit SL : ", DoubleToString(ObjectGetDouble(0, sShortRectLabelSL, OBJPROP_PRICE, 0), _Digits)
                 );
      }
      */
   }
}


//+------------------------------------------------------------------+
//| Orders Manager                                                   |
//+------------------------------------------------------------------+
void ManageOrders()
{
   if(!CheckSpreadForTrade())
      return;

   if(count_all_orders==0) {
      IsNewBar();
      InitialOrders();
   }
   if(!InpOrdModOnEvent)
      ModifyOrders();
}
//+------------------------------------------------------------------+
//| Modify First Order                                               |
//+------------------------------------------------------------------+
void ModifyOrders()
{
//--- handle buylimit
   if(count_buylimit>0) {
      if(OrderSelect(buylimit_ticket, SELECT_BY_TICKET, MODE_TRADES)) {
         if(buylimit_op!=LongPrice || buylimit_sl!=LongStop) {
            if(!CheckSpreadForTrade()) return;
            OrderModify(buylimit_ticket, LongPrice, LongStop, LongTake, 0, clrNONE);
         }
      }
   }
//--- handle buylimit
   if(count_selllimit>0) {
      if(OrderSelect(selllimit_ticket, SELECT_BY_TICKET, MODE_TRADES)) {
         if(selllimit_op!=ShortPrice || selllimit_sl!=ShortStop) {
            if(!CheckSpreadForTrade()) return;
            OrderModify(selllimit_ticket, ShortPrice, ShortStop, ShortTake, 0, clrNONE);
         }
      }
   }
}
//+------------------------------------------------------------------+
//| Initial Orders                                                   |
//+------------------------------------------------------------------+
void InitialOrders()
{
   if (IsNewBar(PERIOD_CURRENT)) opThisBar = false;

   if (opThisBar) return;

   if(InpOrder==LimitOrder) {
      if(count_buylimit==0 && dAsk>LongPrice) {
         OpenOrders(ORDER_TYPE_BUY_LIMIT, InitialLot, LongPrice, LongStop, LongTake, clrAqua);
      }
      if(count_selllimit==0 && dBid<ShortPrice) {
         OpenOrders(ORDER_TYPE_SELL_LIMIT, InitialLot, ShortPrice, ShortStop, ShortTake, clrMagenta);
      }
   }
   else {
      if(InpOrder==BuyLimitOrder) {
         if(count_buylimit==0 && dAsk>LongPrice)
            OpenOrders(ORDER_TYPE_BUY_LIMIT, InitialLot, LongPrice, LongStop, LongTake, clrAqua);
      }
      if(InpOrder==SellLimitOrder) {
         if(count_selllimit==0 && dBid<ShortPrice)
            OpenOrders(ORDER_TYPE_SELL_LIMIT, InitialLot, ShortPrice, ShortStop, ShortTake, clrMagenta);
      }
   }
}
//+------------------------------------------------------------------+
void OpenOrders(int op, double lot, double price, double sl, double tp, color col)
{
   int ticket = 0;
   int counter = 0, maxtry = 10;
   string EA_COMMENT = EA_NAME;
   lot = NormalizeLot(lot);
   price = NormalizeDouble(price, Digits);
   tp = NormalizeDouble(tp, Digits);
   sl = NormalizeDouble(sl, Digits);

//if (AccountFreeMarginCheck(Symbol(), op-4, lotnya)<=0 || GetLastError()==134) {
// Display_Err(134);
// return;  }

   for (counter = 0; counter < maxtry; counter++) {
      ticket = OrderSend(Symbol(), op, lot, price, InpSlippage, sl, tp, EA_COMMENT, InpMagic, 0, col);
      if (ticket > 0/* NO_ERROR */) {
         opThisBar = false;
         return;
      }
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OrdersInformation()
{
   for (int c=0; c < OrdersTotal(); c++ ) {
      if (OrderSelect(c, SELECT_BY_POS, MODE_TRADES)) {
         if (OrderSymbol() != Symbol())continue;
         if (OrderMagicNumber() != InpMagic)continue;
         switch (OrderType()) {
         case OP_BUY :
            count_buy++;
            buy_ticket=OrderTicket();
            buy_lot=OrderLots();
            buy_sl = OrderStopLoss();
            buy_op = OrderOpenPrice();
            buy_tp = OrderTakeProfit();
            break;
         case OP_SELL :
            count_sell++;
            sell_ticket=OrderTicket();
            sell_lot=OrderLots();
            sell_op = OrderOpenPrice();
            sell_sl = OrderStopLoss();
            sell_tp = OrderTakeProfit();
            break;
         case OP_BUYSTOP :
            count_buystop++;
            buystop_ticket=OrderTicket();
            buystop_lot=OrderLots();
            buystop_tp = OrderTakeProfit();
            buystop_sl = OrderStopLoss();
            buystop_op = OrderOpenPrice();
            break;
         case OP_SELLSTOP:
            count_sellstop++;
            sellstop_ticket=OrderTicket();
            sellstop_lot=OrderLots();
            sellstop_op = OrderOpenPrice();
            sellstop_sl = OrderStopLoss();
            sellstop_tp = OrderTakeProfit();
            break;
         case OP_BUYLIMIT :
            count_buylimit++;
            buylimit_ticket=OrderTicket();
            buylimit_lot=OrderLots();
            buylimit_sl = OrderStopLoss();
            buylimit_op = OrderOpenPrice();
            buylimit_tp = OrderTakeProfit();
            break;
         case OP_SELLLIMIT:
            count_selllimit++;
            selllimit_ticket=OrderTicket();
            selllimit_lot=OrderLots();
            selllimit_sl = OrderStopLoss();
            selllimit_op = OrderOpenPrice();
            selllimit_tp = OrderTakeProfit();
            break;
         }
         count_all_orders++;
      }
   }
}

//+------------------------------------------------------------------+
//| Create Rectangle OnInit                                          |
//+------------------------------------------------------------------+
void rectangleCreate()
{
   t0=iTime(_Symbol, PERIOD_CURRENT, 0);
   t1=iTime(_Symbol, PERIOD_CURRENT, 21);

   pLongHigh = Bid - ExtDistLimit;
   pLongLow = pLongHigh - 40*PointX;

   pShortLow = Bid + ExtDistLimit;
   pShortHigh = pShortLow + 40*PointX;

   if(InpOrder==LimitOrder || InpOrder==BuyLimitOrder)
      if(!createRectangle(sLongRectangle, cLongRectColor, t1, pLongLow, t0, pLongHigh))
         return;
   if(InpOrder==LimitOrder || InpOrder==SellLimitOrder)
      if(!createRectangle(sShortRectangle, cShortRectColor, t1, pShortHigh, t0, pShortLow))
         return;;

   /*
   */
}
//+------------------------------------------------------------------+
//| Handle Rectangle OnChartEvent                                    |
//+------------------------------------------------------------------+
void dynamicObjects()
{

   t0=iTime(_Symbol, PERIOD_CURRENT, 0);
   t1=iTime(_Symbol, PERIOD_CURRENT, 21);

   double   pLongRect1=0, pLongRect2=0,
            pShortRect1=0, pShortRect2=0;
   datetime tLongRect1=0, tLongRect2=0,
            tShortRect1=0, tShortRect2=0;

   pLongRect1  = ObjectGetDouble(0, sLongRectangle, OBJPROP_PRICE, 0);
   pLongRect2  = ObjectGetDouble(0, sLongRectangle, OBJPROP_PRICE, 1);
   pShortRect1  = ObjectGetDouble(0, sShortRectangle, OBJPROP_PRICE, 0);
   pShortRect2  = ObjectGetDouble(0, sShortRectangle, OBJPROP_PRICE, 1);
   tLongRect1  = (datetime) ObjectGetInteger(0, sLongRectangle, OBJPROP_TIME, 0);
   tLongRect2  = (datetime) ObjectGetInteger(0, sLongRectangle, OBJPROP_TIME, 1);
   tShortRect1  = (datetime) ObjectGetInteger(0, sShortRectangle, OBJPROP_TIME, 0);
   tShortRect2  = (datetime) ObjectGetInteger(0, sShortRectangle, OBJPROP_TIME, 1);

   LongRectHigh     = MathMax(pLongRect1, pLongRect2);
   LongRectLow      = MathMin(pLongRect1, pLongRect2);
   LeftTimeLongRect    = MathMin(tLongRect1, tLongRect2);
   RightTimeLongRect   = MathMax(tLongRect1, tLongRect2);
  
   ShortRectHigh     = MathMax(pShortRect1, pShortRect2);
   ShortRectLow      = MathMin(pShortRect1, pShortRect2);
   LeftTimeShortRect    = MathMin(tShortRect1, tShortRect2);
   RightTimeShortRect   = MathMax(tShortRect1, tShortRect2);

   LongPrice   = LongRectHigh + BrokerSpread + ExtAddPips;
   LongStop    = LongRectLow - ExtAddPips;
   LongTake    = LongPrice + ExtTakeProfit;
   
   ShortPrice  = ShortRectLow - ExtAddPips;
   ShortStop   = ShortRectHigh + BrokerSpread + ExtAddPips;
   ShortTake   = ShortPrice - ExtTakeProfit;

   if(ObjectFind(0, sLongRectangle)!=-1) {
      if(ShowPriceLabel) {
         priceLabel(sLongRectLabelPrice, SellColor, RightTimeLongRect, LongPrice);
         priceLabel(sLongRectLabelSL, BuyColor, RightTimeLongRect, LongStop);
      }
      if(ShowTrendLine) {
         dynamicTrendline(sLongRectTLPrice, SellColor, LeftTimeLongRect, LongPrice, RightTimeLongRect, LongPrice); //okay
         dynamicTrendline(sLongRectTLSL, BuyColor, LeftTimeLongRect, LongStop, RightTimeLongRect, LongStop); //okay
      }
   }
   if(ObjectFind(0, sShortRectangle)!=-1) {
      if(ShowPriceLabel) {
         priceLabel(sShortRectLabelPrice, SellColor, RightTimeShortRect, ShortPrice);
         priceLabel(sShortRectLabelSL, BuyColor, RightTimeShortRect, ShortStop);
      }
      if(ShowTrendLine) {
         dynamicTrendline(sShortRectTLPrice, SellColor, LeftTimeShortRect, ShortPrice, RightTimeShortRect, ShortPrice); //okay
         dynamicTrendline(sShortRectTLSL, BuyColor, LeftTimeShortRect, ShortStop, RightTimeShortRect, ShortStop);  //okay
      }
   }
}
//+------------------------------------------------------------------+
// Move rectangle                                                    |
//+------------------------------------------------------------------+
bool dynamicRectangle(string   &name,      // line name
                      color     &clr,
                      datetime  &time1,
                      double    &price1,
                      datetime  &time2,
                      double    &price2)
{
//--- reset the error value
   ResetLastError();
//--- move a rectangle by the given coordinates
   if(ObjectFind(0, name)!=-1) {
      if(!ObjectMove(0, name, 0, time1, price1) || !ObjectMove(0, name, 1, time2, price2)) {
         Print(__FUNCTION__, ": failed to move the anchor point! Error code = ", GetLastError());
         return(false);
      }
   }
//--- create a rectangle by the given coordinates
   else  {
      if(!ObjectCreate(0, name, OBJ_RECTANGLE, 0, time1, price1, time2, price2)) {
         Print(__FUNCTION__, ": failed to create a rectangle! Error code = ", GetLastError());
         return(false);
      }
   }
//--- set line color
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
//--- set line display style
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
//--- set line width
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
//--- display in the foreground (false) or background (true)
//--- enable (true) or disable (false) the mode of filling the rectangle
   ObjectSetInteger(0, name, OBJPROP_FILL, true);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(0, name, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);
//ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
//ObjectSetInteger(_Symbol,name,OBJPROP_HIDDEN,hidden);
   return(true);
}
//+------------------------------------------------------------------+
// Move rectangle                                                    |
//+------------------------------------------------------------------+
bool createRectangle(string   &name,      // line name
                     color     &clr,
                     datetime  &time1,
                     double    &price1,
                     datetime  &time2,
                     double    &price2)
{
//--- reset the error value
   ResetLastError();
//--- create a rectangle by the given coordinates
   if(ObjectFind(0, name)==-1) {
      //--- successful execution
      if(!ObjectCreate(0, name, OBJ_RECTANGLE, 0, time1, price1, time2, price2)) {
         Print(__FUNCTION__, ": failed to create a rectangle! Error code = ", GetLastError());
         return(false);
      }
   }
//--- set line color
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
//--- set line display style
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DASH);
   ObjectSetInteger(0, name, OBJPROP_SELECTABLE, true);
   ObjectSetInteger(0, name, OBJPROP_SELECTED, true);
//--- set line width
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
//--- display in the foreground (false) or background (true)
//--- enable (true) or disable (false) the mode of filling the rectangle
   ObjectSetInteger(0, name, OBJPROP_FILL, true);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(0, name, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);
//ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
//ObjectSetInteger(_Symbol,name,OBJPROP_HIDDEN,hidden);
   return(true);
}

//+------------------------------------------------------------------+
//| Create the right price label                                     |
//+------------------------------------------------------------------+
bool priceLabel(const string     &name, // price label name
                const color      &clr,         // priority for mouse click
                datetime         &time,            // anchor point time
                double           &price
               )
{
//--- set anchor point coordinates if they are not set
//--- reset the error value
   ResetLastError();
//--- create a price label
   if(ObjectFind(0, name) == -1) {
      if(!ObjectCreate(0, name, OBJ_ARROW_RIGHT_PRICE, 0, time, price)) {
         Print(__FUNCTION__, ": failed to create the right price label! Error code = ", GetLastError());
         return(false);
      }
   }
   else if(!ObjectMove(0, name, 0, time, price)) {
      Print(__FUNCTION__, ": failed to move the anchor point! Error code = ", GetLastError());
      return(false);
   }
//--- successful execution
//--- set the label color
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
//--- set the border line style
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
//--- set the label size
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
//ObjectSetString(0,name,OBJPROP_FONT,font);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
//--- enable (true) or disable (false) the mode of moving the label by mouse
//--- when creating a graphical object using ObjectCreate function, the object cannot be
//--- highlighted and moved by default. Inside this method, selection parameter
//--- is true by default making it possible to highlight and move the object
//ObjectSetInteger(0,name,OBJPROP_SELECTABLE,true);
//ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,false);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(0, name, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);
//ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click in the chart
//ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
   return(true);
}
//+------------------------------------------------------------------+
// TrendLine Handling                                                |
//+------------------------------------------------------------------+
bool dynamicTrendline(string    &name,   // line name
                      color     &clr,
                      datetime  &time1,
                      double    &price1,
                      datetime  &time2,
                      double    &price2
                     )
{
   if(ObjectFind(0, name) == -1) {
      if(!ObjectCreate(0, name, OBJ_TREND, 0, time1, price1, time2, price2)) {
         Print(__FUNCTION__, ": failed to create a trend line! Error code = ", GetLastError());
         return(false);
      }
   }
//--- successful execution
   else if(!ObjectMove(0, name, 0, time1, price1) || !ObjectMove(0, name, 1, time2, price2)) {
      Print(__FUNCTION__, ": failed to move trendline! Error code = ", GetLastError());
      return(false);
   }
//--- set line color
   ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
//--- set line display style
   ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_DOT);
//--- set line width
   ObjectSetInteger(0, name, OBJPROP_WIDTH, 1);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(0, name, OBJPROP_BACK, true);
//--- enable (true) or disable (false) the mode of continuation of the line's display to the right
   ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, false);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(0, name, OBJPROP_TIMEFRAMES, OBJ_ALL_PERIODS);
//--- successful execution
   return(true);
}
//+------------------------------------------------------------------+
//| Return the flag of a prefixed object presence                    |
//+------------------------------------------------------------------+
bool IsPresentObjects(const string object_prefix)
{
   for(int i=ObjectsTotal(0, 0)-1; i>=0; i--)
      if(StringFind(ObjectName(0, i, 0), object_prefix)>WRONG_VALUE)
         return true;
   return false;
}
//+------------------------------------------------------------------+
void OnInitTestVisual()
{
   if (IsVisualMode() || (!IsTesting())) {
      long hwnd=ChartID();
      if(hwnd>0) { // If it succeeded, additionally customize
         //--- Set the indent of the right border of the chart
         ChartSetInteger(hwnd,CHART_SHIFT,true);
         //--- Display as candlesticks
         ChartSetInteger(hwnd,CHART_MODE,CHART_CANDLES);
         ChartSetInteger(hwnd,CHART_SHOW_PERIOD_SEP, false);
         ChartSetInteger(hwnd,CHART_SHOW_GRID, false);
         ChartSetInteger(hwnd,CHART_FOREGROUND, false);
         ChartSetInteger(hwnd,CHART_BRING_TO_TOP,true);
         ChartSetInteger(hwnd,CHART_SHOW_ASK_LINE,true);
         ChartSetInteger(hwnd,CHART_SHIFT,true);
         ChartSetInteger(hwnd,CHART_AUTOSCROLL,true);
         ChartSetDouble(hwnd,CHART_SHIFT_SIZE,20);
         //--- Set the tick volume display mode
         //ChartSetInteger(handle,CHART_SHOW_VOLUMES,CHART_VOLUME_TICK);
      }
   }
}
//+------------------------------------------------------------------+
bool isNewBar(datetime newbar_time)
{
//--- Initialization of variables
   int new_bars = 0;
   datetime lastbar_time=0;
//--- Just to be sure, check: is the time of (hypothetically) new bar (newbar_time) less than time of last bar (lastbar_time)?
   if(lastbar_time>newbar_time) {
      return(false);
   }
//--- if it's the first call
   if(lastbar_time==0) {
      lastbar_time=newbar_time; //--- set time of last bar and exit
      return(false);
   }
//--- Check for new bar:
   if(lastbar_time<newbar_time) {
      new_bars=1;               // Number of new bars
      lastbar_time=newbar_time; // remember time of last bar
      return(true);
   }
//--- if we've reached this line, then the bar is not new; return false
   return(false);
}
//+------------------------------------------------------------------+
double NormalizePrice(double p, string pair="")
{
// https://forum.mql4.com/43064#515262 zzuegg reports for non-currency DE30:
// MarketInfo(chart.symbol,MODE_TICKSIZE) returns 0.5
// MarketInfo(chart.symbol,MODE_DIGITS) return 1
// Point = 0.1
// Prices to open must be a multiple of ticksize
   ResetLastError();
   if (pair == "") pair = Symbol();
   double tickSize = SymbolInfoDouble(pair,SYMBOL_TRADE_TICK_SIZE);
   return( MathRound(p/tickSize) * tickSize );
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double NormalizeLot(double lots)
{
   ResetLastError();
   double lotStep = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
   double minLot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
   lots = MathRound(lots/lotStep) * lotStep;
   if (lots < minLot) lots = 0;    // or minLot
   return(lots);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsNewBar(const ENUM_TIMEFRAMES tf = PERIOD_CURRENT)
{
   datetime bar_time=0 ;
   if (bar_time < iTime(Symbol(), tf, 0)) {
      bar_time = iTime(Symbol(), tf, 0);
      return (true);
   }
   return (false);
}
//+------------------------------------------------------------------+
//|                        CheckSpreadForTrade                       |
//+------------------------------------------------------------------+
bool CheckSpreadForTrade()
{
//-- if Broker Spread > Max Spread we are allowed
   if(ExtMaxSpread < BrokerSpread) {
      string msgTemp = "Broker spread "+(string)BrokerSpread+" at "+(string)_Symbol+
                       " has larger than max spread = "+(string)ExtMaxSpread+" we allowed" + "\n";
      msgTemp += "We wait until broker spread reduced.";
   }
//--- checking successful
   return(true);
}

//+------------------------------------------------------------------+
