//+------------------------------------------------------------------+
//|                      NonLagDotEA.mq4                             |
//|                 Copyright © 2015, David Currey                   |
//+------------------------------------------------------------------+
extern int MAGICMA = 4564581;
extern string Hlp0 = "TradingMode: Autotrading=0, Advisory Only=1, Discretionary Trading=2";
extern int TradingMode = 0;
extern string Hlp1 = "Leave FixedLotSize=0 for LotSize based on Equity";
extern double FixedLotSize = 0;
extern double MaximumRiskPercentage = 2;
extern int StartHour = 0;
extern int Duration = 24;
extern string Hlp2 = "Use Most Recent Swing Low or High for StopLoss, 0 = No, 1 = Yes";
extern int UseSwingLowOrHigh = 0;
extern string Hlp3 = "Stop Loss Size and/or Trail Value";
extern int StopLoss = 20;
extern string Hlp4 = "Use the First or Most Recent Drawback for Entry Signal, 0 = First, 1 = Most Recent";
extern int UseMostRecentDrawback = 1;
extern string Hlp5 = "Increase in Wager after losses, example 1.5 = 50% increase";
extern double StopLossMultiple = 1.0;
extern string Hlp6 = " 0 = Fixed StopLoss, 1 = Trailing Stop Loss";
extern int TrailingStopLoss = 1;
extern string Hlp7 = "SetStopLossToBreakEvenPips: example 30 = protect loss at 30 pip gain";
extern int SetStopLossToBreakEvenPips = 0;
extern string Hlp8 = "Use NonLagDot reversal for trade closure, 0 = No, 1 = Yes";
extern int UseNonLagDotReversal = 1;
extern int TakeProfit = 1000;
extern string Hlp9 = "Number of Bars for Discretionary Moving Average";
extern int Length = 70;
extern string Hlp10 = "USD=0, EUR=1, AUD=2, GBP=3, CHF=4, CAD=5, NZD=6";
extern int BaseCurrency = 1;
extern string Hlp11 = "Base Currency/First of Pair exchange rate for testing";
extern double RelatedRate = 1;
int EndHour;
int Up = 1;
int Down = 2;
int Direction;
int PrevDirection;
double WagerValue;
double WagerLots;
double NormalWager;
double StopLossPrice;
double PrevStopLossPrice;
double PrevEquity;
double PrevWager;
double TakeWinPrice;
double AdjStopLoss;
double CurrProfitTarget;
double PointValue;
double BaseRate;
double NLD1;
double NLD2;
double PrevOpen;
int stopbuys;
int stopsells;
int buys;
int sells;
int res;
int Spread;
int i;
int Modified;
int BreakEvenCompleted;
string BaseCurrencyString;
string RelatedCurrencyString1;
string RelatedCurrencyString2;
string Message;
string Message2;
bool NewBar;
//+------------------------------------------------------------------+
//| Start function                                                   |
//+------------------------------------------------------------------+
void start()
    {
    CalculateCurrentOrders();
    CheckNewBar();
    if(NewBar == true)
      { 
      CalculateDirection();
      if (((Direction == Up && Close[1] < Open[1])  || (Direction == Down && Close[1] > Open[1])) && UseMostRecentDrawback == 1)
        {
        DeleteStopOrders();
        }
      if(Direction != PrevDirection) 
        {
        if (Direction == Down && UseSwingLowOrHigh == 1) StopLossPrice = iHighest(NULL,0,MODE_HIGH,10,1) + Ask - Bid;
        if (Direction == Up && UseSwingLowOrHigh == 1) StopLossPrice = iLowest(NULL,0,MODE_LOW,10,1) - Ask +Bid; 
        DeleteStopOrders();
        if (UseNonLagDotReversal == 1) ClosePositions();
        }
      PrevDirection = Direction;
      if (stopbuys == 0 && stopsells == 0 && buys == 0 && sells == 0) 
        {
        CheckForOpen();
        }
      }
    if (buys != 0 || sells != 0) CheckForModify();
    }
//+------------------------------------------------------------------+
//| Check for new bar                                  |
//+------------------------------------------------------------------+
void CheckNewBar()                              
  {                                             
   static datetime NewTime=0;                  
   NewBar=false;                               
   if(NewTime!=Time[0])                        
     {
      NewTime=Time[0];                         
      NewBar=true;                                
     }
  }
//+------------------------------------------------------------------+
//| Check for open order conditions                                  |
//+------------------------------------------------------------------+
void CheckForOpen()
    {
    EndHour = StartHour + Duration;
    if (EndHour > 24) return;
    if (StartHour + Duration > 23) EndHour = StartHour - 24;
    if (EndHour > StartHour && (Hour() < StartHour || Hour() > EndHour )) return;
    if (EndHour < StartHour && (Hour() < StartHour && Hour() > EndHour )) return;
    if (Direction == Up && Close[1] < Open[1])
       {
       if (TradingMode != 0 && PrevOpen != Open[0])
         {
         PlaySound("alert.wav");
         Message2 = StringConcatenate("ALERT - BUY ",Symbol()," - ",Period(),"min at ",TimeToString(TimeCurrent(),TIME_MINUTES));
         res = MessageBox(Message,Message2,MB_OKCANCEL);
         PrevOpen = Open[0];
         if (TradingMode == 1) return;
         if (TradingMode == 2 && res != 2) return;
         }
       if(IsTesting()) ObjectsDeleteAll();
       WagerLots = LotsOptimized();
       res=OrderSend(Symbol(),OP_BUYSTOP,WagerLots,High[1],0,0,0,"NonLagDot ",MAGICMA,0,Green);
       if (res > -1) Modified = 0;
       PrevEquity = AccountEquity();
       return;
       }
    if (Direction == Down && Close[1] > Open[1])
       {
       if (TradingMode != 0 && PrevOpen != Open[0])
         {
         PlaySound("alert.wav");
         Message2 = StringConcatenate("ALERT - SELL ",Symbol()," - ",Period(),"min at ",TimeToString(TimeCurrent(),TIME_MINUTES));
         res = MessageBox(Message,Message2,MB_OKCANCEL);
         PrevOpen = Open[0];
         if (TradingMode == 1) return;
         if (TradingMode == 2 && res != 2) return;
         }
       if(IsTesting()) ObjectsDeleteAll();
       WagerLots = LotsOptimized();
       res=OrderSend(Symbol(),OP_SELLSTOP,WagerLots,Low[1],0,0,0,"NonLagDot ",MAGICMA,0,Green);
       if (res > -1) Modified = 0;
       PrevEquity = AccountEquity();
       return;
       }
    }
