//+------------------------------------------------------------------+
//|                                 scooby-doo BOJ trading robot.mq4 |
//|                                  Copyright © 2009, Steve Hopwood |
//|                              http://www.hopwood3.freeserve.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2009, Steve Hopwood"
#property link      "http://www.hopwood3.freeserve.co.uk"
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"
#define  OverboughtGV "scooby-doo overbought 24H"
#define  OversoldGV "scooby-doo oversold 24H"
#define  HedgeTimeGV "scooby-doo hedge time 24H"
#define  up "Up"
#define  down "Down"
#define  none "None"

/*
   for (int cc = OrdersTotal(); cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      if (OrderMagicNumber()==MagicNumber)      
      {
            
      }//if (OrderMagicNumber()==MagicNumber)
   }//for (int cc=0; cc<OrdersTotal(); cc++)

Hedging:
Base lot size = Account equity / 20000

if hedge kicks in then find the biggest loser and divide its orderlots() by 20 and send a reverse trade. Keep doing this every 15 minutes until < 5%


void DisplayUserFeedback()
int start()

----Trading functions----
bool DoesTradeExist(string symbol, int type)
bool SendTrade(int type, string symbol)
void CloseBasket()
void CalculateBaseLotSize()
void CalculateBasketTp()
void GetStrongestPriceInBasket()

----Hedging functions----
MonitorHedgeTrades()
bool SendHedgeTrades()
bool RemoveIndividualStops()

----Take Profit and Stop Loss functions----
void CheckBasketTpSlTarget()
void CalculateBasketStoploss()


----Immediate trade functions----
void ImmediateBuyxxxJPY()
void ImmediateSellxxxJPY()


----Pairs traded----
void CleanUpInputString()
void CalculatePairsPassed()

----Differential lot sizing----
void GetStrongestPriceInBasket(int magic)
      
----News filter functions----
void NewsFilterCheck()

----Immediate action----
void ShowImmediateBuyLabel()
Void ShowImmediateSellLabel()
void ShowImmediateCloseLabel()

----RS readings----
double GetRSIbasket(int timefram, int pos)


----Correlation----
void GetGroupCorrelation()
double Cor(string base, string hedge, int corperiod)
double symboldif(string symbol, int shift, int corperiod)
double powdif(double val)
double u(double val1,double val2)

----AO----
double GetAO()

*/
extern string     GVI="-----General trade inputs-----";
extern string     PairsToTrade="GBPJPY,EURJPY";
extern bool       SendAlertNotTrade=false;
extern bool       TradeLong=true;
extern bool       TradeShort=true;
extern double     BaseLot = 0.1;
extern bool       RobotCalculatesLotSize=true;
extern int        TpMultiplicationFactor=300;
extern double     BasketStopLossPercentage=20;
extern int        EmergencyStopLoss=600;
extern int        EmergencyTakeProfit=200;
extern int        MaxSpreadAllowed=150;
extern int        MagicNumber=56466123456;
extern string     TradeComment="Basket 24H trade";
extern bool       CriminalIsECN=false;
extern bool       TradeSundayCandle=true;
extern string     th="----Trade suspension hours----";
extern int        StartSuspend = 11;
extern int        EndSuspend = 18;
extern int        FridayClose = 11;
//extern string     stu="-----Stop trading-----";
//extern string     st="Use format dd.mm.yyyy  h:mm";
//extern datetime   NoTradeUntil = D'23.11.2009 22:00';
extern string     rsg="----RS Group JPY Strength Index V1.2 & SMA----";
extern double     LowerTfOverBought=80;
extern double     HigherTfOverBought=80;
extern double     LowerTfOverSold=20;
extern double     HigherTfOverSold=20;
extern bool       UseSma=false;
extern string     news="-----News filter-----";
extern bool       UseNewsFilter=true;
extern int        MinsBeforeNews=30;
extern int        MinsAfterNews=30;
extern string     news1="3=High; 2=Medium; 1=Low";
extern int        NewsImpact=1;
extern string     new="----Next JPY Public Holiday----";
extern string     newi="Use format dd.mm.yyyy  h:mm";
extern datetime   NextPublicHoliday = D'23.12.2009 22:00';
extern string     isi="----Immediate basket features----";
extern bool       ShowImmediateBuyBasket=true;
extern bool       ShowImmediateSellBasket=true;
extern bool       ShowImmediateCloseBasket=true;
extern color      LabelColour=Yellow;
extern string     hed="----Hedging----";
extern bool       AllowHedging=true;
//extern int        MaxHedgeTradesAllowed=1;
extern double     HedgeAtLossPercent=5;
extern double     PercentageToHedge=5;
extern int        TrailingStopPips=100;
extern string     oae="----Odds and ends----";
extern int        DisplayGapSize=30;

//Pair extraction
string            InputString;//Holds the contents PairsToTrade for tidying yp etc
int               NoOfPairs;// Holds the number of pairs passed by the user via the inputs screen
string            TradePair[]; //Array to hold the pairs traded by the user

//Bid, Ask, Point, Digits - extracted by Start
double            point;
int               digits;
double            ask;
double            bid;

//Time frames
int               Htf1;

//Public hols
//int               PublicHolidayStarts;
//int               PublicHolidayEnds;
   
//News
bool              NewsTime;

//RS Group indi & LtfSMA
double            LowerTfWhiteLine;
double            HigherTfWhiteLine;
double            LtfSMA, HtfSMA;
string            TrendDirection;

//Basket
double            BasketTP;
double            BasketSL;
bool              ForceBasketClosure;
int               NoOfTrades;
double            BasketUpl;
double            strongest;
int               Tries;

//Sleep at new candle formation
double            LastTime[];

//Hedging
string            HedgeComment = "Hedge for 24H";

// Correlation
double            GroupCorrelation;

//Misc stuff
string            ScreenMessage, Gap;
bool              RobotDisabled;
string            DisabledMessage;
int               OldBars;

