Fill Peaks and Troughs arrays with values

Hi,

I have the below code to calculate peaks and troughs. I need to fill in the values without using loops is it possible.? For example, if PEAKS_BOOL==1 then its high value should be assigned to PEAKS. That can be easily done using ValueWhen, but till i get the new peak the old value should be carryforward.

PEAKS =Null;
TROUGHS = Null;

PEAKS_BOOL = H > Ref( H, 1 ) AND H > Ref( H, -1 ) AND (Ref(H, -1) > Ref(H, -2) OR Ref(L, -1) > Ref(L, -2));

TROUGHS_BOOL = L < Ref( L, 1 ) AND L < Ref( L, -1 ) AND (Ref(L, -1) < Ref(L, -2) OR Ref(H, -1) < Ref(H, -2));

Thanks in Advance…
Vinay

To get what you’re asking for - and because you can’t use recursion in AFL - you can just turn it into a two step process. First get the values at all the peaks, and then fill in the values elsewhere.

ONLY_PEAKS = IIf( PEAKS_BOOL, H, Null );
ONLY_TROUGHS = IIf( TROUGHS_BOOL, L, Null );

PEAKS = ValueWhen( !IsNull(ONLY_PEAKS),ONLY_PEAKS,1); 
TROUGHS = ValueWhen( !IsNull(ONLY_TROUGHS),ONLY_TROUGHS,1);

But I question your definitions of peaks & troughs.

I get why you wouldn’t use the built-in zigzag based peaks & troughs, but if you’re using a definition that seems odd to me.

Traditionally a peak is held to be a higher-high than the prior period, with an equal-or-higher low - while a trough is the opposite (lower-low, equal-or-lower high). Inside & Outside days are continuation of prior.

So I don’t get why you’re checking “tomorrow’s” value (and hence also eliminating results for the most recent period), or looking back 2 periods.

That said, unless I’m misunderstanding you or have had a brain fart, the code provided should do what you’re asking for (and you could just alter your boolean conditional if you want a more traditional version).

can’t use recursion

@pache
Nonsense. If you don’t know AFL it is better to stay quiet than to speak up. Two errors in one sentence. FYI: a) you can have recursion AFL, but b) this code does not need recursion at all.

The code is single liner and it is

Peaks = ValueWhen( Peaks_Bool, High );

and does not require recursion nor loops. One function call. And it keeps the value between peaks as original poster wanted.

If somebody is interested in looping code that draws lines between peaks/troughs here it is:
http://www.amibroker.org/userkb/2007/04/20/plotting-trade-zigzag-lines/

Easily found using Google.

So before posting:
a) questions already answered in docs
b) nonsense answers that make false claims

would you be so clever next time to use Google.

Edited: apparently “brain fart” is a part of innocent nice chit-chat in Australia, so author did not really wanted to offend anyone. Still assuming everybody is from Australia is quite risky

1 Like

in answer to the original poster. I think you are referring to “Fractal Pivots” defined by Bill Williams.

to my knowledge the first 1 to put them in AFL was Edakad, see => http://www.inditraders.com/amibroker/1934-afl-harmonic-patterns.html

here is some of my code using Edakad’s formula extracted from the link above:

// Fractal Pivots
bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );

rightstrength = Param( "Right Strength", 5, 2, 50, 1 );
leftstrength = Param( "Left Strength", 5, 2, 50, 1 );
fact = Param( "Chart Time Frame Factor", 1, 1, 10, 1 );

rightStrength = rightStrength * fact;
leftStrength = leftStrength * fact;

pk = H == HHV( H, leftstrength ) AND Ref( HHV( H, rightstrength ), rightstrength ) < H;
tr = L == LLV( L, leftstrength ) AND Ref( LLV( L, rightstrength ), rightstrength ) > L;

for( i = 0; i < 3; i++ )
{
    VarSet( "px" + i, ValueWhen( pk, bi, i ) );
    VarSet( "tx" + i, ValueWhen( tr, bi, i ) );
    VarSet( "ph" + i, ValueWhen( pk, H, i ) );
    VarSet( "tl" + i, ValueWhen( tr, L, i ) );
}

ll = tr AND tl1 < tl2;
hl = tr AND tl1 > tl2;
hh = pk AND ph1 > ph2;
lh = pk AND ph1 < ph2;
dt = pk AND ph1 == ph2;
db = tr AND tl1 == tl2;

GraphXSpace = 5;
SetChartBkColor( colorBlack );
SetChartOptions( 1, chartShowDates, chartGridMiddle, 0, 0, 0 );
SetBarFillColor( IIf( C > O, ColorRGB( 0, 75, 0 ), IIf( C <= O, ColorRGB( 75, 0, 0 ), colorLightGrey ) ) );
Plot( C, "", IIf( C > O, ColorRGB( 0, 255, 0 ), IIf( C <= O, ColorRGB( 255, 0, 0 ), colorLightGrey ) ), 64, Null, Null, 0, 0, 1 );

PlotShapes( shapeSmallCircle * tr, ColorRGB( 0, 0, 255 ), 0, L, -10 );
PlotShapes( shapeSmallCircle * pk, ColorRGB( 255, 0, 0 ), 0, H, 10 );

