//+------------------------------------------------------------------+
//|                                       AtrBreakOutCodeDemo_EA.mq5 |
//|                                            Inspired by Rene Balke|
///+-----------------------------------------------------------------+
#property copyright ""
#property link      "https://www.youtube.com/watch?v=nlj9gUuf7Wg&t=7038s"
#property description" Code to follow along with Rene Balke YouTube Video:"
#property description" Master MQL5 Programming (Complete All In One Guide)"
#property version   "1.00"

//====================================================================
#include <Expert\Expert.mqh>
//--- available signals
#include <Expert\Signal\SignalAC.mqh>
//--- available trailing
#include <Expert\Trailing\TrailingFixedPips.mqh>
//--- available money management
#include <Expert\Money\MoneyFixedLot.mqh>
// Include the Trade Class code
#include <Trade\Trade.mqh>

ulong        Expert_MagicNumber            =0;       //Determined from Magic Number Generator function.
bool         Expert_EveryTick              =false;      //

string EaName = "AtrBreakoutCodeDemo";


input ENUM_TIMEFRAMES Timeframe = PERIOD_H1;
input int AtrPeriods = 14;
input double TriggerFactor=2.5;
input int TpPoints = 2000;
input int SlPoints = 2000;
input int TslTriggerPoints = 200;
input int TslPoints = 100;

input int Magic = 1;

int handleATR;

// CandleControl for Orders - Only one trade per bar.
int barsTotal = 0; // initialize in OnInit()/ Works in conjuction with the bars variable in OnTick())
//+------------------------------------------------------------------+
//| Global expert object                                             |
//+------------------------------------------------------------------+
CExpert ExtExpert;
//+------------------------------------------------------------------+
//| Global Trade object                                              |
//+------------------------------------------------------------------+
CTrade TradeSignal;
input double MyLotSize = 0.1;
double MyPrice =0.0;
string BuyCommentary = (EaName + " Buy");
string SellCommentary = (EaName + "Sell");


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   Print("");
//--- Get the number of a build where the program is compiled
   Print(__FUNCTION__," Build #",__MQLBUILD__);
//--- Reset reason code can also be obtained in OnInit()
   Print(__FUNCTION__," Deinitialization reason code can be received during the EA reset");
//--- The first way to get a deinitialization reason code
   Print(__FUNCTION__," _UninitReason = ",getUninitReasonText(_UninitReason));
//--- The second way to get a deinitialization reason code
   Print(__FUNCTION__," UninitializeReason() = ",getUninitReasonText(UninitializeReason()));
//---
// Educational Warning
   MessageBox("MQL5 ATR Break Out Code Demonstration. \nNOTIFICATION: This Is For Educational Use Only.    \nThis is not a Tradable EA! \nDo Not Use With Real Money."  +"\nYou have been kindly Told, and Warned."+ "\nYou are running MetaTrader 5 Build #"+IntegerToString(__MQLBUILD__));
//--- during optimization
   if(MQLInfoInteger(MQL_OPTIMIZATION))
     {
      //--- check available RAM for the agent
      int available_memory_mb=TerminalInfoInteger(TERMINAL_MEMORY_TOTAL);
      if(available_memory_mb<2000)
        {
         PrintFormat("Insufficient memory for the test agent: %d MB",
                     available_memory_mb);
         return (INIT_AGENT_NOT_SUITABLE);
        }
     }
// Magic Number Declaration
   TradeSignal.SetExpertMagicNumber(Magic);

//--- Initializing expert
   if(!ExtExpert.Init(Symbol(),Period(),Expert_EveryTick,Expert_MagicNumber))
     {
      //--- failed
      printf(__FUNCTION__+": error initializing expert");
      ExtExpert.Deinit();
      return(INIT_FAILED);
     }
   else
     {
      Print("The Magic Number Is: ",IntegerToString(Expert_MagicNumber));
     }

   handleATR = iATR(NULL, Timeframe, AtrPeriods);
   barsTotal=iBars(NULL,Timeframe);
   return(INIT_SUCCEEDED);
  }//End OnInit

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- The first way to get a deinitialization reason code
   Print(__FUNCTION__," Deinitialization reason code = ",reason);
//--- The second way to get a deinitialization reason code
   Print(__FUNCTION__," _UninitReason = ",getUninitReasonText(_UninitReason));
