iRSI() does not open an order at price close

 
Hi everybody,

I am new at MQL4 coding. I have searched on the forum but I didn't find any answer or explanation.

I am trying to write an EA to open an order when specific conditions are met:

double RSI1 = iRSI(NULL, PERIOD_H1, 21, PRICE_CLOSE, 0);
double RSI2 = iRSI(NULL, PERIOD_H1, 21, PRICE_CLOSE, 1);
double RSI3 = iRSI(NULL, PERIOD_H1, 21, PRICE_CLOSE, 2);

double ATR1 = iATR(NULL, PERIOD_D1, 21, 0);

double High1 = iHigh(NULL, 0, 1);
double Low1 = iLow(NULL, 0, 1);

// first long signal
if (CountOrders() == 0 $$ (RSI3 < 50 && RSI2 > 50) &&
   Ask > High1 + (ATR1 * 0.2))
{ /*...*/}

// first sell signal
if (CountOrders() == 0 $$ (RSI3 > 50 && RSI2 < 50) &&
   Bid < Low1 - (ATR1 * 0.2))
{ /*...*/}

The problem is when I am backtesting, orders are never opened at the close price of the candle

You can see, in the code, the period is H1 so orders should open at 08:00,09:00,10:00,...18:00... but they are not. They are opened at 07:36, 08:48....

I believed that according to the documentation, that by using price_close the rsi would get calculated at the close price for the time frame selected, but it doesn't look that way.

I tried to use this code too :

bool IsNewBar()
{
   static datetime lastbar;
   datetime curbar = (datetime)SeriesInfoInteger(_Symbol,_Period,SERIES_LASTBAR_DATE);
   if(lastbar != curbar)
   {
      lastbar = curbar;
      return true;
   }
   return false;
}

The result is worse : no orders


What am I missing?

 

Your order opened at 7:36 because at that time the Ask has risen above High1+ATR1*0.2

Things are getting even more tight when you take IsNewBar into account: Now a buy order will only be opened when the very first Ask of a new bar is way above the high of the previous bar, which is quite a rare condition.

 
Atr period is D1 ? If you want to open orders on candle close you should put a Volume based condition , ex : if(Volume[0]<=1) and use unly RSI (1) and (2)
 
  1. Catalin Zachiu: Atr period is D1 ? If you want to open orders on candle close you should put a Volume based condition , ex : if(Volume[0]<=1) and use unly RSI (1) and (2)
    For a new bar test, Bars is unreliable (a refresh/reconnect can change number of bars on chart,) volume is unreliable (miss ticks,) Price is unreliable (duplicate prices and The == operand. - MQL4 and MetaTrader 4 - MQL4 programming forum.) Always use time.
    I disagree with making a new bar function, because it can only be called once per tick. A variable can be tested multiple times.
              New candle - MQL4 and MetaTrader 4 - MQL4 programming forum

  2. double RSI3 = iRSI(NULL, PERIOD_H1, 21, PRICE_CLOSE, 2);
    double ATR1 = iATR(NULL, PERIOD_D1, 21, 0);
    On MT4: Unless the current chart is that specific pair/TF referenced, you must handle 4066/4073 errors before accessing prices.
              Download history in MQL4 EA - MQL4 and MetaTrader 4 - MQL4 programming forum

 

Thanks you guys (@lippmaje, @Catalin Zachiu, @whroeder1) for your answers

lippmaje:

Your order opened at 7:36 because at that time the Ask has risen above High1+ATR1*0.2

Things are getting even more tight when you take IsNewBar into account: Now a buy order will only be opened when the very first Ask of a new bar is way above the high of the previous bar, which is quite a rare condition.

I'm using OnStart event. Maybe to avoid what you'are talking about I should use OnTick event ?


