15

I am trying to use CopyRates() to search for a bullish engulfing candlestick pattern (bearish candle followed by a bigger bullish candle) on several timeframes (all timeframes H2 to M10 within an H4 bullish candle after it closes). I read the definition of CopyRates() but I'm finding it a bit challenging to implement. The idea here is from the patterns I want to filter the pattern that has the biggest bearish to bullish candle pair ratio. See what I've done so far below:

In the OnTick():

for (int i=ArraySize(timeframes); i>=1; i--)   {
    
    if(CopyRates(Symbol(), timeframes[i - 1], 1, MyPeriod, rates)!=MyPeriod) {
        Print("Error CopyRates errcode = ",GetLastError()); 
        return;
    }

    // Using bullish engulfing pattern:
    if ((rates[numCandle].open < rates[numCandle].close) &&
        (rates[numCandle + 1].open > rates[numCandle + 1].close) &&
        (rates[numCandle + 1].open < rates[numCandle].close) &&
        (rates[numCandle + 1].close > rates[numCandle].open)) {

        // Not too certain what should be done here
    }
}

Here's the other related code:

input int numCandle=0; 
MqlRates rates[];
ENUM_TIMEFRAMES timeframes[7] = {PERIOD_H2, PERIOD_H1, PERIOD_M30, PERIOD_M20, PERIOD_M15, PERIOD_M12, PERIOD_M10};

void OnInit() {
   ArraySetAsSeries(rates, true);
}

UPDATED

Below is the definition of the bullish engulfing pattern:

enter image description here

The bullish engulfing pattern as shown in the above image is a bearish candle followed by a bullish candle. The bearish candle’s open less than the bullish candle’s close and the bearish candle’s close is greater than the bullish candle’s open. Please note that in several cases, the bearish candle's close is greater than the bullish candle's open by only a fraction. Each of the candles has a body size bigger than it’s upper and lower wicks combined.

not2qubit
  • 10,014
  • 4
  • 72
  • 101
SuperHueman
  • 165
  • 11
  • 1
    Based on the interest in this question I've created a bounty detailing all the necessary parts. Please feel free to ask any question to clarify any additional information you'll need to arrive at the specified solution. – SuperHueman Jun 25 '20 at 08:04
  • I hate those pictures of *"wrongly"* aligned candles. They are misleading and making new comer traders believe it's ok to see huge gaps where the previous *close* does not align with the new *open*. The **only** time this is ok, is if there is *overnight* and out-of sessions trading allowed from some *stock* brokerages. If seen in FX, under normal daily market conditions, you are being bamboozled! – not2qubit Nov 09 '20 at 20:05

2 Answers2

