//+-------------------------------------------------------------------+
//|                                             Ichimoku EA (SHF).mq4 |
//|                                  Copyright © 2009, Steve Hopwood  |
//|                  Trading logic Copyright © 2012, Paul Geirnaerdt  |
//|                              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  ranging "Ranging"
#define  none "None"
#define  both "Both"
#define  buy "Buy"
#define  sell "Sell"
#define  confused "Confused, and so cannot trade"
#define  trending "Trending"
#define  opentrade "There is a trade open"
#define  stopped "Trading is stopped"

//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

/*

HOW TO USE THIS CODE

This code allows us to create auto-trading robots quickly and easily. Use it freely for your own trading. Distribute
trading ea's that you create using it freely at FF. Do not use it in commercial ea's that you claim as your own work; I
retain the copyright of this material.

The first thing you do is save the Generic ea using the name of your new EA. Don't forget to do this, or you will
find yourself taking hours to find out where you downloaded the generic code.

The first function to be called will be void ReadIndicatorValues(). This function contains calls to some of the
more-often used indicators, via functions that contain the call. Remove those functions and inputs you do not need; add
any extra ones that you want.

void CountOpenTrades() and bool DoesTradeExist() essentially do the same thing; they ascertain whether there is already
an open trade and leaves the variable TicketNo set to the final trade in a sequence of trades. I generally use 
CountOpenTrades() when there are likely to be more than one trade open, and DoesTradeExist() when there is only ever
going to be one open trade. 

The Hanover Recent Strength module originated at http://www.forexfactory.com/showthread.php?t=319709 Read about it there.

start() contains calls to all the functions that manage open trades, check trading times etc. 
void LookForTradingOpportunities() is the final function in start() before the feedback display.
void LookForTradingOpportunities() contains the trade-trigger code; simply adapt it to suit the trigger
you are using. IsTradingAllowed() is called from LookForTradingOpportunities(); it contains a variety of filters that
might cancel trading - swap, balance etc.

The code that adapts the bot to x digit criminals is in int init(). Remember to add any other pips inputs to the
list.

There is code to avoid overtrading:
   - UseZeljko ensures 'balanced' trading e.g.  if GJ is a sell, then the next Gx trade bust be a buy
   - OnlyTradeCurrencyTwice ensures a particular currency is not involved in more than two trading pairs
   - sccobs and GxKiwi are margin/margin percent checks. The default represents my favourite

There are swap filters to ensure that high-cost swap pairs only trade in the direction of positive swap

Matt Kennel has provided the code for bool O_R_CheckForHistory(int ticket). Cheers Matt, You are a star.

Caterpillar is a way of scaling into a larger position if the market moves in favour of the trade.

Stealth: In the Aurora thread, we developed what I jokingly call Stealth Technology to hide some of our activities from the
crims. Hidden take profit and stop loss are automatic features:
   - sends a 'hard' sl/tp if required, then draws lines that represent the hidden stops. The lines have names
     consisting of the SlPrefix/TpPrefix plus the trade ticket number.
   - Breakeven, trailing jumping & candlestick trailing stops are operated by reference to the hidden sl line
The user turns off Stealth with a HiddenPips = 0 value in the input. The ea will close the
trade when the Bid touches/passes either of the lines. At the time of 
writing this - 5th October 2011 - Stealth has worked successfully but is still recent, so the odd bug may still
crawl out of the woodwork.

Navigate around the functions by highlighing them and pressing ctrl + F. YOu have to add the Bookmarks facility to
your code editor:
- Click View
- Click Customise
- Scroll down the 'Available' window until you find the bookmarks and click the Insert button to add them to your editor

Code for adding debugging Sleep
Alert("G");
int x = 0;
while (x == 0) Sleep(100);

Code for returning a value as pips. The example returns the range of the previous candle
   int PipDivisor = 1;
   if (Digits == 3 || Digits == 5) PipDivisor = 10;
   double CandleRange = ((High[1] - Low[1]) / Point) / PipDivisor;

Standard order loop code
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;

   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)

Code from George, to detect the shift of an order open time
int shift = iBarShift(NULL,Period(),OrderOpenTime(), false);

FUNCTIONS LIST
void DisplayUserFeedback()
int init()
int start()

----Trading----

void LookForTradingOpportunities()
   void HasBuyFilled()
   void HasSellFilled()
   double CalculateStopLoss(int type)
   double CalculateTakeProfit(int type)
   bool IsTradingAllowed()
   double CalculateLotSize(double price1, double price2)
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
   void ModifyOrder(int ticket, double stop, double take)
void CountOpenTrades()
   void InsertStopLoss(int ticket)
   void InsertTakeProfit(int ticket)
bool CloseTrade(int ticket)
bool LookForTradeClosure(int ticket)
bool CheckTradingTimes()
void CloseAllTrades()
double CalculateTradeProfitInPips()

----Hidden sl/tp---- Doubles up for pending trades-based ea's
void DrawPendingPriceLines()
void DeletePendingPriceLines()
void ReplaceMissingSlTpLines()
void DeleteOrphanTpSlLines()

----Balance/swap filters module----
void TradeDirectionBySwap()
bool IsThisPairTradable()
bool BalancedPair(int type)

----Matt's Order Reliable library code
bool O_R_CheckForHistory(int ticket) Cheers Matt, You are a star.
void O_R_Sleep(double mean_time, double max_time)

----Indicator readings----
void ReadIndicatorValues()
void GetBB(int shift)
double CalculateVolatility()
void CalculateDailyResult()

----Trend detection module----
void TrendDetectionModule()

----Hanover module----
bool HanoverFilter(int type)
void SetUpArrays()
void CleanUpInputString()
int CalculateParamsPassed()
void ReadHanover()
int LoadRSvalues()  
double ReadStrength(string curr, string tf, int shift)

----Central Bank Intervention module----
bool CentralBankInterventionModule()
void StoreQuote()
bool CbiHedging(int type)
bool SetupHedgeTrade(int type, string comment, double lotsize, double price)
bool CbiCloseTrades(int type)


//Caterpillar
void StartCaterpillar()
void LookForCatTradingOpportunities()
void DeleteOrphanGlobals()

----Date/Time functions----
datetime hhmm_to_time(double hhmm)

----Recovery----
void RecoveryModule()
void CheckRecoveryTakeProfit()
int Analyze()
int SymbolsIndex(string SymbolName)
void RecoveryCandlesticktrailingStop()
void LockInRecoveryProfit()
void AddReEntryLine(double price)
void CalculateReEntryLinePips() not included yet
void ReplaceReEntryLine()
void RecoveryCandlesticktrailingStop()

----Trade management module----
void TradeManagementModule()
void BreakEvenStopLoss()
void JumpingStopLoss() 
void HiddenTakeProfit()
void HiddenStopLoss()
void TrailingStopLoss()
void CandlestickTrailingStop()
void ReportError()

*/

extern string  gen="----General inputs----";
extern double  Lot=0.01;
extern int     RiskPercent = 0;//Set to zero to disable and use Lot
extern bool    StopTrading=false;
extern bool    TradeLong=true;
extern bool    TradeShort=true;
extern int     TakeProfit=100;
extern int     StopLoss=100;
extern int     MagicNumber=0;
extern string  TradeComment="G";
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=0;//Added to the 'hard' sl and tp and used for closure calculations

extern string  atr="----ATR----";
extern int     AtrPeriod=0;// 0 turns off atr
extern int     AtrTimeFrame=1440;//Allows tf independent of the chart. 0 means current chart
extern double  AtrTpMultiplier=1;
extern double  AtrSlMultiplier=1;
/////////////////////////////////////////////////////////////////////////////////////////////
double         AtrVal;
/////////////////////////////////////////////////////////////////////////////////////////////

extern string  bf="----Trading balance filters----";
extern bool    UseZeljko=true;
extern bool    OnlyTradeCurrencyTwice=true;

