Jump to content
  • 0

Need help on unable to loan EA on IG MT4


Dellan

Question

Deal all,

I'm new to forex and EA, trying to execute the EA to run a backtesting, but it show error unable to load file, need help regarding this issue.

Due to unable upload EA file, hence I paste the code bellow (is an EA i create by using AlgoWizard "Simple").

//+------------------------------------------------------------------+
//| New strategy EA
//|
//| Generated by StrategyQuant 3.9.132 at 12/30/2022 14:11
//|  
//| Backtested on EURUSD / D1, 2021.12.28 - 2022.12.28 
//|
//| This EA uses 3rd party library OrderReliable for industry-strength 
//| order handling. OrderReliable library is normally distributed under 
//| GPL license. Its author provided it under MIT license limited to 
//| usage only within strategies generated by StrategyQuant.  
//|   
//| This means that this library doesn't restrict you to use your EA 
//| generated by SQ comercially in any way you want.  
//| But if you'll use any method from OrderReliable library outside 
//| of this EA in your own EAs or projects, its use will be governed 
//| by its standard GPL license.  
//| 
//| Scroll to the very bottom of this source code for the full text 
//| of OrderReliable license. 
//+------------------------------------------------------------------+

#property copyright "StrategyQuant.com"
#property link      "http://www.StrategyQuant.com"
#property strict

#include <stdlib.mqh>
#include <stderror.mqh>

const int SLPTTYPE_RANGE = 0;
const int SLPTTYPE_LEVEL = 1;

//+------------------------------------------------------------------+
// -- Variables
//+------------------------------------------------------------------+

extern string CustomComment = "New strategy";
extern int MagicNumber = 11111;
bool LongEntrySignal = false;
bool ShortEntrySignal = false;
bool LongExitSignal = false;
bool ShortExitSignal = false;
extern int MABarOpensPeriod = 10;

//+------------------------------------------------------------------+
// Money Management variables
//+------------------------------------------------------------------+

extern string smm = "----------- Money Management - Fixed size -----------";
extern double mmLots = 0.1;

//+------------------------------------------------------------------+
// Trading Options variables
//+------------------------------------------------------------------+

extern string sdtw = "----------- Dont Trade On Weekends -----------";
extern bool DontTradeOnWeekends = false;
extern string FridayCloseTime = "23:00";
extern string SundayOpenTime = "23:00";
extern string seod = "----------- Exit At End Of Day -----------";
extern bool ExitAtEndOfDay = false;
extern string EODExitTime = "23:55";

extern string seof = "----------- Exit On Friday -----------";
extern bool ExitOnFriday = false;
extern string FridayExitTime = "23:00";

extern string sltr = "----------- Limit Time Range -----------";
extern bool LimitTimeRange = false;
extern string SignalTimeRangeFrom = "08:00";
extern string SignalTimeRangeTo = "16:00";
extern bool ExitAtEndOfRange = false;
extern int OrderTypeToExit = 0;

extern string smmmdfmp = "----------- Max distance from market price -----------";
extern bool LimitMaxDistanceFromMarketPrice = false;   //Limit max distance
extern double MaxDistanceFromMarketPct = 6;   //Max distance %

extern string smtpd = "----------- Max Trades Per Day -----------";
extern int MaxTradesPerDay = 0;
extern string smmslpt = "----------- Min/Max SL/PT -----------";
extern int MinimumSL = 0;   //Minimum SL in pips
extern int MinimumPT = 0;   //Minimum PT in pips
extern int MaximumSL = 0;   //Maximum SL in pips
extern int MaximumPT = 0;   //Maximum PT in pips


      
extern string slts = "----------- Use Tick size from SQ (for CFDs) -----------";
// For exotic pairs (usually non forex CFDs) the default method of computing 
// tick size in EA might not work correctly.
// By turning this on and specifying MainChartTickSizeSQ value you can let EA 
// use the correct tick size          
extern bool UseSQTickSize = false;                                                                             
extern double MainChartTickSizeSQ = 1.0E-4;

//+------------------------------------------------------------------+
// OrderReliable library variables
//+------------------------------------------------------------------+
string     OrderReliableVersion = "v36";
string     OrderReliable_Fname = "OrderReliable (Function Name Not Set)";

int     retry_attempts               = 100; // general retry attempts
int     retry_attempts_bad_price   = 3;  // retry attempts if the error is bad price
double     sleep_time                   = 2.0;
double     sleep_maximum               = 20.0;


int     ErrorLevel             = 3;

bool    UseLimitToMarket     = false;
bool    UseForTesting         = false;
bool    AddSpreadToComment    = false;

//+------------------------------------------------------------------+
// -- SQ internal variables
// add word "extern" in front of the variable you want
// to make configurable
//+------------------------------------------------------------------+
int sqMaxEntrySlippage = 5;          //Max tolerated entry slippage in pips. Zero means unlimited slippage
int sqMaxCloseSlippage = 0;          //Max tolerated close slippage in pips. Zero means unlimited slippage       
bool autoCorrectMaxSlippage = true;  //If set to true, it will automatically adjust max slippage according to symbol digits (*10 for 3 and 5 digit symbols)  

//Some brokers have problems with updating position counts. Set this timeout to non-zero value if you experience this.
//For example EnterReverseAtMarket doesn't work well for Admiral Markets, because OrdersTotal() returns 1 even after the order has been closed.
uint orderSelectTimeout = 0;         //in ms

double sqMinDistance = 0.0;

//+------------------------------------------------------------------+
// Verbose mode values:
// 0 - don't print messages to log at all
// 1 - print messages to log only when trading (not when backtesting)
// 2 - print messages to log always
//+------------------------------------------------------------------+
int sqVerboseMode = 2;

extern bool sqDisplayInfoPanel = true;
extern bool ModifyInsteadOfReplacing = true;

extern int OpenBarDelay = 0; // open bar delay in minutes
// it can be used for Daily strategies to trigger trading a few minutes later -
// because brokers sometimes have technical delay after midnight and we have to postpone order execution

int sqLabelCorner = 1;
int sqOffsetHorizontal = 5;
int sqOffsetVertical = 20;
color sqLabelColor = White;

datetime _sqLastOpenBarTime = 0;
bool _sqIsBarOpen = false;
double gPointCoef = 0;
int _ticket;                     
bool cond[100];

double initialBalance = 0;                    
    
bool openingOrdersAllowed = true;
bool firstCall = true;
bool strategyUsesATM = false;

//////////
//+------------------------------------------------------------------+
// -- Functions
//+------------------------------------------------------------------+

void OnTick() {

   sqInitStart();       
   
   sqManageOrders(MagicNumber);
   
   openingOrdersAllowed = sqHandleTradingOptions();

   //------------------------
   // Rule: Trading signals
   //------------------------
if (sqIsBarOpen()) {
     // init signals only on bar open 
     LongEntrySignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) > sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1));

     ShortEntrySignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) < sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1));

     LongExitSignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) < sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1));

     ShortExitSignal = (sqGetValue("NULL",0, PRICE_OPEN, 0) > sqMA(NULL,0, MABarOpensPeriod, 0, 1, PRICE_CLOSE, 1));

   } 


                
   //------------------------
   // Rule: Long entry
   //------------------------
   if (sqIsBarOpen()
      && ((LongEntrySignal
      && (!(ShortEntrySignal)))
      && (!(LongExitSignal))))
   {
      // Action #1
         _ticket = sqOpenOrder(OP_BUY, "Current", mmLots, 0, MagicNumber, "", 0, false, false, CLR_NONE);

      if(_ticket > 0 && OrderSelect(_ticket, SELECT_BY_TICKET)) {
         // set or initialize all order exit methods (SL, PT, Trailing Stop, Exit After Bars, etc.)
         // StopLoss & ProfitTarget

      }


  }

                
   //------------------------
   // Rule: Short entry
   //------------------------
   if (sqIsBarOpen()
      && ((ShortEntrySignal
      && (!(LongEntrySignal)))
      && (!(ShortExitSignal))))
   {
      // Action #1
         _ticket = sqOpenOrder(OP_SELL, "Current", mmLots, 0, MagicNumber, "", 0, false, false, CLR_NONE);

      if(_ticket > 0 && OrderSelect(_ticket, SELECT_BY_TICKET)) {
         // set or initialize all order exit methods (SL, PT, Trailing Stop, Exit After Bars, etc.)
         // StopLoss & ProfitTarget

      }


  }

                
   //------------------------
   // Rule: Long exit
   //------------------------
   if (sqIsBarOpen()
      && (LongExitSignal
      && sqMarketPositionIsLong(MagicNumber, "Any", "")))
   {
      // Action #1
      sqClosePosition(OrderLots(), // size: SQ.Formulas.CloseSize.FullPosition
                    MagicNumber, // magic number
                    "Any", // symbol
                    1, // direction
                    "" // comment
       );

  }

                
   //------------------------
   // Rule: Short exit
   //------------------------
   if (sqIsBarOpen()
      && (ShortExitSignal
      && sqMarketPositionIsShort(MagicNumber, "Any", "")))
   {
      // Action #1
      sqClosePosition(OrderLots(), // size: SQ.Formulas.CloseSize.FullPosition
                    MagicNumber, // magic number
                    "Any", // symbol
                    -1, // direction
                    "" // comment
       );

  }

                
   return;
}

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

int OnInit() {
   VerboseLog("--------------------------------------------------------");
   VerboseLog("Starting the EA");

   if(!checkComments()){
      return(INIT_FAILED);
   }

   gPointCoef = calculatePointCoef(Symbol());

   VerboseLog("--------------------------------------------------------");

   if(sqDisplayInfoPanel) {
     sqInitInfoPanel();
   }

   SQTime = new CSQTime();

   if(!IsTesting() && !IsOptimization()) {                                         
      initTimer();
   }
           
   initialBalance = AccountInfoDouble(ACCOUNT_BALANCE);
   
   objDontTradeOnWeekends = new CDontTradeOnWeekends();
   objExitAtEndOfDay = new CExitAtEndOfDay();
   objExitOnFriday = new CExitOnFriday();
   objLimitTimeRange = new CLimitTimeRange();
   objMaxDistanceFromMarket = new CMaxDistanceFromMarket();
   objMaxTradesPerDay = new CMaxTradesPerDay();
   objMinMaxSLPT = new CMinMaxSLPT();
   
   

   double minDistanceMT = NormalizeDouble(MarketInfo(Symbol(), MODE_STOPLEVEL) * MarketInfo(Symbol(), MODE_POINT), Digits);
   double minDistanceSQ = NormalizeDouble(sqMinDistance * sqGetPointCoef(Symbol()), Digits);
   
   if(minDistanceSQ < minDistanceMT){
      VerboseLog("--------------------------------------------------------");
      VerboseLog("Warning! Min distance of this symbol is greater than min distance set in SQ! The backtest results may differ");
      VerboseLog("MT min distance: ", DoubleToStr(minDistanceMT), ", SQ min distance: ", DoubleToStr(minDistanceSQ));
      VerboseLog("--------------------------------------------------------");
   }

   //Show all subchart symbols in market watch

   return(0);
}

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

void OnDeinit(const int reason) {
   sqDeinitInfoPanel();
   
   delete SQTime;
   delete objDontTradeOnWeekends;
   delete objExitAtEndOfDay;
   delete objExitOnFriday;
   delete objLimitTimeRange;
   delete objMaxDistanceFromMarket;
   delete objMaxTradesPerDay;
   delete objMinMaxSLPT;
   
   return;
}
    
//+------------------------------------------------------------------+

bool checkComments(){
   if(StringLen(CustomComment) > 30){
      Alert("Strategy initialization error - Comment CustomComment is longer than 30 characters");
      return false;
   }
   return true;
}

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

void initTimer(){
   int period = 20 * 3600;                //20 hours
   period += MathRand() % (10 * 3600);    //add another 0-10 hours randomly

   if(!EventSetTimer(period)){
      VerboseLog("Cannot set timer. Error code: ", IntegerToString(GetLastError()));
   }
}

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

void OnTimer(){
   //clear unused variables
   int deletedCount = 0;
   
   VerboseLog("Clearing variables...");
   
   for(int a=GlobalVariablesTotal() - 1; a>=0; a--){
      string variableName = GlobalVariableName(a);

      if(GlobalVariableCheck(variableName)){
         string variableNameParts[];
         int parts = StringSplit(variableName, '_', variableNameParts);
         
         if(parts != 3 || variableNameParts[0] != getVariablePrefix()) continue;
         
         int ticketNo = StrToInteger(variableNameParts[1]);
         
         bool variableUsed = false;
         
         for(int i=0; i < OrdersTotal(); i++) {
            if(OrderSelect(i, SELECT_BY_POS) == true) {
               if(OrderTicket() == ticketNo){
                  variableUsed = true;
                  break;
               }
            }
         }
         
         ResetLastError();
         
         if(!variableUsed){
            if(GlobalVariableDel(variableName)){
               deletedCount++;
            }
            else {
               VerboseLog("Cannot delete variable. Error code: ", IntegerToString(GetLastError()));
            }
         }
      }
   }
   
   VerboseLog(IntegerToString(deletedCount), " variables cleared");
}

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

bool sqHandleTradingOptions() {
   bool continueWithBarUpdate = true;

   if(!objDontTradeOnWeekends.onBarUpdate()) continueWithBarUpdate = false;
   if(!objExitAtEndOfDay.onBarUpdate()) continueWithBarUpdate = false;
   if(!objExitOnFriday.onBarUpdate()) continueWithBarUpdate = false;
   if(!objLimitTimeRange.onBarUpdate()) continueWithBarUpdate = false;
   if(!objMaxDistanceFromMarket.onBarUpdate()) continueWithBarUpdate = false;
   if(!objMaxTradesPerDay.onBarUpdate()) continueWithBarUpdate = false;
   if(!objMinMaxSLPT.onBarUpdate()) continueWithBarUpdate = false;

   return(continueWithBarUpdate);
}   

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

bool checkMagicNumber(int magicNo){
    if(magicNo == MagicNumber){
         return true;
    }
    return false;
}

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

double sqGetMarketTickSize(string symbol){
   symbol = correctSymbol(symbol);
    
      if(symbol == Symbol()){
         return MainChartTickSizeSQ;
      }
    
   
   return -1;
}

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

double sqGetGlobalSL(string symbol, int orderType, double price) {
   return(sqGetSLLevel(symbol, orderType, price, 1, 0));
}

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

double sqGetGlobalPT(string symbol, int orderType, double price) {
   return(sqGetPTLevel(symbol, orderType, price, 1, 0));
}

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

double sqGetIndicatorByIdentification(string idHash, int shift) {

   return(0);
}


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

double sqGetValueByIdentification(string idHash) {

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   if(idHash == (string) sqStringHash("0")) {
      return (0);
   }

   return(0);
}

//----------------------------------------------------------------------------

void sqManageOrders(int magicNumber) {
   if(_sqIsBarOpen) {
      for(int i=OrdersTotal()-1; i>=0; i--) {
         if (OrderSelect(i,SELECT_BY_POS)==true) {
            if(OrderMagicNumber() != magicNumber || isMarketClosed(OrderSymbol())) {
               continue;
            }  
               
            int ticket = OrderTicket();

            if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
               // handle Exit Methods only for live orders

               sqManageSL2BE(ticket);
               sqManageTrailingStop(ticket);            
               sqManageExitAfterXBars(ticket);               
            }

            sqManageOrderExpiration(ticket);
         }

         if(OrdersTotal() <= 0) return;
      }
   }
}

//----------------------------------------------------------------------------

void sqResetGlobalVariablesForTicket(int ticket) {
   sqSetGlobalVariable(ticket, "sqOrderExpiration", 0);
   sqSetGlobalVariable(ticket, "sqOrderOpenTime", Time[0]);

   sqSetGlobalVariable(ticket, "MoveSL2BE", 0);    
   sqSetGlobalVariable(ticket, "SL2BEAddPips", 0);
   sqSetGlobalVariable(ticket, "TrailingStop", 0);       
   sqSetGlobalVariable(ticket, "TrailingActivation", 0);
   sqSetGlobalVariable(ticket, "ExitAfterBars", 0);
  
}

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

void sqInitStart() {
   // changed recognition of bar open to support also range/renko charts
   if(_sqLastOpenBarTime == 0) {
      _sqLastOpenBarTime = Time[0];
      _sqIsBarOpen = true;
   } 
   else {
      if(_sqLastOpenBarTime != Time[0]) {
        bool processBarOpen = true;

        if(OpenBarDelay > 0) {
           // set bar to open after X minutes from real open
           processBarOpen = false;
  
           long diffInSeconds = TimeCurrent() - Time[0];
           if(diffInSeconds >= OpenBarDelay * 60) {
              processBarOpen = true;
           }
        }
  
        if(processBarOpen) {
           _sqIsBarOpen = true;
           _sqLastOpenBarTime = Time[0];      
        } 
      } 
      else {
         _sqIsBarOpen = false;
      }
   }

   if(_sqIsBarOpen && Bars<30) {
      Print("NOT ENOUGH DATA: Less Bars than 30");
      return;
   }

   if(!IsTesting() && !IsOptimization()) {
      sqTextFillOpens();
      if(_sqIsBarOpen) {
         sqTextFillTotals();
      }
   }
}

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

bool sqIsBarOpen() {
   return(_sqIsBarOpen);
}

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

int sqGetOrderExpiration(int ticket) {
   return (int) sqGetGlobalVariable(ticket, "sqOrderExpiration");
}

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

void sqSetOrderExpiration(int ticket, int bars) {
   sqSetGlobalVariable(ticket, "sqOrderExpiration", bars);
}

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

void sqManageOrderExpiration(int ticket) {
   int tempValue = 0;                                                           
   int barsOpen = 0;

   // Stop/Limit Order Expiration
   if(OrderType() != OP_BUY && OrderType() != OP_SELL) {
      // handle only pending orders
      tempValue = sqGetOrderExpiration(ticket);
      if(tempValue > 0) {
         barsOpen = sqGetOpenBarsForOrder(ticket, tempValue+10);
         if(barsOpen >= tempValue) {
            Verbose("Order with ticket: ", IntegerToString(ticket), " expired");
            sqDeletePendingOrder(ticket);
         }
      }
   }
}

//----------------------------------------------------------------------------

double sqIndicatorHighest(int period, int nthValue, string indicatorIdentification) {     
   if(period > 1000) {
        Alert("Period used for sqIndicatorHighest function is too high. Max value is 1000");
        period = 1000;
   }
   
   if(nthValue < 0 || nthValue >= period) {
       return(-1);
   }
   
   double indicatorValues[1000];
   int i;

   for(i=0; i<1000; i++) {
      indicatorValues[i] = -2147483647;
   }

   for(i=0; i<period; i++) {
      indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i);
   }

   ArraySort(indicatorValues, WHOLE_ARRAY,0,MODE_DESCEND);

   if(nthValue < 0 || nthValue >= period) {
      return(-1);
   }

   return(indicatorValues[nthValue]);
}

//----------------------------------------------------------------------------

double sqIndicatorLowest(int period, int nthValue, string indicatorIdentification) {           
   if(period > 1000) {
        Alert("Period used for sqIndicatorLowest function is too high. Max value is 1000");
        period = 1000;
   }
   
   if(nthValue < 0 || nthValue >= period) {
       return(-1);
   }
   
   double indicatorValues[1000];
   int i;

   for(i=0; i<1000; i++) {
      indicatorValues[i] = 2147483647;
   }

   for(i=0; i<period; i++) {
      indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i);
   }

   ArraySort(indicatorValues,WHOLE_ARRAY,0,MODE_ASCEND);

   if(nthValue < 0 || nthValue >= period) {
      return(-1);
   }

   return(indicatorValues[nthValue]);
}

//----------------------------------------------------------------------------

double sqIndicatorAverage(int period, int maMethod, string indicatorIdentification) {
   double indicatorValues[10000];

   for(int i=0; i<period; i++) {
      indicatorValues[i] = sqGetIndicatorByIdentification(indicatorIdentification, i);
   }

   double maValue = iMAOnArray(indicatorValues, period, period, 0, maMethod, 0);

   return(maValue);
}


//----------------------------------------------------------------------------

double sqIndicatorRecent(int barsBack, string indicatorIdentification) {
   return(sqGetIndicatorByIdentification(indicatorIdentification, barsBack));
}

//----------------------------------------------------------------------------

bool sqIsRising(string indicatorIdentification, int bars, bool allowSameValues, int shift) {
   bool atLeastOnce = false;

   double previousValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1), 6);

   for(int i=1; i<bars; i++) {
      double currentValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1-i), 6);

      if(currentValue < previousValue) {
         // indicator was falling
         return(false);
      }
      if(currentValue == previousValue && allowSameValues == false) {
         // indicator was the same, not allowed
         return(false);
      }
      if(currentValue > previousValue) {
         atLeastOnce = true;
      }

      previousValue = currentValue;
   }

   if(atLeastOnce) {
      return(true);
   }

   // indicator was not rising once
   return(false);
}

//----------------------------------------------------------------------------

bool sqIsFalling(string indicatorIdentification, int bars, bool allowSameValues, int shift) {
   bool atLeastOnce = false;

   double previousValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1), 6);

   for(int i=1; i<bars; i++) {
      double currentValue = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentification, bars+shift-1-i), 6);

      if(currentValue > previousValue) {
         // indicator was rising
         return(false);
      }
      if(currentValue == previousValue && allowSameValues == false) {
         // indicator was the same, not allowed
         return(false);
      }
      if(currentValue < previousValue) {
         atLeastOnce = true;
      }

      previousValue = currentValue;
   }

   if(atLeastOnce) {
      return(true);
   }

   // indicator was not falling once
   return(false);
}

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

string getVariablePrefix(){
   return IsTesting() ? "SQX(Test)" : "SQX";
}

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

void sqSetGlobalVariable(int ticket, string name, double value) {
   GlobalVariableSet(getVariablePrefix()+"_"+IntegerToString(ticket)+"_"+name, value);
}

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

double sqGetGlobalVariable(int ticket, string name) {
   return (GlobalVariableGet(getVariablePrefix()+"_"+IntegerToString(ticket)+"_"+name));
}

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

int sqStringHash(string str){
   int i, h=0, k;
   for (i=0; i<StringLen(str); i++){
      k = StringGetChar(str, i);
      h = (h << 5) + h + k;
   }
   return(h);
}

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

void sqClosePosition(double size, int magicNumber, string symbol, int direction, string comment) {
   Verbose("Closing order with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment);

   if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) {
      Verbose("Order cannot be found");
   } else {
      if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
         sqClosePositionAtMarket(size);
      } else {
         sqDeletePendingOrder(OrderTicket());
      }
   }

   Verbose("Closing order finished ----------------");
}

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

void sqClosePendingOrder(int magicNumber, string symbol, int direction, string comment) {
   Verbose("Closing pending order with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment);

   if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false, true)) {
      Verbose("Order cannot be found");
   } else {
      sqDeletePendingOrder(OrderTicket());
   }

   Verbose("Closing pending order finished ----------------");
}

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

void sqCloseAllPendingOrders(int magicNumber, string symbol, int direction, string comment) {
   Verbose("Closing pending orders with Magic Number: ", IntegerToString(magicNumber), ", symbol: ", symbol, ", direction: ", IntegerToString(direction), ", comment: ", comment);

   while(sqSelectOrder(magicNumber, symbol, direction, comment, false, false, true)) {
      sqDeletePendingOrder(OrderTicket());
   }

   Verbose("Closing pending orders finished ----------------");
}

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

int sqGetOpenBarsForOrder(int ticket, int expBarsPeriod) {
   datetime opTime;

   if (OrderType() == OP_BUY || OrderType() == OP_SELL) {             //live order
       opTime = OrderOpenTime();
   }
   else {                                                         //pending order
       opTime = (datetime) sqGetGlobalVariable(ticket, "sqOrderOpenTime");
   }

   int numberOfBars = 0;
   int limit = MathMin(expBarsPeriod + 10, Bars);

   for(int i=0; i<limit; i++) {
      if(opTime < Time[i]) {
         numberOfBars++;
      }
   }

   return(numberOfBars);
}

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

void Verbose(string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="", string s13="", string s14="" ) {
   if(sqVerboseMode == 0) {
      return;
   } 
    
   if(sqVerboseMode == 1 && (IsTesting() || IsOptimization())) {
      return;
   }
   
   Print("- SQ LOG ", TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14);
}


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

