//+-------------------------------------------------------------------+
//|                                                        Bbands_EA  |
//|                           Copyright © 2011, Steve Hopwood - LHDT  |
//+-------------------------------------------------------------------+

/*
V1.0046  - Fixed a bug when lauching the EA for the first time (EA took position directly, sometimes too late)
         - Removed the trigger on lower timeframe (V1.0045)
         - Changed default settings to reduce DD and stay in profits :
            - ECN to false
            - AllowMultipleTrendTrade to false 
            - BreakEvenPips to 10pips 
            - BreakEvenProfit to 3
            - JumpingStop to true
            - JumpingStopPips to 10pips
V1.0045  - Added trigger on lower TF when all conditions are met
V1.0044  - First version ! Hiaaa !
*/

#property copyright "Copyright © 2011, Steve Hopwood, LhDT"
#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  both "Both"
#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  red "Red"
#define  blue "Blue"

//Pending trade price line
#define  pendingpriceline "Pending price line"
//Hidden sl and tp lines. If UseStealth enabled, the bot will close trades on a touch/break of these lines.
//Each line is named with its appropriate prefix and the ticket number of the relevant trade
#define  TpPrefix "Tp"
#define  SlPrefix "Sl"


//Caterpillar
#define  buyline "Buy line"
#define  sellline "Sell line"

//Defined constants from hanover. Thanks David
#define AUD 0
#define CAD 1
#define CHF 2
#define EUR 3
#define GBP 4
#define JPY 5
#define NZD 6
#define USD 7

#define M1  0
#define M5  1
#define M15 2
#define M30 3
#define H1  4
#define H4  5
#define D1  6
#define W1  7
#define MN  8

extern string  Symp1 = "----Bbands Inputs----";
extern bool    ARS                        = true;
extern int     BarCheck                   = 1;
extern bool    TakeScreenShot             = true;
bool           Open_candleClose           = true;
bool           Close_candleClose          = true;
extern bool    AllowMultipleTrendTrade    = false;

extern string  exc = "----Bbands Values----";
extern int     Length               = 20;
extern int     Deviation            = 0;
extern double  MoneyRisk       = 1.0;


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=2872811;
extern string  TradeComment="Bbands EA";
extern bool    CriminalIsECN=false;
extern double  MaxSpread=120;

//Hidden tp/sl inputs.
extern string  hts="----Stealth stop loss and take profit inputs----";
extern int     HiddenPips=10;//Added to the 'hard' sl and tp and used for closure calculations

extern string  bf="----Trading balance filters----";
extern bool    UseZeljko=false;
extern bool    OnlyTradeCurrencyTwice=false;

extern string  bbi="----Bollinger Band inputs----";
extern int     BbPeriod=25;
extern int     BbDeviation=2;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         BbUpper, BbMiddle, BbLower, BbExtent;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  rsiin="----Rsi inputs----";
extern int     RsiTf=1440;
extern int     RsiPeriod=20;
extern string  rsap="Applied price: 0=Close; 1=Open; 2=High";
extern string  rsap1="3=Low; 4=Median; 5=Typical; 6=Weighted";
extern int     RsiAppliedPrice=0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         RsiVal;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  mai="----Moving average----";
extern int     MaTF=0;//Time frame defaults to current chart 
extern int     MaPeriod=50;
extern int     MaShift=0;//The MA Shift input
extern string  mame="Method: 0=sma; 1=ema; 2=smma;  3=lwma";
extern int     MaMethod=1;
extern string  maap="Applied price: 0=Close; 1=Open; 2=High";
extern string  maap1="3=Low; 4=Median; 5=Typical; 6=Weighted";
extern int     MaAppliedPrice=0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         MaVal;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  vs="----Volatility inputs----";
extern int     LookBackDays=20;
extern int     LowVolatility=100;
extern int     MediumVolatility=150;
extern int     HighVolatility=200;
extern int     PsychoticallyDeranged=250;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         Volatility;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  cat="----Caterpillar trend trade entry and TS----";
extern bool    UseCaterpillar=false;
extern int     MaxTrades=5;
extern int     MinPipsBetweenCandles=5;//Min distance between trade open prices
extern int     CatTimeFrame=60;//Trading/updating tf can be independent of current chart
extern color   BuyLineColour=Green;
extern color   SellLineColour=Red;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int            OldCatBars;
int            OnePip=1;//For adding to sl, candle close etc
bool           CandleTraded;//Only one trade per candle
string         CsGvName;
int            OldH1Bars;//For orphan gv removal
bool           TradeOpen;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  tdm="----Trend detection module----";
extern bool    RisingTrend=false;
extern bool    FallingTrend=false;
extern bool    UseTrendDetection=true;


//RSI. >55 is trending up. < 45 is trending down
extern string  trsi="Rsi trend detection";
extern bool    UseRsiTrendDetection=true;
extern int     RsiTdTf=5;
extern int     RsiTdPeriod=8;
extern string  trs="Applied price: 0=Close; 1=Open; 2=High";
extern string  trs1="3=Low; 4=Median; 5=Typical; 6=Weighted";
extern int     RsiTdAppliedPrice=0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         TrendRsiVal;//Rsi
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//NB V10. D1 candle hi-lo above both ma's: trend is up. Below both: trend is down. In between: market is ranging.
//Also makes an excellent trade trigger in a longer-term trend trading system.
extern string  nbmas="NB V10";
extern bool    UseNanningBobForTrend=false;
extern bool    UseNanningBobForTrigger=false;
extern int     FastNbTdTF=1440;//Time frame defaults to D1 chart 
extern int     FastNbTdPeriod=2;
extern int     FastNbTdShift=2;//The MA Shift input
extern string  nbmame="Method: 0=sma; 1=ema; 2=smma;  3=lwma";
extern int     FastNbTdMethod=2;
extern string  nbmaap="Applied price: 0=Close; 1=Open; 2=High";
extern string  nbmaap1="3=Low; 4=Median; 5=Typical; 6=Weighted";
extern int     FastNbTdAppliedPrice=4;
extern int     SlowNbTdTF=1440;//Time frame defaults to D1 chart 
extern int     SlowNbTdPeriod=8;
extern int     SlowNbTdMethod=2;
extern int     SlowNbTdShift=2;
extern int     SlowNbTdAppliedPrice=4;
extern int     TrendConfirmationCandleTF=15;//Candle for confirming the trend as a trade trigger
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         FastNbTrendMaVal, SlowNbTrendMaVal;//2 MA trend
string         TrendConfirmationCandleDir;//Holds 'up' for an up candle and vice versa
string         TradeTriggerDirection;//For using V10 as a trigger instead of a trend
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Fast ma > slow, trend is up & vice versa
extern string  tmas="Two MA - 'slowkey'";
extern bool    UseSlowkey=false;
extern int     FastMaTdTF=0;//Time frame defaults to current chart 
extern int     FastMaTdPeriod=100;
extern int     FastMaTdShift=0;//The MA Shift input
extern string  tmame="Method: 0=sma; 1=ema; 2=smma;  3=lwma";
extern int     FastMaTdMethod=0;
extern string  tmaap="Applied price: 0=Close; 1=Open; 2=High";
extern string  tmaap1="3=Low; 4=Median; 5=Typical; 6=Weighted";
extern int     FastMaTdAppliedPrice=0;
extern int     SlowMaTdTF=0;//Time frame defaults to current chart 
extern int     SlowMaTdPeriod=200;
extern int     SlowMaTdShift=0;
extern int     SlowMaTdMethod=0;
extern int     SlowMaTdAppliedPrice=0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         FastTrendMaVal, SlowTrendMaVal;//2 MA trend
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Single, much longer term MA. Rising MA the trend is up and vice-versa
extern string  aal="----All averages inputs----";
extern bool    UseAA=false;
extern int     TimeFrame    =  1440;
extern int     Price        =  0;
extern int     MA_Period    = 50;
extern int     MA_Shift     =  0;
extern int     MA_Method    =  0;
extern int     CandleShift  =  0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         AaVal, AaUp, AaDown;//Buffers 0 (val) 1 (up) and 3 (down)
string         AaDirection;
bool           CloseOnOppositeSignal;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  hm="----Hanover module----";
extern bool    UseHanover=false;
extern string  ctf="Time frames";
//extern string  TimeFrames="M1,M5,M15,M30,H1,H4,D1,W1,MN";
extern string  TimeFrames="D1";
extern int     SlopeConfirmationCandles=0;
extern int     StrongThreshold=0;
extern int     WeakThreshold=0;
extern string  hof="Hanover output file";
extern string  OutputFile            = "Output---Recent Strength.CSV";
extern int     NumPoints=15;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Arrays etc
string         InputString;//All purpose string to pass to CleanUpInputString() to remove unwanted leading/trailing stuff
int            NoOfTimeFrames;//The number for timeframes inputted into the TimeFrames input
string         Tf[];//Holds the time frames inputted into the TimeFrames input
string         StrongWeak[];//Holds the pair that represents the strongest and weakest in each time frame
string         StrongestCcy[], WeakestCcy[];//Go on, take a guess
double         StrongVal[], PrevStrongVal[], WeakVal[], PrevWeakVal[];//Another guess?
string         ConstructedPair[];//Holds the pairs made out of the currencies
string         Ccy1, Ccy2;//First and second currency in the pair

//Variables copied from the Strength Alerts indi. int LoadRSvalues() came from this
int      dig, tmf, h, i, j, k;
string alrt[11];
double   RSvalue[8,9,99];   // [currency,timeframe,datapoint#]
                            // currency: 0=AUD, 1=CAD, 2=CHF, 3=EUR, 4=GBP, 5=JPY, 6=NZD, 7=USD
                            // timeframe: 0=M1, 1=M5, 2=M15, 3=M30, 4=H1, 5=H4, 6=D1, 7=W1, 8=MN
                         
string   ccy[8] = {"AUD","CAD","CHF","EUR","GBP","JPY","NZD","USD"};
string   tf[9]  = {"M1","M5","M15","M30","H1","H4","D1","W1","MN"};
string   arr[11];

int      ReadBars;//Bot reads the output file when this != Bars   
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  amc="----Available Margin checks----";
extern string  sco="Scoobs";
extern bool    UseScoobsMarginCheck=false;
extern string  fk="ForexKiwi";
extern bool    UseForexKiwi=false;
extern int     FkMinimumMarginPercent=1500;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool           EnoughMargin;
string         MarginMessage;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  rec="----Recovery----";
extern bool    UseRecovery=false;
extern int     Start_Recovery_at_trades=2;  //DC
extern bool    Use1.1.3.3Recovery=false;
extern bool    Use1.1.2.4Recovery=false;
extern bool    Use1.2.6Recovery=true;//Pippo's idea
extern int     ReEntryLinePips=50;
extern color   ReEntryLineColour=Turquoise;
extern color   BreakEvenLineColour=Blue;
extern int     RecoveryBreakEvenProfitPips=20;
extern bool    UseRecoveryTradeProfitLockin=false;
extern string  rts="Recovery trailing stop";
extern bool    UseRecoveryTrailingStop=true;
extern int     RecoveryTrailingStopAt=10;
extern color   RecoveryStopLossLineColour=Red;
bool    UseHardRecoveryStop=false;//Doesn't work but is part of the code and I cannot be bothered to remove it
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define  breakevenlinename "Break even line"
#define  reentrylinename "Re entry line"
//From iExposure for Recovery BE calcs
#define        SYMBOLS_MAX 1024
#define        DEALS          0
#define        BUY_LOTS       1
#define        BUY_PRICE      2
#define        SELL_LOTS      3
#define        SELL_PRICE     4
#define        NET_LOTS       5
#define        PROFIT         6
int            OldRecoverTrailBars;
bool           RecoveryInProgress, TpMoved;
int            RecoveryLockProfitsAt=50;
int            RecoveryLockInPips=10;
string         ExtSymbols[SYMBOLS_MAX];
int            ExtSymbolsTotal=0;
double         ExtSymbolsSummaries[SYMBOLS_MAX][7];
int            ExtLines=-1;
string         ExtCols[8]={"Symbol",
                   "Deals",
                   "Buy lots",
                   "Buy price",
                   "Sell lots",
                   "Sell price",
                   "Net lots",
                   "Profit"};
int            ExtShifts[8]={ 10, 80, 130, 180, 260, 310, 390, 460 };
int            ExtVertShift=14;
double         buy_price=0.0;
double         sell_price=0.0;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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  spt="----Specific time inputs----";
extern double  StartTime=12.15;

extern string  pts="----Swap filter----";
extern bool    CadPairsPositiveOnly=true;
extern bool    AudPairsPositiveOnly=true;
extern bool    NzdPairsPositiveOnly=true;

extern string  tmm="----Trade management module----";
//Breakeven has to be enabled for JS and TS to work.
extern string  BE="Break even settings";
extern bool    BreakEven=true;
extern int     BreakEvenPips=10;
extern int     BreakEvenProfit=3;
extern string  cts="----Candlestick trailing stop----";
extern bool    UseCandlestickTrailingStop=false;
extern int     CstTimeFrame=0;//Defaults to current chart
extern int     CstTrailCandles=1;//Defaults to previous candle
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int            OldCstBars;//For candlestick ts
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  JSL="Jumping stop loss settings";
extern bool    JumpingStop=true;
extern int     JumpingStopPips=10;
extern string  TSL="Trailing stop loss settings";
extern bool    TrailingStop=false;
extern int     TrailingStopPips=20;
extern string  mis="----Odds and ends----";
extern bool    ShowManagementAlerts=true;
extern int     DisplayGapSize=30;