//Pending price inputs. Keeps things hidden from the crims.
extern string  ppi="----Pending trade inputs----";
extern int     BufferPips=5;
extern color   BuyLineColour=Green;
extern color   SellLineColour=Red;
extern int     TradingTimeFrame=1440;//Defaults to D1. Unfilled 'pendings' will be 'deleted' at the start of each new candle
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool           PendingBuy, PendingSell;
double         PendingPrice, PendingStop, PendingTake;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  vs="----Volatility inputs----";
extern int     VolatilityLookBackCandles=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   CatBuyLineColour=Green;
extern color   CatSellLineColour=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="----Ichimoku detection module----";
extern bool    UseTenkanKijunCross = true;
extern bool    UseKijunCross = false;
extern bool    UseKumoBreakout = false;
extern bool    UseKumoStrength = true;
extern double  KumoStrengthPercentage = 50.0;
extern bool    UseChinkouConfirmation = false;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
bool           TenkanOverKijunCross = false;
bool           KijunOverTenkanCross = false;
bool           PriceOverKijunCross = false;
bool           KijunOverPriceCross = false;
bool           KumoBreakoutBullish = false;
bool           KumoBreakoutBearish = false;
int            KumoStrength = 0;
bool           ChinkouConfirmed = false;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

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 string  SlopeConfirmationCandles="0,0,0,0,0,0,0,0,0";
extern string  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
int            SlopeCandles[];//Holds the slope confirmation candles specified in SlopeConfirmationCandles input
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  cbi="----Central Bank Intervention module----";
extern bool    UseCBI=false;
extern int     TableSize=20;
extern int     Threshold=10;
extern bool    CloseOnCBI=false;
extern bool    HedgeOnCBI=true;
extern double  CbiHedgeLotMultiplier=4;
extern bool    TradeOnCBI=true;
extern int     TradeOnCbiTP=200;//Take profit
extern int     TradeOnCbiSL=50;//Stoploss
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
double         TickTable[20]; // circular buffer to hold the ticks
int            tc = 0; // Tick counter. current position in table
int            is_filled = 0; // is the table full yet?
int            fill_check_counter = 0; // check if we have looped through the table once
double         PipMultiplier = 1.0; // needed to convert a price differenct into a pip value
double         TickDiff;//Difference between current quote and TableSize quotes ago
//Some Booleans to tell the bot what it has already done
bool           TakingEmergencyAction;//Will be true if TickDiff crosses the threshold
bool           TradeSent, HedgeSent, TradesClosed;
bool           HedgingInProgress;//So the bot knows it is dealing with a hedged situation
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

extern string  amc="----Available Margin checks----";
extern string  sco="Scoobs";
extern bool    UseScoobsMarginCheck=false;
extern string  fk="ForexKiwi";
extern bool    UseForexKiwi=true;
extern int     FkMinimumMarginPercent=1500;
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
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=false;
extern int     BreakEvenPips=10;
extern int     BreakEvenProfit=5;
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=false;
extern int     JumpingStopPips=10;
extern bool    AddBEP=true;
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;


//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 */
int            RetryCount = 10;//Will make this number of attempts to get around the trade context busy error.

//Trading variables
int            TicketNo = -1, 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, PendingBuyOpen, PendingSellOpen;//Might need further refinement to reflect the pending type
double         upl;//For keeping track of the upl of hedged positions

//Hidden stops variables
double         HiddenStopLoss, HiddenTakeProfit;


//Date/Time
datetime       ConvertedStartTime;


//Running total of trades
int            LossTrades, WinTrades;
double         OverallProfit;

//Misc
string         Gap, ScreenMessage;
int            OldBars;
string         PipDescription=" pips";
bool           ForceTradeClosure;
int            TurnOff=0;//For turning off functions without removing their code