clr = ColorRGB( 10, 10, 10 );

for( i = lvb; i > fvb; i-- )
{
    // troughs
    if( ll[i] )
    {
        str = "LL";
        PlotTextSetFont( str, "Arial Black", 8, i, L[i], ColorRGB( 0, 0, 250 ), colorDefault, -30 );
    }

    if( hl[i] )
    {
        str = "HL";
        PlotTextSetFont( str, "Arial Black", 8, i, L[i], ColorRGB( 0, 0, 250 ), colorDefault, -30 );
    }

    if( db[i] )
    {
        str = "DB";
        PlotTextSetFont( str, "Arial Black", 8, i, L[i], ColorRGB( 0, 0, 250 ), colorDefault, -30 );
    }

    //peaks
    if( hh[i] )
    {
        str = "HH";
        PlotTextSetFont( str, "Arial Black", 8, i, H[i], ColorRGB( 250, 0, 0 ), colorDefault, 20 );
    }

    if( lh[i] )
    {
        str = "LH";
        PlotTextSetFont( str, "Arial Black", 8, i, H[i], ColorRGB( 250, 0, 0 ), colorDefault, 20 );
    }

    if( dt[i] )
    {
        str = "DT";
        PlotTextSetFont( str, "Arial Black", 8, i, H[i], ColorRGB( 250, 0, 0 ), colorDefault, 20 );
    }
}

Title = Name() +
        " | " + Now( 2 ) +
        " | " + "Pivot Timeframe Factor: " + fact;
3 Likes

I actually use a non-zigzag peaks and troughs function that calculates traditional peaks & troughs via a bar-by-bar approach (extremely similar to the example you provided - I combine the peaks and troughs into a single array). It’s why the OP’s question interested me.

My understanding of recursion is that it’s a function calling itself (or at least that’s what I was taught when I learnt Miranda, many years back). From looking at the wikipedia page on recursion in computer science, that’s clearly a pretty simplistic definition.

But in https://www.amibroker.com/guide/a_userfunctions.html it specifies: Note also that recursion (having a function call itself from within itself) is NOT supported as for now.

Has that changed? Cos I’d love to be able to call functions from within themselves, it’s an approach I feel comfortable with.

One of the things I’ve been wanting to do with my own bar-by-bar version of a peaks-and-troughs function is getting it working in an indefinite number of additional higher timeframes (e.g. peak-of-the-peaks, etc) and I was struggling to come up with a version that wasn’t limited to looping through a pre-set number of higher timeframes.

Edit: Actually… you could make a matrix, and keep expanding it by one row while the peaks/troughs were still getting meaningful/non-identical results, and then run the separate peaks & troughs function to make each new row until then? Or is that getting over-elaborate & there’s a simpler version?

No, recursion is a mathematical term. It was invented LONG LONG time before computers. Fibonacci was using recursion in 1202. Did you see computers back then?

In math it is simply:

yn = f( x, yn-1 )

In computer science recursive algorithm is the one that uses previous result(s) to calculate current value.

Wikipedia unfortunately is written by amateurs and they are focusing on narrowest meaning, but this is wrong understanding of recursion.

All infinite impulse response filtering (like EMA), cumulative sums (Cum) and such are recursive in nature as they use previous value to calculate current:

y (current) = factor * input + ( 1 - factor ) * y( previous )

This kind of calculation can easily be done in AmiBroker explicitly

y = 0;
for( i = 1; i < BarCount; i++ )
{
   y[ i ] = factor * x[ i ] + ( 1 - factor ) * y[ i - 1 ]; 
}

or using built-in AmiBroker function

y = AMA2( x,factor,1 - factor );

Internally it does the same as loop given above.

What you pointed out from the manual is a narrowest meaning of recursion (calling function from within itself) and it is prohibited on purpose as doing so leads to highly inefficient algorithms.

Fundamentally recursive algorithms (in math sense) - like the FACTORIAL or Fibonacci series (in which every number after the first two is the sum of the two preceding ones) can be implemented either using calling the function itself or using one loop.
If implemented using function-based recursion Fibonacci series algorithm has complexity of O(N*N),while the same done using loop has complexity of O(N). With N being 10000 it means 10000 times faster.

// code in C
int fibonacci(int n)  
{
    if(n == 0)
        return 0;
    else 
    if(n == 1)
      return 1;
    else
      return fibonacci(n - 1) + fibonacci(n - 2); // these calls cause HUGE exponentially growing cost
}

// contrary to the above example - the code below has linear complexity O(n)
int fibbonaci_loop(int n)
{
    int prev2 = 0;
    int prev1 = 1;
    int current = 0;
    for (int i = 0; i < n; i++) 
    {
        current = prev1 + prev2;
        prev2 = prev1;
        prev1 = current;
    }
    return current;
}

This plus the fact that function calls are costly because they cause CPU pipeline invalidation causes poor performance of nested function calls.
Any half-skilled programmer knows the difference and avoids nested function call recursion as hell.

8 Likes