// Bbands vars
double         MA,SefcCheck,fisher_blue, fisher_red, Ci_red, Ci_blue, SMA8_previous, SMA8_current, SMA13_previous, SMA13_current,BBValue,BBValueRed,BBValueBlue,BBValue_prev, trendLineValue,CurrentPrice,macd ;
int            AccEquity, Ci_last, last_cross, hTF, lTF;
string         Sentiment,Sentiment5m, TrendLine,TrendLine5m, Emotion,Emotion5m, ShaffDirection, fisher_check, hma, Ci, SMA_Cross, lastTradeType, sar, BBands, BBands_lower;
string         TriggerTrend, TrendDetectionMethod; // used to trigger a trade
bool           PriceHit;


//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, OpenTrades;
bool           CanTradeThisPair;//Will be false when this pair fails the currency can only trade twice filter, or the balanced trade filter
bool           BuyOpen, SellOpen;
int            RetryCount = 10;//Will make this number of attempts to get around the trade context busy error.

//Pending price inputs. Keeps things hidden from the crims
bool           PendingBuy, PendingSell;
double         PendingPrice, PendingStop, PendingTake;
datetime       PendingTime;
double         PendingCandleRange;
double         PendingRecreationCancelPips = 2;
//Hidden stops variables
double         HiddenStopLoss, HiddenTakeProfit;


//Date/Time
datetime       ConvertedStartTime;

//Trend detection
string         trend;


//Misc
string         Gap, ScreenMessage;
int            OldBars;
string         PipDescription=" pips";
bool           ForceTradeClosure;



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);      
   if (TradeLong) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Taking long trades", NL);
   if (TradeShort) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Taking short trades", NL);
   if (!TradeLong && !TradeShort) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Both TradeLong and TradeShort are set to false", NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Lot size: ", Lot, " (Criminal's minimum lot size: ", MarketInfo(Symbol(), MODE_MINLOT), ")", 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, "MaxSpread = ", MaxSpread/10, ": Spread = ", MarketInfo(Symbol(), MODE_SPREAD)/10, 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
   
   if (StartTime > 0)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Start time: ", TimeToStr(ConvertedStartTime, TIME_MINUTES), NL);
   }//if (StartTime > 0)
   
   //Trend
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   if (UseTrendDetection)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trend is ", trend, NL);
      //Rsi
      if (UseRsiTrendDetection)
      {
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trend Rsi ", TrendRsiVal, NL);
      }//if (UseRsiTrendDetection)
      
      //slowkey 2 moving average
      if (UseSlowkey)
      {
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Fast MA ", FastTrendMaVal, ":  Slow MA ", SlowTrendMaVal,  NL);
      }//if (UseSlowkey)
      
      //Single moving average
      if (UseAA)
      {
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "AA (TF:"+TimeFrame+") value ", AaVal, ": AA direction: ", AaDirection, NL);
      }//if (UseAA)
      
      //NB V10
      if (UseNanningBobForTrend)
      {
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Fast MA ", FastNbTrendMaVal, ":  Slow MA ", SlowNbTrendMaVal,  NL);      
      }//if (UseNanningBobForTrend)
   
      if (UseNanningBobForTrigger)
      {
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "NB trade trigger direction: ", TradeTriggerDirection, NL);
      }//if (UseNanningBobForTrigger)
       
       
       
   }//if (UseTrendDetection)
   
      //ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
   
   if (UseHanover)
   {
      string now, then;         
      for (int cc = 0; cc < ArraySize(Tf); cc++)
      {
         double strength1 = ReadStrength(Ccy1, Tf[cc], 0);
         double strength2 = ReadStrength(Ccy2, Tf[cc], 0);
         if (SlopeConfirmationCandles > 0) 
         {
            double prevstrength1 = ReadStrength(Ccy1, Tf[cc], SlopeConfirmationCandles);
            now = StringConcatenate(": Shift ",SlopeConfirmationCandles, " = ", DoubleToStr(prevstrength1, 2));
            double prevstrength2 = ReadStrength(Ccy2, Tf[cc], SlopeConfirmationCandles);
            then = StringConcatenate(": Shift ", SlopeConfirmationCandles, " = ", DoubleToStr(prevstrength2, 2));
         }//if (SlopeCandles[cc] > 0) 
      
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "TF ", Tf[cc], 
                                           ": ", Ccy1, ": Now = ", DoubleToStr(strength1, 2),
                                           now,
                                           ": ", Ccy2, ": Now = ", DoubleToStr(strength2, 2),
                                           then,
                                           NL);
      }//for (int cc = 0; cc < ArraySize(Tf); cc++)
      if (StrongThreshold > 0 && WeakThreshold > 0)
      {
         bool tradeable = false;
         if (strength1 > StrongThreshold && strength2 < WeakThreshold)
         {
            ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Threshold: Can trade this pair long", NL);
            tradeable = true;
         }//if (strength1 > StrongThreshold && strength2 < WeakThreshold)
         
         if (strength2 > StrongThreshold && strength1 < WeakThreshold)
         {
            ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Threshold: Can trade this pair short", NL);
            tradeable = true;
         }//if (strength1 > StrongThreshold && strength2 < WeakThreshold)
         
         if (!tradeable) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Threshold: Cannot trade this pair yet", NL);
      }//if (StrongThreshold > 0 && WeakThreshold > 0)
      
   }//if (UseHanover)

   /*
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Rsi: ", RsiVal, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Moving average: ", MaVal, NL);
   */

   //ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   
   if (BreakEven)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Breakeven is set to ", BreakEvenPips, PipDescription);
      ScreenMessage = StringConcatenate(ScreenMessage,": BreakEvenProfit = ", BreakEvenProfit, PipDescription);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL); 
   }//if (BreakEven)

   if (UseCandlestickTrailingStop)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Using candlestick trailing stop", NL);      
   }//if (UseCandlestickTrailingStop)
   
   if (JumpingStop)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Jumping stop is set to ", JumpingStopPips, PipDescription);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);   
   }//if (JumpingStop)
   

   if (TrailingStop)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trailing stop is set to ", TrailingStopPips, PipDescription);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);   
   }//if (TrailingStop)


   //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BB Upper line: ", DoubleToStr(BbUpper, Digits), NL);
   //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BB Middle line: ", DoubleToStr(BbMiddle, Digits), NL);
   //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BB Lower line: ", DoubleToStr(BbLower, Digits), NL);
   //ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BB Lower line: ", DoubleToStr(BbLower, Digits), NL);
   
   if (MarginMessage != "") ScreenMessage = StringConcatenate(ScreenMessage,NL, Gap, MarginMessage, NL);

   // Symhonie Messages
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "----------------------------------", NL);
   if(ARS) {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "ARS Ratio System: ON. Next ARS Lot : ", Lot, NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Account Equity : ", AccEquity + " " + AccountCurrency(), NL);
   } else {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "ARS Ratio System: OFF. Manual Lot : ", Lot, NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Account Equity : ", AccEquity + " " + AccountCurrency(), NL);
   }
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "----------------------------------", NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BBands Color ("+Period()+")    : ", BBands, NL);
   if(AllowMultipleTrendTrade){
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "MultipleTrade : ON" , NL);
    } else {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "MultipleTrade : OFF" , NL);
    }
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "----------------------------------", NL);
   
   if(SellOpen || BuyOpen) {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "TRADE IN PROGRESS ..." , NL);
   } else { 
      if(AllowMultipleTrendTrade){
       ScreenMessage = StringConcatenate(ScreenMessage,Gap, "LOOKING FOR GOOD ENTRY ... (Multipletrade is ON)" , NL);
      } else {
       if(lastTradeType=="SELL") ScreenMessage = StringConcatenate(ScreenMessage,Gap, "LOOKING FOR -BUY- TRADE (last trade was a " + lastTradeType + ")", NL);
       if(lastTradeType=="BUY") ScreenMessage = StringConcatenate(ScreenMessage,Gap, "LOOKING FOR -SELL- TRADE (last trade was a " + lastTradeType + ")", NL);
       if(!lastTradeType=="BUY" && !lastTradeType=="SELL") ScreenMessage = StringConcatenate(ScreenMessage,Gap, "LOOKING FOR GOOD ENTRY ... (Multipletrade is OFF)" , NL);
      }
   }
   
   Comment(ScreenMessage);


}//void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----

   // get current TF and higher/lower  TF
   if(Period()==1) { hTF = 5; lTF = 0; }
   if(Period()==5) { hTF = 30; lTF = 1; }
   if(Period()==15) { hTF = 60; lTF = 5; }
   if(Period()==30) { hTF = 240; lTF = 15; }
   if(Period()==60) { hTF = 240; lTF = 30; }
   if(Period()==240) { hTF = 1440; lTF = 60; }
   if(Period()==1440) { hTF = 10080; lTF = 240; }
   if(Period()==10080) { hTF = 43200; lTF = 1440; }

   //Adapt to x digit criminals
   int 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;   
   
   if (multiplier > 1) PipDescription = " points";
   
   TakeProfit*= multiplier;
   StopLoss*= multiplier;
   HiddenPips*= multiplier;
   
   BreakEvenPips*= multiplier;
   BreakEvenProfit*= multiplier;
   JumpingStopPips*= multiplier;
   TrailingStopPips*= multiplier;
   
   MinPipsBetweenCandles*= multiplier;//Caterpillar

   Gap="";
   if (DisplayGapSize >0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }//if (DisplayGapSize >0)
   
   //Reset CriminIsECN if crim is IBFX and the punter does not know or, like me, keeps on forgetting
   string name = TerminalCompany();
   int ispart = StringFind(name, "IBFX", 0);
   if (ispart < 0) ispart = StringFind(name, "Interbank FX", 0);
   if (ispart > -1) CriminalIsECN = true;   
   
   //Set up the arrays
   if (UseHanover)
   {
      SetUpArrays();
      Ccy1 = StringSubstr(Symbol(), 0, 3);
      Ccy2 = StringSubstr(Symbol(), 3, 3);
      ReadBars = iBars(NULL, PERIOD_M1);//Don't need it again when start() triggers
      ReadHanover();
   }//if (UseHanover)
   
   if (TradeComment == "") TradeComment = " ";
   ConvertedStartTime = hhmm_to_time(StartTime);
   OldBars = Bars;
   ReadIndicatorValues();//For initial display in case user has turned of constant re-display
   if (UseTrendDetection) TrendDetectionModule();
   DisplayUserFeedback();
   
   //Call sq's show trades indi
   //iCustom(NULL, 0, "SQ_showTrades",Magic, 0,0);

   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment("");
//----
   return(0);
}

////////////////////////////////////////////////////////////////////////////////////////////////
//TRADE MANAGEMENT MODULE

void ReportError()
{
   //All purpose sl mod error reporter. Called when a sl mod fails
   
   int err=GetLastError();
      
   Alert(OrderTicket()," stop loss modification failed with error(",err,"): ",ErrorDescription(err));
   Print(OrderTicket()," stop loss modification failed with error(",err,"): ",ErrorDescription(err));      

}//void ReportError()



void BreakEvenStopLoss() // Move stop loss to breakeven
{

   double NewStop;
   bool result;
   bool modify=false;
   string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0);
   double sl = ObjectGet(LineName, OBJPROP_PRICE1);
   
   if (OrderType()==OP_BUY)
   {
      if (sl >= OrderOpenPrice() ) return;
      if (Bid >= OrderOpenPrice () + (Point*BreakEvenPips))          
      {
         //Calculate the new stop
         NewStop = NormalizeDouble(OrderOpenPrice()+(BreakEvenProfit*Point), Digits);
         if (HiddenPips > 0)
         {
            if (ObjectFind(LineName) == -1)
            {
               ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), 0);
               ObjectSet(LineName, OBJPROP_COLOR, Red);
               ObjectSet(LineName, OBJPROP_WIDTH, 1);
               ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT);
            }//if (ObjectFind(LineName == -1) )
         
            ObjectMove(LineName, 0, TimeCurrent(), NewStop);         
         }//if (HiddenPips > 0)
         modify = true;   
      }//if (Bid >= OrderOpenPrice () + (Point*BreakEvenPips) && 
   }//if (OrderType()==OP_BUY)               			         
    
   if (OrderType()==OP_SELL)
   {
     if (sl <= OrderOpenPrice() && sl > 0) return;
     if (Ask <= OrderOpenPrice() - (Point*BreakEvenPips)) 
     {
         //Calculate the new stop
         NewStop = NormalizeDouble(OrderOpenPrice()-(BreakEvenProfit*Point), Digits);
         if (HiddenPips > 0)
         {
            if (ObjectFind(LineName) == -1)
            {
               ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), 0);
               ObjectSet(LineName, OBJPROP_COLOR, Red);
               ObjectSet(LineName, OBJPROP_WIDTH, 1);
               ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT);
            }//if (ObjectFind(LineName == -1) )
         
            ObjectMove(LineName, 0, Time[0], NewStop);
         }//if (HiddenPips > 0)         
         modify = true;   
     }//if (Ask <= OrderOpenPrice() - (Point*BreakEvenPips) && (OrderStopLoss()>OrderOpenPrice()|| OrderStopLoss()==0))     
   }//if (OrderType()==OP_SELL)

   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify && HiddenStopLoss > 0)
   {
      while (IsTradeContextBusy() ) Sleep(100);
      result = OrderModify(OrderTicket(), OrderOpenPrice(), NewStop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);      
      if (!result) ReportError();
   }//if (modify)
   
} // End BreakevenStopLoss sub

