- ago
The VHF was included in WL6 basic indicators. Is it possible to get it added to WL8?
0
110
6 Replies

Reply

Bookmark

Sort
- ago
#1
You probably already have this, but if not, here's the equivalent popped into a TimeSeries. Of course, adjust the period and variable scope to your needs. Maybe I'll write the full-fledged indicator soon.

CODE:
const int vhfPeriod = 8; TimeSeries vhf = (Highest.Series(bars.Close, vhfPeriod) - Lowest.Series(bars.Close, vhfPeriod)) / (bars.Close - (bars.Close >> 1)).Abs().Sum(vhfPeriod);
0
- ago
#2
paul1986,

Thanks! Your code is MUCH cleaner than what I have been using.
0
- ago
#3
QUOTE:
Maybe I'll write the full-fledged indicator soon.

I had a couple WL6 indicators I had to redevelop for WL8. If the indicator is just for one strategy, what you can do instead is write a private static method (see the VHF function below) for that one indicator as shown below.
CODE:
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace WealthScript3 {    public class MyStrategy : UserStrategyBase    {       static TimeSeries VHF(TimeSeries source, int vhfPeriod = 8)       {          TimeSeries numerator = Highest.Series(source, vhfPeriod) - Lowest.Series(source, vhfPeriod);          TimeSeries denominator = Momentum.Series(source, 1).Abs().Sum(vhfPeriod);          return numerator / denominator;       }       public override void Initialize(BarHistory bars)       {          const int vhfPeriod = 8;          TimeSeries vhf = (Highest.Series(bars.Close, vhfPeriod) - Lowest.Series(bars.Close, vhfPeriod)) /             (bars.Close - (bars.Close >> 1)).Abs().Sum(vhfPeriod);          PlotTimeSeriesLine(vhf, "VHF", "VHF", WLColor.Orange, 6);          TimeSeries vhfMethod = VHF(bars.Close);          PlotTimeSeriesLine(vhfMethod, "VHF method", "VHF");       }       public override void Execute(BarHistory bars, int idx) { }    } }
If you run the above code, you'll see both approaches come up with the same TimeSeries. I'll have to confess, the approach in Post #1 might be slightly more efficient on garbage collection since more work can be done in stack storage than heap storage.
0
- ago
#4
superticker,

Thanks for your code approach. I appreciate the great help from this Board!
1
- ago
#5
Here's the VHF indicator. I made it a bit more flexible. You can use any TimeSeries for each of Highest and Lowest instead of just plain-old Close. It defaults to the Close for both Highest and Lowest. I only did some simple testing. This should be a tad bit speedier and less memory intensive than the TimeSeries of my prior post.

CODE:
using System; using WealthLab.Core; using WealthLab.Indicators; namespace WLUtility.Indicators { /// <summary> /// Vertical Horizontal Filter (VHF) measures the trend strength by comparing the net price movement /// over a period to the sum of absolute price changes. Allows custom TimeSeries for Highest and Lowest. /// </summary> public sealed class VerticalHorizontalFilter : IndicatorBase { public VerticalHorizontalFilter() { // for WL8 - do not remove! } public VerticalHorizontalFilter(BarHistory bars, int period = 14) : this(bars.Close, bars.Close, period) { } public VerticalHorizontalFilter(TimeSeries highSeries, TimeSeries lowSeries, int period = 14) { Parameters[0].Value = highSeries; Parameters[1].Value = lowSeries; Parameters[2].Value = period; Populate(); } public override string Name => "Vertical Horizontal Filter"; public override string Abbreviation => "VHF"; public override string HelpDescription => "Vertical Horizontal Filter"; public override string PaneTag => "VHF"; public override bool IsSmoother => false; public override bool IsCalculationLengthy => false; public override bool PeekAheadFlag => false; public override PlotStyle DefaultPlotStyle => PlotStyle.Line; public override WLColor DefaultColor => WLColor.Orange; public override void Populate() { var highSeries = Parameters[0].AsTimeSeries; var lowSeries = Parameters[1].AsTimeSeries; var period = Parameters[2].AsInt; DateTimes = highSeries.DateTimes; if (period <= 0 || highSeries.Count == 0 || lowSeries.Count == 0) { return; } var highest = new Highest(highSeries, period); var lowest = new Lowest(lowSeries, period); for (var i = 0; i < period; i++) { Values[i] = double.NaN; } var sumChangeAbs = 0.0; // Sum the first window for (var i = 1; i < period; i++) { sumChangeAbs += Math.Abs(highSeries[i] - highSeries[i - 1]); } for (var idx = period; idx < highSeries.Count; idx++) { sumChangeAbs += Math.Abs(highSeries[idx] - highSeries[idx - 1]); sumChangeAbs -= Math.Abs(highSeries[idx - period + 1] - highSeries[idx - period]); Values[idx] = sumChangeAbs == 0 ? 0 : (highest[idx] - lowest[idx]) / sumChangeAbs; } } protected override void GenerateParameters() { AddParameter("High Series", ParameterType.TimeSeries, PriceComponent.Close); AddParameter("Low Series", ParameterType.TimeSeries, PriceComponent.Close); AddParameter("Period", ParameterType.Int32, 14); } public static VerticalHorizontalFilter Series(TimeSeries highSeries, TimeSeries lowSeries, int period = 14) { var key = CacheKey("VerticalHorizontalFilter", highSeries, lowSeries, period); if (highSeries.Cache.TryGetValue(key, out var obj)) { return (VerticalHorizontalFilter) obj; } var indicator = new VerticalHorizontalFilter(highSeries, lowSeries, period); highSeries.Cache[key] = indicator; return indicator; } // Convenience overload for BarHistory public static VerticalHorizontalFilter Series(BarHistory bars, int period = 14) => Series(bars.Close, bars.Close, period); } }
0
Glitch8
 ( 9.81% )
- ago
#6
I will add this to the next Build so we have it as a native, core indicator once again.
0

Reply

Bookmark

Sort