//+-------------------------------------------------------------------+
//|                 Trumpcard auto trading robot by Steve Hopwood.mq4 |
//|                                  Copyright © 2009, Steve Hopwood  |
//|                              http://www.hopwood3.freeserve.co.uk  |
//+-------------------------------------------------------------------+
#property copyright "Copyright © 2009, Steve Hopwood"
#property link      "http://www.hopwood3.freeserve.co.uk"
#include <WinUser32.mqh>
#include <stdlib.mqh>
#define  NL    "\n"
#define  up "Up"
#define  down "Down"
#define  none "None"
#define  buy "Buy"
#define  sell "Sell"
#define  ranging "Ranging"
#define  confused "Confused, and so cannot trade"
#define  trending "Trending"
#define  opentrade "There is a trade open"
#define  stopped "Trading is stopped"
#define  breakevenlinename "Break even line"
#define  reentrylinename "Re entry line"

//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"


/*


Matt Kennel has provided the code for bool O_R_CheckForHistory(int ticket). Cheers Matt, You are a star.


Code for adding debugging Sleep
Alert("G");
int x = 0;
while (x == 0) Sleep(100);

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--)


FUNCTIONS LIST
int init()
int start()

----Trading----

void LookForTradingOpportunities()
   bool WasCloseHigh()
   bool WasCloseLow()
   void ShouldPendingBeCancelled()
   void HasBuyFilled()
   void HasSellFilled()
   double CalculateStopLoss(int type, double price)
   double CalculateTakeProfit(int type, double price)
bool IsTradingAllowed()
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
   void ModifyOrder(int ticket, double stop, double take)
bool DoesTradeExist()
bool CloseTrade(int ticket)
void LookForTradeClosure()
bool CheckTradingTimes()
void CloseAllTrades()

----Hidden sl/tp---- Doubles up for pending trades-based ea's
void DrawPendingPriceLines()
void DeletePendingPriceLines()
void ReplaceMissingSlTpLines()

----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)



----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 bool    StopTrading=false;
extern bool    TradeLong=true;
extern bool    TradeShort=true;
extern int     TakeProfit=10;
extern int     StopLoss=10;
extern int     MagicNumber=0;
extern string  TradeComment="";
extern bool    CriminalIsECN=true;
extern double  MaxSpread=120;

extern string  lbc="----Candles to count for hi-lo----";
extern int     LookBackCandles=3;

extern string  ppd="----Pending price distance from hi-lo----";
extern int     PendingPipsDistance=1;

//Hidden tp/sl inputs.
extern string  hts="----Stealth stop loss and take profit inputs----";
extern int     HiddenPips=10;//Added to the 'hard' sl and tp and used for closure calculations

extern string  mi="====Martingale inputs----";
extern bool    UseMartingale=true;
extern double  MartingaleLotMultiplier=2;
extern double  MaxLotsAllowed=0.64;


extern string  bf="----Trading balance filters----";
extern bool    UseZeljko=true;
extern bool    OnlyTradeCurrencyTwice=true;

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  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 = 9;
extern  int    end_hourm = 12;
extern string  Trade_Hours_E= "Evening Hours 12-24";
extern  int    start_houre = 12;
extern  int    end_houre = 16;

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 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 */

//Trading variables
int            TicketNo, OpenTrades;
bool           CanTradeThisPair;//Will be false when this pair fails the currency can only trade twice filter, or the balanced trade filter
bool           BuyOpen, SellOpen;
int            RetryCount = 10;//Will make this number of attempts to get around the trade context busy error.

//Pending price inputs. Keeps things hidden from the crims
bool           PendingBuy, PendingSell;
double         PendingPrice, PendingStop, PendingTake;
datetime       PendingTime;
double         PendingCandleRange;
double         PendingRecreationCancelPips = 2;
//Hidden stops variables
double         HiddenStopLoss, HiddenTakeProfit;


//Date/Time
datetime       ConvertedStartTime;

//Trend detection
string         trend;


//Misc
string         Gap, ScreenMessage;
int            OldBars;
string         PipDescription=" pips";
bool           ForceTradeClosure;



void DisplayUserFeedback()
{
   
   if (IsTesting() && !IsVisualMode()) return;

   ScreenMessage = "";
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   ScreenMessage = StringConcatenate(ScreenMessage, Gap, TimeToStr(TimeLocal(), TIME_DATE|TIME_MINUTES|TIME_SECONDS), NL );
   /*
   //Code for time to bar-end display from Candle Time by Nick Bilak
   double i;
   int m,s,k;
   m=Time[0]+Period()*60-CurTime();
   i=m/60.0;
   s=m%60;
   m=(m-m%60)/60;
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, m + " minutes " + s + " seconds left to bar end", NL);
   */
      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);      
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Lot size: ", Lot, " (Criminal's minimum lot size: ", MarketInfo(Symbol(), MODE_MINLOT), ")", NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Take profit: ", TakeProfit, PipDescription,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Stop loss: ", StopLoss, PipDescription,  NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Magic number: ", MagicNumber, NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trade comment: ", TradeComment, NL);
   if (CriminalIsECN) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = true", NL);
   else ScreenMessage = StringConcatenate(ScreenMessage,Gap, "CriminalIsECN = false", NL);
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "MaxSpread = ", MaxSpread, ": Spread = ", MarketInfo(Symbol(), MODE_SPREAD), NL, NL );
   
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trading hours", NL);
   if (start_hourm == 0 && end_hourm == 12 && start_houre && end_houre == 24) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            24H trading", NL);
   else
   {
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            start_hourm: ", DoubleToStr(start_hourm, 2), 
                      ": end_hourm: ", DoubleToStr(end_hourm, 2), NL);
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, "            start_houre: ", DoubleToStr(start_houre, 2), 
                      ": end_houre: ", DoubleToStr(end_houre, 2), NL);
                      
   }//else
   
   
   //Pending trade
   ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
   if (PendingBuy || PendingSell)
   {
      string type;
      if (PendingBuy) type = "Pending Buy at ";
      if (PendingSell) type = "Pending Sell at ";
      ScreenMessage = StringConcatenate(ScreenMessage,Gap, type, DoubleToStr(ObjectGet(pendingpriceline, OBJPROP_PRICE1), Digits), NL);
   }//if (PendingBuy || PendingSell)
   

   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;
   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;
   PendingPipsDistance*= multiplier;
   
   BreakEvenPips*= multiplier;
   BreakEvenProfit*= multiplier;
   JumpingStopPips*= multiplier;
   TrailingStopPips*= multiplier;
   
   
   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;   
   
   
   if (TradeComment == "") TradeComment = " ";
   OldBars = Bars;
   DisplayUserFeedback();
   
   //Call sq's show trades indi
   //iCustom(NULL, 0, "SQ_showTrades",Magic, 0,0);

   
//----
   return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
   Comment("");
//----
   return(0);
}


////////////////////////////////////////////////////////////////////////////////////////////////
//TRADE MANAGEMENT MODULE

void ReportError()
{
   //All purpose sl mod error reporter. Called when a sl mod fails
   
   int err=GetLastError();
      
   Alert(OrderTicket()," stop loss modification failed with error(",err,"): ",ErrorDescription(err));
   Print(OrderTicket()," stop loss modification failed with error(",err,"): ",ErrorDescription(err));      

}//void ReportError()



void BreakEvenStopLoss() // Move stop loss to breakeven
{

   double NewStop;
   bool result;
   bool modify=false;
   string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0);
   double sl = ObjectGet(LineName, OBJPROP_PRICE1);
   
   if (OrderType()==OP_BUY)
   {
      if (sl >= OrderOpenPrice() ) return;
      if (Bid >= OrderOpenPrice () + (Point*BreakEvenPips))          
      {
         //Calculate the new stop
         NewStop = NormalizeDouble(OrderOpenPrice()+(BreakEvenProfit*Point), Digits);
         if (HiddenPips > 0)
         {
            if (ObjectFind(LineName) == -1)
            {
               ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), 0);
               ObjectSet(LineName, OBJPROP_COLOR, Red);
               ObjectSet(LineName, OBJPROP_WIDTH, 1);
               ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT);
            }//if (ObjectFind(LineName == -1) )
         
            ObjectMove(LineName, 0, TimeCurrent(), NewStop);         
         }//if (HiddenPips > 0)
         modify = true;   
      }//if (Bid >= OrderOpenPrice () + (Point*BreakEvenPips) && 
   }//if (OrderType()==OP_BUY)               			         
    
   if (OrderType()==OP_SELL)
   {
     if (sl <= OrderOpenPrice() && sl > 0) return;
     if (Ask <= OrderOpenPrice() - (Point*BreakEvenPips)) 
     {
         //Calculate the new stop
         NewStop = NormalizeDouble(OrderOpenPrice()-(BreakEvenProfit*Point), Digits);
         if (HiddenPips > 0)
         {
            if (ObjectFind(LineName) == -1)
            {
               ObjectCreate(LineName, OBJ_HLINE, 0, TimeCurrent(), 0);
               ObjectSet(LineName, OBJPROP_COLOR, Red);
               ObjectSet(LineName, OBJPROP_WIDTH, 1);
               ObjectSet(LineName, OBJPROP_STYLE, STYLE_DOT);
            }//if (ObjectFind(LineName == -1) )
         
            ObjectMove(LineName, 0, Time[0], NewStop);
         }//if (HiddenPips > 0)         
         modify = true;   
     }//if (Ask <= OrderOpenPrice() - (Point*BreakEvenPips) && (OrderStopLoss()>OrderOpenPrice()|| OrderStopLoss()==0))     
   }//if (OrderType()==OP_SELL)

   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify && HiddenStopLoss > 0)
   {
      while (IsTradeContextBusy() ) Sleep(100);
      result = OrderModify(OrderTicket(), OrderOpenPrice(), NewStop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);      
      if (!result) ReportError();
   }//if (modify)
   
} // End BreakevenStopLoss sub

void JumpingStopLoss() 
{
   // Jump sl by pips and at intervals chosen by user .

   if (OrderProfit() < 0) return;//Nothing to do
   string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0);
   double sl = ObjectGet(LineName, OBJPROP_PRICE1);
   if (sl == 0) return;//No line, so nothing to do
   double NewStop;
   bool modify=false;
   bool result;
   
   
   if (OrderType()==OP_BUY)
   {
      if (sl < OrderOpenPrice() ) return;//Not at breakeven yet
      // Increment sl by sl + JumpingStopPips.
      // This will happen when market price >= (sl + JumpingStopPips)
      if (Bid>= sl + ((JumpingStopPips*2)*Point) )
      {
         NewStop = NormalizeDouble(sl + (JumpingStopPips * Point), Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }// if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())      
   }//if (OrderType()==OP_BUY)
   
   if (OrderType()==OP_SELL)
   {
      if (sl > OrderOpenPrice() ) return;//Not at breakeven yet
      // Decrement sl by sl - JumpingStopPips.
      // This will happen when market price <= (sl - JumpingStopPips)
      if (Bid<= sl - ((JumpingStopPips*2)*Point))
      {
         NewStop = NormalizeDouble(sl - (JumpingStopPips * Point), Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }// close if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())         
   }//if (OrderType()==OP_SELL)

   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify && HiddenStopLoss > 0)
   {
      while (IsTradeContextBusy() ) Sleep(100);
      result = OrderModify(OrderTicket(), OrderOpenPrice(), NewStop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);      
      if (!result) ReportError();
   }//if (modify)

} //End of JumpingStopLoss sub


