//+-------------------------------------------------------------------+
//|                                                                   |
//|  http://www.forexfactory.com/showthread.php?p=9226096#post9226096 |
//|  http://www.forexfactory.com/mdswamp                              |
//|                                                                   |
//+-------------------------------------------------------------------+

#property copyright   "2016 - 2017, mdswamp"
#property link        "http://www.forexfactory.com/mdswamp"
#property strict      // property strict is the programmer's friend.
#include <stdlib.mqh>
const int MagicNum = 77;
     //Trailing Stop {{{
extern double     BreakEven          = 45;     // Profit Lock in pips
extern double     ModifiedStop       = 15;     // Profit Lock in pips  
     //Trailing Stop }}}
extern double     TP            = 75;          // Profit Lock in pips
extern double     SL            = 105;         // Profit Lock in pips  
input double TradePercentage    = 0.05;
input double DecreaseFactor     = 1;
input int    TradeingBar        = 2;           // 2 is the second bar after midnight.
input ENUM_TIMEFRAMES TimeFrame = PERIOD_H1;   // PERIOD_M1 PERIOD_M5 PERIOD_M15 PERIOD_M30 PERIOD_H1 PERIOD_H4 PERIOD_D1
//
double LMB;
double LMS;
//--- EA Helper Values ----------
int pointsInPip = 1;
double modifiedStopPoints;
double TPPoints, SLPoints;
//+------------------------------------------------------------------+
//| expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
 {
   int initStatus = INIT_SUCCEEDED;
   //
   EventSetTimer(1);                   // create timer events / set frequency of timer events in seconds
   //
   if( (Bars<100) || (IsTradeAllowed()==false) )
    {
      initStatus = INIT_FAILED;
    }
   //
   if( (Digits == 3) || (Digits == 5) )
    {
      pointsInPip = 10;
    }
   modifiedStopPoints = ModifiedStop*(Point*pointsInPip);
   TPPoints           = TP*(Point*pointsInPip);
   SLPoints           = SL*(Point*pointsInPip);
   Print("ModifiedStopPoints: ",DoubleToStr(modifiedStopPoints,Digits),", TPPoints: ",DoubleToStr(TPPoints,Digits),", SLPoints: ",DoubleToStr(SLPoints,Digits));
   //
   return(initStatus);
 }
//
//+------------------------------------------------------------------+
//| expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
 {
   EventKillTimer();                    // Clean up on Exit
   Comment("");
 }
//
//+------------------------------------------------------------------+
//| expert timer function                                            |
//+------------------------------------------------------------------+
void OnTimer()  //timer should be every minute to coincide with the creation of new bars
 {
   /*
   if( ThereIsANewBarAfterMidnight(TradeingBar, TimeFrame) )
    {
      PerformOrderProcessing();
    }
   */
 }
//
//+------------------------------------------------------------------+
//| expert start function                                            |
//+------------------------------------------------------------------+
void OnTick()
 {
   
   if( ThereIsANewBarAfterMidnight(TradeingBar, TimeFrame) )
    {
      PerformOrderProcessing();
    }
   
 }
//
bool ThereIsANewBarAfterMidnight(const int barNum, ENUM_TIMEFRAMES barPeriod )
 {  // iTime( symbol, timeframe, shift );
   bool newBar = false;
   datetime currentDayBar = iTime( Symbol(), PERIOD_D1, 0 );  // Today's Bar Time (current Year, Month and Day.  Minute and Second are 00 on the Day Bar
   datetime currentBarTime = iTime( Symbol(), barPeriod, 0 );
   if( (barPeriod < PERIOD_D1) && (PERIOD_D1 > (barNum*barPeriod)) )  // Only need 2nd part of this statement
    {
      if( ((barNum*barPeriod*60)+currentDayBar) == currentBarTime )  // Is this the bar that should be traded on?
       {
         newBar = true;
       }
    }
   else if (barPeriod >= PERIOD_D1)  // Always trade on bars larger than D1
    {
      newBar = true;
    }
   return( newBar );
 }
//
void PerformOrderProcessing(void)
 {
   if(ProcessOpenPositions(Symbol())==0)  //--- calculate open orders by current symbol
    {
     CheckForOpen(Symbol());
    }
 }
//+------------------------------------------------------------------+
//| Process open positions                                           |
//+------------------------------------------------------------------+
int ProcessOpenPositions( const string symbol )
 {
   int buys=0,sells=0, ticket;
   //---
   for( int i=OrdersTotal()-1; i>=0; i-- )
    {
      if( OrderSelect(i,SELECT_BY_POS ,MODE_TRADES) )
       {
         if( (OrderSymbol()==symbol) && (OrderMagicNumber()==MagicNum) )
          {
               ticket = OrderTicket();
               if(OrderType()==OP_BUY)
                {
                  buys++;
                  TrailStops(symbol, ticket);
                }
               if(OrderType()==OP_SELL)
                {
                  sells++;
                  TrailStops(symbol, ticket);
                }
          }
        }
       else
        {
          Print("ordeSelect Failed, Index: ",IntegerToString(i),", error: ",GetLastError(),", ",ErrorDescription(GetLastError()));
        }
    }
   return( buys + sells );
 }