void VerboseLog(string s1, string s2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
   if(sqVerboseMode != 1) {
      Log(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
   }

   Verbose(s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
}

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

void Log(string s1, string s2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
   Print(TimeToStr(TimeCurrent()), " ", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
}

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

void sqLog(string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
   Print(TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
}


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

void sqLogToFile(string fileName, string st1, string st2="", string s3="", string s4="", string s5="", string s6="", string s7="", string s8="", string s9="", string s10="", string s11="", string s12="" ) {
   int handle = FileOpen(fileName, FILE_READ | FILE_WRITE, ";");
   if(handle>0) {
      FileSeek(handle,0,SEEK_END);
      FileWrite(handle, TimeToStr(TimeCurrent()), " ", st1, st2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12);
      FileClose(handle);
   }
}

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

bool sqSelectOrder(int magicNumber, string symbol, int direction, string comment, bool goFromNewest=true, bool skipPending=true, bool skipFilled=false) {
    int cc = 0;
    
    if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
    }
    
    if(goFromNewest){
       for (cc = OrdersTotal() - 1; cc >= 0; cc--) {
           if(orderFits(cc, magicNumber, symbol, direction, comment, skipPending, skipFilled)){
              return true;
           }
       }
    }
    else {
       for (cc = 0; cc < OrdersTotal(); cc++) {
           if(orderFits(cc, magicNumber, symbol, direction, comment, skipPending, skipFilled)){
              return true;
           }
       }
    }
    return(false);
}

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

bool orderFits(int index, int magicNumber, string symbol, int direction, string comment, bool skipPending=true, bool skipFilled=false){
    if (OrderSelect(index, SELECT_BY_POS)) {
       // skip pending orders
       if(skipPending && (OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT)) {
          return false;
       }
       // skip filled orders
       if(skipFilled && (OrderType() == OP_BUY || OrderType() == OP_SELL)) {
          return false;
       }

       if(direction != 0) {
          if(direction > 0 && (OrderType() != OP_BUY && OrderType() != OP_BUYSTOP && OrderType() != OP_BUYLIMIT)) return false;
          if(direction < 0 && (OrderType() != OP_SELL && OrderType() != OP_SELLSTOP && OrderType() != OP_SELLLIMIT)) return false;
       }

       if(magicNumber != 0) {
          if(!checkMagicNumber(OrderMagicNumber()) || OrderMagicNumber() != magicNumber) return false;
       }

       if(symbol != "Any") {
          if(OrderSymbol() != correctSymbol(symbol)) return false;
       }

     if(comment != "") {
       if(StringFind(OrderComment(), comment) == -1) return false;
     }

     // otherwise we found the order
     return(true);
   }
   else return false;
}

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

void sqCloseAllPositions(string symbol, int magicNumber, int direction, string comment) {
   int count = 100; // maximum number of positions to close
   int lastTicket = -1;

   while(count > 0) {
      count--;
      if(!sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) {
         // no position found
         break;
      }

      if(lastTicket == OrderTicket()) {
         // trying to close the same position one more time, there must be some error
         break;
      }
      lastTicket = OrderTicket();

      if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
         sqClosePositionAtMarket(OrderLots());
      } else {
         sqDeletePendingOrder(OrderTicket());
      }
   }
}

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

void sqCloseBestPosition(string symbol, int magicNumber, int direction, string comment) {
   double maxPL = -100000000;
   int ticket = 0;
   
   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS)) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }
         else if(!checkMagicNumber(OrderMagicNumber())) continue;
         
         if(OrderProfit() > maxPL) {
            // found order with better profit
            maxPL = OrderProfit();
            ticket = OrderTicket();
            Verbose("Better position found, ticket: ", IntegerToString(ticket),", PL: ", DoubleToString(maxPL));
         }
      }
   }

   if(ticket > 0) {
      if(OrderSelect(ticket, SELECT_BY_TICKET)) {
         sqClosePositionAtMarket(OrderLots());
      }
   }
}

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

void sqCloseWorstPosition(string symbol, int magicNumber, int direction, string comment) {
   double minPL = 100000000;
   int ticket = 0;

   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS)) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }  
         else if(!checkMagicNumber(OrderMagicNumber())) continue;
         
         if(OrderProfit() < minPL) {
            // found order with worse profit
            minPL = OrderProfit();
            ticket = OrderTicket();
            Verbose("Worse position found, ticket: ", IntegerToString(ticket),", PL: ", DoubleToString(minPL));
         }
      }
   }

   if(ticket > 0) {
      if(OrderSelect(ticket, SELECT_BY_TICKET)) {
         sqClosePositionAtMarket(OrderLots());
      }
   }
}

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

int sqGetMarketPosition(string symbol, int magicNumber, string comment) {
   if(sqSelectOrder(magicNumber, symbol, 0, comment, false)) {
      if(OrderType() == OP_BUY) {
         return(1);
      } else {
         return(-1);
      }
   }
   return(0);
}                     

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

bool sqMarketPositionIsShort(int magicNo, string symbol, string comment){
   return sqSelectOrder(magicNo, symbol, -1, comment, false);
}    

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

bool sqMarketPositionIsNotShort(int magicNo, string symbol, string comment){
   if(sqSelectOrder(magicNo, symbol, -1, comment, false)) {
      return false;     
     }
     
     return true;
}     

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

bool sqMarketPositionIsLong(int magicNo, string symbol, string comment){
   return sqSelectOrder(magicNo, symbol, 1, comment, false);
}     

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

bool sqMarketPositionIsNotLong(int magicNo, string symbol, string comment){
   if(sqSelectOrder(magicNo, symbol, 1, comment, false)) {
      return false;     
     }
     
     return true;
}     

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

bool sqMarketPositionIsFlat(int magicNo, string symbol, string comment){
   return sqGetMarketPosition(symbol, magicNo, comment) == 0;
}

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

double sqGetOrderOpenPrice(string symbol, int magicNumber, int direction, string comment) {
   if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) {
      return(OrderOpenPrice());
   }
   return(-1);
}

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

double sqGetOrderStopLoss(string symbol, int magicNumber, int direction, string comment) {
   if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) {
      return(OrderStopLoss());
   }
   return(-1);
}

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

double sqGetOrderProfitTarget(string symbol, int magicNumber, int direction, string comment) {
   if(sqSelectOrder(magicNumber, symbol, direction, comment, false)) {
      return(OrderTakeProfit());
   }
   return(-1);
}

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

double sqGetMarketPositionSize(string symbol, int magicNumber, int direction, string comment) {
   double lots = 0;

   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS)) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(direction != 0) {
            if(direction > 0 && OrderType() != OP_BUY) continue;
            if(direction < 0 && OrderType() != OP_SELL) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         } 
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         if(comment != "") {
            if(StringFind(OrderComment(), comment) == -1) continue;
         }

         lots += OrderLots();
      }
   }

   return(lots);
}

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

double sqGetOpenPL(string symbol, int magicNumber, int direction, string comment) {
   double pl = 0;

   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS)) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(direction != 0) {
            if(direction > 0 && OrderType() != OP_BUY) continue;
            if(direction < 0 && OrderType() != OP_SELL) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }    
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         if(comment != "") {
            if(StringFind(OrderComment(), comment) == -1) continue;
         }

         pl += OrderProfit();
      }
   }

   return(pl);
}

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

double sqGetOpenPLInPips(string symbol, int magicNumber, int direction, string comment) {
   double pl = 0;

   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS)) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(direction != 0) {
            if(direction > 0 && OrderType() != OP_BUY) continue;
            if(direction < 0 && OrderType() != OP_SELL) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }  
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         if(comment != "") {
            if(StringFind(OrderComment(), comment) == -1) continue;
         }

         if(OrderType() == OP_BUY) {
            pl += sqGetBid(OrderSymbol()) - OrderOpenPrice();
         } else {
            pl += OrderOpenPrice() - sqGetAsk(OrderSymbol());
         }
      }
   }

   return(sqConvertToPips(OrderSymbol(), pl));
}

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

double sqGetClosedPLInPips(string symbol, int magicNumber, int direction, string comment, int shift) {
   int index = 0;

   for(int i=OrdersHistoryTotal(); i>=0; i--) {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true ) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(direction != 0) {
            if(direction > 0 && OrderType() != OP_BUY) continue;
            if(direction < 0 && OrderType() != OP_SELL) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }     
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         if(comment != "") {
            if(StringFind(OrderComment(), comment) == -1) continue;
         }

         if(index == shift) {
            if(OrderType() == OP_BUY) {
               return(sqConvertToPips(OrderSymbol(), OrderClosePrice() - OrderOpenPrice()));
            } else {
               return(sqConvertToPips(OrderSymbol(), OrderOpenPrice() - OrderClosePrice()));
            }
         }

         index++;
      }
   }

   return(0);
}

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

double sqGetClosedPLInMoney(string symbol, int magicNumber, int direction, string comment, int shift) {
   int index = 0;

   for(int i=OrdersHistoryTotal(); i>=0; i--) {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true ) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(direction != 0) {
            if(direction > 0 && OrderType() != OP_BUY) continue;
            if(direction < 0 && OrderType() != OP_SELL) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }      
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         if(comment != "") {
            if(StringFind(OrderComment(), comment) == -1) continue;
         }

         if(index == shift) {
            return(OrderProfit());
         }

         index++;
      }
   }

   return(0);
}

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

int sqGetMarketPositionCount(string symbol, int magicNumber, int direction, string comment) {
   int count = 0;

   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS)) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP ||OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(direction != 0) {
            if(direction > 0 && OrderType() != OP_BUY) continue;
            if(direction < 0 && OrderType() != OP_SELL) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }   
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         if(comment != "") {
            if(StringFind(OrderComment(), comment) == -1) continue;
         }

         count++;
      }
   }

   return(count);
}

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

int sqGetBarsSinceOpen(string symbol, int magicNumber, int direction, string comment) {
   if(sqSelectOrder(magicNumber, symbol, direction, comment, false, false)) {
      datetime opTime = OrderOpenTime();

      int numberOfBars = 0;
      int limit = MathMin(10000, Bars);

      for(int i=0; i<limit; i++) {
         if(opTime < Time[i]) {
            numberOfBars++;
         }
      }

      return(numberOfBars);
   }

   return(-1);
}

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

int sqGetBarsSinceClose(string symbol, int magicNumber, int direction, string comment) {
   if(sqSelectOrderInHistory(magicNumber, symbol, direction, comment)) {
      datetime clTime = OrderCloseTime();

      int numberOfBars = 0;
      int limit = MathMin(10000, Bars);

      for(int i=0; i<limit; i++) {
         if(clTime < Time[i]) {
            numberOfBars++;
         }
      }

      return(numberOfBars);
   }

   return(-1);
}


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

int sqGetLastOrderType(string symbol, int magicNumber, string comment) {
   if(sqSelectOrderInHistory(magicNumber, symbol, 0, comment)) {
      if(OrderType() == OP_BUY || OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT) {
         return(1);
      } else {
         return(-1);
      }
   }

   return(0);
}

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

bool sqSelectOrderInHistory(int magicNumber, string symbol, int direction, string comment) {
   for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS,MODE_HISTORY)) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(direction != 0) {
            if(direction > 0 && OrderType() != OP_BUY) continue;
            if(direction < 0 && OrderType() != OP_SELL) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }   
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

       if(symbol != "Any") {
         if(OrderSymbol() != correctSymbol(symbol)) continue;
       }

       if(comment != "") {
         if(StringFind(OrderComment(), comment) == -1) continue;
       }

       // otherwise we found the order
       return(true);
     }
   }

   return(false);
}

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

bool sqSelectPendingOrderByType(int magicNumber, string symbol, int orderType, string comment) {
   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS)) {
         if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
            continue;
         }
         
         if(orderType != 0) {
            if(OrderType() != orderType) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }   
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         if(comment != "") {
            if(StringFind(OrderComment(), comment) == -1) continue;
         }

         // otherwise we found the order
         return(true);
      }
   }

   return(false);
}

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

bool sqSelectPendingOrderByDir(int magicNumber, string symbol, int direction, string comment) {
   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS)) {
         if(OrderType() == OP_BUY || OrderType() == OP_SELL) {
            continue;
         }
       
         if(direction != 0) {
            int orderDirection = sqGetDirectionFromOrderType(OrderType());
            if(orderDirection != direction) continue;
         }

         if(magicNumber != 0) {
            if(OrderMagicNumber() != magicNumber) continue;
         }     
         else if(!checkMagicNumber(OrderMagicNumber())) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         if(comment != "") {
           if(StringFind(OrderComment(), comment) == -1) continue;
         }

         // otherwise we found the order
         return(true);
      }
   }

   return(false);
}
//+------------------------------------------------------------------+

bool sqClosePositionAtMarket(double size) {
   int ticket = OrderTicket();

   Verbose("Closing order with ticket: ", IntegerToString(ticket));

   int orderType = OrderType();

   if(orderType != OP_BUY && orderType != OP_SELL) {
      Verbose("Trying to close non-live order");
      return(false);
   }
   if(!sqCheckConnected()) {
      return(false);
   }

   bool result;

   double price = sqGetClosePrice(orderType, OrderSymbol(), 0);
   result = OrderCloseReliable(ticket, size, price, correctSlippage(sqMaxCloseSlippage, OrderSymbol()));
   if(result) {
      Verbose("Order deleted successfuly");
      return(true);
   }

   return(false);
}

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

double sqGetAsk(string symbol) {
   if(symbol == "NULL" || symbol == "Current") {
     return(NormalizeDouble(Ask, Digits));
   } else {
     return(NormalizeDouble(MarketInfo(correctSymbol(symbol),MODE_ASK), Digits));
   }
}

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

double sqGetBid(string symbol) {
   if(symbol == "NULL" || symbol == "Current") {
     return(NormalizeDouble(Bid, Digits));
   } else {
     return(NormalizeDouble(MarketInfo(correctSymbol(symbol),MODE_BID), Digits));
   }
}

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

bool sqDeleteOrder(int ticket){
   if(!OrderSelect(ticket, SELECT_BY_TICKET)){
      Verbose("Warning! Cannot delete order - order with ticket ", IntegerToString(ticket), " can't be selected");
      return false;
   }

   if(sqIsPendingOrder(OrderType())){
      return OrderDeleteReliable(ticket);
   }
   else {
      return OrderCloseReliableMKT(ticket, OrderLots(), sqGetDirectionFromOrderType(OrderType()) == 1 ? Bid : Ask, correctSlippage(0, OrderSymbol()));
   }
}

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

bool sqDeletePendingOrder(int ticket) {
   Verbose(" Deleting pending order, ticket: " + IntegerToString(ticket));

   int orderType = OrderType();

   if(orderType == OP_BUY || orderType == OP_SELL) {
      Verbose("Trying to delete non-pending order");
      return(false);
   }
   if(!sqCheckConnected()) {
      return(false);
   }
         
   bool result = OrderDeleteReliable(ticket);
   if(result) {
      Verbose("Order deleted successfuly");
      return(true);
   }
   
   return(false);
}

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

int sqOpenOrder(int orderType, string symbol, double size, double price, int magicNumber, string comment, datetime expirationInTime, bool replaceExisting, bool allowDuplicateTrades, color arrowColor, const bool isExitLevel = false) {
   if(size <= 0) return (0);

   string correctedSymbol = correctSymbol(symbol);

   if(isMarketClosed(correctedSymbol)){
      return 0;
   }

   double ask = sqGetAsk(correctedSymbol);
   double bid = sqGetBid(correctedSymbol);
   
   int direction = sqGetDirectionFromOrderType(orderType);
   
   double marketPrice = direction == 1 ? ask : bid;

   price = (orderType == OP_BUY || orderType == OP_SELL) ? marketPrice : price;               
   price = sqFixMarketPrice(price, correctedSymbol);

      if(LimitMaxDistanceFromMarketPrice && (orderType != OP_BUY && orderType != OP_SELL)){
      double pctDistance = NormalizeDouble(MathAbs(price-marketPrice) / marketPrice * 100, 2);
      if(pctDistance > NormalizeDouble(MaxDistanceFromMarketPct, 2)){
         Verbose("Order skipped - too far from market price. Open price: ", DoubleToStr(price), ", Market price: ", DoubleToStr(marketPrice), ", Max distance: ", DoubleToStr(MaxDistanceFromMarketPct), "%"); 
         return(0);  
      }
   }
   
   openingOrdersAllowed = openingOrdersAllowed && sqHandleTradingOptions();
   
   if(!openingOrdersAllowed) return(0);                                                        

   Verbose("Opening order type ", OrderTypeToString(orderType)," with price ", DoubleToString(price), ". Current market prices: ", DoubleToString(ask), " / ", DoubleToString(bid));

   // check if live order exists
   if(!isExitLevel && sqSelectOrder(magicNumber, correctedSymbol, 0, comment) && !allowDuplicateTrades) {
      Verbose("Order with these parameters already exists and duplicate trades are not allowed. Canceling order...");
      Verbose("----------------------------------");
      return(0);
   }

   // check if pending order exists
   if(!isExitLevel){
      while(sqSelectOrder(magicNumber, correctedSymbol, direction, comment, false, false, true)) {
         if(replaceExisting) {
         
            if(!strategyUsesATM && ModifyInsteadOfReplacing && size == OrderLots()) {
               // modify existing pending order
               if(OrderModifyReliable(OrderTicket(), price, 0, 0, expirationInTime)) {
                  // reset global variables for this order
                  sqResetGlobalVariablesForTicket(OrderTicket());
                  return ( OrderTicket() );
               
               } else {
                  Verbose("Modifying order failed, deleting it");
                  sqDeletePendingOrder(OrderTicket());
                  return(0);
               }
            } else {
               // delete existing pending order
               sqDeletePendingOrder(OrderTicket());
            }
   
         } else {
            Verbose("Pending Order with these parameters already exists, and replace is not allowed. Canceling order...", " ----------------");
            return(0);
         }
      }
   }

   if(!checkOrderPriceValid(orderType, correctedSymbol, price, marketPrice)){
      return 0;
   }

   //check free margin
   if(AccountFreeMarginCheck(correctedSymbol, isLongOrder(orderType) ? OP_BUY : OP_SELL, size) <= 0 || GetLastError()==134) {
      Alert("Balance too low for trading!");
      return(0);
    }

   string commentToUse = "";
   if(comment != ""){
      commentToUse = comment;
   }
   else {
      commentToUse = CustomComment;
   }

   int ticket = OrderSendReliable(correctedSymbol, orderType, size, price, correctSlippage(sqMaxEntrySlippage, correctedSymbol), 0, 0, commentToUse, magicNumber, expirationInTime, arrowColor);

   if(ticket > 0) {
      // reset global variables for this order
      sqResetGlobalVariablesForTicket(ticket);
   }

     return(ticket);
}

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

bool isLongOrder(int orderType){
   return orderType == OP_BUY || orderType == OP_BUYLIMIT || orderType == OP_BUYSTOP;
}

//----------------------------------------------------------------------------

int correctSlippage(int slippage, string symbol = NULL){
    if(slippage <= 0) return 100000;
    
    if(autoCorrectMaxSlippage){
       int realDigits = (int) MarketInfo(correctSymbol(symbol), MODE_DIGITS);
       if(realDigits > 0 && realDigits != 2 && realDigits != 4) {
          return slippage * 10;
       }
    }
    
    return slippage;
}

//----------------------------------------------------------------------------

bool checkOrderPriceValid(int orderType, string symbol, double price, double marketPrice){
   if(orderType == OP_BUY || orderType == OP_SELL){
      if(marketPrice == price){
         return true;
      }
      else {
         Verbose("Based on its logic, the strategy tried to place order a market order at incorrect price. Market price: ", DoubleToString(marketPrice), ", order price: ", DoubleToString(price), " (this is NOT an error)");
         return false;
      }
   }
   
   return checkStopPriceValid(orderType, symbol, price, marketPrice, "stop/limit order");
}

//----------------------------------------------------------------------------

bool checkStopPriceValid(int orderType, string symbol, double price, double marketPrice, string name){
   int stopLevel = (int) MarketInfo(symbol, MODE_STOPLEVEL);
   double point = MarketInfo(symbol, MODE_POINT);
   double minDistance = point * stopLevel;
   double minDistanceSQ = sqMinDistance * sqGetPointCoef(symbol);
   
   if(minDistanceSQ > minDistance){
      minDistance = minDistanceSQ;
   }
   
   double priceLevel;
   
   if(orderType == OP_BUYLIMIT || orderType == OP_SELLSTOP){
      priceLevel = marketPrice - minDistance;
      
      if(price <= priceLevel){
         return true;
      }
      else {
         Verbose("Based on its logic, the strategy tried to place ", name, " at incorrect price. Market price: ", DoubleToString(marketPrice), ", max. price allowed: ", DoubleToString(priceLevel), ", ", name, " price: ", DoubleToString(price), " (this is NOT an error)");
         return false;
      }
   }
   else if(orderType == OP_BUYSTOP || orderType == OP_SELLLIMIT){
      priceLevel = marketPrice + minDistance;
      
      if(price >= priceLevel){
         return true;
      }
      else {
         Verbose("Based on its logic, the strategy tried to place ", name, " at incorrect price. Market price: ", DoubleToString(marketPrice), ", min. price allowed: ", DoubleToString(priceLevel), ", ", name," price: ", DoubleToString(price), " (this is NOT an error)");
         return false;
      }
   }
   else return true;
}   

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

int sqGetDirectionFromOrderType(int orderType) {
   if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
      return(1);
   } else {
      return(-1);
   }
}

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

bool sqIsPendingOrder(int orderType) {
   if(orderType != OP_BUY && orderType != OP_SELL) {
      return(true);
   }
   return(false);
}

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

void sqSetSLandPT(int ticket, double sl, double pt) {
   if(sl == 0 && pt == 0) return;
   
   if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
      Verbose("Cannot select order with ticket: ",IntegerToString(ticket));
      return;
   }
   
   if(sl == OrderOpenPrice()) {
      Verbose("SL is the same as order price, cannot set it, so we'll delete the order!");
      if(!sqDeleteOrder(ticket)) {
         Verbose("Warning! Cannot delete order and SL/PT was not set! Error: ", IntegerToString(GetLastError()));
      }

      return;
   }

   if(pt == OrderOpenPrice()) {
      pt = 0;
   }
   
   if(sl > 0 || pt > 0) {
      bool result = sqOrderModify(ticket, OrderOpenPrice(), sqFixMarketPrice(sl, OrderSymbol()), sqFixMarketPrice(pt, OrderSymbol()));
      if(!result) {
         Verbose("Cannot set SL / PT for this order, deleting it!");
         if(!sqDeleteOrder(ticket)){
            Verbose("Warning! Cannot delete order and SL/PT was not set! Error: ", IntegerToString(GetLastError()));
         }
      }
   }
}

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

bool sqOrderModifySL(int ticket,double stopLoss, int type) {
   if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
      Verbose("Cannot select order with ticket: ",IntegerToString(ticket));
   }

   if(type == SLPTTYPE_RANGE) {
      // convert range to price level
      if(sqGetDirectionFromOrderType(OrderType()) == 1) {
         // it is long order
         stopLoss = OrderOpenPrice() - stopLoss;
      } else {
         stopLoss = OrderOpenPrice() + stopLoss;
      }
   }

   return(sqOrderModify(ticket, OrderOpenPrice(), sqFixMarketPrice(stopLoss, OrderSymbol()), OrderTakeProfit()));
}

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

bool sqOrderModifyPT(int ticket,double profitTarget, int type) {
   if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
      Verbose("Cannot select order with ticket: ",IntegerToString(ticket));
   }

   if(type == SLPTTYPE_RANGE) {
      // convert range to price level
      if(sqGetDirectionFromOrderType(OrderType()) == 1) {
         // it is long order
         profitTarget = OrderOpenPrice() + profitTarget;
      } else {
         profitTarget = OrderOpenPrice() - profitTarget;
      }
   }

   return(sqOrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), sqFixMarketPrice(profitTarget, OrderSymbol())));
}

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

bool sqOrderModify(int ticket, double price, double stopLoss, double profitTarget) {
   if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
      Verbose("Cannot select order with ticket: ",IntegerToString(ticket));
   }

   int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS);
   if (digits > 0) {
      stopLoss = NormalizeDouble(stopLoss, digits);
      profitTarget = NormalizeDouble(profitTarget, digits);
    }

   Verbose("Modifying order with ticket: ", IntegerToString(ticket), ", SL: ", DoubleToString(stopLoss), " and PT: ", DoubleToString(profitTarget));

   int orderType = OrderType();

   if(!sqCheckConnected()) {
      return(false);
   }

   bool result;
   double closestPossibleSL, closestPossiblePT;

   double point = MarketInfo(OrderSymbol(), MODE_POINT);
   double minStopLevel = MarketInfo(OrderSymbol(),MODE_STOPLEVEL);
   
   if(stopLoss > 0) {
      // check if SL isn't too close to price
      if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
         if(orderType == OP_BUY) {
            closestPossibleSL = NormalizeDouble(Bid-minStopLevel*point, digits);
         } else {
            closestPossibleSL = NormalizeDouble(OrderOpenPrice()-minStopLevel*point, digits);
         }

         if(stopLoss > closestPossibleSL) {
            Verbose("Cannot modify SL, it cannot be closer than minimum allowed: ", DoubleToString(stopLoss), " > ", DoubleToString(closestPossibleSL));
            return(false);
         }

      } else {
         if(orderType == OP_SELL) {
            closestPossibleSL = NormalizeDouble(Ask+minStopLevel*point, digits);
         } else {
            closestPossibleSL = NormalizeDouble(OrderOpenPrice()+minStopLevel*point, digits);
         }

         if(stopLoss < closestPossibleSL) {
            Verbose("Cannot modify SL, it cannot be closer than minimum allowed: ", DoubleToString(stopLoss), " < ", DoubleToString(closestPossibleSL));
            return(false);
         }
      }
   }
   
   if(profitTarget > 0) {
      // check if PT isn't too close to price
      if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
         if(orderType == OP_BUY) {
            closestPossiblePT = NormalizeDouble(Bid+minStopLevel*point, digits);
         } else {
            closestPossiblePT = NormalizeDouble(OrderOpenPrice()+minStopLevel*point, digits);
         }

         if(profitTarget < closestPossiblePT) {
            Verbose("Cannot modify PT, it cannot be closer than minimum allowed: ", DoubleToString(profitTarget), " < ", DoubleToString(closestPossiblePT));
            return(false);
         }

      } else {
         if(orderType == OP_SELL) {
            closestPossiblePT = NormalizeDouble(Ask-minStopLevel*point, digits);
         } else {
            closestPossiblePT = NormalizeDouble(OrderOpenPrice()-minStopLevel*point, digits);
         }

         if(profitTarget > closestPossiblePT) {
            Verbose("Cannot modify PT, it cannot be closer than minimum allowed: ", DoubleToString(profitTarget), " > ", DoubleToString(closestPossiblePT));
            return(false);
         }
      }
   }
      
   result = OrderModifyReliable(ticket, price, sqFixMarketPrice(stopLoss, OrderSymbol()), sqFixMarketPrice(profitTarget, OrderSymbol()), OrderExpiration());
   if(result) {
      Verbose("Order modified successfuly");
      return(true);
   }

   return(false);
}

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