void TrailingStopLoss()
{
   
   if (OrderProfit() < 0) return;//Nothing to do
   string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0);
   double sl = ObjectGet(LineName, OBJPROP_PRICE1);
   if (sl == 0) return;//No line, so nothing to do
   double NewStop;
   bool modify=false;
   bool result;
   
   if (OrderType()==OP_BUY)
   {
      //if (sl < OrderOpenPrice() ) return;//Not at breakeven yet
      // Increment sl by sl + JumpingStopPips.
      // This will happen when market price >= (sl + JumpingStopPips)
      if (Bid>= sl + (TrailingStopPips * Point) )
      {
         NewStop = NormalizeDouble(Bid - (TrailingStopPips * Point), Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }// if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())      
   }//if (OrderType()==OP_BUY)
   
   if (OrderType()==OP_SELL)
   {
      //if (sl > OrderOpenPrice() ) return;//Not at breakeven yet
      // Decrement sl by sl - JumpingStopPips.
      // This will happen when market price <= (sl - JumpingStopPips)
      if (Bid<= sl - (TrailingStopPips * Point) )
      {
         NewStop = NormalizeDouble(Bid + (TrailingStopPips * Point), Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }// close if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())         
   }//if (OrderType()==OP_SELL)

   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify && HiddenStopLoss > 0)
   {
      while (IsTradeContextBusy() ) Sleep(100);
      result = OrderModify(OrderTicket(), OrderOpenPrice(), NewStop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);      
      if (!result) ReportError();
   }//if (modify)
      
} // End of TrailingStopLoss sub

