Template EA

Author: Copyright 2019, ea-builder.net
Price Data Components
Series array that contains the highest prices of each barSeries array that contains the lowest prices of each barSeries array that contains open time of each bar
Orders Execution
Checks for the total of open ordersIt Closes Orders by itself It automatically opens orders when conditions are reachedIt can change open orders parameters, due to possible stepping strategyChecks for the total of closed orders
Indicators Used
Indicator of the average true rangeMACD HistogramFractals
Miscellaneous
It issuies visual alerts to the screenIt plays sound alertsIt sends emailsIt opens Message Boxes to the user
0 Views
0 Downloads
0 Favorites
Template EA
//+------------------------------------------------------------------+
//|                                                Lloid Grid EA.mq4 |
//|                                   Copyright 2019, ea-builder.net |
//|                                        http://www.ea-builder.net |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, ea-builder.net"
#property link      "http://www.ea-builder.net"
#property version   "1.00"
#property strict


enum enum_VolumeType {Fixed_Size,Risk_Percentage,Risked_Amount,Used_Margin_Percentage,Kelly_Criterion};
enum enum_SLType {Fixed_Pips, ATR_Multiplier, Last_Swing_HighLow};
enum enum_TPType {TP_Fixed_Pips, RR_Ratio};

string Pairs="";
string Timeframes="";
string EAName="Ichimoku Price Action Strategy v1.0";
input string _Settings3=" --- STRATEGY PARAMETERS --- "; //.
input bool BuyMode=true; // Buy Mode
input bool SellMode=true; // Sell Mode


input ENUM_TIMEFRAMES TradingTF=PERIOD_H1; // Trading TF
input string BBIndiName="bb"; // BB Indi Name
extern int    Length=20;      // Bollinger Bands Period
extern int    Deviation=2;    // Deviation
extern double x=0;    // Tune
extern double MoneyRisk=1.00; // Offset Factor

input bool UseMACDFilter=true; // Use MACD Filter
input int MACDFastEMA=12; // MACD Fast EMA Period
input int MACDSlowEMA=26; // MACD Slow EMA Period
input int MACDSignalEMA=9; // MACD Signal Period


input bool WaitForCandleClose=false; // Wait For Candle Close Confirmation
input string ___Settings="";//.
input string __Settings2=" --- TRADE MANAGEMENT --- "; //.
int MultipleEntriesAtTheSameTime=1; // Multiple Entries At The Same Time
double DivideRiskBetweenEntries=true; // Split Risk Between Entries
input string StartTime="00:00"; // Start Time
input string EndTime="00:00";  // End Time
input bool CloseOrdersAtEndOfBar=false; // Close Positions At End Of Bar
input bool CloseOnReverse=true; // Close Positions On Opposite Signal
input enum_TPType TPType=TP_Fixed_Pips; // TP Type
string TakeProfits="20, 40"; // TP Pips (multiple orders)
string TakeProfitRatios="0.5, 1"; // TP Ratios (multiple orders)
input enum_SLType SLType=Fixed_Pips; // SL Type
input  double TakeProfit=20; // TP Pips
input  double TakeProfitRatio=2; // TP RR Ratio
input double StopLoss=50; // SL Pips  (0=Disabled)
input int BarsForSwingSL=10; // Bars For H/L Swing SL
input ENUM_TIMEFRAMES TFForSwingSL=PERIOD_M5; // TF For Swing SL
input double StopATRMultiplier=1; // SL ATR Multiplier
input ENUM_TIMEFRAMES ATRTFSL =PERIOD_M15; // SL ATR TF
input int ATRPeriod=28; // ATR Period
bool OpenAdditionalEntry=false; // Open Additional Entry
double TakeProfit2=20; // TP Pips 2
double TakeProfitRatio2=0.5; // TP Ratio 2
input double MoveToBreakEven=0; // Move To Break-Even Pips (0=Disabled)
input double TrailingStop=50; // Trailing-Stop Pips (0=Disabled)
input double TrailingStopTrigger=25; // Trailing-Stop Trigger Pips
input double TrailingStopStep=5; // Trailing-Stop Step
input double PartialTPPips=0; // Partial Close TP Pips (0=Disabled)
input double PartialCloseLotPercentage=50; // Partial Close Lot Percentage
input bool StealthSLandTP=false; // Stealth SL and TP
input int MaxOpenPositions=1; // Max Open Positions (per Symbol/EA)
int MaxSignalsPerBar=1; // Max Signals Per Bar
int MaxTradesPerBar=0; // Max Trades Per Bar
input string __Settings="";//.
input string _Settings=" --- MONEY MANAGEMENT --- "; //.
input enum_VolumeType VolumeType=Risk_Percentage; // Lot Calculation Method
input double FixedLotSize=0.1; //Fixed Lot-Size Value
input double RiskPercentage=1; // Risk Percentage Value
input double RiskedAmount=100; // USD Risked Amount Value
input double MarginPercentage=2; // Margin Percentage Value
input double LotMultiplierOnLoss=1; //  Lot Multiplier On Loss
input double LotAdderOnLoss=0.0; //  Lot Adder On Loss
ENUM_DAY_OF_WEEK StartDay=MONDAY;  // Start Day
ENUM_DAY_OF_WEEK EndDay=FRIDAY;  // End Day
input string _Settings6="";//.
input string _Settings7=" --- MARKET FILTERS --- ";//.
input double Slippage=3; // Max Slippage (0=Disabled)
input double MaxSpread=5; // Max Spread (0=Disabled)
input string _Settings8="";//.
input string _Settings9=" --- CUSTOMIZATION --- ";//.
input bool SaveTradeScreenshots=true; // Save Screenshots With Trades
input string TradeComment=""; // Trade Comment
input bool SoundAlert=false; // Sound Alert
input string SoundFile="alert2.wav"; // Sound File
input bool PopupAlert=false; // Pop-up Alefrt
input bool EmailAlert=true; // Email Alert
input bool PhoneAlert=false; // Phone Alert
input bool ShowDashBoard=true; // Show Dashboard
input ENUM_BASE_CORNER DashBoardCorner=CORNER_LEFT_UPPER; // DashBoard Corner
input color DashBoardBGColor=clrMidnightBlue; // Dashboard BackGround Color
input color DashBoardColor=clrGold; // Dashboard Text Color
color BearishColor=clrTomato; // Bearish Color
color BullishColor=clrLimeGreen; // Bullish Color
input int MagicNumber=321123; // Magic Number
bool ECN=true;

