Need help with programming the TB-F

@empottasch I was specifically referring only to the Bloomberg book.

Maybe @Siberianman is already too busy testing it on its charts! :sweat_smile:

well if I am violating the law by posting free code then the moderator better remove it since I canā€™t

1 Like

No. I think that you are perfectly OK to post any code derived from their description (no limitations are listed on the book and/or there are no trademarks related to it).
More so, since, as you said Mr. Paul Levine (the inventor of this technique) said its work is free!

The only thing that may not be free (I mean to download as a pdf) is the book.

Please, look at the BOLD highlighted text in above quote.
I will just reword the "free on internet" (like "This code is free on the internet" to avoid any ambiguity that it may refer to the above book.

ok i made a request for removal of my code. I donā€™t care, nobody reads it anyways :slight_smile:

Ideas are not subject to copyright. Copyrights protect expression and patents protect inventions, and neither protect ideas. If @empottasch wrote the code himself based on someoneā€™s idea it is HIS creation and he owns the copyright to the expression, i.e. the FORMULA that he wrote.

He would violate copyright if he published somebodyā€™s else code without permission. If anything here is subject to copyright I would say it is original TS code from first post (if not placed in public domain)

6 Likes

@empottasch Great job Edward. I would not be concerned about your code and copyright. You are not posting the book on line, just your code. I just came across another one of the same authorā€™s earlier articles that was I think a predecessor to the follow up books and articles and it is coded into afl as one of the Traders Tips

"AN ANCHORED VWAP CHANNEL FOR CONGESTED MARKETS"
http://www.amibroker.com/members/traders/07-2010.html

ok thank you. Yes I seen that code. That is basically the VWAP starting at some start defined by selectvalue(). I have that in my latest code as well in the array Midasloop. The only difference is that in that Traders Tips code the value of the VWAP is equal to mp at the first 2 bars. This is not correct. If yo compare it to my code you will see that my violet curve is close to the ā€œtraders tipsā€ blue curve except for the fact that my violet curve is equal to mp at the start point and then moves on from there. This is something I didnā€™t notice before but is stressed upon in the Midas manual.

But this Traders Tips code is nothing special. It is just a volume weighted moving average. These Midas guys didnā€™t invent this!! The only guy who came up with a new idea was Paul Levine. I think I got his TB-F curve correct. But like he mentions the value of D should be calculated using local pullbacks. I did not do this yet.

2 Likes

Re the TradeStation code, here is a direct quote from the online edition (source SafariBooksOnLine):

TradeStation Implementation of Paul Levine's Topfinder/Bottomfinder (TBF)

This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 Unported License http://http://creativecommons.org/licenses/by-sa/3.0/2010, Bob English (www.precisioncapmgt.com).

Since the only violation, in the first post, was to not properly attribute it to its author (Bob English) I'm doing it in this post to comply with that license.

1 Like

BlockquoteThe code is now working correctly, tested it with the test data from the manual.

It's very good! So as far as i understand you don't set the D amount. You make it by set number of bars and count the volume on bars than?
Cause Levin and Cole set the D as volume.
But it the same things i think.
I will compare results from ami with results from QUIK and show it.

I've try to compare the results in QUIK and in Ami. And here what i got:

Here is the Ami
TBF011

And the QUIK:
TBF010

It's great i think

ok yes that looks pretty close. But D depends on your initial setting. I now implemented 1 value for D for the entire calculation. In my code I use the volume at the start bar times a parameter you can change, called nbars. So if you change the parameter nbars the blue curve will change. The orange curve is the VWAP and should be exactly the same as my violet curve (when you start at the same point).

To chose D correctly Paul Levine gives more or less the idea he has but I am not sure this is explained in more detail anywhere else (I will check the Midas manual). The idea is, as I currently understand, is to chose D so that it will touch the first pullback bar. After that D may be changed to fit the next pullback bar ... I think. That would mean that the TB-F curve would repaint. But that is not a big problem since what you are looking for is the end op the curve coinciding with the top. But I will try to fit only the first pullback first.

The way my code is now you can just use the parameter nbar to fit the first pullback. Like in this example:

2017-11-06 at 08-24-32

in my code D is very dependent on the volume of the first bar.

you could also replace

dd = cumvol[stidx] * nbars; // temporary solution to set D

with

dd = ma1[stidx] * nbars; // temporary solution to set D

and define ma1 outside the loop using for instance

ma1 = MA( V, 200 );

but then for the first 200 bars of your data you will not get a TB-F curve. But the duration of the TB-F curve will be more stable. For continuous intraday data the volume is concentrated inside the opening hours. So then it will be hard to get a stable duration of the TB-F curve and you need to adjust for every new start point

1 Like

@empottasch

there is another small improvement you may consider to add in your formula.

As was noted in a previous post:

immagine

You may add a parameter to choose the price field used, leaving the (H + L) / 2 as a default, or as an alternative to use the Low when plotting a support curve and a High when plotting a resistance curve.

1 Like

i was just working on that :slight_smile:

you can indeed just make a parameter so you can set the "mp" variable either to H, L or (H+L)/2

I am trying to make something automatic. I am trying something with pivots or trends not sure yet what is best.

In this case I use ATR peaks and troughs. You need some peak/trough code anyways to find a good start point. In the example it uses the L instead of (H+L)/2

2017-11-06 at 09-55-57

1 Like

It's very intresting results when using H or L at starting bar at the VWAP
TBF013

is that the Quik program? Is the program described somewhere? Is this it?
https://arqatech.com/en/products/quik/

do they give a description of the TB-F?

you can for instance use the pivot code I posted here:

and then instead of

mp = ( H + L ) / 2;

use

if( tr[stidx] )
{
    mp = L;
}
else
    if( pk[stidx] )
    {
        mp = H;
    }
    else
    {
        mp = ( H + L ) / 2;
    }
1 Like

@empottasch yes, this is the QUIK.
But they donā€™t have TB-F by default. This TB-F for QUIK made my freind using TradeStation code.

It's very sad, but the code is not working...

Maybe my AFL's version is a problem? 5.60

yes that needs more recent version but you do not need all the code, just the pivots, see

/*
Ā© AFL code by E.M.Pottasch, 11/2017
TB-F: Top/Bottom Finder, After Paul Levine (1993 or thereabouts), 38 page trading Ebook,
free on internet and Midas Manual 2011 (Andrew Coles, David G. Hawkins), free on internet.

Still to implement:

1)
D is actually determined by iteratively adjusting it to provide a best "fit" to the
price pullbacks subsequent to launch. To start this process, one must set D equal to
some initial guess; I usually choose fifty days worth of volume, i.e. the cumulative
volume at launch minus the cumulative volume fifty trading days earlier. In the fitting
process used to determine D, generally an "eyeball" affair, give more weight to fitting
the more recent pullbacks (from: chapter 15, page 28 -Levine, 1993- )

Chapter 4 of the Midas 2011 Manual talks about D fitting.

2)
*/
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 );
nbars = Param( "nbars", 50, 0, 500, 0.1 );
ww = Param( "width", 5, 0, 10, 1 );
dn = DateTime();
sd = SelectedValue( dn );
start = dn == sd;
//start = DateNum() == 1081031; // Midas example start point
stidx = LastValue( ValueWhen( start, BarIndex() ) );