void CandlestickTrailingStop()
{
   
   //Trails the stop at the hi/lo of the previous candle shifted by the user choice.
   //Only tries to do this once per bar, so an invalid stop error will only be generated once. I could code for
   //a too-close sl, but cannot be arsed. Coders, sort this out for yourselves.
   
   if (OldCstBars == Bars) return;
   OldCstBars = Bars;

   if (OrderProfit() < 0) return;//Nothing to do
   string LineName = SlPrefix + DoubleToStr(OrderTicket(), 0);
   double sl = ObjectGet(LineName, OBJPROP_PRICE1);
   if (sl == 0) return;//No line, so nothing to do
   double NewStop;
   bool modify=false;
   bool result;
   

   if (OrderType() == OP_BUY)
   {
      if (iLow(NULL, CstTimeFrame, CstTrailCandles) > sl)
      {
         NewStop = NormalizeDouble(Low[1], Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }//if (iLow(NULL, CstTimeFrame, CstTrailCandles) > sl)
   }//if (OrderType == OP_BUY)
   
   if (OrderType() == OP_SELL)
   {
      if (iHigh(NULL, CstTimeFrame, CstTrailCandles) < sl)
      {
         NewStop = NormalizeDouble(High[1], Digits);
         if (HiddenPips > 0) ObjectMove(LineName, 0, Time[0], NewStop);
         modify = true;   
      }//if (iHigh(NULL, CstTimeFrame, CstTrailCandles) < sl)
   }//if (OrderType() == OP_SELL)
   
   //Move 'hard' stop loss whether hidden or not. Don't want to risk losing a breakeven through disconnect.
   if (modify && HiddenStopLoss > 0)
   {
      while (IsTradeContextBusy() ) Sleep(100);
      result = OrderModify(OrderTicket(), OrderOpenPrice(), NewStop, OrderTakeProfit(), OrderExpiration(), CLR_NONE);      
      if (!result) ReportError();
   }//if (modify)

}//End void CandlestickTrailingStop()

void TradeManagementModule()
{

   // Call the working subroutines one by one. 

   //Candlestick trailing stop
   if (UseCandlestickTrailingStop) CandlestickTrailingStop();


   // Breakeven
   if(BreakEven) BreakEvenStopLoss();

   // JumpingStop
   if(JumpingStop) JumpingStopLoss();

   //TrailingStop
   if(TrailingStop) TrailingStopLoss();

   

}//void TradeManagementModule()
//END TRADE MANAGEMENT MODULE
////////////////////////////////////////////////////////////////////////////////////////////////

bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)
{
   //pah (Paul) contributed the code to get around the trade context busy error. Many thanks, Paul.
   
   int slippage = 10;
   if (Digits == 3 || Digits == 5) slippage = 100;
   
   color col = Red;
   if (type == OP_BUY || type == OP_BUYSTOP) col = Green;
   
   int expiry = 0;
   //if (SendPendingTrades) expiry = TimeCurrent() + (PendingExpiryMinutes * 60);

   //RetryCount is declared as 10 in the Trading variables section at the top of this file
   for (int cc = 0; cc < RetryCount; cc++)
   {
      for (int d = 0; (d < RetryCount) && IsTradeContextBusy(); d++) Sleep(100);

      RefreshRates();
      if (type == OP_BUY) price = NormalizeDouble(Ask, Digits);
      if (type == OP_SELL) price = NormalizeDouble(Bid, Digits);
      
      if (!CriminalIsECN) int ticket = OrderSend(Symbol(),type, lotsize, price, slippage, stop, take, comment, MagicNumber, expiry, col);
   
   
      //Is a 2 stage criminal
      if (CriminalIsECN)
      {
         ticket = OrderSend(Symbol(),type, lotsize, price, slippage, 0, 0, comment, MagicNumber, expiry, col);
         if (ticket > -1)
         {
	           ModifyOrder(ticket, stop, take);
         }//if (ticket > 0)}
      }//if (CriminalIsECN)
      
      if (ticket > -1) break;//Exit the trade send loop
      if (cc == RetryCount - 1) return(false);
   }//for (int cc = 0; cc < RetryCount; cc++);
   
   //Error trapping for both
   if (ticket < 0)
   {
      string stype;
      if (type == OP_BUY) stype = "OP_BUY";
      if (type == OP_SELL) stype = "OP_SELL";
      if (type == OP_BUYLIMIT) stype = "OP_BUYLIMIT";
      if (type == OP_SELLLIMIT) stype = "OP_SELLLIMIT";
      if (type == OP_BUYSTOP) stype = "OP_BUYSTOP";
      if (type == OP_SELLSTOP) stype = "OP_SELLSTOP";
      int err=GetLastError();
      Alert(Symbol(), " jor ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
      Print(Symbol(), " jor ", stype," order send failed with error(",err,"): ",ErrorDescription(err));
      return(false);
   }//if (ticket < 0)  
   
   
   TicketNo = ticket;
   //Make sure the trade has appeared in the platform's history to avoid duplicate trades.
   //My mod of Matt's code attempts to overcome the bastard crim's attempts to overcome Matt's code.
   bool TradeReturnedFromCriminal = false;
   while (!TradeReturnedFromCriminal)
   {
      TradeReturnedFromCriminal = O_R_CheckForHistory(ticket);
      if (!TradeReturnedFromCriminal)
      {
         Alert(Symbol(), " sent trade not in your trade history yet. Turn of this ea NOW.");
      }//if (!TradeReturnedFromCriminal)
   }//while (!TradeReturnedFromCriminal)
   
   //Got this far, so trade send succeeded
   return(true);
   
}//End bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)

void ModifyOrder(int ticket, double stop, double take)
{
   //Modifies an order already sent if the crim is ECN.
   if (!OrderSelect(ticket, SELECT_BY_TICKET) ) return;//Trade does not exist, so no mod needed
   
   //RetryCount is declared as 10 in the Trading variables section at the top of this file   
   for (int cc = 0; cc < RetryCount; cc++)
   {
      for (int d = 0; (d < RetryCount) && IsTradeContextBusy(); d++) Sleep(100);
        if (take > 0 && stop > 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           if (OrderModify(ticket, OrderOpenPrice(), stop, take, OrderExpiration(), CLR_NONE)) return;           
        }//if (take > 0 && stop > 0)
   
        if (take != 0 && stop == 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           if (OrderModify(ticket, OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE)) return;
        }//if (take == 0 && stop != 0)

        if (take == 0 && stop != 0)
        {
           while(IsTradeContextBusy()) Sleep(100);
           if (OrderModify(ticket, OrderOpenPrice(), stop, OrderTakeProfit(), OrderExpiration(), CLR_NONE)) return;
        }//if (take == 0 && stop != 0)
   }//for (int cc = 0; cc < RetryCount; cc++)
   
   //Got this far, so the order modify failed
   int err=GetLastError();
   Print(Symbol(), " SL/TP  order modify failed with error(",err,"): ",ErrorDescription(err));               
   Alert(Symbol(), " SL/TP  order modify failed with error(",err,"): ",ErrorDescription(err));               

}//void ModifyOrder(int ticket, double tp, double sl)

bool DoesTradeExist()
{
   
   TicketNo = -1;
   
   if (OrdersTotal() == 0) return(false);
   
   for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)
   {
      if (!OrderSelect(cc,SELECT_BY_POS)) continue;
      
      if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
      {
         TicketNo = OrderTicket();
         //Replace missing tp and sl lines
         if (HiddenPips > 0) ReplaceMissingSlTpLines();
         return(true);         
      }//if (OrderMagicNumber()==MagicNumber && OrderSymbol() == Symbol() )      
   }//for (int cc = OrdersTotal() - 1; cc >= 0 ; cc--)

   return(false);

}//End bool DoesTradeExist()



bool IsTradingAllowed()
{
   //Returns false if any of the filters should cancel trading, else returns true to allow trading
   
      
   //Maximum spread
   if (MarketInfo(Symbol(), MODE_SPREAD) > MaxSpread) return(false);
 
 
   //Swap filter
   if (OpenTrades == 0) TradeDirectionBySwap();

   //An individual currency can only be traded twice, so check for this
   CanTradeThisPair = true;
   if (OnlyTradeCurrencyTwice && OpenTrades == 0)
   {
      IsThisPairTradable();      
   }//if (OnlyTradeCurrencyTwice)
   if (!CanTradeThisPair) return(false);
   
   
   
   
   return(true);


}//End bool IsTradingAllowed()

double CalculateLotSize()
{

   //Calculate Martingale lot size

   if (!UseMartingale) return(Lot);
   
   
   //Find most recent trade
   if (OrdersHistoryTotal() == 0) return(Lot);
   double SendLots = Lot;
   
   for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS, MODE_HISTORY) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      if (OrderProfit() < 0)
      {
         double LotStep = MarketInfo(Symbol(),MODE_LOTSTEP);
         double digit = 0;
         if (LotStep == 0.1) digit = 1;
         if (LotStep == 0.01) digit = 2;
         SendLots = NormalizeDouble(OrderLots() * MartingaleLotMultiplier, digit);         
      }//if (OrderProfit() < 0)
      break;
   
   }//for (int cc = OrdersHistoryTotal() - 1; cc >= 0; cc--)
   
   //Check maximum lots allowed filter in the Martingale section
   if (SendLots > MaxLotsAllowed) SendLots = Lot;
   
   return(SendLots);

}//End double CalculateLotSize()


