//Phoenix 6 License information:
//Not Commercial use defined by QPL Open Source License.
//Contact PhoenixFund for Commercial License. Derivative works must also be QPL.
//Unless alternatively licensed by copyright holder, no commercial derivative works may exist.
//+------------------------------------------------------------------+
#property copyright "Copyright PhoenixFund under QPL License. www.bestforextools.com/pf/"

// Constants used in the Signals section

#define Buy                +1
#define Sell               -1
#define None                0

// Constant used in T2_SendTrade for ordersend.

#define Failed             -1

//************* User Variables ******************//
extern string     C_TradeManage              = "===== Trade Management Settings =====";
int        U_maxtrades                = 1;
extern int        P_ConsecSignals            = 10;
bool       U_SignalResetOnBlank        = false;
extern string     U_Trade_CURRENCY           = "USDCHF"; //Currency pair to be traded
extern string     U_Trade_Per             = "M15";  //TimeFrame, use the labels from the MT4 buttons
#define               AcceptSlip                 2
extern int        StaticTP                 = 40;  //Take Profit
extern int        StaticSL                 = 40;  //Stop Loss

extern string     C_Function_Y               = "====== Lotsize Money Management =====";
extern double     U_Lots                     = 1;        //Money management will override setting
double     U_MinLot                   = 0.01;	 //Set to be micro safe by default
extern double     U_MaxLot                   = 90.0;	 //Set to previous max value by default
bool       U_ConfirmSignal1On         = false;  //Will double lotsize if S&R lines near.
extern bool       U_MoneyManage              = true; //Money management for lot sizing
extern double     U_MaxRisk                  = 0.1;     //Percentage of FreeMargin for trade
int        U_DecreaseFactor           = 0;    //6 digit number, 2 digits per subsequent loss 805010= 80% 50% 10%

extern string     C_Function_X1               = "====== Exit Management =====";
extern bool       E_ExitStaticTSOn           = true; //Enable static trailing stops
extern bool       E_ExitParaTSOn             = false; //Enable Parabolic SAR exit - in progress still
extern int        StaticTS                   = 5; //If staticTS is enabled, use this pip value for TS
int         E_MoveTPonTS                =1; //increase Trailing stop by this value in pips each time TS is adjusted. Allows good trades to rise higher
bool        TSConstrictOn               = false; //code currently broken
extern int        E_DelayTS                  = 35; //pips to wait before activating trailing stop
extern int        E_BE_SL                    = 16;  //Pips in profit to enable a Break Even SL
extern int        E_BE_Profit                = 8; //If 0, this sets trade to BE. If a number, this sets the number of pips in profit to lock in
int        E_RecrossMax           =0;      //Not multitrade safe :/ 0 disables setting. Multitrade safe needs an array of ticket numbers?
int recrosscount, bcRecross;
int minStop;                                          //Pulled from broker in init(), minimal TS value

 string     C_Function_X               = "====== Exit Grace Functionality ======";
 int        E_GraceHours         = 0;       //Setting of 0 disables, 24 = 24 hours Daraknor 5.6.6
 int        E_ForceHours         = 0;       //Setting of 0 disables, 48 = 48 hours Darankor 5.6.6
 int        E_GraceTS        = 5;	//Trailing stop in pips to use during Grace Exit: should be small

extern string     C_SignalA                  = "====== Signals Enabled =================";
int        P_signalsRequired          = 3;     //Now calculated on init
extern bool       P_EntrySignal1On           = true; //These settings turn on/off different signals. 
extern bool       P_EntrySignal2On           = true; //  Editing these settings is not necessary or recommended
extern bool       P_EntrySignal3On           = true; //  when Phoenix is being optimized. New strategies require 
extern bool       P_EntrySignal4On           = true; //  changes to the signals that are executed.
extern bool       P_EntrySignal5On           = false;
extern bool       P_EntrySignal6On           = false;

extern bool       P_EntryFilter1On           = true;  //Enabling these settings reduces the number of trades
extern bool       P_EntryFilter2On           = true;
extern bool       P_EntryFilter3On           = true;
extern bool       P_EntryFilter4On           = true;
//extern bool       P_EntryFilter5On           = false;

extern string     C_Signal1                  = "====== Signal 1 Envelope =================";
extern double     P_EnvPerc                  = 0.008;   //Percent 
extern int        P_EnvPer                   = 6;       //Period

extern string     C_Signal2                  = "====== Signal 2 SMA Difference ===========";
extern int        P_SMAPer                   = 5;
extern int        P_SMA2Bars                 = 6;

extern string     C_Signal3                  = "====== Signal 3 OSMA Cross ===============";
extern int        P_OSMAFast                 = 4;
extern int        P_OSMASlow                 = 16;
extern double     P_OSMASignal               = 8;

extern string     C_Signal4                  = "====== Signal 4: Price Divergence ========";
extern int        P_Fast_Per              = 4; 
int        P_Fast_Price               = PRICE_OPEN;
extern int        P_Slow_Per              = 16;
int        P_Slow_Price               = PRICE_OPEN;
extern double     P_DVBuySell                = 1; //only needs 1 decimal at most
extern double     P_DVStayOut                = 8; //only needs 1 decimal at most
double W_DVBuySell;
double W_DVStayOut;

extern string     C_Signal5_6                  = "===== Signal 5 RSI Direction & 6 RSI =====";
extern int        P_RSI_High                 = 80;
extern int        P_RSI_Low                  = 20;
extern int        P_RSI_Per                  = 2;
double W_RSI1, W_RSI2, W_RSI3;   //3 globals saves 6 indicator calls.
int    W_RSIBar, W_ES4_SRBar;
double W_ES4_SR[4]; 

extern string     C_Filter1                  = "====== Filter 1: BBands Channel Detect =====";
extern int        F_ATRShort                    = 5;    //Short term period for consolidation
//int        F_ATRLong                     = 35;   //Long term reference data vs consolidation
                                                 //changed so Long = 7*short
extern double     F_ATR                         = 0.6; //Minimum value to allow trades
                                                 //Code contributed by Wackena
extern string     C_Filter2                  = "====== Filter 2: Allowed Time ==========";
extern double        F_AllAt1                   = 1;    //Defaults will trader 24 hours Mon-Thu
extern double        F_AllTo1                   = 21;   //TODO Support double and min instead of hour int.
extern double        F_AllAt2                   = 24;
extern double        F_AllTo2                   = 24;
extern double        F_SunAt                    = 0;    //Sunday trading is disabled
extern double        F_SunTo                    = 0;
extern double        F_FriAt                    = 0;    //Friday trading ends early
extern double        F_FriTo                    = 16;
extern double        F_MonAt                    = 4;    //Monday without Japanese Open
extern double        F_MonTo                    = 24;
int currentHour; //One global variable saves thousands of CPU cycles.

extern string     C_Filter3_4                = "====== Filter 3&4 Trend ===============";
extern int        U_TrendPer              = 30;
extern int        U_TrendShift               = 5;
extern double     P_TrendStr            = 30;  //Difference in pips between price and MA.

extern string     C_SystemChange             = "====== System Changes =================";
extern bool       U_WriteLog                 = false;
extern bool       U_WriteDebug               = false;
extern string     U_EAComment                = "";
//******************* Global Variables ***************//

#define    MagicNumSet1     101010
int    maxMagic         =  0; //Set size of magic numbers used

bool   Chain2EntryOn    =  false;
bool   W_GreenLight     =  true;
string W_Trade_Per;
int    nDaysSince1970   =  0;
int    LogHandle        = -1;

int    BuySignalCount;
int    SellSignalCount;

 

//----------------------  INIT  --------------------

void init()
  { //Startup Functions, only called once.
    if((Symbol() != U_Trade_CURRENCY) && (Symbol() != U_Trade_CURRENCY+"m"))
      {
        Alert("These settings are designed for "+U_Trade_CURRENCY+
              " only! Change chart or update U_Trade_CURRENCY"    );

        W_GreenLight=false;
      }

    if(U_MaxLot >MarketInfo(Symbol(),MODE_MAXLOT)) U_MaxLot=MarketInfo(Symbol(),MODE_MAXLOT);
    if(U_MinLot >MarketInfo(Symbol(),MODE_MINLOT)) U_MaxLot=MarketInfo(Symbol(),MODE_MINLOT);

    switch(Period())
      {
        case 1:
          W_Trade_Per="M1";     break;
        case 5:
          W_Trade_Per="M5";     break;
        case 15:
          W_Trade_Per="M15";    break;
        case 30:
          W_Trade_Per="M30";    break;
        case 60:
          W_Trade_Per="H1";     break;
        case 240:
          W_Trade_Per="H4";     break;
        case 1440:
          W_Trade_Per="D1";     break;
        case 10080:
          W_Trade_Per="W1";     break;
        case 43200:
          W_Trade_Per="MN";    break;
        default:
          Alert("Your timeframe "+Period()+" was not detected.");
          W_Trade_Per="";
       }

    if(U_Trade_Per != W_Trade_Per)
      {
        Alert("These settings are designed for "+U_Trade_Per+
          " only! Change chart or update U_Trade_Per");
        W_GreenLight=false;
      }   
    //Initial Settings:

//    W_DVBuySell = P_DVBuySell*Point;
//    W_DVStayOut = P_DVStayOut*Point;
    W_DVBuySell = P_DVBuySell;
    W_DVStayOut = P_DVStayOut;
    //TODO starting balance for complex money management.
    P_signalsRequired=P_EntrySignal1On+P_EntrySignal2On+P_EntrySignal3On+P_EntrySignal4On+P_EntrySignal5On+P_EntrySignal6On;

    minStop=MarketInfo(Symbol(),MODE_STOPLEVEL);
    if(E_BE_SL<E_BE_Profit+minStop) 
      E_BE_Profit=E_BE_SL-minStop;
      
    if(F_AllAt1>F_AllTo1) { Alert("F_AllAt1>F_AllTo1"); W_GreenLight = false; }
    if(F_AllAt2>F_AllTo2) { Alert("F_AllAt2>F_AllTo2"); W_GreenLight = false; }
    if(F_AllTo1>F_AllAt2) { Alert("F_AllTo1>=F_AllAt2"); W_GreenLight = false; }
    if(F_SunAt>F_SunTo) { Alert("F_SunAt>F_SunTo"); W_GreenLight = false; }
    if(F_FriAt>F_FriTo) { Alert("F_FriAt>F_FriTo"); W_GreenLight = false; }
    if(F_MonAt>F_MonTo) { Alert("F_MonAt>F_MonTo"); W_GreenLight = false; }
    //F_ATRLong=7*F_ATRShort; //Filter 1, autoconfigure
}
  

