//+------------------------------------------------------------------+
//|                 Murrey Maths auto-trading EA by SteveHopwood.mq4 |
//|                                  Copyright © 2010, Steve Hopwood |
//|                              http://www.hopwood3.freeserve.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010, Steve Hopwood"
#property link      "http://www.hopwood3.freeserve.co.uk"
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"

//I have taken the code that displays the MM lines directly from this indicator.
//My grateful appreciation to the authour of the indi.
//+------------------------------------------------------------------+
//|                                           Murrey_Math_Line_X.mq4 |
//|                         Copyright © 2004, Vladislav Goshkov (VG).|
//|                                                      4vg@mail.ru |
//|                                 code change by Alex.Piech.FinGeR |
//+------------------------------------------------------------------+

//Alert("G");
//int x = 1;
//while (x == 1) Sleep(100);


/*
void LookForTradingOpportunities()
void DrawLines()
void GetCurrentMMlPosition()
bool DoesTradeExist(double lot)
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
void CountOpenTrades()
void TradeDirectionBySwap()
bool ShouldPositionClose()
void DeletePendingTrades()
void CloseAllTrades()


----Hedging----
void HedgeAll()
void HedgingModule(int cc)


*/

extern string  gi="----General inputs----";
extern double  Lot1=0.01;
extern double  Lot2=0.02;
extern double  Lot3=0.06;
extern double  Lot4=0.12;
extern int     BufferPips=10;
extern bool    TradeLong=true;
extern bool    TradeShort=true;
bool    CriminalIsECN=false;//Remove as an extern to leave the option open for using it - you never know
extern int     MagicNumber=0;
int     TakeProfit=0;//Remove as an extern to leave the option open for using it - you never know

//extern string  lto="----Losing trade options----";
//extern string  hed="Hedging";
bool    UseHedging=false;//Remove as an extern to leave the option open for using it - you never know
double  HedgeLotMultiplier=2;//Remove as an extern to leave the option open for using it - you never know

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=1100;

extern string  pts="----Swap filter----";
//extern bool    TradePositiveSwapOnly=true;
extern bool    CadPairsPositiveOnly=true;
extern bool    AudPairsPositiveOnly=true;
extern bool    NzdPairsPositiveOnly=true;

extern string     mm="----Murray Mathis inputs----";
extern int P = 64;//MM indi
extern int MMPeriod = 15;//MM indi
extern int StepBack = 0;//MM indi

///////////////////////////////////////////////////////////////////////////////////////////
//Indi variables
extern color  mml_clr_m_2_8 = Yellow;       // [-2]/8
extern color  mml_clr_m_1_8 = Purple;       // [-1]/8
extern color  mml_clr_0_8   = DeepSkyBlue;        //  [0]/8
extern color  mml_clr_1_8   = DarkOrange;      //  [1]/8
extern color  mml_clr_2_8   = Red;         //  [2]/8
extern color  mml_clr_3_8   = Green;       //  [3]/8
extern color  mml_clr_4_8   = Blue;        //  [4]/8
extern color  mml_clr_5_8   = Green;       //  [5]/8
extern color  mml_clr_6_8   = Red;         //  [6]/8
extern color  mml_clr_7_8   = DarkOrange;      //  [7]/8
extern color  mml_clr_8_8   = DeepSkyBlue;        //  [8]/8
extern color  mml_clr_p_1_8 = Purple;       // [+1]/8
extern color  mml_clr_p_2_8 = Yellow;       // [+2]/8

extern int    mml_wdth_m_2_8 = 2;        // [-2]/8
extern int    mml_wdth_m_1_8 = 1;       // [-1]/8
extern int    mml_wdth_0_8   = 1;        //  [0]/8
extern int    mml_wdth_1_8   = 1;      //  [1]/8
extern int    mml_wdth_2_8   = 1;         //  [2]/8
extern int    mml_wdth_3_8   = 1;       //  [3]/8
extern int    mml_wdth_4_8   = 1;        //  [4]/8
extern int    mml_wdth_5_8   = 1;       //  [5]/8
extern int    mml_wdth_6_8   = 1;         //  [6]/8
extern int    mml_wdth_7_8   = 1;      //  [7]/8
extern int    mml_wdth_8_8   = 1;        //  [8]/8
extern int    mml_wdth_p_1_8 = 1;       // [+1]/8
extern int    mml_wdth_p_2_8 = 2;       // [+2]/8

extern color  MarkColor   = Blue;
extern int    MarkNumber  = 217;


double  dmml = 0,
        dvtl = 0,
        sum  = 0,
        v1 = 0,
        v2 = 0,
        mn = 0,
        mx = 0,
        x1 = 0,
        x2 = 0,
        x3 = 0,
        x4 = 0,
        x5 = 0,
        x6 = 0,
        y1 = 0,
        y2 = 0,
        y3 = 0,
        y4 = 0,
        y5 = 0,
        y6 = 0,
        octave = 0,
        fractal = 0,
        range   = 0,
        finalH  = 0,
        finalL  = 0,
        mml[13];