whroeder1:
  1. For a new bar test, Bars is unreliable (a refresh/reconnect can change number of bars on chart,) volume is unreliable (miss ticks,) Price is unreliable (duplicate prices and The == operand. - MQL4 and MetaTrader 4 - MQL4 programming forum.) Always use time.
    I disagree with making a new bar function, because it can only be called once per tick. A variable can be tested multiple times.
              New candle - MQL4 and MetaTrader 4 - MQL4 programming forum

  2. On MT4: Unless the current chart is that specific pair/TF referenced, you must handle 4066/4073 errors before accessing prices.
              Download history in MQL4 EA - MQL4 and MetaTrader 4 - MQL4 programming forum

Ok to use time to check if there is a new bar.
f I use the time like you said the EA will open order only on price close ?

whroeder1 can you explain me why I have to download history ?

 
mike94:

I'm using OnStart event. Maybe to avoid what you'are talking about I should use OnTick event ?

It's difficult to spot from your code snippet what you are trying to do.

  • you have 3 RSIs of which you only use two?
  • you want to go long as soon as the Ask is above High1+ATR1*0.2, but this should only happen on 8:00, 9:00, 10:00 etc?
  • you want to check conditions at the close of the bar, but then open a position at the start of a bar?
  • you have been doing all this in OnStart, so do want to run this as script rather than advisor?
https://www.mql5.com/en/blogs/post/573613
what is Expert Advisor, Indicator or Script
what is Expert Advisor, Indicator or Script
  • 2018.05.13
  • www.mql5.com
First, some background information. These are "add ons" that you can use within Metatrader4 (MT4). They are created by writing a set of rules and commands using Metatrader Query Language (MQL) which is quite similar to modern day computer languages (e.g. C++, Java). The code you write (Source Code) is stored in a file with a suffix of MQ4. Once...
 
lippmaje:

It's difficult to spot from your code snippet what you are trying to do.

  • you have 3 RSIs of which you only use two?
  • you want to go long as soon as the Ask is above High1+ATR1*0.2, but this should only happen on 8:00, 9:00, 10:00 etc?
  • you want to check conditions at the close of the bar, but then open a position at the start of a bar?
  • you have been doing all this in OnStart, so do want to run this as script rather than advisor?
https://www.mql5.com/en/blogs/post/573613


Hi

Apologies for misunderstanding. English. It's not my native language

Here are my answers

  • I'm using 3 rsi (full code below)
  • It's my mistake. I thought orders should be opened at the begining of a new hour because the timeframe is H1 and the rsi period is H1
  • Yes. That's exactly what I was thinking
  • For sure, I want an EA.
#property strict

extern double Lot = 0.01;
extern double RSIPeriod = 21;
extern double ATRPeriod = 21;
extern bool AutoClose = false;
extern double TakeProfit = 50;
extern double StopLoss = 30;
extern int MagicNumber = 135496;

//++++ These are adjusted for 5 digit brokers_
int pips2points; // slippage  3 pips    3=points    30=points
double pips2dbl; // Stoploss 15 pips    0.0015      0.00150
int Digits_pips; // DoubleToStr(dbl/pips2dbl, Digits_pips)

int slippage = 3;

int start()
{
    checkIsTradeAllowed();

    if (Digits % 2 == 1) // Adjust for five (5) digit brokers_
    {
        pips2dbl = Point * 10;
        pips2points = 10;
        Digits_pips = 1;
    }
    else
    {
        pips2dbl = Point;
        pips2points = 1;
        Digits_pips = 0;
    }
    slippage *= pips2points;
    // OrderSend(___ Slippage_Pips * pips2points, Bid - StopLossPips * pips2dbl

    bool isfirstBuySignal = false;
    bool isSecondBuySignal = false;

    bool isfirstSellSignal = false;
    bool isSecondSellSignal = false;

    bool isClosefirstBuySignal = false;
    bool isCloseSecondBuySignal = false;

    bool isClosefirstSellSignal = false;
    bool isCloseSecondSellSignal = false;

    bool isFirstBuyOrderClosed = false;
    bool isFirstSellOrderClosed = false;

    double sl = 0.0;
    double tp = 0.0;
    int ticket;

    double rsiCurrent = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, 0);
    double rsiPrevious = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, 1);
    double rsiAntepenultimate = iRSI(NULL, 0, RSIPeriod, PRICE_CLOSE, 2);

    double atrCurrent = iATR(NULL, PERIOD_D1, ATRPeriod, 0);
    double atrPrevious = iATR(NULL, 0, 21, 1);

    double highPrevious = iHigh(NULL, 0, 1);
    double lowPrevious = iLow(NULL, 0, 1);

    // check for 1st buy signal
    if ((rsiAntepenultimate < 50 && rsiPrevious > 50) &&
        countNumberOpenedTrades() == 0 &&
        (Ask > highPrevious + (atrCurrent * 0.2)))
    {
        isfirstBuySignal = true;
    }
    // check for 2nd buy signal
    if ((rsiAntepenultimate < 60 && rsiCurrent > 60) &&
        countNumberOpenedTrades() == 1 &&
        isFirstBuyOrderClosed)
    {
        isSecondBuySignal = true;
    }

    // calcul sl and tp for BUY orders
    if (isfirstBuySignal || isSecondBuySignal)
    {
        if (AutoClose)
        {
            sl = NormalizePrice(Ask - atrCurrent * pips2dbl);
        }
        else
        {
            sl = NormalizePrice(Ask - StopLoss * pips2dbl);
            tp = NormalizePrice(Ask + TakeProfit * pips2dbl);
        }
    }

    // check for sell signal
    if ((rsiAntepenultimate > 50 && rsiPrevious < 50) &&
        countNumberOpenedTrades() == 0 &&
        (Bid < lowPrevious - atrCurrent * 0.2))
    {
        isfirstSellSignal = true;
    }

    // check for 2nd sell signal
    if ((rsiAntepenultimate > 40 && rsiCurrent < 40) &&
        countNumberOpenedTrades() == 1 &&
        isFirstSellOrderClosed)
    {
        isSecondSellSignal = true;
    }

    // calcul sl and tp for SELL orders
    if (isfirstSellSignal || isSecondSellSignal)
    {
        if (AutoClose)
        {
            sl = NormalizePrice(Bid + atrCurrent * pips2dbl);
        }
        else
        {
            sl = NormalizePrice(Bid + StopLoss * pips2dbl);
            tp = NormalizePrice(Bid - TakeProfit * pips2dbl);
        }
    }

    // check for close first buy signal
    if ((rsiPrevious > 70 && rsiCurrent < 70) ||
        ((rsiAntepenultimate > 50 && rsiPrevious < 50) && Bid < lowPrevious - (atrCurrent * 0.2)))
    {
        isClosefirstBuySignal = true;
    }
    // check for close second buy signal
    if ((rsiPrevious > 50 && rsiCurrent < 50) ||
        ((rsiAntepenultimate > 50 && rsiPrevious < 50) && Bid < lowPrevious - (atrCurrent * 0.2)) //même condition -> refacto
    )
    {
        isCloseSecondBuySignal = true;
    }

    // check for close first sell signal
    if ((rsiPrevious < 30 && rsiCurrent > 30) ||
        ((rsiAntepenultimate < 50 && rsiPrevious > 50) && Ask > highPrevious + (atrCurrent * 0.2)))
    {
        isClosefirstSellSignal = true;
    }

    // check for close second sell signal
    if ((rsiPrevious < 50 && rsiCurrent > 50) ||
        ((rsiAntepenultimate < 50 && rsiPrevious > 50) && Ask > highPrevious + (atrCurrent * 0.2)))
    {
        isCloseSecondSellSignal = true;
    }

    if (countNumberOpenedTrades() <= 1)
    {
        RefreshRates();
        if (isfirstBuySignal || isSecondBuySignal)
        {
            ticket = OrderSend(Symbol(), OP_BUY, Lot, Ask, slippage, sl, tp, "BUY signal", MagicNumber, 0, CLR_NONE);
            if (ticket < 0)
            {
                Print("Error opening BUY order : ", GetLastError());
            }
            else
            {
                Print("Opened BUY #: " + ticket + " Price: " + PriceToStr(OrderOpenPrice()) + " slippage: " + slippage + " SL: " + PriceToStr(sl) + " TP: " + PriceToStr(tp));
            }
        }
        if (isfirstSellSignal || isSecondSellSignal)
        {
            ticket = OrderSend(Symbol(), OP_SELL, Lot, Bid, slippage, sl, tp, "SELL signal", MagicNumber, 0, CLR_NONE);
            if (ticket < 0)
            {
                Print("Error opening SELL order :", GetLastError());
            }
        }
    }

    // close orders
    for (int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            continue;
        }
        if (MagicNumber == OrderMagicNumber() && Symbol() == OrderSymbol())
        {
            if (OP_BUY == OrderType() && AutoClose && (isClosefirstBuySignal || isCloseSecondBuySignal))
            {
                OrderClose(OrderTicket(), OrderLots(), Bid, slippage, CLR_NONE);
                isFirstBuyOrderClosed = true;
            }
            if (OP_SELL == OrderType() && AutoClose && (isClosefirstSellSignal || isCloseSecondSellSignal))
            {
                OrderClose(OrderTicket(), OrderLots(), Ask, slippage, CLR_NONE);
                isFirstSellOrderClosed = true;
            }
        }
    }

    return (0);
}

// check for trading and history
void checkIsTradeAllowed()
{
    if (!IsTradeAllowed())
    {
        Print("Trade is not allowed");
        return;
    }

    if (Bars < 100)
    {
        Print("Bars cannot be lesser than 100");
        return;
    }
}

// Count number of open orders
int countNumberOpenedTrades()
{
    int numberOrderCount = 0;
    for (int i = OrdersTotal() - 1; i >= 0; i--)
    {
        if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
        {
            continue;
        }
        if (MagicNumber == OrderMagicNumber() && Symbol() == OrderSymbol())
        {
            numberOrderCount++;
        }
    }

    return (numberOrderCount);
}

double NormalizePrice(double p, string pair = "")
{
    // https://forum.mql4.com/43064#515262 zzuegg reports for non-currency DE30:
    // MarketInfo(chart.symbol,MODE_TICKSIZE) returns 0.5
    // MarketInfo(chart.symbol,MODE_DIGITS) return 1
    // Point = 0.1
    // Prices to open must be a multiple of ticksize
    if (pair == "")
        pair = Symbol();
    double ts = MarketInfo(pair, MODE_TICKSIZE);
    return (MathRound(p / ts) * ts);
}

// Converting numeric value into text string.
string PriceToStr(double p)
{
    return (DoubleToStr(p, Digits));
}


 
mike94:

Here are my answers

  • I'm using 3 rsi (full code below)
  • It's my mistake. I thought orders should be opened at the begining of a new hour because the timeframe is H1 and the rsi period is H1
  • Yes. That's exactly what I was thinking
  • For sure, I want an EA.

Still confused. Do you want to open such orders exactly at the start of a new hour?

If so, can you clarify about this condition: Ask > highPrevious + atrCurrent*0.2

If this condition comes true inside the H1 bar, will it contribute to the buy decision at end of the bar?

 
lippmaje:

Still confused. Do you want to open such orders exactly at the start of a new hour?

If so, can you clarify about this condition: Ask > highPrevious + atrCurrent*0.2

If this condition comes true inside the H1 bar, will it contribute to the buy decision at end of the bar?

 Yes, i'd like to open orders only at start of a new bar .

the condition (Ask > highPrevious + atrCurrent*0.2) should be true only at the begining of the new bar.


What I want to achieve is described in https://c.mql5.com/forextsd/forum/27/article_small.pdf


lippmaje: i can explain in french if you want

 

If you want to act on a new bar then use bar data.

Either check for a new open price, or better check for a more recent open time.

And not if Ask is above previous high or not.

 
Marco vd Heijden:

If you want to act on a new bar then use bar data.

Either check for a new open price, or better check for a more recent open time.

And not if Ask is above previous high or not.

What do you mean by check for a more recent open time.

Reason: