//+-------------------------------------------------------------------+
//|           Awesome with fh auto trading robot by Steve Hopwood.mq4 |
//|                                  Copyright © 2009, Steve Hopwood  |
//|                              http://www.hopwood3.freeserve.co.uk  |
//+-------------------------------------------------------------------+
#property copyright "Copyright © 2009, Steve Hopwood"
#property link      "http://www.hopwood3.freeserve.co.uk"
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"
#define  up "Up"
#define  down "Down"
#define  none "None"
#define  buy "Buy"
#define  sell "Sell"
#define  ranging "Ranging"
#define  confused "Confused, and so cannot trade"
#define  trending "Trending"
#define  opentrade "There is a trade open"
#define  stopped "Trading is stopped"
#define  line "Pivot line"
#define  increasing "Rising, so the robot will trade"
#define  shrinking "Falling, so the robot will not trade"
#define  notmoving "Static, so the robot will not trade"


/*

Matt Kennel has provided the code for bool O_R_CheckForHistory(int ticket). Cheers Matt, You are a star.



Code for adding debugging Sleep
int x = 0;
while (x == 0) Sleep(100);

FUNCTIONS LIST
int init()
int start()

----Trading----

void StartTradingSequence()
void SendNewPendingTrade()
bool IsTradingAllowed()
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
bool DoesTradeExist()
void CountOpenTrades()
void LookForTradeClosure()
bool CheckTradingTimes()
void CloseAllTrades()


----Matt's Order Reliable library code
bool O_R_CheckForHistory(int ticket) Cheers Matt, You are a star.
void O_R_Sleep(double mean_time, double max_time)

----Indicator readings---- 
void ReadIndicatorValues()
void GetBB(int shift)
double GetRsi(int tf, int period, int ap, int shift)
double GetMa(int tf, int period, int mashift, int method, int ap, int shift)
double CalculateVolatility(int period, int LookBack)

----Pivot----
void GetPivot()
void DrawPivot(double pivot)


----Trend detection module----
void TrendDetectionModule()





*/

extern string  gen="----General inputs----";
extern double  Lot=0.01;
extern bool    StopTrading=false;
extern bool    TradeLong=true;
extern bool    TradeShort=true;
extern int     TakeProfit=0;
extern int     StopLoss=0;
extern int     MagicNumber=0;
extern string  TradeComment="";
extern bool    CriminalIsECN=true;
extern int     MaxSpread=40;

extern string  ms="----Martingale----";
extern double  MartingaleMultiplier=0;
extern double  MaxLots=3.84;

extern string  sc="----Post basket closure sleep time----";
extern int     SleepMinsAfterClosure=0;

extern string  sqi="----sq inputs----";
extern int     BoxLength           = 22;
extern int     BoxTimeFrame        = 15;
extern int     BoxRange            = 30;
extern color   BreakoutBoxColor    = DodgerBlue;
// new inputs to adjust BoxRange to the current Daily volatility :
//extern bool   AutoBoxRange     = true;// when true, will use AutoBoxRangeDailyATRfactor*daily_ATR_value as the BoxRange value;
extern int    AutoBoxRangeDailyATRperiod = 30;
extern double AutoBoxRangeDailyATRfactor = 0.20;
extern double  BufferPips = 0; // pips buffer around the Box


extern string  amc="----Available Margin checks----";
extern string  sco="Scoobs";
extern bool    UseScoobsMarginCheck=false;
extern string  fk="ForexKiwi";
extern bool    UseForexKiwi=true;
extern int     FkMinimumMarginPercent=1500;


extern string  tt="----Trading hours----";
extern string  Trade_Hours= "Set Morning & Evening Hours";
extern string  Trade_Hoursi= "Use 24 hour, local time clock";
extern string  Trade_Hours_M= "Morning Hours 0-12";
extern  int    start_hourm = 0;
extern  int    end_hourm = 12;
extern string  Trade_Hours_E= "Evening Hours 12-24";
extern  int    start_houre = 12;
extern  int    end_houre = 24;

extern string  mis="----Odds and ends----";
extern int     DisplayGapSize=30;