double sqGetPrice(int orderType, string symbol, double price) {
   if(price == 0 && (orderType == OP_BUY || orderType == OP_SELL)) {
      // get newest Ask/Bid price for market order
      RefreshRates();
      if(orderType == OP_BUY) {
         price = sqGetAsk(symbol);
      } else {
         price = sqGetBid(symbol);
      }
   }
   
   int digits = (int) MarketInfo(symbol, MODE_DIGITS);

      if (digits > 0) price = NormalizeDouble(price, digits);

   return(price);
}


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

double sqGetClosePrice(int orderType, string symbol, double price) {
   if(price == 0 && (orderType == OP_BUY || orderType == OP_SELL)) {
      // get newest Ask/Bid price for market order
      RefreshRates();
      if(orderType == OP_BUY) {
         price = sqGetBid(symbol);
      } else {
         price = sqGetAsk(symbol);
      }
   }
   
   int digits = (int) MarketInfo(symbol, MODE_DIGITS);

      if (digits > 0) price = NormalizeDouble(price, digits);

   return(price);
}

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

bool sqCheckConnected() {
   if (!IsConnected()) {
      Verbose("Not connected!");
      return(false);
   }
   if (IsStopped()) {
      Verbose("EA stopped!");
      return(false);
   }

   return(true);
}

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

int sleepPeriod = 500; // 0.5 s
int maxSleepPeriod = 20000; // 20 s.

void sqSleep() {
   //if(IsTesting()) return;

   Sleep(sleepPeriod);

   int periods = maxSleepPeriod / sleepPeriod;

   for(int i=0; i<periods; i++) {
      if (MathRand() > 16383) {
         // 50% chance of quitting
         break;
      }

      Sleep(sleepPeriod);
   }
}

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

string sqGetOrderTypeAsString(int type) {
   switch(type) {
      case OP_BUY: return("Buy");
      case OP_SELL: return("Sell");
      case OP_BUYLIMIT: return("Buy Limit");
      case OP_BUYSTOP: return("Buy Stop");
      case OP_SELLLIMIT: return("Sell Limit");
      case OP_SELLSTOP: return("Sell Stop");
   }

   return("Unknown");
}

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

void sqInitInfoPanel() {
      ObjectCreate("line1", OBJ_LABEL, 0, 0, 0);
      ObjectSet("line1", OBJPROP_CORNER, sqLabelCorner);
      ObjectSet("line1", OBJPROP_YDISTANCE, sqOffsetVertical + 0 );
      ObjectSet("line1", OBJPROP_XDISTANCE, sqOffsetHorizontal);
      ObjectSetText("line1", "New strategy", 9, "Tahoma", sqLabelColor);

      ObjectCreate("linec", OBJ_LABEL, 0, 0, 0);
      ObjectSet("linec", OBJPROP_CORNER, sqLabelCorner);
      ObjectSet("linec", OBJPROP_YDISTANCE, sqOffsetVertical + 16 );
      ObjectSet("linec", OBJPROP_XDISTANCE, sqOffsetHorizontal);
      ObjectSetText("linec", "Generated by StrategyQuant EA Wizard", 8, "Tahoma", sqLabelColor);

      ObjectCreate("line2", OBJ_LABEL, 0, 0, 0);
      ObjectSet("line2", OBJPROP_CORNER, sqLabelCorner);
      ObjectSet("line2", OBJPROP_YDISTANCE, sqOffsetVertical + 28);
      ObjectSet("line2", OBJPROP_XDISTANCE, sqOffsetHorizontal);
      ObjectSetText("line2", "------------------------------------------", 8, "Tahoma", sqLabelColor);

      ObjectCreate("lines", OBJ_LABEL, 0, 0, 0);
      ObjectSet("lines", OBJPROP_CORNER, sqLabelCorner);
      ObjectSet("lines", OBJPROP_YDISTANCE, sqOffsetVertical + 44);
      ObjectSet("lines", OBJPROP_XDISTANCE, sqOffsetHorizontal);
      ObjectSetText("lines", "Last Signal:  -", 9, "Tahoma", sqLabelColor);

      ObjectCreate("lineopl", OBJ_LABEL, 0, 0, 0);
      ObjectSet("lineopl", OBJPROP_CORNER, sqLabelCorner);
      ObjectSet("lineopl", OBJPROP_YDISTANCE, sqOffsetVertical + 60);
      ObjectSet("lineopl", OBJPROP_XDISTANCE, sqOffsetHorizontal);
      ObjectSetText("lineopl", "Open P/L: -", 8, "Tahoma", sqLabelColor);

      ObjectCreate("linea", OBJ_LABEL, 0, 0, 0);
      ObjectSet("linea", OBJPROP_CORNER, sqLabelCorner);
      ObjectSet("linea", OBJPROP_YDISTANCE, sqOffsetVertical + 76);
      ObjectSet("linea", OBJPROP_XDISTANCE, sqOffsetHorizontal);
      ObjectSetText("linea", "Account Balance: -", 8, "Tahoma", sqLabelColor);

      ObjectCreate("lineto", OBJ_LABEL, 0, 0, 0);
      ObjectSet("lineto", OBJPROP_CORNER, sqLabelCorner);
      ObjectSet("lineto", OBJPROP_YDISTANCE, sqOffsetVertical + 92);
      ObjectSet("lineto", OBJPROP_XDISTANCE, sqOffsetHorizontal);
      ObjectSetText("lineto", "Total profits/losses so far: -/-", 8, "Tahoma", sqLabelColor);

      ObjectCreate("linetp", OBJ_LABEL, 0, 0, 0);
      ObjectSet("linetp", OBJPROP_CORNER, sqLabelCorner);
      ObjectSet("linetp", OBJPROP_YDISTANCE, sqOffsetVertical + 108);
      ObjectSet("linetp", OBJPROP_XDISTANCE, sqOffsetHorizontal);
      ObjectSetText("linetp", "Total P/L so far: -", 8, "Tahoma", sqLabelColor);
}

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

void sqDeinitInfoPanel() {
   ObjectDelete("line1");
   ObjectDelete("linec");
   ObjectDelete("line2");
   ObjectDelete("lines");
   ObjectDelete("lineopl");
   ObjectDelete("linea");
   ObjectDelete("lineto");
   ObjectDelete("linetp");
}

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

void sqTextFillOpens() {
   ObjectSetText("lineopl", "Open P/L: "+DoubleToStr(sqGetOpenPLInMoney(0), 2), 8, "Tahoma", sqLabelColor);
   ObjectSetText("linea", "Account Balance: "+DoubleToStr(AccountBalance(), 2) , 8, "Tahoma", sqLabelColor);
}

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

void sqTextFillTotals() {
   ObjectSetText("lineto", "Total profits/losses so far: "+DoubleToStr(sqGetTotalProfits(0, 100))+"/"+DoubleToStr(sqGetTotalLosses(0, 100)), 8, "Tahoma", sqLabelColor);
   ObjectSetText("linetp", "Total P/L so far: "+DoubleToStr(sqGetTotalClosedPLInMoney(0, 1000), 2), 8, "Tahoma", sqLabelColor);
}


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

double sqGetOpenPLInMoney(int orderMagicNumber) {
   double pl = 0;

   if(orderSelectTimeout > 0){
       Sleep(orderSelectTimeout);
   }
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if(OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
      if(OrderSymbol() != Symbol()) continue;
      if(orderMagicNumber != 0 && OrderMagicNumber() != orderMagicNumber) continue;

      pl += OrderProfit();
   }

   return(pl);
}

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

int sqGetTotalProfits(int orderMagicNumber, int numberOfLastOrders) {
   double pl = 0;
   int count = 0;
   int profits = 0;

   for(int i=OrdersHistoryTotal(); i>=0; i--) {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) {

         if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) {
            // return the P/L of last order
            // or return the P/L of last order with given Magic Number
            count++;

            if(OrderType() == OP_BUY) {
               pl = (OrderClosePrice() - OrderOpenPrice());
            } else {
               pl = (OrderOpenPrice() - OrderClosePrice());
            }

            if(pl > 0) {
               profits++;
            }

            if(count >= numberOfLastOrders) break;
         }
      }
   }

   return(profits);
}

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

int sqGetTotalLosses(int orderMagicNumber, int numberOfLastOrders) {
   double pl = 0;
   int count = 0;
   int losses = 0;

   for(int i=OrdersHistoryTotal(); i>=0; i--) {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) {

         if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) {
            // return the P/L of last order
            // or return the P/L of last order with given Magic Number
            count++;

            if(OrderType() == OP_BUY) {
               pl = (OrderClosePrice() - OrderOpenPrice());
            } else {
               pl = (OrderOpenPrice() - OrderClosePrice());
            }

            if(pl < 0) {
               losses++;
            }

            if(count >= numberOfLastOrders) break;
         }
      }
   }

   return(losses);
}


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

double sqGetTotalClosedPLInMoney(int orderMagicNumber, int numberOfLastOrders) {
   double pl = 0;
   int count = 0;

   for(int i=OrdersHistoryTotal(); i>=0; i--) {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && OrderSymbol() == Symbol()) {
         if(orderMagicNumber == 0 || OrderMagicNumber() == orderMagicNumber) {
            // return the P/L of last order or the P/L of last order with given Magic Number

            count++;
            pl = pl + OrderProfit();

            if(count >= numberOfLastOrders) break;
         }
      }
   }

   return(pl);
}

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

double sqGetSLLevel(string symbol, int orderType, double price, int valueInPips, double value) {
   return(sqGetSLPTLevel(-1.0, symbol, orderType, price, valueInPips, value));
}

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

double sqGetPTLevel(string symbol, int orderType, double price, int valueInPips, double value) {
   return(sqGetSLPTLevel(1.0, symbol, orderType, price, valueInPips, value));
}

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

/**
* valueType: 1 - pips, 2 - real pips (ATR range), 3 - price level
*/
double sqGetSLPTLevel(double SLorPT, string symbol, int orderType, double price, int valueType, double value) {
   string correctedSymbol = correctSymbol(symbol);
   double pointCoef = sqGetPointCoef(symbol);

   if(valueType == 1) {
      // convert from pips to real points
      value = sqConvertToRealPips(correctedSymbol, value);
   }
   
   if(price == 0) {
      // price can be zero for market order
      if(orderType == OP_BUY) {
         price = sqGetAsk(correctedSymbol);
      } else {
         price = sqGetBid(correctedSymbol);
      }
   }
   
   double slptValue = value;
   
   if(valueType != 3) {
      if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
         slptValue = price + (SLorPT * value);
      } else {
         slptValue = price - (SLorPT * value);
      }
   }

   // check that SL / PT is within predefined boundaries
   double minSLPTValue, maxSLPTValue;
   
   if(SLorPT < 0) {
      // it is SL
      
      if(MinimumSL <= 0) {
         minSLPTValue = slptValue;
      } else {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            minSLPTValue = price + (SLorPT * MinimumSL * pointCoef);
            slptValue = MathMin(slptValue, minSLPTValue);
            
         } else {
         
            minSLPTValue = price - (SLorPT * MinimumSL * pointCoef);
            slptValue = MathMax(slptValue, minSLPTValue);
         }
   
      }
      
      if(MaximumSL <= 0) {
         maxSLPTValue = slptValue;
      } else {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            maxSLPTValue = price + (SLorPT * MaximumSL * pointCoef);
            slptValue = MathMax(slptValue, maxSLPTValue);

         } else {
            maxSLPTValue = price - (SLorPT * MaximumSL * pointCoef);
            slptValue = MathMin(slptValue, maxSLPTValue);
         }

      }
      
   } else {
      // it is PT

      if(MinimumPT <= 0) {
         minSLPTValue = slptValue;
      } else {
         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            minSLPTValue = price + (SLorPT * MinimumPT * pointCoef);
            slptValue = MathMax(slptValue, minSLPTValue);
            
         } else {
            minSLPTValue = price - (SLorPT * MinimumPT * pointCoef);
            slptValue = MathMin(slptValue, minSLPTValue);
         }

      }
      
      if(MaximumPT <= 0) {
         maxSLPTValue = slptValue;
      } else {

         if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
            maxSLPTValue = price + (SLorPT * MaximumPT * pointCoef);
            slptValue = MathMin(slptValue, maxSLPTValue);

         } else {
         
            maxSLPTValue = price - (SLorPT * MaximumPT * pointCoef);
            slptValue = MathMax(slptValue, maxSLPTValue);
         }
      }
   }
               
   return (slptValue);
}  

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

double sqConvertToPips(string symbol, double value) {
   if(symbol == "NULL" || symbol == "Current") {
      return(value / gPointCoef);
   }

   // recognize point coeficient         
   double ticksize = sqGetMarketTickSize(symbol);
   if(ticksize < 0){
      ticksize = calculatePointCoef(symbol);
   }

   return(value / ticksize);
}                  
                         
//+------------------------------------------------------------------+

double sqConvertToRealPips(string symbol, double value) {
   if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") {
      return NormalizeDouble(gPointCoef * value, 6);
   }

   double pointCoef = sqGetPointCoef(symbol);

   return NormalizeDouble(pointCoef * value, 6);
}

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

double sqGetPointCoef(string symbol) {
   if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") {
      return(gPointCoef);
   }

   return calculatePointCoef(symbol);
}

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

double calculatePointCoef(string symbol){
   string correctedSymbol = correctSymbol(symbol);
   
   if(UseSQTickSize) {
      double ticksize = sqGetMarketTickSize(correctedSymbol);
      if(ticksize >= 0){
         return ticksize;
      }
   }
      
   int realDigits = (int) MarketInfo(correctedSymbol, MODE_DIGITS);
   if(realDigits > 0 && realDigits != 2 && realDigits != 4) {
       realDigits -= 1;
   }
   return 1.0 / MathPow(10, realDigits);
}

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

bool sqDoublesAreEqual(double n1, double n2) {
   string st1 = DoubleToStr(n1, Digits);
   string st2 = DoubleToStr(n2, Digits);

   return (st1 == st2);
}

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

double sqHighest(string symbol, int timeframe, int computedFrom, int period, int shift) {
   double maxnum = -100000000;
   double val;

   for(int i=shift; i<shift+period; i++) {
      val = sqGetValue(symbol, timeframe, computedFrom, i);

      if(val > maxnum) {
         maxnum = val;
      }
   }

   return(maxnum);
}

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

double sqHighestIndex(string symbol, int timeframe, int computedFrom, int period, int shift) {
   double maxnum = -100000000;
   int index = 0;
   double val;

   for(int i=shift; i<shift+period; i++) {
      val = sqGetValue(symbol, timeframe, computedFrom, i);

      if(val > maxnum) {
         maxnum = val;
         index = i;
      }
   }

   return(index);
}

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

double sqLowest(string symbol, int timeframe, int computedFrom, int period, int shift) {
   double minnum = 100000000;
   double val;

   for(int i=shift; i<shift+period; i++) {
      val = sqGetValue(symbol, timeframe, computedFrom, i);

      if(val < minnum) {
         minnum = val;
      }
   }

   return(minnum);
}

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

double sqLowestIndex(string symbol, int timeframe, int computedFrom, int period, int shift) {
   double minnum = 100000000;
   int index = 0;
   double val;

   for(int i=shift; i<shift+period; i++) {
      val = sqGetValue(symbol, timeframe, computedFrom, i);

      if(val < minnum) {
         minnum = val;
         index = i;
      }
   }

   return(index);
}

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

double sqGetValue(string symbol, int timeframe, int computedFrom, int shift) {
   double val = 0;
   
   if(symbol == "NULL" || symbol == "Current") {
      switch(computedFrom) {
         case PRICE_OPEN: val = iOpen(NULL, timeframe, shift); break;
         case PRICE_HIGH: return iHigh(NULL, timeframe, shift); break;
         case PRICE_LOW: val = iLow(NULL, timeframe, shift); break;
         case PRICE_CLOSE: val = iClose(NULL, timeframe, shift); break;
         case PRICE_MEDIAN: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift))/2; break;
         case PRICE_TYPICAL: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift)+iClose(NULL, timeframe, shift))/3; break;
         case PRICE_WEIGHTED: val = (iHigh(NULL, timeframe, shift)+iLow(NULL, timeframe, shift)+iClose(NULL, timeframe, shift)+iClose(NULL, timeframe, shift))/4; break;
      }

   } else {
      switch(computedFrom) {
         case PRICE_OPEN: val = iOpen(symbol, timeframe, shift); break;
         case PRICE_HIGH: val = iHigh(symbol, timeframe, shift); break;
         case PRICE_LOW: val = iLow(symbol, timeframe, shift); break;
         case PRICE_CLOSE: val = iClose(symbol, timeframe, shift); break;
         case PRICE_MEDIAN: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift))/2; break;
         case PRICE_TYPICAL: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift)+iClose(symbol, timeframe, shift))/3; break;
         case PRICE_WEIGHTED: val = (iHigh(symbol, timeframe, shift)+iLow(symbol, timeframe, shift)+iClose(symbol, timeframe, shift)+iClose(symbol, timeframe, shift))/4; break;
      }
   }

   return roundValue(val);
}

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

void sqDrawUpArrow(int shift) {
   string name = StringConcatenate("Arrow_", MathRand());

   ObjectCreate(name, OBJ_ARROW, 0, Time[shift], Low[shift]-100*Point); //draw an up arrow
   ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID);
   ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_ARROWUP);
   ObjectSet(name, OBJPROP_COLOR, Green);
}

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

void sqDrawDownArrow(int shift) {
   string name = StringConcatenate("Arrow_", MathRand());

   ObjectCreate(name, OBJ_ARROW, 0, Time[shift], High[shift]+100*Point); //draw an down arrow
   ObjectSet(name, OBJPROP_STYLE, STYLE_SOLID);
   ObjectSet(name, OBJPROP_ARROWCODE, SYMBOL_ARROWDOWN);
   ObjectSet(name, OBJPROP_COLOR, Red);
}

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

void sqDrawVerticalLine(int shift) {
   string name = StringConcatenate("VerticalLine", MathRand());

   ObjectCreate(name, OBJ_VLINE, 0, Time[shift], 0);                       //draw a vertical line
   ObjectSet(name,OBJPROP_COLOR, Red);
   ObjectSet(name,OBJPROP_WIDTH, 1);
   ObjectSet(name,OBJPROP_STYLE, STYLE_DOT);
}

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

double sqDaily(string symbol, int tf, string mode, int shift) {
   return sqGetOHLC(symbol, PERIOD_D1, mode, shift);
}                

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

double sqWeekly(string symbol, int tf, string mode, int shift) {
   return sqGetOHLC(symbol, PERIOD_W1, mode, shift);
}

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

double sqMonthly(string symbol, int tf, string mode, int shift) {
   return sqGetOHLC(symbol, PERIOD_MN1, mode, shift);
}
  
//+------------------------------------------------------------------+

double sqGetOHLC(string symbol, int tf, string mode, int shift){
   if(symbol == "NULL" || symbol == "Current") {
      if(mode == "Open") {
         return(iOpen(NULL, tf, shift));
      }
      if(mode == "Close") {
         return(iClose(NULL, tf, shift));
      }
      if(mode == "High") {
         return(iHigh(NULL, tf, shift));
      }
      if(mode == "Low") {
         return(iLow(NULL, tf, shift));
      }
   } 
   else {
      if(mode == "Open") {
         return(iOpen(symbol, tf, shift));
      }
      if(mode == "Close") {
         return(iClose(symbol, tf, shift));
      }
      if(mode == "High") {
         return(iHigh(symbol, tf, shift));
      }
      if(mode == "Low") {
         return(iLow(symbol, tf, shift));
      }
   }                 

   return(-1);
}

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

int getHHMM(string time){
   string result[];           
   int k = StringSplit(time, ':', result);
   
   if(k == 2){
      int hour = StrToInteger(StringSubstr(result[0], 0, 1) == "0" ? StringSubstr(result[0], 1, 1) : result[0]);
      int minute = StrToInteger(StringSubstr(result[1], 0, 1) == "0" ? StringSubstr(result[1], 1, 1) : result[1]);
      return (hour * 100) + minute;
   }
   else {
      Print("Incorrect time value format. Value: '" + time + "'");
      return 0;
   }
}

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

int sqGetDate(int day, int month, int year) {
   return (year - 1900) * 10000 + month * 100 + day;
}

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

int sqGetBarDate(datetime dt) {
   return (TimeYear(dt) - 1900) * 10000 + TimeMonth(dt) * 100 + TimeDay(dt);
}

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

double sqGetTime(int hour, int minute, int second) {
   return 100 * hour + minute + 0.01 * second;
}

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

int getSQTime(datetime time){
   int minutesToday = (int) ((ulong) time / 60) % (24 * 60);
   int hours = minutesToday / 60;
   int minutes = minutesToday % 60;
   
   return hours*100 + minutes;
}

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

double sqSafeDivide(double var1, double var2) {
   if(var2 == 0) return(100000000);
   return(var1/var2);
}

//+------------------------------------------------------------------+
//+ Candle Pattern functions
//+------------------------------------------------------------------+

bool sqBearishEngulfing(string symbol, int timeframe, int shift) {
   double O = sqOpen(symbol, timeframe, shift);
   double O1 = sqOpen(symbol, timeframe, shift+1);
   double C = sqClose(symbol, timeframe, shift);
   double C1 = sqClose(symbol, timeframe, shift+1);

   double ocDiff = NormalizeDouble(O-C, _Digits);
   double o1c1Diff = NormalizeDouble(C1-O1, _Digits);

   if ((C1>O1)&&(O>C)&&(O>=C1)&&(O1>=C)&&(ocDiff>o1c1Diff)) {
      return(true);
   }

   return(false);
}

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

bool sqBullishEngulfing(string symbol, int timeframe, int shift) {
   double O = sqOpen(symbol, timeframe, shift);
   double O1 = sqOpen(symbol, timeframe, shift+1);
   double C = sqClose(symbol, timeframe, shift);
   double C1 = sqClose(symbol, timeframe, shift+1);

   double coDiff = NormalizeDouble(C-O, _Digits);
   double o1c1Diff = NormalizeDouble(O1-C1, _Digits);
   
   if ((O1>C1)&&(C>O)&&(C>=O1)&&(C1>=O)&&(coDiff>o1c1Diff)) {
      return(true);
   }

   return(false);
}

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

bool sqDarkCloudCover(string symbol, int timeframe, int shift) {
   double L = sqLow(symbol, timeframe, shift);
   double H = sqHigh(symbol, timeframe, shift);

   double O = sqOpen(symbol, timeframe, shift);
   double O1 = sqOpen(symbol, timeframe, shift+1);
   double C = sqClose(symbol, timeframe, shift);
   double C1 = sqClose(symbol, timeframe, shift+1);
   
     double tickSize = sqGetPointCoef(symbol);

     double Piercing_Line_Ratio = 0.5f;
     double Piercing_Candle_Length = 10.0f;
     
     double HL = NormalizeDouble(H-L, _Digits);
     double OC = NormalizeDouble(O-C, _Digits);
     double OC_HL = HL != 0 ? NormalizeDouble(OC/HL, 6) : 0;
     double O1C1_D2 = NormalizeDouble((O1+C1)/2, _Digits);
     double PCL_MTS = NormalizeDouble(Piercing_Candle_Length*tickSize, _Digits);
             
     if(C1 > O1 && O1C1_D2 > C && O > C && C > O1 && OC_HL > Piercing_Line_Ratio && HL >= PCL_MTS) {
         return true;
     }

   return(false);
}

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

bool sqDoji(string symbol, int timeframe, int shift) {
   double diff = NormalizeDouble(MathAbs(sqOpen(symbol, timeframe, shift) - sqClose(symbol, timeframe, shift)), _Digits);
   double coef = NormalizeDouble(sqGetPointCoef(symbol) * 0.6, _Digits); 
   
   if(diff < coef) {
      return(true);
   }
   
   return(false);
}

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

bool sqHammer(string symbol, int timeframe, int shift) {
   double H = sqHigh(symbol, timeframe, shift);
   double L = sqLow(symbol, timeframe, shift);
   double L1 = sqLow(symbol, timeframe, shift+1);
   double L2 = sqLow(symbol, timeframe, shift+2);
   double L3 = sqLow(symbol, timeframe, shift+3);

   double O = sqOpen(symbol, timeframe, shift);
   double C = sqClose(symbol, timeframe, shift);
   double CL = NormalizeDouble(H-L, _Digits);

   double BodyLow, BodyHigh;
   double Candle_WickBody_Percent = 0.9;
   double CandleLength = 12;

   if (O > C) {
      BodyHigh = O;
      BodyLow = C;
   } else {
      BodyHigh = C;
      BodyLow = O;
   }

   double LW = NormalizeDouble(BodyLow - L, _Digits);
   double UW = NormalizeDouble(H - BodyHigh, _Digits);
   double BLa = NormalizeDouble(MathAbs(O - C), _Digits);
   double BL90 = NormalizeDouble(BLa * Candle_WickBody_Percent, _Digits);
   
   double pipValue = sqGetPointCoef(symbol);
   
   double LW_D2 = NormalizeDouble(LW / 2, _Digits);
   double LW_D3 = NormalizeDouble(LW / 3, _Digits);
   double LW_D4 = NormalizeDouble(LW / 4, _Digits);
   double BL90_M2 = NormalizeDouble(2 * BL90, _Digits);
   double CL_MPV = NormalizeDouble(CandleLength * pipValue, _Digits);
     
   if(L <= L1 && L < L2 && L < L3)  {
         if(LW_D2 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C && LW_D3 <= UW && LW_D4 <= UW)  {
              return(true);
      }
      if(LW_D3 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C && LW_D4 <= UW)  {
          return(true);
      }
      if(LW_D4 > UW && LW > BL90_M2 && CL >= CL_MPV && O != C)  {
              return(true);
      }
   }
   
   return(false);
}

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