void DisplayUserFeedback()
{

   ScreenMessage = "";
   
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trading ", PairsToTrade, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "BaseLot size = ", BaseLot, NL);
   if (TradeLong) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trading Long", NL);
   if (TradeShort) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trading Short", NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "RS Group JPY V1.2 Strength Index White line readings: ", LowerTfWhiteLine, "  ", HigherTfWhiteLine, NL);   
   if (UseSma)
   {
      ScreenMessage = StringConcatenate(ScreenMessage, Gap, "LtfSMA:  ", LtfSMA, ":  HtfSMA  ", HtfSMA, 
                     ": Trend direction = ", TrendDirection, NL);   
   }
   GetGroupCorrelation();
   ScreenMessage= StringConcatenate(ScreenMessage, Gap, "Group correlation = ",GroupCorrelation);
   if (GroupCorrelation <= 0.7) ScreenMessage= StringConcatenate(ScreenMessage, ": Trading is not allowed ");
   if (GroupCorrelation > 0.7) ScreenMessage= StringConcatenate(ScreenMessage, ": Trading is allowed ");
   ScreenMessage= StringConcatenate(ScreenMessage,NL);
   ScreenMessage= StringConcatenate(ScreenMessage, Gap, "Maximum spread is ",MaxSpreadAllowed," pips",NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Emergency Stop loss = ", EmergencyStopLoss, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Emergency Take profit: ", EmergencyTakeProfit, NL);   
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Basket Take Profit: ", DoubleToStr(BasketTP, 2), NL);   
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Basket Stop Loss: ", DoubleToStr(BasketSL, 2), NL);   
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Magic number: ", MagicNumber, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Trade comment: ", TradeComment, NL);
   //ScreenMessage = StringConcatenate(ScreenMessage, Gap, "NextPublicHoliday1: ", TimeToStr(NextPublicHoliday), NL);
   ScreenMessage= StringConcatenate(ScreenMessage, Gap, "StartSuspend = ", DoubleToStr(StartSuspend, 2), NL);
   ScreenMessage= StringConcatenate(ScreenMessage, Gap, "EndSuspend = ", DoubleToStr(EndSuspend, 2), NL);
   ScreenMessage= StringConcatenate(ScreenMessage, Gap, "Friday close = ", DoubleToStr(FridayClose, 2), NL);
   if (UseNewsFilter) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "News filter is turned on ", NL);
   else ScreenMessage = StringConcatenate(ScreenMessage, Gap, "News filter is turned off ", NL);   
   if (AllowHedging) 
   {
      ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Hedging is enabled at ", 
            HedgeAtLossPercent, "% (" ,NormalizeDouble(-(AccountBalance() * 5) / 100, 2),")", NL);   
   }//if (AllowHedging) 
   if (CriminalIsECN) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "CriminalIsECN = true:    ", NL);
   else  ScreenMessage = StringConcatenate(ScreenMessage, Gap, "CriminalIsECN = false:    ", NL);
   double LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Lotstep = ", LotStep, NL);
      
   Comment(ScreenMessage);
   
}//End void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----

   //This robot is not to be used on live accounts yet
   if (!IsDemo() )
   {
      MessageBox("This robot will not run on a live account.");
      Comment("                This robot does not run on a live account");
      DisabledMessage = "This robot does not run on a live account";
      RobotDisabled = true;
      return;
   }//if (IsDemo() )
   
   
   //Check magic number.
   if (!IsDemo() )
   {
      if (MagicNumber == 123456)
      {
         MessageBox("You cannot run this robot until changed the MagicNumber input from the default of 12345." + NL 
                    + "Please reload the robot with a new MagicNumber input.");
         Comment("                This robot can do nothing. Please reload it");
         DisabledMessage = "You need to change the MagicNumber input";
         RobotDisabled = true;
         return;
      }//if (MagicNumber == 12345)
   }//if (!IsDemo)
      
   //Insufficient length
   string mn = DoubleToStr(MagicNumber,0);
   if (StringLen(mn) < 5)
   {
      MessageBox("Your MagicNumber input needs to be at least 5 digits long, Your MagicNumber is " + mn + NL 
                 + "Please reload the robot with the MagicNumber input containing at least 5 digits - the more the better.");
      Comment("                This robot can do nothing. Please reload it");
      DisabledMessage = "You need to make the MagicNumber input at 5 digits long - more is better";
      RobotDisabled = true;
      return;
   }//if (StringLen(mn) < 5)

   //Check chart and tf
   int index = StringFind(Symbol(), "GBPJPY");
   if (index == -1)
   {
      MessageBox("Sorry. This robot must go on a GBPJPY chart. The robot cannot function.");
      DisabledMessage = "Incorrect chart for this robot. Please close the chart and reload onto a GPPJPY chart.";
      RobotDisabled = true;
      return;
   }//if (index == -1)
   if (Period() != PERIOD_H1)
   {
      MessageBox("Warning. This robot should go on a GBPJPY H1 chart for best trading results.");
   }//if (index == -1)
   
   //Check size of hedge percentage
   if (!IsDemo() && HedgeAtLossPercent > 7)
   {
      HedgeAtLossPercent = 7;
      MessageBox("Information. The maximum allowable HedgeAtLossPercent input is 7");
   }//if (!IsDemo() && HedgeAtLossPercent > 7)

   //Amend inputs to cater for different broker digits
   int dig = MarketInfo(Symbol(), MODE_DIGITS);
   if (dig == 2)
   {   
      EmergencyStopLoss/= 10;
      EmergencyTakeProfit/= 10;
      MaxSpreadAllowed/= 10;
      TrailingStopPips/= 10;
   }//if (dig = 3)
   
   //Extract the pairs traded by the user
   // Cleanup first
   InputString=PairsToTrade;
   CleanUpInputString();
   
   // Extract the number of paraaters passed by the user
   CalculatePairsPassed();
   
   string AddChar = StringSubstr(Symbol(),6,4);
   
   // Resize the array appropriately
   string NewArray = ArrayResize(TradePair, NoOfPairs);
   
   int Index = 0;//For searching InputString
   int LastIndex = 0;//Points the the most recent Index
   for (int cc = 0; cc < NoOfPairs; cc ++)
   {
      Index = StringFind(InputString, ",",LastIndex);
      if (Index > -1)
      {
         TradePair[cc] = StringSubstr(InputString, LastIndex,Index-LastIndex);
         TradePair[cc] = StringTrimLeft(TradePair[cc]);
         TradePair[cc] = StringTrimRight(TradePair[cc]);
         TradePair[cc] = StringConcatenate(TradePair[cc], AddChar);
         
         LastIndex = Index+1;         
      }//if (Index > -1)            
   }//for (int cc; cc<NoOfPairs; cc ++)

   // Set up period if for higher filters
   if (Period() == PERIOD_M1) {Htf1 = PERIOD_M15;}
   if (Period() == PERIOD_M5) {Htf1 = PERIOD_M15;}
   if (Period() == PERIOD_M15) {Htf1 = PERIOD_H1;}
   if (Period() == PERIOD_M30) {Htf1 = PERIOD_H4;}
   if (Period() == PERIOD_H1) {Htf1 = PERIOD_H4;}
   if (Period() == PERIOD_H4) {Htf1 = PERIOD_D1;}
   if (Period() == PERIOD_D1) {Htf1 = PERIOD_W1;}
   if (Period() == PERIOD_W1) {Htf1 = PERIOD_W1;}
   if (Period() == PERIOD_MN1) RobotDisabled  = false;

   Gap="";
   if (DisplayGapSize >0)
   {
      for (cc=0; cc< DisplayGapSize; cc++)
      {
         Gap = StringConcatenate(Gap, " ");
      }   
   }

  
  
   bool TradeExists = DoesTradeExist(Symbol(), OP_BUY);
   if (!TradeExists) TradeExists = DoesTradeExist(Symbol(), OP_SELL);
   
   OldBars=Bars;
   for (cc = 0; cc < NoOfPairs; cc++) 
   {   
      LastTime[cc] = iTime(TradePair[cc], 0, 0);
   }//for (cc = 0; cc < NoOfPairs; cc++) 

   //start();
   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment("");
   
   ObjectDelete("Immediate Buy Basket");
   ObjectDelete("Immediate Sell Basket");
   ObjectDelete("Immediate Close Basket");
   
//----
   return(0);
}


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

void CalculatePairsPassed()
{
   // Calculates the numbers of paramaters passed in MagicNumber and TradeComment.
   
   int Index = 0;//For searching NoTradePairs
   int LastIndex;//Points the the most recent Index
   
   while(Index > -1)
      {
         Index = StringFind(InputString, ",",LastIndex);
         if (Index > -1)
         {
            NoOfPairs ++;
            LastIndex = Index+1;            
         }//if (Index > -1)
      }//while(int cc > -1)
   
   
   
}//End void CalculatePairsPassed()


