//+------------------------------------------------------------------+
//|                                      Ilan1.6_PipStep_QProfit.mq4 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+

/*
 SETTING RECOMENDADO PARA UNA CUENTA DE 1000$
 BROKER 4 DIGITOS.
 GBPUSD
 TF: 5 MIN
*/

extern double           LotExponent                = 1.4;   
extern double           slip                       = 3.0;           
extern double           Lots                       = 0.04;         
extern int              lotdecimal                 = 2;          
extern double           TakeProfit                 = 10.0;    
extern double           TakeProfitExponent         = 1.2; 
extern string           ProfitQuant                = "PROFIT QUANT";
extern bool             ProfitQuantumStep          = true;   
extern string           StartStepExpProfitSrting   = "TAKE PROFIT EXPONENTIAL";
extern int              StartStepExpProfit         = 3;       
extern double           Pipstep                    = 25.0;      
extern double           PipStepExponent            = 1.2;
extern string           Quant                      = "QUANT";
extern bool             QuantumStep                = true;   
extern string           StartStepExpSrting         = "PIP STEP EXPONENTIAL";
extern int              StartStepExp               = 3;      
extern double           RsiMinimum                 = 30.0;    
extern double           RsiMaximum                 = 70.0;    
extern int              MagicNumber                = 2222;  
extern int              MaxTrades                  = 10;

//***********************************************************************************************************************************
//***********************************************************************************************************************************

double   Stoploss             = 5000.0;            
double   TrailStart           = 100.0;
double   TrailStop            = 100.0;                
bool     UseEquityStop        = FALSE;
double   TotalEquityRisk      = 20.0;
bool     UseTrailingStop      = FALSE;
bool     UseTimeOut           = FALSE;            
double   MaxTradeOpenHours    = 48.0;
string   EAName               ="Ilan1.6_PipStep_QProfit";
int      timeprev             = 0,expiration;            
int      NumOfTrades          = 0;
int      cnt                  = 0, total, counter;
double   Stopper              = 0.0;
bool     TradeNow             = FALSE; 
bool     LongTrade            = FALSE; 
bool     ShortTrade           = FALSE;  
bool     NewOrdersPlaced      = FALSE;

double   PriceTarget; 
double   StartEquity; 
double   BuyTarget; 
double   SellTarget;
double   AveragePrice; 
double   SellLimit; 
double   BuyLimit;
double   LastBuyPrice; 
double   LastSellPrice; 
double   Spread;
bool     flag;
double   iLots;
double   AccountEquityHighAmt; 
double   PrevEquity;
bool     dummyResult;

//***********************************************************************************************************************************
//***********************************************************************************************************************************

int init() 
{
   Spread = MarketInfo(Symbol(), MODE_SPREAD) * Point;
   return (0);
}