6
     ENUM_TIMEFRAMES timeframes[7] = {PERIOD_H2, PERIOD_H1, PERIOD_M30, PERIOD_M20, PERIOD_M15, PERIOD_M12, PERIOD_M10};
     //ENUM_TIMEFRAMES timeframes[4] = {PERIOD_H1, PERIOD_M30, PERIOD_M15, PERIOD_M5};
     //---
     const int LONG=1, SHORT=-1, NO_DIR=0;
     const ENUM_TIMEFRAMES timeframeHighest = PERIOD_H4;
     string bestRatioObjectName="bestBullish2BearishPattern!";
     
     datetime lastCandleTime=0;
     
     void OnTick()
     {
        if(!isNewBar(PERIOD_H4))
           return;
        //most likely you will call this block after new bar check?
        MqlRates rates[];
        ArraySetAsSeries(rates,true);
        if(CopyRates(_Symbol,timeframeHighest,0,2,rates)==-1)
        {
           printf("%i %s: failed to load/copy rates on %d. error=%d",__LINE__,__FILE__,PeriodSeconds(timeframeHighest)/60,_LastError);
           return;
        }
        if(getCandleDir(rates[1])!=LONG)
           return;
        const datetime timeStart=rates[1].time, timeEnd=rates[0].time;   //within a bullish H4 candle - DONE
        
        double bestRatio = -1;//once a bearish2bullish ratio is higher, we'll move to new place
        for(int i=ArraySize(timeframes)-1;i>=0;i--)
        {
           if(CopyRates(_Symbol,timeframes[i],timeStart,timeEnd,rates)<0)
           {
              printf("%i %s: failed to copy rates on %d. error=%d",__LINE__,__FILE__,PeriodSeconds(timeframeHighest)/60,_LastError);
              return;
           }
           processRates(rates,bestRatio,bestRatioObjectName);
        }
        printf("%i %s: best=%.5f, objName =%s: %.5f-%.5f",__LINE__,__FILE__,bestRatio,bestRatioObjectName,
         ObjectGetDouble(0,bestRatioObjectName,OBJPROP_PRICE1),ObjectGetDouble(0,bestRatioObjectName,OBJPROP_PRICE2));
        //ExpertRemove();//for scripting, a one time call
     }
     bool isNewBar(const ENUM_TIMEFRAMES tf)
       {
        const datetime time=iTime(_Symbol,tf,0);
        if(time>lastCandleTime)
          {
           lastCandleTime=time;
           return true;
          }
        return false;
       }
     int getCandleDir(const MqlRates& rate) // candle direction: +1 for BULL, -1 for BEAR
       {
        if(rate.close-rate.open>_Point/2.)
           return 1;
        if(rate.open-rate.close>_Point/2.)
           return-1;
        return 0;
       }
     void processRates(const MqlRates& rates[],double &best,const string bestObjName)
     {
        for(int i=ArraySize(rates)-2; i>0; /* no sense to catch last candle - we cant compare it with anybody */ i--)
        {
           if(getCandleDir(rates[i])!=LONG)
              continue;//current - bullish
           if(getCandleDir(rates[i+1])!=SHORT)
              continue;//prev - bearish
           if(rates[i].close-rates[i+1].open>_Point/2.){}
           else continue;
           if(rates[i+1].close-rates[i].open>_Point/2.){}
           else continue;
           const double body=rates[i].close-rates[i].open, twoWicks = rates[i].high-rates[i].low- body;
           if(body<twoWicks)
              continue;   //Each of the candles has a body size bigger than it’s upper and lower wicks combined.
     //---
           const double prevBody = rates[i+1].open - rates[i+1].close;
           const double newRatio = body / prevBody;
           if(newRatio>best) // eventually we'll find best bull2bear ratio
           {
              moveRectangle(rates[i+1],rates[i].time,bestObjName);
              best = newRatio;
           }
        }
     }
     void moveRectangle(const MqlRates& rate,const datetime rectEnd,const string objectName)
     {
        if(ObjectFind(0,objectName)<0)
        {
           if(!ObjectCreate(0,objectName,OBJ_RECTANGLE,0,0,0,0,0))
           {
              printf("%i %s: failed to draw %s. error=%d",__LINE__,__FILE__,objectName,_LastError);
              return;
           }
           //add GUI things like how to display the rectangle
        }
        //moving the rectangle to a new place, even for the first time
        ObjectSetDouble(0,objectName,OBJPROP_PRICE,0,rate.open);
        ObjectSetDouble(0,objectName,OBJPROP_PRICE,1,rate.close);
        ObjectSetInteger(0,objectName,OBJPROP_TIME,0,rate.time);
        ObjectSetInteger(0,objectName,OBJPROP_TIME,1,rectEnd);
     }

Genes
  • 181
  • 1
  • 1
  • 14