//----------------------  START  --------------------

void start()
  {
    if(W_GreenLight == false)
      return(0);
    L1_OpenLogFile("MyLog.txt");
    int ordercount;

    //*************** Detect open trades *********************//
    for (int cticket = 0; cticket < OrdersTotal(); cticket++) 
      {
       if (OrderSelect(cticket, SELECT_BY_POS) == false)
         continue;

       if (OrderSymbol() != Symbol())
         continue;

       if (OrderMagicNumber() >= MagicNumSet1 && OrderMagicNumber() <= MagicNumSet1 + maxMagic)
         {
           X1_ManageExit(OrderTicket());
           ordercount++;

      //  PContour - removed the following lines in favour of condensed order management.
      //     if      (OrderType() == OP_BUY)   X1_ManageExit(OrderTicket()); //Buy
      //     else if (OrderType() == OP_SELL)  X1_ManageExit(OrderTicket()); //Sell
         }
      }
    if ( ordercount < U_maxtrades) A1_OpenTrade_If_Signal();
    L9_FlushLog();
  } //End Start() 

//********************* Check for New Trade *******************//

void A1_OpenTrade_If_Signal()
  { //Check singals and conditions to enter new trade
    int  signalCount;
    bool enableBuy= true;
    bool enableSell=true;

//EntryFilters enable or disable trading, while EntrySignals generate "buy" or "sell"
//EntryFilter should return "false" if trading is still enabled.    
    if (P_EntryFilter1On) //Changed filters to quit ASAP.
      if (Z_F1_BlockTradingFilter1()) return;

    if (P_EntryFilter2On)
      if (Z_F2_BlockTradingFilter2()) return;

    if (P_EntryFilter3On)
      if (Z_F3_BlockTradingFilter3()) { enableBuy=false; BuySignalCount=0; }

    if (P_EntryFilter4On)
      if (Z_F4_BlockTradingFilter4()) { enableSell=false; SellSignalCount=0; }

//    if (P_EntryFilter5On)
//      if (Z_F5_BlockTradingFilter5()) return;

    //Check all the EntrySignals for Buy=1 or Sell=-1 values. See constants at top of file.

    if (P_EntrySignal1On)
      {
        signalCount += Z_S1_EntrySignal1();    
        if(U_WriteDebug) L3_WriteDebug("Signal1 sum: "+signalCount);
      }
    if (P_EntrySignal2On)
      {
        signalCount += Z_S2_EntrySignal2();    
        if(U_WriteDebug) L3_WriteDebug("Signal2 sum: "+signalCount);
      }
    if (P_EntrySignal3On)
      {
        signalCount += Z_S3_EntrySignal3();    
        if(U_WriteDebug) L3_WriteDebug("Signal3 sum: "+signalCount);
      }
    if (P_EntrySignal4On)
      {
        signalCount += Z_S4_EntrySignal4();    
        if(U_WriteDebug) L3_WriteDebug("Signal4 sum: "+signalCount);
      }
    if (P_EntrySignal5On)
      {
        signalCount += Z_S5_EntrySignal5();    
        if(U_WriteDebug) L3_WriteDebug("Signal5 sum: "+signalCount);
      }
    if (P_EntrySignal6On)
      {
        signalCount += Z_S6_EntrySignal6();    
        if(U_WriteDebug) L3_WriteDebug("Signal5 sum: "+signalCount);
      }
    // Counting up the number of buy or sell signals that happen consecutively.  
    if(enableBuy)
      if(signalCount >= P_signalsRequired) 
        { //Check for Buy
          BuySignalCount++;
          SellSignalCount=0;
        }   
    if(enableSell)
      if(signalCount <= (-1)*P_signalsRequired)
        {
          BuySignalCount=0;
          SellSignalCount++;
        }
    if(U_SignalResetOnBlank)
       if(  (signalCount <= (-1)*P_signalsRequired) && (signalCount >= P_signalsRequired))
         {//If neither buy nor sell signal is received
           BuySignalCount =0;
           SellSignalCount=0;
         }
    if(U_WriteLog) L2_WriteLog("signal#:"+signalCount+" P_ConsecSignals:" +P_ConsecSignals+" BuySignalCount:" +BuySignalCount+" SellSignalCount:"+ SellSignalCount);
     // If the BuySignalCount or SellSignalCount exceeds the P_ConsecSignals required
     // then the Buy order or Sell order will be submitted.
    if(P_ConsecSignals <= BuySignalCount)
      {
        A1_1_OrderNewBuy(M1_MM_OptimizeLotSize()*A1_3_EntryConfirmation(OP_BUY));
        BuySignalCount   =0;
        recrosscount=0; //reset recross count for new trade.
      }
    else if(P_ConsecSignals <= SellSignalCount)
      {
        A1_2_OrderNewSell(M1_MM_OptimizeLotSize()*A1_3_EntryConfirmation(OP_SELL));
        SellSignalCount  =0;
        recrosscount=0; //reset recross count for new trade.
      }
  }

  
