Comments on S&C Traders' Tips Issue 05/2015

*** This message is posted in Amibroker Community Forum ***

Hello,
Regarding to Amibroker code for Stocks & Commodities Traders’ Tips Issue 05/2015, the code seems malfunction. Enclosed please find the code regarding to my comments on modifying the code. However, the code seems running very very slow. Is it because of varget? I am using it in 1 min chart. How can I speed it up!

Please comment!

Regards,

Terence

SetBarsRequired( sbrAll, 0 );

function FindMiddlePIP( data, x0, x1, curdist )
{
    bi = BarIndex();

    y0 = data[ x0 ];
    y1 = data[ x1 ];

    line = y0 + ( y1 - y0 ) * ( bi - x0 ) / ( x1 - x0 );

    distance = abs(  data - line );
    maxbars = HHVBars( distance, x1 - x0 );
    pipbar = Nz( x1 - maxbars[ x1 ], -1 );

    if ( pipbar != -1 )
        VarSet( "curdist", distance[ pipbar ] ); // VarSet( curdist, distance[ pipbar ] );
        
    return pipbar;
}

LogMode = ParamToggle( "Mode", "Linear|Logarithmic", 0 );
MaxLegs = Param( "MaxLegs", 20, 4, 500 );

// one leg first - from start to end
pips = 0;
pips[ 0 ] = 1;
pips[ BarCount - 1 ] = 1;

data = Close;

if ( LogMode ) data = log( Data );

for ( legs = 0; legs < maxlegs; legs++ )
{
    x0 = 0;
    x1 = -1;
    oldpip = -1;
    maxdist = 0;

    for ( i = 0; i < BarCount; i++ )
    {
        if ( pips[ i ] )
        {
            x1 = i;

            if ( x1 > x0 )
            {
                VarSet( "curdist", 0 ); //curdist = 0;
                newpip = FindMiddlePIP( data, x0, x1, VarGet("curdist") ); // newpip = FindMiddlePIP( data, x0, x1, "curdist" );

                if ( newpip != -1 && VarGet("curdist") > maxdist  ) // if ( newpip != -1 && curdist > maxdist  )
                {
                    maxdist = VarGet("curdist"); // maxdist = curdist;

                    if ( oldpip != -1 )
                        pips[ oldpip ] = 0; // remove smaller one

                    pips[ newpip ] = 1;
                    oldpip = newpip;
                }

                x0 = x1; // next leg
                x1 = -1; //
            }
        }
    }
}

// draw lines connecting pip points
x0 = 0;
x1 = -1;
zzline = Null;
for ( i = 0; i < BarCount; i++ )
{
     if ( pips[ i ] )
     {
        x1 = i;
        line = LineArray( x0, data[ x0 ], x1, data[ x1 ] );
        zzline = IIf( NOT IsNull( line ), line, zzline );
        x0 = x1;
     }
}

if ( LogMode )
    zzline = exp( zzline );

Plot( zzline, "zzTop", colorRed, styleThick );
Plot( C, "Price", colorDefault );

@ngterry I tried using the original code on my daily data and it works quickly and Plots just fine. Perhaps it is your use of 1 minute bars?

Hello
I start to read the code and My eyes stoped at the first line.
So you have to do something with this. Read the link to find out how and when we use it.

Now, one more solution is:
Since you run this afl in 1 min chart (and maybe in live data), what i am thinking is to minimize the repeating execution, to ONCE per new bar.

// When using 1 minute data the newbar code by  herman gives a signal each minute
PrevDT = StaticVarGet("DateTime");
DT = LastValue(DateTime());
NewBar = DT != PrevDT;
StaticVarSet("DateTime",DT);

if( NewBar )
{
  // insert your code in here to execute Once per NewBar 
}

or this code

/*  NewBar  by Tomasz Janeczko 03/02/2015
The easiest is just to check the change in Status("lastbarend") - if value returned changes it means
new bar 
*/
varname = "lastbarend" + GetChartID();
NewBar = Status("lastbarend") != StaticVarGet( varname );

if( NewBar ) StaticVarSet( varname, Status("lastbarend") );

i looked at the article of this method and it is presented like an indicator but one has to define the number of legs. So if you use all data and more data comes in then the number of legs stay the same and therefor the function will “repaint” or redraw itself, since for every new data point that comes in it will have to recalculate all PIP points. Since the first 2 points of this method are fixed, namely the first and the last datapoint, you will have to use setbarsrequired( sbrall, 0 ), so it will be slow if you work in the 1-minute time frame. But the method makes no sense at all if you ask me, I wouldn’t waste time on it.

It is strange. I am sure the original code does not respond in 1 min chart, unless I modify the code.

Thank you all for your precious comments!

You should NOT modify S&C Traders Tips code. The original is working fast and precisely 100% as described in the Stocks&Commodities article and does not have any “malfunctions”.

I don’t think I cannot differentiate between slowness and malfunction. I have tried it again and again. Since portfoliobuilder had tested in on daily data, that means the program is working properly. Is there any chance because I am using real-time database (esignal), even though I switched to use the original database shipped with Amibroker, the original program still does not respond?

First quesiton: what AmiBroker version you are using? I guess you are using some ancient one, without mulithreading.That is the source of your problems.

