Need help with programming the TB-F

Hello!

I need some help.

I have the code of the TB-F indicator. It is the TradeStation code. Could someone recode it to AFL?

Here it is:

Input: Vol_D(0),                //Input Volume ("D") 
TBF_Price(L),                    //Bar Price to use (L or H or (O+H+L)/3) 
MyVolume,                       //Bar Volume information to use; 
StartingDate(1120101),    //Start Date in TradeStation date format: YYYMMDD, where YYY is years since 1900. Example date is January 1, 2012 StartingTime(1530), //Start Time in military time with nopunctuation; ample time is 3:30 pm 
StartColor(Yellow),           //Color of TBF curve will start with StartColor and end with EndColor . . . 
EndColor(Red);                //. . . and changes according to % D completion 

Vars: running(false),        //whether or not TBF calculation has started and not ended 

pv(0),                             //cumulative price ∗ volume 
vol(0),                            //cumulative volume 
_D(0),                            //variable that holds input volume, D 
pvInt(0),                        //interpolated pv 
j(0),                               //loop iterator 
e(0),                              //"e" variable 
eT(0),                            //temporary copy of "e" used for iteration 
tbf(0),                            //current calculated price of TBF curve 
pct_D(0);                        //percent completion of TBF curve 

//begin at user specified date and time 
if (date = StartingDate and time = StartingTime) or running then begin 

    running = true; 

    pv = pv + TBF_Price ∗ MyVolume;                                    //add current bar’s price ∗ volume to cumulative total 
    vol = vol + (MyVolume);                                                 //running total of volume 


