//+------------------------------------------------------------------+
//|                                      Waimate Slope Direction.mq4 |
//|                                                       bfis108137 |
//|                                             baaaaaary at msn.com |
//+------------------------------------------------------------------+



#include <Arrays\ArrayInt.mqh>
#include <Arrays\List.mqh>
//--- input parameters
input int   RSIPeriod=13;
input int   CCIPeriod=21;
input int   MFIPeriod=13;
input int   WPRPeriod=55;
input int   DeMarkerPeriod=13;
input int   MomentumPeriod=10;
input int   StdDevPeriod=8;
input int   RSIPrice          = PRICE_CLOSE;
input int   CCIPrice          = PRICE_TYPICAL;
input int   MFIPrice          = PRICE_CLOSE;
input int   WPRPrice          = PRICE_CLOSE;
input int   DeMarkerPrice     = PRICE_CLOSE;
input int   MomentumPrice     = PRICE_CLOSE;
input int   StdDevPrice       = PRICE_CLOSE;
input int   barsToCheck=1000;


input double   SignalLineTop=0.0001;
input double   SignalLineBot=-0.0001;
input double   lots=0.01;
input double   lotsIncrement=0.01;
input int      pipsAgainst=100;   
input int      slippage=30;
input int      magic=358312356;
input int      AtrPeriods=8;
input double   SlAtrMult=0;
input double   TpAtrMult=3;
input double   maxLossPercent=1;
input double   maxProfitPercent=0.0001;

bool setSlTp=false;
int removeSlTpType=-1;
//int      sl=0;
CArrayInt toClose;
CArrayInt toDefineSlTp;
CList toSetTpSl;
datetime last;
int toPlace = -1;
double lotsToPlace = -1;
double pipsAgainstReal;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
      pipsAgainstReal = pipsAgainst * Point;
      last = Time[0]; 
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
   
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
      CheckMaxProfitLoss(0);
      CheckMaxProfitLoss(1);
      PlaceOrder(setSlTp);
      DefineSlTp();
      SetSlTp();
      CloseOrders();
      RemoveSlTpOfType();
      
      double sig = SignalCheck();      
      bool longExists = OrderTypeCount(0) > 0;
      bool shortExists = OrderTypeCount(1) > 0;
      double lastLots = 0;
      if(sig == -1 && !longExists && !shortExists)return;
      if(sig == 0 && !longExists)
      {
         toPlace = 0;
         setSlTp = true;
         lotsToPlace = lots;
         return;
      }
      if(sig == 1 && !shortExists)
      {
         toPlace = 1;
         setSlTp = true;
         lotsToPlace = lots;
         return;
      }
      if(longExists)
      {
         double lastLong = GetLastEntry(0,lastLots);
         double nextLong = lastLong - pipsAgainstReal;
         if(Ask <= nextLong)
         {
            toPlace = 0;
            setSlTp = true;
            lotsToPlace = lastLots + lotsIncrement; 
            //removeSlTpType = 0;
         }
      }
      else if(shortExists)
      {
         double lastShort = GetLastEntry(1,lastLots);
         double nextShort = lastShort + pipsAgainstReal;
         if(Bid >= nextShort)
         {
            toPlace = 1;
            setSlTp = true;
            lotsToPlace = lastLots + lotsIncrement;
            //removeSlTpType = 1;
         }
      }
  }
  
  double GetIndicatorValue(int candle)
  {
      double RSI = iRSI(NULL,0,RSIPeriod,RSIPrice,candle);
      double CCI = iCCI(NULL,0,CCIPeriod,CCIPrice,candle);
      double MFI = iMFI(NULL,0,MFIPeriod,candle);
      double WPR = iWPR(NULL,0,WPRPeriod,candle);
      double DeMarker = iDeMarker(NULL,0,DeMarkerPeriod,candle);
      double Momentum = iMomentum(NULL,0,MomentumPeriod,MomentumPrice,candle);
      double StdDev = iStdDev(NULL,0,StdDevPeriod,0,MODE_EMA,StdDevPrice,candle);
      double result = (((RSI-50) + ((DeMarker*100)-50) + (MFI-50) + (WPR+50) + ((Momentum -100)*10))/5)/StdDev ;
      return(result);
  }