bi = BarIndex();
fvb = FirstVisibleValue( bi );
lvb = LastVisibleValue( bi );

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;

if( tr[stidx] )
{
    mp = L;
}
else
    if( pk[stidx] )
    {
        mp = H;
    }
    else
    {
        mp = ( H + L ) / 2;
    }

MidasLoop = Null;
TBFLoop = Null;
MidasLoop[stidx] = mp[stidx];
TBFLoop[stidx] = mp[stidx];
cumpvol = Cum( mp * V ) - ValueWhen( Ref( start, 1 ), Cum( mp * V ) );
cumvol = Cum( V ) - ValueWhen( Ref( start, 1 ), Cum( V ) );
ma1 = MA( V, 200 );

for( i = stidx + 1; i <= lvb; i++ )
{
    MidasLoop[i] = cumpvol[i] / cumvol[i]; // VWAP starting at index stidx

    //dd = 61200000; // Midas example data D value
    //dd = cumvol[stidx] * nbars; // temporary solution to set D
    dd = ma1[stidx] * nbars; // temporary solution to set D
    d1 = cumvol[i];
    e1 = d1 * ( 1 - d1 / dd ); // if d1 > dd then e1 < 0, end of TB-F curve
    x1 = d1 - e1;
    idx = stidx;

    for( j = stidx + 1; j <= i; j++ )
    {
        if( x1 > cumvol[j - 1] AND x1 < cumvol[j] )
        {
            idx = j;
            //_TRACE( "i: " + i + " j: " + j );
            break;
        }
    }

    // interpolate
    if( idx != 0 AND  e1 >= 0 )
    {
        v0 = cumpvol[idx - 1];
        v1 = cumpvol[idx];
        t = ( x1 - cumvol[idx - 1] ) / ( cumvol[idx] - cumvol[idx - 1] );
        result = ( 1 - t ) * v0 + t * v1;
        TBFLoop[i] = ( cumpvol[i] - result ) / e1;
    }
}

SetChartOptions( 0, chartShowDates );
SetChartBkColor( ColorRGB( 0, 0, 0 ) );
Plot( Close, "Price", colorDefault, styleCandle, Null, Null, 0, 0, 1 );
Plot( MidasLoop, "Midas", colorViolet, styleLine | styleNoRescale, Null, Null, 0, 0, ww );
Plot( TBFLoop, "TB-F", colorLightBlue, styleLine | styleNoRescale, Null, Null, 0, 0, ww );

PlotShapes( shapeSmallCircle*tr, ColorRGB( 0, 250, 0 ), 0, L, -10 );
PlotShapes( shapeSmallCircle*pk, ColorRGB( 250, 0, 0 ), 0, H, 10 );
6 Likes

The REQUIREMENT for using this forum is using AmiBroker 6.00 or HIGHER. Any older is NOT accepted.
See How to use this site