# Need help with programming the TB-F

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:

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

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

1 Like

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

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:

``````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

@empottasch
dear friend, i have one more entreaty. If it possible of course.
Let's see at QUIK TB-F:

As you can see there are digits above the tb-f curve. This the procent of the spent TB-F. So as we can see it the final bars of this tb-f

So is it possible to make the same in Ami?

1 Like

yes this is possible because D (or the amount of fuel ) is known. Will add this tomorrow

1 Like

you can add the following at the bottom of the code I posted

``````if( stidx < ( BarCount - 1 ) AND( d1 / dd * 100 ) <= 100 )
{
x1 = LastValue( ValueWhen( TBFLoop, bi ) );
y1 = LastValue( ValueWhen( TBFLoop, TBFLoop ) );
pleft = d1 / dd * 100;
GfxSetZOrder( -5 );
GfxSetCoordsMode( 1 );
GfxSetTextAlign( 0 | 8 );
GfxSetBkColor( ColorRGB( 0, 0, 0 ) );
GfxSetTextColor( ColorRGB( 0, 255, 255 ) );
GfxSelectFont( "Tahoma", 10 );
GfxTextOut( "" + Prec( pleft, 2 ), x1 + 1 , y1 );
}
``````
1 Like

It give the error

i wrote that for the last code I posted.

so not sure which code you use but just add bi = BarIndex(); like this

``````bi = BarIndex();
if( stidx < ( BarCount - 1 ) AND( d1 / dd * 100 ) <= 100 )
{
x1 = LastValue( ValueWhen( TBFLoop, bi ) );
y1 = LastValue( ValueWhen( TBFLoop, TBFLoop ) );
pleft = d1 / dd * 100;
GfxSetZOrder( -5 );
GfxSetCoordsMode( 1 );
GfxSetTextAlign( 0 | 8 );
GfxSetBkColor( ColorRGB( 0, 0, 0 ) );
GfxSetTextColor( ColorRGB( 0, 255, 255 ) );
GfxSelectFont( "Tahoma", 10 );
GfxTextOut( "" + Prec( pleft, 2 ), x1 + 1 , y1 );
}
``````

i used gfx functions because you are using 5.6 but it would be better to use PlotTextSetFont(), but you need a more recent version of Amibroker for that

2 Likes

you then also use this at the bottom of your code instead

``````bi = BarIndex();
if( stidx < ( BarCount - 1 ) AND( d1 / dd * 100 ) <= 100 )
{
x1 = LastValue( ValueWhen( TBFLoop, bi ) );
y1 = LastValue( ValueWhen( TBFLoop, TBFLoop ) );
pleft = Prec( d1 / dd * 100, 2 );
PlotTextSetFont( "" + pleft, "Tahoma", 10, x1, y1, ColorRGB( 0, 255, 255 ), colorDefault, 10 );
}
``````
2 Likes

Awesome! Thanks a lot!

1 Like

Hi @empottasch,

Really appreciate your contribution of TB_F codes here, this is huge because I am a long time fan of MIDAS(Paul Levine) since he first published these articles back in early 90's. I even used "WinMidas" which was developed by Dr Fisher, Paul's colleague. I have been looking to understand/implement TB_F for AB but never got around the "e" calculation. One question regarding your code if you could elaborate the logic behind

``````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;
}
``````

Is "result" the interpolation mechanism? I don't really follow this part.

Again, than you for your work.

One more thing, what does the for loop do?

hi, i'm sorry, i would have to dig into it again and doing other things now. Best to go through it step by step or try to write your own version and then compare.