string  ln_txt[13],        
        buff_str = "";
        
int     
        bn_v1   = 0,
        bn_v2   = 0,
        OctLinesCnt = 13,
        mml_thk = 8,
        mml_clr[13],
        mml_wdth[13],
        mml_shft = 50,
        nTime = 0,
        CurPeriod = 0,
        nDigits = 0,
        i = 0;
int NewPeriod=0;
///////////////////////////////////////////////////////////////////////////////////////////

double         BandHigh, BandLow;//Hi-lo of the market's MM band
double         OctaveSize = 195;
int            Band;//Band the market is within
int            OpenTrades;
double         BasketUpl;//For hedging
bool           ForceTradeClosure, ForcePendingTradeDeletion;

//Trade ticket numbers etc
int            TradeTicketNo[5];//Will use 1 to 4
int            TicketNo;//Temp store for successful order-send ticket number
bool           BuyPending, SellPending;//Set to true if pendings are in place

//mm lines
//Store mm +2/8 and -2/8 to check for a redraw
double OldHigh, OldLow;


//Matt's O-R stuff
int 	         O_R_Setting_max_retries 	= 1000;
double 	      O_R_Setting_sleep_time 		= 4.0; /* seconds */
double 	      O_R_Setting_sleep_max 		= 15.0; /* seconds */