//+------------------------------------------------------------------+

int SignalCheck()
{
   double indi = GetIndicatorValue(0);
   if(indi >= SignalLineTop)return(1);
   if(indi <= SignalLineBot)return(0);
   return(-1);
}

double GetSlPips()
{
   return(Atr() * SlAtrMult);
}

double GetTpPips()
{
   return(Atr() * TpAtrMult);
}

double Atr()
{
   return(iATR(Symbol(),0,AtrPeriods,0));
}

int Signal(int cndl)
{
   
   return(-1);
}

int GetDir(int cndl)
{
   return(-1);
}

double GetLastEntry(int type, double& lastLots)
{
   double lastEntry = 0;
   lastLots = 0;
   for(int i=OrdersTotal()-1;i>=0;i--)
   {
      if(!OrderSelect(i,SELECT_BY_POS))continue;
      if(OrderMagicNumber() != magic)continue;
      if(OrderSymbol() != Symbol())continue;
      if(OrderType() != type)continue;
      if(lastEntry == 0)
      {
         lastLots = OrderLots();
         lastEntry = OrderOpenPrice();
         continue;
      }
      switch(type)
      {
         case 0:
         if(OrderOpenPrice() < lastEntry)
         {
            lastEntry = OrderOpenPrice();
            lastLots = OrderLots();
         }
         break;
         case 1:
         if(OrderOpenPrice() > lastEntry)
         {
            lastEntry = OrderOpenPrice();
            lastLots = OrderLots();
         }
         break;
      }
   }
   return(lastEntry);
}

void CloseOrdersOfType(int type)
{
   for(int i=OrdersTotal()-1;i>=0;i--)
   {
      if(!OrderSelect(i,SELECT_BY_POS))continue;
      if(OrderMagicNumber() != magic)continue;
      if(OrderSymbol() != Symbol())continue;
      if(OrderType() != type)continue;
      toClose.Add(OrderTicket());
   }
}

void CheckMaxProfitLoss(int type)
{
   if(OrderTypeCount(type) < 2)return;
   double prct = GetProfitLossPercent(type);
   bool close = false;
   if(prct > 0 && prct >= maxProfitPercent)close = true;
   if(prct < 0 && MathAbs(prct) > maxLossPercent)close = true;
   if(close)
   {
      CloseOrdersOfType(type);
      if(toPlace ==  type)
      {
         toPlace = -1;
         removeSlTpType = -1;         
      }
   }
}

double GetProfitLossPercent(int type)
{
   double totProfit = 0;
   for(int i=OrdersTotal()-1;i>=0;i--)
   {
      if(!OrderSelect(i,SELECT_BY_POS))continue;
      if(OrderMagicNumber() != magic)continue;
      if(OrderSymbol() != Symbol())continue;
      if(OrderType() != type)continue;
      totProfit += OrderProfit();
   }
   double bal = AccountCredit() + AccountBalance();
   double prct = totProfit / bal;
   return(prct);
}

void RemoveSlTpOfType()
{
   if(removeSlTpType == -1)return;
   for(int i=OrdersTotal()-1;i>=0;i--)
   {
      if(!OrderSelect(i,SELECT_BY_POS))return;
      if(OrderMagicNumber() != magic)continue;
      if(OrderSymbol() != Symbol())continue;
      if(OrderType() != removeSlTpType)continue;
      if(OrderTakeProfit() == 0 && OrderStopLoss() == 0)continue;
      if(!OrderModify(OrderTicket(),OrderOpenPrice(),0,0,OrderExpiration()))return;
   }
   removeSlTpType = -1;
}