void DisplayUserFeedback()
{
   
   if (IsTesting() && !IsVisualMode()) return;

   ScreenMessage = "";
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Updates for this EA are to be found at http://www.stevehopwoodforex.com", NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Feeling generous? Help keep the coder going with a small Paypal donation to pianodoodler@hotmail.com", 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, ": Spread = ", MarketInfo(Symbol(), MODE_SPREAD), NL);
   if (VolatilityLookBackCandles > 0) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Volatility: ", Volatility, " pips a day",  NL);
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, 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);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Use Tenkan Kijun cross: ");
   if (UseTenkanKijunCross)
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "YES", NL);
   }
   else
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "NO", NL);
   }
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Use Kijun cross: ");
   if (UseKijunCross)
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "YES", NL);
   }
   else
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "NO", NL);
   }
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Use Kijun breakout: ");
   if (UseKumoBreakout)
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "YES", NL);
   }
   else
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "NO", NL);
   }
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Use Kumo strength: ");
   if (UseKumoStrength)
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "YES", NL);
      ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Kumo strength percentage: ", NormalizeDouble(KumoStrengthPercentage, 1), NL);
   }   
   else   
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "NO", NL);
   }   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Use Chinkou confirmation: ");
   if (UseChinkouConfirmation)
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "YES", NL);
   }
   else   
   {
      ScreenMessage = StringConcatenate(ScreenMessage, "NO", 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 (SlopeCandles[cc] > 0) 
         {
            double prevstrength1 = ReadStrength(Ccy1, Tf[cc], SlopeCandles[cc]);
            now = StringConcatenate(": Shift ", SlopeCandles[cc], " = ", DoubleToStr(prevstrength1, 2));
            double prevstrength2 = ReadStrength(Ccy2, Tf[cc], SlopeCandles[cc]);
            then = StringConcatenate(": Shift ", SlopeCandles[cc], " = ", 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)

   //Running total of trades
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Results today. Wins: ", WinTrades, ": Losses ", LossTrades,
                                     ": P/L ", DoubleToStr(OverallProfit, 2), NL);
   
   //Central Bank Intervention
   if (UseCBI)
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);   
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Central Bank Intervention", NL);
      string actions = "        ";
      if (TradeOnCBI) actions = StringConcatenate(actions, "Taking new trade: ");
      if (HedgeOnCBI) actions = StringConcatenate(actions, "Hedging existing trades: ");
      if (CloseOnCBI) actions = StringConcatenate(actions, "Closing existing trades: ");
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, actions, NL);
      if (is_filled == 0) // table not full yet, so nothing to do
      { 
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "        ", "Filling Tick table. ", fill_check_counter, " of ", TableSize, " Ticks filled.");         
      }//if (is_filled == 0)
      else 
      {
         ScreenMessage = StringConcatenate(ScreenMessage,Gap, "        ", "Current tick difference: ", DoubleToStr(TickDiff, 1), ", Threshold: ", Threshold);
      }//else

   }//if (UseCBI)
   
   
   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);

   
   Comment(ScreenMessage);


}//void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----

   //Adapt to x digit criminals
   int multiplier = 1;
   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;
   TradeOnCbiTP*= multiplier;
   TradeOnCbiSL*= multiplier;
   BufferPips*= 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;   
   
   /////////////////////////////////////////////////////////////////////////////////////////////////////////
   //Hanover module
   //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)
   /////////////////////////////////////////////////////////////////////////////////////////////////////////
   
   /////////////////////////////////////////////////////////////////////////////////////////////////////////
   //CBI module
   int ret = ArrayResize(TickTable, TableSize);
   if (ret == -1) {
      Alert("Error: Could not initialize tick table!\n");
   }
   
   if (Digits == 2 || Digits == 3) PipMultiplier = 100.0;
   else if (Digits == 4 || Digits == 5) PipMultiplier = 10000.0;
   /////////////////////////////////////////////////////////////////////////////////////////////////////////
   
   if ((JumpingStop || TrailingStop) && !BreakEven) 
   {
      BreakEven = true;
      if (JumpingStop) BreakEvenPips = JumpingStopPips;
      if (TrailingStop) BreakEvenPips = TrailingStopPips;
   }//if (JumpingStop || TrailingStop) 
   
   if (TradeComment == "") TradeComment = " ";
   ConvertedStartTime = hhmm_to_time(StartTime);
   OldBars = Bars;
   TicketNo = -1;
   ReadIndicatorValues();//For initial display in case user has turned of constant re-display
   TrendDetectionModule();
   if (VolatilityLookBackCandles > 0) Volatility = CalculateVolatility();
   DisplayUserFeedback();
   //This forces the platform to 2048 bars of data - necessary if this is a new CrapT4 installation
   iBars(NULL, Period() );
   
   //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 (OrderStopLoss() >= OrderOpenPrice() - (HiddenPips * Point) ) 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 ((OrderStopLoss() <= OrderOpenPrice() + (HiddenPips * Point) ) && OrderStopLoss() > 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)
   {
      if (NewStop == OrderStopLoss() ) return;
      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) )
       sl = MathMax(sl, OrderOpenPrice());
       if (Bid >=  sl + ((JumpingStopPips * 2) * Point) )//George{
       {
          NewStop = NormalizeDouble(sl + (JumpingStopPips * Point), Digits);
          if (AddBEP) NewStop = NormalizeDouble(NewStop + (BreakEvenProfit*Point), Digits);
          if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
          if (NewStop - OrderStopLoss() >= Point) modify = true;//George again. What a guy
       }// 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)) Original code
          sl = MathMin(sl, OrderOpenPrice());
          if (sl == 0) sl = OrderOpenPrice();
          if (Bid <= sl - ((JumpingStopPips * 2) * Point) )//George
          {
             NewStop = NormalizeDouble(sl - (JumpingStopPips * Point), Digits);
             if (AddBEP) NewStop = NormalizeDouble(NewStop - (BreakEvenProfit*Point), Digits);
             if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
             if (OrderStopLoss() - NewStop >= Point || OrderStopLoss() == 0) modify = true;//George again. What a guy   
          }// 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)
   {
      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) ) Original code
          sl = MathMax(sl, OrderOpenPrice());
          if (Bid >= sl + (TrailingStopPips * Point) )//George
          {
             NewStop = NormalizeDouble(sl + (TrailingStopPips * Point), Digits);
             if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
             if (NewStop - OrderStopLoss() >= Point) modify = true;//George again. What a guy
          }//if (Bid >= MathMax(sl,OrderOpenPrice()) + (TrailingStopPips * Point) )//George
       }//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) ) Original code
          sl = MathMin(sl, OrderOpenPrice());
          if (sl == 0) sl = OrderOpenPrice();
          if (Bid <= sl  - (TrailingStopPips * Point))//George
          {
             NewStop = NormalizeDouble(sl - (TrailingStopPips * Point), Digits);
             if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
             if (OrderStopLoss() - NewStop >= Point || OrderStopLoss() == 0) modify = true;//George again. What a guy   
          }//if (Bid <= MathMin(sl, OrderOpenPrice() ) - (TrailingStopPips * Point) )//George
       }//if (OrderType()==OP_SELL)


   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify)
   {
      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)
   {
      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;
   
   //For CBI module. Set to true if the module detects a massive move
   if (TakingEmergencyAction) slippage = 1000;
   
   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(), " ", WindowExpertName(), " ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
         Print(Symbol(), " ", WindowExpertName(), " ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
         return(false);
      }//if (ticket < 0)  
   }//for (int cc = 0; cc < RetryCount; cc++);
   
   
   TicketNo = ticket;
   //Make sure the trade has appeared in the platform's history to avoid duplicate trades.
   //My mod of Matt's code attempts to overcome the bastard crim's attempts to overcome Matt's code.
   bool TradeReturnedFromCriminal = false;
   while (!TradeReturnedFromCriminal)
   {
      TradeReturnedFromCriminal = O_R_CheckForHistory(ticket);
      if (!TradeReturnedFromCriminal)
      {
         Alert(Symbol(), " sent trade not in your trade history yet. Turn of this ea NOW.");
      }//if (!TradeReturnedFromCriminal)
   }//while (!TradeReturnedFromCriminal)
   
   //Got this far, so trade send succeeded
   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 (stop == 0 && take == 0) return; //nothing to do

   if (!OrderSelect(ticket, SELECT_BY_TICKET) ) return;//Trade does not exist, so no mod needed
   
   //RetryCount is declared as 10 in the Trading variables section at the top of this file   
   for (int cc = 0; cc < RetryCount; cc++)
   {
      for (int d = 0; (d < RetryCount) && IsTradeContextBusy(); d++) Sleep(100);
        if (take > 0 && stop > 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           if (OrderModify(ticket, OrderOpenPrice(), stop, take, OrderExpiration(), CLR_NONE)) 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)

//=============================================================================
//                           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)


///////////////////////////////////////////////////////////////////////////////////////////////////////


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()

double CalculateLotSize(double price1, double price2)
{
   //Calculate the lot size by risk. Code kindly supplied by jmw1970. Nice one jmw.
   
   if (price1 == 0 || price2 == 0) return(Lot);//Just in case
   
   double FreeMargin = AccountFreeMargin();
   double TickValue = MarketInfo(Symbol(),MODE_TICKVALUE) ;
   double LotStep = MarketInfo(Symbol(),MODE_LOTSTEP);


   double SLPts = MathAbs(price1 - price2);
   SLPts/= Point;
   
   double Exposure = SLPts * TickValue; // Exposure based on 1 full lot

   double AllowedExposure = (FreeMargin * RiskPercent) / 100;
   
   int TotalSteps = ((AllowedExposure / Exposure) / LotStep);
   double LotSize = TotalSteps * LotStep;

   double MinLots = MarketInfo(Symbol(), MODE_MINLOT);
   double MaxLots = MarketInfo(Symbol(), MODE_MAXLOT);
   
   if (LotSize < MinLots) LotSize = MinLots;
   if (LotSize > MaxLots) LotSize = MaxLots;
   return(LotSize);

}//double CalculateLotSize(double price1, double price1)

double CalculateStopLoss(int type)
{
   //Returns the stop loss for use in LookForTradingOpps and InsertMissingStopLoss
   double stop, price;

   RefreshRates();
   
   if (type == OP_BUY)
   {
      price = Ask;
      if (StopLoss > 0) 
      {
         stop = NormalizeDouble(price - (StopLoss * Point), Digits);
         HiddenStopLoss = stop;
      }//if (StopLoss > 0) 

      //ATR sl is AtrVal
      if (AtrPeriod > 0)
      {
         stop = NormalizeDouble(price - (AtrVal * AtrSlMultiplier), Digits);         
      }//if (AtrPeriod > 0)

      if (HiddenPips > 0 && stop > 0) stop = NormalizeDouble(stop - (HiddenPips * Point), Digits);
   }//if (type == OP_BUY)
   
   if (type == OP_SELL)
   {
      price = Bid;
      if (StopLoss > 0) 
      {
         stop = NormalizeDouble(price + (StopLoss * Point), Digits);
         HiddenStopLoss = stop;         
      }//if (StopLoss > 0) 
      
      //ATR sl is AtrVal
      if (AtrPeriod > 0)
      {
         stop = NormalizeDouble(price + (AtrVal * AtrSlMultiplier), Digits);         
      }//if (AtrPeriod > 0)

      if (HiddenPips > 0 && stop > 0) stop = NormalizeDouble(stop + (HiddenPips * Point), Digits);

   }//if (type == OP_SELL)
   
   return(stop);
   
}//End double CalculateStopLoss(int type)

double CalculateTakeProfit(int type)
{
   //Returns the stop loss for use in LookForTradingOpps and InsertMissingStopLoss
   double take, price;

   RefreshRates();
   
   if (type == OP_BUY)
   {
      price = Ask;
      if (TakeProfit > 0) 
      {
         take = NormalizeDouble(price + (TakeProfit * Point), Digits);
         HiddenTakeProfit = take;
      }//if (TakeProfit > 0) 

         
      //ATR tp is AtrTpPercent of AtrVal
      if (AtrPeriod > 0)
      {
         double AtrPips;
         AtrPips = AtrVal * AtrTpMultiplier;
         take = NormalizeDouble(price + AtrPips, Digits);
      }//if (AtrPeriod > 0)
      
      if (HiddenPips > 0 && take > 0) take = NormalizeDouble(take + (HiddenPips * Point), Digits);

   }//if (type == OP_BUY)
   
   if (type == OP_SELL)
   {
      price = Bid;
      if (TakeProfit > 0) 
      {
         take = NormalizeDouble(price - (TakeProfit * Point), Digits);
         HiddenTakeProfit = take;         
      }//if (TakeProfit > 0) 
      
      //ATR tp is AtrTpPercent of AtrVal
      if (AtrPeriod > 0)
      {
         AtrPips = AtrVal * AtrTpMultiplier;
         take = NormalizeDouble(price - AtrPips, Digits);
      }//if (AtrPeriod > 0)

      if (HiddenPips > 0 && take > 0) take = NormalizeDouble(take - (HiddenPips * Point), Digits);

   }//if (type == OP_SELL)
   
   return(take);
   
}//End double CalculateTakeProfit(int type)

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;
   
   ////////////////////////////////////////////////////////////////////////////////////////////////////////
   //Trading decision.
   //Examine the filters one by one.
   //Work on the basis that a failed filter turns off SendLong/Short
   bool SendLong = true, SendShort = true;

   //Hanover RS
   if (UseHanover && !HanoverFilter(OP_BUY) ) SendLong = false;

   //Balanced pair trade filter. Only apply to pre-recovery trades.
   if (OpenTrades + 1 < Start_Recovery_at_trades || !UseRecovery)
   {
      if (UseZeljko && !BalancedPair(OP_BUY) ) SendLong = false;
   }//if (OpenTrades + 1 < Start_Recovery_at_trades)
   
   //User choice of trade direction
   if (!TradeLong) SendLong = false;

   //Other filters
   if (!UseTenkanKijunCross || !TenkanOverKijunCross) SendLong = false;
   if (!UseKijunCross || !PriceOverKijunCross) SendLong = false;
   if (!UseKumoBreakout || !KumoBreakoutBullish) SendLong = false;
   if (UseChinkouConfirmation && !ChinkouConfirmed) SendLong = false;
   if (OpenTrades == 1) SendLong = false;

   //Hanover RS
   if (UseHanover && !HanoverFilter(OP_SELL) ) SendShort = false;

   //Balanced pair trade filter. Only apply to pre-recovery trades
   if (OpenTrades + 1 < Start_Recovery_at_trades || !UseRecovery)
   {
      if (UseZeljko && !BalancedPair(OP_SELL) ) SendShort = false;
   }//if (OpenTrades + 1 < Start_Recovery_at_trades)

   //User choice of trade direction
   if (!TradeShort) SendShort = false;
   
   //Other filters
   if (!UseTenkanKijunCross || !KijunOverTenkanCross) SendShort = false;
   if (!UseKijunCross || !KijunOverPriceCross) SendShort = false;
   if (!UseKumoBreakout || !KumoBreakoutBearish) SendShort = false;
   if (UseChinkouConfirmation && !ChinkouConfirmed) SendShort = false;
   if (OpenTrades == 1) SendShort = false;

//////////////////////////////////////////////////////////////////////////////////////////////////////////
//REMEMBER TO DELET THIS OR THE EA WILL NEVER TRADE
//SendLong = false; SendShort = false;
//////////////////////////////////////////////////////////////////////////////////////////////////////////


   ////////////////////////////////////////////////////////////////////////////////////////////////////////
   
   
   //Long 
   if (SendLong)
   {
      //Got this far, so there is going to be a trade send of some sort. Setting up price here makes
      //this code most easily adaptable to easy alteration
      price = Ask;//Change this to whatever the price needs to be
      
      take = CalculateTakeProfit(OP_BUY);
      
      stop = CalculateStopLoss(OP_BUY);
      
      //Lot size calculated by risk
      if (RiskPercent > 0) SendLots = CalculateLotSize(price, NormalizeDouble(stop, Digits) );

      type = OP_BUY;
      SendTrade = true;
   }//if (SendLong)
   
   //Short
   if (SendShort)
   {
      //Got this far, so there is going to be a trade send of some sort. Setting up price here makes
      //this code most easily adaptable to easy alteration
      price = Bid;//Change this to whatever the price needs to be

      take = CalculateTakeProfit(OP_SELL);
      
      stop = CalculateStopLoss(OP_SELL);
      
      //Lot size calculated by risk
      if (RiskPercent > 0) SendLots = CalculateLotSize(NormalizeDouble(stop, Digits), price);
      
      type = OP_SELL;
      SendTrade = true;      
   }//if (SendShort)
   
   if (UseKumoStrength)
   {
      SendLots = SendLots * (1 + KumoStrength * KumoStrengthPercentage / 100);
   }

   if (SendTrade)
   {
      bool result = SendSingleTrade(type, TradeComment, SendLots, price, stop, take);
   }//if (SendTrade)
   
   //Actions when trade send succeeds
   if (SendTrade && result)
   {
      if (HiddenPips > 0) ReplaceMissingSlTpLines();
   }//if (result)
   
   //Actions when trade send fails
   if (SendTrade && !result)
   {
   
   }//if (!result)
   
   

}//void LookForTradingOpportunities()