//+------------------------------------------------------------------+
//| Check for modify order conditions                                |
//+------------------------------------------------------------------+
void CheckForModify()
  {
  for(i=0;i<OrdersTotal();i++)
      {
      if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
      if (OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)
         {
         if (Modified == 0)
            {
            if (OrderType()==OP_BUY) 
               {
               if (StopLoss != 0  && UseSwingLowOrHigh == 0) StopLossPrice = Bid - (StopLoss * PointValue);
               if (TakeProfit > 1000) TakeProfit = 1000;
               if (TakeProfit != 0) TakeWinPrice = Ask + (TakeProfit * PointValue); 
               res = OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice, TakeWinPrice, 0,clrMaroon);
               if (res > -1) 
                  {
                  CurrProfitTarget = WagerLots * Close[0] / PointValue / 10000 * 50;
                  PrevStopLossPrice = StopLossPrice;
                  BreakEvenCompleted = 0;
                  Modified = 1;
                  return;
                  }
               }
            if (OrderType()==OP_SELL) 
               {
               if (StopLoss != 0  && UseSwingLowOrHigh == 0) StopLossPrice = Ask + (StopLoss * PointValue);
               if (TakeProfit > 1000) TakeProfit = 1000;
               if (TakeProfit != 0) TakeWinPrice = Bid - (TakeProfit * PointValue);   
               res = OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice, TakeWinPrice, 0,clrMaroon);
               if (res > -1) 
                  {
                  CurrProfitTarget = WagerLots * Close[0]  / PointValue / 10000 * 50;
                  PrevStopLossPrice = StopLossPrice;
                  BreakEvenCompleted = 0;
                  Modified = 1;
                  return;
                  }
               }
            }

         if (Modified == 1)
            {
            Spread = Ask - Bid;
            if (OrderType()==OP_BUY && SetStopLossToBreakEvenPips != 0 
            && Close[0] - OrderOpenPrice() - Spread >= SetStopLossToBreakEvenPips * PointValue
            && BreakEvenCompleted == 0)
               {
               StopLossPrice = OrderOpenPrice() + Spread + PointValue;
               res = OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice, TakeWinPrice, 0, clrMaroon);
               if (res > -1) 
                  {
                  CurrProfitTarget = OrderProfit() + (WagerLots * Close[0] / PointValue / 10000 * 50);
                  BreakEvenCompleted = 1;
                  PrevStopLossPrice = StopLossPrice;
                  }
               }
            if (OrderType()==OP_SELL && SetStopLossToBreakEvenPips != 0 
            && OrderOpenPrice() - Close[0] - Spread >= SetStopLossToBreakEvenPips * PointValue
            && BreakEvenCompleted == 0)
               {
               StopLossPrice = OrderOpenPrice() - Spread - PointValue;
               res = OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice, TakeWinPrice, 0, clrMaroon);
               if (res > -1) 
                  {
                  CurrProfitTarget = OrderProfit() + (WagerLots * Close[0] / PointValue / 10000 * 50);
                  BreakEvenCompleted = 1;
                  PrevStopLossPrice = StopLossPrice;
                  }
               }
            }   
         if (Modified == 1 && TrailingStopLoss==1)
            {
            if (OrderProfit() > CurrProfitTarget && ((OrderType()==OP_BUY)|| (OrderType()==OP_SELL))) 
               {
               if (OrderType()==OP_BUY) 
                  {
                  StopLossPrice = Bid - (StopLoss * PointValue);
                  if (StopLossPrice > PrevStopLossPrice) res = OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice, TakeWinPrice, 0, clrMaroon);
                  PrevStopLossPrice = StopLossPrice;
                  }
               if (OrderType()==OP_SELL)
                  {
                  StopLossPrice = Ask + (StopLoss * PointValue);
                  if (StopLossPrice < PrevStopLossPrice) res = OrderModify(OrderTicket(),OrderOpenPrice(),StopLossPrice, TakeWinPrice, 0, clrMaroon);
                  PrevStopLossPrice = StopLossPrice;
                  }
               if (res > -1) CurrProfitTarget = OrderProfit() + (WagerLots * Close[0] / PointValue / 10000 * 50);
               } 
            }
         }
      }
   }   
//+------------------------------------------------------------------+
//| Close Positions                               |
//+------------------------------------------------------------------+
void ClosePositions()
    {
       for(i=0;i<OrdersTotal();i++)
       {
       if (OrderType()==OP_BUY && OrderMagicNumber()==MAGICMA)
          {
          res = OrderClose(OrderTicket(),OrderLots(),Bid,1,clrMaroon);
          if (res > -1) return;
          }
       if (OrderType()==OP_SELL && OrderMagicNumber()==MAGICMA)
          {
          res = OrderClose(OrderTicket(),OrderLots(),Ask,1,clrMaroon);
          if (res > -1) return;
          }
       }
    }
//+------------------------------------------------------------------+
//| Delete Stop Orders                               |
//+------------------------------------------------------------------+
void DeleteStopOrders()
    {
       for(i=0;i<OrdersTotal();i++)
       {
       if (OrderType()==OP_BUYSTOP && OrderMagicNumber()==MAGICMA)
          {
          res = OrderDelete(OrderTicket());
          if (res > -1) return;
          }
       if (OrderType()==OP_SELLSTOP  && OrderMagicNumber()==MAGICMA)
          {
          res = OrderDelete(OrderTicket());
          if (res > -1) return;
          }
       }
    }
