// Digger R&D version AAB
// Entry: Reverse
// TP: Trailing stop according to Volatility * 5

#include <Trade\Trade.mqh>

#define              N 10                    
input int            APVFactor=5;
input double         Risk=0.1;  
               
enum                 lastDealEnum {no,buy,sell}; 
lastDealEnum         lastDeal = buy;
datetime             BarTime=D'03.12.1977'; 
CTrade Trade;

void OnTick()
{

   if(NewBar())
      if(!PositionSelect(Symbol())) 
         Trade();

   TrailingStop();

   return;
}

bool NewBar()
{
   datetime New_Time[1];
   int copied=CopyTime(_Symbol,_Period,0,1,New_Time);
   if(copied>0)
     {
      if(BarTime!=New_Time[0])
        {
         BarTime=New_Time[0];
         return(true);
        }
     }
   else
     {
      Alert(GetLastError());
      ResetLastError();
      return(false);
     }
   return(false);
}

bool TradeDirection()
{
   
   // Random Directiom
//   bool r=(rand()>32768/2);      
//   return(r);

   // Reverse entry
   if(lastDeal==buy) 
   {
      lastDeal=sell; 
      return(false);
   }
   if(lastDeal==sell) 
   {
      lastDeal=buy; 
      return(true);
   }
   
   return(true);
}

void Trade()
{
   double Equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double LotSize=0.2;//NormalizeDouble(Equity*Risk/1000, 2);

   if(TradeDirection())
     {
      SendBuyOrder(LotSize);
     }
   else
     {
      SendSellOrder(LotSize);
     }
   return;
}

void TrailingStop()
{

   MqlRates rates[N];
   if(CopyRates(_Symbol,_Period,0,N,rates)!=N)
   {
      Alert("CopyRates of ",_Symbol," failed, no history");
      return;
   }

   double AverageVolatility=0;
   for(int i=0; i<N; i++)
   {
      AverageVolatility=AverageVolatility + rates[i].high - rates[i].low;
   }
   AverageVolatility=AverageVolatility/N;
   
   
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
   
   //double LastPrice=NormalizeDouble(SymbolInfoDouble(_Symbol,SYMBOL_LAST), _Digits);
   //there is no Last Price for Forex symbol tick
  
   for(int i = PositionsTotal()-1; i >= 0; i--)
   {
      string symbol = PositionGetSymbol(i);
      
      if(_Symbol == symbol)
      {
         ulong PositionTicket = PositionGetInteger(POSITION_TICKET);
         double CurrentStopLoss = PositionGetDouble(POSITION_SL);

         Print("ID = ", i);
       
         if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
         {

            Print("[BUY] Ask = ", Ask);
            Print("Current SL = ", CurrentStopLoss);
            Print("Distance = ", NormalizeDouble(MathAbs(Ask-CurrentStopLoss), _Digits));
            Print("Volatility = ", NormalizeDouble(AverageVolatility*APVFactor, _Digits));
            //Print("VolatilityRaw = ", NormalizeDouble(AverageVolatility, _Digits));
            //for(int i=0; i<N; i++)
            //{
            //   Print("Volatility Rate [", i, "] = ", rates[i].high - rates[i].low);
            //}

            double Distance = NormalizeDouble(MathAbs(Ask-CurrentStopLoss), _Digits);
            double Volatility = NormalizeDouble(AverageVolatility*APVFactor, _Digits);

            if(Distance > Volatility)
            {

               double SL=NormalizeDouble(Ask-Volatility,_Digits);
               Print("New SL = ", SL);

               if(!Trade.PositionModify(PositionTicket, SL, 0))
               {
                  Print("SL Error: ", Trade.ResultRetcode(), " ", Trade.ResultRetcodeDescription());
               }
            }
         }

         if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
         {

            Print("[SELL] Bid = ", Bid);
            Print("Current SL = ", CurrentStopLoss);
            Print("Distance = ", NormalizeDouble(MathAbs(CurrentStopLoss-Bid), _Digits));
            Print("Volatility = ", NormalizeDouble(AverageVolatility*APVFactor, _Digits));
            //Print("VolatilityRaw = ", NormalizeDouble(AverageVolatility, _Digits));
            //for(int i=0; i<N; i++)
            //{
            //   Print("Volatility Rate [", i, "] = ", rates[i].high - rates[i].low);
            //}

            double Distance = NormalizeDouble(MathAbs(CurrentStopLoss-Bid), _Digits);
            double Volatility = NormalizeDouble(AverageVolatility*APVFactor, _Digits);

            if(Distance > Volatility)
            {
               double SL = NormalizeDouble(Bid + Volatility,_Digits);
               Print("New SL = ", SL);
             
               if(!Trade.PositionModify(PositionTicket, SL, 0))
               {
                  Print("SL Error: ", Trade.ResultRetcode(), " ", Trade.ResultRetcodeDescription());
               }
            }
         }
      }
   }
   return;
}
  
void SendBuyOrder(double pLotSize)
{
   double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
   
   if(!Trade.PositionOpen(_Symbol, ORDER_TYPE_BUY, pLotSize, Ask, 0, 0))
   {
      Print("Buy Order Error: ", Trade.ResultRetcode(), " ", Trade.ResultRetcodeDescription());
   }
   return;
}
  
void SendSellOrder(double pLotSize)
{
   double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
   
   if(!Trade.PositionOpen(_Symbol, ORDER_TYPE_SELL, pLotSize, Bid, 0, 0))
   {
      Print("Sell Order Error: ", Trade.ResultRetcode(), " ", Trade.ResultRetcodeDescription());
   }

   return;
}