void JumpingStopLoss() 
{
   // Jump sl by pips and at intervals chosen by user .

   if (OrderProfit() < 0) return;//Nothing to do
   string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0);
   double sl = ObjectGet(LineName, OBJPROP_PRICE1);
   if (sl == 0) return;//No line, so nothing to do
   double NewStop;
   bool modify=false;
   bool result;
   
   
   if (OrderType()==OP_BUY)
   {
      if (sl < OrderOpenPrice() ) return;//Not at breakeven yet
      // Increment sl by sl + JumpingStopPips.
      // This will happen when market price >= (sl + JumpingStopPips)
      if (Bid>= sl + ((JumpingStopPips*2)*Point) )
      {
         NewStop = NormalizeDouble(sl + (JumpingStopPips * Point), Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }// if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())      
   }//if (OrderType()==OP_BUY)
   
   if (OrderType()==OP_SELL)
   {
      if (sl > OrderOpenPrice() ) return;//Not at breakeven yet
      // Decrement sl by sl - JumpingStopPips.
      // This will happen when market price <= (sl - JumpingStopPips)
      if (Bid<= sl - ((JumpingStopPips*2)*Point))
      {
         NewStop = NormalizeDouble(sl - (JumpingStopPips * Point), Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }// close if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())         
   }//if (OrderType()==OP_SELL)

   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify && HiddenStopLoss > 0)
   {
      while (IsTradeContextBusy() ) Sleep(100);
      result = OrderModify(OrderTicket(), OrderOpenPrice(), NewStop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);      
      if (!result) ReportError();
   }//if (modify)

} //End of JumpingStopLoss sub


void TrailingStopLoss()
{
   
   if (OrderProfit() < 0) return;//Nothing to do
   string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0);
   double sl = ObjectGet(LineName, OBJPROP_PRICE1);
   if (sl == 0) return;//No line, so nothing to do
   double NewStop;
   bool modify=false;
   bool result;
   
   if (OrderType()==OP_BUY)
   {
      if (sl < OrderOpenPrice() ) return;//Not at breakeven yet
      // Increment sl by sl + TrailingStopPips.
      // This will happen when market price >= (sl + JumpingStopPips)
      if (Bid>= sl + (TrailingStopPips * Point) )
      {
         NewStop = NormalizeDouble(sl + (TrailingStopPips * Point), Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }// if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())      
   }//if (OrderType()==OP_BUY)
   
   if (OrderType()==OP_SELL)
   {
      if (sl > OrderOpenPrice() ) return;//Not at breakeven yet
      // Decrement sl by sl - TrailingStopPips.
      // This will happen when market price <= (sl - JumpingStopPips)
      if (Bid<= sl - (TrailingStopPips * Point) )
      {
         NewStop = NormalizeDouble(sl - (TrailingStopPips * Point), Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }// close if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())         
   }//if (OrderType()==OP_SELL)

   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify && HiddenStopLoss > 0)
   {
      while (IsTradeContextBusy() ) Sleep(100);
      result = OrderModify(OrderTicket(), OrderOpenPrice(), NewStop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);      
      if (!result) ReportError();
   }//if (modify)
      
} // End of TrailingStopLoss sub

void CandlestickTrailingStop()
{
   
   //Trails the stop at the hi/lo of the previous candle shifted by the user choice.
   //Only tries to do this once per bar, so an invalid stop error will only be generated once. I could code for
   //a too-close sl, but cannot be arsed. Coders, sort this out for yourselves.
   
   if (OldCstBars == Bars) return;
   OldCstBars = Bars;

   if (OrderProfit() < 0) return;//Nothing to do
   string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0);
   double sl = ObjectGet(LineName, OBJPROP_PRICE1);
   if (sl == 0) return;//No line, so nothing to do
   double NewStop;
   bool modify=false;
   bool result;
   

   if (OrderType() == OP_BUY)
   {
      if (iLow(NULL, CstTimeFrame, CstTrailCandles) > sl)
      {
         NewStop = NormalizeDouble(Low[1], Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }//if (iLow(NULL, CstTimeFrame, CstTrailCandles) > sl)
   }//if (OrderType == OP_BUY)
   
   if (OrderType() == OP_SELL)
   {
      if (iHigh(NULL, CstTimeFrame, CstTrailCandles) < sl)
      {
         NewStop = NormalizeDouble(High[1], Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }//if (iHigh(NULL, CstTimeFrame, CstTrailCandles) < sl)
   }//if (OrderType() == OP_SELL)
   
   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify && HiddenStopLoss > 0)
   {
      while (IsTradeContextBusy() ) Sleep(100);
      result = OrderModify(OrderTicket(), OrderOpenPrice(), NewStop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);      
      if (!result) ReportError();
   }//if (modify)

}//End void CandlestickTrailingStop()

void TradeManagementModule()
{

   // Call the working subroutines one by one. 

   //Candlestick trailing stop
   if (UseCandlestickTrailingStop) CandlestickTrailingStop();


   // Breakeven
   if(BreakEven) BreakEvenStopLoss();

   // JumpingStop
   if(JumpingStop) JumpingStopLoss();

   //TrailingStop
   if(TrailingStop) TrailingStopLoss();

   

}//void TradeManagementModule()
//END TRADE MANAGEMENT MODULE
////////////////////////////////////////////////////////////////////////////////////////////////

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.
   
   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);

   //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);

      RefreshRates();
      if (type == OP_BUY) price = NormalizeDouble(Ask, Digits);
      if (type == OP_SELL) price = NormalizeDouble(Bid, Digits);
      
      if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, expiry, col);
   
   
      //Is a 2 stage criminal
      if (CriminalIsECN)
      {
         ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, expiry, col);
         if (ticket > -1)
         {
	           ModifyOrder(ticket, stop, take);
         }//if (ticket > 0)}
      }//if (CriminalIsECN)
      
      if (ticket > -1) break;//Exit the trade send loop
      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(), " jor ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
         Print(Symbol(), " jor ", 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
   return(true);
   
}//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 (!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)) return;           
        }//if (take > 0 && stop > 0)
   
        if (take != 0 && stop == 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           if (OrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE)) return;
        }//if (take == 0 && stop != 0)

        if (take == 0 && stop != 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           if (OrderModify(ticket, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE)) 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)

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();
         //Replace missing tp and sl lines
         if (HiddenPips > 0) ReplaceMissingSlTpLines();
         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);
 
 
   //Swap filter
   if (OpenTrades == 0) TradeDirectionBySwap();

   //An individual currency can only be traded twice, so check for this
   CanTradeThisPair = true;
   if (OnlyTradeCurrencyTwice && OpenTrades == 0)
   {
      IsThisPairTradable();      
   }//if (OnlyTradeCurrencyTwice)
   if (!CanTradeThisPair) return(false);
   
   
   
   
   return(true);


}//End bool IsTradingAllowed()


void LookForTradingOpportunities()
{


   RefreshRates();
   double take, stop, price;
   int type;
   bool SendTrade;

   double SendLots = Lot;
   //Using Recovery
   double target = ObjectGet(reentrylinename, OBJPROP_PRICE1);
   if (UseRecovery)
   {
      if (RecoveryInProgress)
      {
         if (OpenTrades == 2) 
         {
            if (Use1.1.2.4Recovery) SendLots = Lot * 2;         
            if (Use1.1.3.3Recovery) SendLots = Lot * 3;         
         }//if (OpenTrades == 2) 
      
         if (OpenTrades == 3) 
         {
            if (Use1.1.2.4Recovery) SendLots = Lot * 4;
            if (Use1.1.3.3Recovery) SendLots = Lot * 3;
         }//if (OpenTrades == 3) 
      
         if (OpenTrades == 4) return;//No further trading is possible
      
      
      }//if (RecoveryInProgress)
      
      //This idea from Pippo   
      if (Use1.2.6Recovery && OpenTrades + 1 >= Start_Recovery_at_trades)
      {
         if (OpenTrades == Start_Recovery_at_trades - 1) SendLots = Lot * 2;
         if (OpenTrades == Start_Recovery_at_trades) SendLots = Lot * 6;
         if (OpenTrades == Start_Recovery_at_trades + 1) return;      
      }//if (Use1.2.6Recovery)
   
   }//if (UseRecovery)

   //Check filters
   if (!IsTradingAllowed() ) return;
   //Trend
   string Ttrend = trend;//Temp trend string
   if (!UseTrendDetection) Ttrend = up;//Set up a dummy if the user is not using the trend stuff
   
   //Long 
   if (TriggerTrend == buy && Ttrend == up)//Replace with whatever conditional is appropriate
   {
      if (!TradeLong) return;
   
      //Hanover RS
      if (UseHanover && !HanoverFilter(OP_BUY) ) return(false);
   
      if (UseNanningBobForTrigger && TradeTriggerDirection == down) return;
      //Balanced pair trade filter. Only apply to pre-recovery trades.
      //Will remove the comments when I add Recovery
      //if (OpenTrades + 1 < Start_Recovery_at_trades || !UseRecovery)
      //{
         if (UseZeljko && !BalancedPair(OP_BUY) ) return;
      //}//if (OpenTrades + 1 < Start_Recovery_at_trades)
      if (TakeProfit > 0) 
      {
         take = NormalizeDouble(Ask + (TakeProfit * Point), Digits);
         HiddenTakeProfit = take;
         if (HiddenPips > 0) take = NormalizeDouble(take + (HiddenPips * Point), Digits);
      }//if (TakeProfit > 0) 
      
      if (StopLoss > 0) 
      {
         stop = NormalizeDouble(Ask - (StopLoss * Point), Digits);
         HiddenStopLoss = stop;
         if (HiddenPips > 0) stop = NormalizeDouble(stop - (HiddenPips * Point), Digits);
      }//if (StopLoss > 0) 
      
      type = OP_BUY;
      price = Ask;
      SendTrade = true;
   }//if (Ask > 1000000)
   
   if (!UseTrendDetection) Ttrend = down;//Set up a dummy if the user is not using the trend stuff
   
   //Short
   if (TriggerTrend == sell && Ttrend == down)//Replace with whatever conditional is appropriate
   {
      if (!TradeShort) return;

      //Hanover RS
      if (UseHanover && !HanoverFilter(OP_SELL) ) return(false);

      if (UseNanningBobForTrigger && TradeTriggerDirection == up) return;
      //Balanced pair trade filter. Only apply to pre-recovery trades
      //Will remove the comments when I add Recovery
      //if (OpenTrades + 1 < Start_Recovery_at_trades || !UseRecovery)
      //{
         if (UseZeljko && !BalancedPair(OP_SELL) ) return;
      //}//if (OpenTrades + 1 < Start_Recovery_at_trades)
      if (TakeProfit > 0) 
      {
         take = NormalizeDouble(Bid - (TakeProfit * Point), Digits);
         HiddenTakeProfit = take;
         if (HiddenPips > 0) take = NormalizeDouble(take - (HiddenPips * Point), Digits);
      }//if (TakeProfit > 0) 
      
      if (StopLoss > 0) 
      {
         stop = NormalizeDouble(Bid + (StopLoss * Point), Digits);
         HiddenStopLoss = stop;
         if (HiddenPips > 0) stop = NormalizeDouble(stop + (HiddenPips * Point), Digits);
      }//if (StopLoss > 0) 
      
      type = OP_SELL;
      price = Bid;
      SendTrade = true;      
   }//if (Ask < 0)
   

   if (SendTrade)
   {
      bool result = SendSingleTrade(type, TradeComment, SendLots, price, stop, take);
   }//if (SendTrade)
   
   //Actions when trade send succeeds
   if (SendTrade && result)
   {
      if(TakeScreenShot==true) { WindowScreenShot("bbands_ea/"+Symbol()+"_"+TicketNo+"_IN_"+Hour()+"-"+Minute()+"_"+TradeComment+".gif",1680,1050);  }
      if (HiddenPips > 0) ReplaceMissingSlTpLines();
   }//if (result)
   
   //Actions when trade send fails
   if (SendTrade && !result)
   {
   
   }//if (!result)
   
   

}//void LookForTradingOpportunities()

bool CloseTrade(int ticket)
{   
   while(IsTradeContextBusy()) Sleep(100);
   bool result = OrderClose(ticket, OrderLots(), OrderClosePrice(), 1000, CLR_NONE);

   //Actions when trade send succeeds
   if (result)
   {
      if(TakeScreenShot==true) { WindowScreenShot("bbands_ea/"+Symbol()+"_"+TicketNo+"_OUT_"+Hour()+"-"+Minute()+"_"+TradeComment+".gif",1680,1050);  }
      return(true);
   }//if (result)
   
   //Actions when trade send fails
   if (!result)
   {
      return(false);
   }//if (!result)
   

}//End bool CloseTrade(ticket)

////////////////////////////////////////////////////////////////////////////////////////////////
//Indicator module

/*
void GetBB(int shift)
{
   //Reads BB figures into BbUpper, BbMiddle, BbLower
   
   
   BbUpper = iBands(NULL, 0, BbPeriod, BbDeviation, 0, PRICE_OPEN, MODE_UPPER, shift);
   BbLower = iBands(NULL, 0, BbPeriod, BbDeviation, 0, PRICE_OPEN, MODE_LOWER, shift);
   BbMiddle = iBands(NULL, 0, BbPeriod, BbDeviation, 0, PRICE_OPEN, MODE_MAIN, shift);
   
   BbExtent = BbUpper - BbLower;
   
}//void GetBb(int shift)
*/