//--- The third way to get a deinitialization reason code
   Print(__FUNCTION__," UninitializeReason() = ",getUninitReasonText(UninitializeReason()));

  }//End OnDeinit
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
// Process the trailing stop
   for(int i = 0; i< PositionsTotal(); i++)
     {
      ulong posTicket = PositionGetTicket(i); // get the position ticket.

      // Stops processing trailing stop if no the right symbol for this chart.
      if(PositionGetSymbol(POSITION_SYMBOL) != _Symbol)
         continue;

      // Stops this loop run if it does not find the magic number in the position.
      if(PositionGetInteger(POSITION_MAGIC) != Magic)
         continue;

      double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);

      double posPriceOpen = PositionGetDouble(POSITION_PRICE_OPEN); // get the position Open Price.
      double posSL = PositionGetDouble(POSITION_SL);
      double posTP = PositionGetDouble(POSITION_TP);

      if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_BUY)
        {
         if(bid > posPriceOpen + TslTriggerPoints * _Point)
           {
            // Update the stop loss.
            double sl = bid - TslTriggerPoints * _Point;
            // round the value
            sl = NormalizeDouble(sl,_Digits);

            if(sl > posSL || posSL == 0)
              {
               Print("Buy Stoploss adjusted ", DoubleToString(sl-posSL,5), " pips.");
               TradeSignal.PositionModify(posTicket, sl, posTP);

              }

           }
        }
      else
         if(PositionGetInteger(POSITION_TYPE)==POSITION_TYPE_SELL)
           {
            if(ask < posPriceOpen - TslTriggerPoints * _Point)
              {
               // Update the stop loss.
               double sl = ask + TslTriggerPoints * _Point;
               // round the value
               sl = NormalizeDouble(sl,_Digits);

               if(sl < posSL || posSL ==0)
                 {
                  Print("Sell Stoploss adjusted ", DoubleToString(posSL-sl,5), " pips.");
                  TradeSignal.PositionModify(posTicket, sl, posTP);

                 }

              }
           }

      // Print(posTicket, " > ",posPriceOpen);
     }


// Candle Control - Limit one trade per bar. When there is a new bar, it triggers the loop and then
// updates barsTotal. Loop will not retrigger until barsTotal is not equal to bars due to a new candle.
   int bars = iBars(NULL,Timeframe);
   if(barsTotal != bars)
     {
      barsTotal = bars;

      double atr[];
      // always use the copy buffer to access your array.
      CopyBuffer(handleATR,0,1,1,atr);

      double open = iOpen(NULL, Timeframe,1);
      double close = iClose(NULL,Timeframe,1);

      if((open < close) && ((close-open)> atr[0]* TriggerFactor))   // Up candle
        {
         Print("buy signal");
         executeBuy();

        }
      else
         if((open > close) && ((open-close)> atr[0]* TriggerFactor)) // Down Candle
           {
            Print("sell signal");
            executeSell();
           }
     }
  }//End OnTick
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Return a textual description of the deinitialization reason code |
//+------------------------------------------------------------------+
string getUninitReasonText(int reasonCode)
  {
   string text="";
//---
   switch(reasonCode)
     {
      case REASON_ACCOUNT:
         text="Account was changed";
         break;
      case REASON_CHARTCHANGE:
         text="Symbol or timeframe was changed";
         break;
      case REASON_CHARTCLOSE:
         text="Chart was closed";
         break;
      case REASON_PARAMETERS:
         text="Input-parameter was changed";
         break;
      case REASON_RECOMPILE:
         text="Program "+__FILE__+" was recompiled";
         break;
      case REASON_REMOVE:
         text="Program "+__FILE__+" was removed from chart";
         break;
      case REASON_TEMPLATE:
         text="New template was applied to chart";
         break;
      default:
         text="Another reason";
     }
//---
   return text;
  }
//+------------------------------------------------------------------+
//You always have to call your functions inside some event handling
//function.
void executeBuy()
  {
// buy Signal
   double entry = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
   entry = NormalizeDouble(entry, _Digits);

   double tp  = entry + TpPoints * _Point;
   tp = NormalizeDouble(tp, _Digits);

   double sl  = entry - SlPoints * _Point;
   sl = NormalizeDouble(sl, _Digits);

// Buy to Open at the Ask, Sell to Close at the Bid - cha cha cha.
   TradeSignal.Buy(MyLotSize,NULL,entry,sl,tp,BuyCommentary);

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void executeSell()
  {
// sell signal

   double entry = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   entry = NormalizeDouble(entry, _Digits);

   double tp  = entry - TpPoints * _Point;
   tp = NormalizeDouble(tp, _Digits);

   double sl  = entry + SlPoints * _Point;
   sl = NormalizeDouble(sl, _Digits);

// Sell at the Bid To Open, Buy to Close at Ask - cha cha cha.
   TradeSignal.Sell(MyLotSize,NULL,entry,sl,tp,SellCommentary);
  }



















//+------------------------------------------------------------------+
