//+------------------------------------------------------------------+
//|                                                   The Beauty.mq4 |
//|                                  Copyright © 2010, Steve Hopwood |
//|                                  Copyright © 2010, mbk           |
//|                              http://www.hopwood3.freeserve.co.uk |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2010, Steve Hopwood"
#property link      "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>

#include <LibOrderReliable4.mqh>

#define versionstr "0.3.1"
#define primary "Primary 0.3.1"
#define secondary "Secondary 0.3.1"

#define  NL    "\n"
#define  GvPrefix "macman "
#define  breakevenlinename "Break even line"
#define  reentrylinename "Re entry line"
#define  takeprofitlinename "Take profit line"
#define  up "Market is trending up"
#define  down "Market is trending down"
#define  ranging "Market is ranging"

//From iExposure
//#define SYMBOLS_MAX 1024
//#define BUY_LOTS       17
//#define BUY_PRICE      2
//#define SELL_LOTS      3
//#define SELL_PRICE     4
//#define NET_LOTS       5
//#define PROFIT         6

/*
 *  TheBeauty -- bride to Steve Hopwood & macman's TheBeast
 *
 *  The Beast downloaded on Nov 9 formed the basis of this EA
 *
 *  New features:
 *      Change order handling to LibOrderReliable.
 *
 *      trendAdjust parameter.  Adjust up/down the sixths lines based
 *      on a trend determination.  This is a floating point value between 0 and 1,
 *      At zero it gives the same as The Beast.  With other values it adds in
 *      this fraction of the "trend" estimation to the sixths lines.
 *
 *      Value in real trading is undetermined. Let's experiment. Suggest values 0.3 to 0.5?
 *      Look at related indicator SIXTHS Floating MBK which plots the modified
 *      sixths lines.
 *
 *  V 0.2.0
 *      Add trend-based shrinkage of sixths parameter.
 *      Add decaying take profit.  For open trades which have been Open
 *      for at least HoursToStartDTP, set a take profit which starts at the center sixths line
 *      at HoursToStartDTP, and goes up (for a sell) or down (for a buy) linearly with broker hour bars
 *      so it reaches the yellow lines at HoursToReachYellowLine hours after the trade open.
 *      It will continue to decay to more extremes (and thus likely greater losses) even after this.
 *
 * V 0.2.1
 *      Change handling of moving gold & green lines to readjust pending orders instead of delete.
 *      Previously (as this strategy moves them much more
 */


/*
ChicagoRob's pairs: eurusd - usdjpy - gbpusd - audusd - eurjpy - usdcad - nzdusd - audjpy

void DisplayUserFeedback()
void GetSixths()
void CalculateTrades()
bool IsTradingAllowed()
bool DoesTradeExist(double price)
bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take, int magic)
double CalculateStop(double price, int type)
void LookForTradeClosure()
void CloseAllTrades()
void CountPendingTrades()
void DrawTakeProfitLine(int type)

----Re-entry line----
void AddReEntryLine(double price)
void CalculateReEntryLinePips()

----Recovery----
void RecoveryModule()
void CountOpenTrades()
void CheckRecoveryTakeProfit()
int Analyze()
int SymbolsIndex(string SymbolName)


----Trade management module----
void TradeManagementModule()
void BreakEvenStopLoss()
bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop )
void JumpingStopLoss()
void HiddenTakeProfit()
void HiddenStopLoss()
void TrailingStopLoss()
bool CleanUp()

----Hedging----
void HedgingModule()
bool IsTradeAlreadyHedged(int ticket)
double GetRsi(int tf, int period, int shift)

*/
extern string  gen="----General inputs----";
extern int     BarCount=0;
extern double  trendAdjust=0.2;
extern double  trendSizeAdjust=0.25;
extern bool    StopTrading=false;
extern bool    TradeLong=true;
extern bool    TradeShort=true;
extern int     MaxTradesAllowed=5;
extern bool    Primary_trades=true;
extern bool    Secondary_trades=true;
//extern int   Max_secondary_trades=1;
//extern int   Delay_between_trades=10;
extern double  Primary_trade_Lot_size=0.3;  /* multiplied by 10 for my crim's minimum lot size */
extern double  Secondary_trade_Lot_size=0.1;
extern string  Primary_trade_comment= primary;
extern string  Secondary_trade_comment= secondary;
/* the next two se are now basis points = 1/100th of 1 percent, so that 10 basis points in a 1.5000 pair is twice 10bp in a 0.75 pair */
extern int     MinBasisPointsFromLastEntry=50;
extern int     BasisPointsBufferFromTradeLine=10;
extern string  dtp="----Decaying Take Profit----";
extern bool    UseDecayingTakeProfit=true;
extern int     HoursToStartDTP=40;
/* hours from open time at which to start decaying a take profit */
extern int     HoursToReachYellowLine=60;
/* hours from open time at which point decaying TP reaches the yellow line---it will continue to decay until order is closed. */


// takeprofit line is permanently disabled as there is a
// competing takeprofit strategy in The Beauty
extern string  rec="----Recovery----";
extern bool    UseRecovery=false;
extern int     Start_Recovery_at_trades=2;  //DC
extern bool    Use1.1.3.3Recovery=false;
extern bool    Use1.1.2.4Recovery=true;
extern color   ReEntryLineColour=Yellow;
extern color   BreakEvenLineColour=Aqua;
extern int     ReEntryLinePips=0;
extern int     RecoveryBreakEvenProfitPips=10;
extern string  sli="----Stop loss----";
extern bool    UseStopLoss=false;
extern int     StopLoss=0;
extern string  tmm="----Trade management module----";
extern bool    DoNotOverload5DigitCriminals=false;
extern string  BE="Break even settings";
extern bool    BreakEven=false;
extern int     BreakEvenPips=40;
extern int     BreakEvenProfit=30;
extern bool    HideBreakEvenStop=false;
extern int     PipsAwayFromVisualBE=5;
extern string  JSL="Jumping stop loss settings";
extern bool    JumpingStop=false;
extern int     JumpingStopPips=30;
extern bool    AddBEP=false;
extern bool    JumpAfterBreakevenOnly=true;
extern bool    HideJumpingStop=false;
extern int     PipsAwayFromVisualJS=10;
extern string  TSL="Trailing stop loss settings";
extern bool    TrailingStop=false;
extern int     TrailingStopPips=50;
extern bool    HideTrailingStop=false;
extern int     PipsAwayFromVisualTS=10;
extern bool    TrailAfterBreakevenOnly=false;
extern bool    StopTrailAtPipsProfit=false;
extern int     StopTrailPips=0;
extern string  hsl1="Hidden stop loss settings";
extern bool    HideStopLossEnabled=false;
extern int     HiddenStopLossPips=20;
extern string  htp="Hidden take profit settings";
extern bool    HideTakeProfitEnabled=false;
extern int     HiddenTakeProfitPips=20;
extern string  hed="----Hedging----";
extern bool    UseHedging=false;
extern int     HedgeAtLossPips=500;
extern double  HedgeLotsMiltiplier=2;
extern string  tt="----Trading hours----";
extern string  Trade_Hours= "Set Morning & Evening Hours";
extern string  Trade_Hoursi= "Use 24 hour, local time clock";
extern string  Trade_Hours_M= "Morning Hours 0-12";
extern  int    start_hourm = 0;
extern  int    end_hourm = 12;
extern string  Trade_Hours_E= "Evening Hours 12-24";
extern  int    start_houre = 12;
extern  int    end_houre = 24;
extern string  mis="----Odds and ends----";
extern bool    ShowManagementAlerts=true;
extern int     DisplayGapSize=30;
extern int     GlobalMagic=123971;

//6ths variable.
double         BottomGoldLine;//Bottom, gold line
double         BottomGreenLine;//Bottom, green line
double         MiddleWhiteLine;//Middle, white line
double         TopGreenLine;//Top, green line
double         TopGoldLine;//Top, gold line

bool           ForcePendingTradeDeletion, ForceAllTradeDeletion;
int            OldBars, OpenTrades, PrevOpenTrades, PendingTradesTotal, PrimaryTrades, SecondaryTrades,
  PendingPrimary, PendingSecondary, Old5Bars;
string         GvName, Gap, ScreenMessage;
double         TpLinePrice1;
int            TpLinePipsFromWhite=10;

double         TradeNumber;  //DC to use with recovery module
double         BasketUpl;//Fopr keeping track of the upl of whether a group of trades should be in Recovery
double         MostRecentTradePrice;//For making sure new trades are sent a min pips distance from an existing open trade
double         RsiVal;
string         trend;
bool           HedgingInProgress;

//Recovery
bool           RecoveryInProgress, TpMoved;

int    ExtLines=-1;
string ExtCols[8]= {"Symbol",
                    "Deals",
                    "Buy lots",
                    "Buy price",
                    "Sell lots",
                    "Sell price",
                    "Net lots",
                    "Profit"
                   };
int    ExtShifts[8]= { 10, 80, 130, 180, 260, 310, 390, 460 };
int    ExtVertShift=14;
double buy_price=0.0;
double sell_price=0.0;

double multiplier;  /* multiply Point by this number to get "regular pips" */

// symbolic names for various lines, used in place of enums