// ============================================================================================
// * Line 8/8 и 0/8 (Ultimate Support and Ultimate Resistance).
// * Those lines are the most strong concerning Support and esistance.
// ============================================================================================
//* Line 7/8  (Weak, Place to Stop and Reverse).
//* This line is weak. If suddenly the price was going too fast and too far and stops around this line 
//* it means the price will reverse down very soon. If the price did not stop near this line this price 
//* will continue the movement to the line 8/8.
// ============================================================================================
//* Line 1/8  (Weak, Place to Stop and Reverse).
//* This line is weak. If suddenly the price was going too fast and too far and stops around this line 
//* it means the price will reverse up very soon. If the price did not stop near this line this price
//* will continue the movement down to the line 0/8.
// ============================================================================================
//* Line 2/8 and 6/8 (Pivot, Reverse)
//* Those two lines yield the line 4/8 only to the strength to reverse the price movement.
// ============================================================================================
//* Line 5/8 (Top of Trading Range)
//* The price is spending the about 40% of the time on the movement between the lines 5/8 and 3/8. 
//* If the price is moving near line 5/8 and stopping near the line during the 10 - 12 days so it means 
//* that it is necessary to sell in this "bonus zone" (some people are doing like this) but if the price is keeping the tendency to stay above 
//* 5/8 line, so it means that the price will be above. But if the price is droping below 5/8 line it means that the price will continue 
//* falling to the next level of resistance.
// ============================================================================================
//* Line 3/8 (Bottom of Trading Range).
//* If the price is below this line and in uptrend it means that it will be very difficult for the price to break this level. 
//* If the price broke this line during the uptrend and staying above during the 10 12 days it means that the price will be above this line 
//* during the 40% of its time moving between this line and 5/8 line.
// ============================================================================================
//* Line 4/8 (Major Support/Resistance Line).
//* It is the major line concerning support and resistance. This leve is the better for the new sell or buy. 
//* It is the strong level of support of the price is above 4/8. It is the fine resistance line if the price is below this 4/8 line. 
//* сопротивления.
// ============================================================================================


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{

   double multiplier;
   if(Digits == 2 || Digits == 4) multiplier = 1;
   if(Digits == 3 || Digits == 5) multiplier = 10;
   if(Digits == 6) multiplier = 100;   
   if(Digits == 7) multiplier = 1000;   

   OctaveSize+= multiplier;
   BufferPips+= multiplier;
   TakeProfit+= multiplier;
   MMPeriod*= multiplier;

//---- indicators
   if(MMPeriod>0)
      NewPeriod   = P*MathCeil(MMPeriod/Period());
   else NewPeriod = P;
   
   
   ln_txt[0]  = "Extreme Overshoot  -2/8";// "Extreme overshoot [-2/8]";// [-2/8]
   ln_txt[1]  = "Overshoot  -1/8";// "Overshoot [-1/8]";// [-1/8]
   ln_txt[2]  = "Ultimate Support - Extremely Oversold  0/8";// "Ultimate Support - Extremely Oversold [0/8]";// [0/8]
   ln_txt[3]  = "Weak, Place to Stop and Reverse  1/8";// "Weak, Place to Stop and Reverse - [1/8]";// [1/8]
   ln_txt[4]  = "Strong, Pivot, Reverse  2/8";// "Strong, Pivot, Reverse [2/8]";// [2/8]
   ln_txt[5]  = "Bottom of Trading Range  3/8";// "Bottom of Trading Range - [3/8], if 10-12 bars then 40% Time. BUY Premium Zone";//[3/8]
   ln_txt[6]  = "Major Support/Resistance Pivotal Point  4/8";// "Major Support/Resistance Pivotal Point [4/8]- Best New BUY or SELL level";// [4/8]
   ln_txt[7]  = "Top of Trading Range  5/8";// "Top of Trading Range - [5/8], if 10-12 bars then 40% Time. SELL Premium Zone";//[5/8]
   ln_txt[8]  = "Strong, Pivot, Reverse  6/8";// "Strong, Pivot, Reverse [6/8]";// [6/8]
   ln_txt[9]  = "Weak, Place to Stop and Reverse  7/8";// "Weak, Place to Stop and Reverse - [7/8]";// [7/8]
   ln_txt[10] = "Ultimate Resistance - Extremely Overbought  8/8";// "Ultimate Resistance - Extremely Overbought [8/8]";// [8/8]
   ln_txt[11] = "Overshoot  +1/8";// "Overshoot [+1/8]";// [+1/8]
   ln_txt[12] = "Extreme Overshoot  +2/8";// "Extreme Overshoot [+2/8]";// [+2/8]

   //mml_shft = 3;
   mml_thk  = 3;

   // Начальная установка цветов уровней октав и толщины линий
   mml_clr[0]  = mml_clr_m_2_8;   mml_wdth[0] = mml_wdth_m_2_8; // [-2]/8
   mml_clr[1]  = mml_clr_m_1_8;   mml_wdth[1] = mml_wdth_m_1_8; // [-1]/8
   mml_clr[2]  = mml_clr_0_8;     mml_wdth[2] = mml_wdth_0_8;   //  [0]/8
   mml_clr[3]  = mml_clr_1_8;     mml_wdth[3] = mml_wdth_1_8;   //  [1]/8
   mml_clr[4]  = mml_clr_2_8;     mml_wdth[4] = mml_wdth_2_8;   //  [2]/8
   mml_clr[5]  = mml_clr_3_8;     mml_wdth[5] = mml_wdth_3_8;   //  [3]/8
   mml_clr[6]  = mml_clr_4_8;     mml_wdth[6] = mml_wdth_4_8;   //  [4]/8
   mml_clr[7]  = mml_clr_5_8;     mml_wdth[7] = mml_wdth_5_8;   //  [5]/8
   mml_clr[8]  = mml_clr_6_8;     mml_wdth[8] = mml_wdth_6_8;   //  [6]/8
   mml_clr[9]  = mml_clr_7_8;     mml_wdth[9] = mml_wdth_7_8;   //  [7]/8
   mml_clr[10] = mml_clr_8_8;     mml_wdth[10]= mml_wdth_8_8;   //  [8]/8
   mml_clr[11] = mml_clr_p_1_8;   mml_wdth[11]= mml_wdth_p_1_8; // [+1]/8
   mml_clr[12] = mml_clr_p_2_8;   mml_wdth[12]= mml_wdth_p_2_8; // [+2]/8
   
   //Store mm +2/8 and -2/8 to check for a redraw
   OldHigh = ObjectGet("mml12", OBJPROP_PRICE1);
   OldLow = ObjectGet("mml0", OBJPROP_PRICE1);

   //start();
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment(" ");   
   for(i=0;i<OctLinesCnt;i++) 
   {
       buff_str = "mml"+i;
       ObjectDelete(buff_str);
       buff_str = "mml"+i+".5";
       ObjectDelete(buff_str);
       buff_str = "mml_txt"+i;
       ObjectDelete(buff_str);
       buff_str = "MML_LatestCulcBar";
       ObjectDelete(buff_str);
   }//for(i=0;i<OctLinesCnt;i++) 
   
//----
   return(0);
}