//Matt's O-R stuff
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 */

//Trading variables
int            TicketNo;
bool           FilledOpen, PendingOpen;

datetime       LastSequence.OpenTime;

//BB variables
double         BbUpper, BbMiddle, BbLower, BbExtent, PrevBbExtent;
string         BbVolatility;

//Rsi
double         RsiVal;

//Moving average
double         MaVal;

//Volatility
double         Volatility;

//Date/Time
datetime       ConvertedStartTime;

//Trend detection
string         trend;
double         TrendRsiVal;//Rsi
double         FastTrendMaVal, SlowTrendMaVal;//2 MA trend
double         SingleTrendMaVal, PrevSingleTrendMaVal;//Single trend ma

//Misc
string         Gap, ScreenMessage;
int            OldBars;
string         PipDescription=" pips";
bool           ForceTradeClosure;

int            multiplier;

int _period,_minP,_maxP,_prevP;
datetime box_forming_time;
bool new_box_formed;
string prefix;
double         boxHigh,boxLow,prev_boxHigh,prev_boxLow,_BoxRangeValue,_TradingRangeValue;
double         tHigh,tLow;

void DisplayUserFeedback()
{
   
   if (IsTesting() && !IsVisualMode()) return;

   ScreenMessage = "";
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, TimeToStr(TimeLocal(), TIME_DATE|TIME_MINUTES|TIME_SECONDS), NL );
   /*
   //Code for time to bar-end display from Candle Time by Nick Bilak
   double i;
   int m,s,k;
   m=Time[0]+Period()*60-CurTime();
   i=m/60.0;
   s=m%60;
   m=(m-m%60)/60;
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, m + " minutes " + s + " seconds left to bar end", NL);
   */
      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Lot size: ", Lot, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Take profit: ", TakeProfit, PipDescription,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Stop loss: ", StopLoss, PipDescription,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Magic number: ", MagicNumber, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trade comment: ", TradeComment, NL);
   if (CriminalIsECN) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = true", NL);
   else ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = false", NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Criminal's minimum lot size: ", MarketInfo(Symbol(), MODE_MINLOT), NL, NL );
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trading hours", NL);
   if (start_hourm == 0 && end_hourm == 12 && start_houre && end_houre == 24) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            24H trading", NL);
   else
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            start_hourm: ", DoubleToStr(start_hourm, 2), 
                      ": end_hourm: ", DoubleToStr(end_hourm, 2), NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            start_houre: ", DoubleToStr(start_houre, 2), 
                      ": end_houre: ", DoubleToStr(end_houre, 2), NL);
                      
   }//else
   
   
   //Trend
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   
   
   Comment(ScreenMessage);


}//void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----

   //Adapt to x digit criminals
   if(Digits == 2 || Digits == 4) multiplier = 1;
   if(Digits == 3 || Digits == 5) multiplier = 10;
   if(Digits == 6) multiplier = 100;   
   if(Digits == 7) multiplier = 1000;   
   
   if (multiplier > 1) PipDescription = " points";
   
   TakeProfit*= multiplier;
   StopLoss*= multiplier;
   BufferPips*= multiplier;
   
   Gap="";
   if (DisplayGapSize >0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }//if (DisplayGapSize >0)
   

   if (TradeComment == "") TradeComment = " ";
   
   DisplayUserFeedback();

   if (BoxTimeFrame==0) BoxTimeFrame=Period();
   _period = BoxLength * BoxTimeFrame/Period();
   _minP   = _period;
   _prevP  = _period;
   _BoxRangeValue = BoxRange * Point*multiplier; // convert pips to price range
    
   prefix = "Awesome fh"+BoxLength+" "+BoxTimeFrame+" "+BoxRange;
   
   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment("");
   if (!IsTesting()) RemoveObjects(prefix);
//----
   return(0);
}


bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
{
      
   
   int slippage = 10;
   if (Digits == 3 || Digits == 5) slippage = 100;
   
   color col = Red;
   if (type == OP_BUY || type == OP_BUYSTOP) col = Green;
   
   int expiry = 0;
   //if (SendPendingTrades) expiry = TimeCurrent() + (PendingExpiryMinutes * 60);

   if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, expiry, col);
   
   if (CriminalIsECN && (type == OP_BUYSTOP || type == OP_SELLSTOP) ) 
   {
      ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, expiry, col);
   }//if (CriminalIsECN && (type == OP_BUYSTOP || OrderType() == OP_SELLSTOP) ) 
   
   //Is a 2 stage criminal
   if (CriminalIsECN && (type == OP_BUY || type == OP_SELL) )
   {
      bool result;
      int err;
      ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, expiry, col);
      if (ticket > 0)
      {
	     
	     if (take > 0 && stop > 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), stop, take, OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL/TP  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take > 0 && stop > 0)
      
	     if (take != 0 && stop == 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take == 0 && stop != 0)

        if (take == 0 && stop != 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take == 0 && stop != 0)

      }//if (ticket > 0)
        
      
      
   }//if (CriminalIsECN)
   
   //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";
      err=GetLastError();
      Alert(Symbol(), " ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
      Print(Symbol(), " ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
      return(false);
   }//if (ticket < 0)  
   

   TicketNo = ticket;
   //Make sure the trade has appeared in the platform's history to avoid duplicate trades
   O_R_CheckForHistory(ticket); 
   
   //Got this far, so trade send succeeded
   return(true);
   
}//End bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
/*
bool DoesTradeExist()
{
   
   TicketNo = -1;
   
   if (OrdersTotal() == 0) return(false);
   
   for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      
      if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
      {
         TicketNo = OrderTicket();
         return(true);         
      }//if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)

   return(false);

}//End bool DoesTradeExist()
*/


bool IsTradingAllowed()
{
   //Returns false if any of the filters should cancel trading, else returns true to allow trading
   
      
   //Maximum spread
   if (MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread) return(false);
 
   //Volatility measured by BB
   
   
   return(true);


}//End bool IsTradingAllowed()


void StartTradingSequence()
{

   if (!IsTradingAllowed() ) return;
   
   double take, stop, price, tp, sl;
   int type,err;
   bool result,SendTrade;

   RefreshRates();
   
   // use either fixed TP/SL or based on CZ Box size
   if (TakeProfit > 0) tp = TakeProfit * Point;
   else tp = _TradingRangeValue;
   if (StopLoss > 0) sl = (StopLoss * Point);
   else sl = 2*_TradingRangeValue;
   
   
   //Long 
   //if (Low[1] <= tHigh && Close[1] > tHigh)
   if (Low[0] <= tHigh && Close[0] > tHigh)
   {
      take = NormalizeDouble(Ask + tp, Digits);
      stop = NormalizeDouble(Ask - sl, Digits);
      type = OP_BUY;
      price = Ask;
      SendTrade = true;
   }//if (Open[1] <= tHigh && Close[1] > tHigh)
   
   
   //Short
   //if (High[1] >= tLow && Close[1] < tLow)
   if (High[0] >= tLow && Close[0] < tLow)
   {
      take = NormalizeDouble(Bid - tp, Digits);
      stop = NormalizeDouble(Bid + sl, Digits);
      type = OP_SELL;
      price = Bid;
      SendTrade = true;      
   }//if (Open[1] >= tLow && Close[1] < tLoe)
   
   if (SendTrade)
   {
      result = SendSingleTrade(type, TradeComment, Lot, price, stop, take);
   }//if (SendTrade)

   

}//void StartTradingSequence()

////////////////////////////////////////////////////////////////////////////////////////////////
//Indicator module





/*
void ReadIndicatorValues()
{

   //GetBB(0);
   //RsiVal = GetRsi(RsiTf, RsiPeriod, RsiAppliedPrice, 0);
   //MaVal = GetMa(MaTF, MaPeriod, MaShift, MaMethod, MaAppliedPrice, 0);
   //Volatility = CalculateVolatility(PERIOD_D1, LookBackDays);
   
}//void ReadIndicatorValues()
*/
//End Indicator module
////////////////////////////////////////////////////////////////////////////////////////////////

