
// Originated by Charvo @ Forexfactory.com

//+------------------------------------------------------------------+
//|              External Variables                                  |
//+------------------------------------------------------------------+


extern double AlertLvL4LONG               =    0;
extern double AlertLvL4SHOT               =    10000;
extern double deftTP               =    0;
extern double deftSL               =    0;
extern int    BEoffset                   =    2;


extern string OrderCMT              =    "";

extern int    SpreadCap             =    10;
extern string ClearanceNote         =    "must larger than BEoffset";
extern int    Clearance             =     10;

extern int    ScreenCorner          =     1;
extern bool   UsePresetAlert          =    false;
extern int    MagicBase             =    100;

//+------------------------------------------------------------------+
//|              Internal Variables                                  |
//+------------------------------------------------------------------+

int      MagicNumber, i, pairdigits, NumBuys, NumSels, TotalTrades, StartPos, EnteringDIR;
double   pairpoint, baseBuyAt, baseSelAt, HiBound, LoBound, allBuyLots, allSelLots, UseLots, NetExposure;
double   EAPL, DDpeak, EQpeak, BuyPL, SelPL, TPgoal;


double   LongAPL           = 0; //{0,0,0,0,0,0};
double   ShotAPL           = 0; //{0,0,0,0,0,0};
int   LongTickets[]           = {0,0,0,0,0,0};
int   ShotTickets[]           = {0,0,0,0,0,0};


double BuyPosTP, BuyPosSL, SelPosTP, SelPosSL;

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+

int init()
{   
   //MagicNumber = GetMagic4(Symbol());
   //Alert(WindowExpertName() +" price is " + EnteringDIR); //FreeRunner()
   if ( Digits == 3 || Digits == 5 ) 
   {
    SpreadCap = SpreadCap*10;
   }

   pairdigits = MarketInfo(Symbol(), MODE_DIGITS);
    
   if (pairdigits < 4)
      pairpoint = 0.01;
   else
      pairpoint = 0.0001;
   
   if (Symbol() == "XAUUSD")
   {
      SpreadCap = 1;
      pairpoint = 0.1;  
   }  

   LongAPL = AlertLvL4LONG;
   ShotAPL = AlertLvL4SHOT;
  
   Alert(WindowExpertName() + " init LongAPL is " + LongAPL);                      
   return (0);
   
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
int start()
{

   Count_Pos_Lots(); 
   
   NoPosReset();

   CheckAPL(); 

   PrintChartComments();
   
   UpdateDragAlertLvL();        
   //Alert(WindowExpertName() + "5 LongAPL is " + LongAPL);                      
   
   return(0);  
   
}

//+------------------------------------------------------------------+
// Start() finish.  All supporting routines FromBelow.
//+------------------------------------------------------------------+

void Count_Pos_Lots()
{
  NumBuys            =    0;
  BuyPL              =    0.0;
  allBuyLots         =    0.0;
  NumSels            =    0;
  SelPL              =    0.0;
  allSelLots         =    0.0;

  BuyPosTP           =     0;
  BuyPosSL           =     0;
  SelPosTP           =     0;
  SelPosSL           =     0;
   
  int m = 0;
  int n = 0;

  for (i = 0; i < OrdersTotal(); i++)
  {
    OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
    if (OrderSymbol() == Symbol() && OrderType() == OP_BUY && OrderComment() == OrderCMT )
    {
      BuyPL += OrderProfit() + OrderSwap() + OrderCommission();     
      allBuyLots += OrderLots();
      NumBuys++;
      
      BuyPosTP = OrderTakeProfit();
      BuyPosSL = OrderStopLoss();     
      
      LongTickets[m] = OrderTicket();
      m = m + 1;
      
      //ObjectDelete(LongTickets[m-1] + " L-APL");
      ObjectCreate(LongTickets[m-1] + " L-APL", OBJ_HLINE, 0, 0, LongAPL);

         ObjectSet(LongTickets[m-1] + " L-APL", OBJPROP_STYLE, STYLE_DASHDOT);
         ObjectSet(LongTickets[m-1] + " L-APL", OBJPROP_BACK, True);
         ObjectSet(LongTickets[m-1] + " L-APL", OBJPROP_COLOR, Lime);
         ObjectSet(LongTickets[m-1] + " L-APL", OBJPROP_WIDTH, 1);      
                            
    }

    if (OrderSymbol() == Symbol() && OrderType() == OP_SELL && OrderComment() == OrderCMT)
    {
      SelPL += OrderProfit() + OrderSwap() + OrderCommission();
      allSelLots += OrderLots();
      NumSels++;
      
      SelPosTP = OrderTakeProfit();
      SelPosSL = OrderStopLoss();      

      ShotTickets[n] = OrderTicket();
      n = n + 1;
     
      ObjectCreate(ShotTickets[n-1] + " S-APL", OBJ_HLINE, 0, 0, ShotAPL);

      ObjectSet(ShotTickets[n-1] + " S-APL", OBJPROP_STYLE, STYLE_DASHDOT);
      ObjectSet(ShotTickets[n-1] + " S-APL", OBJPROP_BACK, True);
      ObjectSet(ShotTickets[n-1] + " S-APL", OBJPROP_COLOR, Red);
      ObjectSet(ShotTickets[n-1] + " S-APL", OBJPROP_WIDTH, 1);
                    
    }
  }

  NetExposure    = MathAbs(allSelLots - allBuyLots);
  TotalTrades  = NumBuys + NumSels;
  
  return(0);
}


void CheckAPL()     // this sub examine if NOW is good time to start a trading sequence.
{
    
  
  for (i = 0; i < OrdersTotal(); i++)
  {
    OrderSelect(i,SELECT_BY_POS,MODE_TRADES);
   
   if ( OrderType() == OP_BUY && MarketInfo(Symbol(), MODE_BID) < LongAPL && OrderComment() == OrderCMT ) 
   {  
      JumpTP();
   }
      
   if ( OrderType() == OP_SELL && MarketInfo(Symbol(), MODE_BID) > ShotAPL && OrderComment() == OrderCMT )   
   {
      JumpTP();
   }
  }

}

void JumpTP()
{  
   bool BE;

      for(int n=0; n<OrdersTotal();n++)   
      {  
         OrderSelect(n, SELECT_BY_POS, MODE_TRADES);     

         if (OrderComment() == OrderCMT && OrderSymbol()==Symbol())
         {
            if ( OrderType() == OP_BUY && (OrderTakeProfit() > (OrderOpenPrice() + Clearance * pairpoint) || OrderTakeProfit() == 0) )
            {
               BE = OrderModify(OrderTicket(),OrderOpenPrice(),0, NormalizeDouble(OrderOpenPrice()+BEoffset*pairpoint, MarketInfo(Symbol(), MODE_DIGITS)), 0,Green);           
               if (BE) 
               {
                  Alert(WindowExpertName() + " BE a " + Symbol() + " pos, @ " + OrderOpenPrice() + ", @ " + TimeToStr(TimeCurrent(),TIME_MINUTES));
                  Print(WindowExpertName() + " BE a " + Symbol() + " pos, @ " + OrderOpenPrice() + ", @ " + TimeToStr(TimeCurrent(),TIME_MINUTES));
               }            
               else
               {
                  Alert(WindowExpertName() + " Failed to BE a " + Symbol() + " @ " + OrderOpenPrice() + ", @" + TimeToStr(TimeCurrent(),TIME_MINUTES) + " due to error " + GetLastError());            
                  Print(WindowExpertName() + " Failed to BE a " + Symbol() + " @ " + OrderOpenPrice() + ", @" + TimeToStr(TimeCurrent(),TIME_MINUTES) + " due to error " + GetLastError());            
               }
            }           
            if ( OrderType() == OP_SELL && (OrderTakeProfit() < (OrderOpenPrice() - Clearance * pairpoint) || OrderTakeProfit() == 0) )
            {
               BE = OrderModify(OrderTicket(),OrderOpenPrice(),0,NormalizeDouble(OrderOpenPrice()-BEoffset*pairpoint, MarketInfo(Symbol(), MODE_DIGITS)), 0,Green);           
               if (BE) 
               {
                  Alert(WindowExpertName() + " BE a " + Symbol() + " pos, @ " + OrderOpenPrice() + ", @ " + TimeToStr(TimeCurrent(),TIME_MINUTES));
                  Print(WindowExpertName() + " BE a " + Symbol() + " pos, @ " + OrderOpenPrice() + ", @ " + TimeToStr(TimeCurrent(),TIME_MINUTES));
               }            
               else
               {
                  Alert(WindowExpertName() + " Failed to BE a " + Symbol() + " @ " + OrderOpenPrice() + ", @ " + TimeToStr(TimeCurrent(),TIME_MINUTES) + " due to error " + GetLastError());            
                  Print(WindowExpertName() + " Failed to BE a " + Symbol() + " @ " + OrderOpenPrice() + ", @ " + TimeToStr(TimeCurrent(),TIME_MINUTES) + " due to error " + GetLastError());            
               }
            }                     
         }
      }

} 


void  NoPosReset()      // if no positions, but variables are used (after exiting a previous pos), reinit arrays, delete existing lines
{
   if (ArraySize(LongTickets) > 0 && NumBuys == 0)
   {
      for (i = ArraySize(LongTickets)-1;i>0;i--)
      {
         ObjectDelete(LongTickets[i-1] + " L-APL");
      }
      ArrayResize(LongTickets,0);
   }
   
   if (ArraySize(ShotTickets) > 0 && NumSels == 0)
   {
      for (i = ArraySize(ShotTickets)-1;i>0;i--)
      {
         ObjectDelete(ShotTickets[i-1] + " S-APL");
      }
      ArrayResize(ShotTickets, 0);      
   }

   return(0);
}


void UpdateDragAlertLvL()
{
   double DragLonglvl, DragShotlvl;  
   
   if (NumBuys > 0)
   {      
      for(i = ArraySize(LongTickets)-1;i>=0;i--)
      {  
         OrderSelect(LongTickets[i],SELECT_BY_TICKET);
         if (OrderSymbol() == Symbol() && OrderType() == OP_BUY && OrderComment() == OrderCMT )
         {
            DragLonglvl = NormalizeDouble(ObjectGet(LongTickets[i]+"-LONGapl",OBJPROP_PRICE1),MarketInfo(Symbol(), MODE_DIGITS));              
            Alert(WindowExpertName() + " in if Dragged LongAPL is @ " + DragLonglvl);   
            if(DragLonglvl != LongAPL)   
            {
            //ObjectDelete(LongTickets[0] + " L-APL");
            //ObjectCreate(LongTickets[0] + " L-APL", OBJ_HLINE, 0, 0, DragLonglvl);
            ObjectSet(LongTickets[0] + " L-APL", OBJPROP_STYLE, STYLE_DASHDOT);
            ObjectSet(LongTickets[0] + " L-APL", OBJPROP_BACK, True);
            ObjectSet(LongTickets[0] + " L-APL", OBJPROP_COLOR, Lime);
            ObjectSet(LongTickets[0] + " L-APL", OBJPROP_WIDTH, 1);      
            //LongAPL = DragLonglvl;            
            }
         }
      }
   }

   if (NumSels > 0)
   {
      for (i=ArraySize(ShotTickets)-1;i>=0;i--)
      {
         OrderSelect(ShotTickets[i],SELECT_BY_TICKET);      
         if (OrderSymbol() == Symbol() && OrderType() == OP_SELL && OrderComment() == OrderCMT )
         {
            DragShotlvl = NormalizeDouble(ObjectGet(ShotTickets[i]+"-SHOTapl",OBJPROP_PRICE1),MarketInfo(Symbol(), MODE_DIGITS));              
            if(DragShotlvl != ShotAPL)   ShotAPL = DragShotlvl;
         }      
      }
   }   
   
   return(0);
}     

void PrintChartComments()
{
      string commentStr;
      int PipDist2Long, PipDist2Short;
      
      if (LongAPL > 0)  PipDist2Long   = (-LongAPL + MarketInfo(Symbol(), MODE_BID))/pairpoint;
      if (ShotAPL > 0)  PipDist2Short  = (ShotAPL - MarketInfo(Symbol(), MODE_BID))/pairpoint;

      commentStr = Symbol() + "L: Lot: " + DoubleToStr(allBuyLots,2) + "; APL: " + DoubleToStr(LongAPL, MarketInfo(Symbol(), MODE_DIGITS)) + "; from Bid: " + PipDist2Long + "; TP: " + DoubleToStr(BuyPosTP,MarketInfo(Symbol(), MODE_DIGITS)) + ";"; 
      if (NumBuys > 0)   printComment_l(commentStr, 2, 40, 1);

      commentStr = Symbol() + "S: Lot: " + DoubleToStr(allSelLots,2) + "; APL: " + DoubleToStr(ShotAPL, MarketInfo(Symbol(), MODE_DIGITS)) + "; from Bid: " + PipDist2Short + "; TP: " + DoubleToStr(SelPosTP,MarketInfo(Symbol(), MODE_DIGITS)) + ";"; 
      if (NumSels > 0)   printComment_l(commentStr, 3, 65, 3);          
}

void printComment_l(string commentStr, int i, int j, int colorcode)
{  

            ObjectCreate("TradeComment"+i,OBJ_LABEL,0,0,0);
            ObjectSet("TradeComment"+i,OBJPROP_CORNER,ScreenCorner);
            ObjectSet("TradeComment"+i,OBJPROP_XDISTANCE,5);
            ObjectSet("TradeComment"+i,OBJPROP_YDISTANCE,j);             

            if (colorcode == 1)  ObjectSetText("TradeComment"+i,commentStr,12,"Courier New Bold",Lime);
            if (colorcode == 2)  ObjectSetText("TradeComment"+i,commentStr,12,"Courier New Bold",DeepSkyBlue);
            if (colorcode == 3)  ObjectSetText("TradeComment"+i,commentStr,12,"Courier New Bold",DeepPink);      
}

void StringSplitToReals(string InputString, string Separator, double & ResultArray[])
{
   ArrayResize(ResultArray, 0);
   int lenSeparator = StringLen(Separator), NewArraySize;
   while (InputString != "") 
   {
      int p = StringFind(InputString, Separator);
      if (p == -1) {
         NewArraySize = ArraySize(ResultArray) + 1;
         ArrayResize(ResultArray, NewArraySize);      
         ResultArray[NewArraySize - 1] = StrToDouble(InputString);
         InputString = "";
      } else {
         NewArraySize = ArraySize(ResultArray) + 1;
         ArrayResize(ResultArray, NewArraySize);      
         ResultArray[NewArraySize-1] = StrToDouble(StringSubstr(InputString, 0, p));
         InputString = StringSubstr(InputString, p + lenSeparator);
         if (InputString == "")
         {
            ArrayResize(ResultArray, NewArraySize + 1);      
            ResultArray[NewArraySize] = 0;
         }

      }     
   }
}


// take the 1st, 4th, and 6th letters of a pair name to make a magicNO.
/*int GetMagic4(string  symbol)
{
   string MagicStr;
   int    MagicLength, MagicNO;
   
   //if (StringLen(symbol) == 6)
   //{
      MagicStr = DoubleToStr(StringGetChar(symbol, 0),0) + DoubleToStr(StringGetChar(symbol, 2),0) + DoubleToStr(StringGetChar(symbol, 3),0);// + DoubleToStr(StringGetChar(symbol, 5),0);
      MagicLength = StringLen(MagicStr);
      MagicNO  = StrToInteger(MagicStr);
      
   //}   
   MagicNO  = MagicBase * MathPow(10, MagicLength) + MagicNO;    
   Alert(WindowExpertName() + " use MN: " + MagicNO + " for " + Symbol() + ".");
   return(MagicNO);
}*/


/*
void DrawBElvls(int dir, double fromlevel)
{
   // there is no 'pip' involved in calculation

   double DD, BEdist, BElvl;
      
   if (dir == 1)
   {
      DD = allSelLots * (HierLvl - AlertLvL);
      BEdist = DD / NetExposure;
      BElvl  = fromlevel + BEdist;
   }

   if (dir == -1)
   {
      DD = allBuyLots * (HierLvl - AlertLvL);
      BEdist = DD / NetExposure;
      BElvl  = fromlevel - BEdist;
   }

   ObjectDelete("BE_level");
   ObjectCreate("BE_level", OBJ_HLINE, 0, 0, BElvl);
   ObjectSet("BE_level", OBJPROP_STYLE, STYLE_SOLID);
   ObjectSet("BE_level", OBJPROP_BACK, True);
   ObjectSet("BE_level", OBJPROP_COLOR, Green);
   ObjectSet("BE_level", OBJPROP_WIDTH, 1);

}*/


