(*Description... Peaks&Troughs Indicator (PTBar) and Swing Indicator (SI) - as described in November 2006 Stocks&Commodities (Siligardos' article on "Active Trend Lines") function PTBarSeries builds a series containing bar numbers of most recent peaks/troughs, by measuring percent changes from lowest values, that is: using (100*Threshold)/(100+Threshold) when looking for peaks [this is to ensure that any two consecutive peaks (resp. troughs) will have exactly one trough (resp. peak) between them] function SISeries builds a series that interpolates through those peaks and troughs N.B.: USES FUTURE INFORMATION!!! *) function PTBarSeries(Series: integer; Threshold: float): integer; begin var Name: string = 'PTBar(' + GetDescription(Series) + ',' + FloatToStr(Threshold) + ')'; Result := FindNamedSeries(Name); if Result >= 0 then exit; Result := CreateNamedSeries(Name); var Bar1, Bar2, Bar: integer; var PeakReversalFactor: float = 100 / (100 + Threshold); var TroughReversalFactor: float = (100 + Threshold) / 100; // locate Bar2 as the earliest bar that goes "far enough" from first bar for Bar2 := 1 to BarCount - 1 do if (@Series[Bar2] >= @Series[Bar1] * TroughReversalFactor) or (@Series[Bar2] <= @Series[Bar1] * PeakReversalFactor) then break; // go on, alternating peaks and troughs for Bar := Bar2 to BarCount - 1 do begin if (@Series[Bar2] > @Series[Bar1]) then // looking for a new peak begin if (@Series[Bar] >= @Series[Bar2]) then Bar2 := Bar // found higher high else if (@Series[Bar] <= @Series[Bar2] * PeakReversalFactor) then begin // reversal triggered at Bar, peak at Bar2 is confirmed Bar1 := Bar2; Bar2 := Bar; end; end else // @Series[Bar2] < @Series[Bar1], looking for a new trough begin if (@Series[Bar] <= @Series[Bar2]) then Bar2 := Bar // found lower low else if (@Series[Bar] >= @Series[Bar2] * TroughReversalFactor) then begin // reversal triggered at Bar, trough at Bar2 is confirmed Bar1 := Bar2; Bar2 := Bar; end; end; // Bar1 is last confirmed peak/trough bar (as seen at Bar) SetSeriesValue(Bar, Result, Bar1); end; end; function PTBar(Bar, Series: integer; Threshold: float): integer; begin Result := trunc(GetSeriesValue(Bar, PTBarSeries(Series, Threshold))); end; function SISeries(Series: integer; Threshold: float): integer; begin var Name: string = 'SwingIndicator(' + GetDescription(Series) + ',' + FloatToStr(Threshold) + ')'; Result := FindNamedSeries(Name); if Result >= 0 then exit; Result := CreateNamedSeries(Name); var Bar, Bar1, Bar2: integer; var PTBs: integer = PTBarSeries(Series, Threshold); Bar1 := BarCount - 1; for Bar := Bar1 downto 0 do begin if Bar = Bar1 then begin Bar2 := Bar1; Bar1 := trunc(@PTBs[Bar2]); end; SetSeriesValue(Bar, Result, LineExtendY(Bar1, @Series[Bar1], Bar2, @Series[Bar2], Bar)); end; end; function SI(Bar, Series: integer; Threshold: float): float; begin Result := GetSeriesValue(Bar, SISeries(Series, Threshold)); end;