Calculate the stop loss at the close of the candle

Edinson Perez  

I try to use the strategy tester to know if the strategy works or not, but I would like to calculate the stoploss at the close of the candle in which the stoploss was activated and not the stoploss of the operation that was created, does anyone have an idea of how do it ?


#include <Trade/Trade.mqh>

/* Handler */
int MACD_h;

/* Arrays where the indicator data is stored */
double MACD[];
double SIGNAL[];

/* For openning operations */
CTrade trade;
ulong trade_ticket = 0;
bool time_passed = true;
int contador = 0;

int OnInit() {
   /* Initializing the handlers */
   MACD_h = iMACD(_Symbol, _Period, 12, 26, 9, PRICE_CLOSE);
   
   ArraySetAsSeries(MACD, true);
   ArraySetAsSeries(SIGNAL, true);

   return(INIT_SUCCEEDED);
}

void OnTick() {
   /* Saving the data of the indicator */
   CopyBuffer(MACD_h, 0, 1, 4, MACD);
   CopyBuffer(MACD_h, 1, 1, 4, SIGNAL);
   
   /* Checking if there's an open operation */
   if (PositionSelectByTicket(trade_ticket) == false) {
      // Reseting the trade flags
      trade_ticket = 0;
   }
   
   
   if ( // Buy
      MACD[2] < SIGNAL[2] && MACD[1] > SIGNAL[1] && trade_ticket <= 0 && time_passed == true ) {
      /* Precio actual */
      /*
      double Ask = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_ASK), _Digits);
      
      //--- Abrir compra
      trade.Buy(1, _Symbol, Ask, Ask-90000*_Point, Ask+100000*_Point, NULL);
      trade_ticket = trade.ResultOrder();
      */
      
      double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
      
      //--- Abrir venta      
      trade.Sell(10, _Symbol, Bid, Bid+90000*_Point, Bid-100000*_Point, NULL);
      trade_ticket = trade.ResultOrder();
      Alert("Orden puesta MACD");
      
      contador = contador + 1;
      Print("#############################################################################:    ", contador);
      time_passed = false;

      time_passed = false;
      
      EventSetTimer(PeriodSeconds(PERIOD_CURRENT)*3);
      
   }
}

void OnTimer() {
   time_passed = true;
}
The Fundamentals of Testing in MetaTrader 5
The Fundamentals of Testing in MetaTrader 5
  • www.mql5.com
