/*
 - use the OrderComment to manage only these orders 
*/
#property copyright "Copyright 2020, TradingToolCrypto Corp."
#property link      "https://github.com/tradingtoolcrypto"
#property version   "1.00"

#include <Trade\Trade.mqh>
//#include <TradingToolCrypto\CBP\CryptoBridgeProClass.mqh>

CPositionInfo m_position; // trade position object
CTrade m_trade;           // trading object
COrderInfo m_order;


input group "----------- ROBOT ------------";
input string OrderComment ="ROBOT";
input bool PopupAlert = false;
input bool AllowBuy = true;
input bool AllowSell = true;
input double BuyLotsize = 1.0;
input double SellLotsize = 1.0;

input group "----------- ROBOT Pending Orders ------------";
input bool DeletePending = false;
input int DaysAfter = 1;

input group "----------- ROBOT TP SL  ------------";
input bool PercentageBasedTargets = false;
input double StoplossPercentage = 1.0;
input double RiskReward = 5;

input bool TargetsByPoints = false;
input double TakeProfitInPoints = 50000;
input double StopLossInPoints = 50000;

input group "----------- ROBOT Trailing SL  ------------";
input bool   TrailingAtPoints = false;
input double StartAtPointsInProfit = 5000;
input double StartAtPoints = 4500;
input double TrailingValue = 1000;
input double TrailingStep =  100;

input bool   TrailingAtFractal = false;
input bool   FractalInProfit = false;

input group "----------- INDICATORS ------------";
input group "----------- ZIG-ZAG ------------";
input string FolderLocationZigZag = "Job\\ZigFib";

input int ZigZag_LookBackBars = 12;
input int ZigZag_MinSwingSize = 0;

input group "----------- EMA ------------";
input string FolderLocationEMA = "Job\\vidya";
input bool UseEMALogic = false;
input int CMO_Period_Fast = 9;
input int CMO_Period_Slow = 9;

input int EMA_Period_Fast = 34;
input int EMA_Period_Slow = 35;

input int EMA_Shift_Fast = 0;
input int EMA_Shift_Slow = 0;

input group "----------- BROKER------------";
input bool SendToBroker = true;
input group "----------- EXCHANGE ------------";
input bool SendToExchange = false;

int Zig_handle;
int EMA1_handle;
int EMA2_handle;
int Fractal_handle;
string WHAT_MARKET;

int digitV = 0;
int digitQ = 0;
double points;