bool sqPiercingLine(string symbol, int timeframe, int shift) {
   double L = sqLow(symbol, timeframe, shift);
   double H = sqHigh(symbol, timeframe, shift);

   double O = sqOpen(symbol, timeframe, shift);
   double O1 = sqOpen(symbol, timeframe, shift+1);
   double C = sqClose(symbol, timeframe, shift);
   double C1 = sqClose(symbol, timeframe, shift+1);
   
     double tickSize = sqGetPointCoef(symbol);

     double Piercing_Line_Ratio = 0.5f;
     double Piercing_Candle_Length = 10.0f;
     
     double HL = NormalizeDouble(H-L, _Digits);
     double CO = NormalizeDouble(C-O, _Digits);
     double CO_HL = HL != 0 ? NormalizeDouble(CO/HL, 6) : 0;
     double O1C1_D2 = NormalizeDouble((O1+C1)/2, _Digits);
     double PCL_MTS = NormalizeDouble(Piercing_Candle_Length*tickSize, _Digits);
             
     if(C1 < O1 && O1C1_D2 < C && O < C && C < O1 && CO_HL > Piercing_Line_Ratio && HL >= PCL_MTS) {
         return true;
     }

   return(false);
}

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

bool sqShootingStar(string symbol, int timeframe, int shift) {
   double L = sqLow(symbol, timeframe, shift);
   double H = sqHigh(symbol, timeframe, shift);
   double H1 = sqHigh(symbol, timeframe, shift + 1);
   double H2 = sqHigh(symbol, timeframe, shift + 2);
   double H3 = sqHigh(symbol, timeframe, shift + 3);

   double O = sqOpen(symbol, timeframe, shift);
   double C = sqClose(symbol, timeframe, shift);
   double CL = NormalizeDouble(H - L, _Digits);

   double BodyLow, BodyHigh;
   double Candle_WickBody_Percent = 0.9;
   double CandleLength = 12;

   if (O > C) {
      BodyHigh = O;
      BodyLow = C;
   } else {
      BodyHigh = C;
      BodyLow = O;
   }

   double LW = NormalizeDouble(BodyLow - L, _Digits);
   double UW = NormalizeDouble(H - BodyHigh, _Digits);
   double BLa = NormalizeDouble(MathAbs(O - C), _Digits);
   double BL90 = NormalizeDouble(BLa * Candle_WickBody_Percent, _Digits);
   
   double pipValue = sqGetPointCoef(symbol);
   
   double UW_D2 = NormalizeDouble(UW / 2, _Digits);
   double UW_D3 = NormalizeDouble(UW / 3, _Digits);
   double UW_D4 = NormalizeDouble(UW / 4, _Digits);
   double BL90_M2 = NormalizeDouble(2 * BL90, _Digits);
   double CL_MPV = NormalizeDouble(CandleLength * pipValue, _Digits);

   if(H >= H1 && H > H2 && H > H3)  {
      if(UW_D2 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C && UW_D3 <= LW && UW_D4 <= LW)  {
         return(true);
      }
      if(UW_D3 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C && UW_D4 <= LW)  {
         return(true);
      }
      if(UW_D4 > LW && UW > BL90_M2 && CL >= CL_MPV && O != C)  {
         return(true);
      }
   }

   return(false);


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

double sqOpen(string symbol, int timeframe, int shift) {
   if(symbol == "NULL") {
      return (iOpen(NULL, timeframe, shift));
   } else {
      return (iOpen(symbol, timeframe, shift));
   }
}   

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

double sqHigh(string symbol, int timeframe, int shift) {
   if(symbol == "NULL") {
      return (iHigh(NULL, timeframe, shift));
   } else {
      return (iHigh(symbol, timeframe, shift));
   }
}   

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

double sqLow(string symbol, int timeframe, int shift) {
   if(symbol == "NULL") {
      return (iLow(NULL, timeframe, shift));
   } else {
      return (iLow(symbol, timeframe, shift));
   }
}   

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

double sqClose(string symbol, int timeframe, int shift) {
   if(symbol == "NULL") {
      return (iClose(NULL, timeframe, shift));
   } else {
      return (iClose(symbol, timeframe, shift));
   }
}   


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

double sqTrueRange(string symbol, int timeframe, int shift) {

   double close1 = sqClose(symbol, timeframe, shift+1);
   double high = sqHigh(symbol, timeframe, shift+1);
   double low = sqLow(symbol, timeframe, shift+1);

   double TrueHigh, TrueLow;

    if(close1 > high) {
        TrueHigh = close1;
    } else {
        TrueHigh = high;
    }

    if(close1 < low) {
        TrueLow = close1;
    } else {
        TrueLow = low;
    }

    double TrueRange = TrueHigh - TrueLow;
    
    return (TrueRange);
}   

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

bool sqTradeRecentlyClosed(string symbol, int magicNumber, bool checkThisBar, bool checkThisMinute) {
    int ordersChecked = 0;

    string strCurrentTimeMinutes = TimeToStr( TimeCurrent(), TIME_DATE|TIME_MINUTES);

   for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--) {
      if (OrderSelect(cc, SELECT_BY_POS,MODE_HISTORY)) {

         // skip pending orders
         if(OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT) {
            continue;
         }

         if(magicNumber != 0 && OrderMagicNumber() != magicNumber) continue;

         if(symbol != "Any") {
            if(OrderSymbol() != correctSymbol(symbol)) continue;
         }

         ordersChecked++;
            if(ordersChecked > 10) {
                // check only the very last 10 orders
                break;
            }

            if(checkThisBar) {
                if(OrderCloseTime() >= Time[0]) {
                    // order finished this bar
                    return(true);
                }
            }

            if(checkThisMinute) {
               string strCloseTimeMinutes = TimeToStr( OrderCloseTime(), TIME_DATE|TIME_MINUTES);

                if(strCurrentTimeMinutes == strCloseTimeMinutes) {
                    // order finished this minute
                    return(true);
                }
            }
        }
   }

   return(false);
}
 
//+------------------------------------------------------------------+

double roundDown(double value, int decimals) {
      double p = 0;
      
      switch(decimals) {
          case 0: return (int) value; 
          case 1: p = 10; break;
          case 2: p = 100; break;
          case 3: p = 1000; break;
          case 4: p = 10000; break;
          case 5: p = 100000; break;
          case 6: p = 1000000; break;
          default: p = MathPow(10, decimals);
      }

      value = value * p;
      double tmp = MathFloor(value + 0.00000001);
      return NormalizeDouble(tmp/p, decimals);
}

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

class CSQTime {
public:

   datetime setHHMM(datetime time, string hhmm) {
      string date = TimeToStr(time,TIME_DATE);//"yyyy.mm.dd"
      return (StrToTime(date + " " + hhmm));
   }

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

   datetime correctDayStart(datetime time) {
      MqlDateTime strTime;
      TimeToStruct(time, strTime);
      strTime.hour = 0;
      strTime.min = 0;
      strTime.sec = 0;
      return (StructToTime(strTime));
   }
   
  //+------------------------------------------------------------------+

   datetime getDateInMs(datetime time) {
      MqlDateTime strTime;
      TimeToStruct(time, strTime);
      strTime.hour = 0;
      strTime.min = 0;
      strTime.sec = 0;
      return (StructToTime(strTime));
   }
      
   //+------------------------------------------------------------------+

   datetime correctDayEnd(datetime time) {
      MqlDateTime strTime;
      TimeToStruct(time, strTime);
      strTime.hour = 23;
      strTime.min = 59;
      strTime.sec = 59;
      return (StructToTime(strTime));
   }
   
   //+------------------------------------------------------------------+

   datetime setDayOfMonth(datetime time, int day) {
        MqlDateTime strTime;
        TimeToStruct(time, strTime);
        strTime.day = day;
        return (StructToTime(strTime));
   }
   
   //+------------------------------------------------------------------+

   int getMonth(datetime time) {
      return TimeMonth(time);
   }
   
   //+------------------------------------------------------------------+

   int getDaysInMonth(datetime time) {
      MqlDateTime strTime;
      TimeToStruct(time, strTime);
      if(strTime.mon==2) {
        return  28+isLeapYear(strTime.year);
      }
      
      return 31-((strTime.mon-1)%7)%2;
   }
   
   //+------------------------------------------------------------------+

    bool isLeapYear(const int _year){
       if(_year%4 == 0){
          if(_year%400 == 0)return true;
          if(_year%100 > 0)return true;
       }
       return false;
    }
   
   //+------------------------------------------------------------------+

   datetime addDays(datetime time, int days) {
      int oneDay = 60 * 60 * 24;
      
      return (time + (days * oneDay));
   }
   
   //+------------------------------------------------------------------+

   datetime setDayOfWeek(datetime time, int desiredDow) {
      int dow = convertToSQDOW(TimeDayOfWeek(time));
      desiredDow = convertToSQDOW(desiredDow);
      
      int diffInDays = desiredDow - dow;
      
      //Print("DiffInDays: ", diffInDays, ", dow: ", dow, ", desiredDow: ", desiredDow);
      
      return addDays(time, diffInDays);
   }  
   
   //+------------------------------------------------------------------+

   /**
    * converts from MT DOW format: 0 = Sunday, 1 = Monday ... 6 = Saturday
    * to SQ DOW format: 1 = Monday, 2 = Tuesday ... 7 = Sunday
   */
   int convertToSQDOW(int dow) {
      if(dow == 0) dow = 7;
      
      return(dow);
   } 
};

// create variable for class instance (required)
CSQTime* SQTime;

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

bool sqEvaluateFuzzySignal(int conditionsCount, int minTrueConditions) {

    bool signalValue = false;
  int trueConditionsCount = 0;
   
  if(minTrueConditions <= 0) {
      minTrueConditions = 1;
  }
        
    for(int i=0; i<conditionsCount; i++) {
        bool value = cond[i];
                
        if(value) {
            trueConditionsCount++;
        }
                
        if(trueConditionsCount >= minTrueConditions) {
            signalValue = true;
            break;
        }
    }
            
    return(signalValue);
}

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

string correctSymbol(string symbol){
  if(symbol == "NULL" || symbol == "Current" || symbol == "Same as main chart") {
      return Symbol();
  }
  else return symbol;
}

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

double sqFixMarketPrice(double price, string symbol){             
   symbol = correctSymbol(symbol);
   
   double tickSize = MarketInfo(symbol, MODE_TICKSIZE);  
   
   if(tickSize == 0){
      return price;
   }
       
   int digits = (int) MarketInfo(symbol, MODE_DIGITS);
   double finalPrice = tickSize * MathRound(NormalizeDouble(price, digits) / tickSize);
   return NormalizeDouble(finalPrice, digits);
}
//+------------------------------------------------------------------+

bool sqIsUptrend(string symbol, int timeframe, int method) {
   if(method == 0) {
      return (iClose(symbol, timeframe, 1) > sqMA(symbol, timeframe, 200, 0, MODE_SMA, PRICE_CLOSE, 1));      
     }
     return(false);    
}

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

bool sqIsDowntrend(string symbol, int timeframe, int method) {
   if(method == 0) {
      return (iClose(symbol, timeframe, 1) < sqMA(symbol, timeframe, 200, 0, MODE_SMA, PRICE_CLOSE, 1));      
     }
     return(false);    
}


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

int sqGetMonthLastTradingDay(string symbol, int timeframe, bool includeWeekends) {
    datetime barTime = iTime(symbol, timeframe, 0);
    datetime lastTradingDate = SQTime.setDayOfMonth(barTime, SQTime.getDaysInMonth(barTime));

    if(!includeWeekends) {
        if(TimeDayOfWeek(lastTradingDate) == 6) {
            lastTradingDate = SQTime.addDays(lastTradingDate, -1);
        
        } else if(TimeDayOfWeek(lastTradingDate) == 0) {
            lastTradingDate = SQTime.addDays(lastTradingDate, -2);
        }
    }

    return TimeDay(lastTradingDate);
}

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

datetime monthFirstTradingDay = 0;

bool sqIsMonthFirstTradingDay(string symbol, int timeframe, bool includeWeekends) {
    datetime date = SQTime.getDateInMs(iTime(symbol, timeframe, 0));
    
    if(monthFirstTradingDay == 0) {
        monthFirstTradingDay = date;
    }

    if(SQTime.getMonth(monthFirstTradingDay)!=SQTime.getMonth(date)) {
        if(!includeWeekends) {
            if(TimeDayOfWeek(date) != 6 && TimeDayOfWeek(date) != 0) {
                monthFirstTradingDay = date;
            }
        } else {
            monthFirstTradingDay = date;
        }
    }

    return monthFirstTradingDay==date;
}

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

bool isMarketClosed(string symbol){
   return !IsTesting() && !IsOptimization() && MarketInfo(symbol, MODE_TRADEALLOWED) == 0;
}

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

double fixLotSize(string symbol, double size){
   string correctedSymbol = correctSymbol(symbol);
   double Smallest_Lot = MarketInfo(correctedSymbol, MODE_MINLOT);
   double Largest_Lot = MarketInfo(correctedSymbol, MODE_MAXLOT);    
   double LotStep = MarketInfo(correctedSymbol, MODE_LOTSTEP);

   double mod = MathMod(size, LotStep);
   double finalSize = size;
   
   if(MathAbs(mod - LotStep) > 0.000001){
      finalSize -= mod;
   } 

   if(finalSize < Smallest_Lot){
      Verbose("Calculated lot size (", DoubleToStr(finalSize), ") is lower than minimum possible (", DoubleToStr(Smallest_Lot), "). Using minimum lot size...");
      return Smallest_Lot;
   }
   else if(finalSize > Largest_Lot){
      Verbose("Calculated lot size (", DoubleToStr(finalSize), ") is larger than maximum possible (", DoubleToStr(Largest_Lot), "). Using maximum lot size...");
      return Largest_Lot;
   }
   else {
      return finalSize;
   }
}

double roundValue(double value){
    return NormalizeDouble(value + 0.0000000001, 6);
}

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

int sqFixRanges(int value, int min, int max, int defaultVal) {
   if(value < min || value > max) {
      return (defaultVal);
   }
   
   return value;
}

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

double sqBarRange(string symbol, int timeframe, int shift) {
  double range;
   if(symbol == "NULL" || symbol == "Current") {
      range = iHigh(NULL, timeframe, shift) - iLow(NULL, timeframe, shift);
   } else {
      range = iHigh(symbol, timeframe, shift) - iLow(symbol, timeframe, shift);
   }
   
   return roundValue(range);
}

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

double sqHeikenAshi(string symbol, int timeframe, string mode, int shift) {
   if(symbol == "NULL" || symbol == "Current") {
      if(mode == "Open") {
         return(NormalizeDouble(iCustom(NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 2, shift), 6));
      }
      if(mode == "Close") {
         return(NormalizeDouble(iCustom(NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 3, shift), 6));
      }
      if(mode == "High") {
         return(NormalizeDouble(MathMax(iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6));
      }
      if(mode == "Low") {
         return(NormalizeDouble(MathMin(iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( NULL, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6));
      }

   } else {
      if(mode == "Open") {
         return(NormalizeDouble(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 2, shift), 6));
      }
      if(mode == "Close") {
         return(NormalizeDouble(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 3, shift), 6));
      }
      if(mode == "High") {
         return(NormalizeDouble(MathMax(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6));
      }
      if(mode == "Low") {
         return(NormalizeDouble(MathMin(iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 0, shift), iCustom( symbol, timeframe, "SqHeikenAshi", 0,0,0,0, 1, shift)), 6));
      }
   }

   return(-1);
}

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

double sqBiggestRange(string symbol, int timeframe, int period, int shift) {
   double maxnum = -100000000;
   double range;

   for(int i=shift; i<shift+period; i++) {
      if(symbol == "NULL" || symbol == "Current") {
         range = iHigh(NULL, timeframe, i) - iLow(NULL, timeframe, i);
      } else {
         range = iHigh(symbol, timeframe, i) - iLow(symbol, timeframe, i);
      }

      if(range > maxnum) {
         maxnum = range;
      }
   }

   return roundValue(maxnum);
}

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

double sqSmallestRange(string symbol, int timeframe, int period, int shift) {
   double minnum = 100000000;
   double range;

   for(int i=shift; i<shift+period; i++) {
      if(symbol == "NULL" || symbol == "Current") {
         range = iHigh(NULL, timeframe, i) - iLow(NULL, timeframe, i);
      } else {
         range = iHigh(symbol, timeframe, i) - iLow(symbol, timeframe, i);
      }

      if(range < minnum) {
         minnum = range;
      }
   }

   return roundValue(minnum);
}

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

double sqMA(string symbol, int timeframe, int ma_period, int ma_shift, int ma_method, int applied_price, int shift) {
    
   ma_method = sqFixRanges(ma_method, 0, 3, 0);
   applied_price = sqFixRanges(applied_price, 0, 6, 0);

   return roundValue(iMA(symbol, timeframe, ma_period, ma_shift, ma_method, applied_price, shift));
}

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

double sqTEMA(string symbol, int timeframe, int ma_period, int applied_price, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqTEMA", ma_period, applied_price, 0, shift));
}

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

double sqIchimoku(string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int line, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqIchimoku", tenkanPeriod, kijunPeriod, senkouPeriod, line, shift));
}

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

double sqAroon(string symbol, int timeframe, int period, int line, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqAroon", period, false, false, line, shift));
}

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

double sqBBWidthRatio(string symbol, int timeframe, int period, double deviation, int appliedPrice, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqBBWidthRatio", period, deviation, appliedPrice, 0, shift));
}

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

double sqAvgVolume(string symbol, int timeframe, int period, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqAvgVolume", period, 1, shift));
}
            
//+------------------------------------------------------------------+

double sqFibo(string symbol, int timeframe, int fiboRange, double fiboLevel) {
   fiboRange = sqFixRanges(fiboRange, 1, 7, 1);

   return roundValue(iCustom(symbol, timeframe, "SqFibo", fiboRange, fiboLevel, 0, 0, 0));
}

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

double sqLinReg(string symbol, int timeframe, int period, int line, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqLinReg", period, line, 0, shift));
}

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

double sqPivots(string symbol, int timeframe, int startHour, int startMinute, int line, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqPivots", startHour, startMinute, line, shift));
}

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

double sqQQE(string symbol, int timeframe, int rsiPeriod, int sF, double wF, int line, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqQQE", rsiPeriod, sF, wF, line, shift));
}

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

double sqKeltnerChannel(string symbol, int timeframe, int period, double Deviation, int line, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqKeltnerChannel", period, Deviation, line, shift));
}

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

double sqMTKeltnerChannel(string symbol, int timeframe, int period, double Deviation, int line, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqMTKeltnerChannel", period, Deviation, line, shift));
}

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

double sqRSI(string symbol, int timeframe, int period, int applied_price, int shift) {
   return roundValue(iRSI(symbol, timeframe, period, applied_price, shift));
}

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

double sqCCI(string symbol, int timeframe, int period, int applied_price, int shift) {
   return roundValue(iCCI(symbol, timeframe, period, applied_price, shift));
}

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

double sqAC(string symbol, int timeframe, int shift) {
   return roundValue(iAC(symbol, timeframe, shift));
}

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

double sqADX(string symbol, int timeframe, int period, int line, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqADX", period, line, shift));
}

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

double sqATR(string symbol, int timeframe, int period, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqATR", period, 0, shift));
}

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

double sqAO(string symbol, int timeframe, int shift) {
   return roundValue(iAO(symbol, timeframe, shift));
}

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

double sqBearsPower(string symbol, int timeframe, int period, int applied_price, int shift) {
   return roundValue(iBearsPower(symbol, timeframe, period, applied_price, shift));
}

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

double sqBullsPower(string symbol, int timeframe, int period, int applied_price, int shift) {
   return roundValue(iBullsPower(symbol, timeframe, period, applied_price, shift));
}

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

double sqDeMarker(string symbol, int timeframe, int period, int shift) {
   return roundValue(iDeMarker(symbol, timeframe, period, shift));
}

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

double sqMACD(string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int mode, int shift) {
   return roundValue(iMACD(symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price, mode, shift));

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

double sqMomentum(string symbol, int timeframe, int period, int applied_price, int shift) {
   return roundValue(iMomentum(symbol, timeframe, period, applied_price, shift));
}

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

double sqStochastic(string symbol, int timeframe, int Kperiod, int Dperiod, int slowing, int method, int price_field, int mode, int shift) {
   price_field = sqFixRanges(price_field, 0, 1, 0);
   method = sqFixRanges(method, 0, 3, 0);
   
   return roundValue(iCustom(symbol, timeframe, "SqStochastic", Kperiod, Dperiod, slowing, method, price_field, mode, shift));

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

double sqOsMA(string symbol, int timeframe, int fast_ema_period, int slow_ema_period, int signal_period, int applied_price, int shift) {
   return roundValue(iOsMA(symbol, timeframe, fast_ema_period, slow_ema_period, signal_period, applied_price, shift));
}

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

double sqBands(string symbol, int timeframe, int period, double deviation, int bands_shift, int applied_price, int mode, int shift) {
   return roundValue(iBands(symbol, timeframe, period, deviation, bands_shift, applied_price, mode+1, shift));
}
    
//+------------------------------------------------------------------+

double sqBBRange(string symbol, int timeframe, int period, double deviation, int applied_price, int shift) {
   return roundValue(iBands(symbol, timeframe, period, deviation, 0, applied_price, 1, shift) - iBands(symbol, timeframe, period, deviation, 0, applied_price, 2, shift));
}

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

double sqSAR(string symbol, int timeframe, double step, double maximum, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqParabolicSAR", step, maximum, 0, shift));
   //return roundValue(iSAR(symbol, timeframe, step, maximum, shift));
}

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

double sqStdDev(string symbol, int timeframe, int ma_period, int ma_shift, int ma_method, int applied_price, int shift) {
   return roundValue(iStdDev(symbol, timeframe, ma_period, ma_shift, ma_method, applied_price, shift));
}

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

double sqHighestInRange(string symbol, int timeframe, string timeFrom, string timeTo, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqHighestInRange", timeFrom, timeTo, 0, shift));
}
     
//+------------------------------------------------------------------+

double sqLowestInRange(string symbol, int timeframe, string timeFrom, string timeTo, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqLowestInRange", timeFrom, timeTo, 0, shift));
}

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

double sqFractal(string symbol, int timeframe, int fractal, int bufferIndex, int shift) {
   return roundValue(iCustom(symbol, timeframe, "SqFractal", fractal, bufferIndex, shift));
}

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

bool sqIchimokuChikouSpanCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) {
   double chikouSpan1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 4, shift+1);
    double chikouSpan0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 4, shift);
    double c = iClose(symbol, timeframe, shift);
    double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
    double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
    if(kumoBottom > kumoTop) {
        double temp = kumoBottom;
        kumoBottom = kumoTop;
        kumoTop = temp;
    }
    
    signalStrength = sqFixRanges(signalStrength, 0, 2, 1);
        
    bool signal;
    
    if(bullishOrBearish == -1) {
       // bearish;
       signal = (chikouSpan1 >= c) && (chikouSpan0 < c) && (chikouSpan1 > chikouSpan0);
        
        if(signalStrength == 2) {
            // for strong signal the cross should happen below kumo cloud
            signal = signal && (c < kumoBottom);
            
        } else if(signalStrength == 1) {
            // for neutral signal the cross should happen in kumo cloud
            signal = signal && (c < kumoTop);
            
        } else if(signalStrength == 0) {
            // do nothing, if there is cross signal is always at least weak
            
        } else {
            return false;;
        }
        
        return signal;
        
    } else if(bullishOrBearish == 1) { 
       // bullish
       signal = (chikouSpan1 <= c) && (chikouSpan0 > c) && (chikouSpan1 < chikouSpan0);
       
       if(signalStrength == 2) {
            // for strong signal the cross should happen above kumo cloud
            signal = signal && (c > kumoTop);
            
        } else if(signalStrength == 1) {
            // for neutral signal the cross should happen in kumo cloud
            signal = signal && (c > kumoBottom);
            
        } else if(signalStrength == 0) {
            // do nothing, if there is cross signal is always at least weak
            
        } else {
            return false;
        }

        return signal;
        
    } else {
            return false;
    }
}


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

bool sqIchimokuSenkouSpanCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) {
    double senkouSpanA1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift+1);
    double senkouSpanA0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
    double senkouSpanB1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift+1);
    double senkouSpanB0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
    double c = iClose(symbol, timeframe, shift);
            
    double kumoTop = MathMax(senkouSpanA0,  senkouSpanB0); 
    double kumoBottom = MathMin(senkouSpanA0,  senkouSpanB0); 
        
    bool signal;
    
    signalStrength = sqFixRanges(signalStrength, 0, 2, 1);
    
    if(bullishOrBearish == -1) {
       // bearish;
       signal = (senkouSpanA1 > senkouSpanB1) && (senkouSpanA0 < senkouSpanB0);
        
        if(signalStrength == 2) {
            // for strong signal the cross should happen below kumo cloud
            signal = signal && (c < kumoBottom);
            
        } else if(signalStrength == 1) {
            // for neutral signal the cross should happen in kumo cloud
            signal = signal && (c < kumoTop);
            
        } else if(signalStrength == 0) {
            // do nothing, if there is cross signal is always at least weak
            
        } else {
            return false;;
        }
        
        return signal;
        
    } else if(bullishOrBearish == 1) { 
       // bullish
       signal = (senkouSpanA1 < senkouSpanB1) && (senkouSpanA0 > senkouSpanB0);
       
       if(signalStrength == 2) {
            // for strong signal the cross should happen above kumo cloud
            signal = signal && (c > kumoTop);
            
        } else if(signalStrength == 1) {
            // for neutral signal the cross should happen in kumo cloud
            signal = signal && (c > kumoBottom);
            
        } else if(signalStrength == 0) {
            // do nothing, if there is cross signal is always at least weak
            
        } else {
            return false;
        }

        return signal;
        
    } else {
            return false;
    }
}

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

bool sqIchimokuKijunSenCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) {
    double o = iOpen(symbol, timeframe, shift);
    double c = iClose(symbol, timeframe, shift);
    double kijun = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift);

    double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
    double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
    if(kumoBottom > kumoTop) {
        double temp = kumoBottom;
        kumoBottom = kumoTop;
        kumoTop = temp;
    }
        
    bool signal;
    
    signalStrength = sqFixRanges(signalStrength, 0, 2, 1);
    
    if(bullishOrBearish == -1) {
       // bearish;
       signal = (o > kijun) && c < kijun;
        
        if(signalStrength == 2) {
            // for strong signal the cross should happen below kumo cloud
            signal = signal && (kijun < kumoBottom);
            
        } else if(signalStrength == 1) {
            // for neutral signal the cross should happen in kumo cloud
            signal = signal && (kijun < kumoTop);
            
        } else if(signalStrength == 0) {
            // do nothing, if there is cross signal is always at least weak
            
        } else {
            return false;;
        }
        
        return signal;
        
    } else if(bullishOrBearish == 1) { 
       // bullish
       signal = (o < kijun) && c > kijun;
       
        if(signalStrength == 2) {
            // for strong signal the cross should happen above kumo cloud
            signal = signal && (kijun > kumoTop);
            
        } else if(signalStrength == 1) {
            // for neutral signal the cross should happen in kumo cloud
            signal = signal && (kijun > kumoBottom);
            
        } else if(signalStrength == 0) {
            // do nothing, if there is cross signal is always at least weak
            
        } else {
            return false;
        }

        return signal;
        
    } else {
            return false;
    }
}

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

bool sqIchimokuTenkanKijunCross(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift, int signalStrength) {
    double tenkan1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 0, shift+1);
    double tenkan0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 0, shift);

    double kijun1 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift+1);
    double kijun0 = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 1, shift);

    double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
    double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
    if(kumoBottom > kumoTop) {
        double temp = kumoBottom;
        kumoBottom = kumoTop;
        kumoTop = temp;
    }
        
    bool signal;
    
    signalStrength = sqFixRanges(signalStrength, 0, 2, 1);
    
    if(bullishOrBearish == -1) {
       // bearish;
       signal = (tenkan1 > kijun1) && tenkan0 < kijun0;
        
        if(signalStrength == 2) {
            // for strong signal the cross should happen below kumo cloud
            signal = signal && (tenkan0 < kumoBottom);
            
        } else if(signalStrength == 1) {
            // for neutral signal the cross should happen in kumo cloud
            signal = signal && (tenkan0 < kumoTop);
            
        } else if(signalStrength == 0) {
            // do nothing, if there is cross signal is always at least weak
            
        } else {
            return false;;
        }
        
        return signal;
        
    } else if(bullishOrBearish == 1) { 
       // bullish
       signal = (tenkan1 < kijun1) && tenkan0 > kijun0;
       
        if(signalStrength == 2) {
            // for strong signal the cross should happen above kumo cloud
            signal = signal && (tenkan0 > kumoTop);
            
        } else if(signalStrength == 1) {
            // for neutral signal the cross should happen in kumo cloud
            signal = signal && (tenkan0 > kumoBottom);
            
        } else if(signalStrength == 0) {
            // do nothing, if there is cross signal is always at least weak
            
        } else {
            return false;
        }

        return signal;
        
    } else {
            return false;
    }
}

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

bool sqIchimokuKumoBreakout(int bullishOrBearish, string symbol, int timeframe, int tenkanPeriod, int kijunPeriod, int senkouPeriod, int shift) {
    double o = iOpen(symbol, timeframe, shift);
    double c = iClose(symbol, timeframe, shift);

    double kumoTop = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 2, shift);
    double kumoBottom = sqIchimoku(symbol, timeframe, tenkanPeriod, kijunPeriod, senkouPeriod, 3, shift);
    if(kumoBottom > kumoTop) {
        double temp = kumoBottom;
        kumoBottom = kumoTop;
        kumoTop = temp;
    }
        
    bool signal;
    
    if(bullishOrBearish == -1) {
       // bearish;
       signal = (o > kumoBottom) && c < kumoBottom;
        
        return signal;
        
    } else if(bullishOrBearish == 1) { 
       // bullish
       signal = (o < kumoTop) && c > kumoTop;
        
        return signal;
        
    } else {
            return false;
    }
}


//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// ExitMethods includes
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+


// Move Stop Loss to Break Even
void sqManageSL2BE(int ticket) {

   double val = sqGetGlobalVariable(ticket, "MoveSL2BE");
   if(val == 0) {
      return;
   }

   if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
      return;
   }

   double moveSLAtValue = sqGetValueByIdentification((string) val);

   if(moveSLAtValue > 0) {
      double newSL = 0;
      int error;

      int valueType = (int) sqGetGlobalVariable(ticket, "MoveSL2BEType");
      int orderType = OrderType();
      int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS);

      if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
         if(valueType == SLPTTYPE_RANGE) {
            moveSLAtValue = Bid - moveSLAtValue;
         }
      } else {
         if(valueType == SLPTTYPE_RANGE) {
            moveSLAtValue = Ask + moveSLAtValue;
         }
      }

      moveSLAtValue = NormalizeDouble(moveSLAtValue, digits);
      double addPips = NormalizeDouble(sqGetValueByIdentification((string) sqGetGlobalVariable(ticket, "SL2BEAddPips")), digits);
      
      double currentSL = OrderStopLoss();

      if(orderType == OP_BUY) {
         newSL = NormalizeDouble(OrderOpenPrice() + addPips, digits);

         if ((OrderOpenPrice() <= moveSLAtValue || sqDoublesAreEqual(OrderOpenPrice(), moveSLAtValue)) && (currentSL == 0 || currentSL < newSL) && !sqDoublesAreEqual(currentSL, newSL)) {
            Verbose("Moving SL 2 BE for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(newSL));
            if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit())) {
               error = GetLastError();
               Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ",  DoubleToString(currentSL));
            }
         }

      } else { // orderType == OP_SELL
         newSL = NormalizeDouble(OrderOpenPrice() - addPips, digits);

         if ((OrderOpenPrice() >= moveSLAtValue || sqDoublesAreEqual(OrderOpenPrice(), moveSLAtValue)) && (currentSL == 0 || currentSL > newSL) && !sqDoublesAreEqual(currentSL, newSL)) {
            Verbose("Moving SL 2 BE for order with ticket: ", IntegerToString(OrderTicket()), "  to :", DoubleToString(newSL));
            if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), newSL, OrderTakeProfit())) {
               error = GetLastError();
               Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ", DoubleToString(currentSL));
            }
         }
      }
   }
}
// Trailing Stop
void sqManageTrailingStop(int ticket) {

   double val = sqGetGlobalVariable(ticket, "TrailingStop");
   if(val == 0) {
      return;
   }

   if(!OrderSelect(ticket, SELECT_BY_TICKET)) {
      return;
   }
   
   double tsValue = sqGetValueByIdentification((string) val);
   
   if(tsValue > 0) {
      double plValue;
      int error;

      int valueType = (int) sqGetGlobalVariable(ticket, "TrailingStopType");
      int orderType = OrderType();
      int digits = (int) MarketInfo(OrderSymbol(), MODE_DIGITS);

      if(orderType == OP_BUY || orderType == OP_BUYSTOP || orderType == OP_BUYLIMIT) {
         if(valueType == SLPTTYPE_RANGE) {
            tsValue = Bid - tsValue;
         }
      } else {
         if(valueType == SLPTTYPE_RANGE) {
            tsValue = Ask + tsValue;
         }
      }

      tsValue = NormalizeDouble(tsValue, digits);

      double tsActivation = NormalizeDouble(sqGetValueByIdentification((string) sqGetGlobalVariable(ticket, "TrailingActivation")), digits);
      double currentSL = OrderStopLoss();

      if(orderType == OP_BUY) {
         plValue = NormalizeDouble(Bid - OrderOpenPrice(), digits);

         if ((plValue >= tsActivation || sqDoublesAreEqual(plValue, tsActivation)) && (currentSL == 0 || currentSL < tsValue) && !sqDoublesAreEqual(currentSL, tsValue)) {
            Verbose("Moving trailing stop for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(tsValue));
            if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), tsValue, OrderTakeProfit())) {
               error = GetLastError();
               Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ",  DoubleToString(currentSL));
            }
         }
      } else { // orderType == OP_SELL
         plValue = NormalizeDouble(OrderOpenPrice() - Ask, digits);

         if ((plValue >= tsActivation || sqDoublesAreEqual(plValue, tsActivation)) && (currentSL == 0 || currentSL > tsValue) && !sqDoublesAreEqual(currentSL, tsValue)) {
            Verbose("Moving trailing stop for order with ticket: ", IntegerToString(OrderTicket()), " to :", DoubleToString(tsValue));
            if(!sqOrderModify(OrderTicket(), OrderOpenPrice(), tsValue, OrderTakeProfit())) {
               error = GetLastError();
               Verbose("Failed, error: ", IntegerToString(error), " - ", ErrorDescription(error),", Ask: ", DoubleToString(Ask), ", Bid: ", DoubleToString(Bid), " Current SL: ",  DoubleToString(currentSL));
            }
         }
      }
   }
}
void sqManageExitAfterXBars(int ticket) {
   int exitBars = (int) sqGetGlobalVariable(ticket, "ExitAfterBars");
   if(exitBars > 0) {
      if (sqGetOpenBarsForOrder(ticket, exitBars+10) >= exitBars) {
         Verbose("Exit After ", IntegerToString(exitBars), "bars - closing order with ticket: ", IntegerToString(OrderTicket()));
         sqClosePositionAtMarket(OrderLots());
      }
   }
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
// Trading Options includes
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+

class CTradingOption {
public:
   virtual bool onBarUpdate() = 0;
};

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

class CDontTradeOnWeekends: public CTradingOption {
   private:
      datetime thisFridayCloseTime; 
      datetime thisSundayOpenTime;
       
   public:
      CDontTradeOnWeekends() {
         thisFridayCloseTime = D'1970.01.01';    
         thisSundayOpenTime = D'1970.01.01';
      }

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

      virtual bool onBarUpdate() {
         if(!DontTradeOnWeekends) {
                  return true;
         }
         
         if(!sqIsBarOpen()) {
            return(true);
         }

         datetime currentTime = TimeCurrent();

         if(thisFridayCloseTime < 100) {
            initTimes(currentTime, 0);
         }
         
         if(currentTime < thisFridayCloseTime) {
            // trade normally
            return true;
         }
         
         if(currentTime < thisSundayOpenTime) {
               // do not allow opening new positions until sunday.
                  // returning false means there will be no more processing on this tick.
                  // this is what we want because we don't want to be trading after close of all positions
                  return false;
            }
         else {
            // new week starting
            initTimes(currentTime, DayOfWeek() == 0 ? 1 : 0); 

            return true;
         }
      }           

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

      void initTimes(datetime currentTime, int addDays) {
         if(addDays > 0) {
                thisFridayCloseTime = SQTime.addDays(currentTime, addDays);
          } else {
                thisFridayCloseTime = currentTime;
          }
    
          // set time of EOD 
          thisFridayCloseTime = SQTime.setDayOfWeek(thisFridayCloseTime, (FridayCloseTime == "00:00" || FridayCloseTime == "0:00") ? SATURDAY : FRIDAY);
          thisFridayCloseTime = SQTime.setHHMM(thisFridayCloseTime, FridayCloseTime);    
         
          thisSundayOpenTime = SQTime.setDayOfWeek(currentTime, SUNDAY);
         thisSundayOpenTime = SQTime.setHHMM(thisSundayOpenTime, SundayOpenTime);    
      }
};

// create variable for class instance (required)
CDontTradeOnWeekends* objDontTradeOnWeekends;class CExitAtEndOfDay : public CTradingOption {
   private:
       datetime dailyEODExitTime;
       datetime EODTime;
       bool closedThisDay;
   
   public:
      CExitAtEndOfDay() {
         dailyEODExitTime = D'1970.01.01';
         EODTime = D'1970.01.01';
         closedThisDay = false;
      }

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

      virtual bool onBarUpdate() {
        if(!ExitAtEndOfDay) {
              return(true);
          }                   
                             
        onTick();

        if(!sqIsBarOpen()) {
           return(true);
        }
        
          datetime currentTime = TimeCurrent();

          if(currentTime > EODTime) {
             //it is a new day
              initTimesForCurrentDay(currentTime);
          }

          if(currentTime >= dailyEODExitTime) {
              // returning false means there will be no more processing on this tick
            // this is what we want because we don't want to be trading after close of all positions
              return(false); 
          }

          return(true);
      }     
        
       //------------------------------------------------------------------------

     virtual void onTick() {
        if(!ExitAtEndOfDay) {
              return;
          }
        
        datetime currentTime = TimeCurrent();
        datetime currentTimeDayStart = SQTime.correctDayStart(currentTime);    
                datetime currentTimeDayEnd = SQTime.correctDayEnd(currentTime);
        
        if(!closedThisDay && currentTime >= dailyEODExitTime) {
          // we should close all positions at midnight, so close them at the first tick of a new day
              for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
            if (OrderSelect(cc, SELECT_BY_POS)) {
      
               if(!checkMagicNumber(OrderMagicNumber())) continue;
               
               bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL;
               
               //Close all orders at the end of a day. When there is a data gap, on the first tick of new day close all pending orders and orders filled before current day start
               if(currentTimeDayEnd == EODTime || !isLiveOrder || OrderOpenTime() < currentTimeDayStart) {
                  if(isLiveOrder){
                     sqClosePositionAtMarket(OrderLots());
                  }
                  else {
                     sqDeletePendingOrder(OrderTicket());
                  }
               }
            }
         }
          
                closedThisDay = true;
          }
          
     }

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

      void initTimesForCurrentDay(datetime currentTime) {
          // set end time of the current day (so that we now when new day starts)
          EODTime = SQTime.correctDayEnd(currentTime);

          // set time of EOD
          if(EODExitTime == "00:00" || EODExitTime == "0:00"){
             dailyEODExitTime = EODTime;
          }
          else {
             dailyEODExitTime = SQTime.setHHMM(currentTime, EODExitTime);
          }
          
              closedThisDay = false;
      }
};

// create variable for class instance (required)
CExitAtEndOfDay* objExitAtEndOfDay;


class CExitOnFriday : public CTradingOption {
   private:
      datetime thisFridayExitTime; 
      datetime thisSundayBeginTime;
      datetime EOFDayTime;
      bool closedThisWeek;
       
   public:
      CExitOnFriday() {
         thisFridayExitTime = D'1970.01.01';    
         thisSundayBeginTime = D'1970.01.01';
         closedThisWeek = false;
      }

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

      virtual bool onBarUpdate() {
         if(!ExitOnFriday) {
                  return true;
         }
         
         onTick();
         
         if(!sqIsBarOpen()) {
            return(true);
         }

         datetime currentTime = TimeCurrent();

         if(thisFridayExitTime < 100) {
            initFridayExitTime(currentTime, 0);
         }
         
         if(currentTime < thisFridayExitTime) {
            // trade normally
            return true;
         }
         
         if(currentTime < thisSundayBeginTime) {
               // do not allow opening new positions until sunday.
                  // returning false means there will be no more processing on this tick.
                  // this is what we want because we don't want to be trading after close of all positions
                  return false;
            }
         else {
            // new week starting
            initFridayExitTime(currentTime, DayOfWeek() == 0 ? 1 : 0); 

            return true;
         }
      }           
        
       //------------------------------------------------------------------------

     virtual void onTick() {
        if(!ExitOnFriday) {
                  return;
        }
        
        datetime currentTime = TimeCurrent();      
        datetime currentTimeDayStart = SQTime.correctDayStart(currentTime);      
                datetime currentTimeDayEnd = SQTime.correctDayEnd(currentTime);

            if(!closedThisWeek && currentTime >= thisFridayExitTime) {
                    // time is over friday closing time, we should close the positions
                    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
              if (OrderSelect(cc, SELECT_BY_POS)) {
        
                 if(!checkMagicNumber(OrderMagicNumber())) continue;
                 
                 bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL;
                 
                 //Close all orders at the end of Friday. When there is a data gap, on the first tick of new day close all pending orders and orders filled before current day start
                 if(currentTimeDayEnd == EOFDayTime || !isLiveOrder || OrderOpenTime() < currentTimeDayStart) {
                    if(isLiveOrder){
                        sqClosePositionAtMarket(OrderLots());
                    }
                    else {
                        sqDeletePendingOrder(OrderTicket());
                    }
                 }
              }
           }
           
                    closedThisWeek = true;
            } 
     }

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

      void initFridayExitTime(datetime currentTime, int addDays) {
         if(addDays > 0) {
                thisFridayExitTime = SQTime.addDays(currentTime, addDays);
          } else {
                thisFridayExitTime = currentTime;
          }
    
          // set time of EOD 
          thisFridayExitTime = SQTime.setDayOfWeek(thisFridayExitTime, (FridayExitTime == "00:00" || FridayExitTime == "0:00") ? SATURDAY : FRIDAY);
          thisFridayExitTime = SQTime.setHHMM(thisFridayExitTime, FridayExitTime);    
         
        EOFDayTime = SQTime.correctDayEnd(thisFridayExitTime);
       
          thisSundayBeginTime = SQTime.setDayOfWeek(currentTime, SUNDAY);
          thisSundayBeginTime = SQTime.correctDayStart(thisSundayBeginTime);
        
        closedThisWeek = false;
      }
};

// create variable for class instance (required)
CExitOnFriday* objExitOnFriday;

class CLimitTimeRange : public CTradingOption {
   private:
      datetime dailySignalTimeRangeFrom;
      datetime dailySignalTimeRangeTo;
      bool closedThisDay;
      
   public:
      CLimitTimeRange() {
         closedThisDay = false;
      }

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

      virtual bool onBarUpdate() {     
        if(!LimitTimeRange) {
            return true;
        }
                                
        onTick();
           
        if(!sqIsBarOpen()) {
           return true;
        }
        
        datetime currentTime = TimeCurrent();
    
        if(currentTime > dailySignalTimeRangeTo) {
            // it is new day
            initTimesForCurrentDay(currentTime);
        }

        if(currentTime < dailySignalTimeRangeFrom || currentTime >= dailySignalTimeRangeTo) {
            // time is outside given range
            // returning false means there will be no more processing on this tick
               // this is what we want because we don't want to be trading outside of this time range
            
            return false; 
        }
    
        return true;
     }
        
     //------------------------------------------------------------------------

     virtual void onTick() {
        if(!LimitTimeRange) {
            return;
        }
        
        datetime currentTime = TimeCurrent();
        if(!closedThisDay && ExitAtEndOfRange && currentTime >= dailySignalTimeRangeTo) {
           for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
              if (OrderSelect(cc, SELECT_BY_POS)) {
        
                 if(!checkMagicNumber(OrderMagicNumber())) continue;
                 
                 bool isLiveOrder = OrderType() == OP_BUY || OrderType() == OP_SELL;
               
                 if(isLiveOrder){
                    if(OrderTypeToExit != 2) { // not pending only
                       sqClosePositionAtMarket(OrderLots());
                    }
                 }
                 else {
                    if(OrderTypeToExit != 1) { // not live only
                       sqDeletePendingOrder(OrderTicket());
                    }
                 }
              }
           }
           
           closedThisDay = true;
        }
     }

    //------------------------------------------------------------------------

    void initTimesForCurrentDay(datetime currentTime) {
       // set time of range open 
       dailySignalTimeRangeFrom = SQTime.setHHMM(currentTime, SignalTimeRangeFrom);
    
       dailySignalTimeRangeTo = SQTime.setHHMM(currentTime, SignalTimeRangeTo);    

      int timeFrom = getHHMM(SignalTimeRangeFrom);
      int timeTo = getHHMM(SignalTimeRangeTo);

      if(timeFrom >= timeTo){
         if(getSQTime(currentTime) < timeTo){
            dailySignalTimeRangeFrom = SQTime.addDays(dailySignalTimeRangeFrom, -1);
         }
         else {
            dailySignalTimeRangeTo = SQTime.addDays(dailySignalTimeRangeTo, 1);
         }
      }
      else {
         if(currentTime > dailySignalTimeRangeTo) {
                dailySignalTimeRangeFrom = SQTime.addDays(dailySignalTimeRangeFrom, 1);
                dailySignalTimeRangeTo = SQTime.addDays(dailySignalTimeRangeTo, 1);
            }
      }

       closedThisDay = false;
    }
};


// create variable for class instance (required)
CLimitTimeRange* objLimitTimeRange;

class CMaxDistanceFromMarket : public CTradingOption {
   private:
      
   public:
      CMaxDistanceFromMarket() {
      }

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

      virtual bool onBarUpdate() {
         return true;
      }
};

// create variable for class instance (required)
CMaxDistanceFromMarket* objMaxDistanceFromMarket;


class CMaxTradesPerDay : public CTradingOption {
   private:
      int lastHistoryPositionChecked;
      datetime openTimeToday;
      datetime EODTime;
      bool reachedLimitToday;
      
   public:
      CMaxTradesPerDay() {
         EODTime = D'1970.01.01';
         lastHistoryPositionChecked = 0;
      }

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

      virtual bool onBarUpdate() {
         if(MaxTradesPerDay <= 0) {
            return true;
         }
        
         datetime currentTime = TimeCurrent();

         if(currentTime > EODTime) {
            // it is new day
            initTimeForCurrentDay(currentTime);
         }        
        
           if(reachedLimitToday) {
              return false;
           }
           
         if(getNumberOfTradesToday() >= MaxTradesPerDay) {
            reachedLimitToday = true;
            return(false);
         }
        
         return true;
      }

      //------------------------------------------------------------------------

      void initTimeForCurrentDay(datetime currentTime) {
            // set end time of the current day (so that we now when new day starts)
         EODTime = SQTime.correctDayEnd(currentTime);

         openTimeToday = SQTime.correctDayStart(currentTime);
         
         reachedLimitToday = false;
      }
      
      //------------------------------------------------------------------------

        int getNumberOfTradesToday() {
            int todayTradesCount = 0;
            int i = 0;

            // count closed trades that started today
            int startAt = lastHistoryPositionChecked -10;
            if(startAt < 0) {
                startAt = 0;
            }

         for(i=startAt;i<OrdersHistoryTotal();i++) {
            if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==true && checkMagicNumber(OrderMagicNumber())) {
               lastHistoryPositionChecked = i;

               if(OrderOpenTime() >= openTimeToday) {
                  todayTradesCount++;
               }
            }
         }

         for(i=0; i<OrdersTotal(); i++) {
            if (OrderSelect(i,SELECT_BY_POS)==true && checkMagicNumber(OrderMagicNumber())) {

               if(OrderOpenTime() >= openTimeToday) {
                  todayTradesCount++;
               }
            }
         }
   
            return todayTradesCount;
        }      
};

// create variable for class instance (required)
CMaxTradesPerDay* objMaxTradesPerDay;


class CMinMaxSLPT : public CTradingOption {
   private:
      
   public:
      CMinMaxSLPT() {
      }

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

      virtual bool onBarUpdate() {
         return true;
      }
};

// create variable for class instance (required)
CMinMaxSLPT* objMinMaxSLPT;
// Money Management - Fixed Size used

//=============================================================================
//                              OrderReliable.mqh
//
//         Copyright ? 2006, Derk Wehler     (derkwehler@gmail.com)
//
//  This file is simply LibOrderReliable as a header file instead of a library
//
//  In order to read this code most clearly in the Metaeditor, it is advised
//  that you set your tab settings to 4 (instead of the default 3): 
//  Tools->Options->General Tab, set Tab Size to 4, uncheck "Insert spaces"
//
// ***************************************************************************
// OrderReliable library MIT license
// 
// Copyright (c) 2006 Derk Wehler
// 
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// LICENSE LIMITATION
// This MIT license is limited only for use of OrderReliable within 
// strategies generated by StrategyQuant. Any method from this library 
// that will be used outside of this source code will be governed 
// by GPL license.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// ***************************************************************************