#define TOPGOLD 1
#define TOPGREEN 2
#define BOTTOMGREEN 3
#define BOTTOMGOLD 4


void DisplayUserFeedback()
{

    if (IsTesting() && !IsVisualMode()) return;

    ScreenMessage = "";
    ScreenMessage = StringConcatenate(ScreenMessage,Gap,"The Beauty ",versionstr, 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, "Primary_trade_Lot_size: ", Primary_trade_Lot_size, NL);
    ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Secondary_trade_Lot_size: ", Secondary_trade_Lot_size, NL);
    if (TradeLong == true) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trading long ", NL);
    if (TradeShort == true) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trading short ", 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, "Criminal's minimum lot size: ", MarketInfo(Symbol(), MODE_MINLOT), 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, "            end_houre: ", DoubleToStr(start_hourm, 2),
                                          ": end_houre: ", DoubleToStr(end_hourm, 2), NL);

    }//else

    ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
    ScreenMessage = StringConcatenate(ScreenMessage,Gap, "BarCount = ", BarCount, NL);
    ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Recovery starts at ", Start_Recovery_at_trades, " filled Primary trades", NL);
    ScreenMessage = StringConcatenate(ScreenMessage,Gap, "ReEntryLinePips = ", ReEntryLinePips, NL);
    if (StopTrading) ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trading suspended", NL);

    ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
    if (BreakEven) {
        ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Breakeven is set to ", BreakEvenPips, " with BreakEvenProfit = ", BreakEvenProfit, NL);
    }//if (BreakEven)

    if (JumpingStop) {
        ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Jumping stop is set to ", JumpingStopPips);
        if (AddBEP) ScreenMessage = StringConcatenate(ScreenMessage,": BreakEvenProfit = ", BreakEvenProfit);
        if (JumpAfterBreakevenOnly) ScreenMessage = StringConcatenate(ScreenMessage, ": JumpAfterBreakevenOnly = true");
        ScreenMessage = StringConcatenate(ScreenMessage,Gap, NL);
    }//if (JumpingStop)

    if (BreakEven) {
        ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Trailing stop is set to ", TrailingStopPips, " pips", NL);
    }//if (BreakEven)

    if (UseHedging) {
        ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Hedging is enabled ", " with HedgeAtLossPips = ", HedgeAtLossPips, ": HedgeLotsMiltiplier = ", HedgeLotsMiltiplier, NL);
        ScreenMessage = StringConcatenate(ScreenMessage,Gap, "Rsi D1 trend: ", trend, ": Val = ", RsiVal, NL);
    }//if (UseHedging)

    ScreenMessage=StringConcatenate(ScreenMessage,Gap,"BasketUPL = ",BasketUpl, " #Primaries = ",PrimaryTrades," #Secondaries = ",SecondaryTrades, NL);
    ScreenMessage=StringConcatenate(ScreenMessage,Gap, " #PendingPrimaries=", PendingPrimary, " #PendingSecondaries=", PendingSecondary); 
    Comment(ScreenMessage);
}//void DisplayUserFeedback()


//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int init()
{
//----
    //ReEntryLinePips is calculated using Atr during GetSixths(). I keep this code in case we change our minds
    if (ReEntryLinePips == 0) {
        //Reset ReEntryLinePips according to pair volatility. My thanks to Max for this
        if (StringSubstr(Symbol(), 0, 6) == "AUDCAD") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDCHF") {
            ReEntryLinePips =180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDJPY") {
            ReEntryLinePips =180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDNZD") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDUSD") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "CADCHF") {
            ReEntryLinePips =180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "CADJPY") {
            ReEntryLinePips =200;
        }
        if (StringSubstr(Symbol(), 0, 6) == "CHFJPY") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURAUD") {
            ReEntryLinePips =200;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURCAD") {
            ReEntryLinePips =200;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURCHF") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURGBP") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURJPY") {
            ReEntryLinePips =200;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURNZD") {
            ReEntryLinePips =250;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURUSD") {
            ReEntryLinePips =180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "GBPCHF") {
            ReEntryLinePips =200;
        }
        if (StringSubstr(Symbol(), 0, 6) == "GBPJPY") {
            ReEntryLinePips =250;
        }
        if (StringSubstr(Symbol(), 0, 6) == "GBPUSD") {
            ReEntryLinePips =200;
        }
        if (StringSubstr(Symbol(), 0, 6) == "NZDJPY") {
            ReEntryLinePips =180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "NZDUSD") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "SGDJPY") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDCHF") {
            ReEntryLinePips =180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDCAD") {
            ReEntryLinePips =150;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDJPY") {
            ReEntryLinePips =180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDNOK") {
            ReEntryLinePips =1500;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDSEK") {
            ReEntryLinePips =1500;
        }
    }//if (ReEntryLinePips == 0)

    //In case this is a symbol not in the list
    if (ReEntryLinePips == 0) ReEntryLinePips = 200;


    if(Digits == 2 || Digits == 4) multiplier = 1;
    if(Digits == 3 || Digits == 5) multiplier = 10;
    if(Digits == 6) multiplier = 100;
    if(Digits == 7) multiplier = 1000;

    TpLinePipsFromWhite*= multiplier;
    StopLoss*= multiplier;
    RecoveryBreakEvenProfitPips*= multiplier;
    ReEntryLinePips*= multiplier;
//    PipsBufferFromTradeLine*= multiplier;
//    MinPipsFromLastEntry*= multiplier;
    BreakEvenPips*= multiplier;
    BreakEvenProfit*= multiplier;
    PipsAwayFromVisualBE*= multiplier;
    JumpingStopPips*= multiplier;
    PipsAwayFromVisualJS*= multiplier;
    TrailingStopPips*= multiplier;
    PipsAwayFromVisualTS*= multiplier;
    StopTrailPips*= multiplier;
    HiddenStopLossPips*= multiplier;
    HiddenTakeProfitPips*= multiplier;
    HedgeAtLossPips*= multiplier;

    if (BarCount == 0) {
        //Set up the BarCount. H1 TF first. Default barcount set at 170
        //From scoobs
        //BarCount = NormalizeDouble((iATR(NULL,1440 ,200,0)/MarketInfo(Symbol(),MODE_POINT))/10,0);


        if (StringSubstr(Symbol(), 0, 6) == "AUDCAD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDCHF") {
            BarCount = 210;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDJPY") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDNZD") {
            BarCount = 20;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDSGD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "AUDUSD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "CADCHF") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "CADJPY") {
            BarCount = 180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "CHFJPY") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "CHFSGD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURAUD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURCAD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURCHF") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURGBP") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURJPY") {
            BarCount = 180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURNZD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURSGD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "EURUSD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "GBPAUD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "GBPCAD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "GBPCHF") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "GBPJPY") {
            BarCount = 180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "GBPUSD") {
            BarCount = 155;
        }
        if (StringSubstr(Symbol(), 0, 6) == "NZDCAD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "NZDCHF") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "NZDJPY") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "NZDUSD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "SGDJPY") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDCAD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDCHF") {
            BarCount = 180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDHKD") {
            BarCount = 170;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDJPY") {
            BarCount = 180;
        }
        if (StringSubstr(Symbol(), 0, 6) == "USDSGD") {
            BarCount = 170;
        }


        double dBarCount = BarCount;
        //dBarCount*= multiplier;
        //BarCount = dBarCount;

        //Andy's formula
        BarCount = MathRound(dBarCount/Period()*60);

    }//if (BarCount == 0)


    Gap="";
    if (DisplayGapSize >0) {
        for (int cc=0; cc< DisplayGapSize; cc++) {
            Gap = StringConcatenate(Gap, " ");
        }
    }//if (DisplayGapSize >0)

    // delete spurious old breakevenlines
    if (ObjectFind(breakevenlinename) > -1) ObjectDelete(breakevenlinename);



    Comment("..................Waiting for the first tick");

    OldBars = Bars;
    Old5Bars = iBars(NULL, PERIOD_M5);//For 'mopping up' operations

    GvName = GvPrefix + Symbol();
    PrevOpenTrades = GlobalVariableGet(GvName);
    if (ObjectFind(takeprofitlinename) == 0 && ObjectGet(takeprofitlinename, OBJPROP_COLOR) == Gray) TpLinePrice1 = ObjectGet(takeprofitlinename, OBJPROP_PRICE1);

    start();

//----
    return(0);
}
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
int deinit()
{
//----
    Comment("");
//----
    return(0);
}

double ema_diff(int shift, int back, int EMA_period)
{

    return(iMA(NULL,PERIOD_H1,EMA_period,0,MODE_EMA,PRICE_TYPICAL,shift) -
           iMA(NULL,PERIOD_H1,EMA_period,0,MODE_EMA,PRICE_TYPICAL,shift+back) );
}


/* utility functions */
double BasisPointsAway(double p1, double p2)
{
    return( (p2-p1)/p1 * 10000.0 );
}

/* return true if p1 and p2 are as close or closer than 'realpips' apart */
bool IsDeltaPriceSmallPips(double p1, double p2, double realpips)
{
    return ( MathAbs(p1-p2) <= realpips*Point*multiplier);
}