void A1_1_OrderNewBuy(double lots)  //Trade TP+SL Signals
  { 
    T2_SendTrade(StaticTP, StaticSL, lots, OP_BUY);
  }

void A1_2_OrderNewSell(double lots)   //Trade TP+SL Signals
  { 
    T2_SendTrade(StaticTP, StaticSL, lots, OP_SELL);
  }





double A1_3_EntryConfirmation(int direction)
{ //Gann Style Support and Resist Lines.
   if(!U_ConfirmSignal1On) return (1.0);
   double value=1;
   if(W_ES4_SRBar>iBars(Symbol(),PERIOD_H4))
   {
      W_ES4_SRBar=iBars(Symbol(),PERIOD_H4);
      W_ES4_SR[4]=iHigh(Symbol(),PERIOD_H4,1);
      W_ES4_SR[0]=iLow(Symbol(),PERIOD_H4,1);
      if(W_ES4_SR[4]-W_ES4_SR[0]<(StaticTP+StaticSL)*Point)
      {
         W_ES4_SR[4]=iHigh(Symbol(),PERIOD_D1,1);
         W_ES4_SR[0]=iLow(Symbol(),PERIOD_D1,1);
      }
      W_ES4_SR[3]=(W_ES4_SR[0]+W_ES4_SR[4])*0.75;
      W_ES4_SR[2]=(W_ES4_SR[0]+W_ES4_SR[4])*0.5;
      W_ES4_SR[1]=(W_ES4_SR[0]+W_ES4_SR[4])*0.25;
   }
   int next=ArrayBsearch(W_ES4_SR,Bid);
   if(direction==OP_SELL) 
   {
      if(Bid+StaticSL*Point>W_ES4_SR[next]) value=2;
   }
   if(direction==OP_BUY) 
   {
      if(next !=0)//safe array
      { 
         if(Bid-StaticSL*Point<W_ES4_SR[next-1]) value=2; 
      }
      else value=1;
   }
   return (value);  
}

/*double EntryConfirmation2()
{ //TODO Speed Angle Check
return(1.0);
}
*/

/*double EntryConfirmation3()
{ //TODO 4-7 Rule
return(1.0);
}
*/

//********************* Money Management *****************//

double M1_MM_OptimizeLotSize()
  {
    if(!U_MoneyManage)
      return(U_Lots);

    double lots         =U_Lots;
    int    orders       =HistoryTotal();
    int    i            =orders-1;
    int    trades       =0;
    int    wins         =0;
    int    losses       =0;
    double lotStep=MarketInfo(Symbol(),MODE_LOTSTEP);

    //if(U_WriteLog) L2_WriteLog("ALERT lotstep from broker is "+lotStep);

    //if(lotStep==0) lotStep =.0001; //TODO Safety feature... need to debug this better.

    lots=AccountFreeMargin()*U_MaxRisk/1000.0;
    
    if(U_DecreaseFactor > 256)    //need to check for a real value
      { 
        while (trades< 3 && i > 0)
          {
            if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)
              {
                if(U_WriteLog) L2_WriteLog("Error in history!");
                break;
              }
            if(OrderSymbol()==Symbol() && OrderType()<=OP_SELL)
              {
                trades++;
                if(OrderProfit()<0) losses++;
                if(OrderProfit()>0) wins++;
              }
            i--;
          }
       if (U_DecreaseFactor > 999999)
         {
           if(U_WriteLog) L2_WriteLog("U_DecreaseFactor too large.  Changed to 902005");
           U_DecreaseFactor = 902005;
         }

       int Loss1_Percentage =  U_DecreaseFactor * 0.0001;
       int Loss2_Percentage = (U_DecreaseFactor - 10000 * Loss1_Percentage) * 0.01;
       int Loss3_Percentage = (U_DecreaseFactor - 10000 * Loss1_Percentage
                                                -   100 * Loss2_Percentage);
                                                
       if(U_WriteLog) L2_WriteLog("Decrease Factors "+Loss1_Percentage+" "+Loss2_Percentage+" "+Loss3_Percentage) ;

//     if (losses==0){ lots=lots*100             *0.01;   }  //This line is just documentation
       if (losses==1){ lots=lots*Loss1_Percentage*0.01;   }
       if (losses==2){ lots=lots*Loss2_Percentage*0.01;   }
       if (losses>=3){ lots=lots*Loss3_Percentage*0.01;   }
       if(U_WriteLog) L2_WriteLog("  losses "+losses+"  lots "+lots);
      }

    if(lots<U_MinLot) { lots=U_MinLot; if(U_WriteLog) L2_WriteLog("lots switched to min "+lots); }
    if(lots>U_MaxLot) { lots=U_MaxLot; if(U_WriteLog) L2_WriteLog("lots switched to max "+lots); }

    lots /=lotStep;
    lots  = NormalizeDouble(lots,0);
    lots *= lotStep;

    return(lots);
  }