double GetRsi(int tf, int period, int ap, int shift)
{
   return(iRSI(NULL, tf, period, ap, shift) );
}//End double GetRsi(int tf, int period, int ap, int shift)



double GetMa(int tf, int period, int mashift, int method, int ap, int shift)
{
   return(iMA(NULL, tf, period, mashift, method, ap, shift) );
}//End double GetMa(int tf, int period, int mashift, int method, int ap, int shift)

/*
double CalculateVolatility(int period, int LookBack)
{
   //Calculates the volatility of a pair based on an average of their movement over LookBack periods
   
   double pips;
   for (int cc = 1; cc < LookBack; cc++)
   {
      pips+= iHigh(NULL, period, cc) - iLow(NULL, period, cc);      
   }//for (int cc = 1; cc < LookBack; cc++)
   
   pips/= LookBack;//Average pips movement per day
   //Alert(pips);

   //Convert to pips
   int multiplier;
   if (Digits == 2) multiplier = 10;
   if (Digits == 3) multiplier = 100;
   if (Digits == 4) multiplier = 1000;
   if (Digits == 5) multiplier = 10000;
   
   pips*= multiplier;
   int rpips = pips;//Convert to a simple integer - all we need
   
   return(rpips);
   
}//End double CalculateVolatility(int period, int LookBack)
*/

double GetAa(int tf, int price, int period, int mashift, int method, int buffer, int shift)
{

   return(iCustom(NULL, 0, "AllAverages_v2.1 cc", tf, price, period, mashift, method, buffer, shift));

}//End double GetAa(int tf, int price, int period, int mashift, int method, int buffer, int shift)

string GetBBands(int tf, int shift)
{
   //string BBColor;
   BBValueBlue = iCustom(NULL, tf, "BBands_Stop_v2", Length, Deviation, MoneyRisk, 4, shift);
   BBValueRed =  iCustom(NULL, tf, "BBands_Stop_v2", Length, Deviation, MoneyRisk, 5, shift);
   if (BBValueBlue != EMPTY_VALUE) { return(blue); } else { return(red); }
}

void LookForInstantClosure()
{
   
   //BBands = GetBBands(0,0);
   if ((BBands==blue || MA>BBValue ) && SellOpen)
   {
        //Alert("CLOSED "+Symbol()+" (Sell) TRADE TICKET : " + TicketNo);
        CloseTrade(TicketNo);
        TriggerTrend=NULL;
        //ReadIndicatorValues();
   }

   if ((BBands==red || MA<BBValue) && BuyOpen)
   {
        //Alert("CLOSED "+Symbol()+" (Buy) TRADE TICKET : " + TicketNo);
        CloseTrade(TicketNo);
        TriggerTrend=NULL;
        //ReadIndicatorValues();
   }
   
}


void ReadIndicatorValues()
{

   // ARS System - Lot calculation based on equity
   if(ARS) { 
      if(MarketInfo(Symbol(), MODE_MINLOT) == 0.01){
         Lot = NormalizeDouble((AccountEquity()/10000),2);  
      } else {
         Lot = NormalizeDouble((AccountEquity()/10000),1);
      }
   } 
   
   PriceHit=false;
   
   MA = GetMa(0, 20, 0, 2, 0, 0);
   //MA = GetMa(0, 30, 0, 3, 0, 0);
   macd= iMACD(NULL,0,4,20,4,PRICE_CLOSE,MODE_SIGNAL,0);
   
   // BBANDS CURRENT TIMEFRAME
   BBands = GetBBands(0,BarCheck); // tf, shift
   
   
   if(BBands==blue) { 
      BBValue = BBValueBlue;
      //CurrentPrice = Ask;
      //if(BBValue >= CurrentPrice) PriceHit=true;
   } else {
      BBValue = BBValueRed; 
      //CurrentPrice = Bid;
      //if(BBValue <= CurrentPrice) PriceHit=true;
   }
   
   
   // BBANDS LOWER TIMEFRAME
   BBands_lower = GetBBands(hTF,0); // tf, shift
   if(BBands_lower==blue) { 
      BBValue_prev = BBValueBlue;
      //CurrentPrice = Ask;
      //if(BBValue >= CurrentPrice) PriceHit=true;
   } else {
      BBValue_prev = BBValueRed; 
      //CurrentPrice = Bid;
      //if(BBValue <= CurrentPrice) PriceHit=true;
   }
   
   // VERIFY PRICe ACTION
   
   PriceHit=true;
   
   if(AllowMultipleTrendTrade) 
   {
      lastTradeType="NONE";
   } else {
      if(lastTradeType!="BUY" && lastTradeType!="SELL" && BBands==blue) lastTradeType="BUY";
      if(lastTradeType!="BUY" && lastTradeType!="SELL" && BBands==red) lastTradeType="SELL";
   }
   
   if(BBands==blue && MA > BBValue && PriceHit==true && (Open[1]<Close[0]) && !BuyOpen && lastTradeType!="BUY" ) { TriggerTrend = buy;lastTradeType = "BUY";}
   if(BBands==red && MA < BBValue  && PriceHit==true && (Open[1]>Close[0])&& !SellOpen && lastTradeType!="SELL" ) { TriggerTrend = sell;lastTradeType= "SELL";}  
   
}//void ReadIndicatorValues()

//End Indicator module
////////////////////////////////////////////////////////////////////////////////////////////////

void LookForTradeClosure()
{
   //Close the trade if the new candle opens inside the bands
   
   if (!OrderSelect(TicketNo, SELECT_BY_TICKET) ) return;
   if (OrderSelect(TicketNo, SELECT_BY_TICKET) && OrderCloseTime() > 0) return;
   
   bool CloseTrade;
   
   string LineName = TpPrefix + DoubleToStr(TicketNo, 0);
   //Work with the lines on the chart that represent the hidden tp/sl
   double take = ObjectGet(LineName, OBJPROP_PRICE1);
   LineName = SlPrefix + DoubleToStr(TicketNo, 0);
   double stop = ObjectGet(LineName, OBJPROP_PRICE1);
   
   if (OrderType() == OP_BUY)
   {
      //TP
      if (Bid >= take && take > 0) CloseTrade = true;
      //SL
      if (Bid <= stop && stop > 0) CloseTrade = true;

   }//if (OrderType() == OP_BUY)
   
   
   if (OrderType() == OP_SELL)
   {
      //TP
      if (Bid <= take && take > 0) CloseTrade = true;
      //SL
      if (Bid >= stop && stop > 0) CloseTrade = true;

   }//if (OrderType() == OP_SELL)
   
   if (CloseTrade)
   {
      bool result = CloseTrade(TicketNo);
      //Actions when trade send succeeds
      if (result)
      {
         DeletePendingPriceLines();
      }//if (result)
   
      //Actions when trade send fails
      if (!result)
      {
   
      }//if (!result)
   

   }//if (CloseTrade)
   
   
}//void LookForTradeClosure()

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 (OrderSymbol() != Symbol() ) continue;
      while(IsTradeContextBusy()) Sleep(100);
      if (OrderType() == OP_BUY || OrderType() == OP_SELL) bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, CLR_NONE);
      if (result) cc++;
      if (!result) ForceTradeClosure= true;
      
   }//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()
{
   OpenTrades = 0;
   TicketNo = -1;
   BuyOpen = false;
   SellOpen = false;

   if (OrdersTotal() == 0) return;
   
   for (int cc = 0; cc <= OrdersTotal(); cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
      {
         OpenTrades++;
         TicketNo = OrderTicket();   
         if (OrderType() == OP_BUY) BuyOpen = true;
         if (OrderType() == OP_SELL) SellOpen = true;
         //Replace missing tp and sl lines
         if (HiddenPips > 0) ReplaceMissingSlTpLines();
         //Check for possible trade closure
         LookForTradeClosure();
      }//if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
   }//for (int cc = 0; cc < OrdersTotal() - 1; cc++)
   
   
}//End void CountOpenTrades();

//=============================================================================
//                           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)


///////////////////////////////////////////////////////////////////////////////////////////////////////
//Balance/swap filters module
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 IsThisPairTradable()
{
   //Checks to see if either of the currencies in the pair is already being traded twice.
   //If not, then return true to show that the pair can be traded, else return false
   
   string c1 = StringSubstr(Symbol(), 0, 3);//First currency in the pair
   string c2 = StringSubstr(Symbol(), 3, 3);//Second currency in the pair
   int c1open = 0, c2open = 0;
   CanTradeThisPair = true;
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      int index = StringFind(OrderSymbol(), c1);
      if (index > -1)
      {
         c1open++;         
      }//if (index > -1)
   
      index = StringFind(OrderSymbol(), c2);
      if (index > -1)
      {
         c2open++;         
      }//if (index > -1)
   
      if (c1open == 1 && c2open == 1) 
      {
         CanTradeThisPair = false;
         return(false);   
      }//if (c1open == 1 && c2open == 1) 
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)

   //Got this far, so ok to trade
   return(true);
   
}//End bool IsThisPairTradable()

bool BalancedPair(int type)
{

   //Only allow an individual currency to trade if it is a balanced trade
   //e.g. UJ Buy open, so only allow Sell xxxJPY.
   //The passed parameter is the proposed trade, so an existing one must balance that

   //This code courtesy of Zeljko (zkucera) who has my grateful appreciation.
   
   string BuyCcy1, SellCcy1, BuyCcy2, SellCcy2;

   if (type == OP_BUY || type == OP_BUYSTOP)
   {
      BuyCcy1 = StringSubstr(Symbol(), 0, 3);
      SellCcy1 = StringSubstr(Symbol(), 3, 3);
   }//if (type == OP_BUY || type == OP_BUYSTOP)
   else
   {
      BuyCcy1 = StringSubstr(Symbol(), 3, 3);
      SellCcy1 = StringSubstr(Symbol(), 0, 3);
   }//else

   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS)) continue;
      if (OrderSymbol() == Symbol()) continue;
      if (OrderMagicNumber() != MagicNumber) continue;      
      if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP)
      {
         BuyCcy2 = StringSubstr(OrderSymbol(), 0, 3);
         SellCcy2 = StringSubstr(OrderSymbol(), 3, 3);
      }//if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP)
      else
      {
         BuyCcy2 = StringSubstr(OrderSymbol(), 3, 3);
         SellCcy2 = StringSubstr(OrderSymbol(), 0, 3);
      }//else
      if (BuyCcy1 == BuyCcy2 || SellCcy1 == SellCcy2) return(false);
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)

   //Got this far, so it is ok to send the trade
   return(true);

}//End bool BalancedPair(int type)



//End Balance/swap filters module
///////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////
//Recovery module
void RecoveryModule()
{
   
   //Draw a breakeven line if there is not one in place already.
   //The bot will adjust the tp's during the CountOpenTrades function.

   if (ObjectFind(breakevenlinename) > -1) return;
   
   //Do not need a breakeven line if Recovery is already at be
   //if (ObjectFind(breakevenlinename) > -1) return;
   
   
   buy_price = 0;
   sell_price = 0;
   CheckRecoveryTakeProfit();
   double recovery_profit;
   if (buy_price > 0) 
   {
      recovery_profit = buy_price;
      recovery_profit = NormalizeDouble(buy_price + (RecoveryBreakEvenProfitPips * Point), Digits);
   }//if (buy_price > 0) 
   
   if (sell_price > 0) 
   {
      recovery_profit = sell_price;
      recovery_profit = NormalizeDouble(sell_price - (RecoveryBreakEvenProfitPips * Point), Digits);
   }//if (sell_price > 0) 

   ObjectCreate(breakevenlinename,OBJ_HLINE,0,TimeCurrent(), recovery_profit );
   ObjectSet(breakevenlinename,OBJPROP_COLOR,BreakEvenLineColour);
   ObjectSet(breakevenlinename,OBJPROP_STYLE,STYLE_SOLID);
   ObjectSet(breakevenlinename,OBJPROP_WIDTH,2);
   
}//End void RecoveryModule()

void CheckRecoveryTakeProfit()
{
   //This is adapted from the NB iExposure indicator. I do not understand how it works.
   //There will be redundant code, so anybody wishing to clear it up is most welcome to do so.
   
   ExtLines = 0;
   int    i,col,line;

   ArrayInitialize(ExtSymbolsSummaries,0.0);
   int total=Analyze();
   if(total>0)
   {
      line=0;
      for(i=0; i<ExtSymbolsTotal; i++)
      {
         if (ExtSymbols[i] != Symbol() ) continue;
         if(ExtSymbolsSummaries[i][DEALS]<=0) continue;
         line++;
         //---- add line
         if(line>ExtLines)
         {
            int y_dist=ExtVertShift*(line+1)+1;
            /*for(col=0; col<8; col++)
              {
               name="Line_"+line+"_"+col;
               if(ObjectCreate(name,OBJ_LABEL,windex,0,0))
                 {
                  ObjectSet(name,OBJPROP_XDISTANCE,ExtShifts[col]);
                  ObjectSet(name,OBJPROP_YDISTANCE,y_dist);
                 }
              }*/
            ExtLines++;
         }//if(line>ExtLines)
         //---- set line
         //color  price_colour;//Steve mod
         int    digits=MarketInfo(ExtSymbols[i],MODE_DIGITS);
         double buy_lots=ExtSymbolsSummaries[i][BUY_LOTS];
         double sell_lots=ExtSymbolsSummaries[i][SELL_LOTS];
         if(buy_lots!=0)  buy_price=NormalizeDouble(ExtSymbolsSummaries[i][BUY_PRICE]/buy_lots, Digits);
         if(sell_lots!=0) sell_price=NormalizeDouble(ExtSymbolsSummaries[i][SELL_PRICE]/sell_lots, Digits);
         
      }//for(i=0; i<ExtSymbolsTotal; i++)
   }//if(total>0)


}//End void CheckRecoveryTakeProfit()