void HasBuyFilled()
{
   //This function examines the Ask to see if a pending Buy price has been reached, and sends the trade if so.
   //Uses the Bid for buys also, as this is the price we see on the chart and the hi-lo is the Bid hi-lo.

   double take, stop, price;
   int type;
   double SendLot = Lot;
   bool CancelTrade = false;

   //Check filters
   if (!IsTradingAllowed() ) CancelTrade = true;
   if (UseZeljko && !BalancedPair(OP_BUY) ) CancelTrade = true;
   if (!TradeLong) CancelTrade = true;//Just in case

   if (CancelTrade)
   {
      ObjectDelete(pendingpriceline);
      return;
   }//if (CancelTrade)
   
   
   //Set pending price 
   if (ObjectFind(pendingpriceline) > -1) double PendingPrice = ObjectGet(pendingpriceline, OBJPROP_PRICE1);
   
   RefreshRates();
   if (Ask >= PendingPrice && PendingPrice > 0)
   {
      price = Ask;
      type = OP_BUY;
      
      //Stop loss calculations
      stop = CalculateStopLoss(OP_BUY);
      
      
      //Take profit calculations
      take = CalculateTakeProfit(OP_BUY);
      
      //Risk based lot calculator
      if (RiskPercent > 0) SendLot = CalculateLotSize(price, stop);
      
      bool result = SendSingleTrade(type, TradeComment, SendLot, price, stop, take);
      if (result)
      {
         ObjectDelete(pendingpriceline);
      }//if (result)
      
      
      
   }//if (Ask >= PendingPrice)
   

}//End void HasBuyFilled()