bool WasCloseHigh()
{
   //Returns true if the previous close was higher than that of the previous LookBackCandles, else returns false

   int consult = LookBackCandles + 1;
   for (int cc = 2; cc <= consult; cc++)
   {
      if (Close[cc] > Close[1] ) return(false);
   }//for (int cc = 1; cc <= consult; cc++)
   

   //Got this far, so is a high
   return(true);

}//End bool WasCloseHigh()

bool WasCloseLow()
{
   //Returns true if the previous close was lower than that of the previous LookBackCandles, else returns false

   int consult = LookBackCandles + 1;
   for (int cc = 2; cc <= consult; cc++)
   {
      if (Close[cc] < Close[1] ) return(false);
   }//for (int cc = 1; cc <= consult; cc++)
   

   //Got this far, so is a low
   return(true);

}//End bool WasCloseHigh()

double CalculateStopLoss(int type, double price)
{
   //Flexible stop loss calculation function
   double stop;
   
   if (type == OP_BUY)
   {
      if (StopLoss > 0) stop = NormalizeDouble(price - (StopLoss * Point), Digits);
      //Add the hidden pips
      stop = NormalizeDouble(stop - (HiddenPips * Point), Digits);
   }//if (type == OP_BUY)


   if (type == OP_SELL)
   {
      if (StopLoss > 0) stop = NormalizeDouble(price + (StopLoss * Point), Digits);
      //Add the hidden pips
      stop = NormalizeDouble(stop + (HiddenPips * Point), Digits);
   }//if (type == OP_SELL)



   return(stop);

}//End int CalculateStopLoss(int type, double price)

double CalculateTakeProfit(int type, double price)
{
   //Flexible take profit calculation function
   double take;
   double spread = MarketInfo(Symbol(), MODE_SPREAD) * Point;
   
   if (type == OP_BUY)
   {
      if (TakeProfit > 0) take = NormalizeDouble(price + (TakeProfit * Point), Digits);
      
      //Add the hidden pips
      take = NormalizeDouble(take + (HiddenPips * Point), Digits);
   }//if (type == OP_BUY)


   if (type == OP_SELL)
   {
      if (TakeProfit > 0) take = NormalizeDouble(price - (TakeProfit * Point), Digits);
      
      //Add the hidden pips
      take = NormalizeDouble(take - (HiddenPips * Point), Digits);
   }//if (type == OP_SELL)



   return(take);

}//End double CalculateTakeProfit(int type, double price)


void HasBuyFilled()
{
   //'Phantom' pending trade details are held in these variables.
   //bool           PendingBuy, PendingSell;
   //double         PendingPrice;
   //datetime       PendingTime;
   
   //This function examines the Bid 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 SendLots = CalculateLotSize();
   
   //Reset pending price just in case it has been set to zero for any reason
   if (ObjectFind(pendingpriceline) > -1) PendingPrice = ObjectGet(pendingpriceline, OBJPROP_PRICE1);
   
   RefreshRates();
   if (Bid >= PendingPrice)
   {
      price = Ask;
      type = OP_BUY;
      //Flexible stop loss calculator
      stop = CalculateStopLoss(OP_BUY, price); 
      //Flexible take profit calculator
      take = CalculateTakeProfit(OP_BUY, price);        

      

      bool result = SendSingleTrade(type, TradeComment, SendLots, price, stop, take);
      if (result) 
      {
         PendingBuy = false;
         DeletePendingPriceLines();         
      }//if (result) 
      
      
   }//if (Bid >= PendingPrice)
   

}//End void HasBuyFilled()

void HasSellFilled()
{
   //'Phantom' pending trade details are held in these variables.
   //bool           PendingBuy, PendingSell;
   //double         PendingPrice;
   //datetime       PendingTime;
   
   //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 SendLots = CalculateLotSize();
   //Reset pending price just in case it has been set to zero for any reason
   if (ObjectFind(pendingpriceline) > -1) PendingPrice = ObjectGet(pendingpriceline, OBJPROP_PRICE1);
   
   RefreshRates();
   if (Bid <= PendingPrice)
   {
      price = Bid;
      type = OP_SELL;
      //Flexible stop loss calculator
      stop = CalculateStopLoss(OP_SELL, price); 
      //Flexible take profit calculator
      take = CalculateTakeProfit(OP_SELL, price);        

         
      
      bool result = SendSingleTrade(type, TradeComment, SendLots, price, stop, take);
      if (result) 
      {
         PendingSell = false;
         DeletePendingPriceLines();      
      }//if (result) 
      
   }//if (Bid >= PendingPrice)
   

}//End void HasSellFilled()

void ShouldPendingBeCancelled()
{
   
   //No cancellation if the previous bar was an IB
   if (High[1] <= High[2] && Low[1] <= Low[2] ) return;


   PendingBuy = false;
   PendingSell = false;
   DeletePendingPriceLines();
     
   
}//End void ShouldPendingBeCancelled()