int T2_SendTrade(int TP, int SL, double lot, int order, int incMagic = 0)  //Execute Trades
  { 

    double price;
    color  arrow;
    int    ticket;

    string tradecomment= U_EAComment + " P6B T"+ incMagic;

    if (order %2==OP_BUY)
      { //if number is even
        price =  Ask;
        arrow =  Blue;
      }

    if (order %2==OP_SELL)
      { //if number is odd
        price =  Bid;
        SL    = -SL;
        TP    = -TP;
        arrow =  Red;
      }
  //ticket = OrderSend(Symbol(),OP_BUY,1,Ask,3,Ask-25*Point,Ask+25*Point,"My order #2",16384,0,Green);
    ticket = OrderSend( Symbol(),
                        order,
                        lot,
                        price,
                        AcceptSlip,
                        price-SL*Point,
                        price+TP*Point,
                        tradecomment,
                        MagicNumSet1 + incMagic,
                        0, 
                        arrow );

    if (ticket != Failed)
      {
        if(U_WriteLog) L2_WriteLog("Success:"+ticket+" "+Symbol()+" order:"+order+" lot:"+lot+" price:"+price+" SL:"+(price-SL*Point)+" TP:"+(price+TP*Point));
        return (ticket); //TODO use ticket number somehow
      } 
    else
      {
        int error=GetLastError();
        if(U_WriteLog) L2_WriteLog("Error:"+error+" "+Symbol()+" order:"+order+" lot:"+lot+" price:"+price+" SL:"+(price-SL*Point)+" TP:"+(price+TP*Point));

    if(error==129 || error==130 || error==135 || error==138)
          { //Handle a few errors we know about, usually price movement. TODO make this configurable.
            RefreshRates();

            ticket = OrderSend( Symbol(), 
                                order, 
                                lot, 
                                price, 
                                AcceptSlip,
                                price - SL * Point,
                                price + TP * Point, 
                                tradecomment,
                                MagicNumSet1 + incMagic,
                                0, 
                                arrow );

            if (ticket != Failed) 
              return (ticket); //TODO use ticket number somehow
            else 
              if(U_WriteLog) L2_WriteLog("Error: Order send failed twice. Quitting."+ GetLastError());
          }
    if(error==4 || error==136 || error==137 ||error==146)
          { //Busy Errors, sleep a little then retry
            Sleep(2000);
            RefreshRates();
            ticket = OrderSend( Symbol(), 
                                order, 
                                lot, 
                                price, 
                                AcceptSlip,
                                price - SL * Point,
                                price + TP * Point, 
                                tradecomment,
                                MagicNumSet1 + incMagic,
                                0, 
                                arrow );

            if (ticket != Failed) 
              return (ticket); //TODO use ticket number somehow
            else 
              if(U_WriteLog) L2_WriteLog("Error: Order send failed twice. Quitting."+ GetLastError());
          }
      }
  }
  
//**********  Exit Strategies & Trailing Stops **********************************//
void X1_ManageExit(int myticket)
{ //Contains all of the exit strategies and trade management routines. Listed in priority.
    minStop=MarketInfo(Symbol(),MODE_STOPLEVEL); //updated every tick in case of news SL movement
  
    if(E_GraceHours !=0 ||E_ForceHours !=0) 
      X1_ForceClose_or_GraceModify(myticket);
  
    if(E_RecrossMax!=0)
      {
        double price;
          if (OrderType() == OP_BUY)   price=Bid;
          if (OrderType() == OP_SELL)  price=Ask;
          if(Bars>bcRecross)
            { //Bar hasn't been counted yet
              if(OrderOpenPrice()>price-1 && OrderOpenPrice()<price+1)
                {
                  recrosscount++;
                  bcRecross=Bars;

                  if (recrosscount>=E_RecrossMax)
                     if(!OrderClose(myticket,OrderLots(),price,AcceptSlip,Red)) 
                       L4_WriteError();
                }
              }
    
      }
  //TODO StealthExit  
  if(E_BE_SL!=0)
  {  //    BreakEven SL @target
    if(E_BE_SL<E_BE_Profit+minStop) E_BE_Profit=E_BE_SL-minStop; //keeps trade safe all of the time
    if(Bid-OrderOpenPrice()>Point*E_BE_Profit && (OrderStopLoss()< OrderOpenPrice()+E_BE_Profit*Point))
    {
      if (OrderType() == OP_BUY)
        X9_ModifySL(OrderOpenPrice()+E_BE_Profit*Point,myticket); 
      if (OrderType() == OP_SELL)
        X9_ModifySL(OrderOpenPrice()-E_BE_Profit*Point,myticket); 
    } 
  }
  if (E_ExitParaTSOn) 
  {
    double paraSAR=iSAR(NULL,0,0.02,0.2,1);
  //      if(U_WriteDebug) L3_WriteDebug("ParaTS: "+paraSAR+" TP"+OrderTakeProfit()+" SL"+OrderStopLoss()+" Bid"+Bid);
    if(OrderType() == OP_BUY)
      if(paraSAR<Bid && OrderProfit()>0) 
        OrderClose(OrderTicket(),OrderLots(),Bid,AcceptSlip,Red);
        //X9_ModifyTrailingStop(myticket,minStop,0);
    if(OrderType() == OP_SELL)
      if(paraSAR>Ask && OrderProfit()>0) 
        OrderClose(OrderTicket(),OrderLots(),Ask,AcceptSlip,Red);
  } 
  else if (E_ExitStaticTSOn) 
  {
    X9_ModifyTrailingStop(myticket,StaticTS,E_DelayTS);
  }
}


