# TASC 2015-05 | Filtering Price Movement (Siligardos)

We’ve implemented the “Perceptually Important Points” (PIPs) method in a script study that uses a recursive call to find the PIP having the maximum absolute value of the vertical distance from the line connecting two PIPs previously found. The price movement plot is based on a user-specified percentage. As suggested by the article, for a DataSeries plotted in the arithmetic scale the minimum vertical distance required to find a PIP is the percentage of the DataSeries’ entire range, whereas a fixed vertical distance in a log plot is inherently represented equally by the same percentage. For example, on a log chart the distance between 1 and 10 is the same as that between 10 and 100 (or for any other 1000% price change). Finally note that due to the manner in which the indicator is constructed, the zzTOP indicator “must not” be used for backtesting, but rather could be useful for digitally scanning many charts for patterns. Figure 1. Wealth-Lab’s zzTopAuto routine automatically adjusts for the chart pane’s log or arithmetic scale.

```using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using WealthLab;
using WealthLab.Indicators;
using Community.Components;namespace WealthLab.Strategies
{
internal struct PipInterval
{
public int X1;
public int X2;
}

public class zzTOPAutoStudy : WealthScript
{
StrategyParameter _pct;
StrategyParameter _thickness;
List<int> _pipList;      // list of PIP bar numbers

public zzTOPAutoStudy()
{
_pct = CreateParameter("PIP Percent", 20, 2, 50, 1);
_thickness = CreateParameter("Line Width", 2, 1, 3, 1);
}

int getPipBar(DataSeries ds, PipInterval pi, double minMove, bool useLog)
{
int pip = 0;
double maxDiff = 0;
double delta, y;

for(int bar = pi.X1; bar <= pi.X2; bar++)
{
if (useLog)
{
y = LineExtendYLog( pi.X1, ds[pi.X1], pi.X2, ds[pi.X2], bar );
delta = Math.Abs(Math.Log(ds[bar] / y));
}
else
{
y = LineExtendY( pi.X1, ds[pi.X1], pi.X2, ds[pi.X2], bar );
delta = Math.Abs(ds[bar] - y);
}

if( delta > maxDiff )
{
maxDiff = delta;
pip = bar;
}
}

if (maxDiff < minMove)
pip = -1;   // invalid; no PIP in specified PipInterval

if (pip > 0)

return pip;
}

/* Find the new PIP for each PipInterval in the List and return the new PipIntervals */
internal List<PipInterval> zzTopAuto(List<PipInterval> piList, DataSeries ds, double minmove, bool useLog)
{
List<PipInterval> nextList = new List<PipInterval>();

foreach (PipInterval pi in piList)
{
int bar = getPipBar(ds, pi, minmove, useLog);

if (bar == -1)
continue;
else
{
PipInterval newinvl = new PipInterval();
newinvl.X1 = pi.X1;
newinvl.X2 = bar;

PipInterval newinvl2 = new PipInterval();
newinvl2.X1 = bar;
newinvl2.X2 = pi.X2;
}
}

if (nextList.Count != 0)
zzTopAuto(nextList, ds, minmove, useLog);

return nextList;
}

void ZZTOP(DataSeries ds, ChartPane cp, double minPercent)
{
// Minimum vertical move for the arithmetic and log cases
double minV = 0;
if (cp.LogScale)
minV = Math.Log(1 + minPercent/100d);
else
{
int bc = Bars.Count;
minV = minPercent / 100d * (Highest.Value(bc-1, ds, bc) - Lowest.Value(bc-1, ds, bc));
}

// Initialize _pipList with the first and last bar numbers
int nbars = Bars.Count - 1;
_pipList = new List<int>();

// Initialize the first list to pass to zzTopAuto
PipInterval interval = new PipInterval();
interval.X1 = 0;
interval.X2 = nbars;
List<PipInterval> aList = new List<PipInterval>();

// Let the recursion begin!
zzTopAuto(aList, ds, minV, cp.LogScale);

// Sort the result to plot lines between the PIPs
_pipList.Sort();

int lastpip = 0;
foreach (int pip in _pipList)
{
if (pip == 0) continue;
DrawLine(cp, lastpip, ds[lastpip], pip, ds[pip], Color.Blue, LineStyle.Solid, _thickness.ValueInt);
lastpip = pip;
}

int segments = _pipList.Count - 1;
DrawLabel(cp, "Log Scale: " + cp.LogScale.ToString());
DrawLabel(cp, "Segment Count: " + segments.ToString());
DrawLabel(cp, "PIP: " + minPercent + "%");
//DrawLabel(cp, "Press Go! after switch between Log and Arithmetic scales!", Color.Red);
}

protected override void Execute()
{
ZZTOP(Close, PricePane, _pct.Value);

DataSeries rsi = RSI.Series(Close, 14);
ChartPane rsiPane = CreatePane(40, true, true);
PlotSeries(rsiPane, rsi, Color.Black, LineStyle.Solid, 1);
ZZTOP(rsi, rsiPane, _pct.Value);
}
}
}```

Robert Sucher
www.wealth-lab.com
 Important Disclaimer: The information provided by Wealth-Lab is strictly for informational purposes and is not to be construed as advice or solicitation to buy or sell any security.  The owner of Wealth-Lab.com assumes no liability resulting from the use of the material contained herein for investment purposes. By using this web site, you agree to the terms of this disclaimer and our Terms of Use.

ScrewTurn Wiki. Some of the icons created by FamFamFam.