void LookForTradingOpportunities()
{


   RefreshRates();

   //Check filters
   if (!IsTradingAllowed() ) return;
   double SendLots = CalculateLotSize();
   //Is the previous close price a hi or lo?
   bool IsHigh = WasCloseHigh();
   bool IsLow = WasCloseLow();
   
   //Long 
   if (IsHigh)
   {
      if (!TradeLong) return;
      //Balanced pair trade filter. Only apply to pre-recovery trades.
      //Will remove the comments when I add Recovery
      if (UseZeljko && !BalancedPair(OP_BUY) ) return;
      
      PendingBuy = true;
      PendingPrice = NormalizeDouble(High[1] + (PendingPipsDistance * Point), Digits);
      PendingStop = 0;
      if (StopLoss > 0) PendingStop = NormalizeDouble(PendingPrice - (StopLoss * Point), Digits);
      
      PendingTake = 0;
      if (TakeProfit > 0) PendingTake = NormalizeDouble(PendingPrice + (TakeProfit * Point), Digits);
      DrawPendingPriceLines();
   }//if (IsHigh)
   
   
   //Short
   if (IsLow)
   {
      if (!TradeShort) return;
      //Balanced pair trade filter. Only apply to pre-recovery trades
      //Will remove the comments when I add Recovery
      if (UseZeljko && !BalancedPair(OP_SELL) ) return;

      PendingSell = true;
      PendingPrice = NormalizeDouble(Low[1] - (PendingPipsDistance * Point), Digits);
      PendingStop = 0;
      if (StopLoss > 0) PendingStop = NormalizeDouble(PendingPrice + (StopLoss * Point), Digits);
      
      PendingTake = 0;
      if (TakeProfit > 0) PendingTake = NormalizeDouble(PendingPrice - (TakeProfit * Point), Digits);
      DrawPendingPriceLines();
   }//if (Ask < 0)
   

   

}//if (IsLow)

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)


void LookForTradeClosure()
{
   //Close the trade if the new candle opens inside the bands
   
   if (!OrderSelect(TicketNo, SELECT_BY_TICKET) ) return;
   if (OrderSelect(TicketNo, SELECT_BY_TICKET) && OrderCloseTime() > 0) return;
   
   bool CloseTrade;
   
   string LineName = TpPrefix + DoubleToStr(TicketNo, 0);
   //Work with the lines on the chart that represent the hidden tp/sl
   double take = ObjectGet(LineName, OBJPROP_PRICE1);
   LineName = SlPrefix + DoubleToStr(TicketNo, 0);
   double stop = ObjectGet(LineName, OBJPROP_PRICE1);
   
   if (OrderType() == OP_BUY)
   {
      //TP
      if (Bid >= take && take > 0) CloseTrade = true;
      //SL
      if (Bid <= stop && stop > 0) CloseTrade = true;

   }//if (OrderType() == OP_BUY)
   
   
   if (OrderType() == OP_SELL)
   {
      //TP
      if (Bid <= take && take > 0) CloseTrade = true;
      //SL
      if (Bid >= stop && stop > 0) CloseTrade = true;

   }//if (OrderType() == OP_SELL)
   
   if (CloseTrade)
   {
      bool result = CloseTrade(TicketNo);
      //Actions when trade send succeeds
      if (result)
      {
         DeletePendingPriceLines();
      }//if (result)
   
      //Actions when trade send fails
      if (!result)
      {
   
      }//if (!result)
   

   }//if (CloseTrade)
   
   
}//void LookForTradeClosure()

void CloseAllTrades()
{
   ForceTradeClosure= false;
   
   if (OrdersTotal() == 0) return;
   
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() != Symbol() ) continue;
      while(IsTradeContextBusy()) Sleep(100);
      if (OrderType() == OP_BUY || OrderType() == OP_SELL) bool result = OrderClose(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, CLR_NONE);
      if (result) cc++;
      if (!result) ForceTradeClosure= true;
      
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)


}//End void CloseAllTrades()


bool CheckTradingTimes()
{
   int hour = TimeHour(TimeLocal() );
   
   if (end_hourm < start_hourm)
	{
		end_hourm += 24;
	}
	

	if (end_houre < start_houre)
	{
		end_houre += 24;
	}
	
	bool ok2Trade = true;
	
	ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre);

	// adjust for past-end-of-day cases
	// eg in AUS, USDJPY trades 09-17 and 22-06
	// so, the above check failed, check if it is because of this condition
	if (!ok2Trade && hour < 12)
	{
 		hour += 24;
		ok2Trade = (hour >= start_hourm && hour <= end_hourm) || (hour >= start_houre && hour <= end_houre);		
		// so, if the trading hours are 11pm - 6am and the time is between  midnight to 11am, (say, 5am)
		// the above code will result in comparing 5+24 to see if it is between 23 (11pm) and 30(6+24), which it is...
	}


   // check for end of day by looking at *both* end-hours

   if (hour >= MathMax(end_hourm, end_houre))
   {      
      ok2Trade = false;
   }//if (hour >= MathMax(end_hourm, end_houre))

   return(ok2Trade);

}//bool CheckTradingTimes()


