//+------------------------------------------------------------------+
//|                                                        L5_PM.mq4 |
//|                        Copyright 2014, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2014, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"
#property strict

extern int enMagic = 122;
extern double efSLPt = 10;
extern double efTPPt = 5;
extern double efBE = 3;
extern double efTS = 3;
extern double efTSS = 1;


#define MAX_ORDERS    10
#define NO_SLOT       -1
#define EMPTY_SLOT    -1

#define ID_TICKET     0
#define ID_CMD        1

#define ID_PRICE      0
#define ID_SL         1
#define ID_TP         2
#define ID_MAXPROFIT  3

double gfPtScale = 1;
int ganOrders[MAX_ORDERS,2];
double gafOrderDetail[MAX_ORDERS,4];

//+------------------------------------------------------------------+
int GetFirstOrder()
{
  int nResult=NO_SLOT;
  for (int i=0; i < MAX_ORDERS; i++)
    if (ganOrders[i,ID_TICKET] != EMPTY_SLOT)
    {
      nResult=i;
      break;
    }
  return(nResult);
}
//+------------------------------------------------------------------+
int GetNextOrder(int nSlot)
{
  int nResult=NO_SLOT;
  for (int i=nSlot+1; i < MAX_ORDERS; i++)
    if (ganOrders[i,ID_TICKET] != EMPTY_SLOT)
    {
      nResult=i;
      break;
    }
  return(nResult);
}
//+------------------------------------------------------------------+
int FindOrder(int nTicket)
{
  int nResult=NO_SLOT;
  for (int i=0; i < MAX_ORDERS; i++)
    if (ganOrders[i,ID_TICKET] == nTicket)
    {
      nResult=i;
      break;
    }
  return(nResult);
}
//+------------------------------------------------------------------+
int GetFreeSlot()
{
  int nResult=NO_SLOT;
  for (int i=0; i < MAX_ORDERS; i++)
    if (ganOrders[i,ID_TICKET] == EMPTY_SLOT)
    {
      nResult=i;
      break;
    }
  return(nResult);
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
void DeleteClosedOrders()
{
  int nSlot=GetFirstOrder();
  while (nSlot != NO_SLOT)
  {
    if (OrderSelect(ganOrders[nSlot,ID_TICKET],SELECT_BY_TICKET))
      if (OrderCloseTime() != 0)
      {
        Print("DeleteClosedOrders(): #",ganOrders[nSlot,ID_TICKET]," deeleted from processing list as closed");
        ganOrders[nSlot,ID_TICKET]=EMPTY_SLOT;
      }
    nSlot=GetNextOrder(nSlot);
  }
}
//+------------------------------------------------------------------+
void AddOrder()
{
  int nSlot=GetFreeSlot();
  
  if (nSlot == NO_SLOT)
  {
    Print("AddOrder(): No free slot found to place #",OrderTicket()," in processing list");
    return;
  }
  ganOrders[nSlot,ID_CMD]=OrderType();
  gafOrderDetail[nSlot,ID_PRICE]=OrderOpenPrice();
  switch(ganOrders[nSlot,ID_CMD]) {
    case(OP_BUY):
      gafOrderDetail[nSlot,ID_TP]=gafOrderDetail[nSlot,ID_PRICE]+efTPPt*Point*gfPtScale;
      gafOrderDetail[nSlot,ID_SL]=gafOrderDetail[nSlot,ID_PRICE]-efSLPt*Point*gfPtScale;
      break;
    case(OP_SELL):
      gafOrderDetail[nSlot,ID_TP]=gafOrderDetail[nSlot,ID_PRICE]-efTPPt*Point*gfPtScale;
      gafOrderDetail[nSlot,ID_SL]=gafOrderDetail[nSlot,ID_PRICE]+efSLPt*Point*gfPtScale;
      break;
    default: return;
  }
  gafOrderDetail[nSlot,ID_MAXPROFIT]=0;
  ganOrders[nSlot,ID_TICKET]=OrderTicket();
  Print("AddOrder(): #",ganOrders[nSlot,ID_TICKET]," added to processing list");
}
//+------------------------------------------------------------------+
void AddNewOrders()
{
  int nCnt=OrdersTotal();
  for (int i=0; i < nCnt; i++)
    if (OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
      if ((OrderSymbol() == Symbol()) && (OrderMagicNumber() == enMagic) &&
         ((OrderType() == OP_BUY) || (OrderType() == OP_SELL)))
        if (FindOrder(OrderTicket()) == NO_SLOT)
          AddOrder();
}
//+------------------------------------------------------------------+
void RecalcSL(int nSlot)
{
  double fProfit;
  double fNewSLPt;
  double fTSSCnt;
  double fTSSCnt1;
  
  if ((efBE == 0) && (efTS == 0))
    return;
  
  switch(ganOrders[nSlot,ID_CMD]) {
    case(OP_BUY):
      fProfit=(Bid-gafOrderDetail[nSlot,ID_PRICE])/Point/gfPtScale;
      break;
    case(OP_SELL):
      fProfit=(gafOrderDetail[nSlot,ID_PRICE]-Ask)/Point/gfPtScale;
      break;
    default: return;
  }
  
  if ((fProfit < 0) || (fProfit <= gafOrderDetail[nSlot,ID_MAXPROFIT]))
    return;
    
  gafOrderDetail[nSlot,ID_MAXPROFIT]=fProfit;
  
  if ((efBE != 0) && (efTS == 0))
  {
    if (fProfit < efBE)
      return;
    fNewSLPt=0;
  }
  else if ((efBE == 0) && (efTS != 0))
  {
    if (fProfit < efTS)
      return;
    fTSSCnt=MathFloor((fProfit-efTS)/efTSS);
    if (fTSSCnt == 0)
      return;
    fNewSLPt=efSLPt-fTSSCnt*efTSS;
  }
  else
  {
    if ((fProfit < efBE) && (fProfit < efTS))
      return;
    if ((fProfit > efBE) && (fProfit < efTS))
      fNewSLPt=0;
    else if ((fProfit < efBE) && (fProfit > efTS))
    {
      fTSSCnt=MathFloor((fProfit-efTS)/efTSS);
      if (fTSSCnt == 0)
        return;
      fNewSLPt=efSLPt-fTSSCnt*efTSS;
    }
    else
    {
      if (efTS >= efBE)
      {
        fTSSCnt=MathFloor((fProfit-efTS)/efTSS);
        fNewSLPt=-fTSSCnt*efTSS;
      }
      else
      {
        fTSSCnt1=MathFloor((efBE-efTS)/efTSS);
        fNewSLPt=efSLPt-fTSSCnt1*efTSS;
        if (fNewSLPt > 0)
          fNewSLPt=0;
        fTSSCnt=MathFloor((fProfit-efTS)/efTSS)-fTSSCnt1;
        fNewSLPt-=fTSSCnt*efTSS;
      }
    }
  }
  switch(ganOrders[nSlot,ID_CMD]) {
    case(OP_BUY):
      gafOrderDetail[nSlot,ID_SL]=gafOrderDetail[nSlot,ID_PRICE]-fNewSLPt*Point*gfPtScale;
      break;
    case(OP_SELL):
      gafOrderDetail[nSlot,ID_SL]=gafOrderDetail[nSlot,ID_PRICE]+fNewSLPt*Point*gfPtScale;
      break;
    default: return;
  }
  Print("RecalcSL(): SL of #",ganOrders[nSlot,ID_TICKET]," changed to ",fNewSLPt,"pt, and set to ",NormalizeDouble(gafOrderDetail[nSlot,ID_SL],Digits));
}
//+------------------------------------------------------------------+
void RecalcSLs()
{
  int nSlot=GetFirstOrder();
  while (nSlot != NO_SLOT)
  {
    if (OrderSelect(ganOrders[nSlot,ID_TICKET],SELECT_BY_TICKET))
      RecalcSL(nSlot);
    nSlot=GetNextOrder(nSlot);
  }
}
//+------------------------------------------------------------------+
void CloseByTPSL()
{
  int nSlot=GetFirstOrder();
  bool bNeedClose;
  double fPrice=0;
  color lClr=clrNONE;
  string cMsg;
  
  while (nSlot != NO_SLOT)
  {
    bNeedClose=false;
    switch(ganOrders[nSlot,ID_CMD]) {
      case(OP_BUY):
        if ((Bid >= gafOrderDetail[nSlot,ID_TP]) ||
            (Bid <= gafOrderDetail[nSlot,ID_SL]))
        {
          if (Bid >= gafOrderDetail[nSlot,ID_TP])
            cMsg="TP";
          else
            cMsg="SL";
          bNeedClose=true;
          fPrice=Bid;
          lClr=clrBlue;
        }
        break;
      case(OP_SELL):
        if ((Ask <= gafOrderDetail[nSlot,ID_TP]) ||
            (Ask >= gafOrderDetail[nSlot,ID_SL]))
        {
          if (Ask <= gafOrderDetail[nSlot,ID_TP])
            cMsg="TP";
          else
            cMsg="SL";
          bNeedClose=true;
          fPrice=Ask;
          lClr=clrRed;
        }
        break;
    }
    if (bNeedClose)
      if (OrderSelect(ganOrders[nSlot,ID_TICKET],SELECT_BY_TICKET))
        if (OrderClose(ganOrders[nSlot,ID_TICKET],OrderLots(),fPrice,5,lClr))
        {
          Print("CloseByTPSL(): #",ganOrders[nSlot,ID_TICKET]," closed by ",cMsg,", and removed from processing list");
          ganOrders[nSlot,ID_TICKET]=EMPTY_SLOT;
        }
    nSlot=GetNextOrder(nSlot);
  }
}
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//---
  if ((Digits==5) || (Digits==3))
    gfPtScale=10;
  else
    gfPtScale=1;
    
  for (int i=0; i < MAX_ORDERS; i++)
    ganOrders[i,ID_TICKET]=EMPTY_SLOT;
//---
  return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//---
  
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//---
  DeleteClosedOrders();
  AddNewOrders();
  RecalcSLs();
  CloseByTPSL();
}
//+------------------------------------------------------------------+