int deinit() 
{
   return (0);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

int start() 
{
   total = CountTrades();
   counter = total + 1;
   int PipStepE = NormalizeDouble(Pipstep*MathPow(PipStepExp(total),TradeStepExp(total)),0);
   int TakeProfitE = NormalizeDouble(TakeProfit*MathPow(TakeProfitExp(total),TradeProfitStepExp(total)),0);
   double PrevCl;
   double CurrCl;
   if (UseTrailingStop) TrailingAlls(TrailStart, TrailStop, AveragePrice);
   if (UseTimeOut) 
   {
      if (TimeCurrent() >= expiration) 
      {
         CloseThisSymbolAll();
         Print("Closed All due to TimeOut");
      }
   }
   if (timeprev == Time[0]) return (0);
   timeprev = Time[0];
   double CurrentPairProfit = CalculateProfit();
   if (UseEquityStop) 
   {
      if (CurrentPairProfit < 0.0 && MathAbs(CurrentPairProfit) > TotalEquityRisk / 100.0 * AccountEquityHigh()) 
      {
         CloseThisSymbolAll();
         Print("Closed All due to Stop Out");
         NewOrdersPlaced = FALSE;
      }
   }
   total = CountTrades();
   if (total == 0) flag = FALSE;
   for (cnt = OrdersTotal() - 1; cnt >= 0; cnt--) 
   {
      dummyResult = OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) 
      {
         if (OrderType() == OP_BUY) 
         {
            LongTrade = TRUE;
            ShortTrade = FALSE;
            break;
         }
      }
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) 
      {
         if (OrderType() == OP_SELL) 
         {
            LongTrade = FALSE;
            ShortTrade = TRUE;
            break;
         }
      }
   }
   if (total > 0 && total <= MaxTrades) 
   {
      RefreshRates();
      LastBuyPrice = FindLastBuyPrice();
      LastSellPrice = FindLastSellPrice();
      if (LongTrade && LastBuyPrice - Ask >= PipStepE * Point) TradeNow = TRUE;
      if (ShortTrade && Bid - LastSellPrice >= PipStepE * Point) TradeNow = TRUE;
   }
   if (total < 1) 
   {
      ShortTrade = FALSE;
      LongTrade = FALSE;
      TradeNow = TRUE;
      StartEquity = AccountEquity();
   }
   if (TradeNow) 
   { 
      LastBuyPrice = FindLastBuyPrice();
      LastSellPrice = FindLastSellPrice();
      if (ShortTrade) 
      {
         NumOfTrades = total;
         iLots = NormalizeDouble(Lots * MathPow(LotExponent, NumOfTrades), lotdecimal);
         RefreshRates();
         int ticket = OpenPendingOrder(1, iLots, Bid, slip, Ask, 0, 0, EAName + "-" + counter, MagicNumber, 0, HotPink);
         if (ticket < 0) 
         {
            Print("Error: ", GetLastError());
            return (0);
         }
         LastSellPrice = FindLastSellPrice();
         TradeNow = FALSE;
         NewOrdersPlaced = TRUE;
      } 
      else 
      {
         if (LongTrade) 
         {
            NumOfTrades = total;
            iLots = NormalizeDouble(Lots * MathPow(LotExponent, NumOfTrades), lotdecimal);
            ticket = OpenPendingOrder(0, iLots, Ask, slip, Bid, 0, 0, EAName + "-" + counter, MagicNumber, 0, Lime);
            if (ticket < 0) 
            {
               Print("Error: ", GetLastError());
               return (0);
            }
            LastBuyPrice = FindLastBuyPrice();
            TradeNow = FALSE;
            NewOrdersPlaced = TRUE;
         }
      }
   }
   if (TradeNow && total < 1) 
   {  
      PrevCl = iClose(Symbol(), 0, 2);
      CurrCl = iClose(Symbol(), 0, 1);
      SellLimit = Bid;
      BuyLimit = Ask;
      if (!ShortTrade && !LongTrade) 
      {
         NumOfTrades = total;
         iLots = NormalizeDouble(Lots * MathPow(LotExponent, NumOfTrades), lotdecimal);
         if (PrevCl > CurrCl) {
            if (iRSI(NULL, PERIOD_H1, 14, PRICE_CLOSE, 1) > RsiMinimum) 
            {
               ticket = OpenPendingOrder(1, iLots, SellLimit, slip, SellLimit, 0, 0, EAName + "-" + counter, MagicNumber, 0, HotPink);
               if (ticket < 0) 
               {
                  Print("Error: ", GetLastError());
                  return (0);
               }
               LastBuyPrice = FindLastBuyPrice();
               NewOrdersPlaced = TRUE;
            }
         } 
         else 
         {
            if (iRSI(NULL, PERIOD_H1, 14, PRICE_CLOSE, 1) < RsiMaximum) 
            {
               ticket = OpenPendingOrder(0, iLots, BuyLimit, slip, BuyLimit, 0, 0, EAName + "-" + counter, MagicNumber, 0, Lime);
               if (ticket < 0) 
               {
                  Print("Error: ", GetLastError());
                  return (0);
               }
               LastSellPrice = FindLastSellPrice();
               NewOrdersPlaced = TRUE;
            }
         }
         if (ticket > 0) expiration = TimeCurrent() + 60.0 * (60.0 * MaxTradeOpenHours);
         TradeNow = FALSE;
      }
   }
   total = CountTrades();
   AveragePrice = 0;
   double Count = 0;
   for (cnt = OrdersTotal() - 1; cnt >= 0; cnt--) 
   {
      dummyResult = OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) 
      {
         if (OrderType() == OP_BUY || OrderType() == OP_SELL) 
         {
            AveragePrice += OrderOpenPrice() * OrderLots();
            Count += OrderLots();
         }
      }
   }
   if (total > 0) AveragePrice = NormalizeDouble(AveragePrice / Count, Digits);
   if (NewOrdersPlaced) 
   {
      for (cnt = OrdersTotal() - 1; cnt >= 0; cnt--) {
         dummyResult = OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
         if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) 
         {
            if (OrderType() == OP_BUY) 
            {
               PriceTarget = AveragePrice + TakeProfitE * Point;
               BuyTarget = PriceTarget;
               Stopper = AveragePrice - Stoploss * Point;
               flag = TRUE;
            }
         }
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) 
         {
            if (OrderType() == OP_SELL) 
            {
               PriceTarget = AveragePrice - TakeProfitE * Point;
               SellTarget = PriceTarget;
               Stopper = AveragePrice + Stoploss * Point;
               flag = TRUE;
            }
         }
      }
   }
   if (NewOrdersPlaced) 
   {           
      Print("PipStepE = ",PipStepE);
      Print("TakeProfitE = ",TakeProfitE);
      if (flag == TRUE) 
      {
         for (cnt = OrdersTotal() - 1; cnt >= 0; cnt--) 
         {
            dummyResult = OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
            if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
            if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) dummyResult = OrderModify(OrderTicket(), AveragePrice, OrderStopLoss(), PriceTarget, 0, Yellow);
            NewOrdersPlaced = FALSE;
         }
      }
   }
   return (0);
}