void CloseAllTrades()
{
   ForceTradeClosure= false;
   
   if (OrdersTotal() == 0) return;
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderSymbol() == Symbol() )
      {
         while(IsTradeContextBusy()) Sleep(100);
         if (OrderType() == OP_BUY || OrderType() == OP_SELL) bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, CLR_NONE);
         if (OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP) result = OrderDelete(OrderTicket(), CLR_NONE);
         if (result) cc++;
         if (!result) ForceTradeClosure= true;
      }//if (OrderSymbol() == Symbol() )
   
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)


}//End void CloseAllTrades()


bool CheckTradingTimes()
{
   int hour = TimeHour(TimeLocal() );
   
   if (end_hourm < start_hourm)
	{
		end_hourm += 24;
	}
	

	if (end_houre < start_houre)
	{
		end_houre += 24;
	}
	
	bool ok2Trade = true;
	
	ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre);

	// adjust for past-end-of-day cases
	// eg in AUS, USDJPY trades 09-17 and 22-06
	// so, the above check failed, check if it is because of this condition
	if (!ok2Trade && hour < 12)
	{
 		hour += 24;
		ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre);		
		// so, if the trading hours are 11pm - 6am and the time is between  midnight to 11am, (say, 5am)
		// the above code will result in comparing 5+24 to see if it is between 23 (11pm) and 30(6+24), which it is...
	}


   // check for end of day by looking at *both* end-hours

   if (hour >= MathMax(end_hourm, end_houre))
   {      
      ok2Trade = false;
   }//if (hour >= MathMax(end_hourm, end_houre))

   return(ok2Trade);

}//bool CheckTradingTimes()

void CountOpenTrades()
{
   TicketNo = -1;
   FilledOpen = false;
   PendingOpen = false;

   if (OrdersTotal() == 0) return;
   
   for (int cc = 0; cc <= OrdersTotal(); cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
      {
         if (OrderType() == OP_BUY || OrderType() == OP_SELL) 
         {
            FilledOpen = true;
            //Only need the ticket number of the most recent filled trade
            TicketNo = OrderTicket();
         }//if (OrderType() == OP_BUY || OrderType() == OP_SELL) 
         
         if (OrderType() == OP_BUYSTOP || OrderType() == OP_SELLSTOP) 
         {
            PendingOpen = true;            
         }//if (OrderType() == OP_BUY || OrderType() == OP_SELL) 
         
      }//if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
   }//for (int cc = 0; cc < OrdersTotal() - 1; cc++)
   
   
}//End void CountOpenTrades();

void GetFirstTradeOfLastSequence()
{
   // we want to find the first trade of the last sequence:
   // it is the one with initial Lot size

   LastSequence.OpenTime = 0;
   if (OrdersHistoryTotal() == 0) return;
   
   //find last closed trade in trades history; start from last history trade=latest
   for (int cc = OrdersHistoryTotal()-1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS, MODE_HISTORY) ) continue;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
      {
         if (OrderLots() == Lot) 
         {
            LastSequence.OpenTime = OrderOpenTime();
            return;
         }
      }
   }

}