//+------------------------------------------------------------------+
//| Check for close order conditions                                 |
//+------------------------------------------------------------------+
//Trailing Stop
void TrailStops( const string& symbol, const int& ticket )
 {
   static int modifyAttempts;
   if( OrderStopLoss() != OrderOpenPrice() )
    {         
      if( ((OrderProfit() - OrderCommission()) / (OrderLots() / MarketInfo(OrderSymbol(),MODE_TICKVALUE)) >= BreakEven) ) 
       {
         if(OrderType()==OP_BUY)
          {
            if( OrderStopLoss()<((Bid-modifiedStopPoints)-(10*Point)) )  // Price has moved enough to move the SL
             {
               modifyAttempts++;
               bool Mod = OrderModify(ticket,OrderOpenPrice(),Bid-modifiedStopPoints,OrderTakeProfit(),0,clrRoyalBlue);
               if(!Mod)
                {
                  string errString = ("Error in Buy OrderModify for Ticket: "+IntegerToString(ticket)+". Error code= "+IntegerToString(GetLastError())+", "+ErrorDescription(GetLastError()));
                  Print( errString,", ",IntegerToString(modifyAttempts));
                  Comment( errString +", "+IntegerToString(modifyAttempts));
                }
               else
                  Comment("Buy order modified successfully. "+IntegerToString(modifyAttempts));
             }
          }  
         if(OrderType()==OP_SELL)
          {
            if( OrderStopLoss()>((Ask+modifiedStopPoints)+(10*Point)) )  // Price has moved enough to move the SL
             { // bool  OrderModify( ticket, price, stoploss, expiration, arrow_color );
               modifyAttempts++;
               bool Mod = OrderModify(ticket,OrderOpenPrice(),Ask+modifiedStopPoints,OrderTakeProfit(),0,clrOrangeRed);
               if(!Mod)
                {
                  string errString = ("Error in Sell OrderModify for Ticket: "+IntegerToString(ticket)+". Error code= "+IntegerToString(GetLastError())+", "+ErrorDescription(GetLastError()));
                  Print( errString,", ",IntegerToString(modifyAttempts));
                  Comment( errString+", "+IntegerToString(modifyAttempts));
                 }
               else
                  Comment("Sell order modified successfully. "+IntegerToString(modifyAttempts));
             }
          }
       }                       
    }
 }//Trailing Stop }}}
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+  
void CheckForOpen(string symbol)
 {
   double Poin = Point;
   if ((Point == 0.00001) || (Point == 0.001)) Poin *= 10;
   //
   double spread = MathAbs(Ask-Bid);        // spread
   double maxGap = 25*Point;                // maximum allowed spread and maximum allowed price movement from the Bar open.
   double openSpace = MathAbs(Close[1]-Bid); // how far the price has moved from the closing of the last bar.
   //--- go trading only for first ticks of new bar
   // if( Volume[0] < 1 )   // A new  Bar has time has arrived, Chart time is updated with a quote (Volume is always at least one.  Gaps are made this way)
   // use Volume[0] < 2
   if( (openSpace < maxGap) && (spread < maxGap) && (Volume[0]<2) ) // price hasn't moved too far to open a trade, the spread is OK, and there's only been an opening quote
    {
      int  res = 0;
      string direction;
      //--- Buy conditions
      if( (Open[0]>Open[1]) )  // direction is Long
       { // int  OrderSend(symbol,cmd, volume, price,  slippage,  stoploss, takeprofit,  comment=NULL,  magic=0, expiration=0, arrow_color=clrNONE  );
         direction = "Buy";
         res=OrderSend(symbol,OP_BUY,LotsOptimized(),Ask,3,Bid-SLPoints,Ask+TPPoints,IntegerToString(MagicNum),MagicNum,0,clrRoyalBlue);
       }
      //--- Sell conditions
      if( (Open[0]<Open[1]) )  // direction is Short
       {
         direction = "Sell";
         res=OrderSend(symbol,OP_SELL,LotsOptimized(),Bid,3,Ask+SLPoints,Bid-TPPoints,IntegerToString(MagicNum),MagicNum,0,clrOrangeRed);
       }
      if(res < 0)  // OrderSend returns -1 on error, otherwise, returns a ticket number.
       {
         Print("SLPoints: ",DoubleToStr(SLPoints,Digits),", TPPoints: ",DoubleToStr(TPPoints,Digits),", OrderSend of ",direction," Failed, Error: ",IntegerToString(GetLastError()),", ",ErrorDescription(GetLastError()) );
       }
     }
 }
//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double LotsOptimized()
 {
   double lot=0.0;
   int    orders=HistoryTotal();     // history orders total
   //--- select lot size
   lot = NormalizeDouble(AccountFreeMargin()*TradePercentage/(DecreaseFactor*1000.0),1);
   //--- calcuulate number of losses orders without a break
   if(DecreaseFactor>0)
    {
      for(int i=orders-1;i>=0;i--)
       {
         if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY)==false)
          {
            Print("Error in history!");
            break;
          }
         if(OrderSymbol()!=Symbol() || OrderType()>OP_SELL)
            continue;
         //---
         if(OrderProfit()>0) lot=NormalizeDouble(AccountFreeMargin()*TradePercentage/(DecreaseFactor*1000.0),1);
         if(OrderProfit()<0) lot=NormalizeDouble(AccountFreeMargin()*TradePercentage/(DecreaseFactor*1000.0),1);
       }      
    }
   //--- return lot size
   if(lot<MarketInfo(Symbol(),MODE_MINLOT)) lot=MarketInfo(Symbol(),MODE_MINLOT);
   if(lot>MarketInfo(Symbol(),MODE_MAXLOT)) lot=MarketInfo(Symbol(),MODE_MAXLOT);
   return(lot);
 }
//+------------------------------------------------------------------+
//| End of the EA Functions                                          |
//+------------------------------------------------------------------+