double IsDeltaPriceSmallBP(double p1, double p2, double bp)
{
    double ref=0.5*(p1+p2);
    return ( MathAbs(p1-p2)/ref *10000 <= bp );
}

bool DoesLineNeedToMove(double p1, double p2)
{
    /* at least 1.5 full pips */
    return( !IsDeltaPriceSmallPips(p1,p2,1.5));
}


void GetSixths()
{

    double ctgl = TopGoldLine;
    double cbgl = BottomGoldLine;

    /*
    Old code that read the lines on the screen
    TopGoldLine = NormalizeDouble(ObjectGet("fivesixth", OBJPROP_PRICE1), Digits);
    TopGreenLine = NormalizeDouble(ObjectGet("foursixth", OBJPROP_PRICE1), Digits);
    MiddleWhiteLine = NormalizeDouble(ObjectGet("threesixth", OBJPROP_PRICE1), Digits);
    BottomGreenLine = NormalizeDouble(ObjectGet("twosixth", OBJPROP_PRICE1), Digits);
    BottomGoldLine = NormalizeDouble(ObjectGet("onesixth", OBJPROP_PRICE1), Digits);
    */
    double thelow=Low[iLowest(NULL,0,MODE_LOW,BarCount,1)];
    double thehigh= High[iHighest(NULL,0,MODE_HIGH,BarCount,1)];

    double value = (thehigh-thelow);      //value top of the chart - value bottom
    double cen = 0.5*(thehigh+thelow);
    double sixth = value/6;
    double valueS = (value*(MathPow(10,Digits)));
    double sixthS = (sixth*(MathPow(10,Digits)));

    int iavg = MathRound(BarCount*0.5);
    // int iavg = MathRound( ((ihighest-i) + (ilowest-i))*0.5);

    double trend =  0.25*( ema_diff(0, iavg, 13) + ema_diff(0,iavg,34)
                           + ema_diff(0, iavg,89)  + ema_diff(0,iavg,233) );

    double offset = trend* trendAdjust;


    //double width = sixth*(1.0-alpha*trendSizeAdjust);
    double width = sixth - trendSizeAdjust*MathAbs(trend);

    width = MathMax(width,Point);


    BottomGoldLine  = NormalizeDouble(cen-2*width+offset, Digits);
    BottomGreenLine = NormalizeDouble(cen-1*width+offset, Digits);
    MiddleWhiteLine = NormalizeDouble(cen+offset, Digits);
    TopGreenLine    = NormalizeDouble(cen+1*width+offset, Digits);
    TopGoldLine     = NormalizeDouble(cen+2*width+offset, Digits);

    if (!IsTesting() && !IsVisualMode() ) {
        //Draw the lines
        double tl = ObjectGet("fivesixth", OBJPROP_PRICE1);
        double bl = ObjectGet("onesixth", OBJPROP_PRICE1);

        if (DoesLineNeedToMove(bl,BottomGoldLine) || DoesLineNeedToMove(tl,TopGoldLine)) {
            if (ObjectFind("onesixth") == -1) {
                ObjectCreate("onesixth",1,0,TimeCurrent(),BottomGoldLine);
                ObjectSet("onesixth",OBJPROP_COLOR,Gold);
                ObjectSet("onesixth",OBJPROP_STYLE,STYLE_SOLID);
                ObjectSet("onesixth",OBJPROP_WIDTH,2);
            }//if (ObjectFind("onesixth") == -1)
            else ObjectMove("onesixth",0,TimeCurrent(),BottomGoldLine);

            if (ObjectFind("twosixth") == -1) {
                ObjectCreate("twosixth",1,0,TimeCurrent(),BottomGreenLine);
                ObjectSet("twosixth",OBJPROP_COLOR,Green);
                ObjectSet("twosixth",OBJPROP_STYLE,STYLE_SOLID);
                ObjectSet("twosixth",OBJPROP_WIDTH,2);
            }//if (ObjectFind(
            else ObjectMove("twosixth",0,TimeCurrent(),BottomGreenLine);

            if (ObjectFind("threesixth") == -1) {
                ObjectCreate("threesixth",1,0,TimeCurrent(),MiddleWhiteLine);
                ObjectSet("threesixth",OBJPROP_COLOR,White);
                ObjectSet("threesixth",OBJPROP_STYLE,STYLE_SOLID);
                ObjectSet("threesixth",OBJPROP_WIDTH,2);
            }//if (ObjectFind(
            else ObjectMove("threesixth",0,TimeCurrent(),MiddleWhiteLine);

            if (ObjectFind("foursixth") == -1) {
                ObjectCreate("foursixth",1,0,TimeCurrent(),TopGreenLine);
                ObjectSet("foursixth",OBJPROP_COLOR,Green);
                ObjectSet("foursixth",OBJPROP_STYLE,STYLE_SOLID);
                ObjectSet("foursixth",OBJPROP_WIDTH,2);
            }//if (ObjectFind(
            else ObjectMove("foursixth",0,TimeCurrent(),TopGreenLine);

            if (ObjectFind("fivesixth") == -1) {
                ObjectCreate("fivesixth",1,0,TimeCurrent(),TopGoldLine);
                ObjectSet("fivesixth",OBJPROP_COLOR,Gold);
                ObjectSet("fivesixth",OBJPROP_STYLE,STYLE_SOLID);
                ObjectSet("fivesixth",OBJPROP_WIDTH,2);
            }//if (ObjectFind(
            else ObjectMove("fivesixth",0,TimeCurrent(),TopGoldLine);
        }//if(ctgl != TopGoldLine || cbgl != BottomGoldLine)
    }//if (!IsTesting() && !IsVisualMode() )
}//void GetSixths()

////////////////////////////////////////////////////////////////////////////////////////////////
//TRADE MANAGEMENT MODULE

/* given an integer cc which is in 0..OrdersTotal()-1,
   select it, and return true if it is my symbol and in my GlobalMagic */

bool SelectOneOfMyOrders(int cc)
{
    if (!OrderSelect(cc,SELECT_BY_POS)) {
        return(false);
    }
    if (OrderMagicNumber() != GlobalMagic) {
        return(false);
    }
    if (OrderSymbol() != Symbol()) {
        return(false);
    }
    return(true);
}

/* return true if the selected order is pending */
bool IsSelectedOrderPending()
{
    return ((OrderType() == OP_BUYSTOP) || (OrderType() == OP_SELLSTOP));
}

/* return true if the selected order is open */
bool IsSelectedOrderOpen()
{
    return ((OrderType() == OP_BUY) || (OrderType() == OP_SELL));
}

bool IsSelectedOrderPrimary()
{
    /* change if you want to do it by lot size instead of comment if you
       are paranoid and want to eliminate trade comments from being sent to criminal */
    return (StringFind(OrderComment(),"Primary",0) != -1);
}

bool IsSelectedOrderSecondary()
{
    return (StringFind(OrderComment(),"Secondary",0) != -1);
}

/*
extern double  Primary_trade_Lot_size=0.03;
extern double  Secondary_trade_Lot_size=0.01;
extern string  Primary_trade_comment="P";
extern string  Secondary_trade_comment="N";
*/

/* return the ticker of one of my trades,
   e.g. to return pending Primary sell, use FindMyTrade(OP_SELLSTOP,Primary_trade_comment) */

int FindMyTrade(int ordertype, string comment)
{
    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
        if (!SelectOneOfMyOrders(cc)) continue;
        if ((OrderType() == ordertype) && (OrderComment() == comment)) {
            return(OrderTicket());
        }
    }
    return(0);
}

/* return the distance (in price) from the closest primary or secondary trade (open or pending) */
double DistanceToClosestTrade(double price, bool wantprimary) {
   bool found = false;
   double min; 
   for (int cc=OrdersTotal()-1; cc >= 0; cc--) {
        if (!SelectOneOfMyOrders(cc)) continue;
        // if ((OrderType() != OP_BUY) && (OrderType() != OP_SELL)) continue;
        if ((IsSelectedOrderPrimary() && wantprimary) || (IsSelectedOrderSecondary() && !wantprimary)) {
            double diff = MathAbs(OrderOpenPrice() - price); 
            if (found) {
               min = MathMin(min,diff); 
            } else {
               min = diff;
               found = true; 
            }
        }
    }
    if (found) {
      return(diff); 
    } else {
      return(-1.0); 
    }
}
        


bool DoesTradeExist(double price)
{
    if (OrdersTotal() == 0) return(false);
    string sPrice = DoubleToStr(price, Digits);

    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
        if (!SelectOneOfMyOrders(cc)) continue;
        if (IsDeltaPriceSmallPips(price,OrderOpenPrice(),1.0)) {
            return(true);
        }
    }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
    return(false);

}//End bool DoesTradeExist(double price)

int EarliestPendingSecondaryTicket()
{
    /* return the ticketnumber of the earliest secondary ticket */
    datetime dt=0;
    int ticket=0;
    int cc;
    for (cc = OrdersTotal()-1; cc >= 0; cc--) {
        if (!SelectOneOfMyOrders(cc)) continue;
        if (IsSelectedOrderPending() && IsSelectedOrderSecondary() ) {
            datetime dtnow=OrderOpenTime();
            if ((dt == 0) || (dtnow < dt)) {
                dt = dtnow;
                ticket = OrderTicket();
            }
        }
    }
    return(ticket);
}