int CountTrades() 
{
   int count = 0;
   for (int trade = OrdersTotal() - 1; trade >= 0; trade--) 
   {
      dummyResult = OrderSelect(trade, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
         if (OrderType() == OP_SELL || OrderType() == OP_BUY) count++;
   }
   return (count);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

void CloseThisSymbolAll() 
{
   for (int trade = OrdersTotal() - 1; trade >= 0; trade--) 
   {
      dummyResult = OrderSelect(trade, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol() == Symbol()) 
      {
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber) 
         {
            if (OrderType() == OP_BUY)  dummyResult = OrderClose(OrderTicket(), OrderLots(), Bid, slip, Blue);
            if (OrderType() == OP_SELL) dummyResult = OrderClose(OrderTicket(), OrderLots(), Ask, slip, Red);
         }
         Sleep(1000);
      }
   }
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

int OpenPendingOrder(int pType, double pLots, double pLevel, int sp, double pr, int sl, int tp, string pComment, int pMagic, int pDatetime, color pColor) 
{
   int ticket = 0;
   int err = 0;
   int c = 0;
   int NumberOfTries = 100;
   switch (pType) 
   {
   case 2:
      for (c = 0; c < NumberOfTries; c++) 
      {
         ticket = OrderSend(Symbol(), OP_BUYLIMIT, pLots, pLevel, sp, StopLong(pr, sl), TakeLong(pLevel, tp), pComment, pMagic, pDatetime, pColor);
         err = GetLastError();
         if (err == 0) break;
         if (!(err == 4|| err == 137 || err == 146 || err == 136)) break;
         Sleep(1000);
      }
   break;
   
   case 4:
      for (c = 0; c < NumberOfTries; c++) 
      {
         ticket = OrderSend(Symbol(), OP_BUYSTOP, pLots, pLevel, sp, StopLong(pr, sl), TakeLong(pLevel, tp), pComment, pMagic, pDatetime, pColor);
         err = GetLastError();
         if (err == 0) break;
         if (!(err == 4 || err == 137 || err == 146 || err == 136)) break;
         Sleep(5000);
      }
   break;
   
   case 0:
      for (c = 0; c < NumberOfTries; c++) 
      {
         RefreshRates();
         ticket = OrderSend(Symbol(), OP_BUY, pLots, Ask, sp, StopLong(Bid, sl), TakeLong(Ask, tp), pComment, pMagic, pDatetime, pColor);
         err = GetLastError();
         if (err == 0) break;
         if (!(err == 4 || err == 137 || err == 146 || err == 136)) break;
         Sleep(5000);
      }
   break;
   
   case 3:
      for (c = 0; c < NumberOfTries; c++) 
      {
         ticket = OrderSend(Symbol(), OP_SELLLIMIT, pLots, pLevel, sp, StopShort(pr, sl), TakeShort(pLevel, tp), pComment, pMagic, pDatetime, pColor);
         err = GetLastError();
         if (err == 0) break;
         if (!(err == 4 || err == 137 || err == 146|| err == 136)) break;
         Sleep(5000);
      }
   break;
   
   case 5:
      for (c = 0; c < NumberOfTries; c++) 
      {
         ticket = OrderSend(Symbol(), OP_SELLSTOP, pLots, pLevel, sp, StopShort(pr, sl), TakeShort(pLevel, tp), pComment, pMagic, pDatetime, pColor);
         err = GetLastError();
         if (err == 0) break;
         if (!(err == 4 || err == 137|| err == 146 || err == 136)) break;
         Sleep(5000);
      }
   break;
   
   case 1:
      for (c = 0; c < NumberOfTries; c++) 
      {
         ticket = OrderSend(Symbol(), OP_SELL, pLots, Bid, sp, StopShort(Ask, sl), TakeShort(Bid, tp), pComment, pMagic, pDatetime, pColor);
         err = GetLastError();
         if (err == 0) break;
         if (!(err == 4 || err == 137|| err == 146 || err == 136)) break;
         Sleep(5000);
      }
   }
   return (ticket);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

double StopLong(double price, int stop) 
{
   if (stop == 0) return (0);
   else return (price - stop * Point);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

double StopShort(double price, int stop) 
{
   if (stop == 0) return (0);
   else return (price + stop * Point);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

double TakeLong(double price, int stop) 
{
   if (stop == 0) return (0);
   else return (price + stop * Point);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

double TakeShort(double price, int stop) 
{
   if (stop == 0) return (0);
   else return (price - stop * Point);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

double CalculateProfit() 
{
   double Profit = 0;
   for (cnt = OrdersTotal() - 1; cnt >= 0; cnt--) 
   {
      dummyResult = OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES);
      if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
      if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber)
         if (OrderType() == OP_BUY || OrderType() == OP_SELL) Profit += OrderProfit();
   }
   return (Profit);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************
   
   void TrailingAlls(int pType, int stop, double AvgPrice) 
   {
      int profit;
      double stoptrade;
      double stopcal;
      if (stop != 0) 
      {
         for (int trade = OrdersTotal() - 1; trade >= 0; trade--) 
         {
            if (OrderSelect(trade, SELECT_BY_POS, MODE_TRADES)) 
            {
               if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
               if (OrderSymbol() == Symbol() || OrderMagicNumber() == MagicNumber) 
               {
                  if (OrderType() == OP_BUY) 
                  {
                     profit = NormalizeDouble((Bid - AvgPrice) / Point, 0);
                     if (profit < pType) continue;
                     stoptrade = OrderStopLoss();
                     stopcal = Bid - stop * Point;
                     if (stoptrade == 0.0 || (stoptrade != 0.0 && stopcal > stoptrade)) dummyResult = OrderModify(OrderTicket(), AvgPrice, stopcal, OrderTakeProfit(), 0, Aqua);
                  }
               if (OrderType() == OP_SELL) 
               {
                  profit = NormalizeDouble((AvgPrice - Ask) / Point, 0);
                  if (profit < pType) continue;
                  stoptrade = OrderStopLoss();
                  stopcal = Ask + stop * Point;
                  if (stoptrade == 0.0 || (stoptrade != 0.0 && stopcal < stoptrade)) dummyResult = OrderModify(OrderTicket(), AvgPrice, stopcal, OrderTakeProfit(), 0, Red);
               }
            }
            Sleep(1000);
         }
      }
   }
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

double AccountEquityHigh() 
{
   if (CountTrades() == 0) AccountEquityHighAmt = AccountEquity();
   if (AccountEquityHighAmt < PrevEquity) AccountEquityHighAmt = PrevEquity;
   else AccountEquityHighAmt = AccountEquity();
   PrevEquity = AccountEquity();
   return (AccountEquityHighAmt);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

   double FindLastBuyPrice() 
   {
      double oldorderopenprice;
      int oldticketnumber;
      double unused = 0;
      int ticketnumber = 0;
      for (int tcnt = OrdersTotal() - 1; tcnt >= 0; tcnt--) 
      {
         dummyResult = OrderSelect(tcnt, SELECT_BY_POS, MODE_TRADES);
         if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_BUY) 
         {
            oldticketnumber = OrderTicket();
            if (oldticketnumber > ticketnumber) 
            {
               oldorderopenprice = OrderOpenPrice();
               unused = oldorderopenprice;
               ticketnumber = oldticketnumber;
            }
         }
      }
      
      return (oldorderopenprice);
   }

   double FindLastSellPrice() 
   {
      double oldorderopenprice;
      int oldticketnumber;
      double unused = 0;
      int ticketnumber = 0;
      for (int tcnt = OrdersTotal() - 1; tcnt >= 0; tcnt--) 
      {
         dummyResult = OrderSelect(tcnt, SELECT_BY_POS, MODE_TRADES);
         if (OrderSymbol() != Symbol() || OrderMagicNumber() != MagicNumber) continue;
         if (OrderSymbol() == Symbol() && OrderMagicNumber() == MagicNumber && OrderType() == OP_SELL) 
         {
            oldticketnumber = OrderTicket();
            if (oldticketnumber > ticketnumber) 
            {
               oldorderopenprice = OrderOpenPrice();
               unused = oldorderopenprice;
               ticketnumber = oldticketnumber;
            }
         }
      }
      return (oldorderopenprice);
   }
  
//***********************************************************************************************************************************
//***********************************************************************************************************************************

double PipStepExp(int Step)
{
   double QStepEx =  0;
   if(QuantumStep == true && Step >= StartStepExp)
   QStepEx = PipStepExponent;
   else
   QStepEx = 1;
   return (QStepEx);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

int TradeStepExp(int Trades)
{
   double TradeStep = 0;
   if(QuantumStep == true && Trades >= StartStepExp)
   TradeStep = Trades - StartStepExp + 1;
   else
   TradeStep = Trades;
   return (TradeStep);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

double TakeProfitExp(int Step)
{
   double QProfitEx =  0;
   if(ProfitQuantumStep == true && Step >= StartStepExpProfit)
   QProfitEx = TakeProfitExponent;
   else
   QProfitEx = 1;
   return (QProfitEx);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************

int TradeProfitStepExp(int Trades)
{
   double PTradeStep = 0;
   if(ProfitQuantumStep == true && Trades >= StartStepExpProfit)
   PTradeStep = Trades - StartStepExpProfit + 1;
   else
   PTradeStep = Trades;
   return (PTradeStep);
}

//***********************************************************************************************************************************
//***********************************************************************************************************************************