// http://www.stevehopwoodforex.com

//please do not publish this outside of http://www.stevehopwoodforex.com
#include <stdlib.mqh>
#include <WinUser32.mqh>
#property strict
#define  NL    "\n"
string          Gap,ScreenMessage;
#define version "PendingEA 1.60"
#property copyright "Copyright © 2015, milanese "
#property link      "http://SteveHopwoodForex.com"
extern string   gen="----General inputs----";
extern int     MagicNumber=88987;
extern double   RequiredMarginPercentile=1000;
extern double  FixedLot=0.1;
extern bool    RemoveEAAfterClosingLastEAPos=true;
extern bool    showUserDisplay=true;
extern bool    showDisplayBox=true;
extern color   displayBoxBackgroundColour=clrDimGray;
extern bool    DoNeverUseATR=false;
extern bool    AddSpreadToComment=true;
extern int     slippage=1;
extern string   gen1="----Pending Price Inputs----";
extern double  PendingPriceBuy=0;
extern double  PendingPriceSell=0;
extern bool    SetAutoPendingStopBuy=true;
extern bool    SetAutoPendingStopSell=true;
extern bool    SetAutoPendingLimitBuy=false;
extern bool    SetAutoPendingLimitSell=false;
extern bool    useATRForDistancePendingToPrice=true;
extern int     atrDistancePendingTF=PERIOD_H4;
extern double  atrMultiplicatorDistancePending=1.1;
extern int     atrPeriodDistancePending=14;
extern double  DistancePendingToPrice=40;
extern string   pen1="----Use previous candle High/low for initial Pending----";
extern string   pen2="----using this overrides all other initial PendingPrice settings----";
extern bool    useCandleHighLowForInitial=false;
extern int     TimeFrameForCandleHL=PERIOD_M15;
extern bool    SetNewEveryNextIfNotFilled=true;
extern string   dyn="----Dynamic Initial Pending Move Options----";
extern string   dyn1="----This is only working with AutoBuySellStop----";
extern bool    movePendingBuyDownIfPriceMovesDown=false;
extern bool    movePendingSellUpIfPriceMovesUp=false;
extern string   opp="----After First Fill Options----";
extern bool    RemoveEA_afterFilling=false;
extern bool    DeleteOppositeAfterFill=true;
extern bool    MoveOppositeOrderWithPrice=false;
extern double  OppositeMoveLevel=10;
extern double  MinDistanceForOppositeMoveToPrice=25;
extern string   sta="----Stacking Inputs----";
extern bool    UseStacking=true;
extern double  LotForStackPositions=0.05;
extern bool    UseStackLotTooForFirstOpposite=false;
extern bool    useATRForStackingLevel=true;
extern int     atrForStackingLevelTF=PERIOD_H4;
extern double  atrMultiplicatorForStackingLevel=1;
extern int     atrPeriodForStackingLevel=14;
extern double  StackingLevel=50;
extern int     MaxOpenPositions=10;
int      TicksToCount=5;
double          AverageSpread=0;
bool    UseFixedLot=true;
bool   weHaveOpenTrades=false;
extern string   gen3="----Spread and Price Buffer inputs----";
extern double MaxSpreadAllowedMultiplicator=1;
extern int     MaxDiffPrice=4;
extern string   man="----Trade Management & PartClose & SL/TP inputs----";
extern string   slSet="---SL/TP inputs----";
extern bool    useATRForStopLoss=true;
extern int     atrForStopLossTF=PERIOD_H4;
extern double  atrMultiplicatorForStopLoss=1.4;
extern int     atrPeriodForStopLoss=14;
extern double  SL=50;
extern bool    useATRForTakeProfit=true;
extern int     atrForTakeProfitTF=PERIOD_H4;
extern double  atrMultiplicatorForTakeProfit=1.6;
extern int     atrPeriodForTakeProfit=14;
extern double  TP=150;
extern string   jumSet="---General TradeManagement inputs----";
extern bool    manageAllTradesInThisPair=false;
extern bool    Use_SetBEAndJump=true;
extern bool    MoveSLOnlyIfWin=true;
extern string   pBasketSet="---PairBasket Management inputs----";
extern string   pBasketSet1="---Values are in AccountCurrency----";
extern bool   UseCloseAllOfPairInProfit=true;
extern double CloseAllOfPairInProfit=75;
extern bool   UseCloseAllOfPairInLoss=true;
extern double CloseAllOfPairInLoss=50;
extern string   partSet="---PartClose inputs----";
extern bool    PartCloseEnabled=true;
extern bool    PartCloseWithBE=false;
extern bool    PartCloseAsFirstTP=true;
extern bool    useATRForPartClosePips=true;
extern int     atrForPartClosePipsTF=PERIOD_H4;
extern double  atrMultiplicatorForPartClosePips=1.5;
extern int     atrPeriodForPartClosePips=14;
extern double  PartCloseFirstTpPips=25;
extern double   PartClosePercent=10;
extern string   bejsSet="---BE & JS inputs----";
extern double  BEProfit=4;
extern double  JumpStep=15;
extern bool    useATRForSLMinDistanceToPrice=true;
extern int     atrForSLMinDistanceToPriceTF=PERIOD_H4;
extern double  atrMultiplicatorForSLMinDistanceToPrice=1.1;
extern int     atrPeriodForSLMinDistanceToPrice=14;
extern double  SLMinDistanceToPrice=45;
extern string   fridayClSet="---FridayClose inputs----";
extern bool    UseCloseFriday=false;
extern int     FridayCloseHour=21;
extern int     FridayCloseMinute=15;

double bevar;
bool   TradeHasPartClosed=false;
string          SpreadGvName;
int             CountedTicks=0;
double adr=0;

double  Risk_percent=3;
double   LotStep,MinLot,MaxLot;
bool ForceTradeClosure=false;
//Calculating the factor needed to turn pip values into their correct points value to accommodate different Digit size.
//Thanks to Lifesys for providing this code. Coders, you need to briefly turn of Wrap and turn on a mono-spaced font to view this properly and see how easy it is to make changes.
string          pipFactor[]  = {"JPY","XAG","SILVER","BRENT","WTI","XAU","GOLD","SP500","S&P","UK100","WS30","DAX30","DJ30","NAS100","CAC40"};
double          pipFactors[] = { 100,  100,  100,     100,    100,  10,   10,    10,     10,   1,      1,     1,      1,     1,       1};
double          factor;//For pips/points stuff. Set up in int init()
                       ///////////////////////////////////////////////////////////////////////////////////////


bool     BrokerHasSundayCandle=false;

double awr_value=0;
bool BuyOk=false;
bool SellOk=false;

//Steve shell mandatory variables
int             O_R_Setting_max_retries=10;
double          O_R_Setting_sleep_time=4.0; /* seconds */
double          O_R_Setting_sleep_max=15.0; /* seconds */
int            RetryCount=10;//Will make this number of attempts to get around the trade context busy error.
bool    CriminalIsECN=true;
bool           TakingEmergencyAction;
int            TicketNo=-1,OpenTrades;
//end of Steve shell mandatory variables

bool SignalBuy=false;
bool SignalSell=false;
double lot;

bool FlagCloseFriday=false;