void X1_ForceClose_or_GraceModify(int ticket)   //contrib by HerbertH in original Phoenix 2007 thread.
  {  
    int    PerForce = E_ForceHours*3600;
    int    PerGrace = E_GraceHours*3600;
    double newSL       =0;

    OrderSelect(ticket, SELECT_BY_POS, MODE_TRADES); //TODO verify this line is redundant and unnecessary

    if (PerForce!=0)
      {
      if((OrderOpenTime() + PerForce) < Time[0])
         {
         if(OrderType() == OP_BUY)  OrderClose(OrderTicket(),OrderLots(),Bid,3,Red); //3 points slippage allowed?
         if(OrderType() == OP_SELL) OrderClose(OrderTicket(),OrderLots(),Ask,3,Red);
         }
      }

    if(PerGrace!=0)
      {
        if(OrderOpenTime() + PerGrace < Time[0])
          {
            X9_ModifyTrailingStop(ticket, E_GraceTS,-1000);  // -1000=No profit delay on TS with PerGrace
          }
      }
   }

void X9_ModifyTrailingStop(int ticket, int tsvalue, int delayts)
  {
    double slvalue;
    if(tsvalue>=minStop) //check minimal value allowed by broker
      {        //TODO decrease tsvalue to make constricting difference between TP and SL.
        if(TSConstrictOn)
        { //Code currently broken
          if(OrderProfit()>0)
            tsvalue=((OrderTakeProfit()-OrderStopLoss())/Point)*0.5;
          if(tsvalue<minStop)
            tsvalue=minStop;
        }
      } 
    else 
      { //Set safe value
        tsvalue=minStop;
      }
    if(U_WriteDebug) L3_WriteDebug("EXIT:TS ticket:"+ticket+" tsvalue:"+tsvalue+" delayts:"+delayts);

    if      (OrderType() == OP_BUY)
      {
        slvalue=Bid-(Point*tsvalue);
        if (OrderStopLoss() < slvalue && OrderOpenPrice()+Point*delayts<Bid+tsvalue*Point)
        {
          //if(U_WriteDebug) L3_WriteDebug("OrderSL:" +OrderStopLoss()+ " slvalue:"+ slvalue);
          if(!X9_ModifySL(slvalue,ticket))
          {
            L4_WriteError();
            L3_WriteDebug("ERROR OrderSL:" +OrderStopLoss()+ " slvalue:"+ slvalue);
          }
        }
      } 
    else if (OrderType() == OP_SELL)
      {
        slvalue=Ask+(Point*tsvalue);
        if (OrderStopLoss() > slvalue && OrderOpenPrice()-Point*delayts>Ask-tsvalue*Point)
        {
          //if(U_WriteDebug) L3_WriteDebug("OrderSL:" +OrderStopLoss()+ " slvalue:"+ slvalue);
          if(!X9_ModifySL(slvalue,ticket))
          {
            L4_WriteError();
            L3_WriteDebug("ERROR OrderSL:" +OrderStopLoss()+ " slvalue:"+ slvalue);
          }
        }
      }
  }

bool X9_ModifySL(double sl, int ticket)
  {
    double MoveTP;
    if(E_MoveTPonTS !=0)
    {
      if (OrderType() == OP_SELL) 
      {
        MoveTP=E_MoveTPonTS*(-1)*Point;
        if(Ask-OrderTakeProfit()+MoveTP<minStop*Point) 
          MoveTP=minStop*Point*(-1) -OrderTakeProfit(); //Set the new distance to minimum safe point, -OTP() cancels OTP()
      }
      else 
      {
        MoveTP=E_MoveTPonTS*Point;
        if(OrderTakeProfit()-Bid+MoveTP<minStop*Point) 
          MoveTP=minStop*Point -OrderTakeProfit();  //Set the new distance to minimum safe point, -OTP() cancels OTP()
      }
    }
    
    if(U_WriteDebug) L3_WriteDebug("MODIFY Ticket:"+ticket+" OpenPrice:"+OrderOpenPrice()+" SL:"+sl+" TP:"+(OrderTakeProfit()+MoveTP*Point));
    if(OrderModify ( ticket, OrderOpenPrice(), sl,
                      OrderTakeProfit()+MoveTP,
                      0, Red) ==(-1)) 
        return(false);
    else return(true);
  }


//********************** SIGNALS *********************//
int Z_S1_EntrySignal1()
  { //Envelope Filter
    int Signal=None;

    double HighEnvelope1 = iEnvelopes(NULL,0,P_EnvPer,MODE_SMA,0,PRICE_CLOSE,P_EnvPerc,MODE_UPPER,1);
    double LowEnvelope1  = iEnvelopes(NULL,0,P_EnvPer,MODE_SMA,0,PRICE_CLOSE,P_EnvPerc,MODE_LOWER,1);
    double CloseBar1     = iClose(NULL,0,1);

    if(CloseBar1 > HighEnvelope1) {Signal=Sell;}
    if(CloseBar1 < LowEnvelope1)  {Signal=Buy; }

    if(U_WriteDebug) L3_WriteDebug("Signal 1 "+Signal+" HighEnv:"+HighEnvelope1+" LowEnv:"+LowEnvelope1+" Close:"+CloseBar1);

    return (Signal);
  }