// ***************************************************************************
//
//  A library for MT4 expert advisors, intended to give more reliable
//  order handling.    This library only concerns the mechanics of sending
//  orders to the Metatrader server, dealing with transient connectivity
//  problems better than the standard order sending functions.  It is
//  essentially an error-checking wrapper around the existing transaction
//  functions. This library provides nothing to help actual trade strategies,
//  but ought to be valuable for nearly all expert advisors which trade 'live'.
//
//
//=============================================================================
//
//  Contents:
//
//        OrderSendReliable()
//            This is intended to be a drop-in replacement for OrderSend()
//            which, one hopes is more resistant to various forms of errors
//            prevalent with MetaTrader.
//
//        OrderSendReliable2Step()
//            This function is intended to be used when brokers do not allow
//            initial stoploss and take-profit settings as part of the initial
//            market order. After successfully playing an order, it will then
//            Call OrderModifyReliable() to update the SL and TP settings.
//
//        OrderModifyReliable()
//            A replacement for OrderModify with more error handling.
//
//        OrderCloseReliable()
//            A replacement for OrderClose with more error handling.
//
//        OrderCloseReliableMKT()
//            This function is intended for closing orders ASAP; the
//            principal difference is that in its internal retry-loop,
//            it uses the new "Bid" and "Ask" real-time variables as opposed
//            to the OrderCloseReliable() which uses only the price given upon
//            entry to the routine.  More likely to get the order closed if 
//          price moves, but more likely to "slip"
//
//        OrderDeleteReliable()
//            A replacement for OrderDelete with more error handling.
//
//===========================================================================
//                      CHANGE LOG BEGUN 28 March, 2014
//         Prior to this, Source OffSite was used to save changes
//      Start with revision 32, which is what SOS had as last change
//
//  v32, 28 Mar 14: 
//  Small bug fixes for Build 600 changes
//
//  v33, 25 Apr 16: 
//  Tiny adjustment made to GetOrderDetails() for non-forex pairs
//
//  v34, 21 Jun 16: 
//  Changed SleepRandomTime() to just sleep 200ms
//
//  v35, 20 Jul 16: (important)
//  Added MySymbolConst2Val(), MySymbolVal2String(), necessary for correct
//  functioning of GetOrderDetails()
//
//  v36, 23 Apr 19: (Mark Fric, SQ)
//  Added separate retry_attempts_bad_price variable that can configure repeat 
//  attempts for ERR_INVALID_PRICE and ERR_INVALID_STOPS errors
//
//    14.10.2020 (Tomas Brynda) - added ERR_MARKET_CLOSED on user requested
//    "important when using Daily strategies 
//    during roll over market is closed for several seconds"
//
//===========================================================================


//=============================================================================
//                             OrderSendReliable()
//
//  This is intended to be a drop-in replacement for OrderSend() which,
//  one hopes, is more resistant to various forms of errors prevalent
//  with MetaTrader.
//
//    RETURN VALUE:
//     Ticket number or -1 under some error conditions.  
//
//  FEATURES:
//     * Re-trying under some error conditions, sleeping a random
//       time defined by an exponential probability distribution.
//
//     * Automatic normalization of Digits
//
//     * Automatically makes sure that stop levels are more than
//       the minimum stop distance, as given by the server. If they
//       are too close, they are adjusted.
//
//     * Automatically converts stop orders to market orders
//       when the stop orders are rejected by the server for
//       being to close to market.  NOTE: This intentionally
//       applies only to OP_BUYSTOP and OP_SELLSTOP,
//       OP_BUYLIMIT and OP_SELLLIMIT are not converted to market
//       orders and so for prices which are too close to current
//       this function is likely to loop a few times and return
//       with the "invalid stops" error message.
//       Note, the commentary in previous versions erroneously said
//       that limit orders would be converted.  Note also
//       that entering a BUYSTOP or SELLSTOP new order is distinct
//       from setting a stoploss on an outstanding order; use
//       OrderModifyReliable() for that.
//
//     * Displays various error messages on the log for debugging.
//
//  ORIGINAL AUTHOR AND DATE:
//     Matt Kennel, 2006-05-28
//
//=============================================================================
int OrderSendReliable(string symbol, int cmd, double volume, double price,
                      int slippage, double stoploss, double takeprofit,
                      string comment="", int magic=0, datetime expiration=0,
                      color arrow_color=CLR_NONE)
{
    OrderReliable_Fname = "OrderSendReliable";
    int ticket = -1;
  
  price = NormalizeDouble(price, Digits);
    takeprofit = NormalizeDouble(takeprofit, Digits);
    stoploss = NormalizeDouble(stoploss, Digits);
  
    // ========================================================================
    // If testing or optimizing, there is no need to use this lib, as the 
    // orders are not real-world, and always get placed optimally.  By 
    // refactoring this option to be in this library, one no longer needs 
    // to create similar code in each EA.
    if (!UseForTesting)
    {
        if (IsOptimization()  ||  IsTesting())
        {
            ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss,
                               takeprofit, comment, magic, expiration, arrow_color);
            return(ticket);
        }
    }
    // ========================================================================
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Get information about this order
    double realPoint = MarketInfo(symbol, MODE_POINT);
    double adjPoint = realPoint;
    if (adjPoint == 0.00001  ||  adjPoint == 0.001)
        adjPoint *= 10;
    int digits;
    double point, M = 0;
    double bid, ask;
    double sl, tp;
    double priceNow = 0;
    double hasSlippedBy = 0;
    
    GetOrderDetails(0, symbol, cmd, digits, point, sl, tp, bid, ask, false);
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
    OrderReliablePrint("Attempted " + OrderTypeToString(cmd) + " " + symbol + ": " + DoubleToStr(volume, 3) + " lots @" + 
                       DoubleToStr(price, digits+1) + " sl:" + DoubleToStr(stoploss, digits+1) + " tp:" + DoubleToStr(takeprofit, digits+1));


    // Normalize all price / stoploss / takeprofit to the proper # of digits.
    price = NormalizeDouble(price, digits);
    stoploss = NormalizeDouble(stoploss, digits);
    takeprofit = NormalizeDouble(takeprofit, digits);

    // Check stop levels, adjust if necessary
    EnsureValidStops(symbol, cmd, price, stoploss, takeprofit);

    int cnt, cnt_bad_price;
    GetLastError(); // clear the global variable.
    int err = 0;
    bool exit_loop = false;
    bool limit_to_market = false;
    bool fixed_invalid_price = false;

    // Concatenate to comment if enabled
    double symSpr = MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID);
    if (AddSpreadToComment)
        comment = comment + " (Spr: " + DoubleToStr(symSpr / adjPoint, 1) + ")";
        
    // Limit/Stop order...............................................................
    if (cmd > OP_SELL)
    {
        cnt = 0;
        cnt_bad_price = 0;
        while (!exit_loop)
        {
            // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =
            // Calculating our own slippage internally should not need to be done for pending orders; see market orders below
            // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =

            OrderReliablePrint("About to call OrderSend(), comment = " + comment);
            ticket = OrderSend(symbol, cmd, volume, price, slippage, stoploss,
                               takeprofit, comment, magic, expiration, arrow_color);
            err = GetLastError();

            switch (err)
            {
                case ERR_NO_ERROR:
                    exit_loop = true;
                    break;

                // retryable errors
                case ERR_SERVER_BUSY:
                case ERR_NO_CONNECTION:
                case ERR_OFF_QUOTES:
                case ERR_BROKER_BUSY:
                case ERR_TRADE_CONTEXT_BUSY:
                case ERR_TRADE_TIMEOUT:
                case ERR_TRADE_DISABLED:
                case ERR_PRICE_CHANGED:
                case ERR_REQUOTE:
                case ERR_MARKET_CLOSED:
                    cnt++;
                    break;

                case ERR_INVALID_PRICE:
                case ERR_INVALID_STOPS:
                    cnt++;
                    cnt_bad_price++;
                    break;

                case ERR_INVALID_TRADE_PARAMETERS:
                default:
                    // an apparently serious error.
                    exit_loop = true;
                    break;

            }  // end switch

            if (cnt > retry_attempts)
                exit_loop = true;

            if (cnt_bad_price > retry_attempts_bad_price)
                exit_loop = true;


            if (exit_loop)
            {
                if (!limit_to_market)
                {
                    if (err != ERR_NO_ERROR  &&  err != ERR_NO_RESULT)
                        OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
                    else if (cnt > retry_attempts)
                        OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")");
                }
            }
            else
            {
                OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err));
                
                SleepRandomTime(sleep_time, sleep_maximum);
                RefreshRates();
            }
        }

        // We have now exited from loop.
        if (err == ERR_NO_ERROR  ||  err == ERR_NO_RESULT)
        {
            OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Successful " + OrderTypeToString(cmd) + " order placed with comment = " + comment + ", details follow.");
            if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
                OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket));
            sqOrderPrint();
            return(ticket); // SUCCESS!
        }
        if (!limit_to_market)
        {
            OrderReliablePrint("Failed to execute stop or limit order after " + IntegerToString(retry_attempts) + " retries");
            OrderReliablePrint("Failed trade: " + OrderTypeToString(cmd) + " " + DoubleToStr(volume, 2) + " lots  " + symbol +
                               "@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss));
            OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
            
            OrderReliablePrint("");
            return(-1);
        }
    }  // end

    if (limit_to_market)
    {
        OrderReliablePrint("Going from stop/limit order to market order because market is too close.");
        cmd %= 2;
        if (cmd == OP_BUY)    price = ask;
        else                 price = bid;
    }

    // We now have a market order.
    err = GetLastError(); // so we clear the global variable.
    err = 0;
    ticket = -1;
    exit_loop = false;


    // Market order..........................................................
    if (cmd == OP_BUY  ||  cmd == OP_SELL)
    {
        cnt = 0;
        cnt_bad_price = 0;
        while (!exit_loop)
        {
            // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =
            // Get current price and calculate slippage
            RefreshRates();
            if (cmd == OP_BUY)
            {
                M = 1.0;
                priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS));    // Open @ Ask
                hasSlippedBy = (priceNow - price) / point;    // (Adjusted Point)
            }
            else if (cmd == OP_SELL)
            {
                M = -1.0;
                priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS));    // Open @ Bid
                hasSlippedBy = (price - priceNow) / point;    // (Adjusted Point)
            }

            // Check if slippage is more than caller's maximum allowed
            if (priceNow != price  &&  hasSlippedBy > slippage)
            {
                // Actual price has slipped against us more than user allowed
                // Log error message, sleep, and try again
                OrderReliablePrint("Actual Price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits+1) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips.  Retrying...");
                err = ERR_PRICE_CHANGED;
            }
            else
            {
                if (priceNow != price)
                {
                    // If the price has slipped "acceptably" (either negative or within 
                    // "Slippage" param), then we need to adjust the SL and TP accordingly
                    if (stoploss != 0)        stoploss += M * hasSlippedBy;
                    if (takeprofit != 0)    takeprofit += M * hasSlippedBy;
                    OrderReliablePrint("Actual Price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits+1) + "; Requested Price = " + DoubleToStr(price, Digits) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips (\'positive slippage\').  Attempting order at market");
                }
                OrderReliablePrint("About to call OrderSend(), comment = " + comment);
                ticket = OrderSend(symbol, cmd, volume, priceNow, (int)(slippage - hasSlippedBy), 
                                   stoploss, takeprofit, comment, magic,    expiration, arrow_color);
                err = GetLastError();
            }
            // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =

            switch (err)
            {
                case ERR_NO_ERROR:
                    exit_loop = true;
                    break;

                case ERR_INVALID_PRICE:
                    if (cmd == OP_BUY)
                        OrderReliablePrint("INVALID PRICE ERROR - Requested Price: " + DoubleToStr(price, Digits) + "; Ask = " + DoubleToStr(MarketInfo(symbol, MODE_ASK), Digits));
                    else
                        OrderReliablePrint("INVALID PRICE ERROR - Requested Price: " + DoubleToStr(price, Digits) + "; Bid = " + DoubleToStr(MarketInfo(symbol, MODE_BID), Digits));
                    cnt++; // a retryable error
                    cnt_bad_price++;
                    break;
                    
                case ERR_INVALID_STOPS:
                    OrderReliablePrint("INVALID STOPS on attempted " + OrderTypeToString(cmd) + " : " + DoubleToStr(volume, 2) + " lots " + " @ " + DoubleToStr(price, Digits) + ", SL = " + DoubleToStr(stoploss, Digits) + ", TP = " + DoubleToStr(takeprofit, Digits));
                    cnt++; // a retryable error
                    cnt_bad_price++;
                    break;
                    
                case ERR_SERVER_BUSY:
                case ERR_NO_CONNECTION:
                case ERR_OFF_QUOTES:
                case ERR_BROKER_BUSY:
                case ERR_TRADE_CONTEXT_BUSY:
                case ERR_TRADE_TIMEOUT:
                case ERR_TRADE_DISABLED:
                case ERR_PRICE_CHANGED:
                case ERR_REQUOTE:
                case ERR_MARKET_CLOSED:
                    cnt++; // a retryable error
                    break;

                default:
                    // an apparently serious, unretryable error.
                    exit_loop = true;
                    break;
            }  

            if (cnt > retry_attempts)
                exit_loop = true;

            if (cnt_bad_price > retry_attempts_bad_price)
                exit_loop = true;

            if (exit_loop)
            {
                if (err != ERR_NO_ERROR  &&  err != ERR_NO_RESULT)
                    OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
                if (cnt > retry_attempts)
                    OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")");
            }
            else
            {
                OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) +"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err));
                
                SleepRandomTime(sleep_time, sleep_maximum);
                RefreshRates();
            }
        }

        // We have now exited from loop; if successful, return ticket #
        if (err == ERR_NO_ERROR  ||  err == ERR_NO_RESULT)
        {
            OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Successful " + OrderTypeToString(cmd) + " order placed with comment = " + comment + ", details follow.");
            if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
                OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket));
            sqOrderPrint();
            return(ticket); // SUCCESS!
        }
        
        // If not successful, log and return -1
        OrderReliablePrint("Failed to execute OP_BUY/OP_SELL, after " + IntegerToString(retry_attempts) + " retries");
        OrderReliablePrint("Failed trade: " + OrderTypeToString(cmd) + " " + DoubleToStr(volume, 2) + " lots  " + symbol +
                           "@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss));
        OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
    }
    return(-1);
}


//=============================================================================
//                             OrderSendReliable2Step()
//
//  Some brokers don't allow the SL and TP settings as part of the initial
//  market order (Water House Capital).  Therefore, this routine will first
//  place the market order with no stop-loss and take-profit but later
//  update the order accordingly
//
//    RETURN VALUE:
//     Same as OrderSendReliable; the ticket number
//
//  NOTES:
//     Order will not be updated if an error continues during
//     OrderSendReliableMKT.  No additional information will be logged
//     since OrderSendReliableMKT would have already logged the error
//     condition
//
//  ORIGINAL AUTHOR AND DATE:
//     Jack Tomlinson, 2007-05-29
//
//=============================================================================
int OrderSendReliable2Step(string symbol, int cmd, double volume, double price,
                           int slippage, double stoploss, double takeprofit,
                           string comment="", int magic=0, datetime expiration=0,
                           color arrow_color=CLR_NONE)
{
    OrderReliable_Fname = "OrderSendReliable2Step";
    int ticket = -1;
    double slipped = 0;
  
  price = NormalizeDouble(price, Digits);
    takeprofit = NormalizeDouble(takeprofit, Digits);
    stoploss = NormalizeDouble(stoploss, Digits);
    
    // ========================================================================
    // If testing or optimizing, there is no need to use this lib, as the 
    // orders are not real-world, and always get placed optimally.  By 
    // refactoring this option to be in this library, one no longer needs 
    // to create similar code in each EA.
    if (!UseForTesting)
    {
        if (IsOptimization()  ||  IsTesting())
        {
            ticket = OrderSend(symbol, cmd, volume, price, slippage, 0, 0, 
                               comment, magic, 0, arrow_color);

            if (!OrderModify(ticket, price, stoploss, takeprofit, expiration, arrow_color))
                OrderReliablePrint("Order Modify of Ticket #" + IntegerToString(ticket) + " FAILED");
            
            return(ticket);
        }
    }
    // ========================================================================
    
    
    OrderReliablePrint("Doing OrderSendReliable, followed by OrderModifyReliable:");

    ticket = OrderSendReliable(symbol, cmd, volume, price, slippage,
                                0, 0, comment, magic, expiration, arrow_color);

    if (stoploss != 0 || takeprofit != 0)
    {
        if (ticket >= 0)
        {
            double theOpenPrice = price;
            if (OrderSelect(ticket, SELECT_BY_TICKET))
            {
                slipped = OrderOpenPrice() - price;
                theOpenPrice = OrderOpenPrice();
            }
            else
                OrderReliablePrint("Failed to select ticket #" + IntegerToString(ticket) + " after successful 2step placement; cannot recalculate SL & TP");
            if (slipped > 0)
            {
                OrderReliablePrint("2step order slipped by: " + DoubleToStr(slipped, Digits) + "; SL & TP modified by same amount");
                if (takeprofit != 0)    takeprofit += slipped;
                if (stoploss != 0)        stoploss += slipped;
            }
            OrderModifyReliable(ticket, theOpenPrice, stoploss, takeprofit, expiration, arrow_color);
        }
    }
    else
        OrderReliablePrint("Skipping OrderModifyReliable because no SL or TP specified.");

    return(ticket);
}


//=============================================================================
//                             OrderModifyReliable()
//
//  This is intended to be a drop-in replacement for OrderModify() which,
//  one hopes, is more resistant to various forms of errors prevalent
//  with MetaTrader.
//
//  RETURN VALUE:
//     TRUE if successful, FALSE otherwise
//
//  FEATURES:
//     * Re-trying under some error conditions, sleeping a random
//       time defined by an exponential probability distribution.
//
//     * Displays various error messages on the log for debugging.
//
//
//  ORIGINAL AUTHOR AND DATE:
//     Matt Kennel, 2006-05-28
//
//=============================================================================
bool OrderModifyReliable(int ticket, double price, double stoploss,
                         double takeprofit, datetime expiration,
                         color arrow_color=CLR_NONE)
{
    OrderReliable_Fname = "OrderModifyReliable";
    bool result = false;
    bool non_retryable_error = false;

    // ========================================================================
    // If testing or optimizing, there is no need to use this lib, as the 
    // orders are not real-world, and always get placed optimally.  By 
    // refactoring this option to be in this library, one no longer needs 
    // to create similar code in each EA.
    if (!UseForTesting)
    {
        if (IsOptimization()  ||  IsTesting())
        {
            result = OrderModify(ticket, price, stoploss,
                                 takeprofit, expiration, arrow_color);
            return(result);
        }
    }
    // ========================================================================
    
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Get information about this order
    string symbol = "ALLOCATE";        // This is so it has memory space allocated
    int type;
    int digits;
    double point;
    double bid, ask;
    double sl, tp;
    GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask);
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        
    
    OrderReliablePrint("Attempted modify of #" + IntegerToString(ticket) + " price:" + DoubleToStr(price, digits+1) +
                       " sl:" + DoubleToStr(stoploss, digits+1) + " tp:" + DoubleToStr(takeprofit, digits+1) + 
                       " exp:" + TimeToStr(expiration));

    // Below, we call "EnsureValidStops".  If the order we are modifying 
    // is a pending order, then we should use the price passed in.  But 
    // if it's an open order, the price passed in is irrelevant; we need 
    // to use the appropriate bid or ask, so get those...
    double prc = price;
    if (type == OP_BUY)            prc = bid;
    else if (type == OP_SELL)    prc = ask;

    // With the requisite info, we can do error checking on SL & TP
    prc = NormalizeDouble(prc, digits);
    price = NormalizeDouble(price, digits);
    stoploss = NormalizeDouble(stoploss, digits);
    takeprofit = NormalizeDouble(takeprofit, digits);
    
    // If SL/TP are not changing then send in zeroes to EnsureValidStops(),
    // so that it does not bother to try to change them
    double newSL = stoploss;
    double newTP = takeprofit;
    if (stoploss == sl)        newSL = 0;
    if (takeprofit == tp)    newTP = 0;
    EnsureValidStops(symbol, type, prc, newSL, newTP, false);
    if (stoploss != sl)        stoploss = newSL;
    if (takeprofit != tp)    takeprofit = newTP;


    int cnt = 0;
    int cnt_bad_price = 0;
    int err = GetLastError(); // so we clear the global variable.
    err = 0;
    bool exit_loop = false;

    while (!exit_loop)
    {
        result = OrderModify(ticket, price, stoploss,
                             takeprofit, expiration, arrow_color);
        err = GetLastError();

        if (result == true)
            exit_loop = true;
        else
        {
            switch (err)
            {
                case ERR_NO_ERROR:
                    exit_loop = true;
                    OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting");
                    break;

                case ERR_NO_RESULT:
                    // Modification to same value as before
                    // See below for reported result
                    exit_loop = true;
                    break;

                // Shouldn't be any reason stops are invalid (and yet I've seen it); try again
                case ERR_INVALID_PRICE:
                case ERR_INVALID_STOPS:    
                    OrderReliablePrint("OrderModifyReliable, ERR_INVALID_STOPS, Broker\'s Min Stop Level (in pips) = " + DoubleToStr(MarketInfo(symbol, MODE_STOPLEVEL) * Point / AdjPoint(symbol), 1));
//                    EnsureValidStops(symbol, price, stoploss, takeprofit);
               cnt_bad_price++;
               
                case ERR_COMMON_ERROR:
                case ERR_SERVER_BUSY:
                case ERR_NO_CONNECTION:
                case ERR_TOO_FREQUENT_REQUESTS:
                case ERR_TRADE_TIMEOUT:        // for modify this is a retryable error, I hope.
                case ERR_OFF_QUOTES:
                case ERR_BROKER_BUSY:
                case ERR_TOO_MANY_REQUESTS:
                case ERR_TRADE_CONTEXT_BUSY:
                case ERR_TRADE_DISABLED:
                case ERR_MARKET_CLOSED:
                    cnt++;     // a retryable error
                    break;

                case ERR_TRADE_MODIFY_DENIED:
                    // This one may be important; have to Ensure Valid Stops AND valid price (for pends)
                    break;
                
                case ERR_PRICE_CHANGED:
                case ERR_REQUOTE:
                    RefreshRates();
                    continue;     // we can apparently retry immediately according to MT docs.

                default:
                    // an apparently serious, unretryable error.
                    exit_loop = true;
                    non_retryable_error = true;
                    break;

            }  // end switch
        }

        if (cnt > retry_attempts)
            exit_loop = true;

        if (cnt_bad_price > retry_attempts_bad_price)
            exit_loop = true;

        if (!exit_loop)
        {
            OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+"("+IntegerToString(retry_attempts_bad_price)+")" + ": Retryable error: " + OrderReliableErrTxt(err));
            
            SleepRandomTime(sleep_time, sleep_maximum);
            RefreshRates();
        }
        else
        {
            if (cnt > retry_attempts)
                OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts));
            else if (non_retryable_error)
                OrderReliablePrint("Non-retryable error: "  + OrderReliableErrTxt(err));
        }
    }

    // we have now exited from loop.
    if (err == ERR_NO_RESULT)
    {
        OrderReliablePrint("Server reported modify order did not actually change parameters.");
        OrderReliablePrint("Redundant modification: " + IntegerToString(ticket) + " " + symbol +
                           "@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss));
        OrderReliablePrint("Suggest modifying code logic to avoid.");
    }
    
    if (result)
    {
        OrderReliablePrint("Ticket #" + IntegerToString(ticket) + ": Modification successful, updated trade details follow.");
        if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
            OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(ticket));
        sqOrderPrint();
    }
    else
    {
        OrderReliablePrint("Failed to execute modify after " + IntegerToString(retry_attempts) + " retries");
        OrderReliablePrint("Failed modification: "  + IntegerToString(ticket) + " " + symbol +
                           "@" + DoubleToStr(price) + " tp@" + DoubleToStr(takeprofit) + " sl@" + DoubleToStr(stoploss));
        OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
    }
    
    return(result);
}