bool DoesTradeExist(string symbol, int type)
{
   //Returns true if there is already a trade in place, else false
   
   if (OrdersTotal() == 0) return(false); //nothing to do
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() == MagicNumber && OrderSymbol() == symbol && OrderType() == type) return(true);   
   }//for (int cc = OrdersTotal() - 1; cc >= 0, cc--)
   
   //Got this far, so no trade exists
   return(false);

}//bool DoesTradeExist(string symbol, int type)

bool SendTrade(int type, string symbol)
{
   // Attempts to place a trade according to type, i.e.
   // 0 = OP_BUY
   // 1 = OP_SELL
   // 4 = OP_BUYSTOP
   // 5 = OP_SELLSTOP

   // Check spread
   if (MarketInfo(symbol, MODE_SPREAD) > MaxSpreadAllowed)
   {
      string rr;
      if (type == 0) rr = "Buy ";
      else rr = "Sell";
      Alert(symbol, " scooby-doo basket ", rr, " cancelled; spread too wide");
      return(false);// Spread too large, so abort send
   }//if (MarketInfo(NULL, MODE_SPREAD) > MaxSpreadAllowed)

   //Convert sl and tp from integers to doubles
   double ConvertedStopLoss = EmergencyStopLoss;
   double ConvertedTakeProfit = EmergencyTakeProfit;
   
   double sl = NormalizeDouble(ConvertedStopLoss * point, digits);
   double tp = NormalizeDouble(ConvertedTakeProfit * point, digits);
   
   RefreshRates();
   
   // Buy trade
   if (type == 0)
   {
      double TradePrice=ask;
      double Stop = NormalizeDouble(ask - sl,digits);
      double Take = NormalizeDouble(ask + tp,digits);
      
   }//if (type == 0)   
   
   
   // Sell trade
   if (type == 1)
   {
      TradePrice=bid;      
      Stop = NormalizeDouble(bid + sl,digits);
      Take = NormalizeDouble(bid - tp,digits);
      
   }//if (type == 1)
   
   //Calculate differential lot size
   double LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);   
   //Make sure that there are not too many decimal places in the result of the calculation
   int decimals;
   if (LotStep >0 && LotStep < 0.1) decimals = 2;//0.01
   if (LotStep >0.09 && LotStep < 1) decimals = 1;//0.1
   if (LotStep >0.9) decimals = 0;//1   
   double PairBid = MarketInfo(symbol, MODE_BID);
   double Lot = (NormalizeDouble(BaseLot * (strongest / PairBid), decimals));

   
   //Non ECN crook
   if (!CriminalIsECN) int ticket = OrderSend(symbol,type, Lot, TradePrice, 50, Stop, Take, TradeComment, MagicNumber,0, CLR_NONE);
   
   //Is a 2 stage criminal
   if (CriminalIsECN)
   {
     ticket = OrderSend(symbol, type, Lot, TradePrice, 50, 0, 0, TradeComment, MagicNumber,0, CLR_NONE);
	  if (EmergencyStopLoss != 0)
	  {
		  if (ticket > 0)
		  {
			  bool result = OrderModify(ticket, OrderOpenPrice(),	Stop, Take, 0, CLR_NONE);
			  if (!result)
			  {
			      int err=GetLastError();
               Alert(Symbol(), " ", type," TP order modify failed with error(",err,"): ",ErrorDescription(err));
               Print("Order send failed with error(",err,"): ",ErrorDescription(err));      
			  }//if (!result)
		  }//if (ticket > 0)	  
	  }//if (Take != 0)
	  else Print("Skipping OrderModify because no SL or TP specified.");
      
   }//if (CriminalIsECN)

   //Error trapping for both   
   if (ticket < 0)
   {
      err=GetLastError();
      Alert(symbol, " ", type," order send failed with error(",err,"): ",ErrorDescription(err),
                     "Lots=",Lot);
      Print("Order send failed with error(",err,"): ",ErrorDescription(err));
      if (err == 146) Sleep(1000);//Trade context busy error, so sleep 1 second to give it a break
      return(false);
   }//if (ticket < 0)
   else return(true);

}//End void SendTrade(type)

bool SendHedgeTrades()
{
   //Sends hedge trades.
   //Returns true if a trades was sent, else false
   
   
   double loss = 0;
   string symbol;
   int type, digits;
   double lots, LotStep;
   
   //Find the biggest losing trade
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() == MagicNumber && OrderComment() != HedgeComment)
      {
         if (OrderProfit() < loss)
         {
            symbol = OrderSymbol();
            type = OrderType();
            lots = OrderLots();
            loss = OrderProfit();
            digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
            LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);   
         }//if (OrderProfit() < loss)         
      }//if (OrderMagicNumber() == MagicNumber && OrderComment() != HedgeComment)
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   if (symbol == "") return;//Nothing to do
   
   //Make sure that there are not too many decimal plases in the result of the calculation
   int decimals;
   if (LotStep >0 && LotStep < 0.1) decimals = 2;//0.01
   if (LotStep >0 && LotStep < 0.1 && LotStep != 0.01) decimals = 1;//Truncate if the criminal is playing cute
   if (LotStep >0.09 && LotStep < 1) decimals = 1;//0.1
   if (LotStep >0.9) decimals = 0;//1
   
   //Calculate 5% of the original trade size
   double SendLots = NormalizeDouble(lots * PercentageToHedge / 100, decimals);
   if (SendLots == 0) SendLots = LotStep;
   
   RefreshRates();
   
   if(type == OP_SELL)
   {
      double TradePrice = MarketInfo(symbol, MODE_ASK);  
      int ticket = OrderSend(symbol, OP_BUY, SendLots, TradePrice, 50, 0, 0, HedgeComment, MagicNumber,0, CLR_NONE);
      if (ticket < 0)
      {
         int err=GetLastError();
         Alert(symbol, " Buy hedge order send failed with error(",err,"): ",ErrorDescription(err));
         return(false);
      }//if (ticket < 0)
      else return(true);      
   }//if(type == OP_SELL)
   
   if(type == OP_BUY)
   {
      TradePrice = MarketInfo(symbol, MODE_BID);
      ticket = OrderSend(symbol, OP_SELL, SendLots, TradePrice, 50, 0, 0, HedgeComment, MagicNumber,0, CLR_NONE);
      if (ticket < 0)
      {
         err=GetLastError();
         Alert(symbol, " Sell hedge order send failed with error(",err,"): ",ErrorDescription(err));            
         return(false);
      }//if (ticket < 0)  
      else return(true);              
   }//if(type == OP_BUY)
   //Got this far, so no hedge has been sent
   return(false);
   
}//End bool SendHedgeTrades()