void HasSellFilled()
{
   //This function examines the Bid to see if a pending Buy price has been reached, and sends the trade if so

   double take, stop, price;
   int type;
   double SendLot = Lot;
   bool CancelTrade = false;
   
   //Check filters
   if (!IsTradingAllowed() ) CancelTrade = true;
   if (UseZeljko && !BalancedPair(OP_SELL) ) CancelTrade = true;
   if (!TradeShort) CancelTrade = true;//Just in case

   if (CancelTrade)
   {
      ObjectDelete(pendingpriceline);
      return;
   }//if (CancelTrade)

   //Set pending price 
   if (ObjectFind(pendingpriceline) > -1) double PendingPrice = ObjectGet(pendingpriceline, OBJPROP_PRICE1);
   
   RefreshRates();
   if (Bid <= PendingPrice && PendingPrice > 0)
   {
      price = Bid;
      type = OP_SELL;
      
      //Stop loss calculator
      stop = CalculateStopLoss(OP_SELL);
      
      
      //Take profit calculations
      take = CalculateTakeProfit(OP_SELL);
      
      //Risk based lot calculator
      if (RiskPercent > 0) SendLot = CalculateLotSize(stop, price);

      bool result = SendSingleTrade(type, TradeComment, SendLot, price, stop, take);
      if (result)
      {
         ObjectDelete(pendingpriceline);
      }//if (result)
            
   }//if (Bid >= PendingPrice)
   

}//End void HasSellFilled()


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)
   {
      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 CalculateVolatility()
{
   //Calculates the volatility of a pair based on an average of their movement over LookBack periods
   
   double pips;
   

   pips = iATR(Symbol(), PERIOD_D1, VolatilityLookBackCandles, 0);
   
   //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)

void CalculateDailyResult()
{
   //Calculate the no of winners and losers from today's trading. These are held in the history tab.

   LossTrades = 0;
   WinTrades = 0;
   OverallProfit = 0;
   
   
   for (int cc = 0; cc <= OrdersHistoryTotal(); cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS, MODE_HISTORY) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      
      OverallProfit+= (OrderProfit() + OrderSwap() + OrderCommission() );
      if (OrderProfit() > 0) WinTrades++;
      if (OrderProfit() < 0) LossTrades++;
   }//for (int cc = 0; cc <= tot -1; cc++)
   
   

}//End void CalculateDailyResult()

double GetAtr()
{
   //Returns the value of atr
   
   return(iATR(NULL, AtrTimeFrame, AtrPeriod, 0) );   

}//End double GetAtr()

void ReadIndicatorValues()
{
   double tenkan_current;
   double kijun_current;
   double tenkan_prior;
   double kijun_prior;
   
   double senkou_span_a;
   double senkou_span_b;
   
   double chinkou_span;
   
   KumoStrength = 0;
   ChinkouConfirmed = false;

   tenkan_current = iIchimoku(NULL, 0, 9, 26, 52, MODE_TENKANSEN, 0);
   kijun_current = iIchimoku(NULL, 0, 9, 26, 52, MODE_KIJUNSEN, 0);
   
   int chinkou = 26;
   
   tenkan_prior = iIchimoku(NULL, 0, 9, 26, 52, MODE_TENKANSEN, 1);
   kijun_prior = iIchimoku(NULL, 0, 9, 26, 52, MODE_KIJUNSEN, 1);

   // Tenkan Kijun Cross, Bullish signal
   TenkanOverKijunCross = false;
   if ( tenkan_current > kijun_current && tenkan_prior < kijun_prior )
   {
      TenkanOverKijunCross = true;
      
      // Kumo
      senkou_span_a = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANA, 0);
      senkou_span_b = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANB, 0);
   
      KumoStrength = 0; // below Kumo, weak
      if (kijun_current <= MathMax(senkou_span_a, senkou_span_b) && kijun_current >= MathMin(senkou_span_a, senkou_span_b)) KumoStrength = 1; // inside Kumo, normal
      if (kijun_current > MathMax(senkou_span_a, senkou_span_b)) KumoStrength = 2; // above Kumo, strong

      // Chinkou
      chinkou_span = iIchimoku(NULL, 0, 9, 26, 52, MODE_CHINKOUSPAN, chinkou);
      ChinkouConfirmed = chinkou_span > Close[chinkou];
   }

   // Kijun Tenkan Cross, Bearish signal
   KijunOverTenkanCross = false;
   if ( tenkan_current < kijun_current && tenkan_prior > kijun_prior )
   {
      KijunOverTenkanCross = true;
      
      // Kumo
      senkou_span_a = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANA, 0);
      senkou_span_b = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANB, 0);
   
      KumoStrength = 0; // above Kumo, weak
      if (kijun_current <= MathMax(senkou_span_a, senkou_span_b) && kijun_current >= MathMin(senkou_span_a, senkou_span_b)) KumoStrength = 1; // inside Kumo, normal
      if (kijun_current < MathMin(senkou_span_a, senkou_span_b)) KumoStrength = 2; // below Kumo, strong

      // Chinkou
      chinkou_span = iIchimoku(NULL, 0, 9, 26, 52, MODE_CHINKOUSPAN, chinkou);
      ChinkouConfirmed = chinkou_span < Close[chinkou];
   }
   
   // Price Kijun Cross, Bullish signal
   PriceOverKijunCross = false;
   if ( Ask > kijun_current && Close[1] < kijun_prior )
   {
      PriceOverKijunCross = true;
      
      // Kumo
      senkou_span_a = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANA, 0);
      senkou_span_b = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANB, 0);
   
      KumoStrength = 0; // below Kumo, weak
      if (kijun_current <= MathMax(senkou_span_a, senkou_span_b) && kijun_current >= MathMin(senkou_span_a, senkou_span_b)) KumoStrength = 1; // inside Kumo, normal
      if (kijun_current > MathMax(senkou_span_a, senkou_span_b)) KumoStrength = 2; // above Kumo, strong

      // Chinkou
      chinkou_span = iIchimoku(NULL, 0, 9, 26, 52, MODE_CHINKOUSPAN, chinkou);
      ChinkouConfirmed = chinkou_span > Close[chinkou];
   }

   // Kijun Price Cross, Bearish signal
   KijunOverPriceCross = false;
   if ( Bid < kijun_current && Close[1] > kijun_prior )
   {
      KijunOverPriceCross = true;
      
      // Kumo
      senkou_span_a = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANA, 0);
      senkou_span_b = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANB, 0);
   
      KumoStrength = 0; // above Kumo, weak
      if (kijun_current <= MathMax(senkou_span_a, senkou_span_b) && kijun_current >= MathMin(senkou_span_a, senkou_span_b)) KumoStrength = 1; // inside Kumo, normal
      if (kijun_current < MathMin(senkou_span_a, senkou_span_b)) KumoStrength = 2; // below Kumo, strong

      // Chinkou
      chinkou_span = iIchimoku(NULL, 0, 9, 26, 52, MODE_CHINKOUSPAN, chinkou);
      ChinkouConfirmed = chinkou_span < Close[chinkou];
   }
   
   // Kumo Breakout
   senkou_span_a = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANA, 1);
   senkou_span_b = iIchimoku(NULL, 0, 9, 26, 52, MODE_SENKOUSPANB, 1);
   // Bullish Breakout
   KumoBreakoutBullish = false;
   if (Close[1] > MathMax(senkou_span_a, senkou_span_b) && Close[2] < MathMax(senkou_span_a, senkou_span_b))
   {
      KumoBreakoutBullish = true;

      KumoStrength = 0; // normal
      if (senkou_span_a > senkou_span_b) KumoStrength = 1; // bullish Kumo, strong
   }
   
   // Bearish Breakout
   KumoBreakoutBearish = false;
   if (Close[1] < MathMin(senkou_span_a, senkou_span_b) && Close[2] > MathMin(senkou_span_a, senkou_span_b))
   {
      KumoBreakoutBearish = true;

      KumoStrength = 0; // normal
      if (senkou_span_a < senkou_span_b) KumoStrength = 1; // bearish Kumo, strong
   }
   
   if (AtrPeriod > 0) AtrVal = GetAtr();
   
}//void ReadIndicatorValues()

//End Indicator module
////////////////////////////////////////////////////////////////////////////////////////////////

bool LookForTradeClosure(int ticket)
{
   //Close the trade if the close conditions are met.
   //Called from within CountOpenTrades(). Returns true if a close is needed and succeeds, so that COT can increment cc,
   //else returns false
   
   if (!OrderSelect(ticket, SELECT_BY_TICKET) ) return(true);
   if (OrderSelect(ticket, SELECT_BY_TICKET) && OrderCloseTime() > 0) return(true);
   
   bool CloseThisTrade;
   
   string LineName = TpPrefix + DoubleToStr(ticket, 0);
   //Work with the lines on the chart that represent the hidden tp/sl
   double take = ObjectGet(LineName, OBJPROP_PRICE1);
   LineName = SlPrefix + DoubleToStr(ticket, 0);
   double stop = ObjectGet(LineName, OBJPROP_PRICE1);
   
   if (OrderType() == OP_BUY)
   {
      //TP
      if (Bid >= take && take > 0) CloseThisTrade = true;
      //SL
      if (Bid <= stop && stop > 0) CloseThisTrade = true;

   }//if (OrderType() == OP_BUY)
   
   
   if (OrderType() == OP_SELL)
   {
      //TP
      if (Bid <= take && take > 0) CloseThisTrade = true;
      //SL
      if (Bid >= stop && stop > 0) CloseThisTrade = true;

   }//if (OrderType() == OP_SELL)
   
   if (CloseThisTrade)
   {
      bool result = CloseTrade(TicketNo);
      //Actions when trade close succeeds
      if (result)
      {
         DeletePendingPriceLines();
         TicketNo = -1;//TicketNo is the most recently trade opened, so this might need editing in a multi-trade EA
         OpenTrades--;//Rather than OpenTrades = 0 to cater for multi-trade EA's
         return(true);//Makes CountOpenTrades increment cc to avoid missing out ccounting a trade
      }//if (result)
   
      //Actions when trade close fails
      if (!result)
      {
         return(false);//Do not increment cc
      }//if (!result)
   }//if (CloseThisTrade)
   
   //Got this far, so no trade closure
   return(false);//Do not increment cc
   
}//End bool 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--)

   //If full closure succeeded, then allow new trading
   if (!ForceTradeClosure) 
   {
      OpenTrades = 0;
      BuyOpen = false;
      SellOpen = false;
   }//if (!ForceTradeClosure) 

}//End void CloseAllTrades()


bool CheckTradingTimes()
{
   //This code contributed by squalou. Many thanks, sq.
   
   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()
{
   //Not all these will be needed. Which ones are depends on the individual EA.
   OpenTrades = 0;
   TicketNo = -1;
   BuyOpen = false;
   SellOpen = false;
   PendingBuyOpen = false;
   PendingSellOpen = false;
   int type;//Saves the OrderType() for consulatation later in the function
   
   upl = 0;//Unrealised profit and loss for hedging/recovery basket closure decisions

   if (OrdersTotal() == 0) return;
   
   //Iterating backwards through the orders list caters more easily for closed trades than iterating forwards
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      bool TradeWasClosed = false;//See 'check for possible trade closure'

      //Ensure the trade is still open
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      //Ensure the EA 'owns' this trade
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      
      //All conditions passed, so carry on
      type = OrderType();//Store the order type
      
      OpenTrades++;
      //Store the latest trade sent. Most of my EA's only need this final ticket number as either they are single trade
      //bots or the last trade in the sequence is the important one. Adapt this code for your own use.
      if (TicketNo  == -1) TicketNo = OrderTicket();
      
      //upl might not be needed. Depends on the individual EA
      upl+= (OrderProfit() + OrderSwap() + OrderCommission()); 
      //The next line of code calculates the pips upl of an open trade. As yet, I have done nothing with it.
      //something = CalculateTradeProfitInPips()
      
      //Trade types
      if (OrderType() == OP_BUY) BuyOpen = true;
      if (OrderType() == OP_SELL) SellOpen = true;
      //These might need extra coding if both stop and limit orders are used
      if (OrderType() == OP_BUYSTOP || OrderType() == OP_BUYLIMIT) PendingBuyOpen = true;
      if (OrderType() == OP_SELLSTOP || OrderType() == OP_SELLLIMIT) PendingSellOpen = true;
      //Add missing tp/sl in case rapidly moving markets prevent their addition - ECN
      if (OrderStopLoss() == 0 && StopLoss > 0) InsertStopLoss(TicketNo);
      if (OrderTakeProfit() == 0 && TakeProfit > 0) InsertTakeProfit(TicketNo);

      //Replace missing tp and sl lines
      if (HiddenPips > 0) ReplaceMissingSlTpLines();
      
      //Check for possible trade closure and order management. Only if hedging and Recovery are not in progress.
      //Extra code will be needed if Caterpillar is being used. As coded, Cat and Recovery are not compatible - it must
      //be one or the other
      if (!HedgingInProgress && !RecoveryInProgress && (type == OP_BUY || type == OP_SELL) )
      {
         if (HiddenPips > 0) 
         {
            TradeWasClosed = LookForTradeClosure(OrderTicket() );
            if (TradeWasClosed) 
            {
               if (type == OP_BUY) BuyOpen = false;//Will be reset if subsequent trades are buys that are not closed
               if (type == OP_SELL) SellOpen = false;//Will be reset if subsequent trades are sells that are not closed
               cc++;
            }//if (TradeWasClosed) 
            
         }//if (HiddenPips > 0) 
         
         if (OrderProfit() > 0 && !TradeWasClosed) TradeManagementModule();
      }//if (!HedgingInProgress && !RecoveryInProgress && (type == OP_BUY || type == OP_SELL) )
      
   }//for (int cc = OrdersTotal() - 1; cc <= 0; c`c--)
   
   //Detect Recovery and Hedging. Both HedgingInProgress and RecoveryInProgress are reset to false in start(),
   //if the call to this function results in OpenTrades == 0
   //Detect hedging
   if (BuyOpen && SellOpen) HedgingInProgress = true;
   
   //Detect Recovery.   
   if (UseRecovery && OpenTrades >- Start_Recovery_at_trades) RecoveryInProgress = true;
   
}//End void CountOpenTrades();

void InsertStopLoss(int ticket)
{
   //Inserts a stop loss if the ECN crim managed to swindle the original trade out of the modification at trade send time
   //Called from CountOpenTrades() if StopLoss > 0 && OrderStopLoss() == 0.
   
   while(IsTradeContextBusy()) Sleep(100);
   if (!OrderSelect(ticket, SELECT_BY_TICKET) || OrderCloseTime() > 0) return;
   
   double stop;
   
   if (OrderType() == OP_BUY)
   {
      stop = CalculateStopLoss(OP_SELL);
   }//if (OrderType() == OP_BUY)
   
   if (OrderType() == OP_SELL)
   {
      stop = CalculateStopLoss(OP_SELL);
   }//if (OrderType() == OP_SELL)
   

   OrderModify(ticket, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);

}//End void InsertStopLoss(int ticket)

void InsertTakeProfit(int ticket)
{
   //Inserts a TP if the ECN crim managed to swindle the original trade out of the modification at trade send time
   //Called from CountOpenTrades() if TakeProfit > 0 && OrderTakeProfit() == 0.
   
   while(IsTradeContextBusy()) Sleep(100);
   if (!OrderSelect(ticket, SELECT_BY_TICKET) || OrderCloseTime() > 0) return;
   
   double take;
   
   if (OrderType() == OP_BUY)
   {
      take = CalculateTakeProfit(OP_BUY);
   }//if (OrderType() == OP_BUY)
   
   if (OrderType() == OP_SELL)
   {
      take = CalculateTakeProfit(OP_SELL);
   }//if (OrderType() == OP_SELL)
   

   OrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE);

}//End void InsertStopLoss(int ticket)