int EarliestPendingPrimaryTicket()
{
    /* return the ticketnumber of the earliest Primary ticket */
    datetime dt=0;
    int ticket=0;
    for (int cc = OrdersTotal()-1; cc >= 0; cc--) {
        if (!SelectOneOfMyOrders(cc)) continue;
        if (IsSelectedOrderPending() && IsSelectedOrderPrimary() ) {
            datetime dtnow=OrderOpenTime();
            if ((dt == 0) || (dtnow < dt)) {
                dt = dtnow;
                ticket = OrderTicket();
            }
        }
    }
    return(ticket);
}

/* return true if there was something to do */
bool CleanUpOneIteration()
{
    bool result;

    CountOpenTrades();
    CountPendingTrades();

    // close orphaned secondaries
    if (PendingSecondary > 0 && PendingPrimary == 0 && PrimaryTrades == 0) {
        int ticket = EarliestPendingSecondaryTicket();
        if (ticket > 0) {
            result = OrderDeleteReliable(ticket);
            return(true);
        }
    }
    // delete duplicate primary trades
    if (PendingPrimary > 1) {
        ticket = EarliestPendingPrimaryTicket();
        if (ticket > 0) {
            result = OrderDeleteReliable(ticket);
            return(true);
        }
    }
   // delete duplicate secondary trades
    if (PendingSecondary > 1) {
        ticket = EarliestPendingSecondaryTicket();
        if (ticket > 0) {
            result = OrderDeleteReliable(ticket);
            return(true);
        }
    }
    
    return(false);
}

bool CleanUp()
{
    for (int i=1; i< 10; i++) {
        if (CleanUpOneIteration() == false) {
            return(true);
        }
    }
    Print("Attempted 10 iterations in CleanUp() without getting a nothing-to-do return.");
    return(false);
}


bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop )
{
    //Reusable code that can be called by any of the stop loss manipulation routines except HiddenStopLoss().
    //Checks to see if the market has hit the hidden sl and attempts to close the trade if so.
    //Returns true if trade closure is successful, else returns false

    //Check buy trade
    if (type == OP_BUY) {
        double sl = NormalizeDouble(stop + (iPipsAboveVisual * Point), Digits);
        if (Bid <= sl) {
            bool result = OrderCloseReliable(OrderTicket(), OrderLots(), OrderClosePrice(), 5000, CLR_NONE);
            if (result) {
                if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());
            }//if (result)
            else {
                int err=GetLastErrorReliable();
                if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            }//else
        }//if (Bid <= sl)
    }//if (type = OP_BUY)

    //Check buy trade
    if (type == OP_SELL) {
        sl = NormalizeDouble(stop - (iPipsAboveVisual * Point), Digits);
        if (Ask >= sl) {
            result = OrderCloseReliable(OrderTicket(), OrderLots(), OrderClosePrice(), 5000, CLR_NONE);
            if (result) {
                if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());
            }//if (result)
            else {
                err=GetLastErrorReliable();
                if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            }//else
        }//if (Ask >= sl)
    }//if (type = OP_SELL)
    return(result); // added by MBK

}//End bool CheckForHiddenStopLossHit(int type, int iPipsAboveVisual, double stop )