Daniel Kniaz
  • 4,338
  • 2
  • 11
  • 18
  • I've been following this question closely because I'm very interested in the solution. I added (https://pastebin.com/rjdqtx1K) as the GUI. I tried running the code but didn't see any rectangle. The previous candle and current `H4` candles on my chart are bullish. Am I missing something? – SuperHyperMegaSomething Jun 30 '20 at 16:08
  • difficult to say. first, are you sure the object exist (check with list of objects) ? Next, it might happen that you do not see an object because it's too small on H4 chart. I would rather inspect M1 charts for that. Next, full code showing where you added GUI objects is needed – Daniel Kniaz Jul 01 '20 at 10:04
  • There is no object in the object list. Not sure why it doesn't appear. Here's my full `moveRectangle()` (https://pastebin.com/0WmdTvTG). Also, if I understand your code well it should draw a rectangle if candle 0 on `H4` is bullish, right? So will it be searching after `H4` has closed or continually as H4 candle 0 is being formed? This seems to confuse me a bit. – SuperHyperMegaSomething Jul 01 '20 at 10:37
  • 1. are you sure you have a pattern? 2. what do you see in the experts log file - if failed to create an object, an error would be logged – Daniel Kniaz Jul 01 '20 at 14:36
  • 1
    1. I am using the same pattern you provided in your solution. The only changes I've made are in the `moveRectangle()` link I provided. 2. Oops, forgot to check the expert log. I got this error `25 MultiTimeframeTest.mq5: failed to load/copy rates on 240. error=4003` and it appeared on every pair I tried testing. – SuperHyperMegaSomething Jul 01 '20 at 17:00
  • @DanielKniaz please pardon me, I haven't checked on the question for a number of days. I'll definitely check the solution soon and get back to you before the bounty expires – SuperHueman Jul 01 '20 at 17:08
  • @DanielKniaz I seem to be getting the same `error=4003` as SuperHyoerMegaSomething on the currency pairs I tested. – SuperHueman Jul 02 '20 at 08:41
  • Oh, I see. made an error when copying the answer. please try again – Daniel Kniaz Jul 02 '20 at 09:38
  • @DanielKniaz I got the error `array out of range in ‘MTFCopyRates.mq5' (59,30)`. Line 30 from my code is `const datetime timeStart=rates[0].time, timeEnd=TimeCurrent(); //within a bullish H4 candle - DONE` and line 59 is `if(getCandleDir(rates[i+1])!=SHORT)` – SuperHueman Jul 02 '20 at 10:43
  • You didn't address "if I understand your code well it should draw a rectangle if candle 0 on H4 is bullish, right? So will it be searching after H4 has closed or continually as H4 candle 0 is being formed? This seems to confuse me a bit." in your reply to my comment. – SuperHyperMegaSomething Jul 02 '20 at 10:48
  • @SuperHueman it happens because sometimes there's not enough of candles from the start of current H4 candle, e.g. if it is 5:01 pm now - there are two H1 candles (4:00 and 5:00), and it is it 4:01 now - you can only find one H1 candle since H4 start (which is 4:00:00). need to make a logical decision to fix the possible error – Daniel Kniaz Jul 02 '20 at 15:00
  • @SuperHyperMegaSomething The code I uploaded makes a one-time operation then exits. If you need it to do constantly - describe what you expect to have (and code at the top), and remove `ExpertRemove();` line – Daniel Kniaz Jul 02 '20 at 15:01
  • 3
    @DanielKniaz I think I should have explained it better in my question. I am interested in the `H4` bullish candle after it closes. That's basically searching through candle index 1 on the `H4` chart. As a candle forms there are times when it switches from being bullish to bearish so checking on the candle as it forms wouldn't be necessary for my case. I will update the question to categorically state that. Please could you update your solution to factor this, then I'll award you the bounty. – SuperHueman Jul 02 '20 at 16:41
  • @DanielKniaz the bounty will end in less than an hour, so I awarded you the bounty. Thank you. Please could you update the solution to search within an `H4` bullish candle after it closes. – SuperHueman Jul 03 '20 at 06:50
  • 1
    @DanielKniaz also the idea behind the rectangle is to open a trade, so shifting the rectangle till the overall highest ratio is found would lead to opening and closing several trades till the highest ratio one is found. I've been trying to figure out a way to restructure the code to find the overall highest rectangle before drawing it only once but I haven't been able to. I wanted to ask another question but I felt this didn't warrant another question. Could you please help in the regard. – SuperHueman Jul 05 '20 at 20:13
  • @SuperHueman I updated - code is called once per bar, previous H4 bar (and all inner lower tf elements). If you need to open trades from the rectangle - keep in mind that you probably need to be specific and catch only the last vs previous bar analysis on the lower timeframes – Daniel Kniaz Jul 06 '20 at 14:48
  • @DanielKniaz I am getting an `array out of range in ‘MTFNewCopyRates.mq5' (75,29)` error. I tried it on several pairs that had the previous H4 candle as bull but got the same error. Line 29 is `if(CopyRates(_Symbol,timeframeHighest,0,2,rates)==-1)` and line 75 is `if(getCandleDir(rates[i+1])!=SHORT)`. – SuperHueman Jul 07 '20 at 14:01
  • @DanielKniaz I have to admit that figuring out how to catch the last region (that gives the overall highest ratio within the `H4` candle) to open a trade has been quite a challenge for me. I wanted to ask another question on that but didn't think it warranted a new question since it's so closely related to this solution. Could you please help with this. – SuperHueman Jul 07 '20 at 14:46
  • I do not know what you mean by highest ratio - what to compare, what to achieve ? – Daniel Kniaz Jul 07 '20 at 14:57
  • 1
    @DanielKniaz Pardon me, I meant the biggest ratio for bullish engulfing pattern (as calculated above). Currently the code compares two bullish engulfing patterns and keeps moving the rectangle till it arrives at the one with the biggest ratio from H2 to M10. I want to place a trade after all the engulfing pattern ratio comparisons are done so the trade is taken on the bullish engulfing pattern with the biggest ration (where the rectangle finally settles). – SuperHueman Jul 07 '20 at 15:43
  • @DanielKniaz I am also getting the `array out of range` error that SuperHueman got – IronThrone Jul 08 '20 at 12:17
  • 2
    @DanielKniaz I got the `array out of range` error too. I tried fixing it yesterday but couldn't. I also tried a sightly different approach to your solution that doesn't require moving the rectangle so it draws only on the finally desired region within the H4 candle. But I realised it's not an easy task :) though it solves SuperHueman's other issue in the process. Kudos, you'll definitely get my +50 votes when you're done fixing the errors and adding SuperHueman's latest request – Bane Jul 08 '20 at 12:45
  • @DanielKniaz Nice solution. Just need to fix the array range error. As Bane stated, moving rectangle only once when H4 closes as bullish would be a wonderful addition – Containment Jul 08 '20 at 14:26
  • @DanielKniaz I haven’t been here for a few days. This solution I believe deserves more credit but the errors might be preventing that. Any plans of fixing this one? – IronThrone Jul 11 '20 at 18:00
  • @SuperHueman @Containment @Bane @IronThrone - error out of array fixed by shifting to the next candle (first candle within H4 bar is thrown. not a best solution, just as an example. More wise would be to compute the time more presicely, or call `iClose,iOpen...` for the candle before the first within H4 – Daniel Kniaz Jul 13 '20 at 14:16
  • 1
    @DanielKniaz Thanks for the update. I've still been trying to sort this out and forgot to check for your reply. Does "first candle within H4 bar is thrown" refer to the H2 bar? If that's the case then only half of the timeframe is searched, which is far from ideal as you said. How would I compute the time more precisely? Also I haven't been able to get a condition for the resting position of the rectangle in order to place a trade as I detailed in previous comments. Could you also please address this too. – SuperHueman Jul 22 '20 at 15:04
  • in order to apply `CopyRates` you need to know either dates or number of candles. they are different for each timeframe. so you have to either recompute and pass for each TF, or live without first candle. no idea what you mean by `resting position of the rectangle` – Daniel Kniaz Jul 23 '20 at 10:49
  • @DanielKniaz I'm still not sure if by the "first candle within H4" is referring to an H2 candle. Please confirm that for me. To be honest, I've spent about 3 months plus researching on this and trying to figure out a way to search for a candlestick pattern through multiple timeframes but your solution here is the closest I've come. I really appreciate your assistance so far but I still really don't fully understand how I would go about completing the solution as you explained in your comment above. Please could you help further with this, possibly providing a more complete solution. `1/2` – SuperHueman Jul 23 '20 at 19:36
  • 5
    @DanielKniaz Please note that this would also benefit so many people who have shown interest in this question and solution. `2/2` – SuperHueman Jul 23 '20 at 19:37
  • @DanielKniaz In previous comments I mentioned that I want to open a trade based on the upper and lower values of the rectangle. Based on the current solution, the rectangle keeps moving as it compares ratios, so I've been trying to figure out how to filter the biggest ratio where the rectangle wont move again, that's what I meant when I said the `resting position of the rectangle`. Otherwise I was thinking of placing a pending order and cancelling it whenever the rectangle moves till it stops, which isn't a good way to go about solving the problem. How could I solve this issue? – SuperHueman Jul 23 '20 at 20:05
  • @DanielKniaz I've been watching this closely. and judging from the response, and upvotes to SuperHueman's last but one comment, it's fair to say that a lot of users here, including me are really interested in a more effective or usable solution. It's definitely not something easy to code as I said earlier that I tried to fix your code but couldn't figure it out. Also I am willing to now award you an extra 100 points instead of 50 I mentioned earlier once this is done and the 'moving rectangle issue' (that SuperHueman mentioned in his previous comment) for opening trades is also done. – Bane Jul 27 '20 at 18:55
  • 1
    @DanielKniaz I just created a new bounty of 150 points for this. – Bane Jul 29 '20 at 11:06
  • @Bane 150 points, wow. I've still been trying to get this fully figured out. – SuperHueman Jul 29 '20 at 11:59
1

Assuming that MyPeriod is initialized to 2, the rest of the code seems correct. You should create a variable to keep the timeframe that had the greatest ratio. Inside your if you have to calculate the candlestick body size for candle+1 and candle and calculate the ratio, then if the calculated ratio is greater than the previous calculated you change the value AND update the timeframe in which you find it.

By the end of your for loop you may decide in which timeframe you want to put your order.

prmottajr
  • 1,804
  • 1
  • 12
  • 22