void MonitorHedgeTrades()
{
   //Called when there are hedged trades open.
   //Manages the trailing stop


   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() == MagicNumber && OrderComment() == HedgeComment)
      {         
         double sl=OrderStopLoss(); //Stop loss
         bid = MarketInfo(OrderSymbol(), MODE_BID);
         ask = MarketInfo(OrderSymbol(), MODE_ASK);
         digits = MarketInfo(OrderSymbol(), MODE_DIGITS);
         point = MarketInfo(OrderSymbol(), MODE_POINT);
         if (OrderType()==OP_BUY) 
         {            
	         if (bid >= OrderOpenPrice() + (TrailingStopPips*point))
	         {
	             if (OrderStopLoss() == 0) sl = OrderOpenPrice();
	             if (bid > sl + (TrailingStopPips*point))
	             {
	                sl = NormalizeDouble(bid - (TrailingStopPips*point), digits);
	                bool result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
                  if (result)
                  {
                     Print("Trailing stop updated: ", OrderSymbol(), ": SL ", sl, ": Ask ", ask);
                  }//if (result) 
                  else
                  {
                     int err=GetLastError();
                     Print(Symbol(), " order modify failed with error(",err,"): ",ErrorDescription(err));
                  }//else

	             }//if (bid > sl +  (TrailingStopPips*point))
	         }//if (bid >= OrderOpenPrice() + (TrailingStopPips*point))
         }//if (OrderType()==OP_BUY) 

         if (OrderType()==OP_SELL) 
         {
		      if (ask <= OrderOpenPrice() - (TrailingStopPips*point))
		      {                
		          if (OrderStopLoss() == 0) sl = OrderOpenPrice();
		          if (ask < sl -  (TrailingStopPips*point))
		          {
	                  sl = NormalizeDouble(ask + (TrailingStopPips*point), digits);
  	                  result = OrderModify(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
                     if (result)
                     {
                        Print("Trailing stop updated: ", OrderSymbol(), ": SL ", sl, ": Bid ", bid);
                     }//if (result)
                     else
                     {
                        err=GetLastError();
                        Print(Symbol(), " order modify failed with error(",err,"): ",ErrorDescription(err));
                     }//else
    
		          }//if (ask < sl -  (TrailingStopPips*point))
		      }//if (ask <= OrderOpenPrice() - (TrailingStopPips*point))
         }//if (OrderType()==OP_SELL) 


      }//if (OrderMagicNumber() == MagicNumber && OrderComment() = HedgeComment)
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)

}//End MonitorHedgeTrades()

void CheckBasketTpSlTarget()
{
   //Calculates the basket upl and sets the close basket variable if need be
   ForceBasketClosure = false;
   NoOfTrades=0;
   BasketUpl = 0;
   int NoOfHedgeTrades;
   
   bool OverSoldBasket, OverBoughtBasket;
   
   static bool RemoveStops = false;
   if (RemoveStops) RemoveStops = RemoveIndividualStops();//In case any modify failed
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() == MagicNumber)
      {
         NoOfTrades++;
         BasketUpl+= OrderProfit();
         if (OrderType() == OP_SELL && OrderComment() != HedgeComment) OverSoldBasket = true;
         if (OrderType() == OP_BUY && OrderComment() != HedgeComment) OverBoughtBasket = true;
         if (OrderComment() == HedgeComment) NoOfHedgeTrades++;            
      }//if (OrderMagicNumber == MagicNumber)      
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   
   //Set the close force variable if upl is <= basket stop loss
   if (BasketUpl <= BasketSL && NoOfTrades > 0)
   {
      ForceBasketClosure = true;
      return;
   }//if (BasketUpl <= BasketSl)
   
   if (AllowHedging)
   {   
      //Handle basket hedging code. Allows for resends if a trade failure happened.
      //Checks the need to send a new hedge trade every 15 minutes
      double HedgeDd = NormalizeDouble(-(AccountBalance() * HedgeAtLossPercent) / 100, 2);
      if (BasketUpl <= HedgeDd)
      {
         bool NewHedgeNeeded = true;
         //Check time of previous hedge send
         if (NoOfHedgeTrades > 0)
         {
            datetime TimeHedgeSent = GlobalVariableGet(HedgeTimeGV);
            datetime TimeNow = TimeLocal();
            if ( (TimeNow - TimeHedgeSent) < (15 * 60) )
            {
               NewHedgeNeeded = false;
            }//if ( (TimeNow - TimeHedgeSent) < (15 * 60) )
            
         }//if (NoOfHedgeTrades > 0)
         
         if (NewHedgeNeeded)
         {
            bool TradeSent = SendHedgeTrades();
            if (TradeSent) 
            {
               NoOfHedgeTrades++;
               GlobalVariableSet(HedgeTimeGV, TimeLocal() );
            }//if (TradeSent) 
         
            if (NoOfHedgeTrades == 1) RemoveStops = RemoveIndividualStops();         
         }//if (NewHedgeNeeded)
         
      }//if (BasketUpl <= HedgeDd)
   }//if (AllowHedging)
   
   //Monitor open hedge trades
   if (NoOfHedgeTrades > 0)
   {
      TpMultiplicationFactor=20;
      if (BasketUpl >= BasketTP && NoOfTrades > 0)
      {
         ForceBasketClosure = true;
         CloseBasket();
      }//if (BasketUpl >= BasketTP && NoOfTrades > 0)      
      MonitorHedgeTrades();
      return;
   }//if (NoOfHedgeTrades > 0)

   
   
   //Set the close force variable if upl is >= tp
   if (BasketUpl >= BasketTP && NoOfTrades > 0) 
   {
      ForceBasketClosure = true;
      GlobalVariableDel(HedgeTimeGV);      
      
      //Reread the indi just to make sure      
      //LowerTfWhiteLine = GetRSIbasket(Period(), 0);
         
      //Close a Sell xxxJPY if indi > 50
      //if (OverSoldBasket && LowerTfWhiteLine > 50)
      //{
         //ForceBasketClosure = true;
      //}//if (OverSoldBasket && LowerTfWhiteLine > 50)
      
      //Close a Buy xxxJPY if indi < 50
      //if (OverBoughtBasket && LowerTfWhiteLine < 50)
      //{
         //ForceBasketClosure = true;
      //}//if (OverBoughtBasket && LowerTfWhiteLine < 50)
      
      
   }//if (BasketUpl >= BasketTP && NoOfTrades > 0) 
         
}//End CheckBasketTpSlTarget()

bool RemoveIndividualStops()
{
   //Removes individual stop losses when hedging has kicked in
   
   bool succeeded = true;
   for (int cc = OrdersTotal(); cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      if (OrderMagicNumber()==MagicNumber && OrderComment() != HedgeComment)      
      {
         if (OrderStopLoss() != 0)
         {
            bool result = OrderModify(OrderTicket(), OrderOpenPrice(), 0, OrderTakeProfit(), OrderExpiration(), CLR_NONE);
            if (!result) succeeded = false;
         }//if (OrderStopLoss() != 0)
            
      }//if (OrderMagicNumber()==MagicNumber)
   }//for (int cc=0; cc<OrdersTotal(); cc++)

   return (succeeded);
}//End bool RemoveIndividualStops()


void CloseBasket()
{
   
   
   
   //Closes an open basket after upl is hit

   ForceBasketClosure = false;
   if (OrdersTotal() == 0) return; //Just in case
   
   
   for (int cc = OrdersTotal(); cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      if (OrderMagicNumber()==MagicNumber)      
      {
            bool result =OrderClose(OrderTicket(),OrderLots(), OrderClosePrice(),5000,CLR_NONE);
            if (!result) 
            {
               ForceBasketClosure = true;
               cc = OrdersTotal();
            }//if (!result) 
            
            else cc++;         
      }//if (OrderMagicNumber()==MagicNumber)
   }//for (int cc=0; cc<OrdersTotal(); cc++)



}//End void CloseBasket()

void GetStrongestPriceInBasket()
{
   //Cycles through the list of pairs being traded to find the strongest pair
   
   strongest=0;
   
   for (int cc = 0; cc < NoOfPairs; cc ++)
   {   
      string symbol = TradePair[cc];
      bid = MarketInfo(symbol, MODE_BID);
      if (bid > strongest) 
      {
         string ss = symbol;
         strongest = bid;
      }//if (bid > strongest) 
         
   }//for (int cc = 0; cc < NoOfPairs; cc ++)

   
}//void GetStrongestPriceInBasket(int magic)

void ImmediateBuyxxxJPY()
{

   //Allow for instant placing of a buy basket
   GetStrongestPriceInBasket();
   if (RobotCalculatesLotSize) CalculateBaseLotSize();
   for (int cc = 0; cc < NoOfPairs; cc ++)
   {   
      string symbol = TradePair[cc];
      point = MarketInfo(symbol, MODE_POINT);
      digits = MarketInfo(symbol, MODE_DIGITS);
      ask = MarketInfo(symbol, MODE_ASK);
      bid = MarketInfo(symbol, MODE_BID);

      bool TradeExists = DoesTradeExist(symbol, OP_BUY);
      if (!TradeExists)
      {
         bool TradeSent = SendTrade(0, symbol);  
      }//if (!TradeExists)
   }//for (int cc = 0; cc < NoOfPairs; cc ++)

}//void ImmediateBuyxxxJPY()

void ImmediateSellxxxJPY()
{
   
   //Allow for instant placing of a sell basket
   
   GetStrongestPriceInBasket();
   if (RobotCalculatesLotSize) CalculateBaseLotSize();
   for (int cc = 0; cc < NoOfPairs; cc ++)
   {   
      string symbol = TradePair[cc];
      point = MarketInfo(symbol, MODE_POINT);
      digits = MarketInfo(symbol, MODE_DIGITS);
      ask = MarketInfo(symbol, MODE_ASK);
      bid = MarketInfo(symbol, MODE_BID);

      bool TradeExists = DoesTradeExist(symbol, OP_SELL);
      if (!TradeExists)
      {
         bool TradeSent = SendTrade(1, symbol);  
      }//if (!TradeExists)
   }//for (int cc = 0; cc < NoOfPairs; cc ++)

}//void ImmediateBuyxxxJPY()

void NewsFilterCheck()
{
   // Checks for impending news events.

   //Call the news reader every 1 minute
   static int OldBar;
   if (OldBar == iBars(Symbol(), PERIOD_M5) ) return(false);
   OldBar = iBars(Symbol(), PERIOD_M5);


   NewsTime = false;    
   for(int cc = 0; cc < NoOfPairs; cc++)
   {
      //Only need to look at AUDJPY GBPJPY USDJPY
      if (StringSubstr(Symbol(), 0, 6) != "AUDJPY" && StringSubstr(Symbol(), 0, 6) != "GBPJPY" 
         && StringSubstr(Symbol(), 0, 6) != "USDJPY") continue;
      int minutesSincePrevEvent = iCustom(NULL, 0, "FFCal Scoobs", TradePair[cc], true, true, false, true, true, 1, 0);
      int minutesUntilNextEvent = iCustom(NULL, 0, "FFCal Scoobs", TradePair[cc], true, true, false, true, true, 1, 1);
      if((minutesUntilNextEvent <= MinsBeforeNews) || (minutesSincePrevEvent <= MinsAfterNews))
      {
         //News event within the chosen timescale
         int impactOfNextEvent = iCustom(NULL, 0, "FFCal Scoobs", TradePair[cc], true, true, false, true, true, 2, 1);
         //Should the robot suspend trading?
         if (impactOfNextEvent >= NewsImpact)
         {
            NewsTime = true;
            break;
         }//if (impact >= NewsImpact)         
      }//if((minutesUntilNextEvent <= Mins.Before.News) || (minutesSincePrevEvent <= Mins.After.News))
   }//for(int cnt = 0; cnt < PairsToTrade; cnt++)  
   
}// End void NewsFilterCheck()

void CalculateBaseLotSize()
{
   //Called if RobotCalulatesLotSize=true. Auto calcs the lot size based on x lots per x units of currency


   if (BaseLot == MarketInfo(Symbol(), MODE_MAXLOT) ) return;//Can't go any bigger
   
   double LotStep = MarketInfo(Symbol(), MODE_LOTSTEP);
   
   //Make sure that there are not too many decimal plases in the result of the calculation
   int decimals;
   if (LotStep >0 && LotStep < 0.1) decimals = 2;//0.01
   if (LotStep >0 && LotStep < 0.1 && LotStep != 0.01) decimals = 1;//Truncate if the criminal is playing cute
   if (LotStep >0.09 && LotStep < 1) decimals = 1;//0.1
   if (LotStep >0.9) decimals = 0;//1
   
   
   BaseLot = NormalizeDouble(AccountEquity() / 25000, decimals);
   
   //....new BaseLot calc. Included for Dee and commented out
 /*
   if ( MarketInfo(Symbol(), MODE_LOTSIZE)==10000 ) //mini acct: $10,000 position per 1.0 lots
   {
      BaseLot = NormalizeDouble(AccountBalance() / 20000, decimals) * 10;
   } 
   else //standard acct: $100,000 position per 1.0 lots
   {   
      BaseLot = NormalizeDouble(AccountBalance() / 20000, decimals);
   }
 */
   //....

   double MaxLots = MarketInfo(Symbol(), MODE_MAXLOT);

   //Adjust incorrect lot sizes
   if (BaseLot < MarketInfo(Symbol(), MODE_MINLOT) )
   {
      BaseLot = MarketInfo(Symbol(), MODE_MINLOT);      
   }//if (BaseLot < MarketInfo(Symbol(), MODE_MINLOT) )
   
   if (BaseLot > MarketInfo(Symbol(), MODE_MAXLOT) )
   {
      BaseLot = MarketInfo(Symbol(), MODE_MAXLOT);      
   }//if (BaseLot < MarketInfo(Symbol(), MODE_MAXLOT) )


}//End void CalculateBaseLotSize()

void ShowImmediateBuyLabel()
{
   
   if (ObjectFind("Immediate Buy Basket") == -1)
   {
      ObjectCreate("Immediate Buy Basket", OBJ_LABEL, 0, 0, 0);
      ObjectSet("Immediate Buy Basket", OBJPROP_BACK, 0);
      ObjectSet("Immediate Buy Basket", OBJPROP_CORNER, 2);
      ObjectSet("Immediate Buy Basket", OBJPROP_XDISTANCE, 6);
      ObjectSet("Immediate Buy Basket", OBJPROP_YDISTANCE, 20);
      ObjectSetText("Immediate Buy Basket","Immediate Buy Basket", 12,"Times New Roman",LabelColour);
   }

   if (ObjectFind("Immediate Buy Basket") != -1 && ObjectGet("Immediate Buy Basket", OBJPROP_XDISTANCE)!=6)
   {
      ObjectSet("Immediate Buy Basket", OBJPROP_XDISTANCE, 6);
      ObjectSet("Immediate Buy Basket", OBJPROP_YDISTANCE, 20);
      ImmediateBuyxxxJPY();
   }

}//End Void ShowImmediateBuyLabel()

void ShowImmediateSellLabel()
{
   
   if (ObjectFind("Immediate Sell Basket") == -1)
   {
      ObjectCreate("Immediate Sell Basket", OBJ_LABEL, 0, 0, 0);
      ObjectSet("Immediate Sell Basket", OBJPROP_BACK, 0);
      ObjectSet("Immediate Sell Basket", OBJPROP_CORNER, 2);
      ObjectSet("Immediate Sell Basket", OBJPROP_XDISTANCE, 200);
      ObjectSet("Immediate Sell Basket", OBJPROP_YDISTANCE, 20);
      ObjectSetText("Immediate Sell Basket","Immediate Sell Basket", 12,"Times New Roman",LabelColour);
   }

   if (ObjectFind("Immediate Sell Basket") != -1 && ObjectGet("Immediate Sell Basket", OBJPROP_XDISTANCE)!=200)
   {
      ObjectSet("Immediate Sell Basket", OBJPROP_XDISTANCE, 200);
      ObjectSet("Immediate Sell Basket", OBJPROP_YDISTANCE, 20);
      ImmediateSellxxxJPY();
   }  

}//End Void ShowImmediateSellLabel()

void ShowImmediateCloseLabel()
{

   if (ObjectFind("Immediate Close Basket") == -1)
   {
      ObjectCreate("Immediate Close Basket", OBJ_LABEL, 0, 0, 0);
      ObjectSet("Immediate Close Basket", OBJPROP_BACK, 0);
      ObjectSet("Immediate Close Basket", OBJPROP_CORNER, 2);
      ObjectSet("Immediate Close Basket", OBJPROP_XDISTANCE, 400);
      ObjectSet("Immediate Close Basket", OBJPROP_YDISTANCE, 20);
      ObjectSetText("Immediate Close Basket","Immediate Close Basket", 12,"Times New Roman",LabelColour);
   }//if (ObjectFind("Immediate Close Basket") == -1)

   if (ObjectFind("Immediate Close Basket") != -1 && ObjectGet("Immediate Close Basket", OBJPROP_XDISTANCE)!=400)
   {
      ObjectSet("Immediate Close Basket", OBJPROP_XDISTANCE, 400);
      ObjectSet("Immediate Close Basket", OBJPROP_YDISTANCE, 20);
      CloseBasket();
   }// if (ObjectFind("Immediate Close Basket") != -1 && ObjectGet("Immediate Close Basket", OBJPROP_XDISTANCE)!=400)

}//End void ShowImmediateCloseLabel()

double GetRSIbasket(int timefram, int pos)
{

   
   //Set up suffixes
   string AddChar = StringSubstr(Symbol(),6,4);
   
   double RSIbasket,divisor=0;
   double r1=0, r2=0, r3=0, r4=0, r5=0, r6=0, r7=0;
   string long_basket1, long_basket2, long_basket3, long_basket4, long_basket5, long_basket6, long_basket7;
   int  T3_Period = 2;
   long_basket1 = "AUDJPY" + AddChar;
   long_basket2 = "CADJPY" + AddChar;
   long_basket3 = "CHFJPY" + AddChar;
   long_basket4 = "EURJPY" + AddChar;
   long_basket5 = "GBPJPY" + AddChar;
   long_basket6 = "NZDJPY" + AddChar;
   long_basket7 = "USDJPY" + AddChar;
   
   if ( iClose(long_basket1,0,pos) != 0 )
      {
         r1 = iRSI(long_basket1,timefram,T3_Period,PRICE_WEIGHTED,pos);
         divisor++;
      }   
   
   if ( iClose(long_basket2,0,pos) != 0 )
      {
         r2 = iRSI(long_basket2,timefram,T3_Period,PRICE_WEIGHTED,pos);
         divisor++;
      }
   
   if ( iClose(long_basket3,0,pos) != 0 )
      {
         r3 = iRSI(long_basket3,timefram,T3_Period,PRICE_WEIGHTED,pos);
         divisor++;
      }   
   
   if ( iClose(long_basket4,0,pos) != 0 )
      {
         r4 = iRSI(long_basket4,timefram,T3_Period,PRICE_WEIGHTED,pos);
         divisor++;
      }
   
   if ( iClose(long_basket5,0,pos) != 0 )
      {         
         r5 = iRSI(long_basket5,timefram,T3_Period,PRICE_WEIGHTED,pos);
         divisor++;
      }
   
   if ( iClose(long_basket6,0,pos) != 0 )
      {         
         r6 = iRSI(long_basket6,timefram,T3_Period,PRICE_WEIGHTED,pos);
         divisor++;
      }   
   
   if ( iClose(long_basket7,0,pos) != 0 )
      {
         r7 = iRSI(long_basket7,timefram,T3_Period,PRICE_WEIGHTED,pos);
         divisor++;
      }   

   RSIbasket = r1 + r2 + r3 + r4 + r5 + r6 + r7;
   RSIbasket = 100 - RSIbasket / divisor;

   return(RSIbasket);

}// End double GetRSIbasket(int timefram, int pos)

void CalculateBasketStoploss()
{

   BasketSL = -AccountBalance() * (BasketStopLossPercentage / 100);
   
}//End void CalculateBasketStoploss()



double Cor(string base, string hedge, int corperiod)
{
   double u1=0,l1=0,s1=0;
   for(int i = corperiod - 1; i >= 0; i--)
   {
      u1 += u(symboldif(base, i, corperiod), symboldif(hedge, i, corperiod));
      l1 += powdif(symboldif(base, i, corperiod));
      s1 += powdif(symboldif(hedge, i, corperiod));
   }//for(int i = corperiod - 1; i >= 0; i--)
   
   if(l1*s1 > 0) return(u1 / MathSqrt(l1*s1));
}//End double Cor(string base, string hedge, int corperiod)

double symboldif(string symbol, int shift, int corperiod)
{
   return(iClose(symbol, 1440, shift) -
   iMA(symbol, 1440, corperiod, 0, MODE_SMA,
PRICE_CLOSE, shift));
}//End double symboldif(string symbol, int shift, int corperiod)

double powdif(double val)
{
   return(MathPow(val, 2));
}//End double powdif(double val)

double u(double val1,double val2)
{
   return((val1*val2));
}//End double u(double val1,double val2)

void GetGroupCorrelation()
{
   //Courtesy of Scoobs. No idea how it works
   
   GroupCorrelation = 0;
   for(int i = 0; i < NoOfPairs; i++)
   {
      if(TradePair[i] != Symbol())
      {
         GroupCorrelation += Cor(Symbol(),TradePair[i],15);
      }//if(TradePair[i] != Symbol())
   }//for(int i = 0; i < NoOfPairs; i++)
   
   GroupCorrelation = GroupCorrelation / (NoOfPairs - 1);
      

}//End void GetGroupCorrelation()