//=============================================================================
//                            OrderCloseReliable()
//
//  This is intended to be a drop-in replacement for OrderClose() which,
//  one hopes, is more resistant to various forms of errors prevalent
//  with MetaTrader.
//
//  RETURN VALUE:
//     TRUE if successful, FALSE otherwise
//
//  FEATURES:
//     * Re-trying under some error conditions, sleeping a random
//       time defined by an exponential probability distribution.
//
//     * Displays various error messages on the log for debugging.
//
//  ORIGINAL AUTHOR AND DATE:
//     Derk Wehler, 2006-07-19
//
//=============================================================================
bool OrderCloseReliable(int ticket, double volume, double price,
                        int slippage, color arrow_color=CLR_NONE)
{
    OrderReliable_Fname = "OrderCloseReliable";
    bool result = false;
    bool non_retryable_error = false;
    
    // ========================================================================
    // If testing or optimizing, there is no need to use this lib, as the 
    // orders are not real-world, and always get placed optimally.  By 
    // refactoring this option to be in this library, one no longer needs 
    // to create similar code in each EA.
    if (!UseForTesting)
    {
        if (IsOptimization()  ||  IsTesting())
        {
            result = OrderClose(ticket, volume, price, slippage, arrow_color);
            return(result);
        }
    }
    // ========================================================================
    

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Get information about this order
    string symbol = "ALLOCATE";        // This is so it has memory space allocated
    int type;
    int digits;
    double point;
    double bid, ask;
    double sl, tp;
    GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask);
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    
    
    OrderReliablePrint("Attempted close of #" + IntegerToString(ticket) + " initial price:" + DoubleToStr(price, digits+1) +
                       " lots:" + DoubleToStr(volume, 3) + " slippage:" + IntegerToString(slippage));


    if (type != OP_BUY && type != OP_SELL)
    {
        OrderReliablePrint("Error: Trying to close ticket #" + IntegerToString(ticket) + ", which is " + OrderTypeToString(type) + ", not OP_BUY or OP_SELL");
        return(false);
    }


    int cnt = 0;
    int err = GetLastError(); // so we clear the global variable.
    err = 0;
    bool exit_loop = false;
    double priceNow = 0;
    double hasSlippedBy = 0;

    while (!exit_loop)
    {
        // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =
        // Get current price and calculate slippage
        RefreshRates();
        if (type == OP_BUY)
        {
            priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS));    // Close @ Bid
            hasSlippedBy = (price - priceNow) / point;    // (Adjusted Point)
        }
        else if (type == OP_SELL)
        {
            priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS));    // Close @ Ask
            hasSlippedBy = (priceNow - price) / point;    // (Adjusted Point)
        }

        // Check if slippage is more than caller's maximum allowed
        if (priceNow != price  &&  hasSlippedBy > slippage)
        {
            // Actual price has slipped against us more than user allowed
            // Log error message, sleep, and try again
            OrderReliablePrint("Actual Price (Bid for buy, Ask for sell) Value = " + DoubleToStr(priceNow, Digits) + "; Slippage from Requested Price = " + DoubleToStr(hasSlippedBy, 1) + " pips.  Retrying...");
            result = false;
            err = ERR_PRICE_CHANGED;
        }
        else
        {
            result = OrderClose(ticket, volume, priceNow, (int)(slippage - hasSlippedBy), arrow_color);
            err = GetLastError();
        }
        // = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : = : =

        if (result == true)
            exit_loop = true;
        else
        {
            switch (err)
            {
                case ERR_NO_ERROR:
                    exit_loop = true;
                    OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting");
                    OrderReliablePrint("If order did not actually close, error code is apparently wrong");
                    break;

                case ERR_NO_RESULT:
                    exit_loop = true;
                    OrderReliablePrint("ERR_NO_RESULT received, but OrderClose() returned false; exiting");
                    OrderReliablePrint("If order did not actually close, error code is apparently wrong");
                    break;

                case ERR_INVALID_PRICE:
                    OrderReliablePrint("ERR_INVALID_PRICE received, but should not occur since we are refreshing rates");
                    cnt++;     // a retryable error
                    break;

                case ERR_PRICE_CHANGED:
                case ERR_COMMON_ERROR:
                case ERR_SERVER_BUSY:
                case ERR_NO_CONNECTION:
                case ERR_TOO_FREQUENT_REQUESTS:
                case ERR_TRADE_TIMEOUT:        // for close this is a retryable error, I hope.
                case ERR_TRADE_DISABLED:
                case ERR_OFF_QUOTES:
                case ERR_BROKER_BUSY:
                case ERR_REQUOTE:
                case ERR_TOO_MANY_REQUESTS:    
                case ERR_TRADE_CONTEXT_BUSY:
                case ERR_MARKET_CLOSED:
                    cnt++;     // a retryable error
                    break;

                default:
                    // Any other error is an apparently serious, unretryable error.
                    exit_loop = true;
                    non_retryable_error = true;
                    break;

            }  // end switch
        }

        if (cnt > retry_attempts)
            exit_loop = true;

        if (exit_loop)
        {
            if (cnt > retry_attempts)
                OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts));
            else if (non_retryable_error)
                OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
        }
        else
        {
            OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) + ": Retryable error: " + OrderReliableErrTxt(err));
            
            SleepRandomTime(sleep_time, sleep_maximum);
        }
    }

    // We have now exited from loop
    if (result  ||  err == ERR_NO_RESULT  ||  err == ERR_NO_ERROR)
    {
        if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
            OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + "     [ Last error: " + OrderReliableErrTxt(err) + " ]");
        else if (OrderCloseTime() > 0)    // Then it closed ok
            OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + "     [ Last error: " + OrderReliableErrTxt(err) + " ]");
        else
        {
            OrderReliablePrint("Close result reported success (or failure, but w/ERR_NO_ERROR); yet order remains!  Must re-try close from EA logic!");
            OrderReliablePrint("Close Failed: Ticket #" + IntegerToString(ticket) + ", Price: " +
                                   DoubleToString(price) + ", Slippage: " + DoubleToString(slippage));
            OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
            result = false;
        }
    }
    else
    {
        OrderReliablePrint("Failed to execute close after " + IntegerToString(cnt-1) + " retries");
        OrderReliablePrint("Failed close: Ticket #" + IntegerToString(ticket) + " @ Price: " + DoubleToString(priceNow) + 
                              " (Requested Price: " + DoubleToString(price) + "), Slippage: " + IntegerToString(slippage));
        OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
    }
    
    
    return(result);
}


//=============================================================================
//                           OrderCloseReliableMKT()
//
//    This function is intended for closing orders ASAP; the principal 
//  difference is that in its internal retry-loop, it uses the new "Bid" 
//  and "Ask" real-time variables as opposed to the OrderCloseReliable(), 
//  which uses only the price given upon entry to the routine.  More likely 
//  to get the order closed if price moves, but more likely to "slip"
//
//  RETURN VALUE:
//     TRUE if successful, FALSE otherwise
//
//  FEATURES:
//     * Re-trying under some error conditions, sleeping a random
//       time defined by an exponential probability distribution.
//
//     * Displays various error messages on the log for debugging.
//
//  ORIGINAL AUTHOR AND DATE:
//     Derk Wehler, 2009-04-03
//
//=============================================================================
bool OrderCloseReliableMKT(int ticket, double volume, double price,
                           int slippage, color arrow_color=CLR_NONE)
{
    OrderReliable_Fname = "OrderCloseReliableMKT";
    bool result = false;
    bool non_retryable_error = false;
    
    // ========================================================================
    // If testing or optimizing, there is no need to use this lib, as the 
    // orders are not real-world, and always get placed optimally.  By 
    // refactoring this option to be in this library, one no longer needs 
    // to create similar code in each EA.
    if (!UseForTesting)
    {
        if (IsOptimization()  ||  IsTesting())
        {
            result = OrderClose(ticket, volume, price, slippage, arrow_color);
            return(result);
        }
    }
    // ========================================================================
    

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Get information about this order
    string symbol = "ALLOCATE";        // This is so it has memory space allocated
    int type;
    int digits;
    double point;
    double bid, ask;
    double sl, tp;
    GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask);
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    
    
    OrderReliablePrint("Attempted close of #" + IntegerToString(ticket) + " initial price:" + DoubleToStr(price, digits+1) +
                       " lots:" + DoubleToStr(price, 3) + " slippage:" + IntegerToString(slippage));


    if (type != OP_BUY && type != OP_SELL)
    {
        OrderReliablePrint("Error: Trying to close ticket #" + IntegerToString(ticket) + ", which is " + OrderTypeToString(type) + ", not OP_BUY or OP_SELL");
        return(false);
    }


    int cnt = 0;
    int err = GetLastError(); // so we clear the global variable.
    err = 0;
    bool exit_loop = false;
    double pnow = 0;
    int slippagenow = 0;

    while (!exit_loop)
    {
        if (type == OP_BUY)
        {
            pnow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS)); // we are buying at Ask
            if (pnow > price)
            {
                // Do not allow slippage to go negative; will cause error
                slippagenow = (int) MathMax(0, slippage - (pnow - price) / point);
            }
        }
        else if (type == OP_SELL)
        {
            pnow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS)); // we are buying at Ask
            if (pnow < price)
            {
                // Do not allow slippage to go negative; will cause error
                slippagenow = (int) MathMax(0, slippage - (price - pnow) / point);
            }
        }

        result = OrderClose(ticket, volume, pnow, slippagenow, arrow_color);
        err = GetLastError();

        if (result == true)
            exit_loop = true;
        else
        {
            switch (err)
            {
                case ERR_NO_ERROR:
                    exit_loop = true;
                    OrderReliablePrint("ERR_NO_ERROR received, but OrderClose() returned false; exiting");
                    break;

                case ERR_NO_RESULT:
                    exit_loop = true;
                    OrderReliablePrint("ERR_NO_RESULT received, but OrderClose() returned false; exiting");
                    break;

                case ERR_COMMON_ERROR:
                case ERR_SERVER_BUSY:
                case ERR_NO_CONNECTION:
                case ERR_TOO_FREQUENT_REQUESTS:
                case ERR_TRADE_TIMEOUT:        // for close this is a retryable error, I hope.
                case ERR_TRADE_DISABLED:
                case ERR_PRICE_CHANGED:
                case ERR_INVALID_PRICE:
                case ERR_OFF_QUOTES:
                case ERR_BROKER_BUSY:
                case ERR_REQUOTE:
                case ERR_TOO_MANY_REQUESTS:    
                case ERR_TRADE_CONTEXT_BUSY:
                case ERR_MARKET_CLOSED:
                    cnt++;     // a retryable error
                    break;

                default:
                    // Any other error is an apparently serious, unretryable error.
                    exit_loop = true;
                    non_retryable_error = true;
                    break;

            }  // end switch
        }

        if (cnt > retry_attempts)
            exit_loop = true;

        if (!exit_loop)
        {
            OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts)+ ": Retryable error: " + OrderReliableErrTxt(err));
            
            SleepRandomTime(sleep_time, sleep_maximum);
        }

        if (exit_loop)
        {
            if (cnt > retry_attempts)
                OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts));
            else if (non_retryable_error)
                OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
        }
    }

    // we have now exited from loop.
    if (result)
    {
        if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
            OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + "     [ Last error: " + OrderReliableErrTxt(err) + " ]");
        else if (OrderCloseTime() > 0)    // Then it closed ok
            OrderReliablePrint("Successful close of Ticket #" + IntegerToString(ticket) + "     [ Last error: " + OrderReliableErrTxt(err) + " ]");
        else
        {
            OrderReliablePrint("Close result reported success, but order remains!  Must re-try close from EA logic!");
            OrderReliablePrint("Close Failed: Ticket #" + IntegerToString(ticket) + ", Price: " +
                                   DoubleToString(price) + ", Slippage: " + IntegerToString(slippage));
            OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
            result = false;
        }
    }
    else
    {
        OrderReliablePrint("Failed to execute close after " + IntegerToString(retry_attempts) + " retries");
        OrderReliablePrint("Failed close: Ticket #" + IntegerToString(ticket) + " @ Price: " +
                               DoubleToString(pnow) + " (Initial Price: " + DoubleToString(price) + "), Slippage: " + 
                               IntegerToString(slippagenow) + " (Initial Slippage: " + IntegerToString(slippage) + ")");
        OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
    }
    
    
    return(result);
}


//=============================================================================
//                            OrderDeleteReliable()
//
//  This is intended to be a drop-in replacement for OrderDelete() which,
//  one hopes, is more resistant to various forms of errors prevalent
//  with MetaTrader.
//
//  RETURN VALUE:
//     TRUE if successful, FALSE otherwise
//
//
//  FEATURES:
//     * Re-trying under some error conditions, sleeping a random
//       time defined by an exponential probability distribution.
//
//     * Displays various error messages on the log for debugging.
//
//  ORIGINAL AUTHOR AND DATE:
//     Derk Wehler, 2006-12-21
//
//=============================================================================
bool OrderDeleteReliable(int ticket, color clr=CLR_NONE)
{
    OrderReliable_Fname = "OrderDeleteReliable";
    bool result = false;
    bool non_retryable_error = false;

    // ========================================================================
    // If testing or optimizing, there is no need to use this lib, as the 
    // orders are not real-world, and always get placed optimally.  By 
    // refactoring this option to be in this library, one no longer needs 
    // to create similar code in each EA.
    if (!UseForTesting)
    {
        if (IsOptimization()  ||  IsTesting())
        {
            result = OrderDelete(ticket, clr);
            return(result);
        }
    }
    // ========================================================================
    
    
    
    OrderReliablePrint("Attempted deletion of pending order, #" + IntegerToString(ticket));
    

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    // Get information about this order
    string symbol = "ALLOCATE";        // This is so it has memory space allocated
    int type;
    int digits;
    double point;
    double bid, ask;
    double sl, tp;
    GetOrderDetails(ticket, symbol, type, digits, point, sl, tp, bid, ask);
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        
    if (type == OP_BUY || type == OP_SELL)
    {
        OrderReliablePrint("error: Trying to close ticket #" + IntegerToString(ticket) +
                           ", which is " + OrderTypeToString(type) +
                           ", not OP_BUYSTOP, OP_SELLSTOP, OP_BUYLIMIT, or OP_SELLLIMIT");
        return(false);
    }


    int cnt = 0;
    int err = GetLastError(); // so we clear the global variable.
    err = 0;
    bool exit_loop = false;

    while (!exit_loop)
    {
        result = OrderDelete(ticket, clr);
        err = GetLastError();

        if (result == true)
            exit_loop = true;
        else
        {
            switch (err)
            {
                case ERR_NO_ERROR:
                    exit_loop = true;
                    OrderReliablePrint("ERR_NO_ERROR received, but OrderDelete() returned false; exiting");
                    break;

                case ERR_NO_RESULT:
                    exit_loop = true;
                    OrderReliablePrint("ERR_NO_RESULT received, but OrderDelete() returned false; exiting");
                    break;

                case ERR_COMMON_ERROR:
                case ERR_SERVER_BUSY:
                case ERR_NO_CONNECTION:
                case ERR_TOO_FREQUENT_REQUESTS:
                case ERR_TRADE_TIMEOUT:        // for delete this is a retryable error, I hope.
                case ERR_TRADE_DISABLED:
                case ERR_OFF_QUOTES:
                case ERR_PRICE_CHANGED:
                case ERR_BROKER_BUSY:
                case ERR_REQUOTE:
                case ERR_TOO_MANY_REQUESTS:
                case ERR_TRADE_CONTEXT_BUSY:
                case ERR_MARKET_CLOSED:
                    cnt++;     // a retryable error
                    break;

                default:    // Any other error is an apparently serious, unretryable error.
                    exit_loop = true;
                    non_retryable_error = true;
                    break;

            }  // end switch
        }

        if (cnt > retry_attempts)
            exit_loop = true;

        if (!exit_loop)
        {
            OrderReliablePrint("Result of attempt " + IntegerToString(cnt) + " of " + IntegerToString(retry_attempts) + ": Retryable error: " + OrderReliableErrTxt(err));
            SleepRandomTime(sleep_time, sleep_maximum);
        }
        else
        {
            if (cnt > retry_attempts)
                OrderReliablePrint("Retry attempts maxed at " + IntegerToString(retry_attempts));
            else if (non_retryable_error)
                OrderReliablePrint("Non-retryable error: " + OrderReliableErrTxt(err));
        }
    }

    // we have now exited from loop.
    if (result)
    {
        OrderReliablePrint("Successful deletion of Ticket #" + IntegerToString(ticket));
        
        return(true); // SUCCESS!
    }
    else
    {
        OrderReliablePrint("Failed to execute delete after " + IntegerToString(retry_attempts) + " retries");
        OrderReliablePrint("Failed deletion: Ticket #" + IntegerToString(ticket));
        OrderReliablePrint("Last error: " + OrderReliableErrTxt(err));
    }
    
    
    return(result);
}

//=============================================================================
//=============================================================================
//                                Utility Functions
//=============================================================================
//=============================================================================

string OrderReliableErrTxt(int err)
{
    return (IntegerToString(err) + "  ::  " + ErrorDescription(err));
}


// Defaut level is 3
// Use level = 1 to Print all but "Retry" messages
// Use level = 0 to Print nothing
void OrderReliableSetErrorLevel(int level)
{
    ErrorLevel = level;
}


void OrderReliablePrint(string s)
{
    // Print to log prepended with stuff;
    if (ErrorLevel >= 99 || (!(IsTesting() || IsOptimization())))
    {
        if (ErrorLevel > 0)
            Print(OrderReliable_Fname + " " + OrderReliableVersion + ":     " + s);
    }
}


void sqOrderPrint() {
  Print("Ticket: "+IntegerToString(OrderTicket())+" - "+
  "OpenTime: "+TimeToString(OrderOpenTime(), TIME_DATE | TIME_MINUTES | TIME_SECONDS)+","+
  "Type: "+IntegerToString(OrderType())+","+
  "Size: "+DoubleToString(OrderLots())+","+
  "Symbol: "+OrderSymbol()+","+
  "OpenPrice: "+DoubleToString(OrderOpenPrice())+","+
  "SL: "+DoubleToString(OrderStopLoss())+","+
  "PT: "+DoubleToString(OrderTakeProfit()));

  Print("Ticket: "+IntegerToString(OrderTicket())+" (continue) - "+
  "CloseTime: "+TimeToString(OrderCloseTime(), TIME_DATE | TIME_MINUTES | TIME_SECONDS)+","+
  "ClosePrice: "+DoubleToString(OrderClosePrice())+","+
  "Commission: "+DoubleToString(OrderCommission())+","+
  "Swap: "+DoubleToString(OrderSwap())+","+
  "Profit: "+DoubleToString(OrderProfit())+","+
  "Comment: "+OrderComment()+","+
  "MagicNumber: "+IntegerToString(OrderMagicNumber()));
}

string OrderTypeToString(int type)
{
    if (type == OP_BUY)         return("BUY");
    if (type == OP_SELL)         return("SELL");
    if (type == OP_BUYSTOP)     return("BUY STOP");
    if (type == OP_SELLSTOP)    return("SELL STOP");
    if (type == OP_BUYLIMIT)     return("BUY LIMIT");
    if (type == OP_SELLLIMIT)    return("SELL LIMIT");
    return("None (" + IntegerToString(type) + ")");
}


//=============================================================================
//                        EnsureValidStops()
//
//  Most MQ4 brokers have a minimum stop distance, which is the number of 
//  pips from price where a pending order can be placed or where a SL & TP 
//  can be placed.  THe purpose of this function is to detect when the 
//  requested SL or TP is too close, and to move it out automatically, so 
//  that we do not get ERR_INVALID_STOPS errors.
//
//  FUNCTION COMPLETELY OVERHAULED:
//     Derk Wehler, 2008-11-08
//
//=============================================================================
void EnsureValidStops(string symbol, int cmd, double price, double& sl, double& tp, bool isNewOrder=true)
{
    string prevName = OrderReliable_Fname;
    OrderReliable_Fname = "EnsureValidStops";
    
    double point = MarketInfo(symbol, MODE_POINT);
    
    // We only use point for StopLevel, and StopLevel is reported as 10 times
    // what you expect on a 5-digit broker, so leave it as is.
    //if (point == 0.001  ||  point == 0.00001)
    //    point *= 10;
        
    double     orig_sl = sl;
    double     orig_tp = tp;
    double     new_sl, new_tp;
    int     min_stop_level = (int) MarketInfo(symbol, MODE_STOPLEVEL);
    double     servers_min_stop = min_stop_level * point;
    double     spread = MarketInfo(symbol, MODE_ASK) - MarketInfo(symbol, MODE_BID);
    //Print("        EnsureValidStops: Symbol = " + symbol + ",  servers_min_stop = " + servers_min_stop); 

    // Skip if no S/L (zero)
    if (sl != 0)
    {
        if (cmd % 2 == 0)    // we are long
        {
            // for pending orders, sl/tp can bracket price by servers_min_stop
            new_sl = price - servers_min_stop;
            //Print("        EnsureValidStops: new_sl [", new_sl, "] = price [", price, "] - servers_min_stop [", servers_min_stop, "]"); 
            
            // for market order, sl/tp must bracket bid/ask
            if (cmd == OP_BUY  &&  isNewOrder)
            {
                new_sl -= spread;    
                //Print("        EnsureValidStops: Minus spread [", spread, "]"); 
            }
            sl = MathMin(sl, new_sl);
        }
        else    // we are short
        {
            new_sl = price + servers_min_stop;    // we are short
            //Print("        EnsureValidStops: new_sl [", new_sl, "] = price [", price, "] + servers_min_stop [", servers_min_stop, "]"); 
            
            // for market order, sl/tp must bracket bid/ask
            if (cmd == OP_SELL  &&  isNewOrder)
            {
                new_sl += spread;    
                //Print("        EnsureValidStops: Plus spread [", spread, "]"); 
            }

            sl = MathMax(sl, new_sl);
        }
        sl = NormalizeDouble(sl, (int) MarketInfo(symbol, MODE_DIGITS));
    }


    // Skip if no T/P (zero)
    if (tp != 0)
    {
        // check if we have to adjust the stop
        if (MathAbs(price - tp) <= servers_min_stop)
        {
            if (cmd % 2 == 0)    // we are long
            {
                new_tp = price + servers_min_stop;    // we are long
                tp = MathMax(tp, new_tp);
            }
            else    // we are short
            {
                new_tp = price - servers_min_stop;    // we are short
                tp = MathMin(tp, new_tp);
            }
            tp = NormalizeDouble(tp, (int) MarketInfo(symbol, MODE_DIGITS));
        }
    }
    
    // notify if changed
    if (sl != orig_sl)
        OrderReliablePrint("SL was too close to brokers min distance (" + IntegerToString(min_stop_level) + "); moved SL to: " + DoubleToString(sl));
    if (tp != orig_tp)
        OrderReliablePrint("TP was too close to brokers min distance (" + IntegerToString(min_stop_level) + "); moved TP to: " + DoubleToString(tp));
        
    OrderReliable_Fname = prevName;
}


//=============================================================================
//                            EnsureValidPendPrice()
//
//  This function is called if OrderSendReliable gets an ERR_INVALID_PRICE 
//  or ERR_INVALID_STOPS error when attempting to place a pending order. 
//  We assume these are signs that the brokers minumum stop distance, which 
//  is what is used for pending distances as well, is too small and the price 
//  is too close to the pending's requested price.  Therefore we want to do 
//  one of two things: 
//
//  If UseLimitToMarket is enabled, then see if the actual and requested 
//  prices are close enough to be within the requested slippage, and if so 
//  return true to indicate a swap to a market order.
//
//  Otherwise, we move the requested price far enough from current price to 
//  (hopefully) place the pending order, and return false (price, sl & tp  
//  are all I/O params).  If this does not work, and the the same error is 
//  received, and the function is called again, it attempts to move the 
//  entry price (and sl & tp) out one more pip at a time.
//
//  RETURN VALUE:
//     True if calling function should convert this to market order, 
//     otherwise False
//
//  ORIGINAL AUTHOR AND DATE:
//     Derk Wehler, 2011-05-17
//
//=============================================================================
bool EnsureValidPendPrice(int err, bool& fixed, string symbol, int cmd, double& price, 
                          double& stoploss, double& takeprofit, int slippage, double point, int digits)
{
    OrderReliable_Fname = "EnsureValidPendPrice";

    double     servers_min_stop = MarketInfo(symbol, MODE_STOPLEVEL) * Point;
    double     old_price, priceNow = 0, hasSlippedBy;
    
    // Assume buy pendings relate to Ask, and sell pendings relate to Bid
    if (cmd % 2 == OP_BUY)
        priceNow = NormalizeDouble(MarketInfo(symbol, MODE_ASK), (int) MarketInfo(symbol, MODE_DIGITS));
    else if (cmd % 2 == OP_SELL)
        priceNow = NormalizeDouble(MarketInfo(symbol, MODE_BID), (int) MarketInfo(symbol, MODE_DIGITS));

    // If we are too close to put in a limit/stop order so go to market.
    if (MathAbs(priceNow - price) <= servers_min_stop)
    {
        if (UseLimitToMarket)
        {
            hasSlippedBy = MathAbs(priceNow - price) / point;    // (Adjusted Point)

            // Check if slippage is more than caller's maximum allowed
            if (priceNow != price  &&  hasSlippedBy > slippage)
            {
                // Actual price is too far from requested price to do market order, 
                // and too close to place pending order (because of broker's minimum 
                // stop distance).  Therefore, report the problem and try again...
                OrderReliablePrint("Actual price (Ask for buy, Bid for sell) = " + DoubleToStr(priceNow, Digits) + ", and requested pend price = " + DoubleToStr(priceNow, Digits) + "; slippage between the two = ?" + DoubleToStr(hasSlippedBy, 1) + " pips, which is larger than user specified.  Cannot Convert to Market Order.");
            }
            else
            {
                // Price has moved close enough (within slippage) to requested 
                // pending price that we can go ahead and enter a market position
                return(true);
            }
        }
        else 
        {
            if (fixed)
            {
                if (cmd == OP_BUYSTOP  ||  cmd == OP_SELLLIMIT)
                {
                    price += point;
                    if (stoploss > 0)   stoploss += point;
                    if (takeprofit > 0) takeprofit += point;
                    OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " Order still has \'" + ErrorDescription(err) + "\', adding 1 pip; new price = " + DoubleToStr(price, Digits));
                    if (stoploss > 0  ||  takeprofit > 0)
                        OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
                }
                else if (cmd == OP_BUYLIMIT  ||  cmd == OP_SELLSTOP)
                {
                    price -= point;
                    if (stoploss > 0)   stoploss -= point;
                    if (takeprofit > 0) takeprofit -= point;
                    OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " Order still has \'" + ErrorDescription(err) + "\', subtracting 1 pip; new price = " + DoubleToStr(price, digits));
                    if (stoploss > 0  ||  takeprofit > 0)
                        OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
                }
            }
            else
            {
                if (cmd == OP_BUYLIMIT)
                {
                    old_price = price;
                    price = priceNow - servers_min_stop;
                    if (stoploss > 0)   stoploss += (price - old_price);
                    if (takeprofit > 0) takeprofit += (price - old_price);
                    OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits));
                    if (stoploss > 0  ||  takeprofit > 0)
                        OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
                }
                else if (cmd == OP_BUYSTOP)
                {
                    old_price = price;
                    price = priceNow + servers_min_stop;
                    if (stoploss > 0)   stoploss += (price - old_price);
                    if (takeprofit > 0) takeprofit += (price - old_price);
                    OrderReliablePrint("Pending " + OrderTypeToString(cmd) + " has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits));
                    if (stoploss > 0  ||  takeprofit > 0)
                        OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
                }
                else if (cmd == OP_SELLSTOP)
                {
                    old_price = price;
                    price = priceNow - servers_min_stop;
                    if (stoploss > 0)   stoploss -= (old_price - price);
                    if (takeprofit > 0) takeprofit -= (old_price - price);
                    OrderReliablePrint("Pending SellStop has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits));
                    if (stoploss > 0  ||  takeprofit > 0)
                        OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
                }
                else if (cmd == OP_SELLLIMIT)
                {
                    old_price = price;
                    price = priceNow + servers_min_stop;
                    if (stoploss > 0)   stoploss -= (old_price - price);
                    if (takeprofit > 0) takeprofit -= (old_price - price);
                    OrderReliablePrint("Pending SellLimit has \'" + ErrorDescription(err) + "\'; new price = " + DoubleToStr(price, digits));
                    if (stoploss > 0  ||  takeprofit > 0)
                        OrderReliablePrint("NOTE: SL (now " + DoubleToStr(stoploss, digits) + ") & TP (now " + DoubleToStr(takeprofit, digits) + ") were adjusted proportionately");
                }
                fixed = true;
            }
            EnsureValidStops(symbol, cmd, price, stoploss, takeprofit);
        }
    }
    return(false);
}