//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()
{
   // Do the right thing!
   
}//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);
            }//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,CatBuyLineColour);
         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,CatSellLineColour);
         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 (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,CatBuyLineColour);
         ObjectSet(buyline,OBJPROP_STYLE,STYLE_SOLID);               
         if (OpenTrades > 1) CaterpillarTrailingStop(OpenTrades);
      }//if (TradeLong)
   
      target = ObjectGet(sellline, OBJPROP_PRICE1);
      if (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,CatSellLineColour);
         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);

   //SlopeConfirmationCandles
   InputString = SlopeConfirmationCandles;
   CleanUpInputString();
   SlopeConfirmationCandles = InputString;
   string NewArray11 = ArrayResize(SlopeCandles, 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)
      {
         SlopeCandles[cc] = StrToInteger(StringSubstr(InputString, LastIndex, Index-LastIndex));
         LastIndex = Index+1;
      }//if (Index > -1)
      else
      {
         SlopeCandles[cc] = 0;
      }
   }//for (cc = 0; cc < NoOfTimeFrames; cc ++)

}//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
      PrevStrongVal[i] = 0;
      PrevWeakVal[i] = 0;
   }//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;

         //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];
            if (SlopeCandles[j] > 0)
            {
               PrevStrongVal[j] = RSvalue[i, DatapointTf, SlopeCandles[j]];
            }
         }//if (RSvalue[i, DatapointTf, 0] > StrongVal[j])
         
         //Find the weakest datapoint on the current currency and timeframe
         if (RSvalue[i, DatapointTf, 0] < WeakVal[j])
         {
            WeakestCcy[j] = ccy[i];
            WeakVal[j] = RSvalue[i, DatapointTf, 0];
            if (SlopeCandles[j] > 0)
            {
               PrevWeakVal[j] = RSvalue[i, DatapointTf, SlopeCandles[j]];
            }
         }//if (RSvalue[i, DatapointTf, 0] < WeakVal[j])

      }//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 (SlopeCandles[cc] > 0) 
      {
         double prevstrength1 = ReadStrength(Ccy1, Tf[cc], SlopeCandles[cc]);
         double prevstrength2 = ReadStrength(Ccy2, Tf[cc], SlopeCandles[cc]);   
      }//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 (SlopeCandles[cc] > 0 && prevstrength1 >= strength1) 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. 
      if (type == OP_SELL)
      {
         //First currency must be the weakest
         if (strength1 >= strength2) return(false);

         //Slope must be falling
         if (SlopeCandles[cc] > 0 && prevstrength1 <= strength1) 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
////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////
//Central Bank Intervention module

bool CentralBankInterventionModule()
{
   /*
   Called from start() if UseCBI is enabled.
   Monitors the TickTable array and reacts to the movement in the market being >= the Threshold.
   The circular TickTable code is provided by Carsten. Many thanks Carsten. You are a star.
   Function returns true if all actions succeed or none are necessary, and false to force the bot to keep on retrying
   */

   //Store the latest quote in TickTable
   StoreQuote();

   if (is_filled == 0) // table not full yet, so nothing to do
   { 
      return(true);
   }//if (is_filled == 0)

   double take, stop, price, type;
   string direction;
   bool result;
   int tries;
   
   // table is full, now we can check for the big moves
   if (TickDiff > Threshold) 
   {
      TakingEmergencyAction = true;//Used in SendSingleTrade to create a mahoosive slippage allowance
      
      //Calculate the direction of the move
      direction = down;
      if (TickTable[tc] > TickTable[tc + 1] ) direction = up;
      
      // The price difference between the latest and the first entry in
      // our table is above the threshold, so take action.

      /////////////////////////////////////////////////////////////////////////////////////////////////
      //Close trade
      if (CloseOnCBI && !TradesClosed && OpenTrades > 0)
      {
         result = false;
         if (direction == down)
         {
            tries = 0;
            while (!result)
            {
               result = CbiCloseTrades(OP_BUY);
               if (result) TradesClosed = true;
               tries++;
               if (tries == 20) return(true);
            }//while (!result)            
         }//if (direction == down)
         
         
         if (direction == up)
         {
            tries = 0;
            while (!result)
            {
               result = CbiCloseTrades(OP_SELL);
               if (result) TradesClosed = true;
               tries++;
               if (tries == 20) return(true);
            }//while (!result)            
         }//if (direction == ip)
      }//if (CloseOnCBI)
      /////////////////////////////////////////////////////////////////////////////////////////////////
      
      /////////////////////////////////////////////////////////////////////////////////////////////////
      //Hedge an existing trade
      if (HedgeOnCBI && !HedgeSent && TicketNo > -1)
      {
         result = false;
         if (direction == down)
         {
            tries = 0;
            while (!result)
            {
               result = CbiHedging(OP_BUY);//Long trades need hedging short
               if (result) HedgeSent = true;
               tries++;
               if (tries == 20) return(true);
            }//while (!result)            
         }//if (direction == down)
         
         
         if (direction == up)
         {
            tries = 0;
            while (!result)
            {
               result = CbiHedging(OP_SELL);//Short trades need hedging long
               if (result) HedgeSent = true;
               tries++;
               if (tries == 20) return(true);
            }//while (!result)            
         }//if (direction == ip)         
      }//if (HedgeOnCBI)
      /////////////////////////////////////////////////////////////////////////////////////////////////
      
      
      /////////////////////////////////////////////////////////////////////////////////////////////////
      //Take a new trade
      if (TradeOnCBI && !TradeSent)
      {         
         if (direction == up)
         {
            type = OP_BUY;
            RefreshRates();
            price = Ask;
            if (TradeOnCbiTP > 0) take = NormalizeDouble(Ask + (TradeOnCbiTP * Point), Digits);
            if (TradeOnCbiSL > 0) stop = NormalizeDouble(Ask - (TradeOnCbiSL * Point), Digits);            
         }//if (direction == up)
         
         if (direction == down)
         {
            type = OP_SELL;
            RefreshRates();
            price = Bid;
            if (TradeOnCbiTP > 0) take = NormalizeDouble(Bid - (TradeOnCbiTP * Point), Digits);
            if (TradeOnCbiSL > 0) stop = NormalizeDouble(Bid + (TradeOnCbiSL * Point), Digits);            
         }//if (direction == up)
         result = SendSingleTrade(type, TradeComment, Lot, price, stop, take);
         if (result) 
         {
            TradeSent = true;
         }//if (result) 
         
         if (!result) 
         {
            return(false);
         }//if (result) 
         
      }//if (TradeOnCBI)
      /////////////////////////////////////////////////////////////////////////////////////////////////
      
      
      
      
   }//if (TickDiff > Threshold) 
   else 
   {   
      TakingEmergencyAction = false;
      TradeSent = false;
      HedgeSent = false;
      TradesClosed = false;
   }//else 


   //Got this far, so everything has worked as required
   return(true);

}//End bool CentralBankInterventionModule()

void StoreQuote()
{

   // fill the current tick value into the table
   TickTable[tc] = Bid;

   if (is_filled == 0) // table not full yet
   { 
      fill_check_counter += 1;
      if (fill_check_counter == TableSize) is_filled = 1;
   }//if (is_filled == 0)
   else 
   {
      TickDiff = MathAbs(TickTable[(tc + 1) % TableSize] - TickTable[tc]) * PipMultiplier;
   }//else   
      
      
   // increment the counter
   tc += 1;
   tc = tc % TableSize;// keeps tc within TableSize

}//End void StoreQuote()

bool CbiCloseTrades(int type)
{
   bool success = true;
   
   if (OrdersTotal() == 0) return(true);
   
   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() == type) bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, CLR_NONE);
      if (result) cc++;
      if (!result) success = false;      
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   
   return(success);

}//End bool CbiCloseTrades(int type)


bool CbiHedging(int type)
{
   //Opens an opposite direction hedge trade to that of the passed param
   bool success = true;
   bool result;
   int HedgeType = OP_SELL;
   if (type == OP_SELL) HedgeType = OP_BUY;
   
   if (OrdersTotal() == 0) return(true);
   
   for (int cc = 0; cc <= OrdersTotal() - 1; cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() != Symbol() ) continue;
      while(IsTradeContextBusy()) Sleep(100);

      //Check to see if the trade is already hedged.
      bool hedged = IsTradeAlreadyHedged(cc);
      if (hedged) 
      {
         //TicketNo is set in CountOpenTrades(). Reset the selected trade in case the intervening code leaves it unselected.
         OrderSelect(TicketNo, SELECT_BY_TICKET, MODE_TRADES);         
      }//if (IsTradeAlreadyHedged(index)) 

      if (!hedged)
      {
         if (OrderType() == type) result = SetupHedgeTrade(HedgeType);
         if (!result) success = false;      
      }//if (!hedged)
      
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   
   return(success);



}//End bool CbiHedging(int type)

bool SetupHedgeTrade(int type)
{
   //Order that needs hedging is already selected. This function sets up and sends the hedge trade
   
   bool result = false;
   int tries = 0;
   double SendLots;
   double price;

   SendLots = OrderLots() * CbiHedgeLotMultiplier;
   
   
   
   if (type == OP_SELL) 
   {
      //Check the trade does need hedging
      if (OrderProfit() > 0 && OrderStopLoss() > OrderOpenPrice() ) return(true);//No need to hedge a safe trade
      RefreshRates();
      price = Bid;
   }//if (type == OP_SELL) 
   
   if (type == OP_BUY) 
   {
      //Check the trade does need hedging
      if (OrderProfit() > 0 && OrderStopLoss() < OrderOpenPrice() ) return(true);//No need to hedge a safe trade
      RefreshRates();
      price = Ask;
   }//if (type == OP_BUY) 
   
   while (IsTradeContextBusy() ) Sleep(100);
   int tn = OrderTicket();//Need this to reselect the trade to remove the tp and sl from the trade
   while (!result)
   {
      result = SendSingleTrade(type, TradeComment, SendLots, price, 0, 0);
      //Remove existing tp/sl from the hedged trade. I will tidy this up later
      if (result) 
      {
         HedgingInProgress = true;
         OrderSelect(tn, SELECT_BY_TICKET);
         if (OrderTakeProfit() > 0) 
         {
            while (IsTradeContextBusy() ) Sleep(100);            
            OrderModify(tn, OrderOpenPrice(), OrderStopLoss(), 0, OrderExpiration(), CLR_NONE);
         }//if (OrderTakeProfit() > 0) 
         
         if (OrderStopLoss() > 0) 
         {
            if (OrderStopLoss() > 0) OrderModify(tn, OrderOpenPrice(), 0, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
         }//if (OrderStopLoss() > 0)             
      }//if (result) 
      
      tries++;
      if (tries == 20) result = true;      
   }//while (!result)
   
   
   return(result);
   
}//bool SetupHedgeTrade()

bool IsTradeAlreadyHedged(int index)
{

   /*
   Trade will already be hedged if:
      - there is an opposite direction trade open
      - the opp trade has a lot size x HedgeLotsMultiplier
   */
   
   //Alread at the end of the trade loop?
   if (index == OrdersTotal() - 1) return(false);
   
   //Need to know the order type and lot size
   int type = OrderType();
   double LotSize = OrderLots();
   
   //Loop through the remaining trades to find a hedge. Reselect original trade and teturn true if found
   for (int cc = index + 1; cc < OrdersTotal(); cc++)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      
      //All EA belonging conditions satisfied, so examine the trades
      if (type == OP_BUY && OrderType() == OP_SELL && OrderLots() == LotSize * CbiHedgeLotMultiplier) 
      {
         //TicketNo is set in CountOpenTrades(). Reset the selected trade.
         OrderSelect(TicketNo, SELECT_BY_TICKET, MODE_TRADES);   
         return(true);//Is a hedge
      }//if (type == OP_BUY && OrderType() == OP_SELL && OrderLots() == LotSize * 2) 
      
      if (type == OP_SELL && OrderType() == OP_BUY && OrderLots() == LotSize * CbiHedgeLotMultiplier) 
      {
         //TicketNo is set in CountOpenTrades(). Reset the selected trade.
         OrderSelect(TicketNo, SELECT_BY_TICKET, MODE_TRADES);   
         return(true);//Is a hedge
      }//if (type == OP_SELL && OrderType() == OP_BUY && OrderLots() == LotSize * 2) 
      
   }//for (int cc = index + 1); cc < OrdersTotal(); cc++)
   
   
   //TicketNo is set in CountOpenTrades(). Reset the selected trade.
   OrderSelect(TicketNo, SELECT_BY_TICKET, MODE_TRADES);
   
   //Got this far, so trade is not already hedged
   return(false);

}//End bool IsTradeAlreadyHedged(int index)