bool DoChecksFirst()
{
   //Checks news, Sunday candle and public hols filters. Returns false if trading is not allowed, else return true
   
   //Check news filter first
   if (UseNewsFilter) 
   {
      NewsFilterCheck();      
   }//if (UseNewsFilter) 
   
   if (NewsTime)
   {
      ScreenMessage = StringConcatenate(Gap, "Trading suspended because of news item", NL);
      GlobalVariableDel(OversoldGV);
      GlobalVariableDel(OverboughtGV);
      Comment(ScreenMessage);
      return(false);
   }//if (NewsTime)
      
   //Check public holiday filter
//   int now = TimeLocal();
//   int PublicHolidayStarts = NextPublicHoliday;
//   int PublicHolidayEnds = PublicHolidayStarts + (24 * 60) * 60;
//   if (now > PublicHolidayStarts && now < PublicHolidayEnds)
//   {
//      ScreenMessage = StringConcatenate(Gap, "Trading suspended because of public holiday", NL);
//      Comment(ScreenMessage);
//      return(false);
//   }//if (now > NextPublicHoliday1 || now > NextPublicHoliday2)

   //Check that user has not forgotten to enter the next holiday date
//   if (PublicHolidayStarts < now)
//   {
//      MessageBox("You need to enter the date of the next JPY public holiday. The robot is disabled until you do.");
//      DisabledMessage = "You need to enter the date of the next JPY public holiday.";
//      RobotDisabled = true;
//      return(false);
//   }//if (NextPublicHoliday1 < TimeLocal() && NextPublicHoliday2 < TimeLocal() )

   //Sunday candle
   if (!TradeSundayCandle && TimeDayOfWeek(TimeLocal())==0)
   {
      ScreenMessage = StringConcatenate(Gap, "Trading suspended because you do not trade the Sunday candle", NL);
      Comment(ScreenMessage);
      return(false);   
   }//if (!TradeSundayCandle && TimeDayOfWeek(TimeLocal())==0)

   

   //Got this far, so everything is ok
   return(true);
   
}//bool DoChecksFirst()

void CheckNewCandleFormation()
{
   //Forces the robot to wait for all the new candles to form
   //Code is an adaptation of that provided by fxjedi, so many thanks to fxjedi

   static double LastTime[];
   Comment(Gap + "New candle. Waiting for all new candles to form");
   bool rollover = false;
   while (!rollover)
   {
      rollover = true;
      for (int cc = 0; cc < NoOfPairs; cc++)
      {
         if (LastTime[cc] == iTime(TradePair[cc], 0, 0) && MarketInfo(TradePair[cc], MODE_SPREAD) > 0 
                                   && MarketInfo(TradePair[cc], MODE_SWAPLONG) != 0)
         {
            rollover = false;
         }//if (lastTime[cc] == iTime(symbols[cc], 0, 0)
      }//for (int cc = 0; cc < NoOfPairs; cc++)         
   }//while (!rollover)

   // now all candles are new and in lockstep so update stored timestamps      
   for (cc = 0; cc < NoOfPairs; cc++) 
   {   
      LastTime[cc] = iTime(TradePair[cc], 0, 0);
   }//for (cc = 0; cc < NoOfPairs; cc++) 
   
}//End void CheckNewCandleFormation()

/*void CalculateBasketTp()
{
   //Calculates the basket take profit
   GetStrongestPriceInBasket();
   for (int cc = 0; cc < NoOfPairs; cc++)
   {
      double PairBid = MarketInfo(TradePair[cc], MODE_BID);
      BasketTP+= BaseLot * (strongest / PairBid);   
   }//for (int cc = 0; cc < NoOfPairs; cc++)
   
   BasketTP/= NoOfPairs;
   BasketTP = NormalizeDouble(BasketTP * TpMultiplicationFactor,2);
   
}//End void CalculateBasketTp()
*/

double GetAO()
{
   //Returns the value of the basket AO
   
   double ao;
   for (int cc = 0; cc < NoOfPairs; cc++)
   {
      ao+= iAO(TradePair[cc], Period(), 0);
   }//for (int cc = 0; cc < NoOfPairs; cc++)
   
   ao/= NoOfPairs;
   return(ao);
   
}//End void GetAO()

//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