//=============================================================================
//                              SleepRandomTime()
//
//  This sleeps a random amount of time defined by an exponential
//  probability distribution. The mean time, in Seconds is given
//  in 'mean_time'.
//
//  This is the back-off strategy used by Ethernet.  This will
//  quantize in fiftieths of seconds, so don't call this with a too
//  small a number.  This returns immediately if we are backtesting
//  and does not sleep.
//
//=============================================================================
void SleepRandomTime(double mean_time, double max_time)
{
    // No need for pauses on tester
    if (IsTesting())
        return;
/*
    // 19Jun16 : Noticed for a long time that when an order fails, 
    // it fails all 10 tries.  So try a different tack here and just 
    // sleep a set time per try.
    Sleep(200);
    return;
*/

    double tenths = MathCeil(mean_time / 0.1);
    if (tenths <= 0)
        return;

    int maxtenths = (int) MathRound(max_time / 0.1);        // 250
    double p = 1.0 - 1.0 / tenths;                    // 0.975

    // Always sleep at least some minimum
    Sleep(20);

    // Now loop through and sleep 1/10th second a max of 
    // (10 * mean_time) times.  But break out "randomly".
    for (int i = 0; i < maxtenths; i++)
    {
        if (MathRand() > p*32768)
            break;

        // MathRand() returns in 0..32767
        Sleep(20);
    }
}


//=============================================================================
//  Adjusted Point funtion
//=============================================================================
double AdjPoint(string sym="")
{
    if (sym == "")
        sym = Symbol();
    double ticksize = MarketInfo(sym, MODE_TICKSIZE);
    if (ticksize == 0.00001  ||  ticksize == 0.001)
        ticksize *= 10;
    return(ticksize);
}


//=============================================================================
//                                LimitToMarket()
//
//  Setting to toggle what OrderSendReliable does with Stop or Limit orders
//  that are requested to be placed too close to the current price.  
//
//  When set True, it will turn any such conundrum from a stop/limit order 
//  into a simple market order
//
//  When set False, the library will alter the price of the Stop/Limit order\
//  just far enough to be able to place the order as a pending order.
//
//=============================================================================
void LimitToMarket(bool limit2market)
{
    UseLimitToMarket = limit2market;
}


//=============================================================================
//                        OrderReliableUseForTesting()
//
//  Setting to toggle whether this OrderReliable library is used in testing 
//  and optimization.  By default, it is set to false, and will thus just pass 
//  orders straight through.
//
//  When set true, it will use the full functions as normally all the time,
//  including testing / optimization.
//
//=============================================================================
void OrderReliableUseForTesting(bool use)
{
    UseForTesting = use;
}


//=============================================================================
//                      OrderReliableAddSpreadToComment()
//
//  Setting to toggle whether this to add the current spread to the trade 
//  commment, so that user can monitor variable spread situations on a 
//  per trade basis.
//
//=============================================================================
void OrderReliableAddSpreadToComment(bool use)
{
    AddSpreadToComment = use;
}


//=============================================================================
//                              GetOrderDetails()
//
//  For some OrderReliable functions (such as Modify), we need to know some
//  things about the order (such as direction and symbol).  To do this, we 
//  need to select the order.  However, the caller may already have an order 
//  selected so we need to be responsible and put it back when done.
//
//  Return false if there is a problem, true otherwise.
//
//=============================================================================
bool GetOrderDetails(int ticket, string& symb, int& type, int& digits, 
                     double& point, double& sl, double& tp, double& bid, 
                     double& ask, bool exists=true)
{
    // If this is existing order, select it and get symbol and type
    if (exists)
    {
        int lastTicket = OrderTicket();
        if (!OrderSelect(ticket, SELECT_BY_TICKET, MODE_TRADES))
        {
            OrderReliablePrint("OrderSelect() error: " + ErrorDescription(GetLastError()));
            return(false);
        }
        symb = OrderSymbol();
        type = OrderType();
        tp = OrderTakeProfit();
        sl = OrderStopLoss();
        
        // Select back the prior ticket num in case caller was using it.
        if (lastTicket >= 0)
        {
            if (!OrderSelect(lastTicket, SELECT_BY_TICKET, MODE_TRADES))
                OrderReliablePrint("Could Not Select Ticket #" + IntegerToString(lastTicket));
        }
    }
    
    // Get bid, ask, point & digits
    bid = NormalizeDouble(MarketInfo(symb, MODE_BID), (int) MarketInfo(symb, MODE_DIGITS));
    ask = NormalizeDouble(MarketInfo(symb, MODE_ASK), (int) MarketInfo(symb, MODE_DIGITS));
    point = MarketInfo(symb, MODE_POINT);
    if (point == 0.001  ||  point == 0.00001)
        point *= 10;
        
    digits = (int) MarketInfo(symb, MODE_DIGITS);
    
    // If this is a forex pair (i.e. symbol length == 6), then digits should not be zero
    if (digits == 0  &&  StringLen(MySymbolVal2String(MySymbolConst2Val(Symbol()))) == 6)
    {
        string prevName = OrderReliable_Fname;
        OrderReliable_Fname = "GetDigits";
        OrderReliablePrint("error: MarketInfo(symbol (" + symb + "), MODE_DIGITS) == 0");
        OrderReliable_Fname = prevName;
        return(false);
    }
    else if (exists)
    {
        tp = NormalizeDouble(tp, digits);
        sl = NormalizeDouble(sl, digits);
        bid = NormalizeDouble(bid, digits);
        ask = NormalizeDouble(ask, digits);
    }
    
    return(true);
}

//=============================================================================
// 20Jul16: Not sure what BS this is; all this ised to work, but not sure how.  
// DerksUtils includes OrderReliable, but not vice versa...  So copied these 
// functions from DerksUtils and changed the names.  Also, abive, where used, 
// it WAS: StringLen(MySymbolVal2String(Symbol())) == 6), which was wrong.
//=============================================================================
int MySymbolConst2Val(string symbol) 
{
    // Handle problem of trailing chars on mini accounts.
    string mySymbol = StringSubstr(symbol,0,6); 
    
    if (mySymbol == "AUDCAD")     return(1);
    if (mySymbol == "AUDJPY")     return(2);
    if (mySymbol == "AUDNZD")     return(3);
    if (mySymbol == "AUDUSD")     return(4);
    if (mySymbol == "CADJPY")     return(5);
    if (mySymbol == "CHFJPY")     return(6);
    if (mySymbol == "EURAUD")     return(7);
    if (mySymbol == "EURCAD")     return(8);
    if (mySymbol == "EURCHF")     return(9);
    if (mySymbol == "EURGBP")     return(10);
    if (mySymbol == "EURJPY")     return(11);
    if (mySymbol == "EURUSD")     return(12);
    if (mySymbol == "GBPCHF")     return(13);
    if (mySymbol == "GBPJPY")     return(14);
    if (mySymbol == "GBPUSD")     return(15);
    if (mySymbol == "NZDJPY")     return(16);
    if (mySymbol == "NZDUSD")     return(17);
    if (mySymbol == "USDCAD")     return(18);
    if (mySymbol == "USDCHF")     return(19);
    if (mySymbol == "USDJPY")    return(20);
    
    // These symbols were added 26Sep10
    if (mySymbol == "AUDCHF")     return(22);
    if (mySymbol == "AUDDKK")     return(23);
    if (mySymbol == "AUDNOK")     return(24);
    if (mySymbol == "AUDSEK")     return(25);
    if (mySymbol == "CADCHF")     return(26);
    if (mySymbol == "CHFNOK")     return(27);
    if (mySymbol == "EURDKK")    return(28);
    if (mySymbol == "EURNZD")     return(29);
    if (mySymbol == "EURPLN")     return(30);
    if (mySymbol == "EURSEK")    return(31);
    if (mySymbol == "EURSGD")     return(32);
    if (mySymbol == "EURZAR")    return(33);
    if (mySymbol == "GBPAUD")     return(34);
    if (mySymbol == "GBPCAD")     return(35);
    if (mySymbol == "GBPNOK")     return(36);
    if (mySymbol == "GBPNZD")     return(37);
    if (mySymbol == "GBPSGD")     return(38);
    if (mySymbol == "NOKJPY")     return(39);
    if (mySymbol == "NZDCAD")     return(40);
    if (mySymbol == "NZDCHF")     return(41);
    if (mySymbol == "NZDGBP")     return(42);
    if (mySymbol == "SEKJPY")     return(43);
    if (mySymbol == "USDAED")    return(44);
    if (mySymbol == "USDBHD")    return(45);
    if (mySymbol == "USDDKK")    return(46);
    if (mySymbol == "USDEGP")    return(47);
    if (mySymbol == "USDHKD")    return(48);
    if (mySymbol == "USDJOD")    return(49);
    if (mySymbol == "USDKWD")    return(50);
    if (mySymbol == "USDMXN")    return(51);
    if (mySymbol == "USDNOK")    return(52);
    if (mySymbol == "USDPLN")    return(53);
    if (mySymbol == "USDQAR")    return(54);
    if (mySymbol == "USDSAR")    return(55);
    if (mySymbol == "USDSEK")    return(56);
    if (mySymbol == "USDSGD")    return(57);
    if (mySymbol == "USDTHB")    return(58);
    if (mySymbol == "USDZAR")    return(59);
    if (mySymbol == "XAGUSD")    return(60);
    if (mySymbol == "XAUUSD")    return(61);
    
    // Originally, this was "other"; kept 
    // the same for backward compatability
    return(21);
}


string MySymbolVal2String(int val) 
{
    if (val == 1)     return("AUDCAD");
    if (val == 2)     return("AUDJPY");
    if (val == 3)     return("AUDNZD");
    if (val == 4)     return("AUDUSD");
    if (val == 5)     return("CADJPY");
    if (val == 6)     return("CHFJPY");
    if (val == 7)     return("EURAUD");
    if (val == 😎     return("EURCAD");
    if (val == 9)     return("EURCHF");
    if (val == 10)     return("EURGBP");
    if (val == 11)     return("EURJPY");
    if (val == 12)     return("EURUSD");
    if (val == 13)     return("GBPCHF");
    if (val == 14)     return("GBPJPY");
    if (val == 15)     return("GBPUSD");
    if (val == 16)     return("NZDJPY");
    if (val == 17)     return("NZDUSD");
    if (val == 18)     return("USDCAD");
    if (val == 19)     return("USDCHF");
    if (val == 20)    return("USDJPY");
    
    // These symbols were added 26Sep10
    if (val == 22)    return("AUDCHF");
    if (val == 23)    return("AUDDKK");
    if (val == 24)    return("AUDNOK");
    if (val == 25)    return("AUDSEK");
    if (val == 26)    return("CADCHF");
    if (val == 27)    return("CHFNOK");
    if (val == 28)    return("EURDKK");
    if (val == 29)    return("EURNZD");
    if (val == 30)    return("EURPLN");
    if (val == 31)    return("EURSEK");
    if (val == 32)    return("EURSGD");
    if (val == 33)    return("EURZAR");
    if (val == 34)    return("GBPAUD");
    if (val == 35)    return("GBPCAD");
    if (val == 36)    return("GBPNOK");
    if (val == 37)    return("GBPNZD");
    if (val == 38)    return("GBPSGD");
    if (val == 39)    return("NOKJPY");
    if (val == 40)    return("NZDCAD");
    if (val == 41)    return("NZDCHF");
    if (val == 42)    return("NZDGBP");
    if (val == 43)    return("SEKJPY");
    if (val == 44)    return("USDAED");
    if (val == 45)    return("USDBHD");
    if (val == 46)    return("USDDKK");
    if (val == 47)    return("USDEGP");
    if (val == 48)    return("USDHKD");
    if (val == 49)    return("USDJOD");
    if (val == 50)    return("USDKWD");
    if (val == 51)    return("USDMXN");
    if (val == 52)    return("USDNOK");
    if (val == 53)    return("USDPLN");
    if (val == 54)    return("USDQAR");
    if (val == 55)    return("USDSAR");
    if (val == 56)    return("USDSEK");
    if (val == 57)    return("USDSGD");
    if (val == 58)    return("USDTHB");
    if (val == 59)    return("USDZAR");
    if (val == 60)    return("XAGUSD");
    if (val == 61)    return("XAUUSD");
    
    return("Unrecognized Pair");
}


//+----------------------------- Include from /MetaTrader4/CustomFunctions/GreaterCount.mq4 -------------------------------------+


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


bool sqIsGreaterCount(string indicatorIdentificationLeft,string indicatorIdentificationRight, int bars,bool NotStrict,int shift) {

       bool atLeastOnce = false;

    for(int i=0; i<bars; i++) { /// bars != Bars in mq4

        double leftIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationLeft,shift+i), 5); /// precision = 5. It returns more acccurate backtest synchronisation
        double rightIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationRight,shift+i), 5);
        
        if(leftIndicator<rightIndicator){

            return (false);
        }
        if(leftIndicator==rightIndicator && NotStrict == false){

            return (false);
        }
        if(leftIndicator>rightIndicator){

            atLeastOnce = true;
        }
    }
    return(atLeastOnce);
}

 
//+----------------------------- Include from /MetaTrader4/CustomFunctions/LowerCount.mq4 -------------------------------------+


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

bool sqIsLowerCount(string indicatorIdentificationLeft,string indicatorIdentificationRight, int bars,bool NotStrict,int shift) {

       bool atLeastOnce = false;

    for(int i=0; i<bars; i++) { /// bars != Bars in mq4

        double leftIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationLeft,shift+i), 5); /// precision = 5. It returns more acccurate backtest synchronisation
        double rightIndicator = NormalizeDouble(sqGetIndicatorByIdentification(indicatorIdentificationRight,shift+i), 5);
        
        if(leftIndicator>rightIndicator){

            return (false);
        }
        if(leftIndicator==rightIndicator && NotStrict == false){

            return (false);
        }
        if(leftIndicator<rightIndicator){

            atLeastOnce = true;
        }
    }
    return(atLeastOnce);
}


 
//+----------------------------- Include from /MetaTrader4/CustomFunctions/SessionOHLC.mq4 -------------------------------------+

double SessionOpen(string symbol, int tf, int startHours, int startMinutes, int daysAgo){
   return getSessionPrice(symbol, tf, 1, startHours, startMinutes, startHours, startMinutes, daysAgo);
}

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

double SessionHigh(string symbol, int tf, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){
   return getSessionPrice(symbol, tf, 2, startHours, startMinutes, endHours, endMinutes, daysAgo);
}

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

double SessionLow(string symbol, int tf, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){
   return getSessionPrice(symbol, tf, 3, startHours, startMinutes, endHours, endMinutes, daysAgo);
}

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

double SessionClose(string symbol, int tf, int endHours, int endMinutes, int daysAgo){
   return getSessionPrice(symbol, tf, 4, endHours, endMinutes, endHours, endMinutes, daysAgo);
}

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

double getSessionPrice(string symbol, int tf, int type, int startHours, int startMinutes, int endHours, int endMinutes, int daysAgo){
   string correctedSymbol = correctSymbol(symbol);
   return iCustom(correctedSymbol, tf, "SqSessionOHLC", type, startHours, startMinutes, endHours, endMinutes, daysAgo, 0, 0);
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/SRPercRankAboveLevelXBars.mqh -------------------------------------+


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

bool sqSRPercRankAboveLevelXBars(int mode,int lenght,int ATRPeriod,double Level, int bars,int shift) {

    bool atLeastOnce = false;

    for(int i=0; i<bars; i++) {  /// bars != Bars in mq4

        if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)<Level){
            
            return (false);
        }
        if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)>Level){
            
            atLeastOnce = true;
        }
    }
    return(atLeastOnce);
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/SRPercRankBelowLevelXBars.mqh -------------------------------------+

bool sqSRPercRankBelowLevelXBars(int mode,int lenght,int ATRPeriod,double Level, int bars,int shift) {
    bool atLeastOnce = false;

    for(int i=0; i<bars; i++) {  /// bars != Bars in mq4

        if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)>Level){
            
            return (false);
        }
        if(NormalizeDouble(iCustom(NULL,0,"SqSRPercentRank",mode,lenght,ATRPeriod,0,shift+i),5)<Level){
            
            atLeastOnce = true;
        }
    }
    return(atLeastOnce);
}
//+----------------------------- Include from /MetaTrader4/CustomFunctions/CustomFunctions.mq4 -------------------------------------+

//+------------------------------------------------------------------+
//+ Custom functions
//+
//+ Here you can define your own custom functions that can be used
//+ in Algo Wizard.
//+ The functions can perform some action (for example draw on chart
//+ or manipulate with orders) or they can return value that
//+ can be used in comparison.
//+
//+ Note! All the functions below must be in valid MQL code!
//+ Contents of this file will be appended to your EA code.
//+
//+------------------------------------------------------------------+

double exampleFunction(double value) {
   return(2 * value);
}

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

 

Thousand thanks in advance :)

Screenshot 2022-12-30 151219.png

Edited by Dellan
  • Like 1
Link to comment

2 answers to this question

Recommended Posts

  • 0

Hi @Dellan,

Due to the variables involved with expert advisors we are not able to provide much help unfortunately. It could be a corrupt file or possibly it could only work on a specific account type or base currency or even a particular symbol naming convention.  For support running the EA we would suggest speaking to the creator of the expert advisor.

All the best!

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • image.png

  • Posts

    • Recently, the Australian S&P/ASX 200 index slightly fell by 0.01%, with this fluctuation mainly influenced by the latest release of the Consumer Price Index (CPI) data. This data not only demonstrates current inflationary pressures but also directly impacts the stock market in the short term. Senior analyst Thomas McGee delves into the impact of these economic indicators on the Australian stock market and discusses the economic logic behind this data and its potential effects on future monetary policy by the Reserve Bank of Australia (RBA). Market Impact of Inflation Data The CPI data for the first quarter released today showed an annual growth rate of 3.6%, surpassing the market expectation of 3.4%. This immediate announcement led to a drop of about 0.5% in the S&P/ASX 200 index, and the market failed to recover these losses by the closing bell. Thomas McGee points out that this rapid response highlights the sensitivity of investors to inflation trends and their immediate impact on the stock market. In addition to the direct reaction of the stock market, the yield of Australian 2-year government bonds also significantly rose by 0.12%, breaking the 4.4% level for the first time since December last year. This change not only reflects the response of the bond market to the CPI data but may also indicate a cautious stance by the RBA regarding rate adjustments in the short term. Forward-looking Analysis of Monetary Policy Following the release of inflation data, the expectation on the market of the first rate cut of RBA has been postponed to after 2025. Thomas McGee emphasizes the importance of this change for investment strategies. He suggests that investors consider how changes in monetary policy will affect market dynamics when making long-term investment decisions, especially in a scenario where rates may remain elevated for an extended period. With inflation data showing higher than expected figures, the market predicts that the RBA may not cut rates in the short term, intensifying expectations of rate hikes. Thomas McGee mentions that this shift in expectations requires investors to reassess their investment portfolios, particularly in terms of fixed-income asset allocation. Furthermore, Thomas McGee notes that although the market may face pressure in the short term, this could also present entry opportunities for investors seeking higher yields. Companies that can maintain cash flow in a high-rate environment may become preferred investment targets. Addressing Challenges and Seizing Opportunities Despite the uncertainties and challenges brought by the current inflation data, Thomas McGee believes that investors can still find stable investment opportunities in this complex environment through thorough market analysis and understanding of future economic policy trends. He encourages investors to maintain flexible investment strategies while closely monitoring changes in economic indicators and central bank policies to effectively address potential market fluctuations and achieve value growth in future investments.
    • EURUSD Elliott Wave Analysis Trading Lounge Day Chart,     Euro/U.S.Dollar(EURUSD) Day Chart     EURUSD Elliott Wave Technical Analysis   FUNCTION: Trend                                 MODE: impulsive                       STRUCTURE:red wave 3                                 POSITION: blue wave 3                               DIRECTION NEXT HIGHER DEGREES:red wave 4                                 DETAILS: red wave 2 looking completed at 1.08854  .Now red wave 3 of 3 is in play . Wave Cancel invalid level: 1.08854           The EUR/USD Elliott Wave Analysis for the Day Chart identifies a trend with impulsive characteristics, reflecting significant and consistent movement in one direction within the Elliott Wave structure. This technical analysis helps traders understand market momentum and potential shifts.   ### Function The function is described as "Trend," indicating that the analysis is focused on the overall direction of the market, typically associated with impulsive waves that drive price action forward.   ### Mode The mode is categorized as "impulsive," pointing to robust, one-directional movement, often linked to waves that exhibit strong trends and rapid price shifts. This mode typically represents the waves driving the broader trend.   ### Structure The structure is "red wave 3," suggesting that the observed wave is the third wave in a larger Elliott Wave pattern. The third wave is generally the strongest among impulsive waves, indicating significant upward or downward momentum.   ### Position The position is "blue wave 3," indicating that the analysis focuses on a specific segment of the broader wave structure. This positioning aligns with a mid-phase impulsive wave within the larger cycle.   ### Direction for the Next Higher Degrees The expected direction for the next higher degrees is "red wave 4," which usually signifies a corrective phase following the completion of an impulsive wave. This direction suggests that once red wave 3 concludes, the market could enter a consolidation or retracement period before the next impulsive phase.   ### Details The details provide more granular information about the wave structure. Red wave 2 is considered complete at the 1.08854 level, indicating that the corrective phase has likely ended, paving the way for red wave 3, which is now in play. This suggests a continuation of the impulsive trend, signifying strong market movement. The "Wave Cancel invalid level" at 1.08854 serves as a critical threshold, suggesting that if this level is breached, the current Elliott Wave structure would be invalidated, leading to a new interpretation of the market dynamics.   Overall, the EUR/USD Elliott Wave Analysis for the Day Chart points to a strong trend with impulsive movement in red wave 3, indicating significant momentum and directional movement. The completion of red wave 2 at 1.08854 suggests that the corrective phase has ended, with red wave 3 now driving the trend forward.           EURUSD Elliott Wave Analysis Trading Lounge 4 Hour Chart,     Euro/U.S.Dollar(EURUSD) 4 Hour Chart     EURUSD Elliott Wave Technical Analysis   FUNCTION: Trend                                 MODE: impulsive                       STRUCTURE:black wave 3                                 POSITION: red wave 3                               DIRECTION NEXT HIGHER DEGREES:black wave 4                                 DETAILS: black wave 2 looking completed or near to end .Now looking for black wave 3 to play or is in play . Wave Cancel invalid level: 1.08854           The EUR/USD Elliott Wave Analysis for the 4-Hour Chart provides insights into the Euro versus the U.S. Dollar market using the Elliott Wave framework. This analysis identifies a trend scenario with impulsive characteristics, indicating the presence of strong directional movement within the observed wave structure.   ### Function The function is described as "Trend," suggesting that the analysis explores a segment within the broader directional trend. This typically involves a focus on the impulsive waves that drive the primary market movement.   ### Mode The mode is categorized as "impulsive," pointing towards a strong, one-directional movement. Impulsive modes are often associated with rapid price changes and suggest a clear trend pattern, as opposed to corrective phases that indicate consolidation or retracement.   ### Structure The structure identified is "black wave 3," indicating that the observed wave pattern represents the third wave within the larger Elliott Wave cycle. Black wave 3 is typically 2 / 2 the strongest and longest among impulsive waves, indicating that the current trend may be gaining momentum.   ### Position The position of the analysis is "red wave 3," denoting that the specific wave under consideration is part of the larger black wave 3. This positioning aligns with a mid-phase impulse within the broader wave structure.   ### Direction for the Next Higher Degrees The expected direction for the next higher degrees is "black wave 4," indicating that after the completion of the current impulsive wave, the structure will likely transition into a corrective phase. Black wave 4 typically signifies a temporary retracement within a broader impulsive pattern.   ### Details The details provide more specific information about the current wave structure. Black wave 2 is considered completed or near completion, suggesting that the impulsive phase (black wave 3) is about to commence or is already underway. This is a critical juncture in the Elliott Wave cycle, as it indicates a shift from a corrective phase to a renewed impulsive trend. The Wave Cancel invalid level is set at 1.08854, indicating a key threshold. If this level is breached, the current Elliott Wave structure would be invalidated, necessitating a new interpretation of the market pattern.   In summary, the EUR/USD Elliott Wave Analysis for the 4-Hour Chart focuses on an impulsive trend structure, with black wave 3 suggesting strong market momentum. The analysis anticipates the end of a corrective phase and the beginning of an impulsive wave, with a Wave Cancel invalid level providing a key point for maintaining the validity of the current Elliott Wave structure.   Technical Analyst : Malik Awais Source : Tradinglounge.com get trial here!      
×
×
  • Create New...
us