int OrderExists()
{
   for(int i=0;i<OrdersTotal();i++)
   {
      if(!OrderSelect(i,SELECT_BY_POS))continue;
      if(OrderMagicNumber() != magic)continue;
      if(OrderSymbol() != Symbol())continue;
      if(OrderType() > 1)continue;
      return(OrderType());
   }
   return(-1);
}

int OrderTypeCount(int orderType)
{
   int ct = 0;
   for(int i=0;i<OrdersTotal();i++)
   {
      if(!OrderSelect(i,SELECT_BY_POS))continue;
      if(OrderMagicNumber() != magic)continue;
      if(OrderSymbol() != Symbol())continue;
      if(OrderType() == orderType)ct++;
   }
   return(ct);
}

void CloseOrders()
{
   for(int i=toClose.Total()-1;i>=0;i--)
   {
      //this could happen after removing an element
      if(i >= toClose.Total())continue;
      if(!OrderSelect(toClose[i],SELECT_BY_TICKET))continue;
      if(OrderClose(toClose[i],OrderLots(),OrderClosePrice(),slippage))toClose.Delete(i);
   }
}

void DefineSlTp()
{
   for(int i=toDefineSlTp.Total()-1;i>=0;i--)
   {
      if(i >= toDefineSlTp.Total())continue;
      int t = toDefineSlTp[i];
      if(OrderTicket() != t)
      {
         if(!OrderSelect(t,SELECT_BY_TICKET))
         {
            toDefineSlTp.Delete(i);
            continue;
         }
      }
      SlTpToSet *slTp = new SlTpToSet(t);
      if(OrderType() == 0)
      {
         if(SlAtrMult > 0)slTp.slToSet = OrderOpenPrice() - GetSlPips();
         if(TpAtrMult > 0)slTp.tpToSet = OrderOpenPrice() + GetTpPips();
      }
      else if(OrderType() == 1)
      {
         if(SlAtrMult > 0)slTp.slToSet = OrderOpenPrice() + GetSlPips();
         if(TpAtrMult > 0)slTp.tpToSet = OrderOpenPrice() - GetTpPips();
      }
      if(slTp.slToSet + slTp.tpToSet > 0)toSetTpSl.Add(slTp);
      toDefineSlTp.Delete(i);
   }   
}

void SetSlTp()
{
   for(int i=toSetTpSl.Total()-1;i>=0;i--)
   {
      if(i >= toSetTpSl.Total())continue;
      SlTpToSet *slTp = toSetTpSl.GetNodeAtIndex(i);
      if(slTp == NULL)
      {
         //toSetTpSl.MoveToIndex(i);
         continue;
      }
      if(!OrderSelect(slTp.ticket,SELECT_BY_TICKET))continue;      
      if(OrderModify(slTp.ticket,OrderOpenPrice(),slTp.slToSet,slTp.tpToSet,OrderExpiration()))
      {
         toSetTpSl.MoveToIndex(i);
         toSetTpSl.DetachCurrent();
         delete slTp;
      }
   }   
}

void PlaceOrder(bool setSlTp=true)
{
   if(toPlace == -1)return;
   double prc = 0;
   if(toPlace == 0)prc = Ask;
   else if(toPlace == 1)prc = Bid;
   int t = OrderSend(Symbol(),toPlace,lotsToPlace,prc,slippage,0,0,"",magic);
   if(t > 0)
   {
      toPlace = -1;
      if(setSlTp)toDefineSlTp.Add(t);
   }
}

class SlTpToSet : CObject
{
   public:
      SlTpToSet(int t);
      SlTpToSet(int t, double slIn, double tpIn);
     ~SlTpToSet(void);
     int ticket;
     double slToSet;
     double tpToSet;
};

SlTpToSet::SlTpToSet(int t)
{
   this.ticket = t;
   this.slToSet = 0;
   this.tpToSet = 0;
}

SlTpToSet::SlTpToSet(int t,double slIn,double tpIn)
{
   this.ticket = t;
   this.slToSet = slIn;
   this.tpToSet = tpIn;
}

SlTpToSet::~SlTpToSet(void){}