/*
Not sure I explained that very well so I will try and do it with pesudo code...

Over.Bought = 80
Over.Sold = 20

if(Old.Bar < Over.Sold)
Over.Sold = Old.Bar
else
Over.Sold = 20 //reset

if(Old.Bar > Over.Bought)
Over.Bought = Old.Bar
else
Over.Bought = 80 //reset

BUY XXXJPY if(Old.Bar >= Over.Bought && New.Bar < Over.Bought)

SELL XXXJPY if(Old.Bar <= Over.Sold && New.Bar > Over.Sold)

*/   
   if (RobotDisabled )
   {
      Comment("The robot has been suspended. Reason: ", DisabledMessage);
      return;
   }//if (RobotDisabled )

   if (IsTradeContextBusy() )
   {
      Comment("Trade context is busy because the criminal is too lazy, dim or both to provide a decent server. Please wait for the cretin to stop pissing around.");
      return;
   }//if (IsTradeContextBusy)

   //static bool BasketSendSucceeded = true;//Keeping track of whether a basket send succeeds of not
   Tries = 0;
   //Show immediate action labels.
   //Big, big thanks to matrixebiz; the code came from him
   if (ShowImmediateBuyBasket) ShowImmediateBuyLabel();
   if (ShowImmediateSellBasket) ShowImmediateSellLabel();
   if (ShowImmediateCloseBasket) ShowImmediateCloseLabel();

   
   //Lot size calculation
   if (RobotCalculatesLotSize) CalculateBaseLotSize();
   BasketTP = BaseLot * TpMultiplicationFactor;
   
   CalculateBasketStoploss();
         
   //Monitor open basket
   if (OrdersTotal() > 0)
   {
      CheckBasketTpSlTarget();//Also takes care of hedging
      if (ForceBasketClosure) CloseBasket();//Function will reset ForceBasketClosure if successful
      if (NoOfTrades > 0)
      {
         ScreenMessage = StringConcatenate(Gap, "Monitoring open basket", NL, Gap, "Basket take profit target is ", DoubleToStr(BasketTP, 2), NL);
         ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Basket Stop Loss: ", DoubleToStr(BasketSL, 2), NL);   
         ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Basket trades open: ", NoOfTrades, ": Upl = ", DoubleToStr(BasketUpl, 2), NL);
         if (AllowHedging) ScreenMessage = StringConcatenate(ScreenMessage, Gap, "Hedging is enabled at ", NormalizeDouble(-(AccountBalance() * 5) / 100, 2), NL);
         Comment(ScreenMessage);
         //if (BasketSendSucceeded) return;
         return;
      }//if (NoOfTrades > 0)
         
   }//if (OrdersTotal() > 0)
   
   
   //Check dead-time
   if (TimeHour(TimeLocal()) >= StartSuspend && TimeHour(TimeLocal()) <= EndSuspend)
   {
      Comment(Gap + "Trading suspended during dead hours");
      GlobalVariableDel(OversoldGV);
      GlobalVariableDel(OverboughtGV);
      GlobalVariableDel(HedgeTimeGV);      
      return;
   }//if (TimeHour(TimeLocal()) >= StartSuspend && TimeHour(TimeLocal()) <= EndSuspend)
   
   //Check Friday close
   if (TimeHour(TimeLocal() ) >= FridayClose && TimeDayOfWeek(TimeLocal() ) == 5)
   {
      Comment(Gap + "Trading suspended for Friday close");
      GlobalVariableDel(OversoldGV);
      GlobalVariableDel(OverboughtGV);         
      GlobalVariableDel(HedgeTimeGV);      
      return;
   }//if (TimeHour(TimeLocal()) >= FridayClose && DayOfWeek() == 5)
   
   //Check news and public hols filters first.
   bool FiltersOK = DoChecksFirst();
   if (!FiltersOK) return;   
   
   
   //Give new candles for all the pairs time to form at the start of a new JPY candle
   if (OldBars != Bars)
   {
      CheckNewCandleFormation();
      OldBars = Bars;
   }//if (OldBars != Bars)
      
   
   LowerTfWhiteLine = GetRSIbasket(Period(), 0);
   HigherTfWhiteLine = GetRSIbasket(Htf1, 0);
   LtfSMA = iMA(NULL, 0, 200, 0, MODE_SMA, PRICE_CLOSE, 0);
   HtfSMA = iMA(NULL, Htf1, 200, 0, MODE_SMA, PRICE_CLOSE, 0);
   TrendDirection = none;
   if (LtfSMA > HtfSMA) TrendDirection = up;
   if (LtfSMA < HtfSMA) TrendDirection = down;
   double AoVal = GetAO();


   //Look for an overbought setup.   
   //Spot when the indis are overbought
   if (LowerTfWhiteLine >= LowerTfOverBought && HigherTfWhiteLine >= HigherTfOverBought)
   {         
      GlobalVariableSet(OverboughtGV,0); //value does not matter
   }//if (LowerTfWhiteLine >= LowerTfOverBought && HigherTfWhiteLine >= HigherTfOverBought)


   //Look for an oversold setup.   
   //Spot when the indis are oversold
   if (LowerTfWhiteLine <= LowerTfOverSold && HigherTfWhiteLine <= HigherTfOverSold)
   {         
      GlobalVariableSet(OversoldGV,0); //value does not matter      
   }//if (hour == SellHourStarts etc)


   
   
   //Look for a long basket. Lower tf has to cross back below overbouht to trigger the basket
   if (GlobalVariableCheck(OverboughtGV) && LowerTfWhiteLine < LowerTfOverBought && TradeLong)
   {         
      //Cancel the basket if GJ is wrong side of 200 sma
      if (UseSma && (Bid < LtfSMA + 0.2 || TrendDirection == down) )
      {
         GlobalVariableDel(OverboughtGV);
         return;
      }//if (Bid < LtfSMA)
      
     /* //Lower low check
      if (Low[1] < Low[2])
      {
         GlobalVariableDel(OverboughtGV);
         return;      
      }//if (Bid < High[1])
      */
   
      //Correlation check
      GetGroupCorrelation();
      if (GroupCorrelation <= 0.7)
      {
         GlobalVariableDel(OverboughtGV);
         return;
      }//if (GroupCorrelation <= 0.7)
      
      //AO check
      if (AoVal <= 0)
      {
         GlobalVariableDel(OverboughtGV);
         return;
      }//if (AoVal <= 0)
      
      
      if (SendAlertNotTrade)
      {
         Alert("scooby-doo 24 H alert. Buy xxxJPY");
         GlobalVariableDel(OverboughtGV);
         return;
      }//if (SendAlertNotTrade)
      
      
      //BasketSendSucceeded = true;
      GetStrongestPriceInBasket();
      for (int cc = 0; cc < NoOfPairs; cc ++)
      {   
         string symbol = TradePair[cc];
         point = MarketInfo(symbol, MODE_POINT);
         digits = MarketInfo(symbol, MODE_DIGITS);
         ask = MarketInfo(symbol, MODE_ASK);
         bid = MarketInfo(symbol, MODE_BID);

         bool TradeExists = DoesTradeExist(symbol, OP_BUY);
         if (!TradeExists)
         {
            GlobalVariableDel(OverboughtGV);
            
            bool TradeSent = false;
            while (!TradeSent && Tries < 30)
            {
               TradeSent = SendTrade(0, symbol);
               if (!TradeSent) 
               {
                  Sleep(5000);//Half a second to avoid overloading
                  Tries++;
               }//if (!TradeSent)
            }//while (!TradeSent)
            
            //if (!TradeSent) 
            //{
               //GlobalVariableSet(OverboughtGV, 0);//Force a resend if a trade send fails
               //BasketSendSucceeded = false;
            //}//if (!TradeSent)    
         
         }//if (!TradeExists)                     
         Tries = 0;   
      }//for (int cc = 0; cc < NoOfPairs; cc ++)
   }//if (GlobalVariableCheck && LowerTfWhiteLine < LowerTfOverBought)

      
   //Look for a short basket. Lower tf has to cross back above oversold to trigger the basket
   if (GlobalVariableCheck(OversoldGV) && LowerTfWhiteLine > LowerTfOverSold && TradeShort)
   {        
      
      //Cancel the basket if GJ is wrong side of 200 sma
      if (UseSma && (Bid > LtfSMA - 0.2 || TrendDirection == up) )
      {
         GlobalVariableDel(OversoldGV);
         return;
      }//if (Bid > LtfSMA)

      /* //Higher high check
      if (High[1] > High[2])
      {
         GlobalVariableDel(OversoldGV);
         return;      
      }//if (Bid < High[1])
      */
      
      //Correlation check
      GetGroupCorrelation();
      if (GroupCorrelation < 0.7)
      {
         GlobalVariableDel(OversoldGV);
         return;
      }
      
      //AO check
      if (AoVal >= 0)
      {
         GlobalVariableDel(OversoldGV);
         return;
      }//if (AoVal <= 0)
      
      if (SendAlertNotTrade)
      {
         Alert("scooby-doo 24 H alert. Sell xxxJPY");
         GlobalVariableDel(OversoldGV);
         return;
      }//if (SendAlertNotTrade)
      
      //BasketSendSucceeded = true;
      GetStrongestPriceInBasket();
      for (cc = 0; cc < NoOfPairs; cc ++)
      {   
         symbol = TradePair[cc];
         point = MarketInfo(symbol, MODE_POINT);
         digits = MarketInfo(symbol, MODE_DIGITS);
         ask = MarketInfo(symbol, MODE_ASK);
         bid = MarketInfo(symbol, MODE_BID);

         TradeExists = DoesTradeExist(symbol, OP_SELL);
         if (!TradeExists)
         {
            GlobalVariableDel(OversoldGV);
            TradeSent = false;
            while (!TradeSent && Tries < 30)
            {
               TradeSent = SendTrade(1, symbol);
               if (!TradeSent) 
               {
                  Sleep(5000);//Half a second to avoid overloading
                  Tries++;
               }//if (!TradeSent)
            }//while (!TradeSent)
            
            
            //if (!TradeSent) 
            //{
               //GlobalVariableSet(OversoldGV, 0);//Force a resend if a trade send fails
               //BasketSendSucceeded = false;      
            //}//if (!TradeSent)    
         }//if (!TradeExists)                     
         Tries = 0;
      }//for (int cc = 0; cc < NoOfPairs; cc ++)
   }//if (GlobalVariableCheck && LowerTfWhiteLine < LowerTfOverBought)
      
  
   DisplayUserFeedback();
   
   
   
   
//----
   return(0);
}
//+------------------------------------------------------------------+