Why does this code not work?
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; using WealthLab.AdvancedSmoothers; using WLUtility.Indicators; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { StartIndex = 100; TimeSeries smoothHigh = TEMA.Series(bars.High, 24); TimeSeries smoothLow = TEMA.Series(bars.Low, 24); TimeSeries vhf = VerticalHorizontalFilter.Series(smoothHigh, smoothLow, 10); PlotTimeSeries(vhf, "VHF", "VHF", WLColor.Blue, PlotStyle.Line); } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { if (!HasOpenPosition(bars, PositionType.Long)) { //code your buy conditions here } else { //code your sell conditions here } } //declare private variables below } }
Rename
Because you're using WLUtility.Indicators, I guess you were using the VHF indicator that I published in another thread. But, WealthLab build 139 includes the VHF indicator. You should probably just get rid of the one I published and use the VHF indicator from WealthLab build 139.
@Glitch - looks like the VHF indicator you published in Build 139 is in the WLUtility.Indicators namespace which is the namespace I used when publishing the VHF indicator (in another thread). You may have meant to put VHF in the WealthLab.Indicators namespace.
There is something more basic wrong with the instantiation of this indicator.
Results
The VHF should be between 0 and 1.0, correct?
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Data; using WealthLab.Indicators; using System.Collections.Generic; using WealthLab.AdvancedSmoothers; using WLUtility.Indicators; namespace WealthScript1 { public class MyStrategy : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) { StartIndex = 100; TimeSeries smoothHigh = EMA.Series(bars.High, 10); TimeSeries smoothLow = EMA.Series(bars.Low, 10); TimeSeries vhf = VerticalHorizontalFilter.Series(smoothHigh, smoothLow, 10); PlotTimeSeries(vhf, "VHF", "VHF", WLColor.Blue, PlotStyle.Line); } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { if (!HasOpenPosition(bars, PositionType.Long)) { //code your buy conditions here } else { //code your sell conditions here } } //declare private variables below } }
Results
The VHF should be between 0 and 1.0, correct?
The code
CODE:works as intended, between 0 and 1
new VerticalHorizontalFilter(bars.Close,bars.Close,10);
As ww5 indicated, if you use the closing price then the range is 0 to 1. However, the code I published here https://www.wealth-lab.com/Discussion/VHF-Indicator-Can-it-be-added-12722 uses the high series as the summing of the absolute changes over period n. Hence, that is why you are seeing values greater than 1. I wrote an updated version, VHF2, that still uses two time series, but it averages the two series for summing the absolute changes over the given period.
CODE:
using System; using WealthLab.Core; namespace WealthLab.Indicators; /// <summary> /// Vertical Horizontal Filter 2 (VHF2) measures trend strength by evaluating /// This implementation has TimeSeries inputs for each of the highest and lowest price calculations. /// The sum of absolute changes is based on the average of the two provided series. /// Hence, using closing prices for both high and low series replicates the classic VHF behavior. /// </summary> public sealed class VerticalHorizontalFilter2 : IndicatorBase { private const int DefaultPeriod = 14; public VerticalHorizontalFilter2() { // for WL8 - do not remove! } public VerticalHorizontalFilter2(BarHistory bars, int period = DefaultPeriod) : this(bars.Close, bars.Close, period) { } public VerticalHorizontalFilter2(TimeSeries highSeries, TimeSeries lowSeries, int period = DefaultPeriod) { Parameters[0].Value = highSeries; Parameters[1].Value = lowSeries; Parameters[2].Value = period; Populate(); } public override string Name => "Vertical Horizontal Filter 2"; public override string Abbreviation => "VHF2"; public override string HelpDescription => "Vertical Horizontal Filter 2 (VHF2) measures trend strength using custom high and low series. The summing of absolute changes is based on the average of the two series."; public override string PaneTag => "VHF2"; 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); // Use the average of the two series for the sum of absolute changes. // This fits with the classic VHF which uses the closing prices for the sum of absolute changes. var sumSeries = (highSeries + lowSeries) / 2.0; 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(sumSeries[i] - sumSeries[i - 1]); } for (var idx = period; idx < highSeries.Count; idx++) { sumChangeAbs += Math.Abs(sumSeries[idx] - sumSeries[idx - 1]); sumChangeAbs -= Math.Abs(sumSeries[idx - period + 1] - sumSeries[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, DefaultPeriod); } public static VerticalHorizontalFilter2 Series(TimeSeries highSeries, TimeSeries lowSeries, int period = DefaultPeriod) { var key = CacheKey("VerticalHorizontalFilter2", highSeries, lowSeries, period); if (highSeries.Cache.TryGetValue(key, out var obj)) { return (VerticalHorizontalFilter2) obj; } var indicator = new VerticalHorizontalFilter2(highSeries, lowSeries, period); highSeries.Cache[key] = indicator; return indicator; } // Convenience overload for BarHistory public static VerticalHorizontalFilter2 Series(BarHistory bars, int period = DefaultPeriod) => Series(bars.Close, bars.Close, period); }
Your Response
Post
Edit Post
Login is required