void BreakEvenStopLoss() // Move stop loss to breakeven
{
    //Check hidden BE for trade closure
    if (HideBreakEvenStop) {
        bool TradeClosed = CheckForHiddenStopLossHit(OrderType(), PipsAwayFromVisualBE, OrderStopLoss() );
        if (TradeClosed) return;//Trade has closed, so nothing else to do
    }//if (HideBreakEvenStop)

    bool result;

    if (OrderType()==OP_BUY) {
        if (Ask >= OrderOpenPrice() + (Point*BreakEvenPips) &&
            OrderStopLoss()<OrderOpenPrice()) {
            result = OrderModifyReliable(OrderTicket(),OrderOpenPrice(),NormalizeDouble(OrderOpenPrice()+(BreakEvenProfit*Point), Digits),OrderTakeProfit(),0,CLR_NONE);
            if (result && ShowManagementAlerts==true) Alert("Breakeven set on ", OrderSymbol(), " ticket no ", OrderTicket());
            Print("Breakeven set on ", OrderSymbol(), " ticket no ", OrderTicket());
            if (!result) {
                int err=GetLastErrorReliable();
                if (ShowManagementAlerts==true) Alert("Setting of breakeven SL ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                Print("Setting of breakeven SL ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            }
        }//if (Ask >= OrderOpenPrice()
    } //if (OrderType()==OP_BUY)

    if (OrderType()==OP_SELL) {
        if (Bid <= OrderOpenPrice() - (Point*BreakEvenPips) &&
            (OrderStopLoss()>OrderOpenPrice() || OrderStopLoss()==0)) {
            result = OrderModifyReliable(OrderTicket(),OrderOpenPrice(),NormalizeDouble(OrderOpenPrice()-(BreakEvenProfit*Point), Digits),OrderTakeProfit(),0,CLR_NONE);
            if (result && ShowManagementAlerts==true) Alert("Breakeven set on ", OrderSymbol(), " ticket no ", OrderTicket());
            Print("Breakeven set on ", OrderSymbol(), " ticket no ", OrderTicket());
            if (!result && ShowManagementAlerts) {
                err=GetLastErrorReliable();
                if (ShowManagementAlerts==true) Alert("Setting of breakeven SL ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                Print("Setting of breakeven SL ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            }//if !result && ShowManagementAlerts)
            //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
            // {
            //    PartCloseSuccess = PartCloseTradeFunction();
            //    if (!PartCloseSuccess) SetAGlobalTicketVariable();
            // }//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
        }//if (Bid <= OrderOpenPrice()
    }//if (OrderType()==OP_SELL)

} // End BreakevenStopLoss sub

void JumpingStopLoss()
{
    // Jump sl by pips and at intervals chosen by user .
    // Also carry out partial closure if the user requires this

    // Abort the routine if JumpAfterBreakevenOnly is set to true and be sl is not yet set
    if (JumpAfterBreakevenOnly && OrderType()==OP_BUY) {
        if(OrderStopLoss()<OrderOpenPrice()) return(0);
    }

    if (JumpAfterBreakevenOnly && OrderType()==OP_SELL) {
        if(OrderStopLoss()>OrderOpenPrice() || OrderStopLoss() == 0) return(0);
    }

    double sl=OrderStopLoss(); //Stop loss

    if (OrderType()==OP_BUY) {
        //Check hidden js for trade closure
        if (HideJumpingStop) {
            bool TradeClosed = CheckForHiddenStopLossHit(OP_BUY, PipsAwayFromVisualJS, OrderStopLoss() );
            if (TradeClosed) return;//Trade has closed, so nothing else to do
        }//if (HideJumpingStop)

        // First check if sl needs setting to breakeven
        if (sl==0 || sl<OrderOpenPrice()) {
            if (Ask >= OrderOpenPrice() + (JumpingStopPips*Point)) {
                sl=OrderOpenPrice();
                if (AddBEP==true) sl=sl+(BreakEvenProfit*Point); // If user wants to add a profit to the break even
                bool result = OrderModifyReliable(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
                if (result) {
                    if (ShowManagementAlerts==true) Alert("Jumping stop set at breakeven ",sl, " ", OrderSymbol(), " ticket no ", OrderTicket());
                    Print("Jumping stop set at breakeven: ", OrderSymbol(), ": SL ", sl, ": Ask ", Bid);
                    //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
                    //{
                    //bool PartCloseSuccess = PartCloseTradeFunction();
                    //if (!PartCloseSuccess) SetAGlobalTicketVariable();
                    //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
                }//if (result)
                if (!result) {
                    int err=GetLastErrorReliable();
                    if (ShowManagementAlerts) Alert(OrderSymbol(), "Ticket ", OrderTicket(), " buy trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
                    Print(OrderSymbol(), " buy trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
                }//if (!result)

                return(0);
            }//if (Ask >= OrderOpenPrice() + (JumpingStopPips*Point))
        } //close if (sl==0 || sl<OrderOpenPrice()


        // Increment sl by sl + JumpingStopPips.
        // This will happen when market price >= (sl + JumpingStopPips)
        if (Bid>= sl + ((JumpingStopPips*2)*Point) && sl>= OrderOpenPrice()) {
            sl=sl+(JumpingStopPips*Point);
            result = OrderModifyReliable(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
            if (result) {
                if (ShowManagementAlerts==true) Alert("Jumping stop set at ",sl, " ", OrderSymbol(), " ticket no ", OrderTicket());
                Print("Jumping stop set: ", OrderSymbol(), ": SL ", sl, ": Ask ", Ask);
                //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
                //{
                //PartCloseSuccess = PartCloseTradeFunction();
                //if (!PartCloseSuccess) SetAGlobalTicketVariable();
                //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
            }//if (result)
            if (!result) {
                err=GetLastErrorReliable();
                if (ShowManagementAlerts) Alert(OrderSymbol(), " buy trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
                Print(OrderSymbol(), " buy trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
            }//if (!result)

        }// if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())
    }//if (OrderType()==OP_BUY)

    if (OrderType()==OP_SELL) {
        //Check hidden js for trade closure
        if (HideJumpingStop) {
            TradeClosed = CheckForHiddenStopLossHit(OP_SELL, PipsAwayFromVisualJS, OrderStopLoss() );
            if (TradeClosed) return;//Trade has closed, so nothing else to do
        }//if (HideJumpingStop)

        // First check if sl needs setting to breakeven
        if (sl==0 || sl>OrderOpenPrice()) {
            if (Ask <= OrderOpenPrice() - (JumpingStopPips*Point)) {
                sl = OrderOpenPrice();
                if (AddBEP==true) sl=sl-(BreakEvenProfit*Point); // If user wants to add a profit to the break even
                result = OrderModifyReliable(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
                if (result) {
                    //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
                    //{
                    // PartCloseSuccess = PartCloseTradeFunction();
                    //if (!PartCloseSuccess) SetAGlobalTicketVariable();
                    //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
                }//if (result)
                if (!result) {
                    err=GetLastErrorReliable();
                    if (ShowManagementAlerts) Alert(OrderSymbol(), " sell trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
                    Print(OrderSymbol(), " sell trade. Jumping stop function failed to set SL at breakeven, with error(",err,"): ",ErrorDescription(err));
                }//if (!result)

                return(0);
            }//if (Ask <= OrderOpenPrice() - (JumpingStopPips*Point))
        } // if (sl==0 || sl>OrderOpenPrice()

        // Decrement sl by sl - JumpingStopPips.
        // This will happen when market price <= (sl - JumpingStopPips)
        if (Bid<= sl - ((JumpingStopPips*2)*Point) && sl<= OrderOpenPrice()) {
            sl=sl-(JumpingStopPips*Point);
            result = OrderModifyReliable(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
            if (result) {
                if (ShowManagementAlerts==true) Alert("Jumping stop set at ",sl, " ", OrderSymbol(), " ticket no ", OrderTicket());
                Print("Jumping stop set: ", OrderSymbol(), ": SL ", sl, ": Ask ", Ask);
                //if (PartCloseEnabled && OrderLots() > Preserve_Lots)// Only try to do this if the jump stop worked
                //{
                // PartCloseSuccess = PartCloseTradeFunction();
                //if (!PartCloseSuccess) SetAGlobalTicketVariable();
                //}//if (PartCloseEnabled && OrderLots() > Preserve_Lots)
            }//if (result)
            if (!result) {
                err=GetLastErrorReliable();
                if (ShowManagementAlerts) Alert(OrderSymbol(), " sell trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
                Print(OrderSymbol(), " sell trade. Jumping stop function failed with error(",err,"): ",ErrorDescription(err));
            }//if (!result)

        }// close if (Bid>= sl + (JumpingStopPips*Point) && sl>= OrderOpenPrice())
    }//if (OrderType()==OP_SELL)

} //End of JumpingStopLoss sub

void HiddenStopLoss()
{
    //Called from ManageTrade if HideStopLossEnabled = true

    //Should the order close because the stop has been passed?
    //Buy trade
    if (OrderType() == OP_BUY) {
        double sl = NormalizeDouble(OrderOpenPrice() - (HiddenStopLossPips * Point), Digits);
        if (Bid <= sl) {
            bool result = OrderCloseReliable(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
            if (result) {
                if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());
            }//if (result)
            else {
                int err=GetLastErrorReliable();
                if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            }//else
        }//if (Bid <= sl)
    }//if (OrderType() == OP_BUY)

    //Sell trade
    if (OrderType() == OP_SELL) {
        sl = NormalizeDouble(OrderOpenPrice() + (HiddenStopLossPips * Point), Digits);
        if (Ask >= sl) {
            result = OrderCloseReliable(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
            if (result) {
                if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());
            }//if (result)
            else {
                err=GetLastErrorReliable();
                if (ShowManagementAlerts==true) Alert("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                Print("Stop loss hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            }//else
        }//if (Ask >= sl)
    }//if (OrderType() == OP_SELL)
}//End void HiddenStopLoss()

void HiddenTakeProfit()
{
    //Called from ManageTrade if HideStopLossEnabled = true

    //Should the order close because the stop has been passed?
    //Buy trade
    if (OrderType() == OP_BUY) {
        double tp = NormalizeDouble(OrderOpenPrice() + (HiddenTakeProfitPips * Point), Digits);
        if (Bid >= tp) {
            bool result = OrderCloseReliable(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
            if (result) {
                if (ShowManagementAlerts==true) Alert("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());
            }//if (result)
            else {
                int err=GetLastErrorReliable();
                if (ShowManagementAlerts==true) Alert("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                Print("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            }//else
        }//if (Ask >= tp)
    }//if (OrderType() == OP_BUY)

    //Sell trade
    if (OrderType() == OP_SELL) {
        tp = NormalizeDouble(OrderOpenPrice() - (HiddenTakeProfitPips * Point), Digits);
        if (Ask <= tp) {
            result = OrderCloseReliable(OrderTicket(), OrderLots(), OrderClosePrice(), 5, CLR_NONE);
            if (result) {
                if (ShowManagementAlerts==true) Alert("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket());
            }//if (result)
            else {
                err=GetLastErrorReliable();
                if (ShowManagementAlerts==true) Alert("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
                Print("Take profit hit. Close of ", OrderSymbol(), " ticket no ", OrderTicket()," failed with error (",err,"): ",ErrorDescription(err));
            }//else
        }//if (Bid <= tp)
    }//if (OrderType() == OP_SELL)

}//End void HiddenTakeProfit()

void TrailingStopLoss()
{
    if (TrailAfterBreakevenOnly && OrderType()==OP_BUY) {
        if(OrderStopLoss()<OrderOpenPrice()) return(0);
    }

    if (TrailAfterBreakevenOnly && OrderType()==OP_SELL) {
        if(OrderStopLoss()>OrderOpenPrice()) return(0);
    }

    bool result;
    double sl=OrderStopLoss(); //Stop loss
    double BuyStop=0, SellStop=0;

    if (OrderType()==OP_BUY) {
        if (HideTrailingStop) {
            bool TradeClosed = CheckForHiddenStopLossHit(OP_BUY, PipsAwayFromVisualTS, OrderStopLoss() );
            if (TradeClosed) return;//Trade has closed, so nothing else to do
        }//if (HideJumpingStop)

        if (Bid >= OrderOpenPrice() + (TrailingStopPips*Point)) {
            if (OrderStopLoss() == 0) sl = OrderOpenPrice();
            if (Bid > sl +  (TrailingStopPips*Point)) {
                sl= Bid - (TrailingStopPips*Point);
                // Exit routine if user has chosen StopTrailAtPipsProfit and
                // sl is past the profit Point already
                if (StopTrailAtPipsProfit && sl>= OrderOpenPrice() + (StopTrailPips*Point)) return;
                result = OrderModifyReliable(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
                if (result) {
                    Print("Trailing stop updated: ", OrderSymbol(), ": SL ", sl, ": Ask ", Ask);
                }//if (result)
                else {
                    int err=GetLastErrorReliable();
                    Print(OrderSymbol(), " order modify failed with error(",err,"): ",ErrorDescription(err));
                }//else

            }//if (Bid > sl +  (TrailingStopPips*Point))
        }//if (Bid >= OrderOpenPrice() + (TrailingStopPips*Point))
    }//if (OrderType()==OP_BUY)

    if (OrderType()==OP_SELL) {
        if (Ask <= OrderOpenPrice() - (TrailingStopPips*Point)) {
            if (HideTrailingStop) {
                TradeClosed = CheckForHiddenStopLossHit(OP_SELL, PipsAwayFromVisualTS, OrderStopLoss() );
                if (TradeClosed) return;//Trade has closed, so nothing else to do
            }//if (HideJumpingStop)

            if (OrderStopLoss() == 0) sl = OrderOpenPrice();
            if (Ask < sl -  (TrailingStopPips*Point)) {
                sl= Ask + (TrailingStopPips*Point);
                // Exit routine if user has chosen StopTrailAtPipsProfit and
                // sl is past the profit Point already
                if (StopTrailAtPipsProfit && sl<= OrderOpenPrice() - (StopTrailPips*Point)) return;
                result = OrderModifyReliable(OrderTicket(),OrderOpenPrice(),sl,OrderTakeProfit(),0,CLR_NONE);
                if (result) {
                    Print("Trailing stop updated: ", OrderSymbol(), ": SL ", sl, ": Bid ", Bid);
                }//if (result)
                else {
                    err=GetLastErrorReliable();
                    Print(OrderSymbol(), " order modify failed with error(",err,"): ",ErrorDescription(err));
                }//else

            }//if (Ask < sl -  (TrailingStopPips*Point))
        }//if (Ask <= OrderOpenPrice() - (TrailingStopPips*Point))
    }//if (OrderType()==OP_SELL)

} // End of TrailingStopLoss sub


void TradeManagementModule()
{
    // Call the working subroutines one by one.

    // mbkennel: modified to be smarter about CPU overload managment.
    static datetime lastTickTime=0;
    int minimum_update_interval = 2;

    if ( (TimeCurrent() - lastTickTime) < minimum_update_interval) {
        return;
    }

    // Hidden stop loss
    if (HideStopLossEnabled) HiddenStopLoss();

    // Hidden take profit
    if (HideTakeProfitEnabled) HiddenTakeProfit();

    // Breakeven
    if(BreakEven) BreakEvenStopLoss();

    // JumpingStop
    if(JumpingStop) JumpingStopLoss();

    //TrailingStop
    if(TrailingStop) TrailingStopLoss();
    lastTickTime = TimeCurrent();

}//void TradeManagementModule()
//END TRADE MANAGEMENT MODULE
////////////////////////////////////////////////////////////////////////////////////////////////




bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take, int magic)
{

    int slippage = 10;
    if (Digits == 3 || Digits == 5) slippage = 100;

    if (magic == 0 ) { // added MBK
        magic = GlobalMagic;
    }

    color col = Red;
    if (type == OP_BUY || type == OP_BUYSTOP) col = Green;

    int expiry = 0;
    //if (SendPendingTrades) expiry = TimeCurrent() + (PendingExpiryMinutes * 60);

    int ticket = OrderSendReliable(Symbol(),type, lotsize, price, slippage, stop, take, comment, magic, expiry, col);
    if (ticket < 0) {
        string stype;
        if (type == OP_BUY) stype = "OP_BUY";
        if (type == OP_BUYSTOP) stype = "OP_BUYSTOP";
        if (type == OP_SELL) stype = "OP_SELL";
        if (type == OP_SELLSTOP) stype = "OP_SELLSTOP";
        int err=GetLastErrorReliable();
        //Alert(Symbol(), " ", stype,"  order send failed with error(",err,"): ",ErrorDescription(err));
        Print(Symbol(), " ", stype,"  order send failed with error(",err,"): ",ErrorDescription(err));
        return(false);
    }//if (ticket < 0)

    //Got this far, so trade send succeeded
    Sleep(5000);


    return(true);

}//End bool SendSingleTrade(int type, string comment, double lotsize, double price, double stop, double take)

/* p2 is how many basis points higher or lower than reference
   point p1? */

bool IsTradingAllowed()
{
    //Trades count
    if (OpenTrades + PendingTradesTotal >= MaxTradesAllowed) return(false);

    //This is possibly redundant, gut I include it as a check anyhow
    if (Bid <= TopGoldLine && Ask >= BottomGoldLine) return(false);

    //Min distance from most recently filled trade
    if (MostRecentTradePrice != 0) {
        //Possible short trade
        if (Bid > TopGoldLine) {
            if (BasisPointsAway(MostRecentTradePrice,TopGoldLine) < MinBasisPointsFromLastEntry) {
                return(false);
            }
        }//if (Bid > TopGldLine)

        //Possible long trade
        if (Ask < BottomGoldLine) {
            if (BasisPointsAway(MostRecentTradePrice,BottomGoldLine) > -MinBasisPointsFromLastEntry) {
                return(false);
            }
        }//if (Ask < BottomGoldLine)
    }//if (MostRecentTradePrice != 0)
    return(true);
}//End bool IsTradingAllowed()


double CalculateStop(double price, int type)
{
    double sl;
    double AtrVal = iATR(NULL, 0, 20, 0) * 3;

    if (type == OP_BUY) {
        if (StopLoss > 0) sl = NormalizeDouble(price - (StopLoss * Point), Digits);
        if (StopLoss == 0) sl = NormalizeDouble(price - AtrVal, Digits);
    }//if (type == OP_BUY)


    if (type == OP_SELL) {
        if (StopLoss > 0) sl = NormalizeDouble(price + (StopLoss * Point), Digits);
        if (StopLoss == 0) sl = NormalizeDouble(price + AtrVal, Digits);
    }//if (type == OP_SELL)

    return(sl);

}//End double CalculateStop(double price, int type)

/* return price + bp basis points. bp can be negative */
double BPOffset(double p, double bp)
{
    return(p + p*bp/10000.0);
}

/* see if any new trade is not within MinBasisPointsFromLastEntry */ 
bool IsNewTradeAllowed(double price, bool wantprimary) {
   double pdiff=DistanceToClosestTrade(price, wantprimary); 
   if (pdiff < 0) {
      Print("DEBUG: IsNewTradeAllowed(): pdiff < 0"); 
      return(true); 
   } else {
      if ( (pdiff+price)/price *10000 >= MinBasisPointsFromLastEntry) {
         Print("DEBUG: IsNewTradeAllowed(): pdiff > minbasis points ");
         return(true); 
      } else {
         Print("DEBUG: IsNewTradeAllowed(): pdiff < minbasis points"); 
         return(false); 
      }  
   }
}

/* type should be OP_SELL or OP_BUY.  return true if successful new trade is placed */ 
bool AttemptOneTrade(double price, int type, bool is_primary, string comment, double lots) {
   if (DoesTradeExist(price)) {
      return(false); 
   }
   if (!IsNewTradeAllowed(price,is_primary)) {
      return(false); 
   }
   int type2=0;
   if (type == OP_BUY) {
      type2 = OP_BUYSTOP;
   }
   if (type == OP_SELL) {
      type2 = OP_SELLSTOP;
   }
   if (type2 == 0) return(false); 
   double stop=0.0;
   if (UseStopLoss) {
      stop = CalculateStop(price,type); 
   }
   bool result = SendSingleTrade(type2,comment,lots,price, stop, 0, GlobalMagic);  
}


void CalculateTrades()
{
    double target;
    if (!IsTradingAllowed() ) return;

//extern bool    Use1.1.3.3Recovery=false;
//extern bool    Use1.1.2.4Recovery=true;

    double SendLots = Primary_trade_Lot_size;
    //Using 1.1.2.4 recovery
    if (RecoveryInProgress) {
        if (PrimaryTrades == 2) {
            SendLots = Primary_trade_Lot_size * 2;
            if (Use1.1.3.3Recovery) SendLots = Primary_trade_Lot_size * 3;
        }//if (PrimaryTrades == 2)

        if (PrimaryTrades == 3) {
            SendLots = Primary_trade_Lot_size * 4;
            if (Use1.1.3.3Recovery) SendLots = Primary_trade_Lot_size * 3;
        }//if (PrimaryTrades == 3)

        if (PrimaryTrades == 4) return;//No further trading is possible

        double RecoveryLineVal = ObjectGet(reentrylinename, OBJPROP_PRICE1);
    }//if (RecoveryInProgress)

    double stop=0.0;

    //Primary sell
    target = NormalizeDouble(BPOffset(TopGoldLine,BasisPointsBufferFromTradeLine), Digits);
    if (Bid >= target && Primary_trades && TradeShort) {
        if (RecoveryInProgress && TopGoldLine < RecoveryLineVal) return;
        bool result=AttemptOneTrade(TopGoldLine,OP_SELL,true,Primary_trade_comment,SendLots); 
        if (result) AddReEntryLine(NormalizeDouble(Bid + (ReEntryLinePips * Point), Digits) );
        if (DoesTradeExist(TopGreenLine) ) return;
        if (Secondary_trades && !RecoveryInProgress) {
           result=AttemptOneTrade(TopGreenLine,OP_SELL,false,Secondary_trade_comment,Secondary_trade_Lot_size); 
        }
    }//if (Bid > TopGoldLine && Primary_trades)

    //Secondary sell
    target = NormalizeDouble(BPOffset(TopGreenLine,BasisPointsBufferFromTradeLine), Digits);
    if (Bid <= TopGoldLine && Bid > target && Secondary_trades && TradeShort) {
        if (!RecoveryInProgress) {
           result=AttemptOneTrade(TopGreenLine,OP_SELL,false,Secondary_trade_comment,Secondary_trade_Lot_size); 
        }
    }//if (Bid <= TopGoldLine && Bid > TopGreenLine && Secondary_trades)

    //Primary buy
    target = NormalizeDouble(BPOffset(BottomGoldLine,-BasisPointsBufferFromTradeLine), Digits);
    if (Ask <= target && Primary_trades && TradeLong) {
        if (RecoveryInProgress && BottomGoldLine > RecoveryLineVal) return;
        result = AttemptOneTrade(BottomGoldLine,OP_BUY,true,Primary_trade_comment,SendLots);
        if (result) AddReEntryLine(NormalizeDouble(Ask - (ReEntryLinePips * Point), Digits) );
        if (DoesTradeExist(BottomGreenLine) ) return;
        if (Secondary_trades && !RecoveryInProgress) {
           result=AttemptOneTrade(BottomGreenLine,OP_BUY,false,Secondary_trade_comment,Secondary_trade_Lot_size); 
        }
    }//if (Bid > TopGoldLine && Primary_trades)

    //Secondary buy
    target = NormalizeDouble(BPOffset(BottomGreenLine,-BasisPointsBufferFromTradeLine), Digits);
    if (Ask <= target && Ask >= BottomGoldLine && Secondary_trades && TradeLong) {
        if (!RecoveryInProgress) {
           result=AttemptOneTrade(BottomGreenLine,OP_BUY,false,Secondary_trade_comment,Secondary_trade_Lot_size); 
        }
    }//if (Bid <= TopGoldLine && Bid > TopGreenLine && Secondary_trades)
}//End void CalculateTrades()

bool ReadjustPending(int ticket, double newprice)
{
    /* readjust pending order with given ticket to 'newprice',
       if it is sufficiently different */

    if (ticket == 0) return(false);
    if (!OrderSelect(ticket,SELECT_BY_TICKET)) return(false);

    int type=OrderType();
    color col = Red;
    if (type == OP_BUY || type == OP_BUYSTOP) {
        col = Green;
    }

    if (DoesLineNeedToMove(OrderOpenPrice(),newprice)) {
        return ( OrderModifyReliable(ticket,newprice,OrderStopLoss(),OrderTakeProfit(),OrderExpiration(),col) );
    }
    return(false);
}

void ReadjustPendings()
{
    int TopGold_ticket = FindMyTrade(OP_SELLSTOP, Primary_trade_comment);
    int TopGreen_ticket = FindMyTrade(OP_SELLSTOP, Secondary_trade_comment);
    int BottomGold_ticket = FindMyTrade(OP_BUYSTOP, Primary_trade_comment);
    int BottomGreen_ticket = FindMyTrade(OP_BUYSTOP, Secondary_trade_comment);

    ReadjustPending(TopGold_ticket,TopGoldLine);
    ReadjustPending(TopGreen_ticket,TopGreenLine);
    ReadjustPending(BottomGold_ticket,BottomGoldLine);
    ReadjustPending(BottomGreen_ticket,BottomGreenLine);

}

void DeletePendingTrades()
{
    ForcePendingTradeDeletion = false;

    if (OrdersTotal() == 0) return;

    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
        if (SelectOneOfMyOrders(cc) && IsSelectedOrderPending() && (IsSelectedOrderPrimary() || IsSelectedOrderSecondary() ) ) {
            bool result = OrderDeleteReliable(OrderTicket());
            if (result) {
                cc++;
                ObjectDelete(reentrylinename);
            }
            if (!result) ForcePendingTradeDeletion = true;
        }//if (OrderSymbol() == Symbol() && (OrderComment() == Primary_trade_comment || OrderComment() == Secondary_trade_comment)
    }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
}//void DeletePendingTrades()

void CloseAllTrades()
{
    ForceAllTradeDeletion = false;

    if (OrdersTotal() == 0) return;
    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
        if (!SelectOneOfMyOrders(cc)) continue;

        if (IsSelectedOrderOpen()) bool result = OrderCloseReliable(OrderTicket(), OrderLots(), OrderClosePrice(), 1000, CLR_NONE);
        if (IsSelectedOrderPending()) result = OrderDeleteReliable(OrderTicket() );
        if (result) cc++;
        if (!result) ForceAllTradeDeletion = true;
    }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
}//End void CloseAllTrades()


void LookForTradeClosure()
{
    ForceAllTradeDeletion = false;
    // if (UseTplTp) return;//Take profit line

    if (OrdersTotal() == 0) return;

    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
        if (SelectOneOfMyOrders(cc)) {
            if (OrderType() == OP_SELL && Bid <= MiddleWhiteLine) {
                CloseAllTrades();
            }//if (OrderType == OP_SELL && Bid < MiddleWhiteLine)
            if (OrderType() == OP_BUY && Ask >= MiddleWhiteLine) {
                CloseAllTrades();
            }//if (OrderType == OP_SELL && Bid < MiddleWhiteLine)
        }//if (OrderSymbol() == Symbol() )
    }//for (int cc = OrdersTotal() - 1; cc >= 0; cc--)
}//End void LookForTradeClosure()

void CountOpenTrades()
{
    OpenTrades = 0;
    BasketUpl = 0;
    PrimaryTrades = 0;
    SecondaryTrades = 0;
    bool BuyOpen, SellOpen;

    if (OrdersTotal() == 0) return;

    datetime mostRecentTradeTime=0;

    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
        if (SelectOneOfMyOrders(cc)) {
            if (OrderProfit() > 0 && ObjectFind(breakevenlinename) == -1 && !RecoveryInProgress && !HedgingInProgress) TradeManagementModule();
            if (IsSelectedOrderOpen()) {
                if (OrderType() == OP_BUY) BuyOpen = true;
                if (OrderType() == OP_SELL) SellOpen = true;
                OpenTrades++;
                BasketUpl+= (OrderProfit() + OrderSwap() + OrderCommission() );
                if (OrderOpenTime() > mostRecentTradeTime) {
                    MostRecentTradePrice = OrderOpenPrice();
                }
                if (IsSelectedOrderPrimary()) PrimaryTrades++;
                if (IsSelectedOrderSecondary()) SecondaryTrades++;
                if (OrderProfit() < 0 && UseHedging) HedgingModule();
            }//if (OrderType() == OP_BUY || OrderType() == OP_SELL)

            if (ObjectFind(breakevenlinename) > -1 && !HedgingInProgress) {
                double take = ObjectGet(breakevenlinename, OBJPROP_PRICE1);
                if ((OrderTakeProfit() != take) && IsSelectedOrderOpen() ) {
                    OrderModifyReliable(OrderTicket(), OrderOpenPrice(), OrderStopLoss(), take, OrderExpiration(), CLR_NONE);
                }//if (OrderTakeProfit() != take && (OrderType() == OP_BUY || OrderType() == OP_SELL) )
            }//if (ObjectFind(breakevenlinename) > -1)

        }//if (OrderSymbol() == Symbol() )
    }//for (int cc = 0; cc <= OrdersTotal(); cc++)
    if (BuyOpen && SellOpen) HedgingInProgress = true;
}//End void CountOpenTrades()

void CountPendingTrades()
{
    PendingTradesTotal = 0;
    PendingPrimary = 0;
    PendingSecondary = 0;

    if (OrdersTotal() == 0) return;

    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
        if (!SelectOneOfMyOrders(cc)) continue;
        if (IsSelectedOrderPending()) {
            PendingTradesTotal++;
            if (IsSelectedOrderPrimary()) PendingPrimary++;
            if (IsSelectedOrderSecondary()) PendingSecondary++;
        }//if (OrderType() == OP_BUY || OrderType() == OP_SELL)
    }//for (int cc = 0; cc <= OrdersTotal(); cc++)
}//End void CountPendingTrades()

void RecoveryModule()
{
    //Draw a breakeven line if there is not one in place already.
    //The bot will adjust the tp's during the CountOpenTrades function.
    if (ObjectFind(breakevenlinename) > -1) return;

    buy_price = 0;
    sell_price = 0;
    CheckRecoveryTakeProfit();
    double recovery_profit;
    if (buy_price > 0) {
        recovery_profit = buy_price;
        recovery_profit = NormalizeDouble(buy_price + (RecoveryBreakEvenProfitPips * Point), Digits);
    }//if (buy_price > 0)

    if (sell_price > 0) {
        recovery_profit = sell_price;
        recovery_profit = NormalizeDouble(sell_price - (RecoveryBreakEvenProfitPips * Point), Digits);
    }//if (sell_price > 0)

    ObjectCreate(breakevenlinename,OBJ_HLINE,0,TimeCurrent(), recovery_profit );
    ObjectSet(breakevenlinename,OBJPROP_COLOR,BreakEvenLineColour);
    ObjectSet(breakevenlinename,OBJPROP_STYLE,STYLE_SOLID);
    ObjectSet(breakevenlinename,OBJPROP_WIDTH,2);

}//End void RecoveryModule()

/* mbk: rewritten */
double AverageOrderPrice(int type)
{
    double sum_lots=0.0;
    double sum_price=0.0;
    for (int cc=OrdersTotal() -1; cc >= 0; cc--) {
        if (SelectOneOfMyOrders(cc)) {
            if (OrderType() == type) {
                sum_lots += OrderLots();
                sum_price += OrderOpenPrice()*OrderLots();
            }
        }
    }
    if (sum_lots > 0.0) {
        return(sum_price / sum_lots);
    } else {
        return(0.0);
    }
}

void CheckRecoveryTakeProfit()
{
    buy_price = AverageOrderPrice(OP_BUY);
    sell_price = AverageOrderPrice(OP_SELL);
}


double HoursOpen(int ticket)
{
    /* return the number of hours this trade has been open in broker BAR times!
       which is only physical times not over the weekend */

    if (!OrderSelect(ticket,SELECT_BY_TICKET)) {
        return(0.0);
    }

    datetime opentime= OrderOpenTime();
    if (opentime == 0) {
        return(0.0);
    }
    int barsback=iBarShift(Symbol(),PERIOD_H1,opentime,false);
    int openMinute=TimeMinute(opentime);
    int nowMinute =TimeMinute(TimeCurrent());
    if (barsback == 0) {
        return( (nowMinute-openMinute)/60.0);
    } else {
        return(  (nowMinute + (60-openMinute))/60.0 + (barsback-1.0) );
    }
}


void HandleDecayingTPforTrade(int ticket)
{
    double hoursOpen = HoursOpen(ticket);
    /* check if the hoursOpen is larger */
    if (hoursOpen < HoursToStartDTP) {
        return;
    }
    double fraction = (hoursOpen-HoursToStartDTP) / HoursToReachYellowLine;

    double take;
    if (OrderType() == OP_BUY) {
        take = MiddleWhiteLine - fraction*MathAbs(BottomGoldLine-MiddleWhiteLine);
    }
    if (OrderType() == OP_SELL) {
        take = MiddleWhiteLine + fraction*MathAbs(TopGoldLine-MiddleWhiteLine);
    }
    take = NormalizeDouble(take,Digits);
    bool need_to_adjust= (OrderTakeProfit() == 0);

    if ((OrderType() == OP_BUY) && (take <= OrderTakeProfit() - 1.0*Point*multiplier)) {
        need_to_adjust=true;
    }

    if ((OrderType() == OP_SELL) && (take >= OrderTakeProfit() + 1.0*Point*multiplier)) {
        need_to_adjust=true;
    }

    if (need_to_adjust) {
        bool result = OrderModifyReliable(ticket,OrderOpenPrice(),OrderStopLoss(),take,0,CLR_NONE);
        if (!result) {
            Print("HandleDecayingTPForTrade failed: ticket=",ticket, " hoursOpen=",hoursOpen," fraction=", fraction," take=",take);
        }
    }
}

void HandleDecayingTP()
{
    if (!UseDecayingTakeProfit) {
        return;
    }

    for (int cc = OrdersTotal() - 1; cc >= 0; cc--) {
        if (!SelectOneOfMyOrders(cc)) continue;
        if (IsSelectedOrderOpen()) {
            HandleDecayingTPforTrade(OrderTicket());
        }
    }
}

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))


    int day=TimeDayOfWeek(TimeCurrent()); // notice this is TimeCurrent() not TimeLocal().  Do not trade on Server time==Saturday.
    if (day == 6) {
        ok2Trade=false; // saturday is always out.
    }
    if ((day == 0) && (TimeHour(TimeCurrent())) < 20) {
        ok2Trade=false; // really early on Sunday is also right out.
    }

    return(ok2Trade);

}//bool CheckTradingTimes()

void AddReEntryLine(double price)
{
    if (ObjectFind(reentrylinename) > -1) ObjectDelete(reentrylinename);

    if (!ObjectCreate(reentrylinename,OBJ_HLINE,0,TimeCurrent(),price) ) {
        int err=GetLastErrorReliable();
        Alert("Re-entry line draw failed with error(",err,"): ",ErrorDescription(err));
        Print("Re-entry line draw failed with error(",err,"): ",ErrorDescription(err));
        return(0);

    }//if (!ObjectCreate(reentrylinename,OBJ_HLINE,0,TimeCurrent(),price) )

    ObjectSet(reentrylinename,OBJPROP_COLOR,ReEntryLineColour);
    ObjectSet(reentrylinename,OBJPROP_STYLE,STYLE_SOLID);
    ObjectSet(reentrylinename,OBJPROP_WIDTH,2);
}//void AddReEntryLine(int type, double price)

bool IsTradeAlreadyHedged(int ticket)
{
    for (int cc = OrdersTotal() - 1; cc >=0; cc--) {
        if (SelectOneOfMyOrders(cc)) {
            if (OrderComment() == DoubleToStr(ticket,0)) return(true);
        }
    }//for (int cc = OrdersTotal() - 1; cc >=0; cc--)
    return(false);
}//End bool IsTradeAlreadyHedged(int ticket)

void HedgingModule()
{
    //Called from CountOpenTrades if the trade is losing
    double loss;
    int tn = OrderTicket();
    RefreshRates();

    RsiVal = GetRsi(PERIOD_D1, 20, 0);
    if (RsiVal < 55 && RsiVal > 45) return;

    if (OrderType() == OP_BUY) {
        loss = OrderOpenPrice() - Ask;
        if (loss > (HedgeAtLossPips * Point) ) {
            bool HedgeExists = IsTradeAlreadyHedged(tn);
            OrderSelect(tn, SELECT_BY_TICKET);
            if (HedgeExists) return;
            if (RsiVal > 45) return;
            bool result = SendSingleTrade(OP_SELL, DoubleToStr(tn, 0), OrderLots() * HedgeLotsMiltiplier, Bid, 0, 0, 0);
        }//if (loss > (HedgeAtLossPips * Point)
    }//if (OrderType() == OP_BUY)

    if (OrderType() == OP_SELL) {
        loss = Bid - OrderOpenPrice();
        if (loss > (HedgeAtLossPips * Point) ) {
            HedgeExists = IsTradeAlreadyHedged(tn);
            OrderSelect(tn, SELECT_BY_TICKET);
            if (HedgeExists) return;
            if (RsiVal < 55) return;
            result = SendSingleTrade(OP_BUY, DoubleToStr(tn, 0), OrderLots() * HedgeLotsMiltiplier, Ask, 0, 0, 0);
        }//if (loss > (HedgeAtLossPips * Point)
    }//if (OrderType() == OP_SELL)
}//End void HedgingModule()

double GetRsi(int tf, int period, int shift)
{
    return(iRSI(NULL, tf, period, PRICE_CLOSE, shift) );
}//End double GetRsi(int tf, int period, int shift)


//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
int start()
{

    static double OldBottomGoldLine, OldTopGoldLine;//Keep track of where the sixths were, in case they have moved
    static int OldH1Bars;

    if (UseHedging && OldH1Bars != iBars(NULL, PERIOD_H1) ) {
        RsiVal = GetRsi(PERIOD_D1, 20, 0);
        trend = ranging;
        if (RsiVal > 55) trend = up;
        if (RsiVal < 45) trend = down;
        OldH1Bars = iBars(NULL, PERIOD_H1);
    }//if (UseHedging)

    CountOpenTrades();
    CountPendingTrades();

    //Mop up unwanted duplicate trades and orphaned secondaries
    if (Old5Bars != iBars(NULL, PERIOD_M5) ) {
        Old5Bars = iBars(NULL, PERIOD_M5);
        if (OpenTrades > 0 || PendingPrimary > 0 || PendingSecondary > 0) {
            bool result = CleanUp();
            Sleep(10000);
            if (!result) {
                Old5Bars = 0;
            }//if (!result)
            return;
        }//if (OpenTrades > 0 && Old5Bars != iBars(NULL, PERIOD_M5) )
    }//if (Old5Bars != iBars(NULL, PERIOD_M5) )


    if (OpenTrades == 0) {
        ForcePendingTradeDeletion = false;
        ForceAllTradeDeletion = false;
        PrevOpenTrades = 0;
        GlobalVariableSet(GvName, 0);
        if (ObjectFind(breakevenlinename) > -1) ObjectDelete(breakevenlinename);
        if (ObjectFind(reentrylinename) > -1) ObjectDelete(reentrylinename);
        //if (ObjectFind(takeprofitlinename) > -1) ObjectDelete(takeprofitlinename);
        MostRecentTradePrice=0;
        PrimaryTrades = 0;
        RecoveryInProgress = false;
        HedgingInProgress = false;
    }//if (OpenTrades == 0)

    if (OpenTrades == 0) RecoveryInProgress = false;

    //Recovery
    if (UseRecovery && !HedgingInProgress) {
        if (PrimaryTrades >= Start_Recovery_at_trades) RecoveryInProgress = true;
        if (RecoveryInProgress) {
            if (ObjectFind(takeprofitlinename) > -1) ObjectDelete(takeprofitlinename);
            RecoveryModule();
        }//if (RecoveryInProgress)

        //Replace accidentally deleted be line
        if (RecoveryInProgress && ObjectFind(breakevenlinename) == -1)
            //if (ObjectFind(breakevenlinename) == -1 && OpenTrades > TradeNumber) //DC
        {
            RecoveryModule();
        }//if (ObjectFind(breakevenlinename) == -1 && OpenTrades > 2)
    }//if (UseRecovery)

    if (HedgingInProgress) {
        if (ObjectFind(takeprofitlinename) > -1) ObjectDelete(takeprofitlinename);
        if (BasketUpl >= 0) {
            ForceAllTradeDeletion = true;
            CloseAllTrades();
            return;
        }//if (BasketUpl >= 0)

    }//if (HedgingInProgress)

    //Delete pending orders if a previous attempt failed
    if (ForcePendingTradeDeletion) {
        DeletePendingTrades();
        return;
    }//if (ForcePendingTradeDeletion)

    //Delete open trades if a previous attempt failed
    if (ForceAllTradeDeletion) {
        CloseAllTrades();
        return;
    }//if (ForcePendingTradeDeletion)

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //Trading times
    bool TradeTimeOk = CheckTradingTimes();
    if (!TradeTimeOk) {
        if (PendingTradesTotal > 0) {
            ForcePendingTradeDeletion = true;
            DeletePendingTrades();
        }//if (PendingTradesTotal > 0)

        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)
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    GetSixths();
    ReadjustPendings();
    OldBottomGoldLine = BottomGoldLine;
    OldTopGoldLine = TopGoldLine;

    //Should open trades be closed?
    if (BasketUpl >= 0) LookForTradeClosure();

    HandleDecayingTP();

    //Look for trading opportunities
    if (!StopTrading) {
        CalculateTrades();
    }//if (!StopTrading)

    DisplayUserFeedback();

}