//=============================================================================
//                           O_R_CheckForHistory()
//
//  This function is to work around a very annoying and dangerous bug in MT4:
//      immediately after you send a trade, the trade may NOT show up in the
//      order history, even though it exists according to ticket number.
//      As a result, EA's which count history to check for trade entries
//      may give many multiple entries, possibly blowing your account!
//
//  This function will take a ticket number and loop until
//  it is seen in the history.
//
//  RETURN VALUE:
//     TRUE if successful, FALSE otherwise
//
//
//  FEATURES:
//     * Re-trying under some error conditions, sleeping a random
//       time defined by an exponential probability distribution.
//
//     * Displays various error messages on the log for debugging.
//
//  ORIGINAL AUTHOR AND DATE:
//     Matt Kennel, 2010
//
//=============================================================================
bool O_R_CheckForHistory(int ticket)
{
   //My thanks to Matt for this code. He also has the undying gratitude of all users of my trading robots
   
   int lastTicket = OrderTicket();

   int cnt = 0;
   int err = GetLastError(); // so we clear the global variable.
   err = 0;
   bool exit_loop = false;
   bool success=false;

   while (!exit_loop) {
      /* loop through open trades */
      int total=OrdersTotal();
      for(int c = 0; c < total; c++) {
         if(OrderSelect(c,SELECT_BY_POS,MODE_TRADES) == true) {
            if (OrderTicket() == ticket) {
               success = true;
               exit_loop = true;
            }
         }
      }
      if (cnt > 3) {
         /* look through history too, as order may have opened and closed immediately */
         total=OrdersHistoryTotal();
         for(c = 0; c < total; c++) {
            if(OrderSelect(c,SELECT_BY_POS,MODE_HISTORY) == true) {
               if (OrderTicket() == ticket) {
                  success = true;
                  exit_loop = true;
               }
            }
         }
      }

      cnt = cnt+1;
      if (cnt > O_R_Setting_max_retries) {
         exit_loop = true;
      }
      if (!(success || exit_loop)) {
         Print("Did not find #"+ticket+" in history, sleeping, then doing retry #"+cnt);
         O_R_Sleep(O_R_Setting_sleep_time, O_R_Setting_sleep_max);
      }
   }
   // Select back the prior ticket num in case caller was using it.
   if (lastTicket >= 0) {
      OrderSelect(lastTicket, SELECT_BY_TICKET, MODE_TRADES);
   }
   if (!success) {
      Print("Never found #"+ticket+" in history! crap!");
   }
   return(success);
}//End bool O_R_CheckForHistory(int ticket)

//=============================================================================
//                              O_R_Sleep()
//
//  This sleeps a random amount of time defined by an exponential
//  probability distribution. The mean time, in Seconds is given
//  in 'mean_time'.
//  This returns immediately if we are backtesting
//  and does not sleep.
//
//=============================================================================
void O_R_Sleep(double mean_time, double max_time)
{
   if (IsTesting()) {
      return;   // return immediately if backtesting.
   }

   double p = (MathRand()+1) / 32768.0;
   double t = -MathLog(p)*mean_time;
   t = MathMin(t,max_time);
   int ms = t*1000;
   if (ms < 10) {
      ms=10;
   }
   Sleep(ms);
}//End void O_R_Sleep(double mean_time, double max_time)


///////////////////////////////////////////////////////////////////////////////////////////////////////
//Balance/swap filters module
void TradeDirectionBySwap()
{

   //Sets TradeLong & TradeShort according to the positive/negative swap it attracts

   double LongSwap = MarketInfo(Symbol(), MODE_SWAPLONG);
   double ShortSwap = MarketInfo(Symbol(), MODE_SWAPSHORT);
   

   if (CadPairsPositiveOnly)
   {
      if (StringSubstr(Symbol(), 0, 3) == "CAD" || StringSubstr(Symbol(), 0, 3) == "cad" || StringSubstr(Symbol(), 3, 3) == "CAD" || StringSubstr(Symbol(), 3, 3) == "cad" )      
      {
         if (LongSwap > 0) TradeLong = true;
         else TradeLong = false;
         if (ShortSwap > 0) TradeShort = true;
         else TradeShort = false;         
      }//if (StringSubstr(Symbol(), 0, 3) == "CAD" || StringSubstr(Symbol(), 0, 3) == "cad" )      
   }//if (CadPairsPositiveOnly)
   
   if (AudPairsPositiveOnly)
   {
      if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" )      
      {
         if (LongSwap > 0) TradeLong = true;
         else TradeLong = false;
         if (ShortSwap > 0) TradeShort = true;
         else TradeShort = false;         
      }//if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" )      
   }//if (AudPairsPositiveOnly)
   
   
   if (NzdPairsPositiveOnly)
   {
      if (StringSubstr(Symbol(), 0, 3) == "NZD" || StringSubstr(Symbol(), 0, 3) == "nzd" || StringSubstr(Symbol(), 3, 3) == "NZD" || StringSubstr(Symbol(), 3, 3) == "nzd" )      
      {
         if (LongSwap > 0) TradeLong = true;
         else TradeLong = false;
         if (ShortSwap > 0) TradeShort = true;
         else TradeShort = false;         
      }//if (StringSubstr(Symbol(), 0, 3) == "AUD" || StringSubstr(Symbol(), 0, 3) == "aud" || StringSubstr(Symbol(), 3, 3) == "AUD" || StringSubstr(Symbol(), 3, 3) == "aud" )      
   }//if (AudPairsPositiveOnly)
   
   

}//void TradeDirectionBySwap()

bool IsThisPairTradable()
{
   //Checks to see if either of the currencies in the pair is already being traded twice.
   //If not, then return true to show that the pair can be traded, else return false
   
   string c1 = StringSubstr(Symbol(), 0, 3);//First currency in the pair
   string c2 = StringSubstr(Symbol(), 3, 3);//Second currency in the pair
   int c1open = 0, c2open = 0;
   CanTradeThisPair = true;
   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS) ) continue;
      if (OrderSymbol() != Symbol() ) continue;
      if (OrderMagicNumber() != MagicNumber) continue;
      int index = StringFind(OrderSymbol(), c1);
      if (index > -1)
      {
         c1open++;         
      }//if (index > -1)
   
      index = StringFind(OrderSymbol(), c2);
      if (index > -1)
      {
         c2open++;         
      }//if (index > -1)
   
      if (c1open == 1 && c2open == 1) 
      {
         CanTradeThisPair = false;
         return(false);   
      }//if (c1open == 1 && c2open == 1) 
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)

   //Got this far, so ok to trade
   return(true);
   
}//End bool IsThisPairTradable()

