How to find two highs (or lows) to draw a trendline?



I'm new to MT4 and mql4 and would really appreciate some help with a code I've been working on.

The code is supposed to find the most recent high (multi-candle high that is, not the high of one candle) and then search for the previous high that is higher than the most recent high. Then it would draw a trendline for me (or the user). It is also supposed to determine the times of those two highs in order to draw the trendline of course.

It should also work in the same way for lows (find the recent low and then find the previous low that is lower than the most recent low).

I tried to set up a cycle operation so that it would scan through sets of 3 candles until it found what it was supposed to, but for some reason it doesn't seem to be working and only gives back results for the starting set of candles.

This is the code:

//| expert start function |
int start()
double a, b, c, d, L, M, RecentHigh, LastHigh, PreviousHigh;
bool RHfound=false, result=false,
string Symb=Symbol();
int Cur_Hour=Hour(); //Server time in hours
double Cur_Min=Minute(); //Server time in minutes
double Cur_time=Cur_Hour+Cur_Min/100; //Current time
datetime RHtime, PHtime; //Time of candles forming LastHigh and PreviousHigh

for (int i=2; i<=7; i++) //I need it to look for the RecentHigh within the last 8 or so candles for instance
int h=i+1;
int j=i-1;
M=High[i]; //highest point for candle
c=High[h]; //highest point to left of candle
d=High[j]; //highest point to right of candle

if(c < M && d < M) //If M is higher than c or d then....
RecentHigh = M; //...3-candle High (RecentHigh) = M.
RHtime = Time[i]; //Time of Recent High
RHfound = true; //Recent High found
break; //If RH found before reaching the last candle of cycle, break cycle

for (int i2=9; i2<=29; i2++) //Searching for Previous High among last 30 candles but not among the candles in the search time frame for the RH
int h2=i2+1;
int j2=i2-1;
L=High[i2]; //highest point for candle
a=High[h2]; //highest point to left of candle
b=High[j2]; //highest point to right of candle

if(a < L && b < L) //If L is higher than a or b then.....
LastHigh = L; //...L is Last High and....

if(LastHigh > RecentHigh) //...if Last High is higher than Recent High....

PreviousHigh = LastHigh; //.....Previous High = L (Last High).
PHtime = Time[i2]; //Time of Previous High
break; //If PH found before reaching last candle of search frame, break cycle


int window= 0;
result=ObjectCreate ("trend", OBJ_TREND, window, PHtime, L, RHtime, M);

return(0); //exit

Trying to analyse each section in a script (with Alerts) it seems that the "for" operators aren't cycling for me for some reason, as the Alerts will give the Recent High as being M[i] with i being "2" and the Previous High as being L[i2] with i2 being "9" for example.

Can anyone help? Please advise.



Okay, sorry the code appears that way. Not sure how you post the code properly on the forum.

Again, sorry if it is confusing.

Gordon Gekko
Gordon Gekko  

Okay, sorry the code appears that way. Not sure how you post the code properly on the forum.

Again, sorry if it is confusing.

Try this:






There is no need to bother with loops actually. Check out iHighest and iLowest functionality.


Thanks for the responses, but with iLowest() and iHighest() wouldn't the EA then simply search for the highest and lowest prices within a given range? What I need is to find the high at a given period (let's call it "A") and then find the the first high which is higher than "A" for "x" amount of candles in the past.

So say we have for GBP/USD

A = 1.560 at 22:00 GMT (lets say it was at the candle indexed as 2)

But we have a range of values for 20 candles (on an hourly chart) before A with 1.700 at 7:00 GMT(at candle 17) and 1.580 at 18:00 GMT (at candle 6).

I need my code to find 1.580 at 18:00 GMT within those 20 candles and not 1.700 at 7:00 GMT.

That's why I was trying for a loop, so that it would cycle through sets of 3 candles each and compare the highs of the 3 candles and then determine if the middle candle's high meets the criteria of being higher than the high of the candles on either side and also meets the criteria of being higher than "A". Once that is found it should then break the cycle and draw a trendline for the user's analysis.

To get iHighest to do something similar wouldn't I have to use a lot of nested ifs with iHighest then being used on small sets of candles in each if statement?

So instead of:

for(i=4; i<=26, i++)




I would have to put something like:

if (High[iHighest(NULL,0,MODE_HIGH,3,4)] > A) {etc;}

else if (High[iHighest(NULL,0,MODE_HIGH,3,5)] > A) {etc;}

else if......

else if......

But I thought loops were favoured over nested ifs since it takes less processing time and since loops can be broken once certain criteria are met.