//End Central Bank Intervention module
////////////////////////////////////////////////////////////////////////////////////////////////

double CalculateTradeProfitInPips()
{
   //This function returns the profit/loss of an individual trade in pips. The function is called from
   //within CountTrades(), so the trade is already selected

   double Pips;
   
   //This returns Pips as a whole number
   Pips = (OrderProfit() / OrderLots()) / MarketInfo(OrderSymbol(),MODE_TICKVALUE);

   double digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
   int multiplier;
   if (digits == 2) multiplier = 10;
   if (digits == 3) multiplier = 100;
   if (digits == 4) multiplier = 1000;
   if (digits == 5) multiplier = 10000;
   
   //This returns Pips as a decimal number i.e. Pips * Point
   //Pips = (OrderProfit() / OrderLots()) / MarketInfo(OrderSymbol(),MODE_TICKVALUE) / multiplier;

   return(Pips);

}//double CalculateTradeProfitInPips()

//+------------------------------------------------------------------+
//| expert Correlation function |
//+------------------------------------------------------------------+
int Correlation(string symbol1, int type)
{
   /*
      For this, we have scoobs to thank. In hs thread at http://www.stevehopwoodforex.com/phpBB3/viewtopic.php?p=2530#p2530, 
      he eventually posted this funtion.
      
      The next update will have a correlation module which you can switch on or off.
      Basically if it is switched on then it checks the current symbol you are trying to send against already opened symbols 
      to make sure they do not have a positive correlation.
      Example1:
      BUY GBPUSD
      BUY EURUSD would not be allowed as it has positive correlation with GBPUSD.

      BUY EURUSD
      BUY USDCHF would be allowed as it has negative correlation with EURUSD.

      I may make this available before Monday opening.

      Cheers

      Scoobs

      The function returns 1 for a positive correlation, -1 for a negative correlation. Do not trade positive corrs/
   */
   int Difference = -1;
   for(int count = 0; count < OrdersTotal(); count++)
   {
      if(!OrderSelect(count,SELECT_BY_POS,MODE_TRADES)) continue;
      if(OrderMagicNumber() == MagicNumber && OrderType() == type)
      {
         string symbol2 = OrderSymbol();
         double DiffBuffer1=iClose(symbol1,60,0)-iMA(symbol1,60,20,0,MODE_SMA,PRICE_CLOSE,0);
         double DiffBuffer2=iClose(symbol2,60,0)-iMA(symbol2,60,20,0,MODE_SMA,PRICE_CLOSE,0);
         double PowDiff1=MathPow(DiffBuffer1,2);
         double PowDiff2=MathPow(DiffBuffer2,2);
         double u=0,l=0,s=0;
         u += DiffBuffer1*DiffBuffer2;
         l += PowDiff1;
         s += PowDiff2;
         //if(l*s >0 && (u/MathSqrt(l*s)) > 0) Difference = +1;
         //Matt's suggestion is detailed below
         if(l*s >0 && (u/MathSqrt(l*s)) > 0.5) return(1);
         if(l*s >0 && (u/MathSqrt(l*s)) < -0.5) return(-1);      
      }//if(OrderMagicNumber() == MagicNumber && OrderType() == type)
   }//for(int count = 0; count < OrdersTotal(); count++)
   //return(Difference);
   return(0);

   //Mastt's correlation advice
   //if R > 0.5 return +1
   //if R < -0.5 return -1
   //otherwise return 0.   
   
}//End
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

   
   //Monitor an existing pending trade line
   if (ObjectFind(pendingpriceline) > -1 && TurnOff == 1)
   {
      color col = ObjectGet(pendingpriceline, OBJPROP_COLOR);
      
      if (col == BuyLineColour) HasBuyFilled();
      if (col == SellLineColour) HasSellFilled();
   }//if (ObjectFind(pendingpriceline) > -1)

   /*
   People get twitchy when reading the code being removed from the ex4 file warning, so here is a neat method of
   turning off a function without deleting it, just in case you change your mind and want it later. I actually call
   CalculateTradeProfitInPips() from within CountOpenTrades() and include it here merely as an example.
   */
   if (TurnOff == 1) CalculateTradeProfitInPips();//TurnOff is never 1, so the function is not called
   if (TurnOff == 1) Correlation(Symbol(), 1);
   //Volatility
   if (VolatilityLookBackCandles > 0)
   {
      static datetime VolTime;
      if (VolTime != iTime(NULL, PERIOD_D1, 0) )
      {
         VolTime = iTime(NULL, PERIOD_D1, 0);
         Volatility = CalculateVolatility();
      }//if (VolTime != iTime(NULL, PERIOD_D1) )
   }//if (VolatilityLookBackCandles > 0)
   
   
   if (OrdersTotal() == 0)
   {
      TicketNo = -1;
      ForceTradeClosure = false;
   }//if (OrdersTotal() == 0)

   //Central Bank Intervention module
   if (UseCBI) 
   {
      int tries;
      bool ok = false;
      while (!ok)
      {
         ok = CentralBankInterventionModule();         
         tries++;
         if (tries == 20) ok = true;
      }//while (!ok)         
   }//if (UseCBI) 

   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)
   
   //Daily results so far - they work on what in in the history tab, so users need warning that
   //what they see displayed on screen depends on that.   
   //Code courtesy of TIG yet again. Thanks, George.
   static int OldHistoryTotal;
   if (OrdersHistoryTotal() != OldHistoryTotal)
   {
      CalculateDailyResult();//Does no harm to have a recalc from time to time
      OldHistoryTotal = OrdersHistoryTotal();
   }//if (OrdersHistoryTotal() != OldHistoryTotal)
   
   
   ReadIndicatorValues();

   //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.
   CountOpenTrades();

   //Reset various bools
   if (OpenTrades == 0)
   {
      //CBI
      TakingEmergencyAction = false;
      TradeSent = false;
      HedgeSent = false;
      TradesClosed = false;
      //Hedging and Recovery
      HedgingInProgress = false;
      RecoveryInProgress = false;
   }//if (OpenTrades > 0)


   //Hedging. This might need removing
   if (HedgingInProgress)
   {
      if (upl >= 0) 
      {
         CloseAllTrades();
      }//if (upl <= HedgeStopLoss && HedgeStopLoss != 0) 
      
      if (ForceTradeClosure) return;
   }//if (UseHedging)

   ///////////////////////////////////////////////////////////////////////////////////////////////
   
   //Recovery
   if (UseRecovery && !HedgingInProgress)
   {
      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)

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   
 
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   //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 (!TradeTimeOk)
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   //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      
      TrendDetectionModule();
      
      LookForTradingOpportunities();
   }//if (TicketNo == -1)
   ///////////////////////////////////////////////////////////////////////////////////////////////      

   DisplayUserFeedback();
   
//----
   return(0);
}
//+------------------------------------------------------------------+