//+------------------------------------------------------------------+
//| Calculate optimal lot size                                       |
//+------------------------------------------------------------------+
double LotsOptimized()
    {
    PointValue = .0001;
    if(Symbol() == "AUS200") PointValue = 1;
    if(Symbol() == "SPX200") PointValue = .1;
    if(StringFind(Symbol(),"JPY") > 0) PointValue = .01;
    if(StringFind(Symbol(),"XAU") > 0) PointValue = .1;
    if(StringFind(Symbol(),"GOLD") > 0) PointValue = .1;
    if(StringFind(Symbol(),"XAG") > 0) PointValue = .01;
    if(StringFind(Symbol(),"SILVER") > 0) PointValue = .01;
    WagerValue=NormalizeDouble(AccountEquity()*MaximumRiskPercentage/100,2);
    if(BaseCurrency == 0) BaseCurrencyString = "USD";
    if(BaseCurrency == 1) BaseCurrencyString = "EUR";
    if(BaseCurrency == 2) BaseCurrencyString = "AUD";
    if(BaseCurrency == 3) BaseCurrencyString = "GBP";
    if(BaseCurrency == 4) BaseCurrencyString = "CHF";
    if(BaseCurrency == 5) BaseCurrencyString = "NZD";
    if(BaseCurrency == 6) BaseCurrencyString = "CAD";
    RelatedCurrencyString1 = "";
    RelatedCurrencyString2 = "";
    if (StringFind(Symbol(),BaseCurrencyString) == -1) 
      {
      RelatedCurrencyString1 = StringConcatenate(StringSubstr(Symbol(),0,3),BaseCurrencyString);
      RelatedCurrencyString2 = StringConcatenate(BaseCurrencyString,StringSubstr(Symbol(),0,3));
      }
    if(Symbol() == "XAUUSD" || Symbol() == "XAGUSD" || Symbol() == "GOLD" || Symbol() == "SILVER")  
      {
      RelatedCurrencyString1 = StringConcatenate("USD",BaseCurrencyString);
      RelatedCurrencyString2 = StringConcatenate(BaseCurrencyString,"USD");
      }
    BaseRate = 1;
    if (Direction == Up && StringFind(Symbol(),BaseCurrencyString) == 0) BaseRate = High[1];
    if (Direction == Down && StringFind(Symbol(),BaseCurrencyString) == 0) BaseRate = Low[1];
    if (Direction == Up && StringFind(Symbol(),BaseCurrencyString) == 3) BaseRate = 1/High[1];
    if (Direction == Down && StringFind(Symbol(),BaseCurrencyString) == 3) BaseRate = 1/Low[1];
    if (RelatedCurrencyString1 != "" && iClose(RelatedCurrencyString1,PERIOD_M1,0)!= 0) RelatedRate = iClose(RelatedCurrencyString1,PERIOD_M1,0);
    if (RelatedCurrencyString2 != "" && iClose(RelatedCurrencyString2,PERIOD_M1,0)!= 0) RelatedRate = 1/iClose(RelatedCurrencyString2,PERIOD_M1,0);
    WagerLots = NormalizeDouble(WagerValue * BaseRate * RelatedRate / StopLoss / AccountLeverage() * 10,2);
    Print("Wager Value ",WagerValue,", Base Rate ",BaseRate,", Related Rate ",RelatedRate,", Point Value ",PointValue,", StopLoss ",StopLoss,", Account Leverage ",AccountLeverage());
    Print("Wager Lots ",WagerLots);
    if(FixedLotSize != 0) WagerLots = FixedLotSize;
    NormalWager = WagerLots;
    if (AccountEquity() < PrevEquity && StopLossMultiple > 1) 
       {
       WagerLots =  NormalizeDouble(PrevWager * StopLossMultiple,2);
       if (WagerLots / BaseRate / RelatedRate * StopLoss * AccountLeverage() / 10 > AccountEquity() * .2) WagerLots = NormalWager;
       }
    if (AccountEquity() == PrevEquity && StopLossMultiple > 1) WagerLots = PrevWager;
    PrevWager = WagerLots;
    return(WagerLots);
    }
//+------------------------------------------------------------------+
//| Calculate Direction                                         |
//+------------------------------------------------------------------+
void CalculateDirection()
    {
    NLD2 = iCustom(NULL,0,"nonlagdot",0,Length,0,0,1,0,0,0,2);
    NLD1 = iCustom(NULL,0,"nonlagdot",0,Length,0,0,1,0,0,0,1);
    if(NLD1 > NLD2) Direction = Up;
    if(NLD1 < NLD2) Direction = Down;
    }
//+------------------------------------------------------------------+
//| Calculate open positions                                         |
//+------------------------------------------------------------------+
void CalculateCurrentOrders()
    {
    stopbuys = 0;
    stopsells = 0;
    buys = 0;
    sells = 0;
    for(i=0;i<OrdersTotal();i++)
       {
       if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES)==false) break;
       if (OrderSymbol()==Symbol() && OrderMagicNumber()==MAGICMA)
          {
          if(OrderType()==OP_BUYSTOP) stopbuys++;
          if(OrderType()==OP_SELLSTOP) stopsells++;
          if(OrderType()==OP_BUY) buys++;
          if(OrderType()==OP_SELL) sells++;
          }
       }
    }
//+------------------------------------------------------------------+