int myHour=99;
//int multiplier=1;
double spread=0;
int myMinute=99;
double CostPip=5;
bool TPChangeFlag=false;
double lotForOrder=0;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit(void) 
  {

   while(IsConnected()==false) 
     {
      Comment("Waiting for MT4 connection...");
      Sleep(1000);
     }//while (IsConnected()==false)
   if(!IsExpertEnabled()) 
     {
      Alert("HiddenPendingEA"+": Please enable \"Expert Advisors\" in the top toolbar of Metatrader to run this EA");
     }
   if(!IsTradeAllowed()) 
     {
      Alert("HiddenPendingEA"+": Trade is not allowed. EA cannot run. Please check \"Allow live trading\" in the \"Common\" tab of the EA properties window");
     }


   factor=PFactor(Symbol());

   LotStep= MarketInfo(Symbol(),MODE_LOTSTEP);
   MinLot = MarketInfo(Symbol(),MODE_MINLOT);
   MaxLot = MarketInfo(Symbol(),MODE_MAXLOT);
   BrokerHasSundayCandle=false;
   for(int CC=0; CC<8; CC++) 
     {
      if(TimeDayOfWeek(iTime(NULL,PERIOD_D1,CC))==0) 
        {
         BrokerHasSundayCandle=true;
         break;
        }
     }
//idiot check
   if(RemoveEA_afterFilling==true && UseStacking==true) 
     {
      Alert("HiddenPendingEA"+":You cannot use Stacking & RemoveEA_afterFilling together!!");
      Alert("HiddenPendingEA"+":RemoveEA_afterFilling is set to false");
      RemoveEA_afterFilling=false;
     }
   if(useCandleHighLowForInitial==true)
     {

      SetAutoPendingStopBuy=false;
      SetAutoPendingStopSell=false;
      SetAutoPendingLimitBuy=false;
      SetAutoPendingLimitSell=false;
     }
   adr=GetAtr(Symbol(),atrDistancePendingTF,atrPeriodDistancePending,0);
   if(CloseEnough(adr,0))adr=0.05;
   if(DoNeverUseATR==false) 
     {
      if(useATRForDistancePendingToPrice==true) 
        {

         DistancePendingToPrice=NormalizeDouble((atrMultiplicatorDistancePending*adr*factor),0);
         Alert("HiddenPendingEA"+":DistancePendingToPrice calculated with ATR: ",DoubleToStr(DistancePendingToPrice,0));
        }
     }
   if(SetAutoPendingStopBuy==true)PendingPriceBuy=NormalizeDouble(Ask+(DistancePendingToPrice/factor),Digits);
   if(SetAutoPendingStopSell==true)PendingPriceSell=NormalizeDouble(Bid-(DistancePendingToPrice / factor),Digits);
   if(SetAutoPendingLimitBuy==true)PendingPriceBuy=NormalizeDouble(Ask-(DistancePendingToPrice / factor),Digits);
   if(SetAutoPendingLimitSell==true)PendingPriceSell=NormalizeDouble(Bid+(DistancePendingToPrice/factor),Digits);
   if(UseStacking==false && DeleteOppositeAfterFill==true) MaxOpenPositions=1;
   if(UseStacking==false && DeleteOppositeAfterFill==false) MaxOpenPositions=2;
   if(useCandleHighLowForInitial==true)
     {
      PendingPriceBuy=iHigh(Symbol(),TimeFrameForCandleHL,1);
      PendingPriceSell=iLow(Symbol(),TimeFrameForCandleHL,1);
     }
   if(PendingPriceBuy!=0)CreateBuyLine();
   if(PendingPriceSell!=0)CreateSellLine();
   if(Use_SetBEAndJump && MoveSLOnlyIfWin==false && SL!=0) 
     {
      SLMinDistanceToPrice=SL;
      Alert("SLMinDistanceToPrice set to SL-Value!");
      Alert("SLMinDistanceToPrice new: ",DoubleToString(SLMinDistanceToPrice,1));

     }
   if(Use_SetBEAndJump && MoveSLOnlyIfWin==false && SL==0) 
     {

      Alert("SL can not be 0");
      Alert("SL set to 30 pips!");
      SL=30;
      SLMinDistanceToPrice=SL;
      Alert("SLMinDistanceToPrice new: ",DoubleToString(SLMinDistanceToPrice,1));

     }
//Check if we have open trades to adapt the PendingPrices this is a new security check if EA is new initilised
   CheckForOpenTrades();
   if(DoNeverUseATR==false) 
     {
      setATRValues();
     }
   if(showUserDisplay==true) 
     {
      DisplayUserFeedback();

     }
   ChartSetInteger(ChartID(),CHART_FOREGROUND,false);
   return(INIT_SUCCEEDED);



  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason) 
  {
   Comment("");
   ObjectDelete("messageBox");
   ObjectDelete("PendingPriceBuy");
   ObjectDelete("PendingPriceSell");
   Alert(__FUNCTION__,"_UninitReason = ",getUninitReasonText(_UninitReason));

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CalculateLots(double risk_percent) 
  {
   int SLp=740;
   double risk_value;

   risk_value=AccountBalance()*(risk_percent/100.0)/(SLp*MarketInfo(Symbol(),MODE_TICKVALUE)/factor/MarketInfo(Symbol(),MODE_TICKSIZE));

   return(MathMin(MathMax(MinLot,MathRound(risk_value/LotStep)*LotStep),MaxLot));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountBuys(string strSymbol,int nMagic) 
  {
   int nOrderCount=0;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if(manageAllTradesInThisPair==false) 
        {
         if(OrderMagicNumber()!=nMagic) continue;
        }
      if(OrderSymbol()!=strSymbol) continue;
      if(OrderType()==OP_BUY)

         nOrderCount++;
     }
   return(nOrderCount);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountSells(string strSymbol,int nMagic) 
  {
   int nOrderCount=0;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if(manageAllTradesInThisPair==false) 
        {
         if(OrderMagicNumber()!=nMagic) continue;
        }
      if(OrderSymbol()!=strSymbol) continue;
      if(OrderType()==OP_SELL)

         nOrderCount++;
     }
   return(nOrderCount);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountBuysScanning(string strSymbol,int nMagic) 
  {
   int nOrderCount=0;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;

      if(OrderMagicNumber()!=nMagic) continue;

      if(OrderSymbol()!=strSymbol) continue;
      if(OrderType()==OP_BUY)

         nOrderCount++;
     }
   return(nOrderCount);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountSellsScanning(string strSymbol,int nMagic) 
  {
   int nOrderCount=0;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;

      if(OrderMagicNumber()!=nMagic) continue;

      if(OrderSymbol()!=strSymbol) continue;
      if(OrderType()==OP_SELL)

         nOrderCount++;
     }
   return(nOrderCount);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CountHisto(string strSymbol,int nMagic) 
  {
   int nOrderCount=0;
   for(int i=OrdersHistoryTotal()-1; i>=0; i--) 
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
         if((OrderType()==OP_BUY) || (OrderType()==OP_SELL))
            if(OrderMagicNumber()==nMagic)
               if(OrderSymbol()==strSymbol)
                  nOrderCount++;
     }
   return(nOrderCount);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double LastOpenTradePrice(string strSymbol,int nMagic) 
  {
   double priceLastOpenOrder=0;
   datetime opendate=0;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if(OrderMagicNumber()!=nMagic) continue;
      if(OrderSymbol()!=strSymbol) continue;

      if(OrderOpenTime()>=opendate) 
        {
         priceLastOpenOrder=OrderOpenPrice();
         opendate=OrderOpenTime();
        }
     }
   return(priceLastOpenOrder);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
/*double CalculateTpForBuy(string strSymbol)
{  RefreshRates();
	double tp=0;
	 awr_value = 1.385*(iATR(NULL, PERIOD_D1, 14, 1));
	 tp=Ask+NormalizeDouble(awr_value,Digits);



	return(tp);
}
double CalculateTpForSell(string strSymbol)
{  RefreshRates();

	double tp=0;
	awr_value = 1.385*(iATR(NULL, PERIOD_D1, 14, 1));
	 tp=Bid-NormalizeDouble(awr_value,Digits);



	return(tp);
}

*/
bool CheckTradeAllowedMargin() 
  {
   bool allowed=true;
   if(IsTesting()==false) 
     {
      if((MarketInfo(Symbol(),MODE_MARGINREQUIRED)*lot)>=(AccountFreeMargin()/2))allowed=false;
      if(AccountMargin()>0) 
        {
         double freemarginpercentile=(AccountEquity()/AccountMargin())*100;
         if(freemarginpercentile<RequiredMarginPercentile)allowed=false;
        }
     }
   return(allowed);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double ReturnHighOpenPrice(string strSymbol,int nMagic) 
  {
   double OrderHighOpenPrice=0;
   int ticket=-1;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {

      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if(OrderMagicNumber()!=nMagic) continue;
      if(OrderSymbol()!=strSymbol) continue;
      if((OrderType()==OP_BUY))
         ticket=OrderTicket();
      if(OrderOpenPrice()>=OrderHighOpenPrice)OrderHighOpenPrice=OrderOpenPrice();
     }
   if(ticket>0)bool order_select=OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES);
   return(OrderHighOpenPrice);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double ReturnLowOpenPrice(string strSymbol,int nMagic) 
  {
   double OrderLowOpenPrice=9999;
   int ticket=-1;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {

      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if(OrderMagicNumber()!=nMagic) continue;
      if(OrderSymbol()!=strSymbol) continue;
      if((OrderType()==OP_SELL))
         ticket=OrderTicket();
      if(OrderOpenPrice()<=OrderLowOpenPrice)OrderLowOpenPrice=OrderOpenPrice();
     }
   if(ticket>0) bool order_select=OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES);
   return(OrderLowOpenPrice);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool AllowedSpread(string strSymbol) 
  {
   bool IsOk=true;
   if(spread>AverageSpread*MaxSpreadAllowedMultiplicator)IsOk=false;
   return(IsOk);

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ManageOpenTrades() 
  {
   if(UseCloseFriday==true)CloseFriday(Symbol(),MagicNumber);
   if(MoveOppositeOrderWithPrice==true && DeleteOppositeAfterFill==false) MoveOpposite();
   if(Use_SetBEAndJump==true && MoveSLOnlyIfWin==true) SetBEAndJump(Symbol(),MagicNumber);
   if(Use_SetBEAndJump==true && MoveSLOnlyIfWin==false) DoJS(Symbol(),MagicNumber);
   if(PartCloseEnabled==true) 
     {
      if(PartCloseAsFirstTP==true)doPartCloseFirstTP(Symbol(),MagicNumber);
     }
   if(UseCloseAllOfPairInProfit==true) 
     {
      double ProfitPair=GetProfitPair(Symbol());
      if(ProfitPair>=CloseAllOfPairInProfit) CloseAllOfPair();
      if(ForceTradeClosure==true) CloseAllOfPair();

     }
   if(UseCloseAllOfPairInLoss==true) 
     {
      double ProfitPair=GetProfitPair(Symbol());
      if(ProfitPair<=-(CloseAllOfPairInLoss)) CloseAllOfPair();

      if(ForceTradeClosure==true) CloseAllOfPair();

     }

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void MoveOpposite()

  {
   if(CountBuysScanning(Symbol(),MagicNumber)>0) 
     {
      if(Bid>PendingPriceSell+(MinDistanceForOppositeMoveToPrice/factor)+(OppositeMoveLevel/factor))

         PendingPriceSell=PendingPriceSell+(OppositeMoveLevel/factor);
      CreateSellLine();

     }
   if(CountSellsScanning(Symbol(),MagicNumber)>0) 
     {
      if(Bid<PendingPriceBuy-(MinDistanceForOppositeMoveToPrice/factor)-(OppositeMoveLevel/factor))

         PendingPriceBuy=PendingPriceBuy-(OppositeMoveLevel/factor);
      CreateBuyLine();

     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CheckForOpenTrades() 
  {
   weHaveOpenTrades=false;
   if(CountBuysScanning(Symbol(),MagicNumber)>0) 
     {
      weHaveOpenTrades=true;
      if(UseStacking==true) 
        {

         if(CountBuysScanning(Symbol(),MagicNumber)+CountSellsScanning(Symbol(),MagicNumber)<MaxOpenPositions) 
           {
            PendingPriceBuy=ReturnHighOpenPrice(Symbol(),MagicNumber)+(StackingLevel/factor);
            if(DeleteOppositeAfterFill==true) 
              {
               ObjectDelete("PendingPriceSell");
               PendingPriceSell=0;
              }
            CreateBuyLine();
              } else {
            PendingPriceBuy=0;
            PendingPriceSell=0;
            ObjectDelete("PendingPriceBuy");
            ObjectDelete("PendingPriceSell");

           }
           } else {
         PendingPriceBuy=0;
         PendingPriceSell=0;
         ObjectDelete("PendingPriceBuy");
         ObjectDelete("PendingPriceSell");

        }
     }
   if(CountSellsScanning(Symbol(),MagicNumber)>0) 
     {
      weHaveOpenTrades=true;
      if(UseStacking==true) 
        {
         if(CountBuysScanning(Symbol(),MagicNumber)+CountSellsScanning(Symbol(),MagicNumber)<MaxOpenPositions) 
           {
            PendingPriceSell=ReturnLowOpenPrice(Symbol(),MagicNumber)-(StackingLevel/factor);
            if(DeleteOppositeAfterFill==true) 
              {
               ObjectDelete("PendingPriceBuy");
               PendingPriceBuy=0;
              }
            CreateSellLine();
              } else {
            PendingPriceBuy=0;
            PendingPriceSell=0;
            ObjectDelete("PendingPriceBuy");
            ObjectDelete("PendingPriceSell");

           }
           } else {
         PendingPriceBuy=0;
         PendingPriceSell=0;
         ObjectDelete("PendingPriceBuy");
         ObjectDelete("PendingPriceSell");

        }
     }

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CanTrade() 
  {
   if((DayOfWeek()==5)&& (TimeHour(TimeCurrent())>=20)) return (false);
   else return (true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SM(string message) 
  {

   ScreenMessage=StringConcatenate(ScreenMessage,Gap,message);

  }//End void SM()
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DisplayUserFeedback() 
  {
   string marginOk="";
   if(IsTesting()==true && IsVisualMode()==false) return;
   if(showUserDisplay==false) 
     {
      ObjectDelete("messageBox");
      return;
     }
   if(showDisplayBox==true) 
     {

      RectLabelCreate();
     }

   else ObjectDelete("messageBox");

   ScreenMessage="";
   if(CheckTradeAllowedMargin()==true) marginOk="Margin is OK to take trades";
   if(CheckTradeAllowedMargin()==false) marginOk="We have no Margin to take trades";
   SM("Updates for this EA are to be found at http://www.stevehopwoodforex.com"+NL);
   SM(version);
   SM(" Copyright 2015, by milanese"+NL);
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);
   SM("Broker time = "+TimeToStr(TimeCurrent(),TIME_DATE|TIME_SECONDS)+" Local time = "+TimeToStr(TimeLocal(),TIME_DATE|TIME_SECONDS)+" GMT time = "+TimeToStr(TimeGMT(),TIME_DATE|TIME_SECONDS)+NL);
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);
   SM("Open Price of last open order="+DoubleToStr(LastOpenTradePrice(Symbol(),MagicNumber),Digits)+NL);
   if(int(LastClosedTrade(Symbol(),MagicNumber))!=0) 
     {
      SM("Last EA Trade closure was at: "+DateToStr(LastClosedTrade(Symbol(),MagicNumber))+NL);
     }
   else SM("No closed EA Trade found!"+NL);
   if(int(LastOpenedTrade(Symbol(),MagicNumber))!=0) 
     {
      SM("Last EA Trade was opened at: "+DateToStr(LastOpenedTrade(Symbol(),MagicNumber))+NL);
     }
   else SM("No opened EA Trade found!"+NL);
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);
   if(Use_SetBEAndJump==true) 
     {
      if(PartCloseEnabled==true && PartCloseWithBE==true) 
        {
         double CloseLots=NormalizeLots(Symbol(),FixedLot *(PartClosePercent/100));
         double CloseLotsStack=NormalizeLots(Symbol(),LotForStackPositions *(PartClosePercent/100));
         SM("Part-close is enabled at "+DoubleToStr(PartClosePercent,2)+"% ("+DoubleToStr(CloseLots,2)+" Fixed lots to close)"+NL);
         if(UseStacking==True) SM("Part-close is enabled at "+DoubleToStr(PartClosePercent,2)+"% ("+DoubleToStr(CloseLotsStack,2)+" LotsForStack to close)"+NL);
        }//if (PartCloseEnabled)

     }
   if(PartCloseEnabled==true && PartCloseAsFirstTP==true) 
     {
      SM("PartClose as first TP is enabled"+NL);
      double CloseLots=NormalizeLots(Symbol(),FixedLot *(PartClosePercent/100));
      double CloseLotsStack=NormalizeLots(Symbol(),LotForStackPositions *(PartClosePercent/100));
      SM("Part-close is enabled at "+DoubleToStr(PartClosePercent,2)+"% ("+DoubleToStr(CloseLots,2)+" Fixed lots to close)"+NL);
      if(UseStacking==True) SM("Part-close is enabled at "+DoubleToStr(PartClosePercent,2)+"% ("+DoubleToStr(CloseLotsStack,2)+" LotsForStack to close)"+NL);

     }
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);
   if(DoNeverUseATR==true) 
     {

      SM("All automatic calculating ATR settings are deactivated, manual inputs are used"+NL);

     }
   if(DoNeverUseATR==false) 
     {

      if(useATRForDistancePendingToPrice==true) 
        {
         SM("DistancePendingToPrice (for initial Pendings) is calculated with ATR"+NL);

        }
      if(useATRForStackingLevel==true && UseStacking==true) 
        {
         SM("Stack-Level is calculated with ATR"+NL);

        }
      if(useATRForSLMinDistanceToPrice==true && Use_SetBEAndJump==true) 
        {
         SM("SLMinDistance is calculated by ATR"+NL);

        }
      if(useATRForPartClosePips==true && PartCloseEnabled==true && PartCloseAsFirstTP==true) 
        {
         SM("PartClosePipsForFirstTP are calculated by ATR"+NL);

        }
     }
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);

   if(manageAllTradesInThisPair==true) 
     {
      SM("The EA manages all open positions on :"+Symbol()+NL);
     }
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);
   if(UseStacking==true) 
     {
      SM("StackingLevel= "+DoubleToStr(StackingLevel,1)+NL);
     }
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);
   SM("SLMinDistanceToPrice= "+DoubleToStr(SLMinDistanceToPrice,1)+NL);
   SM("PendingPriceBuy= "+DoubleToString(PendingPriceBuy,Digits)+NL);
   SM("PendingPriceSell= "+DoubleToString(PendingPriceSell,Digits)+NL);
   SM("Profit for all open Positions in this Pair = "+DoubleToString(GetProfitPair(Symbol()),2)+NL);
   if(UseCloseAllOfPairInProfit==true) 
     {
      SM("PairBasket will be closed if PairProfit = "+DoubleToString(CloseAllOfPairInProfit,2)+NL);
     }
   if(UseCloseAllOfPairInLoss==true) 
     {
      SM("PairBasket will be closed if PairLoss = "+DoubleToString(CloseAllOfPairInLoss,2)+NL);
     }
   SM("Count Open Buys="+IntegerToString(CountBuys(Symbol(),MagicNumber))+NL);
   SM("Count Open Sells="+IntegerToString(CountSells(Symbol(),MagicNumber))+NL);
   SM("Count Historical Trades EA="+IntegerToString(CountHisto(Symbol(),MagicNumber))+NL);
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);
   if(CloseEnough(AverageSpread,0)) 
     {
      GetAverageSpread();
      int left=TicksToCount-CountedTicks;
      SM("Calculating the average spread. "+DoubleToStr(left,0)+" left to count."+NL);

     }//
   else SM("AverageSpread(in points) is = "+DoubleToStr((AverageSpread),0)+" MaxAllowedSpread(in points) is = "+DoubleToStr((AverageSpread*MaxSpreadAllowedMultiplicator),0)+" Actual Spread(in points) is= "+DoubleToStr((spread),0)+NL);
   SM("----------------------------------------------------------------------------------------------------------------------------------------------------------------"+NL);
   SM("RequiredMarginPercentile= "+DoubleToString(RequiredMarginPercentile,2)+NL);
   SM(marginOk+NL);

   Comment(ScreenMessage);

  }//void DisplayUserFeedback()
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool SendSingleTrade(int type,string comment,double lotsize,double price,double stop,double take) 
  {
//pah (Paul) contributed the code to get around the trade context busy error. Many thanks, Paul.
   bool do_order=false;
   int ticket=-1;

   if((CountBuysScanning(Symbol(),MagicNumber)+CountSellsScanning(Symbol(),MagicNumber))<MaxOpenPositions) 
     {
      do_order=true;
     }
   color col=Red;
   if(type==OP_BUY || type==OP_BUYSTOP) col=Green;

   int expiry=0;
   if(do_order==true) 
     {
      double symSpr=(MarketInfo(Symbol(),MODE_ASK)-MarketInfo(Symbol(),MODE_BID))*factor;
      if(AddSpreadToComment==true) 
        {
         comment=comment+" (Spr: "+DoubleToStr(symSpr,1)+")";
        }
      for(int cc=0; cc<RetryCount; cc++) 
        {
         for(int d=0;(d<RetryCount) && IsTradeContextBusy(); d++) Sleep(500);

         RefreshRates();
         if(type == OP_BUY) price = NormalizeDouble(Ask, Digits);
         if(type == OP_SELL) price = NormalizeDouble(Bid, Digits);



         ticket=OrderSend(Symbol(),type,lotsize,price,slippage,0,0,comment,MagicNumber,expiry,col);
         if(ticket>-1) 
           {
            ModifyOrder(ticket,stop,take);
            if(UseStacking==false && DeleteOppositeAfterFill==true) 
              {
               PendingPriceBuy=0;
               PendingPriceSell=0;
               ObjectDelete("PendingPriceSell");
               ObjectDelete("PendingPriceBuy");
              }
            if(UseStacking==false && DeleteOppositeAfterFill==false)

              {
               if(type==OP_SELL) 
                 {
                  PendingPriceSell=0;

                  ObjectDelete("PendingPriceSell");

                 }
               if(type==OP_BUY) 
                 {
                  PendingPriceBuy=0;

                  ObjectDelete("PendingPriceBuy");

                 }

              }
            if(UseStacking==true && DeleteOppositeAfterFill==false)

              {

               if(orders_count(MagicNumber)<=MaxOpenPositions) 
                 {
                  if(type==OP_SELL) 
                    {
                     PendingPriceSell=Bid-(StackingLevel/factor);

                     ObjectDelete("PendingPriceSell");

                     CreateSellLine();

                    }
                  if(type==OP_BUY) 
                    {
                     PendingPriceBuy=Ask+(StackingLevel/factor);

                     ObjectDelete("PendingPriceBuy");

                     CreateBuyLine();

                    }
                    } else {

                  if(type==OP_SELL) 
                    {
                     PendingPriceSell=0;

                     ObjectDelete("PendingPriceSell");

                    }
                  if(type==OP_BUY) 
                    {
                     PendingPriceBuy=0;

                     ObjectDelete("PendingPriceBuy");

                    }

                 }

              }
            if(UseStacking==true && DeleteOppositeAfterFill==true)

              {
               if(orders_count(MagicNumber)<=MaxOpenPositions) 
                 {
                  if(type==OP_SELL) 
                    {
                     PendingPriceSell=Bid-(StackingLevel/factor);
                     PendingPriceBuy=0;
                     ObjectDelete("PendingPriceSell");
                     ObjectDelete("PendingPriceBuy");
                     CreateSellLine();

                    }
                  if(type==OP_BUY) 
                    {
                     PendingPriceBuy=Ask+(StackingLevel/factor);
                     PendingPriceSell=0;
                     ObjectDelete("PendingPriceBuy");
                     ObjectDelete("PendingPriceSell");
                     CreateBuyLine();

                    }
                    } else {
                  if(type==OP_SELL) 
                    {
                     PendingPriceSell=0;
                     PendingPriceBuy=0;
                     ObjectDelete("PendingPriceSell");
                     ObjectDelete("PendingPriceBuy");

                    }
                  if(type==OP_BUY) 
                    {
                     PendingPriceBuy=0;
                     PendingPriceSell=0;
                     ObjectDelete("PendingPriceBuy");
                     ObjectDelete("PendingPriceSell");

                    }

                 }

              }

            break;//Exit the trade send loop
           }//if (ticket > -1)}

         if(cc == RetryCount - 1) return(false);

         //Error trapping for both
         if(ticket<0) 
           {
            string stype;
            if(type == OP_BUY) stype = "OP_BUY";
            if(type == OP_SELL) stype = "OP_SELL";
            if(type == OP_BUYLIMIT) stype = "OP_BUYLIMIT";
            if(type == OP_SELLLIMIT) stype = "OP_SELLLIMIT";
            if(type==OP_BUYSTOP) stype="OP_BUYSTOP";
            if(type== OP_SELLSTOP) stype = "OP_SELLSTOP";
            int err=GetLastError();
            Alert(Symbol()," ",WindowExpertName()," ",stype," order send failed with error(",err,"): ",ErrorDescription(err));
            Print(Symbol()," ",WindowExpertName()," ",stype," order send failed with error(",err,"): ",ErrorDescription(err));
            return(false);
           }//if (ticket < 0)
        }//for (int cc = 0; cc < RetryCount; cc++);

      TicketNo=ticket;
      //Make sure the trade has appeared in the platform's history to avoid duplicate trades.
      //My mod of Matt's code attempts to overcome the bastard crim's attempts to overcome Matt's code.
      bool TradeReturnedFromCriminal=false;
      while(!TradeReturnedFromCriminal) 
        {
         TradeReturnedFromCriminal=O_R_CheckForHistory(ticket);
         if(!TradeReturnedFromCriminal) 
           {
            Alert(Symbol()," sent trade not in your trade history yet. Turn of this ea NOW.");
           }//if (!TradeReturnedFromCriminal)
        }//while (!TradeReturnedFromCriminal)

      //Got this far, so trade send succeeded
      if(RemoveEA_afterFilling==true)
         ExpertRemove();
      Alert("Trade has filled correctly");
      Print("Trade has filled correctly");
      return(true);
     }
   return(false);
  }//End bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ModifyOrder(int ticket,double stop,double take) 
  {
//Modifies an order already sent if the crim is ECN.

   if(CloseEnough(stop,0) && CloseEnough(take,0)) return; //nothing to do

   if(!OrderSelect(ticket,SELECT_BY_TICKET)) return;//Trade does not exist, so no mod needed

                                                    //RetryCount is declared as 10 in the Trading variables section at the top of this file
   for(int cc=0; cc<RetryCount; cc++) 
     {
      for(int d=0;(d<RetryCount) && IsTradeContextBusy(); d++) Sleep(100);
      if(take>0 && stop>0) 
        {
         while(IsTradeContextBusy()) Sleep(100);
         if(OrderModify(ticket,OrderOpenPrice(),stop,take,OrderExpiration(),CLR_NONE)) 
           {
            Alert("Modify Order Succeeded !");
            Print("Modify Order Succeeded !");
            return;
           }
        }//if (take > 0 && stop > 0)

      if(!CloseEnough(take,0) && CloseEnough(stop,0)) 
        {
         while(IsTradeContextBusy()) Sleep(100);
         if(OrderModify(ticket,OrderOpenPrice(),OrderStopLoss(),take,OrderExpiration(),CLR_NONE)) 
           {
            Alert("Modify Order Succeeded !");
            Print("Modify Order Succeeded !");
            return;
           }
        }//if (take == 0 && stop != 0)

      if(CloseEnough(take,0) && !CloseEnough(stop,0)) 
        {
         while(IsTradeContextBusy()) Sleep(100);
         if(OrderModify(ticket,OrderOpenPrice(),stop,OrderTakeProfit(),OrderExpiration(),CLR_NONE)) 
           {
            Alert("Modify Order Succeeded !");
            Print("Modify Order Succeeded !");
            return;
           }
        }//if (take == 0 && stop != 0)
     }//for (int cc = 0; cc < RetryCount; cc++)

//Got this far, so the order modify failed
   int err=GetLastError();
   Print(Symbol()," SL/TP  order modify failed with error(",err,"): ",ErrorDescription(err));
   Alert(Symbol()," SL/TP  order modify failed with error(",err,"): ",ErrorDescription(err));

  }//void ModifyOrder(int ticket, double tp, double sl)
//=============================================================================
//                           O_R_CheckForHistory()
//
//  This function is to work around a very annoying and dangerous bug in MT4:
//      immediately after you send a trade, the trade may NOT show up in the
//      order history, even though it exists according to ticket number.
//      As a result, EA's which count history to check for trade entries
//      may give many multiple entries, possibly blowing your account!
//
//  This function will take a ticket number and loop until
//  it is seen in the history.
//
//  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, 2010
//
//=============================================================================
bool O_R_CheckForHistory(int ticket) 
  {
//My thanks to Matt for this code. He also has the undying gratitude of all users of my trading robots

   int lastTicket=OrderTicket();

   int cnt=0;
   int err=GetLastError(); // so we clear the global variable.
   err=0;
   bool exit_loop=false;
   bool success=false;

   while(!exit_loop) 
     {
/* loop through open trades */
      int total=OrdersTotal();
      for(int c=0; c<total; c++) 
        {
         if(OrderSelect(c,SELECT_BY_POS,MODE_TRADES)==true) 
           {
            if(OrderTicket()==ticket) 
              {
               success=true;
               exit_loop=true;
              }
           }
        }
      if(cnt>3) 
        {
/* look through history too, as order may have opened and closed immediately */
         total=OrdersHistoryTotal();
         for(int c=0; c<total; c++) 
           {
            if(OrderSelect(c,SELECT_BY_POS,MODE_HISTORY)==true) 
              {
               if(OrderTicket()==ticket) 
                 {
                  success=true;
                  exit_loop=true;
                 }
              }
           }
        }

      cnt=cnt+1;
      if(cnt>O_R_Setting_max_retries) 
        {
         exit_loop=true;
        }
      if(!(success || exit_loop)) 
        {
         Print("Did not find #"+IntegerToString(ticket)+" in history, sleeping, then doing retry #"+IntegerToString(cnt));
         O_R_Sleep(O_R_Setting_sleep_time,O_R_Setting_sleep_max);
        }
     }
// Select back the prior ticket num in case caller was using it.
   if(lastTicket>=0) 
     {
      bool order_select=OrderSelect(lastTicket,SELECT_BY_TICKET,MODE_TRADES);
     }
   if(!success) 
     {
      Print("Never found #"+IntegerToString(ticket)+" in history! crap!");
     }
   return(success);
  }//End bool O_R_CheckForHistory(int ticket)
//=============================================================================
//                              O_R_Sleep()
//
//  This sleeps a random amount of time defined by an exponential
//  probability distribution. The mean time, in Seconds is given
//  in 'mean_time'.
//  This returns immediately if we are backtesting
//  and does not sleep.
//
//=============================================================================
void O_R_Sleep(double mean_time,double max_time) 
  {
   if(IsTesting()) 
     {
      return;   // return immediately if backtesting.
     }
   double p = (MathRand()+1) / 32768.0;
   double t = -MathLog(p)*mean_time;
   t=MathMin(t,max_time);
   int ms=int(t*1000);
   if(ms<10) 
     {
      ms=10;
     }
   Sleep(ms);
  }//End void O_R_Sleep(double mean_time, double max_time)
//see also the original function by WHRoeder, http://forum.mql4.com/45425#564188, fxdaytrader
double NormalizeLots(string symbol,double lots) 
  {
   if(CloseEnough(MathAbs(lots),0.0)) return(0.0); //just in case ... otherwise it may happen that after rounding 0.0 the result is >0 and we have got a problem, fxdaytrader
   double ls=MarketInfo(symbol,MODE_LOTSTEP);
   lots=MathMin(MarketInfo(symbol,MODE_MAXLOT),MathMax(MarketInfo(symbol,MODE_MINLOT),lots)); //check if lots >= min. lots && <= max. lots, fxdaytrader
   return(MathRound(lots/ls)*ls);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool NewBar(int TimeFrame) 
  {
   static datetime LastTime=0;
   if(iTime(NULL,TimeFrame,0)!=LastTime) 
     {
      LastTime=iTime(NULL,TimeFrame,0);
      return (true);
     }
   else
      return (false);
  }
// for 6xx build compatibility

string StringSubstrOld(string x,int a,int b=-1) 
  {
   if(a<0) a=0; // Stop odd behaviour
   if(b<=0) b=-1; // new MQL4 EOL flag
   return StringSubstr(x,a,b);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void LookForTrading() 
  {

   bool Sell_Flag=true;
   bool Buy_Flag=true;

   SignalBuy=false;
   SignalSell=false;
   RefreshRates();
   double DiffOfPriceSell=MathAbs(Bid-PendingPriceSell);
   double DiffOfPriceBuy=MathAbs(Ask-PendingPriceBuy);
   if(DiffOfPriceSell>MaxDiffPrice/factor) Sell_Flag=false;
   if(DiffOfPriceBuy>MaxDiffPrice/factor) Buy_Flag=false;
   if(PendingPriceBuy!=0)CreateBuyLine();
   if(PendingPriceSell!=0)CreateSellLine();

   int m_bar=0;//Need to deal with a Sunday candle
   int d= TimeDayOfWeek(TimeCurrent());
   if(d == 1 && BrokerHasSundayCandle && Period()==1440) m_bar=m_bar+1;
   adr=GetAtr(Symbol(),PERIOD_D1,10,m_bar+1);
   if(movePendingBuyDownIfPriceMovesDown && SetAutoPendingStopBuy) 
     {
      if(CountBuysScanning(Symbol(),MagicNumber)==0 && CountSellsScanning(Symbol(),MagicNumber)==0) 
        {
         if((PendingPriceBuy-Bid)>DistancePendingToPrice/factor) 
           {

            PendingPriceBuy=Bid+(DistancePendingToPrice/factor);
            CreateBuyLine();

           }

        }
     }
   if(movePendingSellUpIfPriceMovesUp && SetAutoPendingStopSell) 
     {
      if(CountSellsScanning(Symbol(),MagicNumber)==0 && CountBuysScanning(Symbol(),MagicNumber)==0) 
        {
         if((Bid-PendingPriceSell)>DistancePendingToPrice/factor) 
           {

            PendingPriceSell=Bid-(DistancePendingToPrice/factor);
            CreateSellLine();

           }

        }
     }
   if(useCandleHighLowForInitial==true && (CountBuysScanning(Symbol(),MagicNumber)==0 && CountSellsScanning(Symbol(),MagicNumber)==0) && SetNewEveryNextIfNotFilled==true)
     {
      PendingPriceBuy=iHigh(Symbol(),TimeFrameForCandleHL,1);
      PendingPriceSell=iLow(Symbol(),TimeFrameForCandleHL,1);
      CreateBuyLine();
      CreateSellLine();
     }
// SIGNAL BUY CHECK

   RefreshRates();

   if((DeleteOppositeAfterFill==true && CountSellsScanning(Symbol(),MagicNumber)==0 && CountBuysScanning(Symbol(),MagicNumber)<=MaxOpenPositions)) 
     {
      if(Bid>PendingPriceBuy && Buy_Flag==true)

         SignalBuy=true;
     }
   if((DeleteOppositeAfterFill==false && CountSellsScanning(Symbol(),MagicNumber)<=MaxOpenPositions && CountBuysScanning(Symbol(),MagicNumber)<=MaxOpenPositions)) 
     {
      if(Bid>PendingPriceBuy && Buy_Flag==true)

         SignalBuy=true;
     }

// SIGNAL SELL CHECK

   if((DeleteOppositeAfterFill==true && CountBuysScanning(Symbol(),MagicNumber)==0 && CountSellsScanning(Symbol(),MagicNumber)<=MaxOpenPositions)) 
     {
      if(Bid<PendingPriceSell && Sell_Flag==true)

         SignalSell=true;
     }
   if((DeleteOppositeAfterFill==false && CountBuysScanning(Symbol(),MagicNumber)<=MaxOpenPositions && CountSellsScanning(Symbol(),MagicNumber)<=MaxOpenPositions)) 
     {
      if(Bid<PendingPriceSell && Sell_Flag==true)

         SignalSell=true;
     }

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double GetAtr(string symbol,int tf,int period,int shift) 
  {
//Returns the value of atr

   return(iATR(symbol, tf, period, shift) );

  }//End double GetAtr()
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string StringRightPad(string str,int n=1,string str2=" ") 
  {
   return(str + StringRepeat(str2,n-StringLen(str)));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string StringRepeat(string str,int n=1) 
  {
   string outstr="";
   for(int i=0; i<n; i++) outstr=outstr+str;
   return(outstr);
  }
//+------------------------------------------------------------------+
void GetAverageSpread() 
  {

   static double SpreadTotal=0;
   AverageSpread=0;

//Add spread to total and keep track of the ticks
   spread=MarketInfo(Symbol(),MODE_SPREAD);
   SpreadTotal+=spread;
   CountedTicks++;

//All ticks counted?
   if(CountedTicks>=TicksToCount) 
     {
      AverageSpread=SpreadTotal/TicksToCount;
      //Save the average for restarts.
      GlobalVariableSet(SpreadGvName,AverageSpread);

     }//if (CountedTicks >= TicksToCount)

  }//void GetAverageSpread()
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DrawHorizontalLine(string name,double price,color col,int style,int width) 
  {

   ObjectDelete(name);

   ObjectCreate(name,OBJ_HLINE,0,TimeCurrent(),price);
   ObjectSet(name,OBJPROP_COLOR,col);
   ObjectSet(name,OBJPROP_STYLE,style);
   ObjectSet(name,OBJPROP_WIDTH,width);

  }//void DrawLine(string name, double price, color col)
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CreateBuyLine() 
  {
   ObjectDelete("PendingPriceBuy");
   DrawHorizontalLine("PendingPriceBuy",PendingPriceBuy,DarkGreen,STYLE_SOLID,2);

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CreateSellLine() 
  {
   ObjectDelete("PendingPriceSell");
   DrawHorizontalLine("PendingPriceSell",PendingPriceSell,Red,STYLE_SOLID,2);

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double PFactor(string symbol) 
  {
//This code supplied by Lifesys. Many thanks Paul - we all owe you. Gary was trying to make me see this, but I could not understand his explanation. Paul used Janet and John words

   for(int i=ArraySize(pipFactor)-1; i>=0; i--)
      if(StringFind(symbol,pipFactor[i],0)!=-1)
         return (pipFactors[i]);
   return(10000);

  }//End double PFactor(string pair)
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CloseEnough(double num1,double num2) 
  {
/*
	   This function addresses the problem of the way in which mql4 compares doubles. It often messes up the 8th
	   decimal point.
	   For example, if A = 1.5 and B = 1.5, then these numbers are clearly equal. Unseen by the coder, mql4 may
	   actually be giving B the value of 1.50000001, and so the variable are not equal, even though they are.
	   This nice little quirk explains some of the problems I have endured in the past when comparing doubles. This
	   is common to a lot of program languages, so watch out for it if you program elsewhere.
	   Gary (garyfritz) offered this solution, so our thanks to him.
	   */

   if(num1==0 && num2==0) return(true); //0==0
   if(MathAbs(num1 - num2) / (MathAbs(num1) + MathAbs(num2)) < 0.00000001) return(true);

//Doubles are unequal
   return(false);

  }//End bool CloseEnough(double num1, double num2)
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick() 
  {
   SpreadGvName=Symbol()+" THPEA_average_spread";
   AverageSpread=GlobalVariableGet(SpreadGvName);//If no gv, then the value will be left at zero.
   double sell_lot=FixedLot,buy_lot=FixedLot;
   if(weHaveOpenTrades==true && RemoveEAAfterClosingLastEAPos==true) 
     {
      if(orders_count(MagicNumber)==0) 
        {
         weHaveOpenTrades=false;
         PendingPriceBuy=0;
         PendingPriceSell=0;
         ObjectDelete("PendingPriceBuy");
         ObjectDelete("PendingPriceSell");
         ExpertRemove();

        }
     }
   if(DoNeverUseATR==false) 
     {
      setATRValues();
     }
   if(showUserDisplay==true) 
     {
      DisplayUserFeedback();

     }

   if(CountBuys(Symbol(),MagicNumber)>0 || CountSells(Symbol(),MagicNumber)>0) ManageOpenTrades();

//Spread calculation
   spread=MarketInfo(Symbol(),MODE_SPREAD);
   if(CloseEnough(AverageSpread,0)) 
     {
      GetAverageSpread();
      ScreenMessage="";
      int left=TicksToCount-CountedTicks;
      SM("Calculating the average spread. "+DoubleToStr(left,0)+" left to count.");
      Comment(ScreenMessage);

     }//
//Keep the average spread updated
   static double SpreadTotal=0;
   static int counter=0;
   SpreadTotal+=spread;
   counter++;
   if(counter>=2000) 
     {
      AverageSpread=SpreadTotal/counter;
      //Save the average for restarts.
      GlobalVariableSet(SpreadGvName,AverageSpread);
      SpreadTotal=0;
      counter=0;
     }//if (counter >= 500)

   if(LotForStackPositions!=FixedLot && LotForStackPositions!=0) 
     {
      if((CountBuysScanning(Symbol(),MagicNumber)>0) && UseStacking==true) buy_lot=LotForStackPositions;

      else buy_lot=FixedLot;

      if((CountSellsScanning(Symbol(),MagicNumber)>0) && UseStacking==true) sell_lot=LotForStackPositions;

      else sell_lot=FixedLot;
      if((UseStackLotTooForFirstOpposite==true) && (CountSellsScanning(Symbol(),MagicNumber)>0 || CountBuysScanning(Symbol(),MagicNumber)>0)) 
        {
         sell_lot=LotForStackPositions;
         buy_lot=LotForStackPositions;
        }
     }
//Lot size and part-close idiot check for the cretins. Code provided by phil_trade. Many thanks, Philippe.
//adjust Min_lot
   if(buy_lot<MarketInfo(Symbol(),MODE_MINLOT)) 
     {
      Alert(Symbol()+" lot was adjusted to Minlot = "+DoubleToStr(MarketInfo(Symbol(),MODE_MINLOT),Digits));
      buy_lot=MarketInfo(Symbol(),MODE_MINLOT);
     }//if (Lot < MarketInfo(Symbol(), MODE_MINLOT))
   if(sell_lot<MarketInfo(Symbol(),MODE_MINLOT)) 
     {
      Alert(Symbol()+" lot was adjusted to Minlot = "+DoubleToStr(MarketInfo(Symbol(),MODE_MINLOT),Digits));
      sell_lot=MarketInfo(Symbol(),MODE_MINLOT);
     }//if (Lot < MarketInfo(Symbol(), MODE_MINLOT))

   LookForTrading();
//////
//TRADING HERE
//////
//Buypart
   double tp=0;
   double sl=0;


   RefreshRates();

   if(SignalBuy==true && AllowedSpread(Symbol())==true && (CountBuysScanning(Symbol(),MagicNumber)+CountSellsScanning(Symbol(),MagicNumber))<MaxOpenPositions) 
     {
      bool sendSingleTradeBUY=false;
      lotForOrder=buy_lot;
      if(TP!=0)tp=NormalizeDouble(Ask+(TP / factor),Digits);
      if(SL!=0)sl=NormalizeDouble(Ask-(SL / factor),Digits);

      Alert("Attempting to buy ",lotForOrder," of ",Symbol());
      Print("Attempting to buy ",lotForOrder," of ",Symbol());
      sendSingleTradeBUY=SendSingleTrade(OP_BUY,"PendingEA",lotForOrder,Ask,sl,tp);
      if(sendSingleTradeBUY==true) 
        {

         SignalBuy=false;
         weHaveOpenTrades=true;
        }

     }
   if(SignalSell==true && AllowedSpread(Symbol())==true && (CountBuysScanning(Symbol(),MagicNumber)+CountSellsScanning(Symbol(),MagicNumber))<MaxOpenPositions) 
     {
      bool sendSingleTradeSELL=false;
      lotForOrder=sell_lot;
      if(TP!=0)tp=NormalizeDouble(Bid-(TP / factor),Digits);
      if(SL!=0)sl=NormalizeDouble(Bid+(SL / factor),Digits);

      Alert("Attempting to sell ",lotForOrder," of ",Symbol());
      Print("Attempting to sell ",lotForOrder," of ",Symbol());
      sendSingleTradeSELL=SendSingleTrade(OP_SELL,"PendingEA",lotForOrder,Bid,sl,tp);
      if(sendSingleTradeSELL==true) 
        {

         SignalSell=false;
         weHaveOpenTrades=true;

        }

     }

   if(showUserDisplay==true) 
     {
      DisplayUserFeedback();

     }

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void SetBEAndJump(string symbol,int nMagic) 
  {

   int ticket=-1;
   double NewSL=0;
   bool doPartClose=false;

   TradeHasPartClosed=false;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if(manageAllTradesInThisPair==false) 
        {
         if(OrderMagicNumber()!=nMagic) continue;
        }
      if(OrderSymbol()!=symbol)continue;

      if(OrderType()==OP_SELL) 
        {
         ticket=OrderTicket();
         doPartClose=false;
         if(OrderStopLoss()>OrderOpenPrice() || CloseEnough(OrderStopLoss(),0)) 
           {
            NewSL=NormalizeDouble(OrderOpenPrice()-(BEProfit/factor),Digits);
            if(PartCloseWithBE==true && PartCloseEnabled==true) 
              {
               doPartClose=true;
              }
              } else {
            doPartClose=false;
            NewSL=NormalizeDouble(OrderStopLoss()-(JumpStep/factor),Digits);
           }

         if((NewSL-Bid)>(SLMinDistanceToPrice/factor)) 
           {

            if(((NewSL<OrderStopLoss()) || (OrderStopLoss()<(1/factor))) && (NewSL!=0) && (NewSL>Ask+(10/factor))) 
              {

               Alert("SetBEAndJump :Attempting to move SL of ",symbol," to ",NewSL);
               Print("SetBEAndJump :Attempting to move SL of ",symbol," to ",NewSL);
               ModifyOrder(ticket,NewSL,0);
               if(doPartClose==true) 
                 {
                  PartCloseTrade(ticket);
                  if(TradeHasPartClosed==true)Alert("Ticket: ",ticket," was part closed");
                  else Alert("Partclose failed!");

                  TradeHasPartClosed=false;
                 }//doPartClose
              }// if(((NewSL<OrderStopLoss()) || (OrderStopLoss()<(1/factor))) && (NewSL!=0) && (NewSL>Ask+(10/factor)))
           }//if((NewSL-Bid)>(SLMinDistanceToPrice/factor))

        }//OP_SELL

      if(OrderType()==OP_BUY) 
        {
         ticket=OrderTicket();
         doPartClose=false;
         if(OrderStopLoss()<OrderOpenPrice() || CloseEnough(OrderStopLoss(),0)) 
           {
            NewSL=NormalizeDouble(OrderOpenPrice()+(BEProfit/factor),Digits);
            if(PartCloseWithBE==true && PartCloseEnabled==true) 
              {
               doPartClose=true;
              }

              } else {
            NewSL=NormalizeDouble(OrderStopLoss()+(JumpStep/factor),Digits);
            doPartClose=false;
           }
         if((Bid-NewSL)>(SLMinDistanceToPrice/factor)) 
           {
            if(((NewSL>OrderStopLoss()) || (OrderStopLoss()<(1/factor))) && (NewSL!=0) && (NewSL<Bid -(10/factor))) 
              {

               Alert("SetBEAndJump :Attempting to move SL of ",symbol," to ",NewSL);
               Print("SetBEAndJump :Attempting to move SL of ",symbol," to ",NewSL);

               ModifyOrder(ticket,NewSL,0);
               if(doPartClose==true) 
                 {
                  PartCloseTrade(ticket);
                  if(TradeHasPartClosed==true)Alert("Ticket: ",ticket," was part closed");
                  else Alert("Partclose failed!");
                  TradeHasPartClosed=false;
                 }//doPartClose
              }//if(((NewSL>OrderStopLoss()) || (OrderStopLoss()<(1/factor))) && (NewSL!=0) && (NewSL<Bid -(10/factor)))
           }//if((Bid-NewSL)>(SLMinDistanceToPrice/factor))

        }//OP_BUY

     }//for...

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void doPartCloseFirstTP(string symbol,int nMagic) 
  {

   int ticket=-1;
   double NewSL;
   bool doPartClose=false;

   TradeHasPartClosed=false;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      string name=OrderComment();
      if(StringFind(name,"from #")==0) continue;
      if(manageAllTradesInThisPair==false) 
        {
         if(OrderMagicNumber()!=nMagic) continue;
        }
      if(OrderSymbol()!=symbol)continue;

      if(OrderType()==OP_SELL) 
        {
         ticket=OrderTicket();
         doPartClose=false;

         NewSL=NormalizeDouble(OrderOpenPrice(),Digits);

         name=OrderComment();
         if(StringFind(name,"from #")<0)doPartClose=true;

         if((NewSL-Bid)>(PartCloseFirstTpPips/factor)) 
           {

            if(doPartClose==true) 
              {
               PartCloseTrade(ticket);
               if(TradeHasPartClosed==true)Alert("Ticket: ",ticket," was part closed");
               else Alert("Partclose failed!");

               TradeHasPartClosed=false;
              }//doPartClose

           }//if((NewSL-Bid)>(SLMinDistanceToPrice/factor))

        }//OP_SELL

      if(OrderType()==OP_BUY) 
        {
         ticket=OrderTicket();
         doPartClose=false;

         NewSL=NormalizeDouble(OrderOpenPrice(),Digits);

         name=OrderComment();
         if(StringFind(name,"from #")<0)doPartClose=true;

         if((Bid-NewSL)>(PartCloseFirstTpPips/factor)) 
           {

            if(doPartClose==true) 
              {
               PartCloseTrade(ticket);
               if(TradeHasPartClosed==true)Alert("Ticket: ",ticket," was part closed");
               else Alert("Partclose failed!");

               TradeHasPartClosed=false;
              }//doPartClose

           }//if((Bid-NewSL)>(PartCloseFirstTpPips/factor))

        }//OP_BUY

     }//for...

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void DoJS(string symbol,int nMagic) 
  {

   int ticket=-1;
   double NewSL=0;
   if(CloseEnough(OrderStopLoss(),0)) return;

   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if(manageAllTradesInThisPair==false) 
        {
         if(OrderMagicNumber()!=nMagic) continue;
        }

      if(OrderSymbol()!=symbol)continue;

      if(OrderType()==OP_SELL) 
        {
         ticket=OrderTicket();

           {
            NewSL=NormalizeDouble(OrderStopLoss()-(JumpStep/factor),Digits);

            if((NewSL-Bid)>(SLMinDistanceToPrice/factor)) 
              {

               if(((NewSL<OrderStopLoss()) || (OrderStopLoss()<(1/factor))) && (NewSL!=0) && (NewSL>Ask+(10/factor))) 
                 {

                  Alert("DoJS :Attempting to move SL of ",symbol," to ",NewSL);
                  Print("DoJS :Attempting to move SL of ",symbol," to ",NewSL);
                  ModifyOrder(ticket,NewSL,0);
                 }
              }
           }

         //	return;

        }

      if(OrderType()==OP_BUY) 
        {
         ticket=OrderTicket();

           {

            NewSL=NormalizeDouble(OrderStopLoss()+(JumpStep/factor),Digits);
            if((Bid-NewSL)>(SLMinDistanceToPrice/factor)) 
              {
               if(((NewSL>OrderStopLoss()) || (OrderStopLoss()<(1/factor))) && (NewSL!=0) && (NewSL<Bid -(10/factor))) 
                 {

                  Alert("DoJS :Attempting to move SL of ",symbol," to ",NewSL);
                  Print("DoJS :Attempting to move SL of ",symbol," to ",NewSL);
                  ModifyOrder(ticket,NewSL,0);
                 }
              }
           }

        }

     }
//return;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool PartCloseTrade(int ticket) 
  {
//Close PartClosePercent of the initial trade.
//Return true if close succeeds, else false
   if(!OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES)) return(true);//in case the trade closed
   bool selctedOrder=OrderSelect(ticket,SELECT_BY_TICKET,MODE_TRADES);
   bool Success=false;
   double CloseLots=NormalizeLots(OrderSymbol(),OrderLots() *(PartClosePercent/100));

   Success=OrderClose(ticket,CloseLots,OrderClosePrice(),1000,Blue); //fxdaytrader, NormalizeLots(...
   if(Success) TradeHasPartClosed=true;//Warns CountOpenTrades() that the OrderTicket() is incorrect.
   if(!Success) 
     {
      //mod. fxdaytrader, orderclose-retry if failed with ordercloseprice(). Maybe very seldom, but it can happen, so it does not hurt to implement this:
      while(IsTradeContextBusy()) Sleep(100);
      RefreshRates();
      if(OrderType()==OP_BUY) Success = OrderClose(ticket, CloseLots, MarketInfo(OrderSymbol(),MODE_BID), 5000, Blue);
      if(OrderType()==OP_SELL) Success = OrderClose(ticket, CloseLots, MarketInfo(OrderSymbol(),MODE_ASK), 5000, Blue);
      //end mod.
      //original:
      if(Success) TradeHasPartClosed=true;//Warns CountOpenTrades() that the OrderTicket() is incorrect.

      if(!Success) 
        {

         return (false);
        }
     }//if (!Success)

//Got this far, so closure succeeded
   return (true);

  }//bool PartCloseTrade(int ticket)
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string getUninitReasonText(int reasonCode) 
  {
   string text="";
//---
   switch(reasonCode) 
     {
      case REASON_ACCOUNT:
         text="Account was changed";
         break;
      case REASON_CHARTCHANGE:
         text="Symbol or timeframe was changed";
         break;
      case REASON_CHARTCLOSE:
         text="Chart was closed";
         break;
      case REASON_PARAMETERS:
         text="Input-parameter was changed";
         break;
      case REASON_RECOMPILE:
         text="Program "+__FILE__+" was recompiled";
         break;
      case REASON_REMOVE:
         text="Program "+__FILE__+" was removed from chart";
         break;
      case REASON_TEMPLATE:
         text="New template was applied to chart";
         break;
      default:
         text="Another reason";
     }
//---
   return text;
  }
//+------------------------------------------------------------------+
void setATRValues() 
  {
   if(useATRForStackingLevel==true) 
     {

      adr=GetAtr(Symbol(),atrForStackingLevelTF,atrPeriodForStackingLevel,0);
      if(CloseEnough(adr,0))adr=0.05;
      StackingLevel=NormalizeDouble((atrMultiplicatorForStackingLevel*adr*factor),0);
     }

   if(useATRForStopLoss==true) 
     {

      adr=GetAtr(Symbol(),atrForStopLossTF,atrPeriodForStopLoss,0);
      if(CloseEnough(adr,0))adr=0.05;
      SL=NormalizeDouble((atrMultiplicatorForStopLoss*adr*factor),0);
     }
   if(useATRForTakeProfit==true) 
     {

      adr=GetAtr(Symbol(),atrForTakeProfitTF,atrPeriodForTakeProfit,0);
      if(CloseEnough(adr,0))adr=0.05;
      TP=NormalizeDouble((atrMultiplicatorForTakeProfit*adr*factor),0);
     }
   if(useATRForSLMinDistanceToPrice==true) 
     {

      adr=GetAtr(Symbol(),atrForSLMinDistanceToPriceTF,atrPeriodForSLMinDistanceToPrice,0);
      if(CloseEnough(adr,0))adr=0.05;
      SLMinDistanceToPrice=NormalizeDouble((atrMultiplicatorForSLMinDistanceToPrice*adr*factor),0);
     }
   if(useATRForPartClosePips==true) 
     {

      adr=GetAtr(Symbol(),atrForPartClosePipsTF,atrPeriodForPartClosePips,0);
      if(CloseEnough(adr,0))adr=0.05;
      PartCloseFirstTpPips=NormalizeDouble((atrMultiplicatorForPartClosePips*adr*factor),0);
     }
  }
//+------------------------------------------------------------------+
bool RectLabelCreate() 
  {
//--- reset the error value
   ResetLastError();
//--- create a rectangle label
   if(ObjectFind(0,"messageBox")>=0) return true;
   if(!ObjectCreate(0,"messageBox",OBJ_RECTANGLE_LABEL,0,0,0)) 
     {
      Print(__FUNCTION__,
            ": failed to create a rectangle label! Error code = ",GetLastError());
      return(false);
     }
//--- set label coordinates
   ObjectSetInteger(0,"messageBox",OBJPROP_XDISTANCE,0);
   ObjectSetInteger(0,"messageBox",OBJPROP_YDISTANCE,0);
//--- set label size
   ObjectSetInteger(0,"messageBox",OBJPROP_XSIZE,500);
   ObjectSetInteger(0,"messageBox",OBJPROP_YSIZE,500);
//--- set background color
   ObjectSetInteger(0,"messageBox",OBJPROP_BGCOLOR,displayBoxBackgroundColour);
//--- set border type
   ObjectSetInteger(0,"messageBox",OBJPROP_BORDER_TYPE,BORDER_SUNKEN);
//--- set the chart's corner, relative to which point coordinates are defined
   ObjectSetInteger(0,"messageBox",OBJPROP_CORNER,0);
//--- set flat border color (in Flat mode)
   ObjectSetInteger(0,"messageBox",OBJPROP_COLOR,Red);
//--- set flat border line style
   ObjectSetInteger(0,"messageBox",OBJPROP_STYLE,STYLE_SOLID);
//--- set flat border width
   ObjectSetInteger(0,"messageBox",OBJPROP_WIDTH,1);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(0,"messageBox",OBJPROP_BACK,false);
//--- enable (true) or disable (false) the mode of moving the label by mouse
   ObjectSetInteger(0,"messageBox",OBJPROP_SELECTABLE,true);
   ObjectSetInteger(0,"messageBox",OBJPROP_SELECTED,false);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(0,"messageBox",OBJPROP_HIDDEN,false);
//--- set the priority for receiving the event of a mouse click in the chart
   ObjectSetInteger(0,"messageBox",OBJPROP_ZORDER,0);
//--- successful execution
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string  DateToStr(datetime mt4date,string mask="") 
  {

   int counter;
   int c_counter;
   string dayTextC;

   string ltext="",rtext="";
   if(StringSubstrOld(mask,0,1)=="'") 
     {
      for(counter=1; counter<StringLen(mask); counter++) 
        {
         if(StringSubstrOld(mask,counter,1)=="'") break;
         ltext=ltext+StringSubstrOld(mask,counter,1);
        }
      mask=StringSubstrOld(mask,counter+1);
     }
   if(StringSubstrOld(mask,StringLen(mask)-1,1)=="'") 
     {
      for(c_counter=StringLen(mask)-2; c_counter>=0; c_counter--) 
        {
         if(StringSubstrOld(mask,c_counter,1)=="'") break;
         rtext=StringSubstrOld(mask,c_counter,1)+rtext;
        }
      mask=StringSubstrOld(mask,0,c_counter);
     }

   if(mask=="") mask="Y.N.D H:I:S";

   bool blank=false;
   if(StringSubstrOld(StringUpper(mask),0,1)=="B") 
     {
      blank= true;
      mask = StringRight(mask,-1);
     }

   string mth[12] = {"January","February","March","April","May","June","July","August","September","October","November","December"};
   string dow[7]  = {"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};

   int dd  = TimeDay(mt4date);
   int mm  = TimeMonth(mt4date);
   int yy  = TimeYear(mt4date);
   int dw  = TimeDayOfWeek(mt4date);
   int hr  = TimeHour(mt4date);
   int min = TimeMinute(mt4date);
   int sec = TimeSeconds(mt4date);

   bool twelveHoursT=false;
   if(StringFind(StringUpper(mask),"A",0)>=0) twelveHoursT=true;
   int twelveHours=12;
   if(hr>12) twelveHours=hr-12;
   else if(hr>0) twelveHours=hr;
   string ampm="am";
   if(hr>=12)
      ampm="pm";

   int daynumber=int((MathMod(dd,10)));
   if(daynumber==1) dayTextC="st";
   else if(daynumber==2) dayTextC = "nd";
   else if(daynumber==3) dayTextC = "rd";
   else dayTextC="th";

   if(dd>10 && dd<14) dayTextC="th";

   int days = int(MathInt(mt4date/86400));
   int hrs  = int(MathInt(mt4date/3600));
   int mins = int(MathInt(mt4date/60));

   string outdate="";
   for(int i=0; i<StringLen(mask); i++) 
     {
      string char_var=StringSubstrOld(mask,i,1);
      if(char_var=="!") 
        {
         outdate=outdate+StringSubstrOld(mask,i+1,1);
         i++;
         continue;
        }
      if(char_var=="@") 
        {
         string char1 = StringSubstrOld(mask,i+1,1);
         string char2 = StringSubstrOld(mask,i+2,1);
         if(StringUpper(char1) == "D")    outdate = outdate + NumberToStr(days,char2);
         if(StringUpper(char1) == "H")    outdate = outdate + NumberToStr(hrs,char2);
         if(StringUpper(char1) == "I")    outdate = outdate + NumberToStr(mins,char2);
         i+=2;
         continue;
        }
      if(char_var=="d") outdate=outdate+StringTrim(NumberToStr(dd,"2"));
      else if(char_var ==  "D")               outdate = outdate + StringTrim(NumberToStr(dd,"Z2"));
      else if(char_var ==  "m")               outdate = outdate + StringTrim(NumberToStr(mm,"2"));
      else if(char_var ==  "M")               outdate = outdate + StringTrim(NumberToStr(mm,"Z2"));
      else if(char_var ==  "y")               outdate = outdate + StringTrim(NumberToStr(yy,"2"));
      else if(char_var ==  "Y")               outdate = outdate + StringTrim(NumberToStr(yy,"4"));
      else if(char_var ==  "n")               outdate = outdate + StringSubstrOld(mth[mm-1],0,3);
      else if(char_var ==  "N")               outdate = outdate + mth[mm-1];
      else if(char_var ==  "w")               outdate = outdate + StringSubstrOld(dow[dw],0,3);
      else if(char_var ==  "W")               outdate = outdate + dow[dw];
      else if(char_var ==  "h" && twelveHoursT)       outdate = outdate + StringTrim(NumberToStr(twelveHours,"2"));
      else if(char_var ==  "H" && twelveHoursT)       outdate = outdate + StringTrim(NumberToStr(twelveHours,"Z2"));
      else if(char_var ==  "h" && !twelveHoursT)      outdate = outdate + StringTrim(NumberToStr(hr,"2"));
      else if(char_var ==  "H" && !twelveHoursT)      outdate = outdate + StringTrim(NumberToStr(hr,"Z2"));
      else if(char_var ==  "i")               outdate = outdate + StringTrim(NumberToStr(min,"2"));
      else if(char_var ==  "I")               outdate = outdate + StringTrim(NumberToStr(min,"Z2"));
      else if(char_var ==  "s")               outdate = outdate + StringTrim(NumberToStr(sec,"2"));
      else if(char_var ==  "S")               outdate = outdate + StringTrim(NumberToStr(sec,"Z2"));
      else if(char_var ==  "a")               outdate = outdate + ampm;
      else if(char_var ==  "A")               outdate = outdate + StringUpper(ampm);
      else if(StringUpper(char_var)=="T") outdate=outdate+dayTextC;
      else
         outdate=outdate+char_var;
     }
   if(blank && mt4date==0)
      outdate=StringRepeat(" ",StringLen(outdate));
   return(ltext+outdate+rtext);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime LastOpenedTrade(string strSymbol,int nMagic) 
  {
   datetime timeelapsed=0;
   datetime opentime=0;

   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      if((OrderType()==OP_BUY) || (OrderType()==OP_SELL))
         if(OrderMagicNumber()==nMagic)
            if(OrderSymbol()==strSymbol)
               if(OrderOpenTime()>opentime) opentime=OrderOpenTime();
     }

   return(opentime);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
datetime LastClosedTrade(string strSymbol,int nMagic) 
  {
   datetime timeelapsed=0;
   datetime closetime=0;

   for(int i=OrdersHistoryTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)) continue;
      if((OrderType()==OP_BUY) || (OrderType()==OP_SELL))
         if(OrderMagicNumber()==nMagic)
            if(OrderSymbol()==strSymbol)
               if(OrderCloseTime()>closetime) closetime=OrderCloseTime();
     }

   return(closetime);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string StringUpper(string str)

  {
   string outstr = "";
   string lower  = "abcdefghijklmnopqrstuvwxyz";
   string upper  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   for(int i=0; i<StringLen(str); i++) 
     {
      int t1 = StringFind(lower,StringSubstrOld(str,i,1),0);
      if(t1 >=0)
         outstr=outstr+StringSubstrOld(upper,t1,1);
      else
         outstr=outstr+StringSubstrOld(str,i,1);
     }
   return(outstr);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string StringLower(string str)

  {
   string outstr="";
   int i;
   string lower  = "abcdefghijklmnopqrstuvwxyz";
   string upper  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
   for(i=0; i<StringLen(str); i++) 
     {
      int t1 = StringFind(upper,StringSubstrOld(str,i,1),0);
      if(t1 >=0)
         outstr=outstr+StringSubstrOld(lower,t1,1);
      else
         outstr=outstr+StringSubstrOld(str,i,1);
     }
   return(outstr);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string StringRight(string str,int n=1)

  {
   if(n > 0)  return(StringSubstrOld(str,StringLen(str)-n,n));
   if(n < 0)  return(StringSubstrOld(str,-n,StringLen(str)-n));
   return("");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double MathInt(double n,int d=0) 
  {

   return(MathFloor(n*MathPow(10,d)+0.000000000001)/MathPow(10,d));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string NumberToStr(double n,string mask="")

  {
   int ix,jx;
   int i;
   string char_var;
   bool comma,zeros,aster,blank,Round,overf,lftsh,swtch,trimf;
   string out1="";
   string out2= "";
   if(MathAbs(n)==2147483647)
      n=0;

   string ltext="",rtext="";
   if(StringSubstrOld(mask,0,1)=="'") 
     {
      for(ix=1; ix<StringLen(mask); ix++) 
        {
         if(StringSubstrOld(mask,ix,1)=="'") break;
         ltext=ltext+StringSubstrOld(mask,ix,1);
        }
      mask=StringSubstrOld(mask,ix+1);
     }
   if(StringSubstrOld(mask,StringLen(mask)-1,1)=="'") 
     {
      for(jx=StringLen(mask)-2; jx>=0; jx--) 
        {
         if(StringSubstrOld(mask,jx,1)=="'") break;
         rtext=StringSubstrOld(mask,jx,1)+rtext;
        }
      mask=StringSubstrOld(mask,0,jx);
     }

   if(mask=="") mask="TR-9.2";

   mask=StringUpper(mask);
   if(mask == "B")   return(ltext+rtext);

   int dotadj = 0;
   int dot    = StringFind(mask,".",0);
   if(dot<0) 
     {
      dot    = StringLen(mask);
      dotadj = 1;
     }

   int nleft  = 0;
   int nright = 0;
   for(i=0; i<dot; i++) 
     {
      char_var=StringSubstrOld(mask,i,1);
      if(char_var>="0" && char_var<="9") nleft=10*nleft+StrToInteger(char_var);
     }
   if(dotadj==0) 
     {
      for(i=dot+1; i<=StringLen(mask); i++) 
        {
         char_var=StringSubstrOld(mask,i,1);
         if(char_var>="0" && char_var<="9") nright=10*nright+StrToInteger(char_var);
        }
     }
   nright=MathMin(nright,7);

   if(dotadj==1) 
     {
      for(i=0; i<StringLen(mask); i++) 
        {
         char_var=StringSubstrOld(mask,i,1);
         if(char_var>="0" && char_var<="9") 
           {
            dot=i;
            break;
           }
        }
     }

   string csym="";
   if(StringFind(mask,"$",0) >= 0)   csym = "$";
   if(StringFind(mask,"£",0) >= 0)   csym = "£";
   if(StringFind(mask,"€",0) >= 0)   csym = "€";
   if(StringFind(mask,"¥",0) >= 0)   csym = "¥";

   string leadsign  = "";
   string trailsign = "";
   if(StringFind(mask,"+",0)>=0 && StringFind(mask,"+",0)<dot) 
     {
      leadsign=" ";
      if(n > 0)   leadsign  = "+";
      if(n < 0)   leadsign  = "-";
     }
   if(StringFind(mask,"-",0)>=0 && StringFind(mask,"-",0)<dot)
      if(n<0) leadsign="-";
   else leadsign=" ";
   if(StringFind(mask,"-",0)>=0 && StringFind(mask,"-",0)>dot)
      if(n<0) trailsign="-";
   else trailsign=" ";
   if(StringFind(mask,"(",0)>=0 || StringFind(mask,")",0)>=0) 
     {
      leadsign  = " ";
      trailsign = " ";
      if(n<0) 
        {
         leadsign  = "(";
         trailsign = ")";
        }
     }

   if(StringFind(mask,"%",0)>=0) trailsign="%"+trailsign;

   if(StringFind(mask,",",0)>=0) comma=true;
   else comma=false;
   if(StringFind(mask,"Z",0)>=0) zeros=true;
   else zeros=false;
   if(StringFind(mask,"*",0)>=0) aster=true;
   else aster=false;
   if(StringFind(mask,"B",0)>=0) blank=true;
   else blank=false;
   if(StringFind(mask,"R",0)>=0) Round=true;
   else Round=false;
   if(StringFind(mask,"~",0)>=0) overf=true;
   else overf=false;
   if(StringFind(mask,"L",0)>=0) lftsh=true;
   else lftsh=false;
   if(StringFind(mask,";",0)>=0) swtch=true;
   else swtch=false;
   if(StringFind(mask,"T",0)>=0) trimf=true;
   else trimf=false;

   if(Round) n=MathFix(n,nright);
   string outstr=DoubleToStr(n,0);

   int dleft=0;
   for(i=0; i<StringLen(outstr); i++) 
     {
      char_var=StringSubstrOld(outstr,i,1);
      if(char_var>= "0" && char_var <= "9") dleft++;
      if(char_var == ".") break;
     }

// Insert fill characters.......
   string fill=" ";
   if(zeros) fill = "0";
   if(aster) fill = "*";
   if(n<0)
      outstr="-"+StringRepeat(fill,nleft-dleft)+StringSubstrOld(outstr,1,StringLen(outstr)-1);
   else
      outstr=StringRepeat(fill,nleft-dleft)+StringSubstrOld(outstr,0,StringLen(outstr));

   outstr=StringSubstrOld(outstr,StringLen(outstr)-9-nleft,nleft+1+nright-dotadj);

// Insert the commas.......
   if(comma) 
     {
      bool digflg = false;
      bool stpflg = false;
      out1 = "";
      out2 = "";
      for(i=0; i<StringLen(outstr); i++) 
        {
         char_var=StringSubstrOld(outstr,i,1);
         if(char_var==".") stpflg=true;
         if(!stpflg && (nleft-i==3 || nleft-i==6 || nleft-i==9))
            if(digflg) out1=out1+",";
         else out1=out1+" ";
         out1=out1+char_var;
         if(char_var>="0" && char_var<="9") digflg=true;
        }
      outstr=out1;
     }
// Add currency symbol and signs........
   outstr=csym+leadsign+outstr+trailsign;

// 'Float' the currency symbol/sign.......
   out1 = "";
   out2 = "";
   bool fltflg=true;
   for(i=0; i<StringLen(outstr); i++) 
     {
      char_var=StringSubstrOld(outstr,i,1);
      if(char_var >= "0" && char_var <= "9")   fltflg = false;
      if((char_var == " " && fltflg) || (blank && n == 0) )   out1 = out1 + " ";
      else   out2=out2+char_var;
     }
   outstr=out1+out2;

// Overflow........
   if(overf && dleft>nleft) outstr="~"+StringSubstrOld(outstr,1,StringLen(outstr)-1);

// Left shift.......
   if(lftsh) 
     {
      int len= StringLen(outstr);
      outstr = StringLeftTrim(outstr);
      outstr = outstr + StringRepeat(" ",len-StringLen(outstr));
     }

// Switch period and comma.......
   if(swtch) 
     {
      out1 = "";
      for(i=0; i<StringLen(outstr); i++) 
        {
         char_var=StringSubstrOld(outstr,i,1);
         if(char_var==".") out1=out1+",";
         else if(char_var==",") out1=out1+".";
         else
            out1=out1+char_var;
        }
      outstr=out1;
     }

// Trim output....
   if(trimf) outstr=StringTrim(outstr);

   return(ltext+outstr+rtext);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string StringTrim(string str,string char_var=" ")

  {
   string outstr="";
   for(int i=0; i<StringLen(str); i++) 
     {
      if(StringFind(char_var,StringSubstrOld(str,i,1))<0)
         outstr=outstr+StringSubstrOld(str,i,1);
     }
   return(outstr);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double MathFix(double n,int d=0) 
  {

   return(MathRound(n*MathPow(10,d)+0.000000000001*MathSign(n))/MathPow(10,d));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string StringLeftTrim(string str,string char_var=" ")

  {
   bool   left=true;
   string outstr="";
   for(int i=0; i<StringLen(str); i++) 
     {
      if(StringFind(char_var,StringSubstrOld(str,i,1))<0 || !left) 
        {
         outstr=outstr+StringSubstrOld(str,i,1);
         left=false;
        }
     }
   return(outstr);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int MathSign(double n) 
  {

   if(n > 0) return(1);
   else if(n < 0) return (-1);
   else return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double DivZero(double varA,double varB) 
  {
   if(CloseEnough(varB,0.0)) return (0);
   return (varA / varB);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int orders_count(int magic,int type=-1,string comment="") 
  {
   int orders_total=OrdersTotal(),count=0;

   for(int i=0; i<orders_total; i++) 
     {
      if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) 
        {
         if(OrderSymbol()!=Symbol())
            continue;
         if((OrderMagicNumber()==magic || magic==0)
            && (OrderType()==type || type==-1)) 
           {
            if(comment=="" || OrderComment()==comment)
               count++;
           }
        }
     }

   return(count);
  }
//+------------------------------------------------------------------+
double GetProfitPair(string strSymbol) 
  {
   double profit=0;
   double loti=0;
   double relevantLot=0;
   int orders=0;
   for(int i=OrdersTotal()-1; i>=0; i--) 
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      //if(OrderMagicNumber()!=nMagic) continue;
      if(OrderSymbol()!=strSymbol) continue;
      if((OrderType()==OP_BUY) || (OrderType()==OP_SELL))

         profit=profit+(OrderProfit()+OrderSwap()+OrderCommission());
     }

   return(profit);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseAllOfPair() 
  {
   ForceTradeClosure=false;
   bool result=false;
   if(OrdersTotal() == 0) return;

   for(int cc=OrdersTotal()-1; cc>=0; cc--) 
     {
      if(!OrderSelect(cc,SELECT_BY_POS)) continue;
      // if(OrderMagicNumber()!=MagicNumber) continue;
      if(OrderSymbol()!=Symbol()) continue;
      while(IsTradeContextBusy()) Sleep(100);
      if(OrderType()==OP_BUY || OrderType()==OP_SELL) result=OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),1000,CLR_NONE);
      if(result) cc++;

      //if (!result) ForceTradeClosure= true; //original, fxdaytrader

      //mod. fxdaytrader, orderclose-retry if failed with ordercloseprice(). Maybe very seldom, but it can happen, so it does not hurt to implement this:
      if(!result) 
        {
         while(IsTradeContextBusy()) Sleep(100);
         RefreshRates();
         if(OrderType()==OP_BUY) result = OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(),MODE_BID), 5000, CLR_NONE);
         if(OrderType()==OP_SELL) result = OrderClose(OrderTicket(), OrderLots(), MarketInfo(OrderSymbol(),MODE_ASK), 5000, CLR_NONE);
         if(!result) ForceTradeClosure=true;
        }
      //end mod.

     }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseFriday(string strSymbol,int nMagic) 
  {
   int ticket=-1;
   if((DayOfWeek()==5) && (TimeHour(TimeCurrent())>=FridayCloseHour) && (TimeMinute(TimeCurrent())>=FridayCloseMinute)) 
     {

      for(int i=OrdersTotal()-1; i>=0; i--) 
        {
         if(!OrderSelect(i,SELECT_BY_POS)) continue;
         if(OrderMagicNumber()!=nMagic) continue;
         if(OrderSymbol()!=strSymbol) continue;
         if(OrderType()==OP_BUY) 
           {
            ticket=OrderTicket();

            if(AllowedSpread(strSymbol)==true)

              {
               while(IsTradeContextBusy()) Sleep(100);
               Alert("CloseFriday:Attempting to close ",strSymbol);
               Print("CloseFriday:Attempting to close ",strSymbol);
               if(OrderClose(ticket,OrderLots(),Bid,slippage,Red)) 
                 {
                  Alert("CloseFriday:Close ",strSymbol," Succeeded !");
                  Print("CloseFriday:Close ",strSymbol," Succeeded !");
                    } else {
                  Alert("CloseFriday:Close ",strSymbol," Failed !");
                  Print("CloseFriday:Close ",strSymbol," Failed !");
                 }
              }

           }
         if(OrderType()==OP_SELL) 
           {
            ticket=OrderTicket();

            if(AllowedSpread(strSymbol)==true)

              {
               while(IsTradeContextBusy()) Sleep(100);
               Alert("CloseFriday:Attempting to close ",strSymbol);
               Print("CloseFriday:Attempting to close ",strSymbol);
               if(OrderClose(ticket,OrderLots(),Ask,slippage,Red)) 
                 {
                  Alert("CloseFriday:Close ",strSymbol," Succeeded !");
                  Print("CloseFriday:Close ",strSymbol," Succeeded !");
                    } else {
                  Alert("CloseFriday:Close ",strSymbol," Failed !");
                  Print("CloseFriday:Close ",strSymbol," Failed !");
                 }
              }

           }
        }
     }

  }
//+------------------------------------------------------------------+