bool BalancedPair(int type)
{

   //Only allow an individual currency to trade if it is a balanced trade
   //e.g. UJ Buy open, so only allow Sell xxxJPY.
   //The passed parameter is the proposed trade, so an existing one must balance that

   //This code courtesy of Zeljko (zkucera) who has my grateful appreciation.
   
   string BuyCcy1, SellCcy1, BuyCcy2, SellCcy2;

   if (type == OP_BUY || type == OP_BUYSTOP)
   {
      BuyCcy1 = StringSubstr(Symbol(), 0, 3);
      SellCcy1 = StringSubstr(Symbol(), 3, 3);
   }//if (type == OP_BUY || type == OP_BUYSTOP)
   else
   {
      BuyCcy1 = StringSubstr(Symbol(), 3, 3);
      SellCcy1 = StringSubstr(Symbol(), 0, 3);
   }//else

   for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
   {
      if (!OrderSelect(cc, SELECT_BY_POS)) continue;
      if (OrderSymbol() == Symbol()) continue;
      if (OrderMagicNumber() != MagicNumber) continue;      
      if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP)
      {
         BuyCcy2 = StringSubstr(OrderSymbol(), 0, 3);
         SellCcy2 = StringSubstr(OrderSymbol(), 3, 3);
      }//if (OrderType() == OP_BUY || OrderType() == OP_BUYSTOP)
      else
      {
         BuyCcy2 = StringSubstr(OrderSymbol(), 3, 3);
         SellCcy2 = StringSubstr(OrderSymbol(), 0, 3);
      }//else
      if (BuyCcy1 == BuyCcy2 || SellCcy1 == SellCcy2) return(false);
   }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)

   //Got this far, so it is ok to send the trade
   return(true);

}//End bool BalancedPair(int type)



//End Balance/swap filters module
///////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////
//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
   
   //Only need the pending line if the trade is not filled yet
   if (TicketNo == -1)
   {
      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);
   }//if (TicketNo == -1)
   
   
   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 (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 (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 (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()


//END Pending trade price lines module
///////////////////////////////////////////////////////////////////////////////////////////////////////



//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{
//----

   static bool TradeExists;
   
   if (OrdersTotal() == 0)
   {
      TicketNo = -1;
      ForceTradeClosure = false;
   }//if (OrdersTotal() == 0)

   if (ForceTradeClosure) 
   {
      CloseAllTrades();
      return;
   }//if (ForceTradeClosure) 

      
   ///////////////////////////////////////////////////////////////////////////////////////////////
   //Find open trades.
   TradeExists = DoesTradeExist();
   if (TradeExists)
   {
      if (OrderProfit() > 0) TradeManagementModule();
      LookForTradeClosure();
      PendingBuy = false;
      PendingSell = false;
      if (ObjectFind(pendingpriceline) > -1) DeletePendingPriceLines();
   }//if (TradeExists)

   ///////////////////////////////////////////////////////////////////////////////////////////////

   //Detect pending trade line
   if (ObjectFind(pendingpriceline) > -1)
   {
      if (ObjectGet(pendingpriceline, OBJPROP_COLOR) == Green) PendingBuy = true;
      if (ObjectGet(pendingpriceline, OBJPROP_COLOR) == Red) PendingSell = true;
   }//if (ObjectFind(pendingpriceline) > -1)
   
   
   if (PendingBuy)
   {  
      HasBuyFilled();
   }//if (PendingBuy)
   
   if (PendingSell)
   {
      HasSellFilled();
   }//if (PendPendingSellngBuy)
   
   
   
     //Trading times
   bool TradeTimeOk = CheckTradingTimes();
   if (!TradeTimeOk)
   {
      Comment("Outside trading hours\nstart_hourm-end_hourm: ", start_hourm, "-",end_hourm, "\nstart_houre-end_houre: ", start_houre, "-",end_houre);
      return;
   }//if (hour < start_hourm)
   /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   //Available margin filters
   EnoughMargin = true;//For user display
   MarginMessage = "";
   if (UseScoobsMarginCheck && OpenTrades > 0)
   {
      if(AccountMargin() > (AccountFreeMargin()/100)) 
      {
         MarginMessage = "There is insufficient margin to allow trading. You might want to turn off the UseScoobsMarginCheck input.";
         DisplayUserFeedback();
         return;
      }//if(AccountMargin() > (AccountFreeMargin()/100)) 
      
   }//if (UseScoobsMarginCheck)


   if (UseForexKiwi && AccountMargin() > 0)
   {
      
      double ml = NormalizeDouble(AccountEquity() / AccountMargin() * 100, 2);
      if (ml < FkMinimumMarginPercent)
      {
         MarginMessage = StringConcatenate("There is insufficient margin percent to allow trading. ", DoubleToStr(ml, 2), "%");
         DisplayUserFeedback();
         return;
      }//if (ml < FkMinimumMarginPercent)
      
   }//if (UseForexKiwi && AccountMargin() > 0)

   ///////////////////////////////////////////////////////////////////////////////////////////////         
   //Trading
   if (OldBars != Bars)
   {
      OldBars = Bars;
      //Look for pending deletion conditions
      if (PendingBuy || PendingSell) ShouldPendingBeCancelled();

      if (TicketNo == -1 && !StopTrading && !PendingBuy && !PendingSell)
      {   
         LookForTradingOpportunities();
      }//if (TicketNo == -1)
   }//if (OldBars != Bars)
   
   ///////////////////////////////////////////////////////////////////////////////////////////////      

   DisplayUserFeedback();
   
//----
   return(0);
}
//+------------------------------------------------------------------+