What are the differences between the three modes of testing in MetaTrader 5, and what should be particularly looked for? How does the testing of an EA, trading simultaneously on multiple instruments, take place? When and how are the indicator values calculated during testing, and how are the events handled? How to synchronize the bars from different instruments during testing in an "open prices only" mode? This article aims to provide answers to these and many other questions.
Edinson Perez  
Can someone help me with this please, I have been looking for a solution for days :(
Fernando Carreiro  
Edinson Perez: I try to use the strategy tester to know if the strategy works or not, but I would like to calculate the stoploss at the close of the candle in which the stoploss was activated and not the stoploss of the operation that was created, does anyone have an idea of how do it ?

First things first! You are processing data on every tick when necessary. Why copy the MACD data on every tick when you only need to check it on a new bar?

Also, don't use the Timer for delays. Detect the new bar the proper way. Read the following blog post: Detecting the start of a new bar or candle, in an expert advisor.

After you fix that up first, then we can proceed to the other stuff.

Detecting the start of a new bar or candle, in an expert advisor.
Detecting the start of a new bar or candle, in an expert advisor.
  • 2022.03.15
  • www.mql5.com
For an Expert Advisor (EA) , when a new tick quote arrives, the MetaTrader terminal calls the default OnTick() event handling function. However, there is no default event handling function for when a
Edinson Perez  
Fernando Carreiro #:

First things first! You are processing data on every tick when necessary. Why copy the MACD data on every tick when you only need to check it on a new bar?

Also, don't use the Timer for delays. Detect the new bar the proper way. Read the following blog post: Detecting the start of a new bar or candle, in an expert advisor.

After you fix that up first, then we can proceed to the other stuff.


Hi Fernando.

I need to calculate the MACD at each tick, this is part of my strategy, due to the market I am in, the market movements can be very abrupt and depending on those tick movements, I make decisions

Fernando Carreiro  
Edinson Perez #: I need to calculate the MACD at each tick, this is part of my strategy, due to the market I am in, the market movements can be very abrupt and depending on those tick movements, I make decisions

That may be your strategy, but its not what your code shows. You are only "Copying" from position 1 onwards (meaning previous bar, not current bar). Now given the previous bar has already closed and will not change, you only need to read it once at the start of the new candle.

Your own topic's header is "Calculate the stop loss at the close of the candle" and that is how we are responding to your request.

If not, then please explain yourself more clearly and in more detail.

Edinson Perez  
Fernando Carreiro #:

That may be your strategy, but its not what your code shows. You are only "Copying" from position 1 onwards (meaning previous bar, not current bar). Now given the previous bar has already closed and will not change, you only need to read it once at the start of the new candle.

Your own topic's header is "Calculate the stop loss at the close of the candle" and that is how we are responding to your request.

If not, then please explain yourself more clearly and in more detail.


So let's change the code, I just need to know how to take in the calculations at the close of the candle if the stoploss is activated, see the following code how could I do it? you know ?



#include <Trade/Trade.mqh>
CTrade trade;

ulong trade_ticket = 0;
bool time_passed = true;
int contador = 0;



void OnTick() {

   static datetime dtBarCurrent  = WRONG_VALUE;
   datetime dtBarPrevious = dtBarCurrent;
   dtBarCurrent = (datetime) SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE );
   bool bNewBarEvent = ( dtBarCurrent != dtBarPrevious );

   
   if(bNewBarEvent) {
   
      if (PositionSelectByTicket(trade_ticket) == false) {      
         trade_ticket = 0;
      }
      
      double O1=iOpen(Symbol(),_Period,1);
      double C1=iClose(Symbol(),_Period,1);
      
      double O2=iOpen(Symbol(),_Period,2);
      double C2=iClose(Symbol(),_Period,2);
      
      double O3=iOpen(Symbol(),_Period,3);
      double C3=iClose(Symbol(),_Period,3);
      
      
      if ( O1 > C1 && O2 > C2 && O3 > C3 && trade_ticket <= 0 && time_passed == true ) {
               
         double Bid = NormalizeDouble(SymbolInfoDouble(_Symbol, SYMBOL_BID), _Digits);
         
         
         trade.Sell(10, _Symbol, Bid, Bid+90000*_Point, Bid-100000*_Point, NULL);
         trade_ticket = trade.ResultOrder();
         Alert("OP");
         
         contador = contador + 1;
         Print("#############################################################################:    ", contador);
         time_passed = false;
   
         time_passed = false;
         
         EventSetTimer(PeriodSeconds(PERIOD_CURRENT)*3);
         
      }
   }
}

void OnTimer() {
   time_passed = true;
} 
Fernando Carreiro  
Edinson Perez #: So let's change the code, I just need to know how to take in the calculations at the close of the candle if the stoploss is activated, see the following code how could I do it? you know ?

As I have stated, if you want to do something at the start of a new bar (the close of the previous bar), then please incorporate the detection of the new bar so that we can proceed. Nothing else can be accomplished until you have done that part first.

Also, please don't normalise the OHLC prices. They are already normalised, and even if they were not, then that is not the correct way to normalise a price which needs to be normalised according to the tick size, not the number of digits. However, that is a different story.

So for now, please incorporate the new bar detection as explained.

Edinson Perez  
Fernando Carreiro #:

As I have stated, if you want to do something at the start of a new bar (the close of the previous bar), then please incorporate the detection of the new bar so that we can proceed. Nothing else can be accomplished until you have done that part first.

Also, please don't normalise the OHLC prices. They are already normalised, and even if they were not, then that is not the correct way to normalise a price which needs to be normalised according to the tick size, not the number of digits. However, that is a different story.