//begin calculation of TBF price 

    if Vol_D <> 0 then begin 
                _D = Vol_D;                      //store copy of input volume 
                e = vol ∗ (1 - vol / _D);               //calculate "e" 

                //if "e" greater than zero, continue to 
                //calculate TBF price 
               //otherwise, TBF is completed 

               if e > 0 then begin 
                           eT = e;                 //temporary copy of "e" 
                           j = -1;                  //used for iteration 
                //iterate backwards until the cumulative 
                //displaced volume is greater than or 
                //equal to "e" 

                while eT > 0 begin 
                j = j + 1; 
               eT = eT - MyVolume[j]; 
                end; 


               //If displaced volume is greater than "e" 
               //(nearly always), 
              //an interpolated pv amount is calculated 
              //for "j" bars ago using only that part of 
              //"j" bar’s volume needed to make cumulative 
              //displaced volume equal to "e". 
              //Note that at this point, "eT" is negative 
              //and contains the partial volume 
               //of "j" bars ago that should be excluded. 

               if eT < 0 then pvInt = TBF_Price[j] ∗ 
               (MyVolume[j] + eT) else pvInt = 0; 

                tbf = (pv - pv[j] + pvInt) / e;               //calculate 
                                                                         //TBF curve 
                                                                         //price for 
                                                                         //this bar 
                 pct_D = vol / _D ∗ 100;                     //calculate 
                                                                         //percent TBF 
                                                                         //completion 
                  
                plot1(tbf, "TBF"); 
                //Set Plot Color based on gradient between two 
                //Input colors 
                SetPlotColor(1, GradientColor(pct_D, 0, 100, 
                //StartColor, EndColor)); 
        end 
         else running = false; //TBF curve is completed; do 
          //not run anymore 
end; 
end; 

I have some AFL code. But it is working wrong. see the picture: http://imglink.ru/pictures/01-11-17/be908b33338e010cddce9917e369aa8a.jpg
And this is the right (blue or orange lines): http://imglink.ru/pictures/01-11-17/9945a772c9ef7d78559a83aee40557df.jpg

And here is the afl code (that is working wrong):

SetBarsRequired(sbrAll);
 
sd = ParamDate("Input Date","2014-10-06",0); 
st=ParamTime("input time","10:55",0);
dn = DateNum(); 
tn=TimeNum();
  
start = dn == sd AND tn==st; 

mp =  ParamField("Price field",-1);

PV1= Cum(mp * V); 
CV1= Cum( V ); 

D=Param("D",6120000000,500,900000000000000000,500);

PV=PV1-ValueWhen(sd==dn AND tn==st,PV1,1);
CV=CV1-ValueWhen(sd==dn AND tn==st,CV1,1);

E=CV*(1-CV/D);

ET=CV-E;

startloop=EndValue(ValueWhen(sd==dn AND tn==st,BarIndex(),1));
endloop=EndValue(IIf(CV>D,ValueWhen(CV<D,BarIndex(),1),BarCount));

barint=0;

TBF=mp;

for (j=startloop+1;j<endloop;j++)
    {
                k=0;
                i=startloop+1;
        while (ET[j]>0 AND k==0)
                    {
                 
                if (CV[i]>ET[j])
                            {
                            k=1;
                             
                            }
                    i=i+1;
                    }
 
        if (k==1)
                    {
                    barint[j]=i-1;
                    }
 
        Volint[j]=CV[barint[j]]-ET[j];
        Mpint[j]=Low[barint[j]]*Volint[j];
 
        CVint[j]=CV[j]-CV[barint[j]]+Volint[j];
        PVint[j]=PV[j]-PV[barint[j]]+Mpint[j];
        TBF[0]=Low[0];
        TBF[j]=PVint[j]/CVInt[j];
      }
 
TBF1=IIf(BarsSince(start),TBF,Null);

PCT=100*CV/D;

tbf2=IIf(BarIndex()<endloop,TBF1,Null);

Plot(TBF2,"PCT="+WriteVal(PCT,1.0)+"TBF",ParamColor( "Color", colorCycle ), ParamStyle("Style") );
     

Could someone help me?
Thanks!

1 Like

@Siberianman I am unfamiliar with that indicator. Do you have a reference or explanation (or mathematical formula) that explains what you are calculating?

It looks like there is some sort of Volume Weighted Average Price but with some other manipulations thrown on top.

@Siberianman and @quantboy Though I am not familiar with the indicator, there were a series of articles in Technical Analysis of Stocks and Commodities (TASC) in 2008 and then 2009. The initial indicator I think called “MIDAS” was coded by Tomasz as a Traders Tip
http://www.amibroker.com/members/traders/09-2008.html

image

The later 3-part series of articles in 2009 (July, Aug, Sept) derived a new indicator that I think is the “TB-F” that he is referring to, but unfortunately was never one of the Traders Tip articles.

image

Hope that helps anyone inclined to code this, and sorry to @Siberianman if I am mistaken and messed up your thread.

2 Likes

You are right! I talk about this TB-F

this is first article i believe
http://traders.com/Documentation/FEEDbk_docs/2008/09/TradersTips/TradersTips.html

bit detailed information

http://31.210.87.4/ebook/pdf/MIDAS_Technical_Analysis.pdf

If some one is looking for more info

1 Like

how this is written down mathematically … maybe it is correct but I have a hard time figuring it out. If I just look at the formula I would have never figured it out.

Basically this Midas formula posted by Portfoliobuilder is nothing other than:

S/R(i , j) = ( cumpvol(i) - cumpvol(j) ) / ( cumvol(i) - cumvol(j) )

where:
cumpvol = Cum( mp * V )
cumvol = Cum( V )
and mp = ( H + L ) / 2

and j is the index at the launch of the calculation (so the index at the start of the curve you calculate) and i is the index at which you calculate the curve.

this function is already posted by Tomasz, see here:

dn = DateTime();
sd = SelectedValue( dn );

start = dn == sd;
mp = ( H + L ) / 2;
pv = mp * V;
cv = Cum( V );
vss = cv - ValueWhen( start, cv );

denom = IIf( vss == 0, 1, vss );
num = Cum( pv ) - ValueWhen( start, Cum( pv ) );
midas = IIf( BarsSince( start ), num / denom, mp );

SetChartOptions( 0, chartShowDates );
SetChartBkColor( ColorRGB( 0, 0, 0 ) );
Plot( Close, "Price", colorDefault, styleCandle, Null, Null, 0, 0, 1 );
Plot( midas, "Midas", colorYellow, 1 );

now moving to the expanded topfinder/bottomfinder formula I haven’t figured it out yet since I do not understand the math :thinking:

1 Like

The Appendix A of the above book (starting at page 403) explains the logic and the math needed to program the Topfinder-Bottomfinder (TB-F) indicator.

that’s great. Now maybe you read it and let’s see if you can explain it to me :smile: George Constanza will explain:

something as fundamental as the TB-F should not be a problem :wink: Having read how they explain simple stuff in unreadable math formulas makes me kind of hesitant

I also can’t uderstand the math formulas in Cole’s book. I began to think transcription of math formaulas is different in Russia and in America :smile:
But… what’s intresting - the formula that I write in first post - TB-F for TradeStation is right. It’s work in Russian trade terminal “QUIK”. And work right. But how we can get it to AFL? I don’t know :(:disappointed_relieved:

probably it is simple to understand once it is explained correctly. Will try myself again tomorrow, found some more reading on the subject. There are also articles on the internet written by the guy who invented this TB-F (Paul Levine). He is sometimes very clear but mostly he is into Shakespeare, especially when he talks about TB-F

1 Like

I spent some time reading the Chapter 4 of the above book.There is a section that explains the "Critical Role of D in the TB-F Formula)" and it helps to understand why this indicator is a bit odd...

"With the understanding that D is a fixed amount of cumulative volume set by the user, the reader may wonder how much cumulative volume is required on each occasion of its use."
....
"Practically speaking, there are various ways to input D. In the method in ..., for which Hawkins acted as consultant, D is automatically calculated as the user drags the mouse over the pullback. In eSignal and Metastock, we input D manually until a visual fit is obtained between the curve and the pullback. "

Actually I was able to use the provided Amibroker formula (using the SelectedValue for the start date and time instead of params) selecting the "starting" bar directly on a chart and manually entering the value of D (or more simply using again the SelectedValue of the corresponding cumulative volume multiplied times a discretionary user input amount. Probably it is possible to use the range functionality to provide automatically a D value).

This DOES NOT mean that the provided formula is a correct one.... but on some charts, it looks not to far from the descriptions.

immagine

Further work by experts is welcome!

P.S. The orange line is the TB-F line and the yellow one is the Midas curve.

beppe, it’s looking good!
Could you share the formula, please?

hi beppe,

yes it is not so easy, i’m not there yet myself. Not sure it is worth the time but I find it very interesting. Interesting how this guy thought about how this stuff all works.

I hope somebody else figures it out before me (will save me some time :smile: ).

1 Like

As said the formula is the one you posted (I simply added also the TJ coded Midas curve).

The key point is that you need to enter your own estimated cumulative value for the param D, as the book explains, calculating its value based on the cumulative volume from start date/time until the first pullback. You can also change the beginning of the formula to use a selection on the chart (instead of using a parameter):

dn = DateNum();
tn = TimeNum();
sd = SelectedValue( dn );
st = SelectedValue( tn );

(Actually, I only dabbled with EOD data)

Note that you need to use as a starting point what looks like the beginning of an “accelerated trend” (as per the book theory).

In any case, personally, I will not rely on any formula that I do not fully understand!

I know about 'key point' - you need to enter your own estimated cumulative value for the param D
But, Unfortunately, i see such sad result:
TBF009

The hi of the starting candle is 113200 and the TB-F as you can see go to 114135. And after that there are wrong way
Sorry for my English

The initial spike in your chart is probably due to a too low value of D. Try to increase it progressively and see what happens.

Check also the ParamField used for the price: - I used the L (Low).

I did a test on today futures (NQ) 1m charts and got this result (after testing multiple values for D).

immagine

In this chart, I added the cumulative volume pane from the selected bar and the volume for reference (the date/time axis show times as per my time zone).

Since, in any case, it seems quite discretionary (and getting it wrong results in very odd curves) I doubt about the usefulness of it, but probably I'm missing something!

More reading and coding needed...

1 Like

i couldn’t yet explain in 1 sentence what it is all about. But the essence is that it is a derivative of VWAP. VWAP is a volume weighted average. The MIDAS curve is the same but it is calculated from a start point. The TB-F starts at the same point as the Midas curve but only supplies a certain amount of fuel (volume).

Anyways I could reproduce an example in the manual, table A.1 at page 408, up to a certain point. The first few bars I could not reproduce yet. But that is just the start and not so important at this point.

some code below. The amount of “fuel” you can regulate in the param window. This is however not yet finished but might trigger some of you guys to add in

Version( 6.0 );
nbars = Param( "nbars", 20, 0, 300, 1 );
dn = DateTime();
sd = SelectedValue( dn );
start = dn == sd;
stidx = LastValue( ValueWhen( start, BarIndex() ) );
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 ) );

idx = 0;

for( i = stidx + 1; i < BarCount; i++ )
{
    MidasLoop[i] = cumpvol[i] / cumvol[i];

	dd = cumvol[stidx] * nbars;
    d1 = cumvol[i];
    e1 = d1 * ( 1 - d1 / dd );
    x1 = d1 - e1;
    idx = 1;

    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
    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, 2 );
Plot( TBFLoop, "TB-F", colorLightBlue, styleLine | styleNoRescale, Null, Null, 0, 0, 2 );
2 Likes

the response is really spectacular, like close to 0% but for completion I’ll update the code. The code is now working correctly, tested it with the test data from the manual.

thing is with this top/bottom finder is that you need to define D. In my code D can be set using a variable but as far as I understand it D should be calculated using a fit against pullbacks. That is what I will do next and try it out. But my contribution to this thread end here :stuck_out_tongue:

/*
© 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)
*/
Version( 6.0 );
nbars = Param( "nbars", 50, 0, 3000, 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() ) );
mp = ( H + L ) / 2;
lvb = Max( 0, LastVisibleValue( BarIndex() ) ) + 1;

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 ) );

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
    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 );
11 Likes

@empottasch very well done!

Just a small note. The correct book title is:
MIDAS Technical Analysis: A VWAP Approach to Trading and Investing in Today’s Markets
by David G. Hawkins; Andrew Coles
Published by Bloomberg Press, 2011

I personally doubt that this book is actually “free” on the internet. The link in this thread is coming from a dubious domain, and maybe a copyright infringement. Maybe not… but better to stay on the safe side.

(By the way, I have access to this book online - and hundreds of other trading/investing/finance/programming languages books - via a subscription to SafariBooksOnline: (IMHO a very great resource for both traders and programmers!)

2 Likes

well Levine’s work is free. He says so himself in his manual. So the other PhD’s didn’t pay for it, I guess. And most of all I am not making any money posting free code, especially since you are the only 1 reading it :smile: even the guy from Siberia who started this thread has better things to do

1 Like