Any more thoughts? ideas? comments?

Any and all help and comments are appreciated.


I'm not smart enough to grasp your full concept, however it seems that iHighest() would be the best choice. You seem too interested in candles in chunks of 3. Let iHihgest() look back in chunks controlled by your nested for loops.

for (i=10;i<=100;i+=3)



for (i2=1;i2<=20;i2+=3)



if (High2>High1)




sorta like that, whaddya think?

webfoot wrote >>

I'm not smart enough to grasp your full concept, however it seems that iHighest() would be the best choice. You seem too interested in candles in chunks of 3. Let iHihgest() look back in chunks controlled by your nested for loops.

That's how I'd approach this as well...just keep looping backwards grabbing increments of history using the shift features of iHighest and iLowest until you found the candle(s) that meet your requirements.
William Roeder
William Roeder  
Okay, sorry the code appears that way. Not sure how you post the code properly on the forum.

Here's my TL code FWIW
//| Trend line computation.                                          |
double  TL.breakOut[TL.CNT];                            // Exported to setDIR
void ComputeTL() {  // Compute and Display the upper and lower Trend lines
    /* using a windowing method to find the control points. The original idea
     * was found in SHI_Channel_true. If the slopes diverge, the secondary TL
     * becomes a channel.
    /*++++ Find the top and botttom extremes */{
    int LE1[TL.CNT],  LE2[TL.CNT],  LE3[TL.CNT],    WL[TL.CNT],
        WS.prev,  WS = 20;  // Min WS >13 (20 seemed ok);
    while (WS != WS.prev) { WS.prev = WS;
        LE1[TL.UP]  = LocalExtreme(MODE_HIGH, Window.Initial, WS);
        LE2[TL.UP]  = LocalExtreme(MODE_HIGH, LE1[TL.UP]+WS, WS);
        WL[TL.UP]   = LE2[TL.UP]-LE1[TL.UP]+1;

        LE1[TL.LO]  = LocalExtreme(MODE_LOW,  Window.Initial, WS);
        LE2[TL.LO]  = LocalExtreme(MODE_LOW,  LE1[TL.LO]+WS, WS);
        WL[TL.LO]   = LE2[TL.LO]-LE1[TL.LO]+1;

        WS = MathMax(WS,(WL[TL.UP]+WL[TL.LO])/4);   // WS=ave(WL)/2
    double  pLE1[TL.CNT], pLE2[TL.CNT], pLE3[TL.CNT];
    pLE1[TL.UP] = High[LE1[TL.UP]];     pLE2[TL.UP] = High[LE2[TL.UP]];
    pLE1[TL.LO] =  Low[LE1[TL.LO]];     pLE2[TL.LO] =  Low[LE2[TL.LO]];
     LE3[TL.UP] = LocalExtreme(MODE_HIGH, LE2[TL.UP]+WS, WS);
     LE3[TL.LO] = LocalExtreme(MODE_LOW,  LE2[TL.LO]+WS, WS);
    /*---- Find the top and botttom extremes */}

    /* Compute slope/intersect. Positive slope means a downtrend. (Higher in the
     * past.) */
    for (int tl=OBJ.TL; tl < TL.CNT; tl++) {
        double  TL.slope[TL.CNT],   TL.inter[TL.CNT];
        TL.slope[tl] = (pLE2[tl] - pLE1[tl])/(LE2[tl] - LE1[tl]);
        TL.inter[tl] =  pLE1[tl] -  LE1[tl] * TL.slope[tl];

        // Shrink the TLs from LE3 toward LE2 at the touch.
        for(int shift = LE2[tl]+1; shift <= LE3[tl]; shift++) {
            pLE3[tl]    = TL.slope[tl]*shift + TL.inter[tl];
            if( High[shift] >= pLE3[tl]
            &&   Low[shift] <= pLE3[tl]) {  LE3[tl] = shift;    break;
    }   }   }

    if (LE1[TL.UP] < LE1[TL.LO]) {                                          int
                secn = TL.LO,   secDIR=-1,  cntl = TL.UP;   // Upper LE newer,
    } else {    secn = TL.UP;   secDIR=+1;  cntl = TL.LO;   // thus controlling.
    if (LE3[secn] > LE3[cntl]) {    LE3[secn] = LE3[cntl];
        pLE3[secn] = TL.slope[secn]*LE3[secn] + TL.inter[secn];

    /* If the trendlines diverge, make a channel instead */{
    // H(X)=MuX+Bu, L(X)=MlX+Bl   H(X)=L(X) -> X=(Bl-Bu)/(Mu-Ml)
    double div = TL.slope[TL.UP] - TL.slope[TL.LO];
    if( div != 0    // A zero divisor means we already have a perfect channel.
    && (TL.inter[TL.LO]-TL.inter[TL.UP])/div > 0) {     // They meet in the past
        // If the two lines diverge in the future, make a channel instead.
        TL.slope[secn]  = TL.slope[cntl];   // Use a channel instead.
        TL.inter[secn]  = TL.inter[cntl];   // Expand the channel as necessary.
        for(shift = LE1[cntl]; shift <= MathMax(LE2[secn],LE2[cntl]); shift++) {
            double   = TL.slope[secn]*shift + TL.inter[secn];
            if( High[shift] >= &&   Low[shift] <= {
                double pr.cur   = MathMaxDIR(High[shift],  Low[shift], secDIR);
                TL.inter[secn] += MathMaxDIR(, 0,          secDIR);
        }   }
        // Shrink the channel from LE3 toward LE1 at the last touch.
        for(shift = LE3[cntl]; shift < LE3[secn]; shift++) {
     = TL.slope[secn] * shift + TL.inter[secn];
            if( High[shift] >= pLE3[secn]
            &&   Low[shift] <= pLE3[secn]) {    LE3[secn] = shift;    break;
        }   }
        pLE3[secn]    = TL.slope[secn] * LE3[secn] + TL.inter[secn];
        int secnOBJ=OBJ.CHAN;
    } else  secnOBJ=OBJ.TL;
    /* If the trendlines diverge, make a channel instead */}

    /* Compute where and when I expect the market to again hit the TLs.*/{
    /* TL.inter is where the TL is now. Goal is where I think the market
     * will be by the time it hits the TL. Against the trend with too large
     * a slope or with too slow a market is a horrizontal move or worse. */
    double expand.TL[TL.CNT];
    expand.TL[TL.LO]  = MathMax(0, MathMin(1,(Bid             - TL.inter[TL.LO])
                                            /(TL.inter[TL.UP] - TL.inter[TL.LO])
                               )          );
    expand.TL[TL.UP]  = 1 - expand.TL[TL.LO];
    for (tl=OBJ.TL; tl < TL.CNT; tl++) {        // - WL because future<0
        int[TL.CNT];   double[TL.CNT];[tl]        = MathMin(-1,(LE1[tl] - WL[tl])*expand.TL[tl]);[tl]         = TL.slope[tl]*[tl] + TL.inter[tl]; double
        patternHight        = (pLE3[TL.UP] - pLE3[TL.LO]) * TP.PHxDMId.Mult
                            * MathMaxDIR(DMId, 0, TL.DIR[tl]);
        TL.breakOut[tl]     =[tl] + patternHight;
    /* Also compute where and when I expect the market to again hit the TLs.*/}

    if (Show.Objects) {
                pLE3[cntl],             LE3[cntl],
                pLE3[secn],             LE3[secn],
}   // ComputeTL

int LocalExtreme(int mode, int first, int WS) {
    while(true) {
        if (first >= Bars)  first   = Bars - 1;                             int
        last        = MathMin(first + WS, Bars - 1),
        length      = last - first + 1,
        first.prev  = first;
        if (mode == MODE_LOW)   first= Lowest(NULL,0, mode, length, first);
        else                    first=Highest(NULL,0, mode, length, first);
        if (first == first.prev)    return(first);
}   // LocalExtreme

void MoveTL(string name, double P0, int B0, double P1, int B1) {
    /* Trendlines show from point 0 through point 1 to infinity. Purely
     * cosmetic. To disable this use PROP_RAY=false. Use Time[Bx] for past bars.
     * Allow negitive bars (future time) */
    datetime    T0 = Time[MathMaxInt(B0,0)] + MathMax(-B0,0)*Period()*60,
                T1 = Time[MathMaxInt(B1,0)] + MathMax(-B1,0)*Period()*60;
         if (!ObjectMove(   name, 0,        T0,         P0 ))   Alert(
            "ObjectMove(",  name, ", 0, ",  T0, ", ",   P0,
                                            ") [1] failed:", GetLastError() );
    else if (!ObjectMove(   name, 1,        T1,         P1 ))   Alert(
            "ObjectMove(",  name, ", 1, ",  T1, ", ",   P1,
                                            ") [2] failed:", GetLastError() );
}   // MoveTL
int MathMaxInt(int a, int b) {  return (MathMax(a,b)); }    // Allow Time[dbl]