int Z_S2_EntrySignal2()
  { //SMA Difference
    int Signal=None;

    double SMA1=iMA(NULL,0,P_SMAPer,0,MODE_SMA,PRICE_CLOSE,1);
    double SMA2=iMA(NULL,0,P_SMAPer,0,MODE_SMA,PRICE_CLOSE,P_SMA2Bars);

    if (SMA2>SMA1 ) Signal=Buy;
    else            Signal=Sell;

    if(U_WriteDebug) L3_WriteDebug("Signal2 "+Signal+" SMA Diff:"+(SMA2-SMA1)+" SMA2:"+SMA2+" SMA1:"+SMA1);

    return (Signal);
  }


int Z_S3_EntrySignal3()
  { //OSMA Cross
    int Signal=None;

    double OsMABar2=iOsMA(NULL,0,P_OSMAFast,P_OSMASlow,P_OSMASignal,PRICE_CLOSE,2);
    double OsMABar1=iOsMA(NULL,0,P_OSMAFast,P_OSMASlow,P_OSMASignal,PRICE_CLOSE,1);

    if (OsMABar2>OsMABar1) Signal=Buy;
    else                   Signal=Sell;

    if(U_WriteDebug) L3_WriteDebug("Signal3 "+Signal+" OsMA Diff:"+(OsMABar2-OsMABar1)+" OsMABar2:"+OsMABar2+" OsMABar1:"+OsMABar1);

    return (Signal);
  }

int Z_S4_EntrySignal4()
  { //Divergence Trading Signal
    int Signal;  
    double diverge = ZZ_F1_Divergence(P_Fast_Per, P_Slow_Per, P_Fast_Price, P_Slow_Price,0);
    if(diverge >= W_DVBuySell && diverge <= W_DVStayOut) Signal=Buy;
    else if(diverge <= (W_DVBuySell*(-1)) && diverge >= (W_DVStayOut*(-1))) Signal=Sell;
    if(U_WriteDebug) L3_WriteDebug("Signal4 "+Signal+" diverge:"+diverge+" W_DVBuySell:"+W_DVBuySell+" W_DVStayOut:"+W_DVStayOut);
    return (Signal);  
  }

int Z_S5_EntrySignal5()
  { 
   int value=0;
   if(W_RSIBar<Bars)
   {  //This should be based on bars, reduces check to once every bar.
      W_RSIBar=Bars;
      W_RSI3=W_RSI2; //This reduces computation to 1/3
      W_RSI2=W_RSI1;
      W_RSI1 = iRSI(NULL, Period(), P_RSI_Per, PRICE_CLOSE, 1);
   }
   if (W_RSI1 < P_RSI_High)      //Save CPU cycles with quick filters
    { if(W_RSI2 < W_RSI1 && W_RSI3 < W_RSI2) value=Buy; } 
   else if (W_RSI1 > P_RSI_Low)  //only one set needs to be checked, and not always.  
      if(W_RSI2 > W_RSI1 && W_RSI3 > W_RSI2) value=Sell;
   if(U_WriteDebug) L3_WriteDebug("SignalRSI: "+value+" W_RSI1:"+W_RSI1+" W_RSI2:"+W_RSI2+" W_RSI3:"+W_RSI3);
   return(value);
  }
  
int Z_S6_EntrySignal6()
  { 
   int value=0;
   double w_RSI = iRSI(NULL, Period(), P_RSI_Per, PRICE_CLOSE, 1);
   if (w_RSI < P_RSI_High)      //Save CPU cycles with quick filters
      value=Buy;
   else if (w_RSI > P_RSI_Low)  //only one set needs to be checked, and not always.  
      value=Sell;
   if(U_WriteDebug) L3_WriteDebug("SignalRSI: "+value+" w_RSI:"+w_RSI);
   return(value);
  }
  
bool Z_F1_BlockTradingFilter1()
{   //Original code Contributed by Wackena
  bool BlockTrade=false;  //trade by default
  double w_ATR;
  double dAtrShort = iATR(NULL, 0, F_ATRShort, 0);
  //double dAtrLong = iATR(NULL, 0, F_ATRLong, 0);
  //if(dAtrLong != 0) w_ATR = dAtrShort / dAtrLong; 
  //if(w_ATR<F_ATR)BlockTrade=true;
  if(dAtrShort<F_ATR)BlockTrade=true;
  return (BlockTrade); 
}

bool Z_F2_BlockTradingFilter2()   
  { //Time Expiry
    bool BlockTrade=true;  //only trade during permitted hours
    
//    if(TimeHour(TimeCurrent())!=currentHour)
//    {
      currentHour=TimeHour(TimeCurrent());    //one global variable saves thousands of CPU cycles

      if(TimeDayOfWeek(Time[0])==0)  //Sunday
        {
          if(currentHour>=F_SunAt && currentHour<F_SunTo)    BlockTrade=false;
        }
      else if(TimeDayOfWeek(Time[0])==5)  //Friday
        {
          //if(U_WriteDebug) L3_WriteDebug("Today is Friday:"+currentHour);
          if(currentHour>=F_FriAt && currentHour<F_FriTo)    BlockTrade=false;
        }
      else if(TimeDayOfWeek(Time[0])==1)  //Monday
        {
          //if(U_WriteDebug) L3_WriteDebug("Today is Friday:"+currentHour);
          if(currentHour>=F_MonAt && currentHour<F_MonTo)    BlockTrade=false;
        }
      else if((currentHour>=F_AllAt1 && currentHour<F_AllTo1) ||
      (currentHour>=F_AllAt2 && currentHour<F_AllTo2)) BlockTrade=false;
//    }
    return (BlockTrade);
  }
  
bool Z_F3_BlockTradingFilter3()   //if BUY Signal, check buy trend. True = quit.
  {
    bool BlockTrade=false;
  
    double TrendB=iMA(NULL,0,U_TrendPer,U_TrendShift,MODE_LWMA,PRICE_MEDIAN,0)-High[1];

    if(P_TrendStr*Point<TrendB)
      {
        BlockTrade=true;
        if(U_WriteDebug) L3_WriteDebug("EntryFilter3 TrendMA:"+TrendB+" Buy="+BlockTrade+" Buy Allowed");
      }
    else
      { 
        if(U_WriteDebug) L3_WriteDebug("EntryFilter3 TrendMA:"+TrendB+" Buy="+BlockTrade+" Buy DisAllowed");
      }

    return(BlockTrade);
  }
  
bool Z_F4_BlockTradingFilter4()
  {
    //if SELL Signal, check sell trend
    //Currently assuming that rising and falling trends have similar properties.
    bool BlockTrade=false;
    
    double TrendS=Low[1]-iMA(NULL,0,U_TrendPer,U_TrendShift,MODE_LWMA,PRICE_MEDIAN,0);
    
    if(P_TrendStr*Point<TrendS) 
      {
        BlockTrade=true;
        if(U_WriteDebug) L3_WriteDebug("EntryFilter4 TrendMA:"+TrendS+" Sell="+BlockTrade+" Sell DisAllowed");
      }
    else
      {
        if(U_WriteDebug) L3_WriteDebug("EntryFilter4 TrendMA:"+TrendS+" Sell="+BlockTrade+" Sell Allowed");
      }

    return(BlockTrade);
  }

//bool Z_F5_BlockTradingFilter5()   //TODO S&R
//  { 
//    return (false);  //trade by default
//  }

//********************** Signal Functions ******************//

double ZZ_F1_Divergence(int F_Per, int S_Per, int F_Price, int S_Price, int mypos)
  {
    int i;
    double maF2 = iMA(Symbol(), 0, F_Per, 0, MODE_SMA, F_Price, mypos + 1);
    double maS2 = iMA(Symbol(), 0, S_Per, 0, MODE_SMA, S_Price, mypos + 1);

    return((maF2-maS2)/Point);
  }

//*********************** LOGGING **************************//
void L1_OpenLogFile(string strName)
  {
    if (!U_WriteLog && !U_WriteDebug)
      return;

    if (TimeCurrent() / (60 * 60 * 24) > nDaysSince1970 || LogHandle <= 0) 
      { //Pick a new filename and open it.
        if (LogHandle > 0) 
          FileClose(LogHandle);

        string            strMonthPad = "" ;
        if (Month() < 10) strMonthPad = "0";

        string            strDayPad   = "" ;
        if (Day()   < 10) strDayPad   = "0";

        string strFilename = StringConcatenate(strName, "_", Year(),
                                               strMonthPad, Month(),
                                               strDayPad,     Day(), "_log.txt");

        LogHandle =FileOpen(strFilename, FILE_CSV | FILE_READ | FILE_WRITE);

        nDaysSince1970 = TimeCurrent() / (60 * 60 * 24);
      }

    FileFlush(LogHandle);
    FileSeek(LogHandle, 0, SEEK_END);
  }


void L2_WriteLog(string msg)
  {
    if (!U_WriteLog) return;
    if (LogHandle <= 0)   return;

    msg = TimeToStr(TimeCurrent(), TIME_DATE | TIME_MINUTES | TIME_SECONDS) + " " + msg;
    FileWrite(LogHandle, msg);
  }

void L3_WriteDebug(string msg)  //Signal Debugging, rarely called
  {
//    if (!U_WriteDebug) return;
    if (LogHandle <= 0)       return;

    msg = TimeToStr(TimeCurrent(), TIME_DATE | TIME_MINUTES | TIME_SECONDS) + " " + msg;
    FileWrite(LogHandle, msg);
  }

void L4_WriteError()
  {
    if (!U_WriteLog) return;
    if (LogHandle <= 0)   return;

    string msg="Error:"+ GetLastError()+" OrderType:"+OrderType()+" Ticket:"+OrderTicket();

    msg = TimeToStr(TimeCurrent(), TIME_DATE | TIME_MINUTES | TIME_SECONDS) + " " + msg;
    FileWrite(LogHandle, msg);
  }

void L9_FlushLog()
  {
    if (!U_WriteLog) return;

    FileFlush(LogHandle);
  }

//End Of File