So for now, please incorporate the new bar detection as explained.


I already updated my previous code, is there something wrong ?


#include <Trade/Trade.mqh>
CTrade trade;

ulong trade_ticket = 0;
int contador = 0;



void OnTick() {

   static datetime dtBarCurrent  = WRONG_VALUE;
   datetime dtBarPrevious = dtBarCurrent;
   dtBarCurrent = (datetime) SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE );
   bool bNewBarEvent = ( dtBarCurrent != dtBarPrevious );

   
   if(bNewBarEvent) {
   
      if (PositionSelectByTicket(trade_ticket) == false) {      
         trade_ticket = 0;
      }
      
      double O1=iOpen(Symbol(),_Period,1);
      double C1=iClose(Symbol(),_Period,1);
      
      double O2=iOpen(Symbol(),_Period,2);
      double C2=iClose(Symbol(),_Period,2);
      
      double O3=iOpen(Symbol(),_Period,3);
      double C3=iClose(Symbol(),_Period,3);
      
      
      if ( O1 > C1 && O2 > C2 && O3 > C3 && trade_ticket <= 0 && time_passed == true ) {
               
         double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         
         
         trade.Sell(10, _Symbol, Bid, Bid+90000*_Point, Bid-100000*_Point, NULL);
         trade_ticket = trade.ResultOrder();
         Alert("OP");
         
         contador = contador + 1;
         Print("#############################################################################:    ", contador);
         
         
      }
   }
}


Fernando Carreiro  
Edinson Perez #: I already updated my previous code, is there something wrong ?
  1. Now that the new bar is detected, what do you still need the timer for?
  2. You removed normalisation of OHLC data, but you are still normalising the bid price. Why, if It is already normalised?
  3. You said that you wanted to calculate the Stop-loss based on the close price of the candle, so why are you using the bid price for that?
    At least that is what I understood from your explanation in broken English, so correct me if I am wrong.
Edinson Perez  
Fernando Carreiro #:
  1. Now that the new bar is detected, what do you still need the timer for?
  2. You removed normalisation of OHLC data, but you are still normalising the bid price. Why, if It is already normalised?
  3. You said that you wanted to calculate the Stop-loss based on the close price of the candle, so why are you using the bid price for that?
    At least that is what I understood from your explanation in broken English, so correct me if I am wrong.


You're absolutely right, I've updated my code again, but I don't understand how I should take the close of the candlestick as a stoploss once it reaches or exceeds (Bid+90000*_Point)



#include <Trade/Trade.mqh>
CTrade trade;

ulong trade_ticket = 0;
int contador = 0;



void OnTick() {

   static datetime dtBarCurrent  = WRONG_VALUE;
   datetime dtBarPrevious = dtBarCurrent;
   dtBarCurrent = (datetime) SeriesInfoInteger(_Symbol, _Period, SERIES_LASTBAR_DATE );
   bool bNewBarEvent = ( dtBarCurrent != dtBarPrevious );

   
   if(bNewBarEvent) {
   
      if (PositionSelectByTicket(trade_ticket) == false) {      
         trade_ticket = 0;
      }
      
      double O1=iOpen(Symbol(),_Period,1);
      double C1=iClose(Symbol(),_Period,1);
      
      double O2=iOpen(Symbol(),_Period,2);
      double C2=iClose(Symbol(),_Period,2);
      
      double O3=iOpen(Symbol(),_Period,3);
      double C3=iClose(Symbol(),_Period,3);
      
      
      if ( O1 > C1 && O2 > C2 && O3 > C3 && trade_ticket <= 0 ) {
               
         double Bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         
         
         trade.Sell(10, _Symbol, Bid, Bid+90000*_Point, Bid-100000*_Point, NULL);
         trade_ticket = trade.ResultOrder();
         Alert("OP");
         
         contador = contador + 1;
         Print("#############################################################################:    ", contador);
         
         
      }
   }
}
Reason: