//+-------------------------------------------------------------------+
//|                                jor and the pal he met on hols.mq4 |
//|                                  Copyright © 2009, Steve Hopwood  |
//|                              http://www.hopwood3.freeserve.co.uk  |
//+-------------------------------------------------------------------+
#property copyright "Copyright © 2009, Steve Hopwood"
#property link      "http://www.hopwood3.freeserve.co.uk"
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"

#define  up "Up"
#define  down "Down"
#define  none "None"
#define  up "Up"
#define  down "Down"
#define  none "None"
#define  buy "Buy"
#define  sell "Sell"
#define  ranging "Ranging"

/*

This pm from jor sums up neatly what this jor does:

"Steve I first wanted to thank you for all your great contributions to FF and secondly I was wondering if I could have 
just a few minutes of your time to run an udea U have for an EA by you. I trade out of the 15 minute chart with 
moving average but the indicator I use is the Pwr Indicator. When it turns green I go long and short when it goes red. 
The simplicity of the system is great and the results are even better, the thing is I cant stay away 24 hours a day and 
trade this all day long and this is where an EA based on that will be huge. 
I only trade 4 instruments, AUDUSD, EURUSD, USDCHF and Crude Oil. If you want me to I can easily send you a picture of 
the setup in the 15 minute chart, yesterday it caught the entire 700 pip up move and today is currently up over 300 ticks 
in Crude Oil. Once again I would love to work this out with you, I will greatly appreciatte it.
Thanks in advance and looking forward to your response"

This EA is the same, but uses the Cci_T3_2 indi that jor picked up from a pal he met on holiday

Matt Kennel has provided the code for bool O_R_CheckForHistory(int ticket). Cheers Matt, You are a star.



Code for adding debugging Sleep
Alert("G");
int x = 0;
while (x == 0) Sleep(100);

FUNCTIONS LIST
int init()
int start()

----Trading----

void LookForTradingOpportunities()

bool IsTradingAllowed()
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
bool DoesTradeExist()
bool CheckTradingTimes()
double CalculateLotSize(double price1, double price1)
bool LookForTradeClosure()

----Trade direction----
void DrawLines()
void GetPivot()
void DrawPivot(double pivot)

----Trend detection module----
void TrendDetectionModule()

----Matt's Order Reliable library code
bool O_R_CheckForHistory(int ticket) Cheers Matt, You are a star.
void O_R_Sleep(double mean_time, double max_time)

----Indicator readings----
void ReadIndicatorValues()
void GetCci()
double GetMa(int tf, int period, int mashift, int method, int ap, int shift)

----Trade management module----
void TradeManagementModule()
void BreakEvenStopLoss()
bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop )
void JumpingStopLoss() 
void HiddenTakeProfit()
void HiddenStopLoss()
void TrailingStopLoss()



*/
//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  gen="----General inputs----";
extern double  Lot=0.1;//Leave at zero for the bot to calculate lot size by risk
extern int     TakeProfit=20;
extern int     StopLoss=0;//Only included as an option. Users should not set this as the bot exits a failing trade on a signal change
extern int     MagicNumber=956;
extern string  TradeComment="jor and his pal";
extern bool    CriminalIsECN=false;//Deleted extern as it should not be needed here.
extern double  MaxSpread=40;

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 = 8;
extern  int    end_hourm = 12;
extern string  Trade_Hours_E= "Evening Hours 12-24";
extern  int    start_houre = 12;
extern  int    end_houre = 16;

//Cci
extern string  cci="----Cci inputs----";
extern int     CCI_Period=168;
extern int     T3_Period=34;
extern double  b=0.618;

//Hanover
extern string  hm="----Hanover module----";
extern bool    UseHanover=true;
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   
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

//Trend detection defaults to off because this is not a part of jor's original strategy
extern string  tdm="----Trend detection module----";
extern bool    RisingTrend=false;
extern bool    FallingTrend=false;
extern bool    UseTrendDetection=false;

//RSI. >55 is trending up. < 45 is trending down
extern string  trsi="Rsi trend detection";
extern bool    UseRsiTrendDetection=false;
extern int     RsiTdTf=1440;
extern int     RsiTdPeriod=20;
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;

//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 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

//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;

//Single, much longer term MA. Rising MA the trend is up and vice-versa
extern string  sima="Single moving average";
extern bool    UseMaTrendDetection=false;
extern int     SingleMaTdTF=10080;//Time frame defaults to W1
extern int     SingleMaTdPeriod=10;
extern int     SingleMaTdShift=0;//The MA Shift input
extern string  stmame="Method: 0=sma; 1=ema; 2=smma;  3=lwma";
extern int     SingleMaTdMethod=0;
extern string  stmaap="Applied price: 0=Close; 1=Open; 2=High";
extern string  stmaap1="3=Low; 4=Median; 5=Typical; 6=Weighted";
extern int     SingleMaTdAppliedPrice=0;
extern int     CompareWithCandles=5;
extern int     MinimumAcceptableRise=300;//Pure guesswork to make sure there has bee a decent movement in the ma