int Analyze()
{
   double profit;
   int    i,index,type,total=OrdersTotal();
//----
   for(i=0; i<total; i++)
     {
      if(!OrderSelect(i,SELECT_BY_POS)) continue;
      type=OrderType();
      if(type!=OP_BUY && type!=OP_SELL) continue;
      index=SymbolsIndex(OrderSymbol());
      if(index<0 || index>=SYMBOLS_MAX) continue;
      //----
      ExtSymbolsSummaries[index][DEALS]++;
      profit=OrderProfit()+OrderCommission()+OrderSwap();
      ExtSymbolsSummaries[index][PROFIT]+=profit;
      if(type==OP_BUY)
        {
         ExtSymbolsSummaries[index][BUY_LOTS]+=OrderLots();
         ExtSymbolsSummaries[index][BUY_PRICE]+=OrderOpenPrice()*OrderLots();
        }
      else
        {
         ExtSymbolsSummaries[index][SELL_LOTS]+=OrderLots();
         ExtSymbolsSummaries[index][SELL_PRICE]+=OrderOpenPrice()*OrderLots();
        }
     }
//----
   total=0;
   for(i=0; i<ExtSymbolsTotal; i++)
     {
      if(ExtSymbolsSummaries[i][DEALS]>0) total++;
     }
//----
   return(total);
}//int Analyze()

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int SymbolsIndex(string SymbolName)
{
   bool found=false;
//----
   for(int i=0; i<ExtSymbolsTotal; i++)
     {
      if(SymbolName==ExtSymbols[i])
        {
         found=true;
         break;
        }
     }
//----
   if(found) return(i);
   if(ExtSymbolsTotal>=SYMBOLS_MAX) return(-1);
//----
   i=ExtSymbolsTotal;
   ExtSymbolsTotal++;
   ExtSymbols[i]=SymbolName;
   ExtSymbolsSummaries[i][DEALS]=0;
   ExtSymbolsSummaries[i][BUY_LOTS]=0;
   ExtSymbolsSummaries[i][BUY_PRICE]=0;
   ExtSymbolsSummaries[i][SELL_LOTS]=0;
   ExtSymbolsSummaries[i][SELL_PRICE]=0;
   ExtSymbolsSummaries[i][NET_LOTS]=0;
   ExtSymbolsSummaries[i][PROFIT]=0;
//----
   return(i);
}//End int SymbolsIndex(string SymbolName)

void AddReEntryLine(double price)
{
   if (ObjectFind(reentrylinename) > -1) ObjectDelete(reentrylinename);   
   
   
   if (!ObjectCreate(reentrylinename,OBJ_HLINE,0,TimeCurrent(),price) )
   {
      int err=GetLastError();      
      Alert("Re-entry line draw failed with error(",err,"): ",ErrorDescription(err));
      Print("Re-entry line draw failed with error(",err,"): ",ErrorDescription(err));
      return(0);

   }//if (!ObjectCreate(reentrylinename,OBJ_HLINE,0,TimeCurrent(),price) )
   
   ObjectSet(reentrylinename,OBJPROP_COLOR,ReEntryLineColour);
   ObjectSet(reentrylinename,OBJPROP_STYLE,STYLE_SOLID);
   ObjectSet(reentrylinename,OBJPROP_WIDTH,2);     


}//void AddReEntryLine(int type, double price)

void ReplaceReEntryLine()
{

   //Find the most recent trade in the sequence and replace the missing re-entry line
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {      
      if (OrderSelect(cc, SELECT_BY_POS, MODE_TRADES) )
      {
         if (OrderSymbol() == Symbol())
         {            
            if (OrderType() == OP_BUY) AddReEntryLine(NormalizeDouble(OrderOpenPrice() - (ReEntryLinePips * Point), Digits) );
            if (OrderType() == OP_SELL) AddReEntryLine(NormalizeDouble(OrderOpenPrice() + (ReEntryLinePips * Point), Digits) );
            return;
         }//if (OrderSymbol() == Symbol() && OrderCloseTime() == 0)      
         
      }//if (OrderSelect(cc, SELECT_BY_POS) )
      
   }//for (cc = OpenTrades; cc >= 0; cc--)

}//void ReplaceReEntryLine()

void RecoveryCandlesticktrailingStop()
{

   //Called from start()
   //This function will only be called if Recovery is in progress.
   
/*
    * no tp in Recovery trades, just the breakeven line on the chart
    * at be +10, the breakeven line becomes the stop loss line
    * code a candlestick trail for the stop loss line
    * close the Recovery basket when the market retraces to the stop loss line
*/
   
   //Find the trade type. Function leaves an open trade selected   
   
   double target, stop;
   
   RefreshRates();
          
   if (BuyOpen)
   {
      //Should breakeven line be replaced by trailing stop line.
      //Irrelevant if be line has been deleted
      if (ObjectFind(breakevenlinename) > -1)
      {
         target = ObjectGet(breakevenlinename, OBJPROP_PRICE1);
         if (Ask >= target + (RecoveryTrailingStopAt * Point) )
         {
            ObjectDelete(breakevenlinename);
            ObjectCreate(breakevenlinename, 1,0,TimeCurrent(),target);
            ObjectSet(breakevenlinename,OBJPROP_COLOR,RecoveryStopLossLineColour);
            ObjectSet(breakevenlinename,OBJPROP_STYLE,STYLE_SOLID);
            ObjectSet(breakevenlinename,OBJPROP_WIDTH,2);     
            //return;
         }//if (Ask >= target + (RecoveryTrailingStopAt * Point) )
      }//if (ObjectFind(breakevenlinename) > -1)
      
      //Abort the function if be line is wrong colour
      if (ObjectGet(breakevenlinename, OBJPROP_COLOR) != RecoveryStopLossLineColour) return;
  
      //Move the stop at each new candle
      if (OldRecoverTrailBars != Bars)
      {
         target = ObjectGet(breakevenlinename, OBJPROP_PRICE1);
         
         if (Low[1] > target)
         {
            ObjectMove(breakevenlinename, 0, TimeCurrent(), Low[1]);            
         }//if (Low[1] > target)
         OldRecoverTrailBars = Bars;
         //return;
      }//if (OldRecoverTrailBars != Bars)
      
      //Has the market retraced to the recovery stop loss
      target = ObjectGet(breakevenlinename, OBJPROP_PRICE1);
      
      if (Ask <= target)
      {         
         ForceTradeClosure = true;
         CloseAllTrades();
         ObjectDelete(breakevenlinename);
         return;
      }//if (Ask <= target)
   }//if (OrderType() == OP_BUY)
   
   //The most recent trade selected in CountOpenTrades will show the type of trades involved
   if (SellOpen)
   {
      //Should breakeven line be replaced by trailing stop line
      //Irrelevant if be line has been deleted
      if (ObjectFind(breakevenlinename) > -1)
      {
         target = ObjectGet(breakevenlinename, OBJPROP_PRICE1);
         if (Bid <= target - (RecoveryTrailingStopAt * Point) )
         {            
            ObjectDelete(breakevenlinename);
            ObjectCreate(breakevenlinename, 1,0,TimeCurrent(),target);
            ObjectSet(breakevenlinename,OBJPROP_COLOR,RecoveryStopLossLineColour);
            ObjectSet(breakevenlinename,OBJPROP_STYLE,STYLE_SOLID);
            ObjectSet(breakevenlinename,OBJPROP_WIDTH,2);     
            //return;
         }//if (Bid <= target - (RecoveryTrailingStopAt * Point) )
      }//if (ObjectFind(breakevenlinename) > -1)
      
      
      //Abort the function if be line is wrong colour
      if (ObjectGet(breakevenlinename, OBJPROP_COLOR) != RecoveryStopLossLineColour) return;
      
      
      
      //Move the stop at each new candle
      if (OldRecoverTrailBars != Bars)
      {
         target = ObjectGet(breakevenlinename, OBJPROP_PRICE1);
         if (High[1] < target)
         {
            ObjectMove(breakevenlinename, 0, TimeCurrent(), High[1]);         
         }//if (High[1] < target)
         OldRecoverTrailBars = Bars;
         //return;
      }//if (OldRecoverTrailBars != Bars)
      
      //Has the market retraced to the recovery stop loss
      target = ObjectGet(breakevenlinename, OBJPROP_PRICE1);
      //Alert("Target = ", target);
      if (Bid >= target)
      {
         ForceTradeClosure = true;
         CloseAllTrades();
         ObjectDelete(breakevenlinename);
         return;
      }//if (Bid >= target)
   }//if (OrderType() == OP_SELL)
   
   

}//End void RecoveryCandlesticktrailingStop()


//End Recovery module
///////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////
//Trend detection module

void TrendDetectionModule()
{

   static int OldNbBars;

   //Define the trend according to the user's choices.
   //Only called if UseTrendDetection is set to true
   trend = ranging;//Default
   
   //Rsi. This one is scooby-doo's suggestion and is based on a 20 period D1 Rsi.
   if (UseRsiTrendDetection)
   {
      TrendRsiVal = GetRsi(RsiTdTf, RsiTdPeriod, RsiTdAppliedPrice, 0);
      if (TrendRsiVal > 55) trend = up;
      if (TrendRsiVal < 45) trend = down;
   }//if (UseRsiTrendDetection)

   //'slowkey' - double moving average.
   //Slow MA > Fast MA - trend is up and vice versa
   if (UseSlowkey)
   {
      FastTrendMaVal = GetMa(FastMaTdTF, FastMaTdPeriod, FastMaTdShift, FastMaTdMethod, FastMaTdAppliedPrice, 0);   
      SlowTrendMaVal = GetMa(SlowMaTdTF, SlowMaTdPeriod, SlowMaTdShift, SlowMaTdMethod, SlowMaTdAppliedPrice, 0); 
      if (FastTrendMaVal > SlowTrendMaVal) trend = up;
      if (FastTrendMaVal < SlowTrendMaVal) trend = down;
   }//if (UseSlowkey)

   /*
   I picked this up from the book 'Trading Day by Day - Winning the Zero Sum Game' by FH Goslin.
   10 week MA is rising - trend is up.
   10 week MA is falling - trend is down.
   I use AllAverages for detecting this
   */
   if (UseAA)
   {
      AaVal = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 0, CandleShift);
      AaUp = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 1, CandleShift);//Up buffer
      AaDown = GetAa(TimeFrame, Price, MA_Period, MA_Shift, MA_Method, 3, CandleShift);//Down buffer
      
      if (AaUp != EMPTY_VALUE) {AaDirection = up; trend = up;}
      if (AaDown != EMPTY_VALUE) {AaDirection = down; trend = down;}
      if (AaUp != EMPTY_VALUE && AaDown != EMPTY_VALUE) {AaDirection = both; trend = ranging;}//Happens at the turn

      //Close open trades on a signals change
      if (AaUp != EMPTY_VALUE && AaDown == EMPTY_VALUE && SellOpen && CloseOnOppositeSignal)
      {
         CloseTrade(TicketNo);
      }//if (AaUp != EMPTY_VALUE && AaDown == EMPTY_VALUE && SellOpen && CloseOnOppositeSignal)
   
      if (AaDown != EMPTY_VALUE && AaUp == EMPTY_VALUE && BuyOpen && CloseOnOppositeSignal)
      {
         CloseTrade(TicketNo);
      }//if (AaDown != EMPTY_VALUE && AaUp == EMPTY_VALUE && BuyOpen && CloseOnOppositeSignal)
   }//if (UseAA)
   
   //NB V10 2 moving averages.
   //D1 candle hi-lo above both ma's: trend is up. Below both: trend is down. In between: market is ranging.
   //Also makes an excellent trade trigger in a longer-term trend trading system.
   if (UseNanningBobForTrend || UseNanningBobForTrigger)
   {
      
      if (OldNbBars != iBars(NULL, FastNbTdTF) )//Only need this call at the start of each candle
      {
         OldNbBars = iBars(NULL, FastNbTdTF);
         FastNbTrendMaVal = GetMa(FastNbTdTF, FastNbTdPeriod, FastNbTdShift, FastNbTdMethod, FastNbTdAppliedPrice, 0);   
         SlowNbTrendMaVal = GetMa(SlowNbTdTF, SlowNbTdPeriod, SlowNbTdShift, SlowNbTdMethod, SlowNbTdAppliedPrice, 0);          
      }//if (OldNbBars != iBars(NULL, FastNbTdTF) )
      
      //Detect uptrend
      if (iHigh(NULL, PERIOD_D1, 0) > FastNbTrendMaVal && iHigh(NULL, PERIOD_D1, 0) > SlowNbTrendMaVal 
         && iLow(NULL, PERIOD_D1, 0) > FastNbTrendMaVal && iLow(NULL, PERIOD_D1, 0) > SlowNbTrendMaVal) 
         {
            if (UseNanningBobForTrend) trend = up;
            if (UseNanningBobForTrigger) TradeTriggerDirection = up;
         }//if (iHigh(NULL, PERIOD_D1, 0) > FastNbTrendMaVal && iHigh(NULL, PERIOD_D1, 0) > SlowNbTrendMaVal 
         
      //Detect downtrend
      if (iHigh(NULL, PERIOD_D1, 0) < FastNbTrendMaVal && iHigh(NULL, PERIOD_D1, 0) < SlowNbTrendMaVal 
         && iLow(NULL, PERIOD_D1, 0) < FastNbTrendMaVal && iLow(NULL, PERIOD_D1, 0) < SlowNbTrendMaVal) 
         {
            if (UseNanningBobForTrend) trend = down;
            if (UseNanningBobForTrigger) TradeTriggerDirection = down;
         }//if (iHigh(NULL, PERIOD_D1, 0) < FastNbTrendMaVal && iHigh(NULL, PERIOD_D1, 0) < SlowNbTrendMaVal 
         
      //Trade direction candle
      //BB uses a shorter-term candle direction filter to confirm that the market is moving in the correct
      //direction for the trade. This function ascertains the direction of movement of the candle
   
      TrendConfirmationCandleDir = none;
   
      if (iOpen(NULL, TrendConfirmationCandleTF, 1) > iClose(NULL, TrendConfirmationCandleTF, 1) ) TrendConfirmationCandleDir = down;
      if (iOpen(NULL, TrendConfirmationCandleTF, 1) < iClose(NULL, TrendConfirmationCandleTF, 1) ) TrendConfirmationCandleDir = up;

   }//if (UseNanningBobForTrend || UseNanningBobForTrigger)
   
   
}//void TrendDetectionModule()


//End Trend detection module
///////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////
//Pending trade price lines module.
//Doubles up by providing missing lines for the stealth stuff
void DrawPendingPriceLines()
{
   //This function will work for a full pending-trade EA.
   //The pending tp/sl can be used for hiding the stops in a market-trading ea
   
   /*
   ObjectDelete(pendingpriceline);
   ObjectCreate(pendingpriceline, OBJ_HLINE, 0, TimeCurrent(), PendingPrice);
   if (PendingBuy) ObjectSet(pendingpriceline, OBJPROP_COLOR, Green);
   if (PendingSell) ObjectSet(pendingpriceline, OBJPROP_COLOR, Red);
   ObjectSet(pendingpriceline, OBJPROP_WIDTH, 1);
   ObjectSet(pendingpriceline, OBJPROP_STYLE, STYLE_DASH);
   */
   string LineName = TpPrefix + DoubleToStr(TicketNo, 0);//TicketNo is set by the calling function - either CountOpenTrades or DoesTradeExist
   HiddenTakeProfit = 0;
   if (TicketNo > -1 && OrderTakeProfit() > 0)
   {
      if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT)
      {
         HiddenTakeProfit = NormalizeDouble(OrderTakeProfit() - (HiddenPips * Point), Digits);
      }//if (OrderType() == OP_BUY)
      
      if (OrderType() == OP_SELL)
      {
         HiddenTakeProfit = NormalizeDouble(OrderTakeProfit() + (HiddenPips * Point), Digits);
      }//if (OrderType() == OP_BUY)      
   }//if (TicketNo > -1 && OrderTakeProfit() > 0)
   
   if (HiddenTakeProfit > 0 && ObjectFind(LineName) == -1)
   {
      ObjectDelete(LineName);
      ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), HiddenTakeProfit);
      ObjectSet(LineName, OBJPROP_COLOR, Green);
      ObjectSet(LineName, OBJPROP_WIDTH, 1);
      ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT);
   }//if (HiddenTakeProfit > 0)
   
   
   LineName = SlPrefix + DoubleToStr(TicketNo, 0);//TicketNo is set by the calling function - either CountOpenTrades or DoesTradeExist
   HiddenStopLoss = 0;
   if (TicketNo > -1 && OrderStopLoss() > 0)
   {
      if (OrderType() == OP_BUY)
      {
         HiddenStopLoss = NormalizeDouble(OrderStopLoss() + (HiddenPips * Point), Digits);
      }//if (OrderType() == OP_BUY)
      
      if (OrderType() == OP_SELL || OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT)
      {
         HiddenStopLoss = NormalizeDouble(OrderStopLoss() - (HiddenPips * Point), Digits);
      }//if (OrderType() == OP_BUY)      
   }//if (TicketNo > -1 && OrderStopLoss() > 0)
   
   if (HiddenStopLoss > 0 && ObjectFind(LineName) == -1)
   {
      ObjectDelete(LineName);
      ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), HiddenStopLoss);
      ObjectSet(LineName, OBJPROP_COLOR, Red);
      ObjectSet(LineName, OBJPROP_WIDTH, 1);
      ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT);
   }//if (HiddenStopLoss > 0)
   
   

}//End void DrawPendingPriceLines()


void DeletePendingPriceLines()
{

   
   //ObjectDelete(pendingpriceline);
   string LineName = TpPrefix + DoubleToStr(TicketNo, 0);
   ObjectDelete(LineName);
   LineName = SlPrefix + DoubleToStr(TicketNo, 0);
   ObjectDelete(LineName);
   
}//End void DeletePendingPriceLines()

void ReplaceMissingSlTpLines()
{

   if (OrderTakeProfit() > 0 || OrderStopLoss() > 0) DrawPendingPriceLines();

}//End void ReplaceMissingSlTpLines()

void DeleteOrphanTpSlLines()
{

   if (ObjectsTotal() == 0) return;
   
   for (int cc = ObjectsTotal() - 1; cc >= 0; cc--)
   {
      string name = ObjectName(cc);
      
      if ((StringSubstr(name, 0, 2) == TpPrefix || StringSubstr(name, 0, 2) == SlPrefix) && ObjectType(name) == OBJ_HLINE)
      {
         int tn = StrToDouble(StringSubstr(name, 2));
         if (tn > 0) 
         {
            if (!OrderSelect(tn, SELECT_BY_TICKET, MODE_TRADES) || OrderCloseTime() > 0)
            {
               ObjectDelete(name);
               cc++;
            }//if (!OrderSelect(tn, SELECT_BY_TICKET, MODE_TRADES) || OrderCloseTime() > 0)
            
         }//if (tn > 0) 
         
         
      }//if (StringSubstr(name, 0, 1) == TpPrefix)
      
   }//for (int cc = ObjectsTotal() - 1; cc >= 0; cc--)
   
   
}//End void DeleteOrphanTpSlLines()


//END Pending trade price lines module
///////////////////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Caterpillar module
void DeleteOrphanGlobals()
{
   //Remove those globals left behind after a trade closes
   for (int cc = GlobalVariablesTotal() - 1; cc >= 0; cc--)
   {
      CsGvName = GlobalVariableName(cc);
      int tn = StrToDouble(CsGvName);
      if (tn > 0)
      {
         if (!OrderSelect(tn, SELECT_BY_TICKET) || OrderCloseTime() > 0) 
         {
            GlobalVariableDel(CsGvName);
            cc++;            
         }//if (!OrderSelect(tn, SELECT_BY_TICKET) || OrderCloseTime() > 0) 
      }//if (tn > 0)
      
   }//for (int cc = GlobalVariablesTotal() - 1; cc >= 0; cc--)
   

}//End void DeleteOrphanGlobals()
void MoveCaterpillarStopToBreakeven()
{
   //OpenTrades - 1 trade needs to have its stop moved to be at the opening of a new trade
   
   //Select OpenTrades - 1
   int found = 0;
   for (int cc = 0; cc <= OrdersTotal() - 1; cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber ) continue;
      
      //Order must belong to Cat
      found++;
      if (found == OpenTrades - 1) break;   
   }//for (int cc = 0; cc <= OrdersTotal() - 1; cc++)
   
   double stop = OrderOpenPrice();
   bool modify = false;
   
   if (OrderType() == OP_BUY && OrderStopLoss() < OrderOpenPrice() ) modify = true;
   if (OrderType() == OP_SELL && OrderStopLoss() > OrderOpenPrice() ) modify = true;
   
   if (modify)
   {
      int tries = 0;
      bool result = false;
      while (!result)
      {
         result = OrderModify(OrderTicket(), OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
         if (!result)
         {
            tries++;
            if (tries == 1) Alert(OrderTicket(), " stop loss move to BE failed");
            if (tries == 100) 
            {
               result = true;//Give up
               Alert(OrderTicket(), " Caterpillar failed to move the sl to breakeven after 100 attempts.");
            }//if (tries == 100)             
         }//if (!result)
      }//while (!result)      
   }//if (modify)
   
   

}//End void MoveCaterpillarStopToBreakeven()