void DrawLines()
{   
   //Store mm +2/8 and -2/8 to check for a redraw
   OldHigh = ObjectGet("mml12", OBJPROP_PRICE1);
   OldLow = ObjectGet("mml0", OBJPROP_PRICE1);

   if( (nTime != Time[0]) || (CurPeriod != Period()) ) 
   {
   
     //price
      bn_v1 = Lowest(NULL,0,MODE_LOW,NewPeriod+StepBack,StepBack);
      bn_v2 = Highest(NULL,0,MODE_HIGH,NewPeriod+StepBack,StepBack);

      v1 = Low[bn_v1];
      v2 = High[bn_v2];

   //determine fractal.....
      if( v2<=250000 && v2>25000 )
      fractal=100000;
      else
        if( v2<=25000 && v2>2500 )
        fractal=10000;
        else
          if( v2<=2500 && v2>250 )
          fractal=1000;
          else
            if( v2<=250 && v2>25 )
            fractal=100;
            else
              if( v2<=25 && v2>12.5 )
              fractal=12.5;
              else
                if( v2<=12.5 && v2>6.25)
                fractal=12.5;
                else
                  if( v2<=6.25 && v2>3.125 )
                  fractal=6.25;
                  else
                    if( v2<=3.125 && v2>1.5625 )
                    fractal=3.125;
                    else
                      if( v2<=1.5625 && v2>0.390625 )
                      fractal=1.5625;
                      else
                        if( v2<=0.390625 && v2>0)
                        fractal=0.1953125;
      
      range=(v2-v1);
      sum=MathFloor(MathLog(fractal/range)/MathLog(2));
      octave=fractal*(MathPow(0.5,sum));
      mn=MathFloor(v1/octave)*octave;
      if( (mn+octave)>v2 )
      mx=mn+octave; 
      else
        mx=mn+(2*octave);


   // calculating xx
   //x2
       if( (v1>=(3*(mx-mn)/16+mn)) && (v2<=(9*(mx-mn)/16+mn)) )
       x2=mn+(mx-mn)/2; 
       else x2=0;
   //x1
       if( (v1>=(mn-(mx-mn)/8))&& (v2<=(5*(mx-mn)/8+mn)) && (x2==0) )
       x1=mn+(mx-mn)/2; 
       else x1=0;

   //x4
       if( (v1>=(mn+7*(mx-mn)/16))&& (v2<=(13*(mx-mn)/16+mn)) )
       x4=mn+3*(mx-mn)/4; 
       else x4=0;

   //x5
       if( (v1>=(mn+3*(mx-mn)/8))&& (v2<=(9*(mx-mn)/8+mn))&& (x4==0) )
       x5=mx; 
       else  x5=0;

   //x3
       if( (v1>=(mn+(mx-mn)/8))&& (v2<=(7*(mx-mn)/8+mn))&& (x1==0) && (x2==0) && (x4==0) && (x5==0) )
       x3=mn+3*(mx-mn)/4; 
       else x3=0;

   //x6
       if( (x1+x2+x3+x4+x5) ==0 )
       x6=mx; 
       else x6=0;

        finalH = x1+x2+x3+x4+x5+x6;
   // calculating yy
   //y1
       if( x1>0 )
       y1=mn; 
       else y1=0;

   //y2
       if( x2>0 )
       y2=mn+(mx-mn)/4; 
       else y2=0;

   //y3
       if( x3>0 )
       y3=mn+(mx-mn)/4; 
       else y3=0;

   //y4
       if( x4>0 )
       y4=mn+(mx-mn)/2; 
       else y4=0;

   //y5
       if( x5>0 )
       y5=mn+(mx-mn)/2; 
       else y5=0;

   //y6
       if( (finalH>0) && ((y1+y2+y3+y4+y5)==0) )
       y6=mn; 
       else y6=0;

       finalL = y1+y2+y3+y4+y5+y6;

       for( i=0; i<OctLinesCnt; i++) {
            mml[i] = 0;
            }
         
      dmml = (finalH-finalL)/8;

      mml[0] =(finalL-dmml*2); //-2/8
      for( i=1; i<OctLinesCnt; i++) {
           mml[i] = mml[i-1] + dmml;
           }
      for( i=0; i<OctLinesCnt; i++ )
      {
           //Draw the line
           buff_str = "mml"+i;
           if(ObjectFind(buff_str) == -1) 
           {
               ObjectCreate(buff_str, OBJ_HLINE , 0,Time[0], mml[i]);
               ObjectSet(buff_str, OBJPROP_STYLE, STYLE_SOLID);
               ObjectSet(buff_str, OBJPROP_COLOR, mml_clr[i]);
               ObjectSet(buff_str, OBJPROP_WIDTH, mml_wdth[i]);
               ObjectMove(buff_str, 0, Time[0],  mml[i]);
           }//if(ObjectFind(buff_str) == -1) 
           else 
           {
               ObjectMove(buff_str, 0, Time[0],  mml[i]);
           }//else
             
           //Draw the label
           buff_str = "mml_txt"+i;
           if(ObjectFind(buff_str) == -1) 
           {
               ObjectCreate(buff_str, OBJ_TEXT, 0, Time[mml_shft], mml_shft);
               ObjectSetText(buff_str, ln_txt[i], 10, "Arial", mml_clr[i]);
               ObjectMove(buff_str, 0, Time[mml_shft],  mml[i]);
           }//if(ObjectFind(buff_str) == -1) 
           else 
           {
               ObjectMove(buff_str, 0, Time[mml_shft],  mml[i]);
           }//else
        
            //Draw the half-way point line        
            buff_str = "mml"+i + ".5";
            if(ObjectFind(buff_str) == -1) 
            {
                ObjectCreate(buff_str, OBJ_HLINE , 0,Time[0], NormalizeDouble((mml[i-1] + mml[i]) / 2, Digits));
                ObjectSet(buff_str, OBJPROP_STYLE, STYLE_DOT);
                ObjectSet(buff_str, OBJPROP_COLOR, mml_clr[i]);
                ObjectSet(buff_str, OBJPROP_WIDTH, 1);
                ObjectMove(buff_str, 0, Time[0],  NormalizeDouble((mml[i-1] + mml[i]) / 2, Digits));
            }//if(ObjectFind(buff_str) == -1) 
            else 
            {
                ObjectMove(buff_str, 0, Time[0],  NormalizeDouble((mml[i] + mml[i-1]) / 2, Digits));
            }//else
     
       } // for( i=1; i<=OctLinesCnt; i++ ){

      nTime    = Time[0];
      CurPeriod= Period();
   
      string buff_str = "MML_LatestCulcBar";
      if(ObjectFind(buff_str) == -1) {
         ObjectCreate(buff_str, OBJ_ARROW,0, Time[StepBack], Low[StepBack]-2*Point );
         ObjectSet(buff_str, OBJPROP_ARROWCODE, MarkNumber);
         ObjectSet(buff_str, OBJPROP_COLOR, MarkColor);
         }
      else {
         ObjectMove(buff_str, 0, Time[StepBack], Low[StepBack]-2*Point );
         }

   }//if( (nTime != Time[0]) || (CurPeriod != Period()) ) 

   //Check to see if a redraw has occurred
   double high = ObjectGet("mml12", OBJPROP_PRICE1);
   double low = ObjectGet("mml0", OBJPROP_PRICE1);
   
   if ((OldHigh != high || OldLow != low) && OpenTrades > 0)
   {
      DeletePendingTrades();
   }//if (OldHigh != high || OldLow != low)
   
   

}//End void DrawLines()