//All management features default to off because this is not a part of jor's original strategy
extern string  tmm="----Trade management module----";
extern string  BE="Break even settings";
extern bool    BreakEven=false;
extern int     BreakEvenPips=25;
extern int     BreakEvenProfit=10;
extern bool    HideBreakEvenStop=false;
extern int     PipsAwayFromVisualBE=5;
extern string  cts="----Candlestick trailing stop----";
extern bool    UseCandlestickTrailingStop=false;
extern string  JSL="Jumping stop loss settings";
extern bool    JumpingStop=false;
extern int     JumpingStopPips=50;
extern bool    AddBEP=true;
extern bool    JumpAfterBreakevenOnly=false;
extern bool    HideJumpingStop=false;
extern int     PipsAwayFromVisualJS=10;
extern string  TSL="Trailing stop loss settings";
extern bool    TrailingStop=false;
extern int     TrailingStopPips=50;
extern bool    HideTrailingStop=false;
extern int     PipsAwayFromVisualTS=10;
extern bool    TrailAfterBreakevenOnly=false;
extern bool    StopTrailAtPipsProfit=false;
extern int     StopTrailPips=0;
extern string  hsl1="Hidden stop loss settings";
extern bool    HideStopLossEnabled=false;
extern int     HiddenStopLossPips=20;
extern string  htp="Hidden take profit settings";
extern bool    HideTakeProfitEnabled=false;
extern int     HiddenTakeProfitPips=20;

extern string  mis="----Odds and ends----";
extern bool    ShowManagementAlerts=true;
extern int     DisplayGapSize=30;

//Matt's O-R stuff
int 	         O_R_Setting_max_retries 	= 10;
double 	      O_R_Setting_sleep_time 		= 4.0; /* seconds */
double 	      O_R_Setting_sleep_max 		= 15.0; /* seconds */

//Trading variables
int            TicketNo, 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;
bool           TradeExists;

//Trend detection
string         trend;
double         TrendRsiVal;//Rsi
double         FastTrendMaVal, SlowTrendMaVal;//2 MA trend
double         SingleTrendMaVal, PrevSingleTrendMaVal;//Single trend ma

//NB V10 Trend detection/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
   
//Cci
string         CciTrend;
double         CciVal, CciValUp, CciValDown;


//Margin status display
bool           EnoughMargin;
string         MarginMessage;


//Misc
string         Gap, ScreenMessage;
int            OldBars, OldCstBars;
string         PipDescription=" pips";
bool           ForceTradeClosure;
bool           InvalidStopError;//For dealing with invalid stops

void DisplayUserFeedback()
{
   
   if (IsTesting() && !IsVisualMode()) return;

   ScreenMessage = "";
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, TimeToStr(TimeLocal(), TIME_DATE|TIME_MINUTES|TIME_SECONDS), NL );
   /*
   //Code for time to bar-end display from Candle Time by Nick Bilak
   double i;
   int m,s,k;
   m=Time[0]+Period()*60-CurTime();
   i=m/60.0;
   s=m%60;
   m=(m-m%60)/60;
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, m + " minutes " + s + " seconds left to bar end", NL);
   */
      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Lot size: ", Lot, " (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, ": Spread = ", MarketInfo(Symbol(), MODE_SPREAD), 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
   
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Cci direction: ", CciTrend, NL);
   
      if (UseHanover)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
      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);

   
   if (MarginMessage != "") ScreenMessage = StringConcatenate(ScreenMessage,NL, Gap, MarginMessage, NL);

   
   Comment(ScreenMessage);


}//void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----

   //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;
   BreakEvenPips*= multiplier;
   BreakEvenProfit*= multiplier;
   PipsAwayFromVisualBE*= multiplier;
   JumpingStopPips*= multiplier;
   PipsAwayFromVisualJS*= multiplier;
   TrailingStopPips*= multiplier;
   PipsAwayFromVisualTS*= multiplier;
   StopTrailPips*= multiplier;
   HiddenStopLossPips*= multiplier;
   HiddenTakeProfitPips*= multiplier;
   
   Gap="";
   if (DisplayGapSize > 0)
   {
      for (int cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }//if (DisplayGapSize >0)
   
   //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)

   //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 > -1) CriminalIsECN = true;
   OldBars = Bars;
   if (TradeComment == "") TradeComment = " ";
   //OldBars = Bars;
   ReadIndicatorValues();
   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);
}



bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
{
   
   
   int slippage = 10;
   if (Digits == 3 || Digits == 5) slippage = 100;
   
   color col = Red;
   if (type == OP_BUY || type == OP_BUYSTOP) col = Green;
   
   int expiry = 0;
   //if (SendPendingTrades) expiry = TimeCurrent() + (PendingExpiryMinutes * 60);

   if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, expiry, col);
   
   
   //Is a 2 stage criminal
   if (CriminalIsECN)
   {
      bool result;
      int err;
      ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, expiry, col);
      if (ticket > 0)
      {
	     
	     if (take > 0 && stop > 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), stop, take, OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL/TP  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take > 0 && stop > 0)
      
	     if (take != 0 && stop == 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take == 0 && stop != 0)

        if (take == 0 && stop != 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           result = OrderModify(ticket, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
           if (!result)
           {
               err=GetLastError();
               Print(Symbol(), " SL  order modify failed with error(",err,"): ",ErrorDescription(err));               
           }//if (!result)			  
        }//if (take == 0 && stop != 0)

      }//if (ticket > 0)
        
      
      
   }//if (CriminalIsECN)
   
   //Error trapping for both
   if (ticket < 0)
   {
      string stype;
      if (type == OP_BUY) stype = "OP_BUY";
      if (type == OP_SELL) stype = "OP_SELL";
      if (type == OP_BUYLIMIT) stype = "OP_BUYLIMIT";
      if (type == OP_SELLLIMIT) stype = "OP_SELLLIMIT";
      if (type == OP_BUYSTOP) stype = "OP_BUYSTOP";
      if (type == OP_SELLSTOP) stype = "OP_SELLSTOP";
      err=GetLastError();
      Alert(Symbol(), " 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)  
   
   
   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)

bool DoesTradeExist()
{
   
   TicketNo = -1;
   
   if (OrdersTotal() == 0) return(false);
   
   for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      
      if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
      {
         TicketNo = OrderTicket();
         return(true);         
      }//if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)

   return(false);

}//End bool DoesTradeExist()



bool IsTradingAllowed()
{
   //Returns false if any of the filters should cancel trading, else returns true to allow trading
   
        
   //Maximum spread
   if (MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread) return(false);
 
   
   return(true);


}//End bool IsTradingAllowed()


void LookForTradingOpportunities()
{


   RefreshRates();
   double take, stop, price;
   int type;
   bool SendTrade;
   double SendLot = Lot;
   double StopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point;
   
   //Check filters
   if (!IsTradingAllowed() ) return;
   
   double spread = MarketInfo(Symbol(), MODE_SPREAD) * Point;
   
   //The market direction, candle size and higher/lower hi-lo have all been checked prior to reaching this point, so
   //all that is needed is to enter in the direction of the CciTrend

   //Trend
   string Ttrend = trend;//Temp trend string

   //Long 
   if (!UseTrendDetection) Ttrend = up;//Set up a dummy if the user is not using the trend stuff
   if (CciTrend == up && Ttrend == up)
   {
      if (UseHanover && !HanoverFilter(OP_BUY) ) return;
      price = Ask;
      type = OP_BUY;
      if (TakeProfit > 0) take = NormalizeDouble(price + (TakeProfit * Point), Digits);
      if (StopLoss > 0) stop = NormalizeDouble(price - (StopLoss * Point), Digits);
      SendTrade = true;
   }//if (CciTrend == up && TradeLong)
   
   
   //Short
   if (!UseTrendDetection) Ttrend = down;//Set up a dummy if the user is not using the trend stuff
   if (CciTrend == down && Ttrend == down)
   {
      if (UseHanover && !HanoverFilter(OP_SELL) ) return;
      price = Bid;
      type = OP_SELL;
      if (TakeProfit > 0) take = NormalizeDouble(price - (TakeProfit * Point), Digits);
      if (StopLoss > 0) stop = NormalizeDouble(price + (StopLoss * Point), Digits);
      SendTrade = true;      
   }//if (direction == down && TradeShort)
   

   double OldBid;//For comparison when making multiple tries at sending a trade, to avoid merely trying once a second without a quote
      
   if (SendTrade)
   {
         
      bool result = SendSingleTrade(type, TradeComment, SendLot, price, stop, take);
         
   }//if (SendTrade)
   
   //Actions when trade send succeeds
   if (SendTrade && result)
   {
   
   }//if (result)
   
   //Actions when trade send fails
   if (SendTrade && !result)
   {
      OldBars = 0;
   }//if (!result)
   
   

}//void LookForTradingOpportunities()


////////////////////////////////////////////////////////////////////////////////////////////////
//Indicator module




/*
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)
*/




//End Indicator module
////////////////////////////////////////////////////////////////////////////////////////////////


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()


//=============================================================================
//                           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)


///////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////
//INDICATOR MODULE


void GetCci()
{
   //Reads the Cci custom indi and selects a CciTrend based on the return.
   
   CciVal = iCustom(NULL, 0, "CCI_T3_2", CCI_Period, T3_Period, b, 0, 1);
   CciValUp = iCustom(NULL, 0, "CCI_T3_2", CCI_Period, T3_Period, b, 1, 1);
   CciValDown = iCustom(NULL, 0, "CCI_T3_2", CCI_Period, T3_Period, b, 2, 1);
   
   CciTrend = none;
   
   if (CciValUp > 0) CciTrend = up;
   if (CciValDown < 0) CciTrend = down;
   
   //Get confirmation. 
   double PrevCciVal;
   
   //Uptrend. Previous candle should have a falling Cci
   if (CciTrend == up)
   {
      double PrevCciValDown = iCustom(NULL, 0, "CCI_T3_2", CCI_Period, T3_Period, b, 2, 2);
      if (PrevCciValDown == 0)
      {
         CciTrend = none;
      }//if (PrevCciValDown == 0)
   
   }//if (CciTrend == up)
   
  
   //Downtrend. Previous candle should have a rising Cci
   if (CciTrend == down)
   {
      double PrevCciValUp = iCustom(NULL, 0, "CCI_T3_2", CCI_Period, T3_Period, b, 1, 2);
      if (PrevCciValUp == 0)
      {
         CciTrend = none;
      }//if (PrevCciValDown == 0)
      
   }//if (CciTrend == down)
   
   
}//End void GetCci()

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)


void ReadIndicatorValues()
{

   GetCci();
   
}//void ReadIndicatorValues()

//END INDICATOR MODULE
///////////////////////////////////////////////////////////////////////////////////////////////////////

bool LookForTradeClosure()
{
   //Close the trade if the new candle opens inside the bands
   
   if (!OrderSelect(TicketNo, SELECT_BY_TICKET) ) return(true);
   if (OrderSelect(TicketNo, SELECT_BY_TICKET) && OrderCloseTime() > 0) return(true);
 
 
  
   bool success = true;
   
   bool CloseTrade;
   double PrevCciVal;
   
   if (OrderType() == OP_BUY)
   {
      if (CciTrend == down) CloseTrade = true;
   }//if (OrderType() == OP_BUY)
   
   
   if (OrderType() == OP_SELL)
   {
      if (CciTrend == up) CloseTrade = true;

   }//if (OrderType() == OP_SELL)
   
   if (CloseTrade)
   {
      bool result = CloseTrade(TicketNo);
   

      //Actions when trade close succeeds
      if (result)
      {
         TicketNo = -1;
         TradeExists = false;
      }//if (!result)
   


      //Actions when trade close fails
      if (!result)
      {
         success = false;
      }//if (!result)
   

   }//if (CloseTrade)
   
   return(success);
   
}//void LookForTradeClosure()

bool CloseTrade(int ticket)
{   
   while(IsTradeContextBusy()) Sleep(100);
   bool result = OrderClose(ticket, OrderLots(), OrderClosePrice(), 1000, CLR_NONE);

   //Actions when trade send succeeds
   if (result)
   {
      return(true);
   }//if (result)
   
   //Actions when trade send fails
   if (!result)
   {
      OldBars = 0;
   }//if (!result)
   

}//End bool CloseTrade(ticket)

///////////////////////////////////////////////////////////////////////////////////////////////////////
//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.
   */
   if (UseMaTrendDetection)
   {
      SingleTrendMaVal = GetMa(SingleMaTdTF, SingleMaTdPeriod, SingleMaTdShift, SingleMaTdMethod, SingleMaTdAppliedPrice, 0);   
      PrevSingleTrendMaVal = GetMa(SingleMaTdTF, SingleMaTdPeriod, SingleMaTdShift, SingleMaTdMethod, SingleMaTdAppliedPrice, CompareWithCandles);   
      if (SingleTrendMaVal > PrevSingleTrendMaVal &&  SingleTrendMaVal - PrevSingleTrendMaVal >= (MinimumAcceptableRise * Point) ) trend = up;
      if (SingleTrendMaVal < PrevSingleTrendMaVal &&  PrevSingleTrendMaVal - SingleTrendMaVal >= (MinimumAcceptableRise * Point) ) trend = down;      
   }//if (UseMaTrendDetection)
   
   //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)
   {
      
      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 (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 (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
///////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////
//TRADE MANAGEMENT MODULE

bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop )
{
   //Reusable code that can be called by any of the stop loss manipulation routines except HiddenStopLoss().
   //Checks to see if the market has hit the hidden sl and attempts to close the trade if so. 
   //Returns true if trade closure is successful, else returns false
   
   //Check buy trade
   if (type == OP_BUY)
   {
      double sl = NormalizeDouble(stop + (iPipsAboveVisual * Point), Digits);
      if (Bid <= sl)
      {
         while(IsTradeContextBusy()) Sleep(100);
         bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
         if (result)
         {
            if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());      
         }//if (result)
         else
         {
            int err=GetLastError();
            if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
         }//else
      }//if (Bid <= sl)  
   }//if (type = OP_BUY)
   
   //Check buy trade
   if (type == OP_SELL)
   {
      sl = NormalizeDouble(stop - (iPipsAboveVisual * Point), Digits);
      if (Ask >= sl)
      {
         while(IsTradeContextBusy()) Sleep(100);
         result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
         if (result)
         {
            if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());      
         }//if (result)
         else
         {
            err=GetLastError();
            if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
         }//else
      }//if (Ask >= sl)  
   }//if (type = OP_SELL)
   

}//End bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop )


void BreakEvenStopLoss() // Move stop loss to breakeven
{

   //Check hidden BE for trade closure
   if (HideBreakEvenStop)
   {
      bool TradeClosed = CheckForHiddenStopLossHit(OrderType(), PipsAwayFromVisualBE, OrderStopLoss() );
      if (TradeClosed) return;//Trade has closed, so nothing else to do
   }//if (HideBreakEvenStop)


   bool result;

   if (OrderType()==OP_BUY)
         {
            if (Bid >= OrderOpenPrice () + (Point*BreakEvenPips) && 
                OrderStopLoss()<OrderOpenPrice())
            {
               while(IsTradeContextBusy()) Sleep(100);
               result = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(OrderOpenPrice()+(BreakEvenProfit*Point), Digits),OrderTakeProfit(),0,CLR_NONE);
               if (result && ShowManagementAlerts==true) Alert("Breakeven set on ", OrderSymbol(), " ticket no ", OrderTicket());
               Print("Breakeven set on ", OrderSymbol(), " ticket no ", OrderTicket());
               if (!result)
               {
                  int err=GetLastError();
                  if (ShowManagementAlerts==true) Alert("Setting of breakeven SL ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                  Print("Setting of breakeven SL ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
               }//if !result && ShowManagementAlerts)      
               //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
               //{
               //   bool PartCloseSuccess = PartCloseTradeFunction();
               //   if (!PartCloseSuccess) SetAGlobalTicketVariable();
               //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
            }
   	   }               			         
          
   if (OrderType()==OP_SELL)
         {
           if (Ask <= OrderOpenPrice() - (Point*BreakEvenPips) &&
              (OrderStopLoss()>OrderOpenPrice()|| OrderStopLoss()==0)) 
            {
               while(IsTradeContextBusy()) Sleep(100);
               result = OrderModify(OrderTicket(),OrderOpenPrice(),NormalizeDouble(OrderOpenPrice()-(BreakEvenProfit*Point), Digits),OrderTakeProfit(),0,CLR_NONE);
               if (result && ShowManagementAlerts==true) Alert("Breakeven set on ", OrderSymbol(), " ticket no ", OrderTicket());
               Print("Breakeven set on ", OrderSymbol(), " ticket no ", OrderTicket());
               if (!result && ShowManagementAlerts)
               {
                  err=GetLastError();
                  if (ShowManagementAlerts==true) Alert("Setting of breakeven SL ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                  Print("Setting of breakeven SL ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
               }//if !result && ShowManagementAlerts)      
              //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
              // {
              //    PartCloseSuccess = PartCloseTradeFunction();
              //    if (!PartCloseSuccess) SetAGlobalTicketVariable();
              // }//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
            }    
         }
      

} // End BreakevenStopLoss sub

void JumpingStopLoss() 
{
   // Jump sl by pips and at intervals chosen by user .
   // Also carry out partial closure if the user requires this

   // Abort the routine if JumpAfterBreakevenOnly is set to true and be sl is not yet set
   if (JumpAfterBreakevenOnly && OrderType()==OP_BUY)
   {
      if(OrderStopLoss()<OrderOpenPrice()) return(0);
   }
  
   if (JumpAfterBreakevenOnly && OrderType()==OP_SELL)
   {
      if(OrderStopLoss()>OrderOpenPrice() || OrderStopLoss() == 0 ) return(0);
   }
  
   double sl=OrderStopLoss(); //Stop loss

   if (OrderType()==OP_BUY)
   {
      //Check hidden js for trade closure
      if (HideJumpingStop)
      {
         bool TradeClosed = CheckForHiddenStopLossHit(OP_BUY, PipsAwayFromVisualJS, OrderStopLoss() );
         if (TradeClosed) return;//Trade has closed, so nothing else to do
      }//if (HideJumpingStop)
      
      // First check if sl needs setting to breakeven
      if (sl==0 || sl<OrderOpenPrice())
      {
         if (Ask >= OrderOpenPrice() + (JumpingStopPips*Point))
         {
            sl=OrderOpenPrice();
            if (AddBEP==true) sl=sl+(BreakEvenProfit*Point); // If user wants to add a profit to the break even
            while(IsTradeContextBusy()) Sleep(100);
            bool result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
            if (result)
            {
               if (ShowManagementAlerts==true) Alert("Jumping stop set at breakeven ",sl, " ", OrderSymbol(), " ticket no ", OrderTicket());
               Print("Jumping stop set at breakeven: ", OrderSymbol(), ": SL ", sl, ": Ask ", Bid);
               //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
               //{
                  //bool PartCloseSuccess = PartCloseTradeFunction();
                  //if (!PartCloseSuccess) SetAGlobalTicketVariable();
               //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
            }//if (result)
            if (!result)
            {
               int err=GetLastError();
               if (ShowManagementAlerts) Alert(OrderSymbol(), "Ticket ", OrderTicket(), " buy trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
               Print(OrderSymbol(), " buy trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
            }//if (!result)
             
            return(0);
         }//if (Ask >= OrderOpenPrice() + (JumpingStopPips*Point))
      } //close if (sl==0 || sl<OrderOpenPrice()

  
      // Increment sl by sl + JumpingStopPips.
      // This will happen when market price >= (sl + JumpingStopPips)
      if (Bid>= sl + ((JumpingStopPips*2)*Point) && sl>= OrderOpenPrice())      
      {
         sl=sl+(JumpingStopPips*Point);
         while(IsTradeContextBusy()) Sleep(100);
         result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
         if (result)
         {
            if (ShowManagementAlerts==true) Alert("Jumping stop set at ",sl, " ", OrderSymbol(), " ticket no ", OrderTicket());
            Print("Jumping stop set: ", OrderSymbol(), ": SL ", sl, ": Ask ", Ask);
            //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
            //{
               //PartCloseSuccess = PartCloseTradeFunction();
               //if (!PartCloseSuccess) SetAGlobalTicketVariable();
            //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
         }//if (result)
         if (!result)
         {
            err=GetLastError();
            if (ShowManagementAlerts) Alert(OrderSymbol(), " buy trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
            Print(OrderSymbol(), " buy trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
         }//if (!result)
             
      }// if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())      
   }//if (OrderType()==OP_BUY)
   
   if (OrderType()==OP_SELL)
   {
      //Check hidden js for trade closure
      if (HideJumpingStop)
      {
         TradeClosed = CheckForHiddenStopLossHit(OP_SELL, PipsAwayFromVisualJS, OrderStopLoss() );
         if (TradeClosed) return;//Trade has closed, so nothing else to do
      }//if (HideJumpingStop)
            
      // First check if sl needs setting to breakeven
      if (sl==0 || sl>OrderOpenPrice())
      {
         if (Ask <= OrderOpenPrice() - (JumpingStopPips*Point))
         {
            sl = OrderOpenPrice();
            if (AddBEP==true) sl=sl-(BreakEvenProfit*Point); // If user wants to add a profit to the break even
            while(IsTradeContextBusy()) Sleep(100);
            result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
            if (result)
            {
               //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
               //{
                 // PartCloseSuccess = PartCloseTradeFunction();
                  //if (!PartCloseSuccess) SetAGlobalTicketVariable();
               //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
            }//if (result)
            if (!result)
            {
               err=GetLastError();
               if (ShowManagementAlerts) Alert(OrderSymbol(), " sell trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
               Print(OrderSymbol(), " sell trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
            }//if (!result)
             
            return(0);
         }//if (Ask <= OrderOpenPrice() - (JumpingStopPips*Point))
      } // if (sl==0 || sl>OrderOpenPrice()
   
      // Decrement sl by sl - JumpingStopPips.
      // This will happen when market price <= (sl - JumpingStopPips)
      if (Bid<= sl - ((JumpingStopPips*2)*Point) && sl<= OrderOpenPrice())      
      {
         sl=sl-(JumpingStopPips*Point);
         while(IsTradeContextBusy()) Sleep(100);
         result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
         if (result)
         {
            if (ShowManagementAlerts==true) Alert("Jumping stop set at ",sl, " ", OrderSymbol(), " ticket no ", OrderTicket());
            Print("Jumping stop set: ", OrderSymbol(), ": SL ", sl, ": Ask ", Ask);
            //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
            //{
              // PartCloseSuccess = PartCloseTradeFunction();
               //if (!PartCloseSuccess) SetAGlobalTicketVariable();
            //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
         }//if (result)          
         if (!result)
         {
            err=GetLastError();
            if (ShowManagementAlerts) Alert(OrderSymbol(), " sell trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
            Print(OrderSymbol(), " sell trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
         }//if (!result)

      }// close if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())         
   }//if (OrderType()==OP_SELL)

} //End of JumpingStopLoss sub

void HiddenStopLoss()
{
   //Called from ManageTrade if HideStopLossEnabled = true


   //Should the order close because the stop has been passed?
   //Buy trade
   if (OrderType() == OP_BUY)
   {
      double sl = NormalizeDouble(OrderOpenPrice() - (HiddenStopLossPips * Point), Digits);
      if (Bid <= sl)
      {
         while(IsTradeContextBusy()) Sleep(100);
         bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
         if (result)
         {
            if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());      
         }//if (result)
         else
         {
            int err=GetLastError();
            if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
         }//else
      }//if (Bid <= sl)      
   }//if (OrderType() == OP_BUY)
   
   //Sell trade
   if (OrderType() == OP_SELL)
   {
      sl = NormalizeDouble(OrderOpenPrice() + (HiddenStopLossPips * Point), Digits);
      if (Ask >= sl)
      {
         while(IsTradeContextBusy()) Sleep(100);
         result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
         if (result)
         {
            if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());      
         }//if (result)
         else
         {
            err=GetLastError();
            if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
         }//else
      }//if (Ask >= sl)   
   }//if (OrderType() == OP_SELL)
   

}//End void HiddenStopLoss()

void HiddenTakeProfit()
{
   //Called from ManageTrade if HideStopLossEnabled = true


   //Should the order close because the stop has been passed?
   //Buy trade
   if (OrderType() == OP_BUY)
   {
      double tp = NormalizeDouble(OrderOpenPrice() + (HiddenTakeProfitPips * Point), Digits);
      if (Bid >= tp)
      {
         while(IsTradeContextBusy()) Sleep(100);
         bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
         if (result)
         {
            if (ShowManagementAlerts==true) Alert("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());      
         }//if (result)
         else
         {
            int err=GetLastError();
            if (ShowManagementAlerts==true) Alert("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            Print("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
         }//else
      }//if (Ask >= tp)      
   }//if (OrderType() == OP_BUY)
   
   //Sell trade
   if (OrderType() == OP_SELL)
   {
      tp = NormalizeDouble(OrderOpenPrice() - (HiddenTakeProfitPips * Point), Digits);
      if (Ask <= tp)
      {
         while(IsTradeContextBusy()) Sleep(100);
         result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
         if (result)
         {
            if (ShowManagementAlerts==true) Alert("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());      
         }//if (result)
         else
         {
            err=GetLastError();
            if (ShowManagementAlerts==true) Alert("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            Print("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
         }//else
      }//if (Bid <= tp)   
   }//if (OrderType() == OP_SELL)
   

}//End void HiddenTakeProfit()

void TrailingStopLoss()
{
      if (TrailAfterBreakevenOnly && OrderType()==OP_BUY)
      {
         if(OrderStopLoss()<OrderOpenPrice()) return(0);
      }
     
      if (TrailAfterBreakevenOnly && OrderType()==OP_SELL)
      {
         if(OrderStopLoss()>OrderOpenPrice()) return(0);
      }
     
   
   
   bool result;
   double sl=OrderStopLoss(); //Stop loss
   double BuyStop=0, SellStop=0;
   
   if (OrderType()==OP_BUY) 
      {
         if (HideTrailingStop)
         {
            bool TradeClosed = CheckForHiddenStopLossHit(OP_BUY, PipsAwayFromVisualTS, OrderStopLoss() );
            if (TradeClosed) return;//Trade has closed, so nothing else to do
         }//if (HideJumpingStop)
		   
		   if (Bid >= OrderOpenPrice() + (TrailingStopPips*Point))
		   {
		       if (OrderStopLoss() == 0) sl = OrderOpenPrice();
		       if (Bid > sl +  (TrailingStopPips*Point))
		       {
		          sl= Bid - (TrailingStopPips*Point);
		          // Exit routine if user has chosen StopTrailAtPipsProfit and
		          // sl is past the profit Point already
		          if (StopTrailAtPipsProfit && sl>= OrderOpenPrice() + (StopTrailPips*Point)) return;
		          while(IsTradeContextBusy()) Sleep(100);
		          result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
               if (result)
               {
                  Print("Trailing stop updated: ", OrderSymbol(), ": SL ", sl, ": Ask ", Ask);
               }//if (result) 
               else
               {
                  int err=GetLastError();
                  Print(OrderSymbol(), " order modify failed with error(",err,"): ",ErrorDescription(err));
               }//else
   
		       }//if (Bid > sl +  (TrailingStopPips*Point))
		   }//if (Bid >= OrderOpenPrice() + (TrailingStopPips*Point))
      }//if (OrderType()==OP_BUY) 

      if (OrderType()==OP_SELL) 
      {
		   if (Ask <= OrderOpenPrice() - (TrailingStopPips*Point))
		   {
             if (HideTrailingStop)
             {
                TradeClosed = CheckForHiddenStopLossHit(OP_SELL, PipsAwayFromVisualTS, OrderStopLoss() );
                if (TradeClosed) return;//Trade has closed, so nothing else to do
             }//if (HideJumpingStop)
		   
		       if (OrderStopLoss() == 0) sl = OrderOpenPrice();
		       if (Ask < sl -  (TrailingStopPips*Point))
		       {
	               sl= Ask + (TrailingStopPips*Point);
  	               // Exit routine if user has chosen StopTrailAtPipsProfit and
		            // sl is past the profit Point already
		            if (StopTrailAtPipsProfit && sl<= OrderOpenPrice() - (StopTrailPips*Point)) return;
		            while(IsTradeContextBusy()) Sleep(100);
		            result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
                  if (result)
                  {
                     Print("Trailing stop updated: ", OrderSymbol(), ": SL ", sl, ": Bid ", Bid);
                  }//if (result)
                  else
                  {
                     err=GetLastError();
                     Print(OrderSymbol(), " order modify failed with error(",err,"): ",ErrorDescription(err));
                  }//else
    
		       }//if (Ask < sl -  (TrailingStopPips*Point))
		   }//if (Ask <= OrderOpenPrice() - (TrailingStopPips*Point))
      }//if (OrderType()==OP_SELL) 

      
} // End of TrailingStopLoss sub

void CandlestickTrailingStop()
{
   
   //Trails the stop at the hi/lo of the previous candle.
   //Only tries to do this once per bar, so an invalid stop error will only be generated once.
   
   if (OldCstBars == Bars) return;
   OldCstBars = Bars;
   bool result = false, modify = false;
   int err;
   double stop;
   
   if (OrderType() == OP_BUY)
   {
      if (Low[1] > OrderStopLoss() && OrderProfit() >= 0)
      {
         stop = NormalizeDouble(Low[1], Digits);
         modify = true;
      }//if (Close[1] > OrderStopLoss() && OrderProfit() >= 0)
   }//if (OrderType == OP_BUY)
   
   if (OrderType() == OP_SELL)
   {
      if ( (High[1] < OrderStopLoss() || OrderStopLoss() == 0) && OrderProfit() >= 0)
      {
         stop = NormalizeDouble(High[1], Digits);
         modify = true;
      }//if (Close[1] > OrderStopLoss() && OrderProfit() >= 0)
   }//if (OrderType() == OP_SELL)
   
   if (modify)
   {
      result = OrderModify(OrderTicket(), OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
      if (!result)
      {
         err = GetLastError();
         if (err != 130) OldBars = 0;//Retry the modify at the next tick unless the error is invalid stops
      }//if (!result)      
   }//if (modify)

}//End void CandlestickTrailingStop()

void TradeManagementModule()
{

   // Call the working subroutines one by one. 

   //Candlestick trailing stop
   if (UseCandlestickTrailingStop) CandlestickTrailingStop();

   // Hidden stop loss
   if (HideStopLossEnabled) HiddenStopLoss();

   // Hidden take profit
   if (HideTakeProfitEnabled) HiddenTakeProfit();

   // Breakeven
   if(BreakEven) BreakEvenStopLoss();

   // JumpingStop
   if(JumpingStop) JumpingStopLoss();

   //TrailingStop
   if(TrailingStop) TrailingStopLoss();

   

}//void TradeManagementModule()
//END TRADE MANAGEMENT MODULE
////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////
//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 in the first curr and falling in the second
         if (SlopeConfirmationCandles > 0)
         {
            if (prevstrength1 >= strength1) return(false);
            if (prevstrength2 <= strength2) return(false);
         }//if (SlopeConfirmationCandles > 0 
         
         //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 in the first curr and rising in the second curr
         if (SlopeConfirmationCandles > 0)
         {
            if (prevstrength1 <= strength1) return(false);
            if (prevstrength2 >= strength2) return(false);
         }//if (SlopeConfirmationCandles > 0 
         
         //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_SELL)
         
   }//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()
{
//----

   
   
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //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)
  
   ///////////////////////////////////////////////////////////////////////////////////////////////         
   //Trading
   if (OldBars != Bars)
   {
      OldBars = Bars;
      if (UseHanover)
      {
          ReadHanover();
      }//if (UseHanover)
  
      ReadIndicatorValues();
      //Find open trades.   
      TradeExists = DoesTradeExist();
      if (TradeExists)
      {
          if (OrderProfit() > 0) TradeManagementModule();
          bool result = LookForTradeClosure();
          if (!result)
          {
            OldBars = 0;//Force a retry after a failed trade closure
            return;
          }//if (!result)
          
      }//if (TradeExists)
      if (TicketNo == -1)
      {   
         //Trend detection      
         if (UseTrendDetection) TrendDetectionModule();
         if (!UseTrendDetection && RisingTrend) trend = up;
         if (!UseTrendDetection && FallingTrend) trend = down;

         LookForTradingOpportunities();
      }//if (TicketNo == -1)
   }//if (OldBars != Bars)
   
   ///////////////////////////////////////////////////////////////////////////////////////////////      

   DisplayUserFeedback();
   
//----
   return(0);
}
//+------------------------------------------------------------------+