bool AskForManualConfirmation=false; // Ask Manual Confirmation Before Opening Trades
int minTradesForKellyCriterion=20;
bool VirtualPendingOrders=false;
string DashKeys[8];
string DashValues[8];
string DashCount;
int dashRows=1;
datetime lastTradeHour=0;
string pairs[];
string s_timeframes[];
int timeframes[];
double takeProfits[];
double takeProfitRatios[];
string s_takeProfits[];
string s_takeProfitRatios[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   GlobalVariableSet("PClosedLastTime"+Symbol()+timeFrameToString(Period()),0);

   _MaxSpread=MaxSpread;
   _MaxSlippage=Slippage;
   _MaxTraderPerBar=MaxTradesPerBar;
   _ECN=ECN;
   _StealthPendingOrders=VirtualPendingOrders;
   _StealthSLandTP=StealthSLandTP && !IsOptimization();
   _AskForManualConfirmation=AskForManualConfirmation;
   TransformTime(StartTime,StartHour,StartMinute);
   TransformTime(EndTime,EndHour,EndMinute);
   InitAlertTypes(SoundAlert,SoundFile,PopupAlert,EmailAlert,PhoneAlert);

   if(IsTradeAllowed()==false)
      Alert("Please enable the setting \"Allow live trading\" under the Common tab in the Expert Properties (press F7)");
   if(IsExpertEnabled()==false)
      Alert("Expert advisors are disabled! Please enable the Expert Advisors button on the toolbar.");

   ChartSetInteger(0,CHART_SHOW_GRID,false);
   ChartSetInteger(0,CHART_MODE,1);

   if(WaitForCandleClose)
      masterCandleIdx=1;
   dashRows=ArraySize(DashKeys);

   double aux1,aux2;
   if(VolumeType==Kelly_Criterion && GetKellyCriterionFactors(Symbol(),MagicNumber,aux1,aux2)<minTradesForKellyCriterion)
     {
      Alert("Not enough trades in history to process the Kelly Criterion Risk Ratio (at least "+(string)minTradesForKellyCriterion+" trades necessary). The EA will use the Risk Percentage method until there are enough trades to make the proper calculations.");
     }

   if(StringLen(Pairs)>0)
     {
      StringSplit(Pairs,',',pairs);
      for(int i=0; i<ArraySize(pairs); i++)
        {
         pairs[i]=StringTrimLeft(StringTrimRight(pairs[i]));
        }
     }

   if(StringLen(Timeframes)>0)
     {
      StringSplit(Timeframes,',',s_timeframes);
      ArrayResize(timeframes,ArraySize(s_timeframes));
      for(int i=0; i<ArraySize(s_timeframes); i++)
        {
         s_timeframes[i]=StringTrimLeft(StringTrimRight(s_timeframes[i]));
         timeframes[i]=stringToTimeFrame(s_timeframes[i]);
        }
     }
   if(StringLen(TakeProfits)>0)
     {
      StringSplit(TakeProfits,',',s_takeProfits);
      ArrayResize(takeProfits,ArraySize(s_takeProfits));
      for(int i=0; i<ArraySize(s_takeProfits); i++)
        {
         s_takeProfits[i]=StringTrimLeft(StringTrimRight(s_takeProfits[i]));
         takeProfits[i]=stringToTimeFrame(s_takeProfits[i]);
        }
     }
   if(StringLen(TakeProfitRatios)>0)
     {
      StringSplit(TakeProfitRatios,',',s_takeProfitRatios);
      ArrayResize(takeProfitRatios,ArraySize(s_takeProfitRatios));
      for(int i=0; i<ArraySize(s_takeProfitRatios); i++)
        {
         s_takeProfitRatios[i]=StringTrimLeft(StringTrimRight(s_takeProfitRatios[i]));
         takeProfitRatios[i]=stringToTimeFrame(s_takeProfitRatios[i]);
        }
     }
   takeProfitRatios[0]=TakeProfitRatio;
   takeProfits[0]=TakeProfit;
   if(OpenAdditionalEntry)
     {
      MultipleEntriesAtTheSameTime=2;
      ArrayResize(takeProfitRatios,2);
      ArrayResize(takeProfits,2);
      takeProfitRatios[0]=TakeProfitRatio;
      takeProfitRatios[1]=TakeProfitRatio2;
      takeProfits[0]=TakeProfit;
      takeProfits[1]=TakeProfit2;
     }
   else
     {
      MultipleEntriesAtTheSameTime=1;
     }
   /* ChartSetInteger(0,CHART_COLOR_BACKGROUND,clrBlack);
    ChartSetInteger(0,CHART_COLOR_FOREGROUND,clrWhite);
    ChartSetInteger(0,CHART_COLOR_GRID,clrBlack);
    ChartSetInteger(0,CHART_COLOR_CHART_UP,clrAqua);
    ChartSetInteger(0,CHART_COLOR_CHART_DOWN,clrFireBrick);
    ChartSetInteger(0,CHART_COLOR_CANDLE_BULL,clrAqua);
    ChartSetInteger(0,CHART_COLOR_CANDLE_BEAR,clrTomato);
    ChartSetInteger(0,CHART_COLOR_GRID,clrYellow);
    ChartSetInteger(0,CHART_COLOR_VOLUME,clrForestGreen);
    ChartSetInteger(0,CHART_COLOR_ASK,clrRed);
    ChartSetInteger(0,CHART_COLOR_BID,clrRed);
    ChartSetInteger(0,CHART_SCALE,3);*/

   CheckOrders();

   MaxTradesPerBar=MultipleEntriesAtTheSameTime;
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int lastdeinitReason=-1;
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   if(reason!=3)
     {
      ObjectsDeleteAll(0,0,OBJ_BUTTON);
      RemoveDashboard();
     }
   lastdeinitReason=reason;
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   CheckOrders();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double atr(int bufferIdx)
  {
   double ma=iATR(Symbol(),ATRTFSL,ATRPeriod,masterCandleIdx);

   return ma;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CheckOrders()
  {
   bool canBuy=BuyMode;
   bool canSell=SellMode;
   int tf=Period();
   string pair=Symbol();



   double atr=atr(0);
   double pip=GetPip();

   static int signalsThisBar=0;

   if(IsNewCandle())
     {
      signalsThisBar=0;
     }

   int openCloseConditionIdx=4;
   DashKeys[openCloseConditionIdx-1]="Mode";
   DashValues[openCloseConditionIdx-1]="n/a";
   if(BuyMode && SellMode)
      DashValues[openCloseConditionIdx-1]="BUY and SELL";
   else
      if(BuyMode)
         DashValues[openCloseConditionIdx-1]="BUY";
      else
         if(SellMode)
            DashValues[openCloseConditionIdx-1]="SELL";


   int signalConditions=3;
   DashKeys[openCloseConditionIdx+1-1]="Time";
   DashValues[openCloseConditionIdx+1-1]=TimeToStr(TimeLocal());

   DashKeys[openCloseConditionIdx+2-1]="MACD Condition";
   DashValues[openCloseConditionIdx+2-1]="not used";
   if(UseMACDFilter)
     {
      double macdMain=iMACD(Symbol(),TradingTF,MACDFastEMA,MACDSlowEMA,MACDSignalEMA,0,MODE_MAIN,masterCandleIdx);
      double macdSignal=iMACD(Symbol(),TradingTF,MACDFastEMA,MACDSlowEMA,MACDSignalEMA,0,MODE_SIGNAL,masterCandleIdx);

      DashValues[openCloseConditionIdx+2-1]=Direction(macdMain>macdSignal,macdSignal>macdMain,canBuy,canSell);
     }
   static bool lastClosedOrderWasLost=false;
   static double nextOrderLots=0;


   if(CloseOrdersAtEndOfBar)
      CloseOrdersOlderThan(Time[0],MagicNumber);

   if((LotMultiplierOnLoss>1 || LotAdderOnLoss>0))
     {
      if(OrderJustClosed(Symbol(),MagicNumber,-1,true))
        {
         Print("NEW ORDER CLOSED");
         if(_selectedProfit>0)
           {
            lastClosedOrderWasLost=false;
            nextOrderLots=0;
            //   DashValues[openCloseConditionIdx+1]="Win - #"+IntegerToString(_selectedTicket)+": "+DoubleToStr(_selectedProfitPips,1)+" pips at "+TimeToStr(_selectedCloseTime);
            //   DashValues[openCloseConditionIdx+2]="reset lot-size";
            Print("Last order was closed in profit, reset multiplier and adder");
           }
         else
           {
            lastClosedOrderWasLost=true;
            nextOrderLots=_selectedVolume*LotMultiplierOnLoss+LotAdderOnLoss;
            if(VolumeType==Risk_Percentage)
              {
               nextOrderLots=_selectedRiskedPercentage*LotMultiplierOnLoss+LotAdderOnLoss;
               Print("last order's risk percentage was "+DoubleToStr(_selectedRiskedPercentage)+"%");
              }
            else
               if(VolumeType==Risked_Amount)
                 {
                  nextOrderLots=_selectedRiskedAmount*LotMultiplierOnLoss+LotAdderOnLoss;
                  Print("last order's risk in USD was $"+DoubleToStr(_selectedRiskedAmount,2));
                 }
            //     DashValues[openCloseConditionIdx+2]=DoubleToStr(nextOrderLots,1);
            //   DashValues[openCloseConditionIdx+1]="Loss - #"+IntegerToString(_selectedTicket)+": "+DoubleToStr(_selectedProfitPips,1)+" pips at "+TimeToStr(_selectedCloseTime);
            Print("Last order ("+DoubleToStr(_selectedVolume,2)+" lots) was  loss, next order will be "+DoubleToStr(nextOrderLots,2));
           }
        }
     }

   int sign=0;
   if(InInterval(TimeCurrent(),StartHour,StartMinute,EndHour,EndMinute))
     {
      // if inside daily trading interval, set the signal - sign=1 means BUY, sign=-1 means SELL
      if((canBuy) && CountOpenOrders(OP_BUY,Symbol(),MagicNumber)<MaxOpenPositions)
        {
         sign=1;
         TriggerAlerts("Bullish signal for "+pair+" on "+timeFrameToString(Period()));
        if (pair==Symbol())    SetSignalArrow(1,0,233,clrLimeGreen);
         DashValues[openCloseConditionIdx+signalConditions]="Long at "+TimeToStr(TimeCurrent());
        }
      if((canSell) && CountOpenOrders(OP_SELL,Symbol(),MagicNumber)<MaxOpenPositions)
        {
         sign=-1;
         TriggerAlerts("Bearish signal for "+pair+" on "+timeFrameToString(Period()));
           if (pair==Symbol()) SetSignalArrow(-1,0,234,clrTomato);
         DashValues[openCloseConditionIdx+signalConditions]="Short at "+TimeToStr(TimeCurrent());
        }
     }

   if(CloseOnReverse && CountOpenOrders(OP_SELL,Symbol(),MagicNumber)>0 && isBullish(DashValues[openCloseConditionIdx]))
     {
      Print("Bullish signal - close SELL orders");
      CloseSellOrders(pair,MagicNumber);
     }

   if(CloseOnReverse && CountOpenOrders(OP_BUY,Symbol(),MagicNumber)>0 && isBearish(DashValues[openCloseConditionIdx]))
     {
      Print("Bearish signal - close BUY orders");
      CloseBuyOrders(pair,MagicNumber);
     }

   if(sign!=0 && signalsThisBar<MaxSignalsPerBar)
     {
      signalsThisBar++;
      // if we've got a BUY (1) or SELL (-1) signal, calculate SL/TP/volumes and enter a market order
      double sl=0;
      double tp=0;
      double entryPrice=MarketInfo(pair,MODE_ASK);
      if(sign<0)
         entryPrice=MarketInfo(pair,MODE_BID);

      if(StopLoss>0)
         sl=entryPrice+(-1)*sign*StopLoss*pip;
      if(SLType==ATR_Multiplier)
        {
         sl=entryPrice+(-1)*sign*StopATRMultiplier*atr;
        }
      if(SLType==Last_Swing_HighLow)
        {
         sl=iHigh(Symbol(),TFForSwingSL,iHighest(Symbol(),TFForSwingSL,MODE_HIGH,BarsForSwingSL,masterCandleIdx));
         if(sign>0)
            sl=iLow(Symbol(),TFForSwingSL,iLowest(Symbol(),TFForSwingSL,MODE_LOW,BarsForSwingSL,masterCandleIdx));
        }

      double slDistance=MathAbs(entryPrice-sl);

      if(TakeProfit>0)
         tp=entryPrice+sign*TakeProfit*pip;
      if(TPType==RR_Ratio)
         tp=entryPrice+sign*TakeProfitRatio*slDistance;

      bool confirmed=ManuallyConfirmed(sign);
      if(confirmed)
        {
         slDistance=GetPip()*10;
         if(sl!=0)
           {
            slDistance=entryPrice-sl;
            if(sign<0)
               slDistance=sl-entryPrice;
           }
         double volume=CalculateLotSize(pair,MagicNumber,slDistance);
         if(MultipleEntriesAtTheSameTime>1 && DivideRiskBetweenEntries)
            volume=NormLots(volume/DivideRiskBetweenEntries);

         if(nextOrderLots>0)
            volume=CalculateLotSize(Symbol(),MagicNumber,slDistance,nextOrderLots);

         if(sign>0)
           {

            if(CountOpenOrders(OP_BUY,Symbol(),MagicNumber)>=MaxOpenPositions)
               Print("Too many BUY orders on "+Symbol()+", can't open another one");
            else
              {
               for(int i=0; i<MultipleEntriesAtTheSameTime; i++)
                 {
                  if(MultipleEntriesAtTheSameTime>=1)
                    {
                     if(TPType==TP_Fixed_Pips && ArraySize(takeProfits)>=i && takeProfits[i]>0)
                        tp=entryPrice+sign*takeProfits[i]*pip;
                     if(TPType==RR_Ratio && ArraySize(takeProfitRatios)>=i && takeProfitRatios[i]>0)
                        tp=entryPrice+sign*takeProfitRatios[i]*slDistance;
                    }

                  Print("Open order number "+(string)(i+1));
                  if(OpenBuy(pair,volume,sl,tp,TradeComment,MagicNumber))
                     PrintDash(dashRows-2);
                 }
              }

           }
         else
            if(sign<0)
              {

               if(CountOpenOrders(OP_SELL,Symbol(),MagicNumber)>=MaxOpenPositions)
                  Print("Too many SELL orders on "+Symbol()+", can't open another one");
               else
                  for(int i=0; i<MultipleEntriesAtTheSameTime; i++)
                    {

                     if(MultipleEntriesAtTheSameTime>=1)
                       {
                        if(TPType==TP_Fixed_Pips && ArraySize(takeProfits)>=i && takeProfits[i]>0)
                           tp=entryPrice+sign*takeProfits[i]*pip;
                        if(TPType==RR_Ratio && ArraySize(takeProfitRatios)>=i && takeProfitRatios[i]>0)
                           tp=entryPrice+sign*takeProfitRatios[i]*slDistance;
                       }

                     Print("Open order number "+(string)(i+1));
                     if(OpenSell(pair,volume,sl,tp,TradeComment,MagicNumber))
                        PrintDash(dashRows-2);
                    }

              }
        }
     }

   MoveToBE(pair,MagicNumber,MoveToBreakEven,1);
   TrailSL(pair,MagicNumber,TrailingStop,TrailingStopTrigger,TrailingStopStep);

   if(PartialTPPips>0)
     {
      for(int i=OrdersTotal()-1; i>=0; i--)
        {
         double currentSL=0;
         double currentTP=0;
         ResetLastError();
         if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
           {
            Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
            return;
           }
         if(OrderSymbol()==Symbol() && OrderMagicNumber()==MagicNumber)
           {
            if(OrderProfit()>0 && MathAbs(OrderClosePrice()-OrderOpenPrice())/GetPip()>=PartialTPPips)
              {
               Print("partially close order "+(string)OrderTicket());
               int close=OrderClose(OrderTicket(),NormLots(OrderLots()*PartialCloseLotPercentage/100),OrderClosePrice(),10);
              }
           }
        }
     }

   if(VirtualPendingOrders)
     {
      CheckVirtualPendingOrders();
     }
   CheckVirtualStops(pair,MagicNumber);

   DashKeys[0]=EAName;
   DashValues[0]=TimeToStr(TimeCurrent());
   DashKeys[1]="Current spread";
   DashValues[1]=DoubleToStr(MarketInfo(Symbol(),MODE_SPREAD)*(Point/GetPip(Symbol())),1)+" pips";
   DashKeys[2]="Lot-size";
   DashValues[2]="fixed, "+DoubleToStr(FixedLotSize,2)+ " lots";
   if(VolumeType==Used_Margin_Percentage)
      DashValues[2]="dynamic, "+DoubleToStr(MarginPercentage,1)+ "% margin used";
   if(VolumeType==Risk_Percentage)
      DashValues[2]="dynamic, risk="+DoubleToStr(RiskPercentage,1)+ "% of equity";
   if(VolumeType==Risked_Amount)
      DashValues[2]="dynamic, risk="+DoubleToStr(RiskedAmount,1)+ AccountCurrency();
   if(VolumeType==Kelly_Criterion)
      DashValues[2]="dyanmic, kelly criterion, risk="+DoubleToStr(RiskedAmount,1)+ AccountCurrency();

   if(ShowDashBoard)
     {
      DisplayDashboard(281,dashRows-1);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateLotSize(string symbol,int magic,double slDistance,double valueOrPercentage=0)
  {
   slDistance=MathMax(slDistance,Point);

   double lots=FixedLotSize;
   if(VolumeType==Fixed_Size)
     {
      if(valueOrPercentage!=0)
         return valueOrPercentage;
      else
         return (lots);
     }

   if(VolumeType==Used_Margin_Percentage)
     {
      double marginFor1Lot=MarketInfo(symbol,MODE_MARGINREQUIRED);
      double lotsCanBuy=AccountEquity()/marginFor1Lot;
      if(valueOrPercentage!=0)
         lots=lotsCanBuy*valueOrPercentage/100;
      else
         lots=lotsCanBuy*MarginPercentage/100;
     }

   double pipValue=MarketInfo(symbol,MODE_TICKVALUE);
   double point=MarketInfo(symbol,MODE_POINT);
   double pip=GetPip(symbol);

   if(VolumeType==Kelly_Criterion)
     {
      double winFactor=0;
      double winLossRatio=0;
      int trades=GetKellyCriterionFactors(symbol,magic,winFactor,winLossRatio);

      double riskPercentage=RiskPercentage;
      if(valueOrPercentage!=0)
         riskPercentage=valueOrPercentage;
      if(trades>=minTradesForKellyCriterion)
        {
         double kellyRatio=winFactor-((1-winFactor)/winLossRatio);
         riskPercentage=kellyRatio*100;
        }

      lots=AccountEquity()*riskPercentage/100/((slDistance/point)*pipValue);
     }

   if(point==0)
     {
      Print("point=0 for "+symbol+"! - force exit");
      return 0;
     }
   if(pipValue==0)
     {
      Print("pipvalue=0 for "+symbol+"! - force exit");
      return 0;
     }

   if(VolumeType==Risk_Percentage)
     {
      lots=AccountEquity()*RiskPercentage/100/((slDistance/point)*pipValue);
      Print("sl distance="+DoubleToStr(slDistance/Point,1)+" points, risk="+(string)RiskPercentage+"%, lots="+DoubleToStr(lots,2));
      if(valueOrPercentage!=0)
        {
         lots=AccountEquity()*valueOrPercentage/100/((slDistance/point)*pipValue);
         Print("sl distance="+DoubleToStr(slDistance/Point,1)+" points, risk="+(string)valueOrPercentage+"%, lots="+DoubleToStr(lots,2));
        }
     }

   if(VolumeType==Risked_Amount)
     {
      lots=RiskedAmount/((slDistance/point)*pipValue);
      Print("sl distance="+DoubleToStr(slDistance/Point,1)+" points, risk="+(string)RiskedAmount+"USD, lots="+DoubleToStr(lots,2));
      if(valueOrPercentage!=0)
        {
         lots=valueOrPercentage/((slDistance/point)*pipValue);
         Print("sl distance="+DoubleToStr(slDistance/Point,1)+" points, risk="+(string)valueOrPercentage+"USD, lots="+DoubleToStr(lots,2));
        }
     }

   double lotStep=MarketInfo(symbol,MODE_LOTSTEP);
   int digits = 0;
   if(lotStep<= 0.01)
      digits=2;
   else
      if(lotStep<=0.1)
         digits=1;
   lots=NormalizeDouble(lots,digits);

   double minLots=MarketInfo(symbol,MODE_MINLOT);
   if(lots<minLots)
      lots=minLots;

   double maxLots=MarketInfo(symbol,MODE_MAXLOT);
   if(lots>maxLots)
      lots=maxLots;

   return (lots);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DisplayDashboard(int width=200,int currentProfitIdx=-1)
  {
   if(currentProfitIdx!=-1)
     {
      DashKeys[currentProfitIdx]="Running profit";
      DashValues[currentProfitIdx]="No order currently opened";
      int buys=CountOpenOrders(OP_BUY);
      int sells=CountOpenOrders(OP_SELL);
      if(buys+sells!=0)
        {
         string typesB="";
         string typesS="";
         if(buys==1)
            typesB=IntegerToString(buys)+" BUY";
         if(buys>1)
            typesB=IntegerToString(buys)+" BUYs";
         if(sells==1)
            typesS=IntegerToString(sells)+" SELL";
         if(sells>1)
            typesS=IntegerToString(sells)+" SELLs";
         if(buys!=0 && sells!=0)
            typesS=", "+typesS;
         DashValues[currentProfitIdx]="$"+DoubleToStr(CurrentProfit(Symbol(),MagicNumber,-1),2)+" ("+typesB+typesS+")";
        }
     }

   int fontSize=8;
   int xSign=1;
   int ySign=1;
   int DashBoardXOffset=10;
   int DashBoardYOffset=30;
   if(DashBoardCorner==CORNER_RIGHT_LOWER || DashBoardCorner==CORNER_RIGHT_UPPER)
     {
      DashBoardXOffset+=width;
      xSign=-1;
     }
   if(DashBoardCorner==CORNER_RIGHT_LOWER || DashBoardCorner==CORNER_LEFT_LOWER)
     {
      DashBoardYOffset+=9+ArraySize(DashKeys)*(fontSize+fontSize/2);
      ySign=-1;
     }

   string name="dashBack";
   if(ObjectFind(0,name)<0)
     {
      ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,0,0,0);
     }
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,DashBoardXOffset);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,DashBoardYOffset);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,width);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,9+(int)(ArraySize(DashKeys)*(fontSize+fontSize/1.7)));
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,DashBoardBGColor);
   ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_FLAT);
   ObjectSetInteger(0,name,OBJPROP_CORNER,DashBoardCorner);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_BACK,true);
   ObjectSetInteger(0,name,OBJPROP_ZORDER,10);

   for(int i=0; i<ArraySize(DashKeys)+10; i++)
     {
      name="dashRow"+IntegerToString(i);
      if(i>=ArraySize(DashKeys))
        {
         ObjectDelete(0,name);
        }
      else
        {
         if(ObjectFind(0,name)<0)
           {
            ObjectCreate(0,name,OBJ_LABEL,0,0,0);
           }
         color clr=DashBoardColor;
         if(StringFind(DashValues[i],"Bullish")>=0 || StringFind(DashValues[i],"UP")>=0)
            clr=BullishColor;
         if(StringFind(DashValues[i],"Bearish")>=0 || StringFind(DashValues[i],"DOWN")>=0)
            clr=BearishColor;
         ObjectSetInteger(0,name,OBJPROP_XDISTANCE,DashBoardXOffset+xSign*5);
         ObjectSetInteger(0,name,OBJPROP_YDISTANCE,DashBoardYOffset+ySign*3+(int)(ySign*i*(fontSize+fontSize/1.7)));
         ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_FLAT);
         ObjectSetInteger(0,name,OBJPROP_CORNER,DashBoardCorner);
         ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
         ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
         ObjectSetInteger(0,name,OBJPROP_ZORDER,8);
         ObjectSetString(0,name,OBJPROP_TEXT,DashKeys[i]+": "+DashValues[i]);
         ObjectSetText(name,DashKeys[i]+": "+DashValues[i],fontSize);
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void RemoveDashboard()
  {
   ObjectDelete(0,"dashBack");
   for(int i=0; i<ArraySize(DashKeys); i++)
     {
      ObjectDelete(0,"dashRow"+IntegerToString(i));
     }
   ObjectDelete(0,"closeAll");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void AddCloseAllTradesButton(int DashBoardX,int DashBoardY,int fontSize)
  {
   ObjectCreate(0,"closeAll",OBJ_BUTTON,0,0,0);
   ObjectSetInteger(0,"closeAll",OBJPROP_XDISTANCE,DashBoardX+5);
   ObjectSetInteger(0,"closeAll",OBJPROP_YDISTANCE,DashBoardY+13+ArraySize(DashKeys)*(fontSize+fontSize/2));
   ObjectSetInteger(0,"closeAll",OBJPROP_XSIZE,96);
   ObjectSetString(0,"closeAll",OBJPROP_TEXT,"Close all trades");
   ObjectSetInteger(0,"closeAll",OBJPROP_ZORDER,0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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
  {
   if(id==CHARTEVENT_OBJECT_CLICK && sparam=="closeAll")
     {
      CloseBuyOrders(Symbol(),MagicNumber);
      CloseSellOrders(Symbol(),MagicNumber);
      Sleep(100);
      ObjectSetInteger(0,"closeAll",OBJPROP_STATE,false);
     }

   if(id==CHARTEVENT_OBJECT_DRAG)
     {
      string labelName=sparam+"txt";
      if(ObjectFind(labelName)==0)
        {
         double newPrice=ObjectGetDouble(0,sparam,OBJPROP_PRICE1);
         ObjectSetDouble(0,labelName,OBJPROP_PRICE1,newPrice);
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void PrintDash(int rows=1)
  {
   for(int i=1; i<=rows; i++)
     {
      Print(DashKeys[i]+" "+DashValues[i]);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool isBullish(string value)
  {
   return StringFind(value,"Bullish")>=0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool isBearish(string value)
  {
   return StringFind(value,"Bearish")>=0;
  }
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| defines                                                          |
//+------------------------------------------------------------------+
// #define MacrosHello   "Hello, world!"
// #define MacrosYear    2010
int masterCandleIdx;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double FractalUp(int bIdx,string symbol=NULL,int tf=0)
  {
   double fractalUp=iFractals(symbol,tf,MODE_UPPER,bIdx);
   return ok(fractalUp);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double FractalDown(int bIdx,string symbol=NULL,int tf=0)
  {
   double fractalDown=iFractals(symbol,tf,MODE_LOWER,bIdx);
   return ok(fractalDown);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool tradingDay[7];
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void InitTradingDays(bool monday,bool tuesday,bool wednesday,bool thursday,bool friday)
  {
   tradingDay[1]=monday;
   tradingDay[2]=tuesday;
   tradingDay[3]=wednesday;
   tradingDay[4]=thursday;
   tradingDay[5]=friday;
   tradingDay[6]=false;
   tradingDay[0]=false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool TradingDay(int day)
  {
   return tradingDay[day];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
input int Debug=1;
bool _StealthSLandTP=false;
bool _StealthPendingOrders=false;
double _MaxSpread=0;
double _MaxSlippage=300;
int _MaxTraderPerBar=0;
string _VS_Prefix="vs ";
string _ObjPrefix="ea ";
bool _AskForManualConfirmation=false;
bool _ECN=true;
bool _DisplayVPOLabels=true;
bool _ShowArrows=true;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string SymbolSuffix(string symbol)
  {
   return (StringSubstr(symbol,6,0));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void WaitTradeContext()
  {
   datetime tstart=TimeLocal();
//Print("enter WaitTradeContext");
   while(!IsTradeAllowed() && TimeLocal()-tstart<60)
     {
      Sleep(100);
     }
   if(!IsTradeAllowed())
     {
      Print("Trade not allowed");
     }
   else
     {
      //Print("Trade allowed!");
     }

   while(IsTradeContextBusy() && TimeLocal()-tstart<60)
     {
      Sleep(100);
     }
   if(IsTradeContextBusy())
     {
      Print("Trade context busy");
     }
   else
     {
      //Print("Trade context free!");
     }
//Print("leave WaitTradeContext");
  }
//+------------------------------------------------------------------+
string err_msg(int e)
//+------------------------------------------------------------------+
// Returns error message text for a given MQL4 error number
// Usage:   string s=err_msg(146) returns s="Error 0146:  Trade context is busy."
  {
   switch(e)
     {
      case 0:
         return("Error 0000:  No error returned.");
      case 1:
         return("Error 0001:  No error returned, but the result is unknown.");
      case 2:
         return("Error 0002:  Common error.");
      case 3:
         return("Error 0003:  Invalid trade parameters.");
      case 4:
         return("Error 0004:  Trade server is busy.");
      case 5:
         return("Error 0005:  Old version of the client terminal.");
      case 6:
         return("Error 0006:  No connection with trade server.");
      case 7:
         return("Error 0007:  Not enough rights.");
      case 8:
         return("Error 0008:  Too frequent requests.");
      case 9:
         return("Error 0009:  Malfunctional trade operation.");
      case 64:
         return("Error 0064:  Account disabled.");
      case 65:
         return("Error 0065:  Invalid account.");
      case 128:
         return("Error 0128:  Trade timeout.");
      case 129:
         return("Error 0129:  Invalid price.");
      case 130:
         return("Error 0130:  Invalid stops.");
      case 131:
         return("Error 0131:  Invalid trade volume.");
      case 132:
         return("Error 0132:  Market is closed.");
      case 133:
         return("Error 0133:  Trade is disabled.");
      case 134:
         return("Error 0134:  Not enough money.");
      case 135:
         return("Error 0135:  Price changed.");
      case 136:
         return("Error 0136:  Off quotes.");
      case 137:
         return("Error 0137:  Broker is busy.");
      case 138:
         return("Error 0138:  Requote.");
      case 139:
         return("Error 0139:  Order is locked.");
      case 140:
         return("Error 0140:  Long positions only allowed.");
      case 141:
         return("Error 0141:  Too many requests.");
      case 145:
         return("Error 0145:  Modification denied because order too close to market.");
      case 146:
         return("Error 0146:  Trade context is busy.");
      case 147:
         return("Error 0147:  Expirations are denied by broker.");
      case 148:
         return("Error 0148:  The amount of open and pending orders has reached the limit set by the broker.");
      case 149:
         return("Error 0149:  An attempt to open a position opposite to the existing one when hedging is disabled.");
      case 150:
         return("Error 0150:  An attempt to close a position contravening the FIFO rule.");
      case 4000:
         return("Error 4000:  No error.");
      case 4001:
         return("Error 4001:  Wrong function pointer.");
      case 4002:
         return("Error 4002:  Array index is out of range.");
      case 4003:
         return("Error 4003:  No memory for function call stack.");
      case 4004:
         return("Error 4004:  Recursive stack overflow.");
      case 4005:
         return("Error 4005:  Not enough stack for parameter.");
      case 4006:
         return("Error 4006:  No memory for parameter string.");
      case 4007:
         return("Error 4007:  No memory for temp string.");
      case 4008:
         return("Error 4008:  Not initialized string.");
      case 4009:
         return("Error 4009:  Not initialized string in array.");
      case 4010:
         return("Error 4010:  No memory for array string.");
      case 4011:
         return("Error 4011:  Too long string.");
      case 4012:
         return("Error 4012:  Remainder from zero divide.");
      case 4013:
         return("Error 4013:  Zero divide.");
      case 4014:
         return("Error 4014:  Unknown command.");
      case 4015:
         return("Error 4015:  Wrong jump (never generated error).");
      case 4016:
         return("Error 4016:  Not initialized array.");
      case 4017:
         return("Error 4017:  DLL calls are not allowed.");
      case 4018:
         return("Error 4018:  Cannot load library.");
      case 4019:
         return("Error 4019:  Cannot call function.");
      case 4020:
         return("Error 4020:  Expert function calls are not allowed.");
      case 4021:
         return("Error 4021:  Not enough memory for temp string returned from function.");
      case 4022:
         return("Error 4022:  System is busy (never generated error).");
      case 4050:
         return("Error 4050:  Invalid function parameters count.");
      case 4051:
         return("Error 4051:  Invalid function parameter value.");
      case 4052:
         return("Error 4052:  String function internal error.");
      case 4053:
         return("Error 4053:  Some array error.");
      case 4054:
         return("Error 4054:  Incorrect series array using.");
      case 4055:
         return("Error 4055:  Custom indicator error.");
      case 4056:
         return("Error 4056:  Arrays are incompatible.");
      case 4057:
         return("Error 4057:  Global variables processing error.");
      case 4058:
         return("Error 4058:  Global variable not found.");
      case 4059:
         return("Error 4059:  Function is not allowed in testing mode.");
      case 4060:
         return("Error 4060:  Function is not confirmed.");
      case 4061:
         return("Error 4061:  Send mail error.");
      case 4062:
         return("Error 4062:  String parameter expected.");
      case 4063:
         return("Error 4063:  Integer parameter expected.");
      case 4064:
         return("Error 4064:  Double parameter expected.");
      case 4065:
         return("Error 4065:  Array as parameter expected.");
      case 4066:
         return("Error 4066:  Requested history data in updating state.");
      case 4067:
         return("Error 4067:  Some error in trading function.");
      case 4099:
         return("Error 4099:  End of file.");
      case 4100:
         return("Error 4100:  Some file error.");
      case 4101:
         return("Error 4101:  Wrong file name.");
      case 4102:
         return("Error 4102:  Too many opened files.");
      case 4103:
         return("Error 4103:  Cannot open file.");
      case 4104:
         return("Error 4104:  Incompatible access to a file.");
      case 4105:
         return("Error 4105:  No order selected.");
      case 4106:
         return("Error 4106:  Unknown symbol.");
      case 4107:
         return("Error 4107:  Invalid price.");
      case 4108:
         return("Error 4108:  Invalid ticket.");
      case 4109:
         return("Error 4109:  Trade is not allowed. Enable checkbox 'Allow live trading' in the expert properties.");
      case 4110:
         return("Error 4110:  Longs are not allowed. Check the expert properties.");
      case 4111:
         return("Error 4111:  Shorts are not allowed. Check the expert properties.");
      case 4200:
         return("Error 4200:  Object exists already.");
      case 4201:
         return("Error 4201:  Unknown object property.");
      case 4202:
         return("Error 4202:  Object does not exist.");
      case 4203:
         return("Error 4203:  Unknown object type.");
      case 4204:
         return("Error 4204:  No object name.");
      case 4205:
         return("Error 4205:  Object coordinates error.");
      case 4206:
         return("Error 4206:  No specified subwindow.");
      case 4207:
         return("Error 4207:  Some error in object function.");
      //    case 9001:  return("Error 9001:  Cannot close entire order - insufficient volume previously open.");
      //    case 9002:  return("Error 9002:  Incorrect net position.");
      //    case 9003:  return("Error 9003:  Orders not completed correctly - details in log file.");
      default:
         return("Error " + IntegerToString(OrderTicket()) + ": ??? Unknown error.");
     }
   return("n/a");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum StopType {StopType_SL,StopType_TP};
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void AddSpreadCheckFor(string symbol)
  {
   string s_spreadSumGV="Spread Sum "+symbol;
   string s_spreadCountGV="Spread Count "+symbol;

   ResetLastError();
   double sum=GlobalVariableGet(s_spreadSumGV);
   int count=(int)GlobalVariableGet(s_spreadCountGV);

   double pip=GetPip(symbol);
   double spread=NormalizeDouble(MarketInfo(symbol,MODE_SPREAD)*MarketInfo(symbol,MODE_POINT)/pip,2);

   Print(StringConcatenate("Add ",(string)spread," for ",symbol," sum="+(string)sum,", count=",(string)count));

   GlobalVariableSet(s_spreadSumGV,sum+spread);
   GlobalVariableSet(s_spreadCountGV,count+1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int martingaleSells;
int martingaleBuys;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OpenBuy(string pair,double lot,double sl,double tp,string comment,int magic,bool fifo=false,double martingaleMult=0,int maxMultiplications=0)
  {
   int ticket=0,tries=0;
   static datetime last=0;
   static int ordersThisBar=0;
   if(last!=Time[0] || ordersThisBar<_MaxTraderPerBar || _MaxTraderPerBar==0)
     {
      if(!IsTesting())
         ChartBringToTop();
      double SL=0,TP=0;
      if(sl>0)
         SL=sl;
      if(tp>0)
         TP=tp;

      if(martingaleMult>0)
        {
         int lastT=FindOrder(pair,magic,OP_BUY,-1,NULL,0,0,0,0,false,true);
         if(lastT>0 && _selectedProfit<0 && martingaleBuys<maxMultiplications)
           {
            lot=NormLots(_selectedVolume*martingaleMult);
            martingaleBuys++;
           }
         else
           {
            martingaleBuys=0;
           }
        }

      int tries_main=0;
      while(ticket<=0)
        {
         WaitTradeContext();
         RefreshRates();
         int digits=(int) MarketInfo(pair,MODE_DIGITS);
         double point=MarketInfo(pair,MODE_POINT);
         double price= MarketInfo(pair,MODE_ASK);
         double spread=MarketInfo(pair,MODE_SPREAD);
         double _pip=GetPip(pair);

         if(spread*(point/_pip)>_MaxSpread && _MaxSpread!=0)
           {
            Print("Order not opened because spread ("+(string)(spread*(point/_pip))+") is higher than max allowed spread ("+(string)_MaxSpread);
            return false;
           }

         if(!AccountFreeMarginCheck(Symbol(),OP_BUY,lot)>0)
           {
            Print("Order not opened because there's not enough money to buy "+DoubleToStr(lot,2)+" lots, try to lower the volume, ett="+(string)GetLastError());
            return false;
           }

         color arrowColor=clrLimeGreen;
         if(!_ShowArrows)
            arrowColor=clrNONE;
         if(SL!=0 && SL>MarketInfo(pair,MODE_BID)-MarketInfo(pair,MODE_STOPLEVEL)*point)
            SL=MarketInfo(pair,MODE_BID)-MarketInfo(pair,MODE_STOPLEVEL)*point;
         if(TP!=0 && TP<MarketInfo(pair,MODE_BID)+MarketInfo(pair,MODE_STOPLEVEL)*point)
            TP=MarketInfo(pair,MODE_BID)+MarketInfo(pair,MODE_STOPLEVEL)*point;

         if(_ECN)
           {
            ticket=OrderSend(pair,OP_BUY,lot,price,(int)(_MaxSlippage*_pip/point),0,0,comment,magic,Period(),arrowColor);
           }
         else
           {
            Print(price,NormalizeDouble(SL,digits),NormalizeDouble(TP,digits));
            ticket=OrderSend(pair,OP_BUY,lot,price,(int)(_MaxSlippage*_pip/point),NormalizeDouble(SL,digits),NormalizeDouble(TP,digits),comment,magic,Period(),arrowColor);
           }
         if(ticket<0)
            Print(err_msg(GetLastError()));
         if(ticket>0 && _ECN && (SL>0 || TP>0))
           {
            if(fifo && SL!=0)
               SL=FifoAllowedSLTP(SL,pair,OP_SELL,StopType_SL);
            if(fifo && TP!=0)
               TP=FifoAllowedSLTP(TP,pair,OP_SELL,StopType_TP);
            if(OrderSelect(ticket,SELECT_BY_TICKET))
              {
               if(_StealthSLandTP)
                 {
                  if(SL!=0)
                     SetHorizontalLine(_VS_Prefix+"SL"+IntegerToString(ticket),NormalizeDouble(SL,digits),clrRed,STYLE_DASHDOT,"SL for #"+IntegerToString(ticket),0,0);
                  if(TP!=0)
                     SetHorizontalLine(_VS_Prefix+"TP"+IntegerToString(ticket),NormalizeDouble(TP,digits),clrGreen,STYLE_DASHDOT,"TP for #"+IntegerToString(ticket),0,0);
                 }
               else
                 {
                  while(tries<10)
                    {
                     WaitTradeContext();
                     RefreshRates();
                     if(OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(SL,digits),NormalizeDouble(TP,digits),0))
                        break;
                     tries++;
                    }
                 }
              }
           }
         tries_main++;
         if(tries_main>10)
            break;
        }

      if(ticket>0)
        {
         if(last!=Time[0])
            ordersThisBar=0;
         ordersThisBar++;
         last=Time[0];
         Print("Order Buy was opened");
         //  AddSpreadCheckFor(pair);
        }
     }
   return(ticket);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OpenSell(string pair,double lot,double sl,double tp,string comment,int magic,bool fifo=false,double martingaleMult=0,int maxMultiplications=0)
  {
   int ticket=0;
   static datetime last=0;
   static int ordersThisBar=0;
   if(last!=Time[0] || ordersThisBar<_MaxTraderPerBar || _MaxTraderPerBar==0)
     {
      if(!IsTesting())
         ChartBringToTop();
      int tries=0;
      double SL=0,TP=0;
      if(sl>0)
         SL=sl;
      if(tp>0)
         TP=tp;

      if(martingaleMult>0)
        {
         int lastT=FindOrder(pair,magic,OP_SELL,-1,NULL,0,0,0,0,false,true);
         if(lastT>0 && _selectedProfit<0)
           {
            lot=NormLots(_selectedVolume*martingaleMult);
            martingaleSells++;
           }
         else
           {
            martingaleSells=0;
           }
        }

      int tries_main=0;
      while(ticket<=0)
        {
         WaitTradeContext();
         RefreshRates();
         int digits=(int)MarketInfo(pair,MODE_DIGITS);
         double point=MarketInfo(pair,MODE_POINT);
         double price= MarketInfo(pair,MODE_BID);
         double spread=MarketInfo(pair,MODE_SPREAD);
         double _pip=GetPip(pair);

         if(spread*(point/_pip)>_MaxSpread && _MaxSpread!=0)
           {
            Print("Order not opened because spread ("+(string)(spread*(point/_pip))+") is higher than max allowed spread ("+(string)_MaxSpread);
            return false;
           }
         if(!AccountFreeMarginCheck(Symbol(),OP_SELL,lot)>0)
           {
            Print("Order not opened because there's not enough money, try to lower the volume, ett="+(string)GetLastError());
            return false;
           }

         color arrowColor=clrLimeGreen;
         if(!_ShowArrows)
            arrowColor=clrNONE;
         if(SL!=0 && SL<MarketInfo(pair,MODE_ASK)+MarketInfo(pair,MODE_STOPLEVEL)*point)
            SL=MarketInfo(pair,MODE_ASK)+MarketInfo(pair,MODE_STOPLEVEL)*point;
         if(TP!=0 && TP>MarketInfo(pair,MODE_ASK)-MarketInfo(pair,MODE_STOPLEVEL)*point)
            TP=MarketInfo(pair,MODE_ASK)-MarketInfo(pair,MODE_STOPLEVEL)*point;

         if(_ECN)
           {
            ticket=OrderSend(pair,OP_SELL,lot,price,(int)(_MaxSlippage*_pip/point),0,0,comment,magic,0,arrowColor);
           }
         else
           {
            ticket=OrderSend(pair,OP_SELL,lot,price,(int)(_MaxSlippage*_pip/point),NormalizeDouble(SL,digits),NormalizeDouble(TP,digits),comment,magic,0,arrowColor);
           }
         if(ticket<0)
            Print(err_msg(GetLastError()));
         if(ticket>0 && _ECN && (SL>0 || TP>0))
           {
            if(fifo && SL!=0)
               SL=FifoAllowedSLTP(SL,pair,OP_SELL,StopType_SL);
            if(fifo && TP!=0)
               TP=FifoAllowedSLTP(TP,pair,OP_SELL,StopType_TP);
            if(OrderSelect(ticket,SELECT_BY_TICKET))
              {
               if(_StealthSLandTP)
                 {
                  if(SL!=0)
                     SetHorizontalLine(_VS_Prefix+"SL"+IntegerToString(ticket),NormalizeDouble(SL,digits),clrRed,STYLE_DASHDOT,"SL for #"+IntegerToString(ticket),0,0);
                  if(TP!=0)
                     SetHorizontalLine(_VS_Prefix+"TP"+IntegerToString(ticket),NormalizeDouble(TP,digits),clrGreen,STYLE_DASHDOT,"TP for #"+IntegerToString(ticket),0,0);
                 }
               else
                 {
                  while(tries<10)
                    {
                     WaitTradeContext();
                     RefreshRates();
                     if(OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(SL,digits),NormalizeDouble(TP,digits),0))
                        break;
                     tries++;
                    }
                 }
              }
           }
         tries_main++;
         if(tries_main>10)
            break;
        }

      if(ticket>0)
        {
         if(last!=Time[0])
            ordersThisBar=0;
         ordersThisBar++;
         last=Time[0];
         Print("Order Sell was opened");
         // AddSpreadCheckFor(pair);
        }
     }
   return (ticket);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string OscillatorDirection(double price,double buyLevel,double sellLevel)
  {
   if(price<buyLevel)
      return "Bullish";
   if(price>sellLevel)
      return "Bearish";
   return "n/a";
  }
//+----------------------------------------------------------------------+
//| Send command to the terminal to display the chart above all others.  |
//+----------------------------------------------------------------------+
bool ChartBringToTop(const long chart_ID=0)
  {
//--- reset the error value
   ResetLastError();
//--- show the chart on top of all others
   if(!ChartSetInteger(chart_ID,CHART_BRING_TO_TOP,0,true))
     {
      //--- display the error message in Experts journal
      Print(__FUNCTION__+", Error Code = ",GetLastError());
      return(false);
     }
//--- successful execution
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountOpenOrders(int type1=-1,string symbol=NULL,int magic=-1,int type2=-1,string comment="",double min=0,double max=0,double tp=0)
  {
   int total=0;
   for(int i=OrdersTotal()-1; i >= 0; i--)
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return 0;
        }
      if(OrderSymbol()==symbol || StringLen(symbol)==0)
         if(magic<0 || OrderMagicNumber()==magic)
            if(OrderType()==type1 || OrderType()==type2 || type1<0)
               if(StringLen(comment)==0 || StringFind(OrderComment(),comment)>=0)
                  if(min==0 || NormalizeDouble(OrderOpenPrice(),(int)MarketInfo(symbol,MODE_DIGITS))>=NormalizeDouble(min,(int)MarketInfo(symbol,MODE_DIGITS)))
                     if(max==0 || NormalizeDouble(OrderOpenPrice(),(int)MarketInfo(symbol,MODE_DIGITS))<=NormalizeDouble(max,(int)MarketInfo(symbol,MODE_DIGITS)))
                       {
                        double orderTP=OrderTakeProfit();
                        int digits=(int)MarketInfo(OrderSymbol(),MODE_DIGITS);
                        if(tp!=0 && _StealthSLandTP)
                          {
                           orderTP=ObjectGet(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
                          }
                        if(tp==0 || NormalizeDouble(orderTP,digits)==NormalizeDouble(tp,digits))
                           total++;
                       }
     }
   return (total);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int FindOrder(string symbol=NULL,int magic=-1,int type1=-1,int type2=-1,string comment="",double min=0,double max=0,double tp=0,int inLastXSeconds=0,bool oldest=false,bool lookInHistory=false)
  {
   int ticket=-1;

   int total=0;
   for(int i=OrdersTotal()-1; i >= 0; i--)
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return 0;
        }
      if(OrderSymbol()==symbol || StringLen(symbol)==0)
         if(magic<0 || OrderMagicNumber()==magic)
            if(OrderType()==type1 || OrderType()==type2 || type1<0)
               if(StringLen(comment)==0 || StringFind(OrderComment(),comment)>=0)
                  if(min==0 || NormalizeDouble(OrderOpenPrice(),(int)MarketInfo(symbol,MODE_DIGITS))>=NormalizeDouble(min,(int)MarketInfo(symbol,MODE_DIGITS)))
                     if(max==0 || NormalizeDouble(OrderOpenPrice(),(int)MarketInfo(symbol,MODE_DIGITS))<=NormalizeDouble(max,(int)MarketInfo(symbol,MODE_DIGITS)))
                       {
                        if(inLastXSeconds==0 || TimeCurrent()-OrderOpenTime()<=inLastXSeconds)
                          {
                           double orderTP=OrderTakeProfit();
                           int digits=(int)MarketInfo(OrderSymbol(),MODE_DIGITS);
                           if(tp!=0 && _StealthSLandTP)
                             {
                              orderTP=ObjectGet(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
                             }
                           if(tp==0 || NormalizeDouble(orderTP,digits)==NormalizeDouble(tp,digits))
                             {
                              if(oldest)
                                 ticket=OrderTicket();
                              else
                                 return OrderTicket();
                             }
                          }
                       }
     }

   if(_selectedTicket==0 && lookInHistory)
     {
      for(int i=OrdersHistoryTotal()-1; i>=0; i--)
        {
         ResetLastError();
         if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
           {
            Print("Failed to select history orders in "+__FUNCTION__+", error="+(string)GetLastError());
            return false;
           }
         if(OrderSymbol()==symbol)
            if(magic<0 || OrderMagicNumber()==magic)
               if(OrderType()==type1 || OrderType()==type2 || type1<0)
                  if(StringLen(comment)==0 || StringFind(OrderComment(),comment)>=0)
                     if(min==0 || OrderOpenPrice()>=min)
                        if(max==0 || OrderOpenPrice()<=max)
                          {
                           if(inLastXSeconds==0 || TimeCurrent()-OrderOpenTime()<=inLastXSeconds)
                             {
                              double orderTP=OrderTakeProfit();
                              int digits=(int)MarketInfo(OrderSymbol(),MODE_DIGITS);
                              if(tp!=0 && _StealthSLandTP)
                                {
                                 orderTP=ObjectGet(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
                                }
                              if(tp==0 || NormalizeDouble(orderTP,digits)==NormalizeDouble(tp,digits))
                                {
                                 if(oldest)
                                    ticket=OrderTicket();
                                 else
                                    return OrderTicket();
                                }
                             }
                          }
        }
     }

   return ticket;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DeleteLine(string name)
  {
   name=GetObjectName(name);
   ObjectDelete(0,name);
   ObjectDelete(0,name+"txt");
   ObjectDelete(0,name+"bottomtxt");
   ObjectDelete(0,name+"toptxt");
   ObjectDelete(0,name+"pricetxt");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountVirtualPendings(string symbol=NULL,int magic=-1,int type=-1,double minPrice=0,double maxPrice=0,double tp=0,string comment=NULL)
  {
   int total=0;
   int digits=(int)MarketInfo(symbol,MODE_DIGITS);
   if(digits==0)
      digits=5;
   for(int i=0; i<GlobalVariablesTotal(); i++)
     {
      string data=GlobalVariableName(i);
      if(StringFind(data,"sl=")>=0 || StringFind(data,"tp=")>=0)
        {
         int _magic=(int)StringToInteger(GetInfoBitFromVPOString(data,"#"));
         int _type=GetOrderTypeFromVPOString(data);
         string _symbol=GetSymbolFromVPOString(data);
         double _price=(double)StringToDouble(GetInfoBitFromVPOString(data,"@"));
         double _tp=(double)StringToDouble(GetInfoBitFromVPOString(data,"tp="));
         string _comment=GetInfoBitFromVPOString(data,"c=");

         if((_symbol==symbol || symbol==NULL) && (_magic==magic || magic<0))
            if(_type==type || type<0)
               if(minPrice==0 || NormalizeDouble(_price,digits)>=NormalizeDouble(minPrice,digits))
                  if(maxPrice==0 || NormalizeDouble(_price,digits)<=NormalizeDouble(maxPrice,digits))
                     if(tp==0 || NormalizeDouble(_tp,digits)==NormalizeDouble(tp,digits))
                        if(StringFind(_comment,comment)>=0 || comment==NULL)
                           total++;
        }
     }
   return total;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool _UsePointInsteadOfPip=false;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetPip(string symbol=NULL)
  {

   if(symbol==NULL)
      symbol=Symbol();

#ifdef PipValue
   return  PipValue;
#endif

   double point=MarketInfo(symbol,MODE_POINT);

   if(_UsePointInsteadOfPip)
      return point;

   double _pip=point;
   if(point==0.00001 || point==0.001)
     {
      _pip=point*10;
     }
   else
     {
      _pip=point;
     }
   if(StringFind(symbol,"XAU")==0)
     {
      _pip=1;
     }

   if(StringFind(symbol,"XAG")==0)
     {
      _pip=0.1;
     }

   if(MarketInfo(symbol,MODE_BID)>1000)
     {
      return 1;
     }
   return _pip;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetHorizontalLine(string name,double price,color clr,int style,string label="",int width=1,int selected=0)
  {
   name=GetObjectName(name);
   if(ObjectFind(name)==0)
     {
      ObjectSet(name,OBJPROP_PRICE1,price);
      ObjectSet(name,OBJPROP_PRICE2,price);
      ObjectSet(name,OBJPROP_TIME1,iTime(NULL,0,Bars));
      ObjectSet(name,OBJPROP_TIME2,iTime(NULL,0,0));
     }
   else
     {
      ObjectCreate(name,OBJ_HLINE,0,iTime(NULL,0,Bars),price,iTime(NULL,0,0),price);
      ObjectSet(name,OBJPROP_RAY,false);
     }

   ObjectSet(name,OBJPROP_COLOR,clr);
   ObjectSet(name,OBJPROP_STYLE,style);
   ObjectSet(name,OBJPROP_WIDTH,width);
   ObjectSet(name,OBJPROP_SELECTED,selected);
   ObjectSet(name,OBJPROP_STYLE,style);

   if(StringLen(label)!=0 && (IsVisualMode() || !IsTesting()))
     {
      name=name+"pricetxt";
      datetime time=GetTimeForLabel(name,price);
      if(ObjectFind(name)!=0)
        {
         ObjectCreate(name,OBJ_TEXT,0,time,price);
        }
      else
        {
         ObjectSet(name,OBJPROP_PRICE1,price);
         ObjectSet(name,OBJPROP_TIME1,time);
        }
      ObjectSetText(name,label,8);
      ObjectSet(name,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime GetTimeForLabel(string labelName,double price)
  {
   int firstIdx=(int)ChartGetInteger(0,CHART_FIRST_VISIBLE_BAR);
   int candles=(int)ChartGetInteger(0,CHART_WIDTH_IN_BARS);
   datetime time=Time[MathMax(0,firstIdx-candles+8)];

   for(int i=0; i<ObjectsTotal(0,0,OBJ_TEXT); i++)
     {
      string name=ObjectName(0,i,0,OBJ_TEXT);
      if(name==labelName)
         break;
      if(price==ObjectGetDouble(0,name,OBJPROP_PRICE))
        {
         time+=(int)(Period()*60*StringLen(ObjectGetString(0,name,OBJPROP_TEXT))/4.5 *(MathPow(2,5-ChartGetInteger(0,CHART_SCALE))));
        }
     }

   return time;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetVerticalLine(string name,datetime time,color clr,int style,int width=1,string label=NULL,bool labelDown=true)
  {
   name=GetObjectName(name);
   if(ObjectFind(name)==0)
     {
      ObjectSet(name,OBJPROP_TIME1,time);
     }
   else
     {
      ObjectCreate(0,name,OBJ_VLINE,0,time,0);
      ObjectSet(name,OBJPROP_RAY,false);
     }

   ObjectSet(name,OBJPROP_COLOR,clr);
   ObjectSet(name,OBJPROP_STYLE,style);
   ObjectSet(name,OBJPROP_WIDTH,width);

   if(StringLen(label)!=0)
     {
      string labelName=name+"bottomtxt";

      int lowestIdx=iLowest(Symbol(),Period(),MODE_LOW,(int)ChartGetInteger(0,CHART_VISIBLE_BARS),0);
      double labelPrice=Low[lowestIdx];
      if(!labelDown)
        {
         int highestIdx=iHighest(Symbol(),Period(),MODE_HIGH,(int)ChartGetInteger(0,CHART_VISIBLE_BARS),0);
         labelPrice=High[highestIdx];
         labelName=name+"toptxt";
        }

      if(ObjectFind(labelName)!=0)
        {
         ObjectCreate(labelName,OBJ_TEXT,0,time,labelPrice);
        }
      else
        {
         ObjectSet(labelName,OBJPROP_PRICE1,labelPrice);
         ObjectSet(labelName,OBJPROP_TIME1,time);
        }
      ObjectSetText(labelName," "+label,8);
      ObjectSet(labelName,OBJPROP_COLOR,clr);
      ObjectSetInteger(0,labelName,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void UpdateLabels()
  {
   int total=ObjectsTotal(0,-1,OBJ_TEXT);
   int to=MathMax(0,total-20);
   for(int i=total-1; i>=to; i--)
     {
      string name=ObjectName(0,i,-1,OBJ_TEXT);
      if(StringFind(name,"bottomtxt")>=0)
        {

         int lowestIdx=iLowest(Symbol(),Period(),MODE_LOW,(int)ChartGetInteger(0,CHART_VISIBLE_BARS),0);
         double labelPrice=Low[lowestIdx];
         ObjectSetDouble(0,name,OBJPROP_PRICE,labelPrice);
        }
      if(StringFind(name,"toptxt")>=0)
        {
         int highestIdx=iHighest(Symbol(),Period(),MODE_HIGH,(int)ChartGetInteger(0,CHART_VISIBLE_BARS),0);
         double  labelPrice=High[highestIdx];
         ObjectSetDouble(0,name,OBJPROP_PRICE,labelPrice);
        }
      if(StringFind(name,"pricetxt")>=0)
        {
         double  labelPrice=ObjectGetDouble(0,StringSubstr(name,0,StringLen(name)-8),OBJPROP_PRICE1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,labelPrice);
         ObjectSetInteger(0,name,OBJPROP_TIME1,GetTimeForLabel(name,labelPrice));
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetRectangle(string name,datetime time1,datetime time2,double price1,double price2,color clr)
  {
   if(ObjectFind(name)==0)
     {
      ObjectSet(name,OBJPROP_TIME1,time1);
      ObjectSet(name,OBJPROP_TIME2,time2);
      ObjectSet(name,OBJPROP_PRICE1,price1);
      ObjectSet(name,OBJPROP_PRICE2,price2);
     }
   else
     {
      ObjectCreate(0,name,OBJ_RECTANGLE,0,time1,price1,time2,price2);
     }

   ObjectSet(name,OBJPROP_COLOR,clr);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime lastOpenTime[8];
double lastOpenPrice[8];
double lastOpenTP[8];
double lastOpenSL[8];
double lastOpenVolume[8];
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int SetPendingOrder(string symbol,double level,int type,double SLpips,double TPpips,double volume,int magic,string comment,int expiration=0,bool newOrUpdate=false,bool usePoints=false,bool usePriceNotDistance=false)
  {

   double point=MarketInfo(symbol,MODE_POINT);
   double spread=MarketInfo(symbol,MODE_SPREAD);
   double pip=GetPip(symbol);

   if(point==0)
     {
      Print("point=0 for "+symbol+"! - force exit");
      return 0;
     }

   if(spread*(point/pip)>_MaxSpread && _MaxSpread!=0)
     {
      Print("Spread too big, didn't place pending");
      return -1;
     }

   if(usePoints)
      pip=point;

   RefreshRates();

   int digits=(int)MarketInfo(symbol,MODE_DIGITS);
   double minDistance=MarketInfo(symbol,MODE_STOPLEVEL)*point;
   double ask = MarketInfo(symbol,MODE_ASK);
   double bid = MarketInfo(symbol,MODE_BID);
   double sl = 0;
   double tp = 0;
   if(type==OP_SELLLIMIT)
     {
      if(level-bid<minDistance)
        {
         level=bid+minDistance;
        }
      if(SLpips!=0)
        {
         if(SLpips*pip<minDistance)
           {
            sl=level+minDistance;
           }
         else
           {
            sl=level+SLpips*pip;
           }
        }
      if(TPpips!=0)
        {
         if(TPpips*pip<minDistance)
           {
            tp=level-minDistance;
           }
         else
           {
            tp=level-TPpips*pip;
           }
        }
     }
   else
      if(type==OP_BUYSTOP)
        {
         if(level-ask<minDistance)
           {
            Print("adjust buy stop entry level (ask+minDistance), min distance="+(string)MarketInfo(symbol,MODE_STOPLEVEL));
            level=ask+minDistance;
           }
         if(SLpips!=0)
           {
            if(SLpips*pip<minDistance)
              {
               Print("adjust buy stop SL (ask+minDistance)");
               sl=level-minDistance;
              }
            else
              {
               sl=level-SLpips*pip;
              }
           }
         if(TPpips!=0)
           {
            if(TPpips*pip<minDistance)
              {
               Print("adjust buy stop TP (ask+minDistance)");
               tp=level+minDistance;
              }
            else
              {
               tp=level+TPpips*pip;
              }
           }
        }
      else
         if(type==OP_SELLSTOP)
           {
            if(bid-level<minDistance)
              {
               level=bid-minDistance;
              }
            if(SLpips!=0)
              {
               if(SLpips*pip<minDistance)
                 {
                  sl=level+minDistance;
                 }
               else
                 {
                  sl=level+SLpips*pip;
                 }
              }
            if(TPpips!=0)
              {
               if(TPpips*pip<minDistance)
                 {
                  tp=level-minDistance;
                 }
               else
                 {
                  tp=level-TPpips*pip;
                 }
              }
           }
         else
            if(type==OP_BUYLIMIT)
              {
               if(ask-level<minDistance)
                 {
                  level=ask-minDistance;
                 }
               if(SLpips!=0)
                 {
                  if(SLpips*pip<minDistance)
                    {
                     sl=level-minDistance;
                    }
                  else
                    {
                     sl=level-SLpips*pip;
                    }
                 }
               if(TPpips!=0)
                 {
                  if(TPpips*pip<minDistance)
                    {
                     tp=level+minDistance;
                    }
                  else
                    {
                     tp=level+TPpips*pip;
                    }
                 }
              }

   level=NormalizeDouble(level,digits);
   tp=NormalizeDouble(tp,digits);
   sl=NormalizeDouble(sl,digits);


   if(usePriceNotDistance)
     {
      sl=SLpips;
      tp=TPpips;
     }

   string vpo=symbol+",!"+(string)((int)type)+",#"+(string)magic+",@"+DoubleToString(level,digits)+",*"+DoubleToString(volume,2)+",sl="+(string)sl+",tp="+(string)tp+(string)tp+",c="+comment;

   bool newOrder=true;
   if(newOrUpdate)
     {
      if(_StealthPendingOrders)
        {
         for(int i=0; i<GlobalVariablesTotal(); i++)
           {
            string data=GlobalVariableName(i);
            if(StringFind(data,"sl=")>=0 || StringFind(data,"tp=")>=0)
              {
               int _magic=(int)StringToInteger(GetInfoBitFromVPOString(data,"#"));
               double _level=(double)StringToDouble(GetInfoBitFromVPOString(data,"@"));
               double _sl=(double)StringToDouble(GetInfoBitFromVPOString(data,"sl="));
               double _tp=(double)StringToDouble(GetInfoBitFromVPOString(data,"tp="));
               int _type=GetOrderTypeFromVPOString(data);
               string _symbol=GetSymbolFromVPOString(data);

               if(_type==type && _symbol==symbol && _magic==magic)
                 {
                  if(NormalizeDouble(sl,digits)!=_sl || NormalizeDouble(tp,digits)!=_tp || NormalizeDouble(level,digits)!=_level)
                    {

                     DeleteVirtualPending(data);
                     GlobalVariableSet(vpo,1);
                    }
                  newOrder=false;
                 }
              }
           }
        }
      else
        {
         for(int i=OrdersTotal()-1; i>=0; i--)
           {
            ResetLastError();
            if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
              {
               Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
               return -1;
              }
            if(OrderSymbol()==symbol && OrderMagicNumber()==magic)
              {
               if(OrderType()==type)
                 {
                  if(NormalizeDouble(sl,digits)!=NormalizeDouble(OrderStopLoss(),digits)
                     || NormalizeDouble(tp,digits)!=NormalizeDouble(OrderTakeProfit(),digits)
                     || NormalizeDouble(level,digits)!=NormalizeDouble(OrderOpenPrice(),digits))
                    {
                     ResetLastError();
                     if(!OrderModify(OrderTicket(),level,sl,tp,expiration))
                       {
                        Print("Failed to modify order in "+__FUNCTION__+", error="+err_msg(GetLastError()));
                        return OrderTicket();
                       }
                    }
                  newOrder=false;
                 }
              }
           }
        }
     }

   int ticket=0;
   if(newOrder)
     {

      lastOpenPrice[type]=level;;
      lastOpenTime[type]=Time[0];
      lastOpenVolume[type]=volume;

      color clr=clrGreen;
      if(type==OP_SELLSTOP || type==OP_SELLLIMIT)
         clr=clrRed;
      if(!_ShowArrows)
         clr=clrNONE;
      if(_StealthPendingOrders)
        {
         Print("setting virtual pending order ("+symbol+", "+TypeName(type)+", #"+(string)magic+", @"+(string)level+", *"+DoubleToString(volume,2)+", sl="+(string)sl+", tp="+(string)tp+")");
         int count=(int)GlobalVariableGet(vpo);
         Print("sl="+DoubleToStr(sl,5)+" tp="+DoubleToStr(tp,5));
         GlobalVariableSet(vpo,count+1);
         Print("count="+(string)(count+1));
        }
      else
        {
         ResetLastError();
         double _sl=sl;
         double _tp=tp;
         if(_StealthSLandTP)
           {
            _sl=0;
            _tp=0;
           }
         ticket=OrderSend(symbol,type,volume,level,(int)(_MaxSlippage*pip/point),_sl,_tp,comment,magic,expiration,clr);

         if(_StealthSLandTP)
           {
            if(sl!=0)
               SetHorizontalLine(_VS_Prefix+"SL"+IntegerToString(ticket),NormalizeDouble(sl,digits),clrRed,2,"SL for #"+IntegerToString(ticket));
            if(tp!=0)
               SetHorizontalLine(_VS_Prefix+"TP"+IntegerToString(ticket),NormalizeDouble(tp,digits),clrGreen,2,"TP for #"+IntegerToString(ticket));
           }

         if(ticket<=0)
           {
            Print("Failed to place pending order in "+__FUNCTION__+", error="+err_msg(GetLastError()));
           }
        }
     }

   return ticket;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string TypeName(int type)
  {
   switch(type)
     {
      case OP_BUYSTOP:
         return "Buy Stop";
      case OP_BUYLIMIT:
         return "Buy Limit";
      case OP_SELLSTOP:
         return "Sell Stop";
      case OP_SELLLIMIT:
         return "Sell Limit";
     }
   return "";
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double FirstOkOrDefault(double a,double b)
  {
   if(ok(a))
      return a;
   if(ok(b))
      return b;
   return 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void TrailSL(string symbol,int magic,double trailStopPips,double trailStartAt,double trailingStep=0,double stopTrailingAt=0,double trailRatio=0,double trailStartAtRatio=0,double buyTS=0,double sellTS=0,int candlesOffset=0,double pipsOffset=0,bool fifo=false)
  {
   double bid=MarketInfo(symbol,MODE_BID);
   double ask=MarketInfo(symbol,MODE_ASK);
   int digits=(int)MarketInfo(symbol,MODE_DIGITS);
   double pip=GetPip(symbol);
   trailingStep*=GetPip();
   if(trailingStep==0)
      trailingStep=GetPip();

   if(trailStopPips>0 || buyTS>0 || sellTS>0)
     {
      for(int i=OrdersTotal()-1; i>=0; i--)
        {
         if(OrderSelect(i,SELECT_BY_POS))
           {
            int startBar=iBarShift(OrderSymbol(),Period(),OrderOpenTime());
            if(startBar<candlesOffset)
               continue;

            double sl_buy=NormalizeDouble(bid-trailStopPips*pip,digits);
            double sl_sell=NormalizeDouble(ask+trailStopPips*pip,digits);

            if(trailRatio>0)
              {
               sl_buy=OrderOpenPrice()+(bid-OrderOpenPrice())*trailRatio;
               sl_sell=OrderOpenPrice()-(OrderOpenPrice()-ask)*trailRatio;
              }

            if(buyTS>0)
               sl_buy=buyTS;
            if(sellTS>0)
               sl_sell=sellTS;

            double min_sl_buy=NormalizeDouble(bid-pipsOffset*pip,digits);
            double min_sl_sell=NormalizeDouble(ask+pipsOffset*pip,digits);

            sl_buy=MathMin(min_sl_buy,sl_buy);
            sl_sell=MathMax(min_sl_sell,sl_sell);

            if(fifo)
               sl_buy=FifoAllowedSLTP(sl_buy,OrderSymbol(),OrderType(),StopType_SL);
            int sel=OrderSelect(i,SELECT_BY_POS);
            if(fifo)
               sl_sell=FifoAllowedSLTP(sl_sell,OrderSymbol(),OrderType(),StopType_SL);
            sel=OrderSelect(i,SELECT_BY_POS);

            double currentSL=0;
            if(OrderSymbol()==symbol && OrderMagicNumber()==magic)
              {
               // GET CURRENT SL
               if(_StealthSLandTP)
                 {
                  if(ObjectFind(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()))==0)
                    {
                     currentSL=ObjectGet(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
                    }
                 }
               else
                 {
                  currentSL=OrderStopLoss();
                 }
               double currentProfitRatio=0;
               if(OrderOpenPrice()-currentSL!=0 && currentSL!=0)
                  currentProfitRatio=(bid-OrderOpenPrice())/(OrderOpenPrice()-currentSL);

               if(OrderType()==OP_SELL)
                  if(currentSL-OrderOpenPrice()>0 && currentSL!=0)
                     currentProfitRatio=(OrderOpenPrice()-ask)/(currentSL-OrderOpenPrice());

               if(trailStartAtRatio!=0 && currentProfitRatio<trailStartAtRatio)
                  continue;

               if(OrderType()==OP_BUY && bid-OrderOpenPrice()>=trailStartAt*pip && (stopTrailingAt==0 || OrderStopLoss()-OrderOpenPrice()<=stopTrailingAt*pip))
                 {
                  if(currentSL<Point || (sl_buy>=currentSL+trailingStep))
                    {
                     if(_StealthSLandTP)
                       {
                        SetHorizontalLine(_VS_Prefix+"SL"+IntegerToString(OrderTicket()),sl_buy,clrRed,2,"SL for #"+IntegerToString(OrderTicket()));
                       }
                     else
                       {
                        Print("Trail SL for BUY");
                        if(!OrderModify(OrderTicket(),OrderOpenPrice(),sl_buy,OrderTakeProfit(),0))
                          {
                           Print(err_msg(GetLastError()));
                          }
                       }
                    }
                 }
               else
                  if(OrderType()==OP_SELL && OrderOpenPrice()-ask>=trailStartAt*pip && (stopTrailingAt==0 || OrderOpenPrice()-OrderStopLoss()<=stopTrailingAt*pip))
                    {
                     if(currentSL<Point || (sl_sell<=currentSL-trailingStep))
                       {
                        if(_StealthSLandTP)
                          {
                           SetHorizontalLine(_VS_Prefix+"SL"+IntegerToString(OrderTicket()),sl_sell,clrRed,2,"SL for #"+IntegerToString(OrderTicket()));
                          }
                        else
                          {
                           Print("Trail SL for SELL");
                           if(!OrderModify(OrderTicket(),OrderOpenPrice(),sl_sell,OrderTakeProfit(),0))
                             {
                              Print(err_msg(GetLastError()));
                             }
                          }
                       }
                    }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double FifoAllowedSLTP(double price,string symbol,int type,StopType stopType)
  {
   double lowestSL=0;
   double highestSL=0;
   double lowestTP=0;
   double highestTP=0;

   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      double orderSL=OrderStopLoss();
      double orderTP=OrderTakeProfit();

      if(_StealthSLandTP)
        {
         if(ObjectFind(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()))==0)
           {
            orderSL=ObjectGet(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
           }
         if(ObjectFind(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket()))==0)
           {
            orderTP=ObjectGet(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
           }
        }

      if(OrderSymbol()==symbol && OrderType()==type)
        {
         if(lowestSL==0 || orderSL<lowestSL)
           {
            lowestSL=orderSL;
           }
         if(highestSL==0 || orderSL>highestSL)
           {
            highestSL=orderSL;
           }
         if(lowestTP==0 || orderTP<lowestTP)
           {
            lowestTP=orderTP;
           }
         if(highestTP==0 || orderTP>highestTP)
           {
            highestTP=orderTP;
           }
        }
     }

   double bestSLTP=price;

   if(stopType==StopType_SL)
     {
      if(type==OP_BUY)
        {
         if(highestSL!=0)
            bestSLTP=MathMin(highestSL,price);
        }

      if(type==OP_SELL)
        {
         if(lowestSL!=0)
            bestSLTP=MathMax(lowestSL,price);
        }
     }
   if(stopType==StopType_TP)
     {
      if(type==OP_BUY)
        {
         if(lowestTP!=0)
            bestSLTP=MathMax(lowestTP,price);
        }

      if(type==OP_SELL)
        {
         if(highestTP!=0)
            bestSLTP=MathMin(highestTP,price);
        }

      if(type==OP_SELL && stopType==StopType_TP)
         Comment(highestTP);
     }

   return bestSLTP;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void JumpTrailSL(string symbol,int magic,double moveJumpingStop,double jumpingStopPips,double jumpingStartAt)
  {
   double bid=MarketInfo(symbol,MODE_BID);
   double ask=MarketInfo(symbol,MODE_ASK);
   int digits=(int)MarketInfo(symbol,MODE_DIGITS);
   double pip=GetPip(symbol);
   if(jumpingStopPips>0)
     {
      for(int i=OrdersTotal()-1; i>=0; i--)
        {
         if(OrderSelect(i,SELECT_BY_POS))
           {
            double currentSL=0;
            if(OrderSymbol()==symbol && OrderMagicNumber()==magic)
              {
               if(_StealthSLandTP)
                 {
                  if(ObjectFind(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()))==0)
                    {
                     currentSL=ObjectGet(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
                    }
                 }
               else
                 {
                  currentSL=OrderStopLoss();
                 }

               double currentProfitDistance=bid-OrderOpenPrice();
               if(OrderType()==OP_SELL)
                  currentProfitDistance=OrderOpenPrice()-ask;

               int jumpingStopIncrements=(int)MathFloor(currentProfitDistance/(moveJumpingStop*pip));
               double jumpingProfitDistance=jumpingStopIncrements*moveJumpingStop*pip;

               double sl_buy=0;
               double sl_sell=0;
               if(jumpingStopIncrements>0)
                 {
                  sl_buy=NormalizeDouble(OrderOpenPrice()+jumpingProfitDistance-jumpingStopPips*pip,digits);
                  sl_sell=NormalizeDouble(OrderOpenPrice()-jumpingProfitDistance+jumpingStopPips*pip,digits);
                 }

               sl_buy=MathMin(Bid-MinDistance(),sl_buy);
               sl_sell=MathMax(Ask+MinDistance(),sl_sell);

               if(OrderType()==OP_BUY && bid-OrderOpenPrice()>=jumpingStartAt*pip)
                 {
                  if(sl_buy>currentSL && currentSL!=0 && sl_buy>0)
                    {
                     if(_StealthSLandTP)
                       {
                        SetHorizontalLine(_VS_Prefix+"SL"+IntegerToString(OrderTicket()),NormalizeDouble(sl_buy,Digits),clrRed,2,"SL for #"+IntegerToString(OrderTicket()));
                       }
                     else
                       {
                        if(!OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(sl_buy,Digits),OrderTakeProfit(),OrderExpiration()))
                          {
                           Print(err_msg(GetLastError()));
                          }
                       }
                    }
                 }
               else
                  if(OrderType()==OP_SELL && OrderOpenPrice()-ask>=jumpingStartAt*pip)
                    {
                     if(sl_sell<currentSL && currentSL!=0 && sl_sell>0)
                       {
                        if(_StealthSLandTP)
                          {
                           SetHorizontalLine(_VS_Prefix+"SL"+IntegerToString(OrderTicket()),NormalizeDouble(sl_sell,Digits),clrRed,2,"SL for #"+IntegerToString(OrderTicket()));
                          }
                        else
                          {
                           if(!OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(sl_sell,Digits),OrderTakeProfit(),OrderExpiration()))
                             {
                              Print(err_msg(GetLastError()));
                             }
                          }
                       }
                    }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string GetInfoBitFromVPOString(string data,string key)
  {
   string bits[];
   int bitsCount=StringSplit(data,',',bits);
   for(int i=0; i<bitsCount; i++)
     {
      bits[i]=StringTrimLeft(StringTrimRight(bits[i]));
      int comma=StringFind(bits[i],",",0);
      if(comma>=0)
        {
         bits[i]=StringSubstr(bits[i],0,comma)+StringSubstr(bits[i],comma+1);
        }
      if(StringFind(bits[i],key)==0)
         return StringSubstr(bits[i],StringLen(key));
     }

   return "";
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetOrderTypeFromVPOString(string data)
  {
   string s_type=GetInfoBitFromVPOString(data,"!");

   if(StringLen(s_type)>0)
     {
      return (int)StringToInteger(s_type);
     }
   return -1;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string GetSymbolFromVPOString(string data)
  {
   string bits[];
   int bitsCount=StringSplit(data,',',bits);

   return bits[0];
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CheckEquityMM(string symbol="",int magic=-1,double maxProfit=0,double maxLoss=0,double maxProfitPercent=0,double maxLossPercent=0,bool usePips=false)
  {
   bool closeAll=false;

   double currentProfit=CurrentProfit(symbol,magic,-1,usePips);
   double currentProfitPercent=currentProfit/AccountBalance()*100;

   string scope="account";
   if(magic>=0)
      scope+=" with magic #="+(string)magic;
   if(StringLen(symbol)>0)
      scope=symbol;

   if(maxProfit!=0 && currentProfit>0 && currentProfit>maxProfit)
     {
      TriggerAlerts("Max Equity Profit exceeded ("+(string) currentProfit+") - close all orders on "+scope);
      closeAll=true;
     }
   if(maxLoss!=0 && currentProfit<0 && MathAbs(currentProfit)>maxLoss)
     {
      TriggerAlerts("Max Equity Loss exceeded ("+(string) currentProfit+") - close all orders on "+scope);
      closeAll=true;
     }
   if(maxProfitPercent!=0 && currentProfitPercent>0 && currentProfitPercent>maxProfitPercent)
     {
      TriggerAlerts("Max Equity Profit Percentage exceeded ("+(string) currentProfitPercent+") - close all orders on "+scope);
      closeAll=true;
     }
   if(maxLossPercent!=0 && currentProfitPercent<0 && MathAbs(currentProfitPercent)>maxLossPercent)
     {
      TriggerAlerts("Max Equity Loss Percentage exceeded ("+(string) currentProfitPercent+") - close all orders on "+scope);
      closeAll=true;
     }

   if(closeAll)
     {
      for(int i=0; i<=OrdersTotal()-1; i++)
        {
         ResetLastError();
         if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
           {
            Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
            return true;
           }

         if(OrderSymbol()==symbol || StringLen(symbol)==0)
           {
            if(OrderMagicNumber()==magic || magic==0)
              {
               double pip=GetPip(OrderSymbol());
               double price=MarketInfo(OrderSymbol(),MODE_BID);
               if(OrderType()==OP_BUY)
                  price=MarketInfo(OrderSymbol(),MODE_BID);
               if(OrderType()==OP_SELL)
                  price=MarketInfo(OrderSymbol(),MODE_ASK);
               if(price!=0)
                 {
                  if(OrderType()!=OP_BUY && OrderType()!=OP_SELL)
                     OrderDelete(OrderTicket());

                  if(!OrderClose(OrderTicket(),OrderLots(),price,(int)(_MaxSlippage*pip/Point())))
                    {
                     Print("Failed to close order, try deleting it, in "+__FUNCTION__+", error="+(string)GetLastError());
                     return true;
                    }
                  else
                    {
                     i--;
                    }
                 }
              }
           }
        }
     }

   return closeAll;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CheckPipsMM(string symbol="",int magic=-1,double maxProfit=0,double maxLoss=0,double maxProfitPercent=0,double maxLossPercent=0)
  {
   bool closeAll=false;

   double currentProfit=CurrentProfit(symbol,magic,-1,true);

   string scope="account";
   if(magic>=0)
      scope+=" with magic #="+(string)magic;
   if(StringLen(symbol)>0)
      scope=symbol;

   if(maxProfit!=0 && currentProfit>0 && currentProfit>maxProfit)
     {
      TriggerAlerts("Max Profit Pips exceeded ("+(string) currentProfit+") - close all orders on "+scope);
      closeAll=true;
     }
   if(maxLoss!=0 && currentProfit<0 && MathAbs(currentProfit)>maxLoss)
     {
      TriggerAlerts("Max Loss Pips exceeded ("+(string) currentProfit+") - close all orders on "+scope);
      closeAll=true;
     }
   if(closeAll)
     {
      for(int i=OrdersTotal()-1; i>=0; i--)
        {
         ResetLastError();
         if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
           {
            Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
            return true;
           }

         if(OrderSymbol()==symbol || StringLen(symbol)==0)
           {
            if(OrderMagicNumber()==magic || StringLen(symbol)==0)
              {
               double pip=GetPip(OrderSymbol());
               double price=0;
               if(OrderType()==OP_BUY)
                  price=MarketInfo(OrderSymbol(),MODE_BID);
               if(OrderType()==OP_SELL)
                  price=MarketInfo(OrderSymbol(),MODE_ASK);
               if(price!=0)
                 {
                  if(!OrderClose(OrderTicket(),OrderLots(),price,(int)(_MaxSlippage*pip/Point())))
                    {
                     Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
                     return true;
                    }
                 }
              }
           }
        }
     }

   return closeAll;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CurrentProfit(string symbol=NULL,int magic=-1,int type=-1,bool usePips=false,bool weighInLots=false)
  {
   double profit=0;
   double lots=0;
   int total=OrdersTotal();
   for(int b=total-1; b>=0; b--)
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderMagicNumber()==magic || magic<0)
           {
            if(OrderSymbol()==symbol || StringLen(symbol)==0)
              {
               if(OrderType()==type || type==-1)
                 {
                  if(usePips)
                    {
                     double multiplier=1;
                     if(weighInLots)
                        multiplier=OrderLots();
                     if(OrderType()==OP_BUY)
                       {
                        profit+=(MarketInfo(OrderSymbol(),MODE_BID)-OrderOpenPrice())/GetPip(OrderSymbol())*multiplier;
                        lots+=OrderLots();
                       }
                     if(OrderType()==OP_SELL)
                       {
                        profit+=(OrderOpenPrice()-MarketInfo(OrderSymbol(),MODE_ASK))/GetPip(OrderSymbol())*multiplier;
                        lots+=OrderLots();
                       }
                    }
                  else
                    {
                     profit+=OrderProfit();
                    }
                 }
              }
           }
        }
     }
   return  NormalizeDouble(profit,2);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CurrentLots(string symbol=NULL,int magic=-1,int type=-1)
  {
   double lots=0;
   int total=OrdersTotal();
   for(int b=total-1; b>=0; b--)
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderMagicNumber()==magic || magic<0)
           {
            if(OrderSymbol()==symbol || StringLen(symbol)==0)
              {
               if(OrderType()==type || type==-1)
                 {
                  if(OrderType()==OP_BUY)
                    {
                     lots+=OrderLots();
                    }
                  if(OrderType()==OP_SELL)
                    {
                     lots+=OrderLots();
                    }
                 }
              }
           }
        }
     }
   return  NormalizeDouble(lots,2);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CurrentRisk(string symbol=NULL,int magic=-1,int type=-1)
  {
   double risk=0;
   int total=OrdersTotal();
   for(int b=total-1; b>=0; b--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderMagicNumber()==magic || magic<0)
           {
            if(OrderSymbol()==symbol || StringLen(symbol)==0)
              {
               if(OrderType()==type || type<0)
                 {
                  double sl=OrderStopLoss();
                  if(_StealthSLandTP)
                    {
                     sl=ObjectGet(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
                    }

                  double diff=OrderOpenPrice()-sl;
                  if(OrderType()==OP_SELL)
                     diff=sl-OrderOpenPrice();

                  double pipValue=MarketInfo(symbol,MODE_TICKVALUE);
                  double point=MarketInfo(symbol,MODE_POINT);

                  risk+=OrderLots()*(diff/point)*pipValue;
                 }
              }
           }
        }
     }

   return  NormalizeDouble(risk,2);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CurrentVirtualPendingsRisk(string symbol=NULL,int magic=-1,int type=-1)
  {
   double risk=0;
   for(int i=GlobalVariablesTotal()-1; i>=0; i--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      string data=GlobalVariableName(i);

      if(StringFind(data,"sl=")>=0 || StringFind(data,"tp=")>=0)
        {
         double level=(double)StringToDouble(GetInfoBitFromVPOString(data,"@"));
         string _symbol=GetSymbolFromVPOString(data);
         int _type=GetOrderTypeFromVPOString(data);
         double pip=GetPip(symbol);
         int _magic=(int)StringToInteger(GetInfoBitFromVPOString(data,"#"));
         double sl=(double)StringToDouble(GetInfoBitFromVPOString(data,"sl="));
         double volume=NormalizeDouble(StringToDouble(GetInfoBitFromVPOString(data,"*")),2);
         int count=(int)GlobalVariableGet(data);

         if(_magic==magic || magic<0)
           {
            if(_symbol==symbol || StringLen(symbol)==0)
              {
               if(_type==type || type<0)
                 {
                  double diff=level-sl;
                  if(_type==OP_SELLSTOP || _type==OP_SELLLIMIT)
                     diff=sl-level;

                  double pipValue=MarketInfo(_symbol,MODE_TICKVALUE);
                  double point=MarketInfo(_symbol,MODE_POINT);

                  risk+=volume*(diff/point)*pipValue;
                 }
              }
           }
        }
     }
   return  NormalizeDouble(risk,2);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CurrentProfitPips(string symbol=NULL,int magic=-1,int type=-1,bool usePoints=false)
  {
   double profitPips=0;
   double profitDistance=0;
   int total=OrdersTotal();
   for(int b=total-1; b>=0; b--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderMagicNumber()==magic || magic<0)
           {
            if(OrderSymbol()==symbol || StringLen(symbol)==0)
              {
               if(OrderType()==type || (type==-1 && (OrderType()==OP_BUY || OrderType()==OP_SELL)))
                 {
                  double pip=GetPip(OrderSymbol());
                  if(usePoints)
                     pip=MarketInfo(OrderSymbol(),MODE_POINT);
                  if(OrderType()==OP_BUY)
                    {
                     profitDistance+=(MarketInfo(OrderSymbol(),MODE_BID)-OrderOpenPrice());
                    }
                  if(OrderType()==OP_SELL)
                    {
                     profitDistance+=(OrderOpenPrice()-MarketInfo(OrderSymbol(),MODE_ASK));
                    }

                  profitPips=profitDistance/pip;
                 }
              }
           }
        }
     }
   return  profitPips;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool OnceADayAtTime(int hour,int minute,datetime timeToCompare=0)
  {
   bool thatMoment=false;

   if(timeToCompare==0)
      timeToCompare=TimeCurrent();

   int currHour=TimeHour(timeToCompare);
   int currMinute=TimeMinute(timeToCompare);
   int currSeconds=TimeSeconds(timeToCompare);

   static bool firstTimeToday=true;
   if(currHour>hour ||
      (currHour==hour && currMinute>=minute) ||
      (currHour==hour && (currMinute==minute && currSeconds>=0)))
     {
      if(firstTimeToday)
        {
         thatMoment=true;
        }
      firstTimeToday=false;
     }
   else
     {
      firstTimeToday=true;
     }

   return thatMoment;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime GetNextDateByHourAndMin(int h,int _m,datetime dateToCompare)
  {
   datetime currTime=dateToCompare;
   datetime res=dateToCompare;

   if(TimeHour(currTime)>h || (TimeHour(currTime)==h && TimeMinute(currTime)>=_m))
     {
      res = res+24*60*60;
      res = res+(h-TimeHour(currTime))*60*60+(_m-TimeMinute(currTime))*60;
     }
   else
     {
      res=res+(h-TimeHour(currTime))*60*60+(_m-TimeMinute(currTime))*60;
     }
   return (res);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CheckVirtualStops(string symbol,int magic=-1,bool antiSpikeMode=false,bool useBidOnly=false,bool showTicket=true)
  {
   double bid=MarketInfo(symbol,MODE_BID);
   double ask=MarketInfo(symbol,MODE_ASK);
   if(useBidOnly)
      ask=bid;
   double pip=GetPip(symbol);
   if(IsOptimization())
      return;

   for(int i=0; i<=OrdersTotal()-1; i++)
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return;
        }
      if(OrderSymbol()==symbol)
        {
         if(magic<0 || OrderMagicNumber()==magic)
           {

            // Check if Virtual TP or SL have been hit, and if so, Close the orders
            double sl=ObjectGet(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
            double tp=ObjectGet(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
            datetime  time=Time[3];
            ObjectSet(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket())+"pricetxt",OBJPROP_PRICE1,sl);
            ObjectSet(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket())+"pricetxt",OBJPROP_PRICE1,tp);

            double pipValue=MarketInfo(symbol,MODE_TICKVALUE);
            double point=MarketInfo(symbol,MODE_POINT);

            double profit=OrderLots()*((MathAbs(sl-OrderOpenPrice())/point)*pipValue);
            double loss=OrderLots()*((MathAbs(tp-OrderOpenPrice())/point)*pipValue);
            ObjectSetString(0,_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket())+"pricetxt",OBJPROP_TEXT,"profit=$"+DoubleToString(loss,2));
            ObjectSetString(0,_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket())+"pricetxt",OBJPROP_TEXT,"loss=$"+DoubleToString(profit,2));
            //    ObjectSet(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket())+"pricetxt",OBJPROP_TIME1,time);
            //    ObjectSet(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket())+"pricetxt",OBJPROP_TIME1,time);

            double lastLow=0;
            double lastHigh=0;
            if(antiSpikeMode)
              {
               int startBar=iBarShift(OrderSymbol(),Period(),OrderOpenTime());
               if(startBar==0)
                  continue;

               lastLow=iLow(OrderSymbol(),Period(),1);
               lastHigh=iHigh(OrderSymbol(),Period(),1);
              }

            if(OrderType()==OP_BUY && ((bid<=sl && sl>0 && (lastLow<sl || lastLow==0)) || (bid>=tp && tp>0)))
              {
               ResetLastError();
               if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(symbol,MODE_BID),(int)(50*pip/Point())))
                 {
                  Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
                  return;
                 }
               else
                 {
                  i--;
                 }
               Print(OrderSymbol()+" #"+IntegerToString(OrderTicket())+" closed at "+DoubleToString(MarketInfo(symbol,MODE_BID),Digits));
              }

            if(OrderType()==OP_SELL && ((ask>=sl && sl>0 && (lastHigh>sl || lastHigh==0)) || (ask<=tp && tp>0)))
              {
               ResetLastError();
               if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(symbol,MODE_ASK),(int)(50*pip/Point())))
                 {
                  Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
                  return;
                 }
               else
                 {
                  i--;
                 }
               Print(OrderSymbol()+" #"+IntegerToString(OrderTicket())+" closed at "+DoubleToString(MarketInfo(symbol,MODE_ASK),Digits));
              }
           }
        }
     }

   for(int i=OrdersHistoryTotal()-1; i>=0; i--)
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         Print("Failed to select history orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return;
        }
      if(OrderSymbol()==symbol)
        {
         if(magic<0 || OrderMagicNumber()==magic)
           {
            string ticket=IntegerToString(OrderTicket());

            if(ObjectFind(_ObjPrefix+_VS_Prefix+"SL"+ticket)<0 && ObjectFind(_ObjPrefix+_VS_Prefix+"TP"+ticket)<0)
               break;
            ObjectDelete(0,_ObjPrefix+_VS_Prefix+"SL"+ticket);
            ObjectDelete(0,_ObjPrefix+_VS_Prefix+"TP"+ticket);
            ObjectDelete(0,_ObjPrefix+_VS_Prefix+"SL"+ticket+"pricetxt");
            ObjectDelete(0,_ObjPrefix+_VS_Prefix+"TP"+ticket+"pricetxt");
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MoveToBE(string symbol,int magicNumber,double pips,double lockPips,double minProfitPercentage=0,double minProfitRatio=0,bool fifo=false,int orderType=-1)
  {
   if(pips==0 && minProfitPercentage==0 && minProfitRatio==0)
      return;

   double bid=MarketInfo(symbol,MODE_BID);
   double ask=MarketInfo(symbol,MODE_ASK);
   double pip=GetPip(symbol);
   for(int i=OrdersTotal()-1; i>=0; i--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      double currentSL=0;
      double currentTP=0;
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return;
        }
      if(OrderSymbol()==symbol && OrderMagicNumber()==magicNumber && (orderType==-1 || OrderType()==orderType))
        {
         if(_StealthSLandTP)
           {
            if(ObjectFind(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()))==0)
              {
               currentSL=ObjectGet(_ObjPrefix+_VS_Prefix+"SL"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
               currentTP=ObjectGet(_ObjPrefix+_VS_Prefix+"TP"+IntegerToString(OrderTicket()),OBJPROP_PRICE1);
              }
           }
         else
           {
            currentSL=OrderStopLoss();
            currentTP=OrderTakeProfit();
           }

         double currentProfitPerc=0;
         double currentProfitRatio=0;
         if(currentTP-OrderOpenPrice()!=0 && currentSL!=0 && currentTP!=0)
            currentProfitPerc=((bid-OrderOpenPrice())/(currentTP-OrderOpenPrice()))*100;
         if(OrderOpenPrice()-currentSL!=0 && currentSL!=0)
            currentProfitRatio=(bid-OrderOpenPrice())/(OrderOpenPrice()-currentSL);

         if(OrderType()==OP_SELL)
           {
            currentProfitPerc=0;
            currentProfitRatio=0;
            if(OrderOpenPrice()-currentTP!=0 && currentSL!=0 && currentTP!=0)
               currentProfitPerc=((OrderOpenPrice()-ask)/(OrderOpenPrice()-currentTP))*100;
            if(currentSL-OrderOpenPrice()>0 && currentSL!=0)
               currentProfitRatio=(OrderOpenPrice()-ask)/(currentSL-OrderOpenPrice());
           }

         bool moveToBE=false;

         double be=OrderOpenPrice()+lockPips*pip;
         be=MathMin(Bid-MinDistance(),be);
         if(OrderType()==OP_SELL)
           {
            be=OrderOpenPrice()-lockPips*pip;
            be=MathMax(Ask+MinDistance(),be);
           }

         int digits=(int)MarketInfo(OrderSymbol(),MODE_DIGITS);

         be=NormalizeDouble(be,digits);
         if(fifo)
            be=FifoAllowedSLTP(be,OrderSymbol(),OrderType(),StopType_SL);

         int sel=OrderSelect(i,SELECT_BY_POS);

         if(OrderType()==OP_BUY && bid-OrderOpenPrice()>=pips*pip && currentProfitPerc>=minProfitPercentage && currentProfitRatio>=minProfitRatio)
           {
            if(NormalizeDouble(currentSL,digits)<be || currentSL==0)
              {
               // Only move SL up for BUY
               moveToBE=true;
               Print("Move BUY order to BE");
              }
           }
         if(OrderType()==OP_SELL && OrderOpenPrice()-ask>=pips*pip && currentProfitPerc>=minProfitPercentage && currentProfitRatio>=minProfitRatio)
           {
            if(NormalizeDouble(currentSL,digits)>be || currentSL==0)
              {
               // Only move SL down for SELL
               moveToBE=true;
               Print("Moved SELL order to BE");
              }
           }
         if(moveToBE)
           {
            if(_StealthSLandTP)
              {
               SetHorizontalLine(_VS_Prefix+"SL"+IntegerToString(OrderTicket()),be,clrRed,2);
              }
            else
              {
               ResetLastError();
               if(!OrderModify(OrderTicket(),OrderOpenPrice(),be,OrderTakeProfit(),0))
                 {
                  Print("Failed to modify order in "+__FUNCTION__+", error="+(string)GetLastError());
                  return;
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string PrettyTime(string s_time)
  {
// without year
   return StringSubstr(s_time,5,0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DeletePendingOrders(string symbol="",int magic=-1,int type=-1,double min=0,double max=0)
  {
   if(_StealthPendingOrders)
     {
      DeleteVirtualPendings(symbol,magic,type);
      return;
     }

   for(int i=OrdersTotal()-1; i>=0; i--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return;
        }
      if((OrderSymbol()==symbol || StringLen(symbol)==0)
         && OrderType()!=OP_SELL && OrderType()!=OP_BUY)
        {
         if(OrderMagicNumber()==magic || magic<0)
           {
            if(OrderType()==type || type<0)
               if(min==0 || OrderOpenPrice()>=min)
                  if(max==0 || OrderOpenPrice()<=max)
                    {
                     ResetLastError();
                     if(!OrderDelete(OrderTicket()))
                       {
                        Print("Failed to delete pending order in "+__FUNCTION__+", error="+(string)GetLastError());
                        return;
                       }
                     else
                       {
                        if(_StealthPendingOrders)
                          {
                           ObjectDelete(0,_VS_Prefix+"SL"+IntegerToString(OrderTicket()));
                           ObjectDelete(0,_VS_Prefix+"TP"+IntegerToString(OrderTicket()));
                          }
                       }
                    }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseBuyOrders(string symbol=NULL,int magicNumber=-1,string comment="",double closePercentage=100)
  {
   int total=OrdersTotal();
   for(int b=0; b<=total-1; b++)
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
        {
         if((OrderMagicNumber()==magicNumber || magicNumber==-1) && (OrderSymbol()==symbol || StringLen(symbol)==0)
            && (StringLen(comment)==0 || StringFind(OrderComment(),comment)>=0) && OrderType()==OP_BUY)
           {
            ResetLastError();
            color arrowColor=clrSteelBlue;
            if(!_ShowArrows)
               arrowColor=clrNONE;
            if(!OrderClose(OrderTicket(),OrderLots()*closePercentage/100,MarketInfo(OrderSymbol(),MODE_BID),10,arrowColor))
              {
               Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
               return;
              }
            else
              {
               total=OrdersTotal();
               b--;
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseSellOrders(string symbol=NULL,int magicNumber=-1,string comment="",double closePercentage=100)
  {
   int total=OrdersTotal();
   int closed=0;
   for(int b=0; b<=total-1; b++)
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
        {
         if((OrderMagicNumber()==magicNumber || magicNumber==-1) && (OrderSymbol()==symbol || StringLen(symbol)==0)
            && (StringLen(comment)==0 || StringFind(OrderComment(),comment)>=0) && OrderType()==OP_SELL)
           {
            ResetLastError();
            color arrowColor=clrSteelBlue;
            if(!_ShowArrows)
               arrowColor=clrNONE;
            if(!OrderClose(OrderTicket(),OrderLots()*closePercentage/100,MarketInfo(OrderSymbol(),MODE_ASK),10,arrowColor))
              {
               Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
               return;
              }
            else
              {
               total=OrdersTotal();
               b--;
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double  CloseAllOrders(string symbol=NULL,int magicNumber=-1,int type=-1,string comment=NULL)
  {
   int total=OrdersTotal();
   double profit=0;
   for(int b=0; b<=total-1; b++)
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
        {
         if((OrderMagicNumber()==magicNumber || magicNumber==-1) &&
            (OrderSymbol()==symbol || StringLen(symbol)==0) &&
            (OrderType()==type || type<0) &&
            (StringLen(comment)==0 || StringFind(OrderComment(),comment)>=0))
           {
            ResetLastError();
            color arrowColor=clrSteelBlue;
            if(!_ShowArrows)
               arrowColor=clrNONE;
            double closePrice=MarketInfo(OrderSymbol(),MODE_ASK);
            if(OrderType()==OP_BUY)
               closePrice=MarketInfo(OrderSymbol(),MODE_BID);

            if(OrderType()!=OP_BUY && OrderType()!=OP_SELL)
              {
               continue;
              }

            if(!OrderClose(OrderTicket(),OrderLots(),closePrice,10,arrowColor))
              {
               Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
               return 0;
              }
            else
              {
               total=OrdersTotal();
               b--;
               profit+=OrderProfit()+OrderCommission()+OrderSwap();
              }
           }
        }
     }

   return profit;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseProfitableOrders(string symbol=NULL,int magicNumber=-1,int type=-1)
  {
   int total=OrdersTotal();
   for(int b=0; b<=total-1; b++)
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES) && OrderProfit()>=0)
        {
         if((OrderMagicNumber()==magicNumber || magicNumber==-1) && (OrderSymbol()==symbol || StringLen(symbol)==0) && (OrderType()==type || type<0))
           {
            ResetLastError();
            color arrowColor=clrSteelBlue;
            if(!_ShowArrows)
               arrowColor=clrNONE;
            double closePrice=MarketInfo(OrderSymbol(),MODE_ASK);
            if(type==OP_BUY)
               closePrice=MarketInfo(OrderSymbol(),MODE_BID);
            if(!OrderClose(OrderTicket(),OrderLots(),closePrice,10,arrowColor))
              {
               Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
               return;
              }
            else
              {
               total=OrdersTotal();
               b--;
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool allowBuy=true;
bool allowSell=true;
//+------------------------------------------------------------------+
//|                                                                  |
//+--------------------------------------------------------c----------+
bool CheckVirtualPendingOrders(string _symbol=NULL,int _type=-1,bool shortLabel=true,double belowLevel=0,double aboveLevel=0,string comment="",bool logs=false)
  {
   for(int i=GlobalVariablesTotal()-1; i>=0; i--)
     {
      string data=GlobalVariableName(i);

      if(StringFind(data,"sl=")>=0 || StringFind(data,"tp=")>=0)
        {
         double level=(double)StringToDouble(GetInfoBitFromVPOString(data,"@"));
         string symbol=GetSymbolFromVPOString(data);
         if(_symbol!=NULL && symbol!=_symbol)
            continue;

         int type=GetOrderTypeFromVPOString(data);
         if(type!=_type && _type>=0)
            continue;


         double pip=GetPip(symbol);
         int magic=(int)StringToInteger(GetInfoBitFromVPOString(data,"#"));
         double sl=(double)StringToDouble(GetInfoBitFromVPOString(data,"sl="));
         double tp=(double)StringToDouble(GetInfoBitFromVPOString(data,"tp="));
         double volume=NormalizeDouble(StringToDouble(GetInfoBitFromVPOString(data,"*")),2);
         int count=(int)GlobalVariableGet(data);

         double price=MarketInfo(symbol,MODE_ASK);
         if(type==OP_SELLSTOP || type==OP_SELLLIMIT)
            price=MarketInfo(symbol,MODE_BID);

         double priceDiff=price-level;
         if(type==OP_BUYLIMIT || type==OP_SELLSTOP)
            priceDiff=level-price;

         if(logs)
            Print("Checking virtual "+TypeName(type)+", currently at "+DoubleToStr((-1)*priceDiff/GetPip(_symbol),1)+" pips from market price");

         bool minMaxLimitCompliant=(price>=aboveLevel || aboveLevel==0) && (price<=belowLevel || belowLevel==0);

         if(priceDiff>=0 && // price crossed the line
            (priceDiff<=_MaxSlippage*pip || _MaxSlippage==0))
           {
            if(!minMaxLimitCompliant)
              {
               Print("Won't trigger virtual pending order at "+DoubleToStr(price,Digits)+", not below/above "+
                     DoubleToStr(belowLevel,Digits)+"/"+DoubleToStr(aboveLevel,Digits));
              }
            if(count==1)
               Print("Virtual "+TypeName(type)+" is triggered, open market order");
            else
               Print("Virtual "+TypeName(type)+"s"+" are triggered, open market orders");

            for(int iCount=0; iCount<count; iCount++)
              {
               // price just crossed level, open order
               if(type==OP_BUYSTOP || type==OP_BUYLIMIT)
                 {
                  DeleteVirtualPending(data);
                  if(allowBuy)
                    {
                     return  OpenBuy(symbol,volume,sl,tp,comment,magic)>0;
                    }
                  else
                    {
                     Print("Buy not allowed due to extra condition, V pending order was ignored");
                     return false;
                    }
                 }
               if(type==OP_SELLSTOP || type==OP_SELLLIMIT)
                 {
                  DeleteVirtualPending(data);
                  if(allowSell)
                    {
                     return  OpenSell(symbol,volume,sl,tp,comment,magic)>0;
                    }
                  else
                    {
                     Print("Sell not allowed due to extra condition, V pending order was ignored");
                     return false;
                    }
                 }
              }
            DeleteVirtualPending(data);
           }
         if(priceDiff<0)
           {
            // level not crossed yet, draw a line if on current symbol
            if(symbol==Symbol())
              {
               color clr=clrLimeGreen;
               if(type==OP_SELLSTOP || type==OP_SELLLIMIT)
                  clr=clrTomato;
               string label=TypeName(type)+" @"+(string)level+", "+(string)volume+" lots, sl="+(string)sl+", tp="+(string)tp;
               if(shortLabel)
                  label=DoubleToStr(volume,2)+" lots"; //  TypeName(type)+", "+
               if(count>1)
                  label=(string)count+" x "+label+" ("+DoubleToStr(volume,2)+" lots)";
               if(ObjectFind(0,_ObjPrefix+"vp @"+(string)level+" tp="+(string)tp+" sl="+(string)sl)<0)
                  SetHorizontalLine("vp @"+(string)level+" tp="+(string)tp+" sl="+(string)sl,level,clr,2,label);
              }
           }

         if(_MaxSlippage!=0 && priceDiff>_MaxSlippage*pip)
           {
            // missed the train, delete the pending
            Print(data+"missed the train, delete the pending");
            DeleteVirtualPending(data);
           }
        }
     }

   return false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CloseAllIfOneHitsTP(string symbol,int magic,int type=-1)
  {
   for(int i=OrdersHistoryTotal()-1; i>=0; i--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         Print("Failed to select history orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return false;
        }
      if(OrderSymbol()==symbol && OrderMagicNumber()==magic)
        {
         if(OrderType()==type || type<0)
           {
            if(TimeCurrent()-OrderCloseTime()<5)
              {
               // recent
               if(MathAbs(OrderClosePrice()-OrderStopLoss())>MathAbs(OrderClosePrice()-OrderTakeProfit()))
                 {
                  if(type==OP_BUY || type==-1)
                     CloseBuyOrders(Symbol(),magic);
                  if(type==OP_SELL || type==-1)
                     CloseSellOrders(Symbol(),magic);
                  DeletePendingOrders(Symbol(),magic,type);
                  DeleteVirtualPendings(Symbol(),magic,type);
                  return true;
                 }
              }
            else
              {
               return false;
              }
           }
        }
     }
   return  false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string OrderInfo(string templateText)
  {
   string orderInfo=templateText;

   StringReplace(orderInfo,"[SYMBOL]",(string)_selectedSymbol);
   StringReplace(orderInfo,"[SL]",(string)_selectedSL);
   StringReplace(orderInfo,"[TP]",(string)_selectedTP);
   StringReplace(orderInfo,"[TICKET]",(string)_selectedTicket);
   StringReplace(orderInfo,"[OPEN PRICE]",(string)_selectedOpenPrice);
   StringReplace(orderInfo,"[OPEN PRICE]",(string)_selectedClosePrice);
   StringReplace(orderInfo,"[VOLUME]",(string)_selectedVolume);
   StringReplace(orderInfo,"[OPEN TIME]",(string)_selectedOpenTime);
   StringReplace(orderInfo,"[CLOSE TIME]",(string)_selectedCloseTime);
   StringReplace(orderInfo,"[TYPE]",_selectedOrderTypeAsString());
   double closePrice=_selectedClosePrice;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(_selectedType==OP_BUY)
     {
      if(closePrice==0)
         closePrice=MarketInfo(_selectedSymbol,MODE_BID);
      StringReplace(orderInfo,"[PROFIT PIPS]",DoubleToStr((closePrice-_selectedOpenPrice)/GetPip(_selectedSymbol),1));
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(_selectedType==OP_SELL)
     {
      if(closePrice==0)
         closePrice=MarketInfo(_selectedSymbol,MODE_ASK);
      StringReplace(orderInfo,"[PROFIT PIPS]",DoubleToStr((_selectedOpenPrice-closePrice)/GetPip(_selectedSymbol),1));
     }
   StringReplace(orderInfo,"[PROFIT USD]",(string)_selectedProfit);

   return orderInfo;
  }//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string _selectedOrderTypeAsString()
  {
   if(_selectedType==OP_BUY)
     {
      return "BUY";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(_selectedType==OP_SELL)
     {
      return "SELL";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(_selectedType==OP_BUYSTOP)
     {
      return "BUY STOP";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(_selectedType==OP_SELLSTOP)
     {
      return "SELL STOP";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(_selectedType==OP_BUYLIMIT)
     {
      return "BUY LIMIT";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(_selectedType==OP_SELLLIMIT)
     {
      return "SELL LIMIT";
     }

   return "Order (type="+string(_selectedType)+")";
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int _selectedTicket;
int _selectedType;
int _selectedMagicNumber;
double _selectedOpenPrice;
double _selectedClosePrice;
double _selectedVolume;
double _selectedRiskedPercentage;
double _selectedRiskedAmount;
datetime _selectedOpenTime;
datetime _selectedCloseTime;
double _selectedProfit;
double _selectedProfitPips;
double _selectedSwap;
double _selectedCommission;
double _selectedSL;
double _selectedTP;
string _selectedSymbol;
string _selectedComment;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetSelectedOrderFields()
  {
   double tickSize=Point(); // MarketInfo(Symbol(),MODE_TICKSIZE);
   double tickValue=MarketInfo(Symbol(),MODE_TICKVALUE);
   _selectedSymbol=OrderSymbol();
   _selectedTicket=OrderTicket();
   _selectedType=OrderType();
   _selectedOpenPrice=OrderOpenPrice();
   _selectedVolume=OrderLots();
   _selectedOpenTime=OrderOpenTime();
   _selectedCloseTime=OrderCloseTime();
   _selectedProfit=OrderProfit();
   _selectedSL=OrderStopLoss();
   _selectedTP=OrderTakeProfit();
   _selectedProfitPips=(OrderProfit()/MathMax(MathAbs(OrderProfit()),0.0001))*MathAbs(OrderClosePrice()-OrderOpenPrice())/GetPip(OrderSymbol());
   _selectedRiskedAmount=(MathAbs(_selectedOpenPrice-_selectedSL)/tickSize)*tickValue*OrderLots();
   _selectedRiskedPercentage=_selectedRiskedAmount/AccountBalance()*100;
   _selectedSwap=OrderSwap();
   _selectedCommission=OrderCommission();
   _selectedClosePrice=OrderClosePrice();
   _selectedComment=OrderComment();
   _selectedMagicNumber=OrderMagicNumber();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool GetLastOpenedOrder(string symbol,int magicNumber,int type=-1,bool lookInHistory=true)
  {
   _selectedOpenTime=0;
   _selectedTicket=0;
   for(int i=OrdersTotal()-1; i>=0; i--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
        {
         Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return false;
        }
      if(OrderSymbol()==symbol && OrderMagicNumber()==magicNumber)
         if(OrderType()==type || type==-1)
            if(OrderOpenTime()>_selectedOpenTime || _selectedTicket==0)
              {
               SetSelectedOrderFields();
              }
     }

   if(_selectedTicket==0 && lookInHistory)
     {
      for(int i=OrdersHistoryTotal()-1; i>=0; i--)
        {
         ResetLastError();
         if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
           {
            Print("Failed to select history orders in "+__FUNCTION__+", error="+(string)GetLastError());
            return false;
           }
         if(OrderSymbol()==symbol && OrderMagicNumber()==magicNumber)
            if(OrderType()==type || type==-1)
               if(OrderOpenTime()>_selectedOpenTime || _selectedTicket==0)
                 {
                  SetSelectedOrderFields();
                  // break;
                 }
        }
     }
   return (_selectedTicket!=0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool PositionJustOpened(string symbol="",int magic=-1,int type=-1,bool useGlobalTimeStamp=false)
  {
   static int lastTicket=0;
   static datetime lastOpen=0;

   if(useGlobalTimeStamp)
      lastOpen=(int)GlobalVariableGet("PositionJustOpenedLastTime");

   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS))
        {
         Print("Failed to select orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return false;
        }
      if(OrderSymbol()==symbol || StringLen(symbol)==0)
         if(magic==-1 || OrderMagicNumber()==magic)
           {
            if(OrderTicket()!=lastTicket && OrderOpenTime()>=lastOpen)
              {
               // recent
               if(type==OrderType() || (type==-1 && (OrderType()==OP_BUY || OrderType()==OP_SELL)))
                 {
                  lastTicket=OrderTicket();
                  lastOpen=OrderOpenTime();

                  if(useGlobalTimeStamp)
                     GlobalVariableSet("PositionJustOpenedLastTime",(int)lastOpen);

                  SetSelectedOrderFields();
                  return true;
                 }
              }
            else
              {
               return false;
              }
           }
     }
   return  false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool OrderJustClosed(string symbol="",int magic=-1,int type=-1,bool useGlobalTimeStamp=false,bool ignorePartialCloses=false)
  {
   static int lastTicket=0;
   static datetime lastClose=0;

   static int lastHistoryCount=0;
   if(OrdersHistoryTotal()<=lastHistoryCount)
      return false;
   lastHistoryCount=OrdersHistoryTotal();

   if(useGlobalTimeStamp)
      lastClose=(int)GlobalVariableGet("PClosedLastTime"+Symbol()+timeFrameToString(Period()));

   string lastOpenedComment="";
   int newTicket=0;
   if(ignorePartialCloses)
     {
      int sel=OrderSelect(OrdersTotal()-1,SELECT_BY_POS);
      lastOpenedComment=OrderComment();
      newTicket=OrderTicket();
     }

   for(int i=OrdersHistoryTotal()-1; i>=0; i--)
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         Print("Failed to select history orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return false;
        }
      if(OrderSymbol()==symbol || StringLen(symbol)==0)
        {
         if(magic==-1 || OrderMagicNumber()==magic)
           {
            if(OrderTicket()!=lastTicket && OrderCloseTime()>=lastClose && OrderCloseTime()>=TimeCurrent()-Period()*60*200)
              {
               // recent
               if(type==OrderType() || (type==-1))
                 {
                  if(ignorePartialCloses && StringFind(lastOpenedComment,(string)OrderTicket())>=0)
                    {
                     int initialTicket=OrderTicket();
                     if(GlobalVariableCheck("partial"+(string)OrderTicket()))
                       {
                        initialTicket=(int)GlobalVariableGet("partial"+(string)OrderTicket());
                        GlobalVariableDel("partial"+(string)OrderTicket());
                       }
                     GlobalVariableSet("partial"+(string)newTicket,initialTicket);
                    }

                  lastTicket=OrderTicket();
                  lastClose=OrderCloseTime();

                  if(useGlobalTimeStamp)
                     GlobalVariableSet("PClosedLastTime"+Symbol()+timeFrameToString(Period()),(int)lastClose);

                  SetSelectedOrderFields();

                  return true;
                 }
              }
            else
              {
               return false;
              }
           }
        }
     }
   return  false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string OrderTypeToString(ENUM_ORDER_TYPE type)
  {
   switch(type)
     {
      case OP_BUY:
         return "Long";
      case OP_SELL:
         return "Short";
      case OP_BUYSTOP:
         return "BuyStop";
      case OP_SELLSTOP:
         return "SellStop";
      case OP_BUYLIMIT:
         return "BuyLimit";
      case OP_SELLLIMIT:
         return "SellLimit";
     }
   return "";
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DeleteVirtualPendings(string symbol=NULL,int magic=-1,int type=-1,string comment=NULL)
  {
   for(int i=GlobalVariablesTotal()-1; i>=0; i--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      string data=GlobalVariableName(i);
      if(StringFind(data,"sl=")>=0 || StringFind(data,"tp=")>=0)
        {
         int _magic=(int)StringToInteger(GetInfoBitFromVPOString(data,"#"));
         int _type=GetOrderTypeFromVPOString(data);
         string _symbol=GetSymbolFromVPOString(data);
         string _comment=GetInfoBitFromVPOString(data,"c=");

         if((_symbol==symbol || symbol==NULL) && (_magic==magic || magic<1))
            if(_type==type || type<0)
               if(StringFind(_comment,comment)>=0 || comment==NULL)
                 {
                  DeleteVirtualPending(data);
                 }
        }
     }
   CheckVirtualPendingOrders();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DeleteVirtualPending(string data)
  {
   Print("Delete "+data);
   double level=(double)StringToDouble(GetInfoBitFromVPOString(data,"@"));
   string symbol=GetSymbolFromVPOString(data);
   double sl=(double)StringToDouble(GetInfoBitFromVPOString(data,"sl="));
   double tp=(double)StringToDouble(GetInfoBitFromVPOString(data,"tp="));
   GlobalVariableDel(data);
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(symbol==Symbol())
     {
      DeleteLine("vp @"+(string)level+" tp="+(string)tp+" sl="+(string)sl);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseOrdersOlderThan(datetime time,int magic)
  {
   int total=OrdersTotal();
   for(int b=total-1; b>=0; b--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      if(OrderSelect(b,SELECT_BY_POS,MODE_TRADES))
        {
         if(OrderMagicNumber()==magic && OrderSymbol()==Symbol())
           {
            if(OrderOpenTime()<time)
              {
               ResetLastError();
               if(OrderType()==OP_SELL)
                 {
                  if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(Symbol(),MODE_ASK),10,CLR_NONE))
                    {
                     Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
                     return;
                    }
                 }
               if(OrderType()==OP_BUY)
                 {
                  if(!OrderClose(OrderTicket(),OrderLots(),MarketInfo(Symbol(),MODE_BID),10,CLR_NONE))
                    {
                     Print("Failed to close order in "+__FUNCTION__+", error="+(string)GetLastError());
                     return;
                    }
                 }
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetTFIdx(int tf)
  {
   for(int i=0; i<ArraySize(iTfTable); i++)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      if(iTfTable[i]==tf)
        {
         return i;
        }
     }

   return ArraySize(iTfTable);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string sTfTable[] = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
int    iTfTable[] = {1,5,15,30,60,240,1440,10080,43200};
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int stringToTimeFrame(string tfs)
  {
   StringToUpper(tfs);
   for(int i=ArraySize(iTfTable)-1; i>=0; i--)
      if(tfs==sTfTable[i] || tfs==""+(string)iTfTable[i])
         return(iTfTable[i]);
   return(Period());
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string timeFrameToString(int tf)
  {
   if(tf==0)
      tf=Period();
   for(int i=ArraySize(iTfTable)-1; i>=0; i--)
      if(tf==iTfTable[i])
         return(sTfTable[i]);
   return("");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetPipDistanceForValue(string symbol,double value,double lots)
  {
   double pipValue=MarketInfo(Symbol(),MODE_TICKVALUE);
   double point=MarketInfo(symbol,MODE_POINT);

   return ((value/lots)/pipValue)*point;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool _SoundAlert=false; // Sound Alert
string _SoundFile="alert2.wav"; // Sound File
bool _PopupAlert=false; // Pop-up Alert
bool _EmailAlert=true; // Email Alert
bool _PhoneAlert=false; // Phone Alert
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void InitAlertTypes(bool soundAlert,string soundFile,bool popupAlert,bool emailAlert,bool phoneAlert)
  {
   _SoundAlert=soundAlert;
   _SoundFile=soundFile;
   _EmailAlert=emailAlert;
   _PhoneAlert=phoneAlert;
   _PopupAlert=popupAlert;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime lastAlertTime[500];
string lastAlertType[500];
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void TriggerAlerts(string type,string soundFile="",string uniqueType="",int minTimeDistance=0)
  {
   static bool alertsInit=false;

   if(StringLen(uniqueType)==0)
      uniqueType=type;

   if(!alertsInit)
     {
      alertsInit=true;
      for(int i=0; i<500; i++)
        {
         lastAlertType[i]="";
        }
     }

   datetime lastTime=GetLastAlertTime(uniqueType);

   if((lastTime<Time[0] || minTimeDistance!=0) && (TimeCurrent()-lastTime>=minTimeDistance*60))
     {
      SetLastAlertTime(uniqueType);
      // type=type+"\n, Time="+TimeToString(TimeCurrent(),TIME_MINUTES);
      Print(type);
      if(_SoundAlert)
        {
         if(StringLen(soundFile)==0)
            soundFile=_SoundFile;
         PlaySound(soundFile);
        }
      if(_PopupAlert)
        {
         Alert(type);
        }
      if(_EmailAlert)
        {
         SendMail(type,type);
        }
      if(_PhoneAlert)
        {
         SendNotification(type);
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetLastAlertTime(string type)
  {
   int i=0;
   for(i=0; i<500; i++)
     {
      if(lastAlertType[i]==type || StringLen(lastAlertType[i])==0)
        {
         break;
        }
     }
   if(i==500)
      i=0;
   lastAlertTime[i]=TimeCurrent();

   lastAlertType[i]=type;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime GetLastAlertTime(string type)
  {
   for(int i=0; i<500; i++)
     {
      if(lastAlertType[i]==type)
         return (lastAlertTime[i]);
      if(lastAlertType[i]=="")
         break;
     }
   return (0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetTriangle(string name,datetime time1,double price1,datetime time2,double price2,datetime time3,double price3,color clr)
  {
   if(ObjectFind(name)==0)
     {
      ObjectSet(name,OBJPROP_TIME1,time1);
      ObjectSet(name,OBJPROP_TIME2,time2);
      ObjectSet(name,OBJPROP_TIME3,time3);
      ObjectSet(name,OBJPROP_PRICE1,price1);
      ObjectSet(name,OBJPROP_PRICE2,price2);
      ObjectSet(name,OBJPROP_PRICE3,price3);
     }
   else
     {
      ObjectCreate(0,name,OBJ_TRIANGLE,0,time1,price1,time2,price2,time3,price3);
     }

   ObjectSet(name,OBJPROP_COLOR,clr);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double RangeAvg(int startIdx,int bars=10)
  {
   double ravg=0;
   int lim=MathMin(startIdx+bars,Bars);
   for(int i=startIdx; i<lim; i++)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      ravg+=High[i]-Low[i];
     }
   ravg/=lim-startIdx;
   return (ravg);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetSignalArrow(int ssign,int i=0,int arrowCode=0,color clr=0,string name="signal",int size=1)
  {
   if(arrowCode==0 && ssign>0)
      arrowCode = 225;
   if(arrowCode==0 && ssign<0)
      arrowCode = 226;

   if(name=="signal")
      name+=(string)Time[i];
   if(ssign>0)
     {
      if(clr==0)
         clr=clrLimeGreen;
      SetArrow(name,Time[i],clr,arrowCode,Low[i]-ArrowPadding(),ANCHOR_TOP,size);
     }
   else
     {
      if(clr==0)
         clr=clrTomato;
      SetArrow(name,Time[i],clr,arrowCode,High[i]+ArrowPadding(),ANCHOR_BOTTOM,size);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double ArrowPadding()
  {
   static double   m_WinPriceMax= 0.0,m_WinPriceMin = 0.0;
   static long     m_PaneHeight = 0;
   static double Padding;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(m_WinPriceMax != WindowPriceMax() ||
      m_WinPriceMin != WindowPriceMin() ||
      m_PaneHeight!=ChartGetInteger(ChartID(),CHART_HEIGHT_IN_PIXELS,0))
     {
      m_WinPriceMax = WindowPriceMax();
      m_WinPriceMin = WindowPriceMin();
      m_PaneHeight=ChartGetInteger(ChartID(),CHART_HEIGHT_IN_PIXELS,0);
      if(m_PaneHeight>0)
        {
         Padding=NormalizeDouble(20.0 *(m_WinPriceMax-m_WinPriceMin)/m_PaneHeight,Digits);
        }
     }
   return Padding;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetArrow(string name,datetime time,color clr,int code,double price,int anchor,int size=1)
  {
   int bar=iBarShift(NULL,0,time);
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(ObjectFind(name)==0)
     {
      ObjectSet(name,OBJPROP_TIME1,time);
      ObjectSet(name,OBJPROP_PRICE1,price);
      ObjectSet(name,OBJPROP_COLOR,clr);
      ObjectSet(name,OBJPROP_ARROWCODE,code);
     }
   else
     {
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
      ObjectCreate(name,OBJ_ARROW,0,time,price);
      ObjectSet(name,OBJPROP_COLOR,clr);
      ObjectSet(name,OBJPROP_ARROWCODE,code);
      ObjectSet(name,OBJPROP_WIDTH,size);
      ObjectSet(name,OBJPROP_ANCHOR,anchor);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ok(double indiValue,double min=0,double max=0)
  {
   if(indiValue!=EMPTY_VALUE && indiValue!=0)
     {
      if(min==0 || indiValue>=min)
        {
         if(max==0 || indiValue<=max)
           {
            return true;
           }
        }
     }

   return false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string OneSidedIndicatorStatus(double bullishValue,double bearishValue,double bullishValue2=0,double bearishValue2=0)
  {
   string status="n/a";
   if(ok(bullishValue) || ok(bullishValue2))
      status="Bullish";
   if(ok(bearishValue) || ok(bearishValue2))
      status="Bearish";

   return status;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Direction(double ssign,double reference=0)
  {
   if(MathAbs(ssign)>=MathAbs(reference))
     {
      if(ssign>0)
         return "Bullish";
      if(ssign<0)
         return "Bearish";
     }
   return "n/a";
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
color SignColor(double ssign,double reference=0)
  {
   if(MathAbs(ssign)>=MathAbs(reference))
     {
      if(ssign>0)
         return clrLimeGreen;
      if(ssign<0)
         return clrTomato;
     }
   return clrAliceBlue;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Direction(bool conditionBuy,bool conditionSell,bool &canBuy,bool &canSell,string buyLabel="",string sellLabel="",string neutralLabel="")
  {
   if(!conditionBuy)
      canBuy=false;
   if(!conditionSell)
      canSell=false;

   if(conditionBuy && conditionSell)
      return "BOTH "+neutralLabel;
   if(conditionBuy)
      return "Bullish"+ buyLabel;
   if(conditionSell)
      return "Bearish"+ sellLabel;
   return "n/a "+neutralLabel;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string JoinedDirection(string direction1,string direction2,string direction3="none",string direction4="none",string direction5="none",string direction6="none")
  {
   string joined="none";
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(direction1!="none")
     {
      if(joined=="none")
         joined=NormalizeStatus(direction1);
      else
         if(DifferentStatus(joined,direction1))
            joined="n/a";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(direction2!="none")
     {
      if(joined=="none")
         joined=NormalizeStatus(direction2);
      else
         if(DifferentStatus(joined,direction2))
            joined="n/a";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(direction3!="none")
     {
      if(joined=="none")
         joined=NormalizeStatus(direction3);
      else
         if(DifferentStatus(joined,direction3))
            joined="n/a";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(direction4!="none")
     {
      if(joined=="none")
         joined=NormalizeStatus(direction4);
      else
         if(DifferentStatus(joined,direction4))
            joined="n/a";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(direction5!="none")
     {
      if(joined=="none")
         joined=NormalizeStatus(direction5);
      else
         if(DifferentStatus(joined,direction5))
            joined="n/a";
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(direction6!="none")
     {
      if(joined=="none")
         joined=NormalizeStatus(direction6);
      else
         if(DifferentStatus(joined,direction6))
            joined="n/a";
     }
   return joined;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool DifferentStatus(string status1,string status2)
  {
   return NormalizeStatus(status1)!=NormalizeStatus(status2);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string NormalizeStatus(string status)
  {
   if(StringFind(status,"Bullish")>=0)
      status="Bullish";
   if(StringFind(status,"UP")>=0)
      status="Bullish";
   if(StringFind(status,"Bearish")>=0)
      status="Bearish";
   if(StringFind(status,"DOWN")>=0)
      status="Bearish";

   return status;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool NoTradeClosedInLastCandles(string symbol,int magic,int candles)
  {
   bool allGood=true;

   int total=OrdersHistoryTotal();
   datetime lastClosed=0;
   for(int i=total-1; i>=0; i--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         if(OrderSymbol()==symbol && OrderMagicNumber()==magic)
           {
            lastClosed=OrderCloseTime();
            break;
           }
        }
     }
   int lastClosedCandle=iBarShift(Symbol(),Period(),lastClosed);
   return lastClosed>candles;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double NormLots(double lots)
  {
   double lotStep=MarketInfo(Symbol(),MODE_LOTSTEP);
   int digits = 0;
   if(lotStep<= 0.01)
      digits=2;
   else
      if(lotStep<=0.1)
         digits=1;
   lots=NormalizeDouble(lots,digits);

   double minLots=MarketInfo(Symbol(),MODE_MINLOT);
   if(lots<minLots)
      lots=minLots;

   double maxLots=MarketInfo(Symbol(),MODE_MAXLOT);
   if(lots>maxLots)
      lots=maxLots;

   return (lots);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ManuallyConfirmed(int sign)
  {
   if(!_AskForManualConfirmation)
      return true;

   string s_type="BUY";
   if(sign<0)
      s_type="SELL";

   return Verify(WindowExpertName()+ " wants to open a "+s_type+" trade on "+Symbol()+", "+timeFrameToString(Period())+". Do you allow it?");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool Verify(string message,string subject="Manual confirmation required")
  {
   return (MessageBox(message,subject,MB_YESNO)==IDYES);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool InInterval(datetime time,int _beginHour,int _beginMinute,int _endHour,int _endMinute,int _beginSecond=0,int _endSecond=0)
  {
   if(_beginHour==0 && _beginMinute==0 && _endHour==0 && _endMinute==0)
     {
      return (true);
     }
   else
     {
      bool afterBeginTime=TimeHour(time)>_beginHour || (TimeHour(time)==_beginHour && TimeMinute(time)>=_beginMinute)
                          || (TimeHour(time)==_beginHour && TimeMinute(time)==_beginMinute && TimeSeconds(time)>=_beginSecond);
      bool beforeEndTime=(TimeHour(time)<_endHour || (TimeHour(time)==_endHour && TimeMinute(time)<=_endMinute) ||
                          (TimeSeconds(time)==_endHour && TimeMinute(time)==_endMinute && TimeSeconds(time)<=_endSecond) || (_endHour==0 && _endMinute==0));
      return (afterBeginTime && beforeEndTime) || ((afterBeginTime || beforeEndTime) && (_beginHour>_endHour));
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool InHourInterval(datetime time,int startWeekDay,int endWeekDay,int _beginHour,int _beginMinute,int _endHour,int _endMinute)
  {
   if(_beginHour==0 && _beginMinute==0 && _endHour==0 && _endMinute==0)
     {
      return (true);
     }
   else
     {
      return((TimeDayOfWeek(time)>startWeekDay || (TimeDayOfWeek(time)==startWeekDay && (TimeHour(time)>_beginHour || (TimeHour(time)==_beginHour && TimeMinute(time)>=_beginMinute))))
             &&(TimeDayOfWeek(time)<endWeekDay || (TimeDayOfWeek(time)==endWeekDay && (TimeHour(time)<_endHour || (TimeHour(time)==_endHour && TimeMinute(time)<=_endMinute)))));
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetTrendLine(string name,double price1,double price2,datetime time1,datetime time2,color clr,int style,int width=1,bool ray=true,string label="",int window=0,datetime labelTime=0,string labelName="")
  {
   name=GetObjectName(name);

   if(ObjectFind(name)==window)
     {
      ObjectSet(name,OBJPROP_PRICE1,price1);
      ObjectSet(name,OBJPROP_PRICE2,price2);
      ObjectSet(name,OBJPROP_TIME1,time1);
      ObjectSet(name,OBJPROP_TIME2,time2);
      ObjectSet(name,OBJPROP_COLOR,clr);
      if(ray==true)
        {
         ObjectSet(name,OBJPROP_RAY,true);
        }
      else
        {
         ObjectSet(name,OBJPROP_RAY,false);
        }
     }
   else
     {
      ObjectCreate(name,OBJ_TREND,window,time1,price1,time2,price2);
      if(ray==true)
        {
         ObjectSet(name,OBJPROP_RAY,true);
        }
      else
        {
         ObjectSet(name,OBJPROP_RAY,false);
        }
      ObjectSet(name,OBJPROP_COLOR,clr);
      ObjectSet(name,OBJPROP_STYLE,style);
      ObjectSet(name,OBJPROP_WIDTH,width);
     }
   if(StringLen(label)>0)
     {
      if(StringLen(labelName)==0)
         labelName=name+"txt";
      ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER;
      if(labelTime==0)
        {
         labelTime=time2;
         if(price2>price1)
            anchor=ANCHOR_LOWER;
        }
      if(ObjectFind(labelName)!=0)
        {
         ObjectCreate(labelName,OBJ_TEXT,window,labelTime,price2);
        }
      else
        {
         ObjectSet(labelName,OBJPROP_PRICE1,price2);
         ObjectSet(labelName,OBJPROP_TIME1,labelTime);
        }
      ObjectSetText(labelName,label,8);
      ObjectSet(labelName,OBJPROP_COLOR,clr);
      ObjectSet(labelName,OBJPROP_ANCHOR,anchor);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsNewCandle(int tf=0)
  {
   static datetime timeLastCandle=0;
   if(iTime(Symbol(),tf,0)==timeLastCandle)
      return (false);
   timeLastCandle=iTime(Symbol(),tf,0);
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsNewCandle2(int tf=0)
  {
   static datetime timeLastCandle=0;
   if(iTime(Symbol(),tf,0)==timeLastCandle)
      return (false);
   timeLastCandle=iTime(Symbol(),tf,0);
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int GetKellyCriterionFactors(string symbol,int magic,double &winFactor,double &winLossRatio)
  {
   int losses=0;
   int wins=0;
   double winProfit=0;
   double lossProfit=0;

   for(int i=OrdersHistoryTotal()-1; i>=0; i--)
     {
      ResetLastError();
      if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         Print("Failed to select history orders in "+__FUNCTION__+", error="+(string)GetLastError());
         return false;
        }
      if(OrderSymbol()==symbol && OrderMagicNumber()==magic)
        {
         if(OrderProfit()>0)
           {
            wins++;
            winProfit+=OrderProfit();
           }
         if(OrderProfit()<0)
           {
            losses++;
            lossProfit+=OrderProfit();
           }
        }
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(losses==0)
     {
      Print("0 losses, can't process win/loss ratio");
      return -1;
     }

   if(wins>0)
      winProfit/=wins;
   lossProfit/=losses;
   winFactor=(double)wins/(wins+losses);
   winLossRatio=winProfit/MathAbs(lossProfit);

   return wins+losses;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int StartHour=0; // Start Hour
int StartMinute=0; // Start Minute
int EndHour=0; // End Hour
int EndMinute=0; // End Minute
int CloseHour=0; //  Close Hour
int CloseMinute=0; //  Close Minute
int TradeHour;
int TradeMinute=0;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string Ordinal(int number)
  {
   if(number==1)
      return "1st";
   if(number==2)
      return "2nd";
   if(number==3)
      return "3rd";
   else
      return (string)number+"th";
  }
//+------------------------------------------------------------------+
//|                                 t                                 |
//+------------------------------------------------------------------+
void TransformTime(string time,int &hour,int &minute)
  {
   if(StringLen(time)!=5 || StringFind(time,":")!=2)
     {
      Alert("Start Time format must be like 'HH:MM'");
     }

   hour=(int)StringToInteger(StringSubstr(time,0,2));
   minute=(int)StringToInteger(StringSubstr(time,3,2));
  }
//+------------------------------------------------------------------+
//|                                 t                                 |
//+------------------------------------------------------------------+
void TransformTimeS(string time,int &hour,int &minute,int &second)
  {
   if(StringLen(time)!=8 || StringFind(time,":")!=2)
     {
      Alert("Start Time format must be like 'HH:MM'");
     }

   hour=(int)StringToInteger(StringSubstr(time,0,2));
   minute=(int)StringToInteger(StringSubstr(time,3,2));
   second=(int)StringToInteger(StringSubstr(time,6,2));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string font="Ebrima";
int tableFontSize=8;
double xLeftMarginRatio=0.008;
double yTopMarginRatio=0.045;
double xFirstColumnSizeRatio=0.055;
double xColumnSizeRatio=0.052;
double xColumnSeparatorRatio=0.0006;
double yFirstRowSizeRatio=0.05;
double yRowSizeRatio=0.072;
double yRowSeparatorRatio=0.0025;
enum CellType {Radio_Cell,Text_Cell,Button_Cell};
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
struct dashColumn
  {
   string            name;
   string            s_id;
   double            xSizeWindowPercentage;
   double            xOffsetWindowPercentage;
   CellType          cellType;
   string            tag;
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
dashColumn dashColumns[];
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void AddColumn(string headerID,string name,double xSizeWindowPercentage,CellType cellType,int subWindow=0,string tag="",color clr=clrDarkSeaGreen)
  {
   ArrayResize(dashColumns,ArraySize(dashColumns)+1);
   int idx=ArraySize(dashColumns)-1;
   dashColumns[idx].name=name;
   if(StringLen(name)==0)
      dashColumns[idx].name=headerID;
   dashColumns[idx].xSizeWindowPercentage=xSizeWindowPercentage;
   dashColumns[idx].cellType=cellType;
   dashColumns[idx].tag=tag;
   dashColumns[idx].s_id=headerID;

   for(int i=0; i<idx; i++)
     {
      dashColumns[idx].xOffsetWindowPercentage+=dashColumns[i].xSizeWindowPercentage+xColumnSeparatorRatio*100;
     }

   AddCell(dashColumns[idx].name,0,idx,clr,0,subWindow);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void AddCell(string text,int rowIdx,int columnIdx,color clr,double resizeYPercentage=0,int subWindow=0,int fontSize=0)
  {
   string name="row"+(string)rowIdx+"column"+(string)columnIdx;

   int chartXSize=(int)ChartGetInteger(0,CHART_WIDTH_IN_PIXELS,subWindow);
   int chartYSize=(int)ChartGetInteger(0,CHART_HEIGHT_IN_PIXELS,subWindow);

   int columnSize=(int)(chartXSize*xColumnSizeRatio);
   if(columnIdx==0)
      columnSize=(int)(chartXSize*xFirstColumnSizeRatio); // first column
   if(columnIdx>=0 && columnIdx<ArraySize(dashColumns))
      columnSize=(int)(chartXSize*dashColumns[columnIdx].xSizeWindowPercentage/100);

   int rowSize=(int)(int)(chartYSize*yRowSizeRatio);
   if(rowIdx==0)
      rowSize=(int)(chartYSize*yFirstRowSizeRatio); // first row - HEADER

   int columnOffset=(int)(xLeftMarginRatio*chartXSize);
   if(columnIdx>=0 && columnIdx<ArraySize(dashColumns))
      columnOffset+=(int)(chartXSize*dashColumns[columnIdx].xOffsetWindowPercentage/100);
   else
      columnOffset+=(int)(xFirstColumnSizeRatio*chartXSize+chartXSize*xColumnSeparatorRatio+(columnIdx-1)*(chartXSize*xColumnSizeRatio+chartXSize*xColumnSeparatorRatio));

   int rowOffset=(int)(yTopMarginRatio*chartYSize);
   if(rowIdx!=0)
      rowOffset+=(int)(yFirstRowSizeRatio*chartYSize)+(int)(rowIdx-1)*rowSize+(int)(rowIdx*chartYSize*yRowSeparatorRatio);

   AddTextLabel(name,columnOffset,rowOffset,columnSize,rowSize,clr,text,CORNER_LEFT_UPPER,true,subWindow,fontSize);

// add margins
   if(columnIdx==0)
      AddBorder(name+"bl",columnOffset-(int)(xColumnSeparatorRatio*chartXSize*1),rowOffset,(int)(xColumnSeparatorRatio*chartXSize),rowSize+(int)(xColumnSeparatorRatio*chartXSize),clrWhiteSmoke,CORNER_LEFT_UPPER,subWindow);  // add left margin
   if(rowIdx==0)
      AddBorder(name+"bt",columnOffset,rowOffset-(int)(xColumnSeparatorRatio*chartXSize*1),columnSize+(int)(xColumnSeparatorRatio*chartXSize),(int)(xColumnSeparatorRatio*chartXSize),clrWhiteSmoke,CORNER_LEFT_UPPER,subWindow);  // add top margin
   AddBorder(name+"br",columnOffset+columnSize,rowOffset-(int)(xColumnSeparatorRatio*chartXSize*1),(int)(xColumnSeparatorRatio*chartXSize),rowSize+(int)(xColumnSeparatorRatio*chartXSize),clrWhiteSmoke,CORNER_LEFT_UPPER,subWindow);  // add right margin
   AddBorder(name+"bb",columnOffset-(int)(xColumnSeparatorRatio*chartXSize*1),rowOffset+rowSize,columnSize+(int)(xColumnSeparatorRatio*chartXSize)*2,(int)(xColumnSeparatorRatio*chartXSize),clrWhiteSmoke,CORNER_LEFT_UPPER,subWindow);  // add bottom margin
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void AddBorder(string name,int xDistance,int yDistance,int xSize,int ySize,color clr,ENUM_BASE_CORNER corner,int subWindow=0)
  {
   ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,subWindow,0,0);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,clr);
   ObjectSetInteger(0,name,OBJPROP_ZORDER,-99999);
   ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_RAISED);
   ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_BACK,true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void AddTextLabel(string name,int xDistance,int yDistance,int xSize,int ySize,color clr,string text,ENUM_BASE_CORNER corner,bool trim=true,int subWindow=0,int fontSize=0)
  {
   if(StringLen(text)>63)
     {
      text=StringSetChar(text,61,'.');
      text=StringSetChar(text,62,'.');
      text=StringSetChar(text,63,'.');
      text=StringSubstr(text,0,64);
     }
   if(!trim)
      xSize=(int)(StringLen(text)*6.15);

   ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,subWindow,0,0);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,clr);
   ObjectSetInteger(0,name,OBJPROP_ZORDER,-99999);
   ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_RAISED);
   ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_BACK,true);

   name=name+"txt";
   int ySign=1;
   if(corner==CORNER_LEFT_LOWER || corner==CORNER_RIGHT_LOWER)
      ySign=-1;
   ObjectCreate(0,name,OBJ_LABEL,subWindow,0,0);
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance+5);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance+ySign*ySize/2);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
   string trimmedText=text;
   if(trim)
     {
      trimmedText=StringSubstr(text,0,(int)(xSize/6));
      if(StringLen(trimmedText)<StringLen(text))
         trimmedText=StringSubstr(trimmedText,0,StringLen(trimmedText)-2)+"..";
     }

   if(fontSize==0)
      fontSize=tableFontSize;
   ObjectSetText(name,trimmedText,fontSize,font,clrWhiteSmoke);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetLabel(string name,int xDistance,int yDistance,int xSize,int ySize,color clr,string text,int fontSize=10,ENUM_BASE_CORNER corner=CORNER_LEFT_LOWER,ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER,bool trim=true)
  {
   name=GetObjectName(name);

   if(StringLen(text)>63)
     {
      text=StringSetChar(text,61,'.');
      text=StringSetChar(text,62,'.');
      text=StringSetChar(text,63,'.');
      text=StringSubstr(text,0,64);
     }
   if(!trim)
      xSize=(int)(StringLen(text)*6.15);

   int ySign=1;
   if(corner==CORNER_LEFT_LOWER || corner==CORNER_RIGHT_LOWER)
      ySign=-1;
   if(ObjectFind(0,name)<0)
      ObjectCreate(0,name,OBJ_LABEL,0,0,0);
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance+5);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance+ySign*ySize/2);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(0,name,OBJPROP_ZORDER,333);
   string trimmedText=text;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(trim)
     {
      trimmedText=StringSubstr(text,0,(int)(xSize/6));
      if(StringLen(trimmedText)<StringLen(text))
         trimmedText=StringSubstr(trimmedText,0,StringLen(trimmedText)-2)+"..";
     }
   ObjectSetText(name,trimmedText,tableFontSize,font,clrWhiteSmoke);
   ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontSize);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double MinDistance(string symbol=NULL)
  {
   if(StringLen(symbol)==0 || symbol==NULL)
      symbol=Symbol();
   return MarketInfo(symbol,MODE_STOPLEVEL)*MarketInfo(symbol,MODE_POINT);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Spread(string symbol=NULL)
  {
   if(StringLen(symbol)==0 || symbol==NULL)
      symbol=Symbol();
   return MarketInfo(symbol,MODE_SPREAD)*MarketInfo(symbol,MODE_POINT);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetButton(string name,int xDistance,int yDistance,int xSize,int ySize,string text,color textColor,color bgColor,bool state=false,int fontSize=0,ENUM_BASE_CORNER  corner=CORNER_LEFT_UPPER,ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER,int window=0,string s_font="Ebrima")
  {
   name=GetObjectName(name);
   ObjectCreate(name,OBJ_BUTTON,window,0,0);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
   ObjectSetString(0,name,OBJPROP_TEXT,text);
   if(StringLen(s_font)>0)
      ObjectSetString(0,name,OBJPROP_FONT,s_font);
   ObjectSetInteger(0,name,OBJPROP_COLOR,textColor);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bgColor);
   ObjectSetInteger(0,name,OBJPROP_STATE,state);
   if(fontSize==0)
      fontSize=xSize/10;
   ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontSize);
   ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(0,name,OBJPROP_ZORDER,5);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetRectangleLabel(string name,int xDistance,int yDistance,int xSize,int ySize,color clr,color bgColor=clrBlueViolet,
                       ENUM_BASE_CORNER  corner=CORNER_LEFT_UPPER,ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER,bool back=true,int window=0)
  {
   name=GetObjectName(name);
   ObjectCreate(name,OBJ_RECTANGLE_LABEL,window,0,0);
   ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
   ObjectSetInteger(0,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
   ObjectSetInteger(0,name,OBJPROP_COLOR,clr);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bgColor);
   ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_FLAT);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
   ObjectSetInteger(0,name,OBJPROP_BACK,back);
   ObjectSetInteger(0,name,OBJPROP_ZORDER,10);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string GetObjectName(string name)
  {
   if(StringFind(name,_ObjPrefix)<0)
     {
      name=StringConcatenate(_ObjPrefix,name);
     }

   return name;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetInput(string name,int xDistance,int yDistance,int xSize,int ySize,string text,color textColor,color bgColor,bool state=false,string s_font="Ebrima")
  {
   name=GetObjectName(name);
   if(ObjectFind(0,name)<0)
      ObjectCreate(0,name,OBJ_EDIT,0,0,0);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
   ObjectSetString(0,name,OBJPROP_TEXT,text);
   if(StringLen(s_font)>0)
      ObjectSetString(0,name,OBJPROP_FONT,s_font);
   ObjectSetInteger(0,name,OBJPROP_COLOR,textColor);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bgColor);
   ObjectSetInteger(0,name,OBJPROP_STATE,state);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetNumberInput(string name,int xDistance,int yDistance,int xSize,int ySize,string text,color textColor,color bgColor,bool state=false,int window=0,string s_font="Ebrima")
  {
   int arrowsSize=32;

   name=GetObjectName(name);
   if(ObjectFind(0,name)<0)
      ObjectCreate(0,name,OBJ_EDIT,0,0,0);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize-arrowsSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
   ObjectSetString(0,name,OBJPROP_TEXT,text);
   if(StringLen(s_font)>0)
      ObjectSetString(0,name,OBJPROP_FONT,s_font);
   ObjectSetInteger(0,name,OBJPROP_COLOR,textColor);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bgColor);
   ObjectSetInteger(0,name,OBJPROP_STATE,state);

   string nameUp=name+" goUp";
   SetButton(nameUp,xDistance+xSize-arrowsSize,yDistance,arrowsSize,ySize/2,CharToStr(233),clrBlack,bgColor,false,7,0,0,window,"Wingdings");
   string nameDn=name+" goDn";
   SetButton(nameDn,xDistance+xSize-arrowsSize,yDistance+ySize/2,arrowsSize,ySize/2,CharToStr(234),clrBlack,bgColor,false,7,0,0,window,"Wingdings");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetCell(string name,int xDistance,int yDistance,int xSize,int ySize,string text,color textColor,color bgColor,int fontSize=0,int xOffset=0,int yOffset=0,string s_font="Ebrima",bool selectable=false)
  {
   name=GetObjectName(name);

   name=name+"bg";
   if(ObjectFind(0,name)<0)
      ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,0,0,0);
   ObjectSetInteger(0,name,OBJPROP_SELECTABLE,selectable);
   ObjectSetInteger(0,name,OBJPROP_BACK,false);
   ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bgColor);
   ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance);
   ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance);
   ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
   ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(StringLen(text)>0)
     {
      name=StringSubstr(name,0,StringLen(name)-2);
      if(fontSize==0)
         fontSize=(int)(ySize/1.75);

      if(ObjectFind(0,name)<0)
         ObjectCreate(0,name,OBJ_LABEL,0,0,0);
      if(xOffset==0)
         xOffset=(int)((double)xSize*12/(StringLen(text)*fontSize));
      if(yOffset==0)
         yOffset=(int)((double)(ySize-fontSize)/4);
      ObjectSetInteger(0,name,OBJPROP_XDISTANCE,xDistance+xOffset);
      ObjectSetInteger(0,name,OBJPROP_YDISTANCE,yDistance+yOffset);
      ObjectSetInteger(0,name,OBJPROP_XSIZE,xSize);
      ObjectSetInteger(0,name,OBJPROP_YSIZE,ySize);
      ObjectSetString(0,name,OBJPROP_TEXT,text);
      if(StringLen(s_font)>0)
         ObjectSetString(0,name,OBJPROP_FONT,s_font);
      ObjectSetInteger(0,name,OBJPROP_COLOR,textColor);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontSize);
      ObjectSetInteger(0,name,OBJPROP_SELECTABLE,selectable);
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double Get(string key)
  {
   key+=StringConcatenate("",Symbol());
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   if(GlobalVariableCheck(key))
     {
      return GlobalVariableGet(key);
     }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
   else
     {
      return -1;
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime Set(string key,double value)
  {
   key+=StringConcatenate("",Symbol());
   datetime ret=GlobalVariableSet(key,value);

   return ret;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string CurrentVersion()
  {
   double v=1.0;
   string name=WindowExpertName();
   for(int i=StringLen(name)-1; i>=0; i--)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      if(StringSubstr(name,i,1)=="v")
        {
         string vShort=StringSubstr(name,i+1,1);
         string vLong=StringSubstr(name,i+1,3);
         v=StringToDouble(vLong);
         if(v==0)
            v=StringToDouble(vLong);
         break;
        }
     }
   return "v"+DoubleToStr(v,1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
color disabledColor=clrSlateGray;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SelectRadioButton(string selected)
  {
   ObjectSetInteger(0,selected,OBJPROP_STATE,true);

   int pos=StringFind(selected," ");
   string radioGroup=StringSubstr(selected,0,pos);

   for(int i=0; i<ObjectsTotal(0,0,OBJ_BUTTON); i++)
      //+------------------------------------------------------------------+
      //|                                                                  |
      //+------------------------------------------------------------------+
     {
      string name=ObjectName(0,i,0,OBJ_BUTTON);
      if(StringFind(name,radioGroup)>=0 && name!=selected)
        {
         ObjectSetInteger(0,name,OBJPROP_STATE,false);
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CheckActionLines(int magic=-1)
  {
   static double lastBid=0;
   static double lastAsk=0;

   if(lastBid!=0 && lastAsk!=0)
     {
      for(int i=0; i<ObjectsTotal(0,0,OBJ_HLINE); i++)
        {
         string name=ObjectName(0,i,0,OBJ_HLINE);
         double price=ObjectGetDouble(0,name,OBJPROP_PRICE1);
         if(StringFind(name,"buy")>=0 || StringFind(name,"sell")>=0)
           {
            double lastRefPrice=0;
            double refPrice=0;

            if(StringFind(name,"buy")>=0)
              {
               lastRefPrice=lastBid;
               refPrice=Bid;
              }
            if(StringFind(name,"sell")>=0)
              {
               lastRefPrice=lastAsk;
               refPrice=Ask;
              }

            double orderPrice=StringToDouble(GetInfoBitFromVPOString(name,"p="));
            int orderTicket=FindOrder(Symbol(),magic,-1,-1,NULL,orderPrice-5*Point,orderPrice+5*Point,0);

            if(orderTicket<0)
              {
               ObjectDelete(0,name);
               ObjectDelete(0,name+"txt");
               continue;
              }

            double ssign=refPrice-price;
            double lastSign=lastRefPrice-price;

            if(ssign*lastSign<=0)
              {
               // LINE touched or crossed

               color clr=(color)ObjectGetInteger(0,name,OBJPROP_COLOR);

               if(clr==clrTomato || clr==clrLimeGreen)
                 {
                  Print("crossed "+name);
                  double volume=StringToDouble(GetInfoBitFromVPOString(name,"v="));

                  Print("trying to close "+DoubleToStr(volume,2)+" lots for ticket #"+(string)orderTicket);

                  int sel=OrderSelect(orderTicket,SELECT_BY_TICKET,MODE_TRADES);

                  double close=OrderClose(orderTicket,volume,refPrice,(int)(50*GetPip(Symbol())/Point()));

                  if(close)
                    {
                     ObjectSetInteger(0,name,OBJPROP_COLOR,clrGray);
                    }
                 }
              }
           }
        }
     }

   lastBid=Bid;
   lastAsk=Ask;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CrossedAbove(double fast,double slow,double prev_fast,double prev_slow,double minDistance=0)
  {
   return fast>slow && prev_fast<=prev_slow &&  fast-slow>=minDistance;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CrossedBelow(double fast,double slow,double prev_fast,double prev_slow,double minDistance=0)
  {
   return fast<slow && prev_fast>=prev_slow &&  slow-fast>=minDistance;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetText(string name,double price,datetime time,color clr,string text,int fontSize=10,int window=0,ENUM_BASE_CORNER corner=CORNER_LEFT_LOWER,ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER)
  {
   name=GetObjectName(name);
   ObjectCreate(name,OBJ_TEXT,window,0,0);
   ObjectSetInteger(window,name,OBJPROP_ANCHOR,ANCHOR_LEFT);

   ObjectSet(name,OBJPROP_PRICE1,price);

   ObjectSet(name,OBJPROP_SELECTABLE,false);
   ObjectSet(name,OBJPROP_TIME1,time);
   ObjectSetInteger(window,name,OBJPROP_CORNER,corner);
   ObjectSetInteger(window,name,OBJPROP_ANCHOR,anchor);
   ObjectSetInteger(window,name,OBJPROP_ZORDER,0);
   ObjectSetText(name,text,fontSize,NULL,clr);
   ObjectSetInteger(window,name,OBJPROP_FONTSIZE,fontSize);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int Correlated(string pair1,string pair2)
  {
   if(StringSubstr(pair1,0,3)==StringSubstr(pair2,0,3))
      return 1;
   if(StringSubstr(pair1,3,3)==StringSubstr(pair2,3,3))
      return 1;
   if(StringSubstr(pair1,0,3)==StringSubstr(pair2,3,3))
      return -1;
   if(StringSubstr(pair1,3,3)==StringSubstr(pair2,0,3))
      return -1;
   return 0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double SafeMin(double value1,double value2)
  {
   if(!ok(value1) && ok(value2))
      return value2;
   if(!ok(value2) && ok(value1))
      return value1;
   return MathMin(value1,value2);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double SafeMax(double value1,double value2)
  {
   if(!ok(value1) && ok(value2))
      return value2;
   if(!ok(value2) && ok(value1))
      return value1;
   return MathMax(value1,value2);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double SafeDivide(double divideThis,double byThat)
  {
   if(byThat==0)
      return divideThis/0.0000001;
   else
      return divideThis/byThat;
  }
//+------------------------------------------------------------------+

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

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CheckLicense(int lockedAccountNumber,int lockedYear,int lockedMonth,int lockedDayOfMonth)
  {
   if(AccountNumber()!=lockedAccountNumber && lockedAccountNumber!=0)
      return false;
   if(TimeYear(TimeCurrent())>lockedYear || (TimeYear(TimeCurrent())==lockedYear && TimeMonth(TimeCurrent())>lockedMonth)
      ||(TimeYear(TimeCurrent())==lockedYear && TimeMonth(TimeCurrent())==lockedMonth && TimeDay(TimeCurrent())>lockedDayOfMonth))
      return false;
   return true;
  }

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---