//=============================================================================
//                           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(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 #"+ticket+" in history, sleeping, then doing retry #"+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) {
      OrderSelect(lastTicket, SELECT_BY_TICKET, MODE_TRADES);
   }
   if (!success) {
      Print("Never found #"+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 = t*1000;
   if (ms < 10) {
      ms=10;
   }
   Sleep(ms);
}//End void O_R_Sleep(double mean_time, double max_time)







void SendNewPendingTrade()
{
   //Called when there is a filled trade open but no pending hedge in place
      
   if (!OrderSelect(TicketNo, SELECT_BY_TICKET) ) return;
   if (OrderCloseTime() > 0) return;
   
   RefreshRates();
   double take, stop, price, tp, sl;
   int type;

   //Calculate hedge lot size
   double SendLots;
   if (OrderLots() == Lot) SendLots = Lot * 3;//First hedge triple initial lot size
   if (OrderLots() > Lot) SendLots = OrderLots() * 2;//Subsequent trades double the previous lot size
   if (MartingaleMultiplier > 0) SendLots = OrderLots() * MartingaleMultiplier;//Allows the user to customise the martingale lot multiplier
   if (SendLots > MaxLots) {
      Alert(" !!! Lots too high:"+SendLots+">"+MaxLots);
      return;
   }
   
   // use either fixed TP/SL or based on CZ Box size
   if (TakeProfit > 0) tp = TakeProfit * Point;
   else tp = _TradingRangeValue;
   if (StopLoss > 0) sl = (StopLoss * Point);
   else sl = 2*_TradingRangeValue;
   
   //Sell hedge
   if (OrderType() == OP_BUY)
   {
      if (!OrderSelect(TicketNo, SELECT_BY_TICKET) ) return;
      price = NormalizeDouble(OrderOpenPrice() - tp, Digits);
      take = NormalizeDouble(price - tp, Digits);
      stop = NormalizeDouble(price + sl, Digits);
      if (IsTradeContextBusy() ) Sleep(100);
      SendSingleTrade(OP_SELLSTOP, TradeComment, SendLots, price, stop, take);
      
   }//if (OrderType == OP_BUY)
   
   //Buy hedge
   if (OrderType() == OP_SELL)
   {
      //Pending trade
      if (!OrderSelect(TicketNo, SELECT_BY_TICKET) ) return;
      price = NormalizeDouble(OrderOpenPrice() + tp, Digits);
      take = NormalizeDouble(price + tp, Digits);
      stop = NormalizeDouble(price - sl, Digits);
      if (IsTradeContextBusy() ) Sleep(100);
      SendSingleTrade(OP_BUYSTOP, TradeComment, SendLots, price, stop, take);
      
      
   }//if (OrderType == OP_SELL)
   
   
   
}//void SendNewPendingTrade()

//+------------------------------------------------------------------+
int GetPeriodForMinRange(int shift, int MinP, int MaxP, double MinRange, int prevP)
//+------------------------------------------------------------------+
{
  int P;
  double range;
  // calc P so that the Price Range (=Hi-Lo) remains in a "reasonably large value" over the P
  P=prevP; // start with previous P
  if (P<MinP) P=MinP;
  if (P>MaxP) P=MaxP;
  if (_get_range(P,shift) > MinRange) {//range is OK for this P value: try shorter P values
    for (; P>=MinP; P--) {
      if (_get_range(P,shift) <= MinRange) return(P+1);//previous P value was the limit
    }
    return(P);
  }
  //try higher P values
  for (P=prevP+1; P<MaxP; P++) {
    if (_get_range(P,shift) > MinRange) return(P);
  }
  return(MaxP);
}

  double _get_range(int period, int shift)
  {
    return(High[iHighest(NULL,0,MODE_HIGH,period,shift)] - Low[iLowest(NULL,0,MODE_LOW,period,shift)]);
  }

//--------------------------------------------------------------------------------------
void drawBox (string objname, datetime tStart, double vStart, datetime tEnd, double vEnd, color c, int width, int style, bool bg, string comment)
//--------------------------------------------------------------------------------------
{
  if (ObjectFind(objname) == -1) {
    ObjectCreate(objname, OBJ_RECTANGLE, 0, tStart,vStart,tEnd,vEnd);
  } else {
    ObjectSet(objname, OBJPROP_TIME1, tStart);
    ObjectSet(objname, OBJPROP_TIME2, tEnd);
    ObjectSet(objname, OBJPROP_PRICE1, vStart);
    ObjectSet(objname, OBJPROP_PRICE2, vEnd);
  }

  ObjectSet(objname,OBJPROP_COLOR, c);
  ObjectSet(objname, OBJPROP_BACK, bg);
  ObjectSet(objname, OBJPROP_WIDTH, width);
  ObjectSet(objname, OBJPROP_STYLE, style);
  //ObjectSetText(objname, comment);
} /* drawBox */

//+------------------------------------------------------------------
void drawVLine(string objname, int time, color c, int style=STYLE_SOLID, int width=0, int win=0)
//+------------------------------------------------------------------
{
  ObjectCreate(objname, OBJ_VLINE, win, time, 0);
  ObjectSet(objname, OBJPROP_COLOR, c);
  ObjectSet(objname, OBJPROP_STYLE, style);
  ObjectSet(objname, OBJPROP_WIDTH, width);
}

//+------------------------------------------------------------------
void drawTrendLine(string objname, int t1, double p1, int t2, double p2, color c, int style=STYLE_SOLID, int width=0)
//+------------------------------------------------------------------
{
  if (ObjectFind(objname) == -1) {
    ObjectCreate(objname, OBJ_TREND, 0, t1,p1, t2,p2);
  } else {
    ObjectSet(objname, OBJPROP_TIME1, t1);
    ObjectSet(objname, OBJPROP_TIME2, t2);
    ObjectSet(objname, OBJPROP_PRICE1, p1);
    ObjectSet(objname, OBJPROP_PRICE2, p2);
  }
  ObjectSet(objname, OBJPROP_RAY, false);
  ObjectSet(objname, OBJPROP_COLOR, c);
  ObjectSet(objname, OBJPROP_STYLE, style);
  ObjectSet(objname, OBJPROP_WIDTH, width);
}

//--------------------------------------------------------------------------------------
void RemoveObjects(string prefix)
//--------------------------------------------------------------------------------------
{   
   int i;
   string objname;

   for (i = ObjectsTotal(); i >= 0; i--) {
      objname = ObjectName(i);
      if (StringFind(objname, prefix, 0) > -1) ObjectDelete(objname);
   }
} /* RemoveObjects*/

//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

   
   if (OrdersTotal() == 0)
   {
      TicketNo = -1;
      ForceTradeClosure = false;
   }//if (OrdersTotal() == 0)

   if (ForceTradeClosure) 
   {
      CloseAllTrades();
      return;
   }//if (ForceTradeClosure) 

   //ReadIndicatorValues();

   /*
   //Pivot
   if (UsePivot && OldBars != iBars(NULL, PivotTimeFrame) )
   {
      OldBars = iBars(NULL, PivotTimeFrame);
      GetPivot();
   }//if (UsePivot && OldBars != iBars(NULL, PivotTimeFrame)
   
   //Draw a yellow line if one does not already exist
   if (ObjectFind(line) == -1 && UsePivot) 
   {
      GetPivot();      
   }//if (ObjectFind(line) == -1) 
   */
    
    // determine the BoxRange dynamically using the Daily ATR;
   _BoxRangeValue = AutoBoxRangeDailyATRfactor  * iATR(NULL,PERIOD_D1,AutoBoxRangeDailyATRperiod,1);
   double _rangepips = _BoxRangeValue / (Point * multiplier);
   BoxRange = _rangepips;

   //----------------------------------//
   //  Dynamic Breakout Box detection  //
   //----------------------------------//
   

   _period = GetPeriodForMinRange(1, _minP, 999, _BoxRangeValue, _period);
   if (_period > _minP) { // Price range remained below BoxRange longer than BoxLength:
     if (Time[_period] > box_forming_time)
     {// and this new box is not overlapping the previous one: this is a NEW BOX

       box_forming_time = TimeCurrent(); // remember Box starting candle;
       boxHigh = High[iHighest(NULL, 0, MODE_HIGH, _period, 0)];
       boxLow  = Low [iLowest (NULL, 0, MODE_LOW,  _period, 0)];
       // limit the Box Range to BoxRange;
       // snap the Box to the extreme that is opposite of the first(oldest) candle of the Box
       if (High[0+_period-1]==boxHigh) boxHigh = boxLow  + _BoxRangeValue;
       if (Low[0+_period-1]==boxLow)   boxLow  = boxHigh - _BoxRangeValue;

       Print("NEW BOX formed at ",TimeToStr(box_forming_time)," boxHigh="+boxHigh+" boxLow="+boxLow, " range="+DoubleToStr((boxHigh-boxLow)/(Point*multiplier),1));
       if (MathAbs(boxHigh-prev_boxHigh)>3*Point*multiplier) // a new Box is considered only when it is 
       {
          new_box_formed = true;
          // a new box has formed: remember the new box high/low levels
          prev_boxHigh = boxHigh;
          prev_boxLow = boxLow;
       }
       // draw a Box where it started to form:
       drawBox(prefix+TimeToStr(Time[0+1]), Time[0+_minP], boxHigh, Time[0+1], boxLow, BreakoutBoxColor, 0, STYLE_SOLID, true, "");
       drawVLine(prefix+"V"+TimeToStr(Time[0]), Time[0], BreakoutBoxColor);
     }
   }

   // draw High and Low trading lines
   tHigh = boxHigh + BufferPips*Point;
   tLow  = boxLow  - BufferPips*Point;
   // adjust current Box Range to its real value
   _TradingRangeValue = tHigh - tLow;
   drawTrendLine(prefix+"-High-"+TimeToStr(box_forming_time), box_forming_time, tHigh, Time[0], tHigh, BreakoutBoxColor);
   drawTrendLine(prefix+"-Low-"+TimeToStr(box_forming_time), box_forming_time, tLow, Time[0], tLow, BreakoutBoxColor);

   ///////////////////////////////////////////////////////////////////////////////////////////////
   //Find open trades.
   static bool OldFilledOpen;
   OldFilledOpen = FilledOpen;
   CountOpenTrades();
   //Has a basket just closed?
   if (OldFilledOpen && !FilledOpen) 
   {
      if (PendingOpen) CloseAllTrades();
      Comment(Gap, "Sleeping after successful trade closure");
      Sleep(SleepMinsAfterClosure * 60000);
   }//if (OldFilledOpen && !FilledOpen) 
   
   //Delete pending once a trade has hit tp
   if (!FilledOpen && PendingOpen)
   {
      CloseAllTrades();
      return;   
   }//if (!FilledOpen && PendingOpen_
   
   //Add the next trade in the sequence if a pending has filled
   if (FilledOpen && !PendingOpen)
   {
      SendNewPendingTrade();
   }//if (!FilledOpen && PendingOpen_
   

   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //Trading times
   bool TradeTimeOk = CheckTradingTimes();
   if (!TradeTimeOk)
   {
      Comment("Outside trading hours\nstart_hourm-end_hourm: ", start_hourm, "-",end_hourm, "\nstart_houre-end_houre: ", start_houre, "-",end_houre);
      return;
   }//if (hour < start_hourm)
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   //Available margin filters
   if (UseScoobsMarginCheck && FilledOpen > 0)
   {
      if(AccountMargin() > (AccountFreeMargin()/100)) 
      {
         Comment(Gap + "There is insufficient margin to allow trading. You might want to turn off the UseScoobsMarginCheck input.");
         return;
      }//if(AccountMargin() > (AccountFreeMargin()/100)) 
      
   }//if (UseScoobsMarginCheck)


   if (UseForexKiwi && AccountMargin() > 0)
   {
      
      double ml = NormalizeDouble(AccountEquity() / AccountMargin() * 100, 2);
      if (ml < FkMinimumMarginPercent)
      {
         Comment(Gap + "There is insufficient margin percent to allow trading. " + DoubleToStr(ml, 2) + "%");
         return;
      }//if (ml < FkMinimumMarginPercent)
      
   }//if (UseForexKiwi && AccountMargin() > 0)

   ///////////////////////////////////////////////////////////////////////////////////////////////         
   //Trading
   
   if (TicketNo == -1 && !StopTrading)
   {
     // start a new sequence only once per CZ Box
     GetFirstTradeOfLastSequence();
     //FirstTradeOfLastSequence.TicketNo
     if (LastSequence.OpenTime < box_forming_time) {
       // the last sequence started before the last CZ Box formed:
       // => no sequence was started on this session yet
       //Send initial trades in the sequence
       StartTradingSequence();
     }
   }//if (TicketNo == -1)
   ///////////////////////////////////////////////////////////////////////////////////////////////      

   DisplayUserFeedback();
   
//----
   return(0);
}
//+------------------------------------------------------------------+