void GetCurrentMMlPosition()
{

   //Defaults for in case the market is outside MM
   BandHigh = NormalizeDouble(mml[12] + (OctaveSize * Point), Digits);
   BandLow = NormalizeDouble(mml[0] - (OctaveSize * Point), Digits);
   
   Band = 0;
   
   //Calculates the hi-lo of the current band
   RefreshRates();
   for (int cc = 0; cc <= ArraySize(mml); cc++)
   {  
      if (Bid >= mml[cc] && Bid <= mml[cc + 1] )
      {
         BandHigh = mml[cc + 1];
         BandLow = mml[cc];
         Band++;
         break;
      }//if (Bid >= mml[cc] && Bid <= mml[cc + 1] )
      Band++;
   }//for (int cc = 0; cc <= ArraySize(mml); cc++)
   

}//void GetCurrentMMlPosition()

bool DoesTradeExist(double lot)
{
   //-1 is passed as the lot size to force a general find-any
   
   if (OrdersTotal() == 0) return(false);
   
   for (int cc = 0; cc <= OrdersTotal() - 1; cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      if (OrderCloseTime() > 0) continue;
      //-1 is passed as the lot size to force a general find-any   
      if (OrderSymbol() == Symbol() && (OrderLots() == lot || lot == -1)) return(true);   
   }//for (int cc = 0; cc <= OrdersTotal() - 1; cc++)
   
   return(false);
   
}//bool DoesTradeExist(double lot)


void DeletePendingTrades()
{
   ForcePendingTradeDeletion = false;
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() != Symbol() ) continue;
      //if (OrderType() != OP_BUYLIMIT && OrderType() != OP_SELLLIMIT) continue;
      int tn = OrderTicket();
      while(IsTradeContextBusy()) Sleep(100);
      if ((OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLLIMIT) && OrderCloseTime() == 0) 
      {
         bool result = OrderDelete(tn);      
         if (result) cc++;
         if (!result) ForcePendingTradeDeletion = true;//Force a retry at the next tick
      }//if (OrderType() == OP_BUYLIMIT || OrderType() == OP_SELLLIMIT) 
      
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)

}//End void DeletePendingTrades()



