Parent: Object
The PeakTroughCalculator class calculates peaks and troughs in source time series data. Peaks and troughs are detected when the data reverses by a specified amount, which can be expressed as a percentage, point value, ATR multiple, or ATR percentage. The resulting PeakTrough instances are available through the PeakTroughs property. Because a reversal must occur before a peak or trough can be confirmed, detection always occurs after the actual peak or trough. Each PeakTrough contains both the index where the peak or trough occurred (PeakTroughIndex) and the index where it was confirmed (DetectedAtIndex).
Draws lines connecting confirmed peaks. Pass this for usb when calling the method from a C# Coded Strategy. If the most recently confirmed PeakTrough is a trough, the method also draws a dotted gray line from the latest confirmed peak to the current provisional peak.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class DrawPeakLinesExample : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { _ptc = new PeakTroughCalculator( bars, 10.0, PeakTroughReversalType.Percent); _ptc.DrawPeakLines( this, WLColor.Red, 2, LineStyle.Solid); } public override void Execute(BarHistory bars, int idx) { } } }
Draws lines connecting confirmed troughs. Pass this for usb when calling the method from a C# Coded Strategy. If the most recently confirmed PeakTrough is a peak, the method also draws a dotted gray line from the latest confirmed trough to the current provisional trough.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class DrawTroughLinesExample : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { _ptc = new PeakTroughCalculator( bars, 10.0, PeakTroughReversalType.Percent); _ptc.DrawTroughLines( this, WLColor.Green, 2, LineStyle.Solid); } public override void Execute(BarHistory bars, int idx) { } } }
The first constructor calculates peaks and troughs using separate highs and lows TimeSeries. The second constructor accepts a BarHistory and calculates peaks and troughs from its High and Low price series. The optional atrPeriod specifies the period used when reversalType is PeakTroughReversalType.ATR or PeakTroughReversalType.ATRPercent. The third constructor calculates peaks and troughs from a single TimeSeries. The fourth constructor initializes the calculator with an existing List<PeakTrough>. The supported PeakTroughReversalType values are:
- Percent - A peak or trough is detected after the source reverses by reversalAmount percent.
- Point - A peak or trough is detected after the source reverses by reversalAmount points.
- ATR - The reversal amount is determined by multiplying ATR by reversalAmount.
- ATRPercent - The reversal percentage is determined by multiplying ATRP by reversalAmount.
Note: Percentage-based reversals can produce unexpected results when applied to TimeSeries containing negative values. Use PeakTroughReversalType.Point for such series.
using WealthLab.Backtest;
using WealthLab.Core;
using WealthLab.Indicators;
namespace WealthScript
{
public class PeakTroughCalculatorExample : UserStrategyBase
{
private PeakTroughCalculator _ptc;
public override void Initialize(BarHistory bars)
{
_ptc = new PeakTroughCalculator(
bars,
5.0,
PeakTroughReversalType.Percent);
foreach (PeakTrough pt in _ptc.PeakTroughs)
{
WLColor color = pt.Type == PeakTroughType.Peak
? WLColor.Red
: WLColor.Green;
DrawDot(pt.XIndex, pt.YValue, color, 4);
}
}
public override void Execute(BarHistory bars, int idx)
{
}
}
}
Returns true if the two applicable peaks as of idx are within maxPercentDiff percent of one another. When useProvisional is false, only confirmed peaks are considered. When useProvisional is true and the most recent confirmed PeakTrough is a trough, the current provisional peak is compared with the most recent confirmed peak. Because the provisional peak can continue to change, the result can also change until the peak is confirmed. For example, with the default maxPercentDiff of 0.1 and a previous peak of $20.00, another peak between $19.98 and $20.02, inclusive, is considered approximately equal. Unlike PeakState, which returns 0 only when two confirmed peaks have exactly the same value, HasEqualPeaks permits a percentage tolerance.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class EqualPeaksExample : UserStrategyBase { private PeakTroughCalculator _ptc; private SMA _sma; public override void Initialize(BarHistory bars) { _ptc = new PeakTroughCalculator( bars, 5.0, PeakTroughReversalType.Percent); _sma = SMA.Series(bars.Close, 200); PlotIndicator(_sma); ZigZagHL zz = new ZigZagHL( bars, 5.0, PeakTroughReversalType.Percent, false); PlotIndicator(zz, WLColor.Gray); } public override void Execute(BarHistory bars, int idx) { PeakTrough pt = _ptc.GetPeakTrough(idx); if (pt == null) return; if (bars.Close[idx] < _sma[idx] && pt.Type == PeakTroughType.Trough && _ptc.HasEqualPeaks(idx, 0.25, true)) { SetBackgroundColor( bars, idx, WLColor.FromArgb(40, WLColor.Red)); } } } }
Returns true if the two applicable troughs as of idx are within maxPercentDiff percent of one another. When useProvisional is false, only confirmed troughs are considered. When useProvisional is true and the most recent confirmed PeakTrough is a peak, the current provisional trough is compared with the most recent confirmed trough. For example, with the default maxPercentDiff of 0.1 and a previous trough of $20.00, another trough between $19.98 and $20.02, inclusive, is considered approximately equal. Unlike TroughState, which returns 0 only when two confirmed troughs have exactly the same value, HasEqualTroughs permits a percentage tolerance.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class EqualTroughsExample : UserStrategyBase { private PeakTroughCalculator _ptc; private SMA _sma; public override void Initialize(BarHistory bars) { _ptc = new PeakTroughCalculator( bars, 5.0, PeakTroughReversalType.Percent); _sma = SMA.Series(bars.Close, 200); PlotIndicator(_sma); ZigZagHL zz = new ZigZagHL( bars, 5.0, PeakTroughReversalType.Percent, false); PlotIndicator(zz, WLColor.Gray); } public override void Execute(BarHistory bars, int idx) { PeakTrough pt = _ptc.GetPeakTrough(idx); if (pt == null) return; if (bars.Close[idx] > _sma[idx] && pt.Type == PeakTroughType.Peak && _ptc.HasEqualTroughs(idx, 0.25, true)) { SetBackgroundColor( bars, idx, WLColor.FromArgb(40, WLColor.Green)); } } } }
Returns true if the most recent peak as of idx has a lower value than the previous peak. When useProvisional is false, only confirmed peaks are considered. When useProvisional is true, a currently falling-peaks condition can become false following a trough if the provisional peak rises above the previous confirmed peak.
Returns true if the most recent trough as of idx has a lower value than the previous trough. When useProvisional is false, only confirmed troughs are considered. When useProvisional is true, a falling-troughs condition can become true following a peak if the provisional trough falls below the previous confirmed trough.
Returns true if the most recent peak as of idx has a higher value than the previous peak. When useProvisional is false, only confirmed peaks are considered. When useProvisional is true, a rising-peaks condition can become true following a trough if the provisional peak rises above the previous confirmed peak.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class RisingFallingExample : UserStrategyBase { private PeakTroughCalculator _pricePTC; private PeakTroughCalculator _rsiPTC; private RSI _rsi; public override void Initialize(BarHistory bars) { StartIndex = 100; _pricePTC = new PeakTroughCalculator( bars.Close, 10.0, PeakTroughReversalType.Percent); _rsi = RSI.Series(bars.Close, 14); PlotIndicator(_rsi); _rsiPTC = new PeakTroughCalculator( _rsi, 10.0, PeakTroughReversalType.Point); } public override void Execute(BarHistory bars, int idx) { if (_pricePTC.HasRisingPeaks(idx) && _rsiPTC.HasFallingPeaks(idx)) { SetBackgroundColor( bars, idx, WLColor.FromArgb(40, WLColor.Red)); } if (_pricePTC.HasFallingTroughs(idx) && _rsiPTC.HasRisingTroughs(idx)) { SetBackgroundColor( bars, idx, WLColor.FromArgb(40, WLColor.Green)); } } } }
Returns true if the most recent trough as of idx has a higher value than the previous trough. When useProvisional is false, only confirmed troughs are considered. When useProvisional is true, a rising-troughs condition can become false following a peak if the provisional trough falls below the previous confirmed trough.
Compares the two most recent confirmed peaks as of idx. Returns:
- 1 if the most recent peak is higher than the previous peak.
- -1 if the most recent peak is lower than the previous peak.
- 0 if the peaks are equal or insufficient confirmed peaks are available. PeakState considers only confirmed PeakTroughs.
Compares the two most recent confirmed troughs as of idx. Returns:
- 1 if the most recent trough is higher than the previous trough.
- -1 if the most recent trough is lower than the previous trough.
- 0 if the troughs are equal or insufficient confirmed troughs are available. TroughState considers only confirmed PeakTroughs.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class PeakTroughStateExample : UserStrategyBase { private PeakTroughCalculator _pricePTC; private PeakTroughCalculator _rsiPTC; private RSI _rsi; public override void Initialize(BarHistory bars) { StartIndex = 100; _pricePTC = new PeakTroughCalculator( bars.Close, 10.0, PeakTroughReversalType.Percent); _rsi = RSI.Series(bars.Close, 14); PlotIndicator(_rsi); _rsiPTC = new PeakTroughCalculator( _rsi, 10.0, PeakTroughReversalType.Point); } public override void Execute(BarHistory bars, int idx) { if (_pricePTC.PeakState(idx) != _rsiPTC.PeakState(idx)) { SetBackgroundColor( bars, idx, WLColor.FromArgb(40, WLColor.Red)); } if (_pricePTC.TroughState(idx) != _rsiPTC.TroughState(idx)) { SetBackgroundColor( bars, idx, WLColor.FromArgb(40, WLColor.Green)); } } } }
Returns the most recently confirmed peak as of idx, or null if no peak is available.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class GetPeakExample : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { _ptc = new PeakTroughCalculator( bars, 5.0, PeakTroughReversalType.Percent); int idx = bars.Count - 1; PeakTrough lastPeak = null; do { PeakTrough peak = _ptc.GetPeak(idx); if (peak == null) break; if (lastPeak != null) { DrawLine( lastPeak.XIndex, lastPeak.YValue, peak.XIndex, peak.YValue, WLColor.Red, 2); } lastPeak = peak; idx = peak.XIndex - 1; } while (idx > 10); } public override void Execute(BarHistory bars, int idx) { } } }
Returns a List<PeakTrough> containing peaks that had been confirmed as of idx. If maxAgeInDays is specified, peaks whose apex is more than that number of calendar days older than the date at idx are excluded. The returned List is ordered from the most recent qualifying peak backward in time.
using System.Collections.Generic; using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class GetPeaksAsOfExample : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { _ptc = new PeakTroughCalculator( bars, 10.0, PeakTroughReversalType.Percent); List<PeakTrough> peaks = _ptc.GetPeaksAsOf(bars.Count - 1); PeakTrough previous = null; foreach (PeakTrough peak in peaks) { if (previous != null) { DrawLine( previous.XIndex, previous.YValue, peak.XIndex, peak.YValue, WLColor.Blue, 2); } previous = peak; } } public override void Execute(BarHistory bars, int idx) { } } }
Returns the most recently confirmed peak or trough as of idx, or null if none is available.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class GetPeakTroughExample : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { _ptc = new PeakTroughCalculator( bars, 5.0, PeakTroughReversalType.Percent); } public override void Execute(BarHistory bars, int idx) { PeakTrough pt = _ptc.GetPeakTrough(idx); if (pt == null) return; WLColor color = pt.Type == PeakTroughType.Peak ? WLColor.Red : WLColor.Green; SetBarColor(bars, idx, color); } } }
Returns the most recently confirmed trough as of idx, or null if no trough is available.
Returns a List<PeakTrough> containing troughs that had been confirmed as of idx. If maxAgeInDays is specified, troughs whose nadir is more than that number of calendar days older than the date at idx are excluded. The returned List is ordered from the most recent qualifying trough backward in time.
Returns a List<PeakTrough> containing only the peaks generated by the calculator. The List is derived from PeakTroughs and contains PeakTrough instances whose Type is PeakTroughType.Peak.
Returns the complete List<PeakTrough> generated by the calculator, containing both peaks and troughs in chronological order.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class PeakTroughsExample : UserStrategyBase { public override void Initialize(BarHistory bars) { PeakTroughCalculator ptc = new PeakTroughCalculator( bars, 5.0, PeakTroughReversalType.Percent); foreach (PeakTrough pt in ptc.PeakTroughs) { WLColor color = pt.Type == PeakTroughType.Peak ? WLColor.Red : WLColor.Green; DrawDot( pt.PeakTroughIndex, pt.Value, color, 4); } } public override void Execute(BarHistory bars, int idx) { } } }
Returns a List<PeakTrough> containing only the troughs generated by the calculator. The List is derived from PeakTroughs and contains PeakTrough instances whose Type is PeakTroughType.Trough.
Returns the peak following the specified pt, or null if no subsequent peak is available. If pt is itself a peak, the following peak is returned. If pt is a trough, the peak immediately following that trough is returned.
Returns the PeakTrough immediately following pt in the alternating sequence of peaks and troughs. If pt is a peak, this method returns the following trough. If pt is a trough, it returns the following peak.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class NextPeakTroughExample : UserStrategyBase { public override void Initialize(BarHistory bars) { PeakTroughCalculator ptc = new PeakTroughCalculator( bars, 5.0, PeakTroughReversalType.Percent); foreach (PeakTrough pt in ptc.PeakTroughs) { PeakTrough next = ptc.GetNextPeakTrough(pt); if (next == null) continue; DrawLine( pt.XIndex, pt.YValue, next.XIndex, next.YValue, WLColor.Blue, 2); } } public override void Execute(BarHistory bars, int idx) { } } }
Returns the trough following the specified pt, or null if no subsequent trough is available. If pt is itself a trough, the following trough is returned. If pt is a peak, the trough immediately following that peak is returned.
Returns the confirmed peak preceding the specified pt, or null if a previous peak is not available.
Returns the PeakTrough immediately preceding pt in the alternating sequence of peaks and troughs. If pt is a peak, this method returns the preceding trough. If pt is a trough, it returns the preceding peak.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class PreviousPeakTroughExample : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { _ptc = new PeakTroughCalculator( bars, 5.0, PeakTroughReversalType.Percent); } public override void Execute(BarHistory bars, int idx) { PeakTrough current = _ptc.GetPeakTrough(idx); if (current == null) return; PeakTrough previous = _ptc.GetPrevPeakTrough(current); if (previous == null) return; if (current.DetectedAtIndex == idx) { DrawLine( previous.XIndex, previous.YValue, current.XIndex, current.YValue, WLColor.Blue, 2); } } } }
Returns the confirmed trough preceding the specified pt, or null if a previous trough is not available.
Returns the index of the provisional, not-yet-confirmed peak or trough as of idx. After a confirmed trough, this is the index of the highest value encountered while searching for the next peak. After a confirmed peak, it is the index of the lowest value encountered while searching for the next trough. Before the first confirmed PeakTrough is available, the method returns -1.
Returns the value of the provisional, not-yet-confirmed peak or trough as of idx. After a confirmed trough, the method returns the provisional peak value. After a confirmed peak, it returns the provisional trough value. Returns Double.NaN if a provisional value is not available.
using System; using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class ProvisionalPeakTroughExample : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { double reversal = 2.0; _ptc = new PeakTroughCalculator( bars, reversal, PeakTroughReversalType.Percent); ZigZagHL zz = new ZigZagHL( bars, reversal, PeakTroughReversalType.Percent, true); PlotIndicator(zz); } public override void Execute(BarHistory bars, int idx) { int provisionalIndex = _ptc.ProvisionalPeakTroughIndex(idx); double provisionalValue = _ptc.ProvisionalPeakTroughValue(idx); if (provisionalIndex >= 0 && !Double.IsNaN(provisionalValue)) { DrawDot( provisionalIndex, provisionalValue, WLColor.Blue, 3); } } } }
Returns a TrendLine calculated from the specified number of confirmed peaks as of idx. The method returns null if there are not enough peaks available. Set useLog to true to calculate the TrendLine using logarithmic values.
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class PeakTroughTrendLineExample : UserStrategyBase { public override void Initialize(BarHistory bars) { PeakTroughCalculator ptc = new PeakTroughCalculator( bars, 5.0, PeakTroughReversalType.Percent); TrendLine lower = ptc.GetLowerTrendLine(bars.Count - 1, 4); if (lower != null) { DrawLine( lower.Index1, lower.Value1, lower.Index2, lower.Value2, WLColor.Red, 2, LineStyle.Dashed); } TrendLine upper = ptc.GetUpperTrendLine(bars.Count - 1, 4); if (upper != null) { DrawLine( upper.Index1, upper.Value1, upper.Index2, upper.Value2, WLColor.Green, 2, LineStyle.Dashed); } } public override void Execute(BarHistory bars, int idx) { } } }
Calculates and returns the preferred active trendline envelope formed from peaks or troughs as of idx. Specify PeakTroughType.Peak for an upper trendline based on peaks, or PeakTroughType.Trough for a lower trendline based on troughs. points determines how many PeakTroughs are used to form the line. useDescendingPeakTroughs determines whether descending or ascending PeakTroughs are considered. allowableIncursionPct specifies how far another PeakTrough can penetrate the candidate trendline before that line is rejected. Set useLog to true to calculate logarithmic trendlines. maxLookbackDays limits the age of PeakTroughs considered. For a two-point trendline, the method selects the candidate based on slope. For a multi-point trendline, it returns the candidate with the lowest TrendLine.Deviation. Returns null if an appropriate trendline cannot be calculated.
using System; using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class DescendingTrendlineBreak : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { StartIndex = 20; _ptc = new PeakTroughCalculator( bars, 10.0, PeakTroughReversalType.Percent); } public override void Execute(BarHistory bars, int idx) { TrendLine tl = _ptc.TrendlineEnvelope( bars, idx, PeakTroughType.Peak, 4, true, 3.0, false, 1500); if (tl == null) return; double value = tl.ExtendTo(idx, false); if (idx == bars.Count - 1) { DrawLine( tl.Index1, tl.Value1, idx, value, WLColor.Green, 2); } if (!HasOpenPosition(bars, PositionType.Long) && tl.Deviation <= 2.0 && bars.Close[idx] > value && bars.Close[idx - 1] <= tl.ExtendTo(idx - 1, false)) { PlaceTrade( bars, TransactionType.Buy, OrderType.Market); } } } }
Returns the List<TrendLine> of active trendline-envelope candidates that satisfy the supplied criteria. The parameters have the same meanings as those of TrendlineEnvelope. For two-point lines, the returned List is ordered by slope. Peak trendlines are ordered from the most negative to the most positive slope, while trough trendlines are ordered from the most positive to the most negative slope. For multi-point lines, the method returns all qualifying TrendLines. Use each TrendLine's Deviation property to compare how closely its constituent PeakTroughs conform to the line. The method can return null when insufficient qualifying PeakTroughs are available, or an empty List when no active trendlines satisfy the criteria.
using System.Collections.Generic; using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript { public class TrendlineEnvelopesExample : UserStrategyBase { private PeakTroughCalculator _ptc; public override void Initialize(BarHistory bars) { StartIndex = 20; _ptc = new PeakTroughCalculator( bars, 10.0, PeakTroughReversalType.Percent); } public override void Execute(BarHistory bars, int idx) { if (idx != bars.Count - 1) return; List<TrendLine> lines = _ptc.TrendlineEnvelopes( bars, idx, PeakTroughType.Peak, 2, true); if (lines == null) return; foreach (TrendLine line in lines) { DrawLine( line.Index1, line.Value1, idx, line.ExtendTo(idx), WLColor.Red, 1); } } } }