//CryptoBridge bridge;      // cryptoBridge class


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {

//  if(bridge.Init_Api_Keys(Exchange_Number))
//    {
//    Print("Api Keys Loaded ");
//   }

   WHAT_MARKET = Symbol();

   digitQ = SymbolInfoInteger(WHAT_MARKET,SYMBOL_DIGITS);
   digitV = SymbolInfoInteger(WHAT_MARKET,SYMBOL_VOLUME);
   points = SymbolInfoDouble(WHAT_MARKET,SYMBOL_POINT);



//            =============================    "Examples\\Custom Moving Average",
   Zig_handle =   iCustom(WHAT_MARKET,PERIOD_CURRENT,FolderLocationZigZag, ZigZag_LookBackBars, ZigZag_MinSwingSize);
   Print(" HANDLE ZIG " + IntegerToString(Zig_handle));

   if(UseEMALogic)
     {
      EMA1_handle =   iCustom(WHAT_MARKET,PERIOD_CURRENT,FolderLocationEMA,CMO_Period_Fast, EMA_Period_Fast, EMA_Shift_Fast);
      EMA2_handle =   iCustom(WHAT_MARKET,PERIOD_CURRENT,FolderLocationEMA,CMO_Period_Slow, EMA_Period_Slow, EMA_Shift_Slow);
      Print(" HANDLE EMA FAST " + IntegerToString(EMA1_handle));
      Print(" HANDLE EMA SLOW  " + IntegerToString(EMA2_handle));
     }

   if(TrailingAtFractal)
     {
      Fractal_handle = iFractals(WHAT_MARKET,PERIOD_CURRENT);
      Print(" HANDLE FRACTALS " + IntegerToString(Fractal_handle));
     }

//---
   return(INIT_SUCCEEDED);
  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+

double Buy = 0;
double Sell = 0;
double high = 0;
double low = 0;
double high_bar = 0;
double low_bar = 0;
double open_bar = 0;
double close_bar = 0;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnTick()
  {


   if(DeletePending)
     {
      delete_all(DaysAfter);
     }


   place_tp_sl();


   if(TrailingAtPoints && !TrailingAtFractal)
     {
      place_trailing_points();
     }

   if(TrailingAtFractal && !TrailingAtPoints)
     {
      if(fractal_down != 0 && fractal_up != 0)
        {
         place_trailing_fractals();
        }
     }


   /*
   compare the current bar Hi and low and make sure that the zig high or low are not the same
   - we don't want to fire a signal when the repainting is taking place
   Print(" HIGH " + high + " LOW " + low);
   */

   if(IsNewBar(WHAT_MARKET))
     {
      /*
      Get the Fractal data at each new bar
      */
      if(TrailingAtFractal)
        {
         fractals();
        }


      /*
      get the zig zag data
      */
      get_signal_zig();
      high = zig_high();
      low = zig_low();
      /*
      get the bar data
      */
      high_bar = iHigh(WHAT_MARKET,PERIOD_CURRENT,1);
      low_bar = iLow(WHAT_MARKET,PERIOD_CURRENT,1);
      open_bar = iOpen(WHAT_MARKET,PERIOD_CURRENT,1);
      close_bar = iClose(WHAT_MARKET,PERIOD_CURRENT,1);


      /*
      make sure the current bar is not the current high
      - last bar is bearish
      */

      if(Buy != high && high_bar < high && close_bar < open_bar)
        {

         Buy = high;

         if(AllowBuy)
           {
            if(UseEMALogic)
              {
               if(!ema_bullish())
                 {
                  place_order("buy", Buy);
                 }
              }
            else
              {
               place_order("buy", Buy);
              }
           }
        }
      /*
      make sure the current bar is not the current low
      - last bar is bullish
      */
      if(Sell != low && low_bar > low && close_bar > open_bar)
        {

         Sell = low;
         if(AllowSell)
           {
            if(UseEMALogic)
              {
               if(ema_bullish())
                 {
                  place_order("sell", Sell);

                 }
              }
            else
              {
               place_order("sell", Sell);
              }
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsNewBar(string sym_name)
  {

   static datetime last;

   datetime now = iTime(sym_name, NULL, 0);

   if(now > last)
     {

      last = now;
      return (true);
     }
   return (false);
  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void place_order(string side, double price)
  {

   if(PopupAlert)
     {
      Alert("New signal | Type: " + side + " at price: " + DoubleToString(price,digitQ));
     }


   if(side == "buy" && SendToBroker)
     {
      m_trade.OrderOpen(WHAT_MARKET, ORDER_TYPE_BUY_STOP, NormalizeDouble(BuyLotsize, 2), price, price, 0, 0, ORDER_TIME_GTC, 0, OrderComment);
     }

   if(side == "buy" && SendToExchange)
     {
      int random = MathRand();
      //bridge.Open_Trade(Exchange_Symbol_Name, "BUY", "STOP_LOSS", Exchange_Lotsize, price,digitQ,digitV, Exchange_Number,OrderComment +random);
     }

   if(side == "sell" && SendToBroker)
     {
      m_trade.OrderOpen(WHAT_MARKET, ORDER_TYPE_SELL_STOP, NormalizeDouble(SellLotsize, 2), price, price, 0, 0, ORDER_TIME_GTC, 0, OrderComment);
     }

   if(side == "sell" && SendToExchange)
     {
      int random = MathRand();
      //  bridge.Open_Trade(Exchange_Symbol_Name, "SELL", "STOP_LOSS", Exchange_Lotsize, price,digitQ,digitV, Exchange_Number,OrderComment +random);
     }

  }



double EMA1_Buffer[];
double EMA2_Buffer[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool ema_bullish()
  {

   CopyBuffer(EMA1_handle, 0, 0, EMA_Period_Fast+1, EMA1_Buffer);
   CopyBuffer(EMA2_handle, 0, 0, EMA_Period_Slow+1, EMA2_Buffer);

// the indicator arrays
   ArraySetAsSeries(EMA1_Buffer, true);
   ArraySetAsSeries(EMA2_Buffer, true);

   double fast = EMA1_Buffer[0];
   double slow = EMA2_Buffer[0];

   if(fast>slow)
     {
      return(true);
     }


   return(false);



// Print("EMA FAST " + fast + " EMA SLOW " + slow);

  }

/*

 loop through the zig zag buffers with the correct Bar[] that identified the peak and valleys from the indicator outputs
 - save the prices into 3 values and sort them to get the Highest high and the lowest lows
   - value goes into the zig1,2,3

*/
double Buffer1[],  Buffer2[],  Buffer3[];
double zig1,zig2,zig3;
void get_signal_zig()
  {

   int bar1 = (int)   GlobalVariableGet("ZigFib1");
   int bar2 = (int)    GlobalVariableGet("ZigFib2");
   int bar3 = (int)    GlobalVariableGet("ZigFib3");
   /*

   2 Buffers exist within the zig zag indicator

   */
   CopyBuffer(Zig_handle, 0, 0, bar3+1, Buffer1);
   CopyBuffer(Zig_handle, 1, 0, bar3+1, Buffer2);
//  CopyBuffer(Zig_handle, 2, 0, bar3+1, Buffer3);

// the indicator arrays
   ArraySetAsSeries(Buffer1, true);
   ArraySetAsSeries(Buffer2, true);
// ArraySetAsSeries(Buffer3, true);

   /*

   Need to check every buffer with the Zig[bars] and check the value

   */

   double x = Buffer1[bar1];
   double y = Buffer2[bar1];
// double z = Buffer3[bar1];

   double x2 = Buffer1[bar2];
   double y2 = Buffer2[bar2];
//  double z2 = Buffer3[bar2];

   double x3 = Buffer1[bar3];
   double y3 = Buffer2[bar3];
//  double z3 = Buffer3[bar3];
   bool debug_zig = false;
//-------
   if(x>0 && x != EMPTY_VALUE)
     {
      zig1 = x;
     }
   if(y>0 && y != EMPTY_VALUE)
     {
      zig1 = y;
     }
//-------
   if(x2>0 && x2 != EMPTY_VALUE)
     {
      zig2 = x2;
     }

   if(y2>0 && y2 != EMPTY_VALUE)
     {
      zig2 = y2;
     }
//-------
   if(x3>0 && x3 != EMPTY_VALUE)
     {
      zig3 = x3;
     }

   if(y3>0 && y3 != EMPTY_VALUE)
     {
      zig3 = y3;
     }
//  Print("ZIG1 - " + zig1 +  " | ZIG2 - " + zig2 + " | ZIG3 - " + zig3);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double zig_high()
  {
   double h =  fmax(zig1,zig2);
   h =  fmax(h,zig3);
   return(h);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double zig_low()
  {
   double l =  fmin(zig1,zig2);
   l =  fmin(l,zig3);
   return(l);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void place_tp_sl()
  {
   int buy = 0;
   int sell = 0;
   double entry_sell = 0;
   double entry_buy = 0;
   uint total = PositionsTotal();
   
   if(total == 0)
   {
      return;
   }

   for(uint i = 0; i < total; i++)
     {
      ulong ticket = PositionGetTicket(i);
      if(PositionSelectByTicket(ticket))
        {
         string position_symbol = PositionGetString(POSITION_SYMBOL);

         if(position_symbol == WHAT_MARKET &&
            PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY &&
            PositionGetString(POSITION_COMMENT) == OrderComment)
           {

            buy++;
            entry_buy = PositionGetDouble(POSITION_PRICE_OPEN);
            /*

            create a tp and sl

            */
            if(PercentageBasedTargets)
              {
               double stop = entry_buy - (entry_buy* (StoplossPercentage*0.01));
               double profit = entry_buy + ((entry_buy* (StoplossPercentage*0.01) *RiskReward));
               if(PositionGetDouble(POSITION_SL) == 0)
                 {
                  m_trade.PositionModify(ticket,stop, profit);
                 }
              }

            if(TargetsByPoints)
              {
               double stop = entry_buy - (StopLossInPoints * points);
               double profit = entry_buy + (TakeProfitInPoints * points);
               if(PositionGetDouble(POSITION_SL) == 0)
                 {
                  m_trade.PositionModify(ticket,stop, profit);
                 }
              }

           }

         if(position_symbol == WHAT_MARKET &&
            PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL &&
            PositionGetString(POSITION_COMMENT) == OrderComment)
           {

            sell++;
            entry_sell = PositionGetDouble(POSITION_PRICE_OPEN);
            /*

            create a tp and sl

            */
            if(PercentageBasedTargets)
              {
               double stop = entry_sell + (entry_sell* (StoplossPercentage*0.01));
               double profit = entry_sell - ((entry_sell* (StoplossPercentage*0.01) *RiskReward));
               if(PositionGetDouble(POSITION_SL) == 0)
                 {
                  m_trade.PositionModify(ticket,stop, profit);
                 }
              }

            if(TargetsByPoints)
              {
               double stop = entry_sell + (StopLossInPoints * points);
               double profit = entry_sell - (TakeProfitInPoints * points);
               if(PositionGetDouble(POSITION_SL) == 0)
                 {
                  m_trade.PositionModify(ticket,stop, profit);
                 }
              }


           }
        }
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void place_trailing_points()
  {

   ulong ticket=0;
   double price=0;
   double entryprice=0;
   double sl=0;
   double prev_sl=0;
   double prev_tp=0;

   /*
   input double StartAtPointsInProfit = 5000;
   input double StartAtPoints = 4500;
   input double TrailingValue = 1000;
   input double TrailingStep =  100;
   */

   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      if(m_position.SelectByIndex(i))
        {
         // Print(" OrderType: " + m_position.PositionType() +" PositionGetInteger: " +  PositionGetInteger(POSITION_TYPE)  );

         // BUY POSITION
         if(m_position.Symbol() == WHAT_MARKET && m_position.PositionType() == 0 && m_position.Comment() ==  OrderComment)
           {
            ticket = m_position.Ticket();
            price = m_position.PriceCurrent();
            entryprice = m_position.PriceOpen();
            prev_sl = m_position.StopLoss();
            prev_tp = m_position.TakeProfit();
            sl =0;


            if(prev_sl < entryprice)
              {
               if(price  >= entryprice + StartAtPointsInProfit*points)
                 {
                  sl = entryprice + StartAtPoints*points;
                 }
              }
            else
              {

               if((price - prev_sl) + TrailingValue*points > TrailingValue*points)
                 {
                  if(price - TrailingValue*points > prev_sl)
                    {
                     sl = price - TrailingValue*points;
                    }
                 }
              }

            if(sl != 0)
              {
               if(NormalizeDouble(prev_sl,digitQ) != NormalizeDouble(sl,digitQ))
                 {
                  Print("BUY position.StopLoss " + DoubleToString(prev_sl,8)  + " Does NOT == " + DoubleToString(sl,8));

                  if(m_trade.PositionModify(ticket, NormalizeDouble(sl,digitQ), prev_tp))
                    {
                     Print("Trailing #1 BUY position.Ticket " + IntegerToString(ticket)  + " SL Modified to " + DoubleToString(sl,digitQ));
                    }

                 }

              }
           }
        }

      // SELL POSITION
      if(m_position.Symbol() == WHAT_MARKET && m_position.PositionType() == 1 && m_position.Comment() ==  OrderComment)
        {
         ticket = m_position.Ticket();
         price = m_position.PriceCurrent();
         entryprice = m_position.PriceOpen();
         prev_sl = m_position.StopLoss();
         prev_tp = m_position.TakeProfit();
         sl =0;


         if(prev_sl > entryprice)
           {
            if(price  <= entryprice - StartAtPointsInProfit*points)
              {
               sl = entryprice - StartAtPoints*points;
              }
           }
         else
           {

            if((prev_sl-price) - TrailingValue*points > TrailingValue*points)
              {
               if(price + TrailingValue*points < prev_sl)
                 {
                  sl = price + TrailingValue*points;
                 }
              }
           }

         if(sl != 0)
           {
            if(NormalizeDouble(prev_sl,digitQ) != NormalizeDouble(sl,digitQ))
              {
               Print("SELL position.StopLoss " + DoubleToString(prev_sl,8)  + " Does NOT == " + DoubleToString(sl,8));

               if(m_trade.PositionModify(ticket, NormalizeDouble(sl,digitQ), prev_tp))
                 {
                  Print("Trailing #1 BUY position.Ticket " + IntegerToString(ticket)  + " SL Modified to " + DoubleToString(sl,digitQ));
                 }

              }
           }

        }
     }

  }


//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void place_trailing_fractals()
  {

   ulong ticket=0;
   double price=0;
   double entryprice=0;
   double sl=0;
   double prev_sl=0;
   double prev_tp=0;




   /*
   input double StartAtPointsInProfit = 5000;
   input double StartAtPoints = 4500;
   input double TrailingValue = 1000;
   input double TrailingStep =  100;
   */

   for(int i = PositionsTotal() - 1; i >= 0; i--)
     {
      if(m_position.SelectByIndex(i))
        {
         // Print(" OrderType: " + m_position.PositionType() +" PositionGetInteger: " +  PositionGetInteger(POSITION_TYPE)  );

         // BUY POSITION
         if(m_position.Symbol() == WHAT_MARKET && m_position.PositionType() == 0 && m_position.Comment() ==  OrderComment)
           {
            ticket = m_position.Ticket();
            price = m_position.PriceCurrent();
            entryprice = m_position.PriceOpen();
            prev_sl = m_position.StopLoss();
            prev_tp = m_position.TakeProfit();
            sl =0;


            if(FractalInProfit)
              {
               if(price  >= fractal_down && price > entryprice && fractal_down > entryprice)
                 {
                  sl = fractal_down;
                 }
              }
            else
              {
               if(price  >= fractal_down && price > entryprice)
                 {
                  sl = fractal_down;
                 }
              }

            if(sl != 0)
              {
               if(NormalizeDouble(prev_sl,digitQ) != NormalizeDouble(sl,digitQ))
                 {
                  Print("BUY position.StopLoss " + DoubleToString(prev_sl,8)  + " Does NOT == " + DoubleToString(sl,8));

                  if(m_trade.PositionModify(ticket, NormalizeDouble(sl,digitQ), prev_tp))
                    {
                     Print("Trailing #1 BUY position.Ticket " + IntegerToString(ticket)  + " SL Modified to " + DoubleToString(sl,digitQ));
                    }

                 }

              }
           }
        }

      // SELL POSITION
      if(m_position.Symbol() == WHAT_MARKET && m_position.PositionType() == 1 && m_position.Comment() ==  OrderComment)
        {
         ticket = m_position.Ticket();
         price = m_position.PriceCurrent();
         entryprice = m_position.PriceOpen();
         prev_sl = m_position.StopLoss();
         prev_tp = m_position.TakeProfit();
         sl =0;

         if(FractalInProfit)
           {
            if(price  <= fractal_up && price < entryprice && fractal_up < entryprice)
              {
               sl = fractal_up;
              }
           }
         else
           {
            if(price  <= fractal_up && price < entryprice)
              {
               sl = fractal_up;
              }
           }




         if(sl != 0)
           {
            if(NormalizeDouble(prev_sl,digitQ) != NormalizeDouble(sl,digitQ))
              {
               Print("SELL position.StopLoss " + DoubleToString(prev_sl,8)  + " Does NOT == " + DoubleToString(sl,8));

               if(m_trade.PositionModify(ticket, NormalizeDouble(sl,digitQ), prev_tp))
                 {
                  Print("Trailing #1 BUY position.Ticket " + IntegerToString(ticket)  + " SL Modified to " + DoubleToString(sl,digitQ));
                 }

              }
           }

        }
     }

  }

//+------------------------------------------------------------------+
void delete_all(int days)
  {

   int time = TimeCurrent();
   int length = days +(1440*60);// minutes in day times seconds

   for(int i = OrdersTotal() - 1; i >= 0; i--)
     {
      if(m_order.SelectByIndex(i))
        {

         int ordertime = m_order.TimeSetup();

         if(m_order.OrderType() == ORDER_TYPE_BUY_STOP &&
            m_order.Symbol() == WHAT_MARKET && m_order.Comment() == OrderComment)
           {
            if(ordertime + length < time)
              {
               m_trade.OrderDelete(m_order.Ticket());
              }


           }

         if(m_order.OrderType() == ORDER_TYPE_SELL_STOP &&
            m_order.Symbol() == WHAT_MARKET && m_order.Comment() == OrderComment)
           {

            if(ordertime + length < time)
              {
               m_trade.OrderDelete(m_order.Ticket());
              }
           }

        }
     }
  }
//+------------------------------------------------------------------+

double fractal_down = 0;
double fractal_up = 0;

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void fractals()
  {

   double Fractal_Buffer_Up[];
   double Fractal_Buffer_Dn[];

   CopyBuffer(Fractal_handle, 0, 0, 100, Fractal_Buffer_Up);
   CopyBuffer(Fractal_handle, 1, 0, 100, Fractal_Buffer_Dn);


// the indicator arrays
   ArraySetAsSeries(Fractal_Buffer_Up, true);
   ArraySetAsSeries(Fractal_Buffer_Dn, true);

   /*
    grab the last fractal
   */
   double up = EMPTY_VALUE;
   double down = EMPTY_VALUE;

   int try
         = 0;
   while(up == EMPTY_VALUE && try
            < 99)
        {
         try
            ++;
         up =  Fractal_Buffer_Up[try];
         fractal_up = up;
        }

   int try2 = 0;
   while(down == EMPTY_VALUE && try2 < 99)
     {
      try2++;
      down =  Fractal_Buffer_Dn[try2];
      fractal_down = down;
     }
// Print(" Up fractal " + up + " at " + try + "  | Down fractal " + down + " at " + try2);
  }
//+------------------------------------------------------------------+