void LookForTradingOpportunities()
{
   
   if (Band > 3 && Band < 9) return;
   double take, stop, price, lotsize;
   int type;
   bool SendTrade;
   double target;
   //double stoplevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
   
   
   //Long opportunities
   //Swap filter
   //double LongSwap = MarketInfo(Symbol(), MODE_SWAPLONG);
   //double ShortSwap = MarketInfo(Symbol(), MODE_SWAPSHORT);
   bool SwapOk = true;//Leave for now just in case
   //if (TradePositiveSwapOnly && LongSwap < 0) SwapOk = false;
   target = ObjectGet("mml4.5", OBJPROP_PRICE1);
   //The first band needs a buffer to prevent pendings being placed then deleted in rapid succession, as the market 
   //ticks into the band, then straight out again
   target = NormalizeDouble(target - (BufferPips * Point), Digits);
   if (Band == 4 && Bid <= target && SwapOk && TradeLong)
   {
      if (!DoesTradeExist(Lot1) )
      {
         take = NormalizeDouble(mml[3] + (TakeProfit * Point), Digits);
         type = OP_BUYLIMIT;
         price = NormalizeDouble(mml[3], Digits);
         SendTrade = true;
         lotsize = Lot1;         
      }//if (!DoesTradeExist(Lot1) )
      
   }//if (Band == 3 && Bid < mml[3] + (BufferPips * Point))
   

   target = ObjectGet("mml3.5", OBJPROP_PRICE1);
   if (Band == 3 && Bid >= target && SwapOk && TradeLong)
   {
      if (!DoesTradeExist(Lot2) )
      {
         take = NormalizeDouble(mml[2] + (TakeProfit * Point), Digits);
         type = OP_BUYLIMIT;
         price = NormalizeDouble(mml[2], Digits);
         SendTrade = true;
         lotsize = Lot2;
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 3 && Bid < mml[3] + (BufferPips * Point))
   
   target = ObjectGet("mml2.5", OBJPROP_PRICE1);
   if (Band == 2 && Bid >= target && SwapOk && TradeLong)
   {
      if (!DoesTradeExist(Lot3) )
      {
         take = NormalizeDouble(mml[1] + (TakeProfit * Point), Digits);
         type = OP_BUYLIMIT;
         price = NormalizeDouble(mml[1], Digits);
         SendTrade = true;
         lotsize = Lot3;
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 3 && Bid < mml[3] + (BufferPips * Point))
      
   target = ObjectGet("mml1.5", OBJPROP_PRICE1);
   if (Band == 1 && Bid >= target && SwapOk && TradeLong)
   {
      if (!DoesTradeExist(Lot4) )
      {
         take = NormalizeDouble(mml[0] + (TakeProfit * Point), Digits);
         type = OP_BUYLIMIT;
         price = NormalizeDouble(mml[0], Digits);
         SendTrade = true;
         lotsize = Lot4;
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 1 && Bid >= target && SwapOk && TradeLong)
   

   //Short opportunities
   target = ObjectGet("mml9.5", OBJPROP_PRICE1);
   //The first band needs a buffer to prevent pendings being placed then deleted in rapid succession, as the market 
   //ticks into the band, then straight out again
   target = NormalizeDouble(target + (BufferPips * Point), Digits);
   //SwapOk = true;
   //if (TradePositiveSwapOnly && ShortSwap < 0) SwapOk = false;
   if (Band == 9 && Bid >= target && SwapOk && TradeShort)
   {
      if (!DoesTradeExist(Lot1) )
      {
         take = NormalizeDouble(mml[9] - (TakeProfit * Point), Digits);
         type = OP_SELLLIMIT;
         price = NormalizeDouble(mml[9], Digits);
         SendTrade = true;
         lotsize = Lot1;
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 3 && Bid < mml[3] + (BufferPips * Point))
   
   target = ObjectGet("mml10.5", OBJPROP_PRICE1);
   if (Band == 10 && Bid <= target && SwapOk && TradeShort)
   {
      if (!DoesTradeExist(Lot2) )
      {
         take = NormalizeDouble(mml[10] - (TakeProfit * Point), Digits);
         type = OP_SELLLIMIT;
         price = NormalizeDouble(mml[10], Digits);
         SendTrade = true;
         lotsize = Lot2;
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 3 && Bid < mml[3] + (BufferPips * Point))
   
   target = ObjectGet("mml11.5", OBJPROP_PRICE1);
   if (Band == 11 && Bid <= target && SwapOk && TradeShort)
   {
      if (!DoesTradeExist(Lot3) )
      {
         take = NormalizeDouble(mml[11] - (TakeProfit * Point), Digits);
         type = OP_SELLLIMIT;
         price = NormalizeDouble(mml[11], Digits);
         SendTrade = true;
         lotsize = Lot3;
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 3 && Bid < mml[3] + (BufferPips * Point))
   
   target = ObjectGet("mml12.5", OBJPROP_PRICE1);
   if (Band == 12 && Bid <= target && SwapOk && TradeShort)
   {
      if (!DoesTradeExist(Lot4) )
      {
         take = NormalizeDouble(mml[12] - (TakeProfit * Point), Digits);
         type = OP_SELLLIMIT;
         price = NormalizeDouble(mml[12], Digits);
         SendTrade = true;
         lotsize = Lot4;
      }//if (!DoesTradeExist(Lot4) )
   }//if (Band == 12 && Bid <= target && SwapOk && TradeShort)
   
   if (SendTrade)
   {
      //Neutralise the tp if necessary   
      if (TakeProfit == 0) bool result = SendSingleTrade(type, " ", lotsize, price, 0, take);
      else result = SendSingleTrade(type, " ", lotsize, price, 0, 0);      
      //Alert("Band: ", Band, " Lot: ", lotsize, " Price: ", price, " mml ", mml[Band]);
      //int x = 1;
      //while (x == 1) Sleep(100);
      if (result) 
      {
         ForceTradeClosure = false;//Thrashing around a bit here
         OrderSelect(TicketNo, SELECT_BY_TICKET);
         if (type == OP_BUYLIMIT)
         {
            if (OrderLots() == Lot1) TradeTicketNo[1] = TicketNo;
            if (OrderLots() == Lot2) TradeTicketNo[2] = TicketNo;
            if (OrderLots() == Lot3) TradeTicketNo[3] = TicketNo;            
         }//if (type == OP_BUYLIMIT)
         
         if (type == OP_SELLLIMIT)
         {
            if (OrderLots() == Lot1) TradeTicketNo[1] = TicketNo;
            if (OrderLots() == Lot2) TradeTicketNo[2] = TicketNo;
            if (OrderLots() == Lot3) TradeTicketNo[3] = TicketNo;            
         }//if (type == OP_SELLLIMIT)
         
         
      }//if (result) 
      
   }//if (SendTrade)
   
   
}//LookForTradingOpportunities()

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_BUYLIMIT) 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);
   
   
   //Is a 2 stage criminal
   if (CriminalIsECN)
   {
      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)

//=============================================================================
//                           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 CountOpenTrades()
{
  
   OpenTrades = 0;
   BasketUpl = 0;
   ArrayInitialize(TradeTicketNo, -1);
   BuyPending = false;
   SellPending = false;
   double target;
   
   if (OrdersTotal() == 0) return;

  
   
      
   int ot = OrdersTotal() - 1;
   
   for (int cc = 0; cc <= ot; cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      
      if (OrderSymbol() == Symbol())
      {
         BasketUpl+= (OrderProfit() + OrderSwap() + OrderCommission());
      
         if (OrderType() == OP_BUYLIMIT) BuyPending = true;
         if (OrderType() == OP_SELLLIMIT) SellPending = true;
         //Set up ticket numbers
         if (OrderLots() == Lot1) TradeTicketNo[1] = OrderTicket();
         if (OrderLots() == Lot2) TradeTicketNo[2] = OrderTicket();
         if (OrderLots() == Lot3) TradeTicketNo[3] = OrderTicket();            
         if (OrderLots() == Lot4) TradeTicketNo[4] = OrderTicket();            
             
         OpenTrades++;
      }//if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
      
   
   }//for (int cc = OrdersTotal() - 1; cc <= 0; cc--)
   

   
 

}//End void CountOpenTrades()


void CloseAllTrades()
{
   ForceTradeClosure = 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 (OrderType() != OP_BUY && OrderType() != OP_SELL) continue;
      if (OrderSymbol() == Symbol() )
      {
         while(IsTradeContextBusy()) Sleep(100);
         bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, Blue);
         if (result) cc++;
         if (!result) ForceTradeClosure = true;
      }//if (OrderSymbol() == Symbol() )
   
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)


}//End void CloseAllTrades()

void TradeDirectionBySwap()
{

   //Sets TradeLong & TradeShort according to the positive/negative swap it attracts

   double LongSwap = MarketInfo(Symbol(), MODE_SWAPLONG);
   double ShortSwap = MarketInfo(Symbol(), MODE_SWAPSHORT);
   

   if (CadPairsPositiveOnly)
   {
      if (StringSubstr(Symbol(), 0, 3) == "CAD" || StringSubstr(Symbol(), 0, 3) == "cad" || StringSubstr(Symbol(), 3, 3) == "CAD" || StringSubstr(Symbol(), 3, 3) == "cad" )      
      {
         if (LongSwap > 0) TradeLong = true;
         else TradeLong = false;
         if (ShortSwap > 0) TradeShort = true;
         else TradeShort = false;         
      }//if (StringSubstr(Symbol(), 0, 3) == "CAD" || StringSubstr(Symbol(), 0, 3) == "cad" )      
   }//if (CadPairsPositiveOnly)
   
   if (AudPairsPositiveOnly)
   {
      if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" )      
      {
         if (LongSwap > 0) TradeLong = true;
         else TradeLong = false;
         if (ShortSwap > 0) TradeShort = true;
         else TradeShort = false;         
      }//if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" )      
   }//if (AudPairsPositiveOnly)
   
   
   if (NzdPairsPositiveOnly)
   {
      if (StringSubstr(Symbol(), 0, 3) == "NZD" || StringSubstr(Symbol(), 0, 3) == "nzd" || StringSubstr(Symbol(), 3, 3) == "NZD" || StringSubstr(Symbol(), 3, 3) == "nzd" )      
      {
         if (LongSwap > 0) TradeLong = true;
         else TradeLong = false;
         if (ShortSwap > 0) TradeShort = true;
         else TradeShort = false;         
      }//if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" )      
   }//if (AudPairsPositiveOnly)
   
   

}//void TradeDirectionBySwap()


bool ShouldPositionClose()
{
   //Returns true if position should close, else returns false

   double target;
   RefreshRates();
   
   //Long trades
   if (Band == 4)
   {
      if (OrderSelect(TradeTicketNo[1], SELECT_BY_TICKET) > -1 && OrderType() == OP_BUY && OrderProfit() > 0)
      {
         target = ObjectGet("mml4.5", OBJPROP_PRICE1);
         if (Ask >= target) return(true);
      }//if (!DoesTradeExist(Lot1) )      
   }//if (Band == 4)
   

   if (Band == 3)
   {
      if (OrderSelect(TradeTicketNo[2], SELECT_BY_TICKET) > -1 && OrderType() == OP_BUY && OrderProfit() > 0)
      {
         target = ObjectGet("mml3.5", OBJPROP_PRICE1);
         if (Ask >= target) return(true);
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 3)
   
   if (Band == 2)
   {
      if (OrderSelect(TradeTicketNo[3], SELECT_BY_TICKET) > -1 && OrderType() == OP_BUY && OrderProfit() > 0)
      {
         target = ObjectGet("mml2.5", OBJPROP_PRICE1);
         if (Ask >= target) return(true);
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 2)
   
   if (Band == 1)
   {
      if (OrderSelect(TradeTicketNo[4], SELECT_BY_TICKET) > -1 && OrderType() == OP_BUY && OrderProfit() > 0)
      {
         target = ObjectGet("mml1.5", OBJPROP_PRICE1);
         if (Ask >= target) return(true);
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 1)
   

   //Short trades
   if (Band == 9)
   {
      if (OrderSelect(TradeTicketNo[1], SELECT_BY_TICKET) > -1 && OrderType() == OP_SELL && OrderProfit() > 0)
      {
         target = ObjectGet("mml9.5", OBJPROP_PRICE1);
         if (Bid <= target) return(true);
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 9)
   
   if (Band == 10)
   {
      if (OrderSelect(TradeTicketNo[2], SELECT_BY_TICKET) > -1 && OrderType() == OP_SELL && OrderProfit() > 0)
      {
         target = ObjectGet("mml10.5", OBJPROP_PRICE1);
         if (Bid <= target) return(true);
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 10)
   
   if (Band == 11)
   {
      if (OrderSelect(TradeTicketNo[3], SELECT_BY_TICKET) > -1 && OrderType() == OP_SELL && OrderProfit() > 0)
      {
         target = ObjectGet("mml11.5", OBJPROP_PRICE1);
         if (Bid <= target) return(true);
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 11)

   if (Band == 12)
   {
      if (OrderSelect(TradeTicketNo[4], SELECT_BY_TICKET) > -1 && OrderType() == OP_SELL && OrderProfit() > 0)
      {
         target = ObjectGet("mml12.5", OBJPROP_PRICE1);
         if (Bid <= target) return(true);
      }//if (!DoesTradeExist(Lot1) )
   }//if (Band == 12)

   if (Band > 5 && Band < 9 && BasketUpl > 0) return(true);

   //Got this far, so position should remain open
   return(false);

}//End bool ShouldPositionClose()


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{

   //Deal with a trade closure failnre
   if (ForceTradeClosure)
   {
      CloseAllTrades();
      return;
   }//if (ForceTradeClosure)
   
   if (ForcePendingTradeDeletion)
   {
      DeletePendingTrades();
      return;
   }//if (ForcePendingTradeDeletion)
   
   CountOpenTrades();
   if (OpenTrades == 0)
   {
      ForceTradeClosure = false;
      ForcePendingTradeDeletion = false;
   }//if (OpenTrades == 0)
      
   DrawLines();//Also set up mml[] array values
   
   GetCurrentMMlPosition();
 
   CountOpenTrades();
   if (OpenTrades == 0)
   {
      ForceTradeClosure = false;
   }//if (OpenTrades == 0)
   
      
   //Position closure 
   if (OpenTrades > 0 && BasketUpl > 0)
   {
      if (ShouldPositionClose())
      {
         CloseAllTrades();
         return;
      }//if (ShouldPositionClose() )
      
   }//if (OPenTrades > 0 && OPenTrades < 4)
   
   //Delete pending trades if market has moved into the non=trading bands
   if (Band > 4 && Band < 9 && (BuyPending || SellPending) )
   {
      DeletePendingTrades();   
   }//if (Band > 4 && Band < 9 && (PendingBuy || PendingSell)
   
   
  
      //Available margin filters
   if (UseScoobsMarginCheck && OpenTrades > 0)
   {
      if(AccountMargin() > (AccountFreeMargin()/100)) 
      {
         Comment("                                     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("                                     There is insufficient margin percent to allow trading. " + DoubleToStr(ml, 2) + "%");
         return;
      }//if (ml < FkMinimumMarginPercent)
      
   }//if (UseForexKiwi && AccountMargin() > 0)

   //Swap filter
   TradeDirectionBySwap();
   
   LookForTradingOpportunities();
   
   
      string gap = "                                ";
   string ScreenMessage;
   
   ScreenMessage = StringConcatenate(gap, TimeToStr(TimeLocal(), TIME_DATE|TIME_MINUTES|TIME_SECONDS), NL,
                                     gap, "Band high: ", DoubleToStr(BandHigh, Digits), NL,
                                     gap, "Band low: ", DoubleToStr(BandLow, Digits), NL,
                                     gap, "Band no: ", Band, NL);
   


   Comment(ScreenMessage);

}
//+------------------------------------------------------------------+