void CaterpillarTrailingStop(int TradesToCheck)
{
   //Move trade stops 1 candle to the right when there is a new hi or lo, depending on the trade type
   //Also deletes redundant gv's
   
   if (GlobalVariablesTotal() == 0) return;//Shouldn't happen, but you never know
   
   int found, shift, ctime;
   bool result;
   double stop;
   int MaxTradesTicketNo = -1;//This will hold the ticket number of the final trade in the sequence, but which is checked first
   
   
   //Cycle through the Golbal Variables list to look for those with an integer as their name
   for (int cc = GlobalVariablesTotal() - 1; cc >= 0; cc--)
   {
      CsGvName = GlobalVariableName(cc);
      int tn = StrToDouble(CsGvName);
      if (tn > 0)
      {
         //Delete the gv if the trade has closed
         if (!OrderSelect(tn, SELECT_BY_TICKET) || OrderCloseTime() > 0) 
         {
            GlobalVariableDel(CsGvName);
            cc++;
            continue;
         }//if (!OrderSelect(tn, SELECT_BY_TICKET) || OrderCloseTime() > 0) 
         
         //The trade is still open, so check for ownership
         if (OrderSymbol() != Symbol() ) continue;
         if (OrderMagicNumber() != MagicNumber ) continue;
      
         
         //Got this far, so Cat owns the trade and the stop needs moving.
         //Store the ticket number of the most recent trade in the sequence,for BE stop stuff further down
         if (MaxTradesTicketNo == -1) MaxTradesTicketNo = OrderTicket();
         //Calculate the shift back from current candle to the candle open time of the previous cts move
         shift = 0;
         ctime = GlobalVariableGet(CsGvName);
         while (Time[shift] > ctime && shift < Bars)
         {
            shift++;
         }//while (Time[shift} > ctime)
         //Point to the next candls
         shift--;
         //This is an attempt to stop the final trade in the sequence having its stop moved too early, because
         //this can result in it being stopped out as soon as it is opened
         if (shift < 2) continue;

         if (OrderType() == OP_BUY)
         {
            //stop = Low[shift];
            stop = iLow(NULL, CatTimeFrame, shift);
            if (OrderStopLoss() < stop && stop > 0)
            {
               while (IsTradeContextBusy() ) Sleep(100);
               result = OrderModify(tn, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
               GlobalVariableSet(CsGvName, Time[shift]);
            }//if (OrderStopLoss() < stop)            
         }//if (OrderType() == OP_BUY)
         
         if (OrderType() == OP_SELL)
         {
            //stop = High[shift];
            stop = iHigh(NULL, CatTimeFrame, shift);
            if (OrderStopLoss() > stop && stop > 0)
            {
               while (IsTradeContextBusy() ) Sleep(100);
               result = OrderModify(tn, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
               GlobalVariableSet(CsGvName, Time[shift]);
            }//if (OrderStopLoss() > stop)
         }//if (OrderType() == OP_SELL)
         
         found++;
         if (found >= TradesToCheck) break;//All finished

      }//if (tn > -1)
   }//for (int cc = GlobalVariablesTotal() - 1; cc >= 0; cc--)
   
   //Attempt to move the stop of the final trade to BE asap, if OpenTrades has reached the max allowed.   
   if (OpenTrades == MaxTrades)
   {
      if (OrderSelect(MaxTradesTicketNo, SELECT_BY_TICKET) && OrderCloseTime() == 0)
      {
         stop = OrderOpenPrice();
         bool modify = false;
         if (OrderType() == OP_BUY && OrderStopLoss() < OrderOpenPrice() )
         {
            modify = true;
         }//if (OrderType() == OP_BUY && OrderStopLoss() < OrderOpenPrice() )
         
         if (OrderType() == OP_SELL && OrderStopLoss() > OrderOpenPrice() )
         {
            modify = true;
         }//if (OrderType() == OP_SELL && OrderStopLoss() > OrderOpenPrice() )
         
         if (modify)
         {
            result = OrderModify(MaxTradesTicketNo, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
         }//if (modify)
         
      
      }//if (OrderSelect(MaxTradesTicketNo, SELECT_BY_TICKET) && OrderCloseTime() == 0)
      
   }//if (OpenTrades == MaxTrades)

}//void CaterpillarTrailingStop()

void LookForCatTradingOpportunities()
{
   RefreshRates();
   double take, stop, price;
   int type;
   bool SendTrade;
   double spread = MarketInfo(Symbol(), MODE_SPREAD) * Point;

   //Ensure a minimum gap in between trades
   double pipsgap = (OnePip * Point);
   if (OpenTrades > 0) pipsgap*= MinPipsBetweenCandles;
   
   double SendLots = Lot;
   //Check filters
   if (!IsTradingAllowed() ) return;
   
   RefreshRates();
   //Long 
   double target;
   if (TradeLong)
   {      
      target = ObjectGet(buyline, OBJPROP_PRICE1);
      if (Bid > target)
      {
         //if (TakeProfit > 0) take = NormalizeDouble(Ask + (TakeProfit * Point), Digits);
         //stop = NormalizeDouble(Low[1] - spread - (OnePip * Point), Digits);
         //stop = NormalizeDouble(iLow(NULL, CatTimeFrame, 1) - spread - (OnePip * Point), Digits);
         type = OP_BUY;
         price = Ask;
         SendTrade = true;
      }//if (Bid > target) return;
         
   }//if (TradeLong)
   
   
   //Short
   if (TradeShort)
   {
      target = ObjectGet(sellline, OBJPROP_PRICE1);
      if (Bid < target)
      {
         //stop = NormalizeDouble(High[1] + spread + (OnePip * Point), Digits);      
         //stop = NormalizeDouble(iHigh(NULL, CatTimeFrame, 1) + spread + (OnePip * Point), Digits);      
         type = OP_SELL;
         price = Bid;
         SendTrade = true;      
      }//if (Bid < target)      
   }//if (TradeShort)
   

   if (SendTrade)
   {
      bool result = SendSingleTrade(type, TradeComment, SendLots, price, stop, take);
   }//if (SendTrade)
   
   //Actions when trade send succeeds
   if (SendTrade && result)
   {
      OpenTrades++;
      TradeOpen = true;
      CandleTraded = true;
      if (OpenTrades > 1) MoveCaterpillarStopToBreakeven();//Move the stop of the previously opened trade to be
      if (OpenTrades > 2) CaterpillarTrailingStop(OpenTrades - 1);//All trades from OpenTrades - 2 should move their stops 1 candle to the right
      
      
      //Redraw the trade line
      pipsgap = (OnePip * Point);
      if (OpenTrades > 0) pipsgap*= MinPipsBetweenCandles;
      
      if (type == OP_BUY)
      {
         ObjectDelete(buyline);
         target = NormalizeDouble(price + pipsgap + spread, Digits);
         ObjectCreate(buyline,OBJ_HLINE,0,TimeCurrent(), target);
         ObjectSet(buyline,OBJPROP_COLOR,BuyLineColour);
         ObjectSet(buyline,OBJPROP_STYLE,STYLE_SOLID);  
      }//if (type == OP_BUY)
      
      if (type == OP_SELL)
      {
         ObjectDelete(sellline);
         target = NormalizeDouble(price - pipsgap - spread, Digits);
         ObjectCreate(sellline,OBJ_HLINE,0,TimeCurrent(), target);
         ObjectSet(sellline,OBJPROP_COLOR,SellLineColour);
         ObjectSet(sellline,OBJPROP_STYLE,STYLE_SOLID);         
      }//if (type == OP_SELL)

   }//if (result)
   
   //Actions when trade send fails
   if (SendTrade && !result)
   {
      
   }//if (!result)
   
   

}//void LookForCatTradingOpportunities()

void StartCaterpillar()
{
   //This function is the equivalent of start() in the independent Caterpillar EA. Please read BB's user guide
   //for details of how Cat works.
   
   static bool OldTradeOpen;
   static int OldH1Bars;

   //Delete orphan Caterpillar gv's
   if (OldH1Bars != iBars(NULL, PERIOD_H1) )
   {
      OldH1Bars = iBars(NULL, PERIOD_H1);
      if (GlobalVariablesTotal() > 0) DeleteOrphanGlobals();
   }//if (OldH1Bars != iBars(NULL, PERIOD_H1) )
   
   

   //Trading
   if (OpenTrades < MaxTrades && !CandleTraded)
   {
      LookForCatTradingOpportunities();
   }//if (OpenTrades < MaxTrades)

   ///////////////////////////////////////////////////////////////////////////////////////////////
   
   if (OldCatBars != iBars(NULL, CatTimeFrame))
   {
      OldCatBars = iBars(NULL, CatTimeFrame);
      CandleTraded = false;
      
     //Move lines
     //Ensure a minimum gap in between trades     
      double pipsgap = (OnePip * Point);
      if (OpenTrades > 0) pipsgap*= MinPipsBetweenCandles;
      double target;

      target = ObjectGet(buyline, OBJPROP_PRICE1);
      //if (TradeLong && NormalizeDouble(High[1] + pipsgap, Digits) > target)
      if (trend == up && TradeLong && NormalizeDouble(iHigh(NULL, CatTimeFrame, 1) + pipsgap, Digits) > target)
      {
         ObjectDelete(buyline);
         //target = NormalizeDouble(High[1] + pipsgap, Digits);
         target = NormalizeDouble(iHigh(NULL, CatTimeFrame, 1) + pipsgap, Digits);
         ObjectCreate(buyline,OBJ_HLINE,0,TimeCurrent(), target);
         ObjectSet(buyline,OBJPROP_COLOR,BuyLineColour);
         ObjectSet(buyline,OBJPROP_STYLE,STYLE_SOLID);               
         if (OpenTrades > 1) CaterpillarTrailingStop(OpenTrades);
      }//if (TradeLong)
   
      target = ObjectGet(sellline, OBJPROP_PRICE1);
      if (trend == down && TradeShort && NormalizeDouble(iLow(NULL, CatTimeFrame, 1) - pipsgap, Digits) < target)
      {
         ObjectDelete(sellline);
         //target = NormalizeDouble(Low[1] - pipsgap, Digits);
         target = NormalizeDouble(iLow(NULL, CatTimeFrame, 1) - pipsgap, Digits);
         ObjectCreate(sellline,OBJ_HLINE,0,TimeCurrent(), target);
         ObjectSet(sellline,OBJPROP_COLOR,SellLineColour);
         ObjectSet(sellline,OBJPROP_STYLE,STYLE_SOLID);         
         if (OpenTrades > 1) CaterpillarTrailingStop(OpenTrades);
      }//if (TradeShort && ObjectFind(sellline) == -1)
   }//if (OldCatBars != iBars(NULL, CatTimeFrame))
   
   ///////////////////////////////////////////////////////////////////////////////////////////////      


}//End void StartCaterpillar()

//END Caterp[illar module
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////



datetime hhmm_to_time(double hhmm)
{
  return (StrToTime(DoubleToStr(MathFloor(hhmm),0)+":"+DoubleToStr((hhmm-MathFloor(hhmm))*100,0)) );
}//End datetime hhmm_to_time(double hhmm)

////////////////////////////////////////////////////////////////////////////////////////////////
//Hanover module
void SetUpArrays()
{
   //Sets up all the arrays required by this program

   int cc;
   int Index = 0;//For searching InputString
   int LastIndex = 0;//Points the the most recent Index
   

   //TimeFrames
   InputString = TimeFrames;
   CleanUpInputString();
   TimeFrames = InputString;
   NoOfTimeFrames = CalculateParamsPassed();
   string NewArray2 = ArrayResize(Tf, NoOfTimeFrames);
   
   Index = 0;//For searching InputString
   LastIndex = 0;//Points the the most recent Index
   for (cc = 0; cc < NoOfTimeFrames; cc ++)
   {
      Index = StringFind(InputString, ",",LastIndex);
      if (Index > -1)
      {
         Tf[cc] = StringSubstr(InputString, LastIndex,Index-LastIndex);
         Tf[cc] = StringTrimLeft(Tf[cc]);
         Tf[cc] = StringTrimRight(Tf[cc]);
         LastIndex = Index+1;
      }//if (Index > -1)      
   }//for (cc = 0; cc < NoOfTimeFrames; cc ++)

   //StrongWeak
   string NewArray3 = ArrayResize(StrongWeak, NoOfTimeFrames);
   string NewArray4 = ArrayResize(StrongestCcy, NoOfTimeFrames);
   string NewArray5 = ArrayResize(WeakestCcy, NoOfTimeFrames);
   double NewArray6 = ArrayResize(StrongVal, NoOfTimeFrames);
   double NewArray7 = ArrayResize(WeakVal, NoOfTimeFrames);
   double NewArray8 = ArrayResize(PrevStrongVal, NoOfTimeFrames);
   double NewArray9 = ArrayResize(PrevWeakVal, NoOfTimeFrames);
   double NewArray10 = ArrayResize(ConstructedPair, NoOfTimeFrames);
   
   
   
   
}//End void SetUpArrays()

void CleanUpInputString()
{
   // Does any tidying up of the user inputs
   
   //Remove unwanted spaces
   InputString = StringTrimLeft(InputString);
   InputString = StringTrimRight(InputString);

   //Add final comma if ommitted by user
   if (StringSubstr(InputString, StringLen(InputString)-1) != ",") 
      InputString = StringConcatenate(InputString,",");
      
   
}//void CleanUpInputString

int CalculateParamsPassed()
{
   // Calculates the numbers of paramaters passed in LongMagicNumber and TradeComment.
   
   int Index = 0;//For searching NoTradePairs
   int LastIndex;//Points the the most recent Index
   int NoOfParams = 0;
   
   while(Index > -1)
   {
      Index = StringFind(InputString, ",",LastIndex);
      if (Index > -1)
      {
         NoOfParams++;
         LastIndex = Index+1;            
      }//if (Index > -1)
   }//while(int cc > -1)
      
  return(NoOfParams);
}//int CalculateParamsPassed()


//+------------------------------------------------------------------+
string StringRight(string str, int n=1)
//+------------------------------------------------------------------+
// Returns the rightmost N characters of STR, if N is positive
// Usage:    string x=StringRight("ABCDEFG",2)  returns x = "FG"
//
// Returns all but the leftmost N characters of STR, if N is negative
// Usage:    string x=StringRight("ABCDEFG",-2)  returns x = "CDEFG"
{
  if (n > 0)  return(StringSubstr(str,StringLen(str)-n,n));
  if (n < 0)  return(StringSubstr(str,-n,StringLen(str)-n));
  return("");
}


//+------------------------------------------------------------------+
int StringFindCount(string str, string str2)
//+------------------------------------------------------------------+
// Returns the number of occurrences of STR2 in STR
// Usage:   int x = StringFindCount("ABCDEFGHIJKABACABB","AB")   returns x = 3
{
  int c = 0;
  for (int i=0; i<StringLen(str); i++)
    if (StringSubstr(str,i,StringLen(str2)) == str2)  c++;
  return(c);
}


string StringUpper(string str)
//+------------------------------------------------------------------+
// Converts any lowercase characters in a string to uppercase
// Usage:    string x=StringUpper("The Quick Brown Fox")  returns x = "THE QUICK BROWN FOX"
{
  string outstr = "";
  string lower  = "abcdefghijklmnopqrstuvwxyz";
  string upper  = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  for(int i=0; i<StringLen(str); i++)  {
    int t1 = StringFind(lower,StringSubstr(str,i,1),0);
    if (t1 >=0)  
      outstr = outstr + StringSubstr(upper,t1,1);
    else
      outstr = outstr + StringSubstr(str,i,1);
  }
  return(outstr);
}  

//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
string StringTrim(string str)
//+------------------------------------------------------------------+
// Removes all spaces (leading, traing embedded) from a string
// Usage:    string x=StringUpper("The Quick Brown Fox")  returns x = "TheQuickBrownFox"
{
  string outstr = "";
  for(int i=0; i<StringLen(str); i++)  {
    if (StringSubstr(str,i,1) != " ")
      outstr = outstr + StringSubstr(str,i,1);
  }
  return(outstr);
}

//+------------------------------------------------------------------+
int StrToStringArray(string str, string &a[], string delim=",", string init="")  {
//+------------------------------------------------------------------+
// Breaks down a single string into string array 'a' (elements delimited by 'delim')
  for (int i=0; i<ArraySize(a); i++)
    a[i] = init;
  int z1=-1, z2=0;
  if (StringRight(str,1) != delim)  str = str + delim;
  for (i=0; i<ArraySize(a); i++)  {
    z2 = StringFind(str,delim,z1+1);
    a[i] = StringSubstr(str,z1+1,z2-z1-1);
    if (z2 >= StringLen(str)-1)   break;
    z1 = z2;
  }
  return(StringFindCount(str,delim));
}


//+------------------------------------------------------------------+
int ArrayLookupString(string str, string a[])   {
//+------------------------------------------------------------------+
 for (int i=0; i<ArraySize(a); i++)   {
   if (str == a[i])   return(i);
 }  
 return(-1);
} 

//+------------------------------------------------------------------+
double StrToNumber(string str)  {
//+------------------------------------------------------------------+
// Usage: strips all non-numeric characters out of a string, to return a numeric (double) value
//  valid numeric characters are digits 0,1,2,3,4,5,6,7,8,9, decimal point (.) and minus sign (-)
  int    dp   = -1;
  int    sgn  = 1;
  double num  = 0.0;
  for (int i=0; i<StringLen(str); i++)  {
    string s = StringSubstr(str,i,1);
    if (s == "-")  sgn = -sgn;   else
    if (s == ".")  dp = 0;       else
    if (s >= "0" && s <= "9")  {
      if (dp >= 0)  dp++;
      if (dp > 0)
        num = num + StrToInteger(s) / MathPow(10,dp);
      else
        num = num * 10 + StrToInteger(s);
    }
  }
  return(num*sgn);
}

int LoadRSvalues()  
{
  //This code courtesy of hanover. Many thanks David. You are a star.
  
  //Ccy[] holds the individual currency symbol
  //Tf[] holds the time frames
  //God knows where we go from here
  
  // Initialize array......
  for (i=0; i<8; i++)
    for (j=0; j<9; j++)
      for (k=0; k<99; k++)
         RSvalue[i][j][k] = 0;

         // Read data from Recent Strength export file into RSvalue array.......
         h = FileOpen(OutputFile,FILE_CSV|FILE_READ,'~');
         i=0; j=0; k=0;
         string prevtf = "";
         while (!FileIsEnding(h))     
         {
           StrToStringArray(FileReadString(h),arr);
           if (FileIsEnding(h))   break;
           if (arr[1] == "TF ")   
           {                                     // get ccy IDs from header record
             for (i=0; i<8; i++)  
             {
               ccy[i] = StringUpper(StringTrim(arr[i+3]));               
             }//for (i=0; i<8; i++)  
             continue;
           }//if (arr[1] == "TF ")   
           string currtf = StringUpper(StringTrimRight(arr[1]));
           j = ArrayLookupString(currtf,tf);
           if (j<0)     continue;                                    // unknown timeframe - should never happen
           if (currtf != prevtf)                                     // reset datapoint counter on change of timeframe
             k = 0;
           else
             k++;
           if (k>=99)   continue;                                    // max of 99 data points only
           for (i=0; i<8; i++)  
           {                                    // load array values for all currencies
             RSvalue[i][j][k] = StrToNumber(arr[i+3]);
             
           }//for (i=0; i<8; i++)  
           prevtf = currtf;  
         }//while (!FileIsEnding(h))     
  FileClose(h);
  return(0);
}//End int LoadRSvalues()  

void ReadHanover()
{
   //This function reads the output from the indi output file.
   LoadRSvalues();

/* Posted by hanover
If we use RSvalue[i][j][k], then
i = the currency
j = the timeframe
k = the datapoint#. Point #0 is rightmost point on the RS plot; point #1 is the second point from the right; 
point #2 is the third point from the right; and so on, up to the number of points being 
output (set by the NumPoints parameter in RS)

Hence, supposing you want to retrieve the value of the third datapoint for USD,H1, then (using the constants defined earlier) you could use the code:

double value = RSvalue[_USD][_H1][2];
*/
   //Find the strongest and weakest currency
   //Strongest
   double s, ps;//Strongest and previous strongest value
   double w, pw;//Weakest and previous weakest value


   //Currencies
   for (i = 0; i < ArraySize(StrongVal); i++)
   {
      StrongVal[i] = 0;//Initialize the strongest datapoint
      WeakVal[i] = 100000;//Initialize the weakest datapoint
   }//for (i = 0; i < ArraySize(StrongVal); i++)
   
   for (i = 0; i < ArraySize(ccy); i++)
   {
      //Timeframes
      for (j = 0; j < ArraySize(Tf); j++)
      {
         //Data point
         //Extract the timeframe - uses David's constants
         int DatapointTf;
         if (Tf[j] == "M1") DatapointTf = M1;
         if (Tf[j] == "M5") DatapointTf = M5;
         if (Tf[j] == "M15") DatapointTf = M15;
         if (Tf[j] == "M30") DatapointTf = M30;
         if (Tf[j] == "H1") DatapointTf = H1;
         if (Tf[j] == "H4") DatapointTf = H4;
         if (Tf[j] == "D1") DatapointTf = D1;
         if (Tf[j] == "W1") DatapointTf = W1;
         if (Tf[j] == "MN") DatapointTf = MN;
         
         for (k = 0; k < NumPoints; k++)
         {
            //Find the strongest datapoint on the current currency and timeframe
            if (RSvalue[i, DatapointTf, 0] > StrongVal[j])
            {
               StrongestCcy[j] = ccy[i];
               StrongVal[j] = RSvalue[i, DatapointTf, 0];
               PrevStrongVal[j] = RSvalue[i, DatapointTf, SlopeConfirmationCandles];
            }//if (RSvalue[i, j, k] > StrongVal[cc])
            
            //Find the seakest datapoint on the current currency and timeframe
            if (RSvalue[i, DatapointTf, 0] < WeakVal[j])
            {
               WeakestCcy[j] = ccy[i];
               WeakVal[j] = RSvalue[i, DatapointTf, 0];
               PrevWeakVal[j] = RSvalue[i, DatapointTf, SlopeConfirmationCandles];
            }//if (RSvalue[i, j, k] > StrongVal[cc])            
         }//for (k = 0; k <= NumPoints; k++)         
      }//for (j = 0; j < ArraySize(Tf); j++)
   }//for (i = 0; i < ArraySize(ccy); i++)
   //Alert("Strongest ", StrongestCcy[0], "  ", StrongVal[0], " Weakest ", WeakestCcy[0], "  ", WeakVal[0]);
   

   
   


}//End void ReadHanover()

double ReadStrength(string curr, string tf, int shift)
{
   /*
   Returns the strength of the individual currency referenced by the parameters:
      - curr is the currency
      - tf is the time frame
      - shift is how far back in time to look
   */

   //Extract the timeframe - uses David's constants
   int DatapointTf;
   if (tf == "M1") DatapointTf = M1;
   if (tf == "M5") DatapointTf = M5;
   if (tf == "M15") DatapointTf = M15;
   if (tf == "M30") DatapointTf = M30;
   if (tf == "H1") DatapointTf = H1;
   if (tf == "H4") DatapointTf = H4;
   if (tf == "D1") DatapointTf = D1;
   if (tf == "W1") DatapointTf = W1;
   if (tf == "MN") DatapointTf = MN;

   //Allign the curr param with David's constant
   int cc;
   if (curr == "AUD") cc = AUD;
   if (curr == "CAD") cc = CAD;
   if (curr == "CHF") cc = CHF;
   if (curr == "EUR") cc = EUR;
   if (curr == "GBP") cc = GBP;
   if (curr == "JPY") cc = JPY;
   if (curr == "NZD") cc = NZD;
   if (curr == "USD") cc = USD;
   
   return(RSvalue[cc, DatapointTf, shift]);
   
}//End double ReadStrength(string curr, string tf, int shift)

bool HanoverFilter(int type)
{
   //Returns true if the filter indicates sufficient strength/weakness in the pair.
   //Works by running through the tests and returning false if any of them fail. If all pass, the eventually
   //returns true.
   //Tests all fail if the two currencies have equal strength values

   //Read the strength values
   for (int cc = 0; cc < ArraySize(Tf); cc++)
   {
      //First filter. Compare the strength over the chosen time frames
      double strength1 = ReadStrength(Ccy1, Tf[cc], 0);
      double strength2 = ReadStrength(Ccy2, Tf[cc], 0);
      if (SlopeConfirmationCandles > 0) 
      {
         double prevstrength1 = ReadStrength(Ccy1, Tf[cc], SlopeConfirmationCandles);
         double prevstrength2 = ReadStrength(Ccy2, Tf[cc], SlopeConfirmationCandles);   
      }//if (SlopeCandles[cc] > 0)    

     
      //EA is looking to buy. 
      if (type == OP_BUY)
      {
         //First currency must be the strongest
         if (strength1 <= strength2) return(false);

         //Slope must be rising
         if (SlopeConfirmationCandles > 0 && prevstrength1 >= prevstrength2) return(false);
         
         //Threshold. First currency must be above StrongThreshold. Second currency must be below WeakThreshopld
         if (StrongThreshold > 0 && WeakThreshold > 0)
         {
            if (strength1 < StrongThreshold || strength2 > WeakThreshold) return(false);
         }//if (StrongThreshold > 0 && WeakThreshold > 0)
         
      }//if (type == OP_BUY)
      
      //EA is looking to sell, so first currency must be the weakest
      if (type == OP_SELL && strength1 >= strength2) return(false);
      
      //EA is looking to sell. 
      if (type == OP_SELL)
      {
         //First currency must be the weakest
         if (strength1 >= strength2) return(false);

         //Slope must be falling
         if (SlopeConfirmationCandles > 0 && prevstrength1 <= prevstrength2) return(false);
         
         //Threshold. First currency must be below WeakThreshold. Second currency must be above StrongThreshopld
         if (StrongThreshold > 0 && WeakThreshold > 0)
         {
            if (strength1 > WeakThreshold || strength2 < StrongThreshold) return(false);
         }//if (StrongThreshold > 0 && WeakThreshold > 0)

      }//if (type == OP_BUY)
      
      
         
         
         
   }//for (int cc = 0; cc < ArraySize(Tf); cc++)

   

   //Got this far, so all tests have passed.
   return(true);

}//End bool HanoverFilter()


//End Hanover module
////////////////////////////////////////////////////////////////////////////////////////////////

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

   static bool ThereWasATradeOpen;
   static bool TradeExists;
   
   AccEquity = AccountEquity(); 
   
   if (OrdersTotal() == 0)
   {
      TicketNo = -1;
      ForceTradeClosure = false;
   }//if (OrdersTotal() == 0)

   if (ForceTradeClosure) 
   {
      CloseAllTrades();
      return;
   }//if (ForceTradeClosure) 

   if (UseHanover)
   {
      //Read the indi once a minute
      if (ReadBars != iBars(NULL, PERIOD_M1) && UseHanover)
      {
         ReadBars = iBars(NULL, PERIOD_M1);
         ReadHanover();
      }//if (ReadBars != iBars(NULL, PERIOD_M1)
   }//if (UseHanover)
   

    if(Open_candleClose) {
      if (OldBars != Bars)
         {  
            ReadIndicatorValues();
            //LookForInstantClosure();
            OldBars = Bars;
         }
   } else {
       ReadIndicatorValues();
       
   }
   LookForInstantClosure();
   
   /*
   if(Close_candleClose) {
      if (OldBars != Bars)
         {  
            LookForInstantClosure();
            OldBars = Bars;
         }
   } else {
       LookForInstantClosure();
   }
   */
   
   
   

   //Delete orphaned tp/sl lines
   static int M15Bars;
   if (M15Bars != iBars(NULL, PERIOD_M15) )
   {
      M15Bars = iBars(NULL, PERIOD_M15);
      DeleteOrphanTpSlLines();
   }//if (M15Bars != iBars(NULL, PERIOD_M15)
   
      
   ///////////////////////////////////////////////////////////////////////////////////////////////
   //Find open trades.
   //Will not normally need both routines.
   CountOpenTrades();
   TradeExists = DoesTradeExist();
   if (TradeExists)
   {
      if (OrderProfit() > 0) TradeManagementModule();
      LookForTradeClosure();
   }//if (TradeExists)

   ///////////////////////////////////////////////////////////////////////////////////////////////
   
   //Recovery
   if (UseRecovery)
   {
      if (OpenTrades >= Start_Recovery_at_trades) RecoveryInProgress = true;
      
      /*
      I have moved this to SendSingleTrade.
      if (RecoveryInProgress)
      {
         if (ObjectFind(takeprofitlinename) > -1) ObjectDelete(takeprofitlinename);
         RecoveryModule();
      }//if (RecoveryInProgress)
      */
      
      //Replace accidentally deleted be line
      if (RecoveryInProgress && ObjectFind(breakevenlinename) == -1)
      {
         RecoveryModule();      
      }//if (RecoveryInProgress && ObjectFind(breakevenlinename) == -1)
      
      //Recovery trailing sl
      if (RecoveryInProgress && UseRecoveryTrailingStop)
      {
         RecoveryCandlesticktrailingStop();     
      }//if (RecoveryInProgress && UseRecoveryTrailingStop)
      
      
   }//if (UseRecovery)

   //Replace deleted reentry line
   if (RecoveryInProgress && ObjectFind(reentrylinename) == -1)
   {
      ReplaceReEntryLine();
   }//if (RecoveryInProgress && ObjectFind(reentrylinename) == -1)

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////////////////////////////////
   
   //Post trade closure Sleep
   if (!TradeExists && ThereWasATradeOpen)
   {
      ThereWasATradeOpen = false;
      Sleep(1000);//1 second: 1000 * 60 = 1 minute: 1000 * 60 * 60 = 1 hour
   }//if (!TradeExists && ThereWasATradeOpen)
   
 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //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
   EnoughMargin = true;//For user display
   MarginMessage = "";
   if (UseScoobsMarginCheck && OpenTrades > 0)
   {
      if(AccountMargin() > (AccountFreeMargin()/100)) 
      {
         MarginMessage = "There is insufficient margin to allow trading. You might want to turn off the UseScoobsMarginCheck input.";
         DisplayUserFeedback();
         return;
      }//if(AccountMargin() > (AccountFreeMargin()/100)) 
      
   }//if (UseScoobsMarginCheck)


   if (UseForexKiwi && AccountMargin() > 0)
   {
      
      double ml = NormalizeDouble(AccountEquity() / AccountMargin() * 100, 2);
      if (ml < FkMinimumMarginPercent)
      {
         MarginMessage = StringConcatenate("There is insufficient margin percent to allow trading. ", DoubleToStr(ml, 2), "%");
         DisplayUserFeedback();
         return;
      }//if (ml < FkMinimumMarginPercent)
      
   }//if (UseForexKiwi && AccountMargin() > 0)

   ///////////////////////////////////////////////////////////////////////////////////////////////         
   //Trading
   if (UseCaterpillar && !StopTrading) StartCaterpillar();
      
   if (TicketNo == -1 && !StopTrading)
   {
      //Trend detection      
      if (UseTrendDetection) TrendDetectionModule();
      if (!UseTrendDetection && RisingTrend) trend = up;
      if (!UseTrendDetection && FallingTrend) trend = down;
      
   
      LookForTradingOpportunities();
   }//if (TicketNo == -1)
   ///////////////////////////////////////////////////////////////////////////////////////////////      

   DisplayUserFeedback();
   
//----
   return(0);
}
//+------------------------------------------------------------------+