Secondly, did you read the S&C article? The S&C article is written for DAILY interval and all examples in the article use DAILY interval and for up to 64K bars that is Metastock limit (the original author used Metastock) and they used the DLL in Metastock because they have no loops in MS and would not be able to write that at all in MS. AmiBroker code does NOT need to use any DLLs to write formula like this. It is pure AFL and does not have 64K bars limit.
But the code as it is presented in S&C Traders Tips is obviously for DAILY interval too.

It can not be applied to 1-minute without changes because it is simply NOT WRITTEN for 1-minute interval. To use it in 1-minute interval you have to change SetBarsRequired call as was advised by all people in this thread already.

Adjusted code is below (the only change is change to SetBarsRequired and added requirement to use version 6.00 - old versions are NOT supported on this forum).

Version( 6.0 );

function FindMiddlePIP( data, x0, x1, curdist ) 
{ 
  bi = BarIndex(); 

  y0 = data[ x0 ]; 
  y1 = data[ x1 ]; 

  line = y0 + ( y1 - y0 ) * ( bi - x0 ) / ( x1 - x0 ); 

  distance = abs(  data - line ); 
  maxbars = HHVBars( distance, x1 - x0 ); 
  pipbar = Nz( x1 - maxbars[ x1 ], -1 ); 

  if ( pipbar != -1 ) 
     VarSet( curdist, distance[ pipbar ] ); 

  return pipbar; 
} 

LogMode = ParamToggle( "Mode", "Linear|Logarithmic", 0 ); 
MaxLegs = Param( "MaxLegs", 20, 4, 35 ); 

data = Close;
// one leg first - from start to end 
legs = 1; 
pips = 0; 
pips[ 0 ] = 1; 
pips[ BarCount - 1 ] = 1; 

if ( LogMode ) data = log( Data ); 

for ( ; legs < maxlegs; legs++ ) 
{ 
 x0 = 0; 
 x1 = -1; 
 oldpip = -1; 
 maxdist = 0; 

 for ( i = 0; i < BarCount; i++ ) 
 { 
  if ( pips[ i ] ) 
  { 
    x1 = i; 

    if ( x1 > x0 ) 
    { 
      curdist = 0; 
      newpip = FindMiddlePIP( data, x0, x1, "curdist" ); 

      if ( newpip != -1 AND curdist > maxdist  ) 
      { 
          maxdist = curdist; 

          if ( oldpip != -1 ) 
              pips[ oldpip ] = 0; // remove smaller one 

          pips[ newpip ] = 1; 
          oldpip = newpip; 
      } 

      x0 = x1; // next leg 
      x1 = -1; // 
   } 
  } 
 } 
} 

// draw lines connecting pip points 
x0 = 0; 
x1 = -1; 
zzline = Null; 
for ( i = 0; i < BarCount; i++ ) 
{ 
     if ( pips[ i ] ) 
     { 
         x1 = i; 
         line = LineArray( x0, data[ x0 ], x1, data[ x1 ] ); 
         zzline = IIf( NOT IsNull( line ), line, zzline ); 
         x0 = x1; 
     } 
} 

if ( LogMode ) 
     zzline = exp( zzline ); 

Plot( zzline, "zzTop", colorRed, styleThick ); 
Plot( C, "Price", colorDefault ); 

SetBarsRequired( 2000, 0 ); 

When applied to 1-minute data (IQFeed, 400K bars) the display looks like this (make sure you have multithreading turned ON)

image

I included chart timing. As you can see it takes 0.24 second to calculate on 1-minute data with 2 months zoomed in. With just one month of 1-minute data the timing is 0.09 second.

image

If you want better timing you need to follow advice given in the manual http://www.amibroker.com/guide/x_performance.html

As it was noted already the "last leg" of any zig-zag is subject to change due to the way how zig-zag is constructed. Also as you zoom in the number of bars taken into the formula would differ resulting in different number of "legs" (as the original author has choosen to fix the number of "legs" instead of fixing the number of legs per fixed amount of bars, or better per time as say 20 legs per year or something).

I think you are missing the point of S&C Traders Tips code. The point is to present VERBATIM re-implementation of examples given in S&C articles. Traders' Tips don't try to "fix" or "enhance" ideas from S&C articles. Except 2 or 3 cases in entire history when I simply refused to write code because the article made no sense at all, I just re-implemented in AFL what article author wrote in their own platform without getting into much discussion whenever idea is good or bad.

2 Likes

I am using Amibroker, Professional Edition (64-bit), Version 6.27.0, Build date: Nov 1 2017, and Windows 7 Service Pack 1.

It is strange that even updated to the adjusted code, the program still does not respond.

After updated to Amibroker Version 6,27.1, the code works.

When you use BETA versions, the rule is always use very LATEST one, especially if you see two versions differing by 0.0.1. These 0.0.1 updates are fix-only to regressions introduced in previous BETA. In 6.27.0 there was regression to VarSetVarGet as described in read me. 6.27.1 fixed that regression. You would not have problems if you used any other version than 6.27.0. If you want to run stable version, you should be running 6.20 (latest official).

1 Like

Thank you very much, and happy new year!

varname = "lastbarend" + GetChartID();
NewBar = Status("lastbarend") != StaticVarGet( varname );

if( NewBar ) StaticVarSet( varname, Status("lastbarend") );

As I am new to Amibroker AFL, I dont quite understand the above code, can you please help?

Thank very much in advance.
Peter