- ago
Below are two indicators for the WL8 community that could be useful in the current market situation.

One is a % Off ATH Indikator and the other is the RSI Williams Vix Fix from Jan. 2014 TASC Magazine. Feel free to use them or offer suggestions to improve.



CODE:
using WealthLab.Core; using WealthLab.Indicators; namespace Ascnet.WealthLab.Indicators { public class PercentOffATH : IndicatorBase { public PercentOffATH() : base() { } public PercentOffATH(BarHistory source) : base() { Parameters[0].Value = source; Populate(); } public static PercentOffATH Series(BarHistory source) { return new PercentOffATH(source); } protected override void GenerateParameters() { AddParameter("Source", ParameterType.BarHistory, PriceComponent.Close); } public override string Name { get { return "Percent Off All-time High"; } } public override string Abbreviation { get { return "PoATH"; } } public override string HelpDescription { get { return "Percent Off All-time High tracks the percentage difference between the previous day’s closing price and the All-Time high price of the entire price history. This metric tells you how far the price has deviated from/converged on the all-time high price."; } } public override string PaneTag { get { return "Percent Off All-time High"; } } public override PlotStyle DefaultPlotStyle { get { return PlotStyle.Line; } } public override WLColor DefaultColor { get { return WLColor.CornflowerBlue; } } public override void Populate() { BarHistory bars = Parameters[0].AsBarHistory; DateTimes = bars.DateTimes; if (bars.Count == 0 || bars.Count < 10) return; double highestClose = Double.MinValue; TimeSeries offAllTimeHigh = new TimeSeries(bars.DateTimes); for (int bar = 1; bar < bars.Count; bar++) { if (bars.Close[bar] > highestClose) highestClose = bars.Close[bar]; offAllTimeHigh[bar] = -Math.Abs((highestClose - bars.Close[bar]) * 100.0 / highestClose); } Values = offAllTimeHigh.Values; } } }


CODE:
using WealthLab.Core; using WealthLab.Indicators; namespace Ascnet.WealthLab.Indicators { public class RsiWilliamsVixFix : IndicatorBase { public RsiWilliamsVixFix() : base() { } public RsiWilliamsVixFix(BarHistory source, int emaPeriod, int rsiPeriod) : base() { Parameters[0].Value = source; Parameters[1].Value = emaPeriod; Parameters[2].Value = rsiPeriod; Populate(); } public static RsiWilliamsVixFix Series(BarHistory source, int emaPeriod, int rsiPeriod) { return new RsiWilliamsVixFix(source, emaPeriod, rsiPeriod); } protected override void GenerateParameters() { AddParameter("Source", ParameterType.BarHistory, PriceComponent.Close); AddParameter("EmaPeriod", ParameterType.Int32, 3); AddParameter("RsiPeriod", ParameterType.Int32, 14); } public override string Name { get { return "RSI Williams Vix Fix"; } } public override string Abbreviation { get { return "RWVF"; } } public override string HelpDescription { get { return "The VixRSI was presented in the January 2014 issue of the TASC magazine. Many years ago, Larry Williams developed something he calls the VIX fix.What he developed was a simple calculation that closely emulates the performance of the original VIX using only price data, and which can therefore be applied to any tradable. In a nutshell, we take the highest close over the last 22 trading days, subtract today’s low price, and then divide the result by the highest close over the last 22 trading days. Combining the VixFix with the RSI makes it even more powerful to detect Instrument bottoms and oversold areas. Detecting overbought VIX \"greed areas\" can also be useful if you try to catch a fast and profitable long trade on the VIX itself."; } } public override string PaneTag { get { return "RWVF"; } } public override PlotStyle DefaultPlotStyle { get { return PlotStyle.Histogram; } } public override WLColor DefaultColor { get { return WLColor.Green; } } public override void Populate() { BarHistory bars = Parameters[0].AsBarHistory; Int32 emaPeriod = Parameters[1].AsInt; Int32 rsiPeriod = Parameters[2].AsInt; DateTimes = bars.DateTimes; if (bars.Count == 0 || bars.Count < rsiPeriod) return; TimeSeries wvf = ((((Highest.Series(bars.Close, 22) >> 1) - bars.Low) / (Highest.Series(bars.Close, 22) >> 1) * 100) + 50); var ema = EMA.Series(wvf, emaPeriod); var rsi = RSI.Series(EMA.Series(bars.Close, emaPeriod), rsiPeriod); var result = ema / rsi; Values = result.Values; } } }

2
1,304
16 Replies

Reply

Bookmark

Sort
Glitch8
 ( 11.27% )
- ago
#1
Very nice! I added these to our WL8 "Community" repository which is here:

https://github.com/LucidDion/WL8ExtensionDemos

1
- ago
#2
Glitch,
Wondering why I can't see the Github WL8 Community Indicators in WL8? Are they not automatically included or is there still an open feature request?
0
Glitch8
 ( 11.27% )
- ago
#3
We decided to keep it separate for now, we may revisit if we start getting more contributions from the community. Or if there's a feature request for this that gets some support.
1
- ago
#4
For %of ATH (All Time High) indicator, the line
CODE:
offAllTimeHigh[bar] = -Math.Abs((highestClose - bars.Close[bar]) * 100.0 / highestClose);
could be simplified to
CODE:
offAllTimeHigh[bar] = (bars.Close[bar] - highestClose) * 100.0 / highestClose;
It would be nice to include a period parameter so the All Time High could span a certain period.

The TimeSeries datatype has a PercentRank(int period) method that does a somewhat similar thing, and it does include a period parameter. The down side is that it would be slower executing than this %of ATH indicator. The PercentRank method is more robust, but it has to execute a running (moving) sort, which is slower.

Thanks for sharing. It's interesting to see other indicator implementations.
1
- ago
#5
@Springroll Thanks for sharing the indicator.

I have no experience with coding but I thought it would be nice to have an indicator,such as yours , to calculate the distance from 2 user defined indicators. ie, price to vwap. Call it HowFar
So I copied your indicator, dumped it into chatgdp and asked it this

"I would like this code to have variables instead of all-time high and current bar close, so that I can put in any 2 variables and have an outcome"

This was the reply
CODE:
using WealthLab.Core; using WealthLab.Indicators; namespace WealthLab.Community { public class PercentOff : IndicatorBase { public PercentOff() : base() { } public PercentOff(double[] source1, double[] source2) : base() { Parameters[0].Value = source1; Parameters[1].Value = source2; Populate(); } public static PercentOff Series(double[] source1, double[] source2) { return new PercentOff(source1, source2); } protected override void GenerateParameters() { AddParameter("Source1", ParameterType.DoubleArray, Double.MinValue); AddParameter("Source2", ParameterType.DoubleArray, Double.MinValue); } public override string Name { get { return "Percent Off"; } } public override string Abbreviation { get { return "Po"; } } public override string HelpDescription { get { return "Percent Off tracks the percentage difference between two input sources."; } } public override string PaneTag { get { return "Percent Off"; } } public override PlotStyle DefaultPlotStyle { get { return PlotStyle.Line; } } public override WLColor DefaultColor { get { return WLColor.CornflowerBlue; } } public override void Populate() { double[] source1 = Parameters[0].AsDoubleArray; double[] source2 = Parameters[1].AsDoubleArray; if (source1.Length != source2.Length) return; DateTimes = new DateTime[source1.Length]; TimeSeries percentOff = new TimeSeries(DateTimes); for (int i = 0; i < source1.Length; i++) { DateTimes[i] = DateTime.Now; percentOff[i] = -Math.Abs((source1[i] - source2[i]) * 100.0 / source1[i]); } Values = percentOff.Values; } } }

I tried to compile it in WL8 and received lots of errors.
Is the code it produced utterly wrong, or was it on the right track?
0
- ago
#6
@Darcy

I'm using Codex (from OpenAI - must be the same) and figured out that Codex is mostly aware of WL6 and older. Therefore, I use it only to document WL8 code.

End of 2021 during market topping phase, I've develop an IRS Indicator, which measures the ROC spread between two symbols, preferably an Index vs. a stock. And of course, there are several ways to calculate the spread but in my case, this way was pretty suitable.

Could be a good base for you to dive deeper.
CODE:
using WealthLab.Core; using WealthLab.Indicators; namespace Ascnet.WealthLab.Indicators { public class SmoothedROCIndexSpread : IndicatorBase { public SmoothedROCIndexSpread() : base() { } public SmoothedROCIndexSpread(BarHistory source, string indexSymbol, int momentumPeriod, int smoothingPeriod, BarHistory indexBars) : base() { Parameters[0].Value = source; Parameters[1].Value = indexSymbol; Parameters[2].Value = momentumPeriod; Parameters[3].Value = smoothingPeriod; Parameters[4].Value = indexBars; Populate(); } public static SmoothedROCIndexSpread Series(BarHistory source, string indexSymbol, int momentumPeriod, int smoothingPeriod, BarHistory indexBars) { string key = CacheKey("SmoothedROCIndexSpread", indexSymbol, momentumPeriod, smoothingPeriod, indexBars); if (source.Cache.ContainsKey(key)) return (SmoothedROCIndexSpread)source.Cache[key]; SmoothedROCIndexSpread irs = new SmoothedROCIndexSpread(source, indexSymbol, momentumPeriod, smoothingPeriod, indexBars); source.Cache[key] = irs; return irs; } protected override void GenerateParameters() { AddParameter("Source", ParameterType.BarHistory, PriceComponent.Close); AddParameter("Index Symbol", ParameterType.String, "^NDX"); AddParameter("ROC Period", ParameterType.Int32, 14); AddParameter("Smoothing Period", ParameterType.Int32, 21); AddParameter("Index Bars", ParameterType.BarHistory, null); } public override string Name { get { return "Symbol vs Index ROC Spread"; } } public override string Abbreviation { get { return "IRS"; } } public override string HelpDescription { get { return "Calculates the spread of two smoothed ROCs, between a stock and a broad market index."; } } public override string PaneTag { get { return "IRS"; } } public override PlotStyle DefaultPlotStyle { get { return PlotStyle.Line; } } public override WLColor DefaultColor { get { return WLColor.Green; } } /* This method is used to calculate the spread between two different symbols. The parameters of the method are a BarHistory object, a string representing an index symbol, an integer representing the ROC period, an integer representing the smoothing period, and another BarHistory object. The code creates two ROC objects using SMA's of the close prices of each symbol and then subtracts them to get the spread. Finally, it assigns this spread to the Values property. */ public override void Populate() { BarHistory bars = Parameters[0].AsBarHistory; string indexSymbol = Parameters[1].AsString; int momentumPeriod = Parameters[2].AsInt; int smoothingPeriod = Parameters[3].AsInt; BarHistory indexBars = Parameters[4].AsBarHistory; DateTimes = bars.DateTimes; if (bars.Count == 0 || bars.Count < momentumPeriod) return; ROC symbolRoc; ROC indexRoc; TimeSeries spread; SymbolData indexSymbolData = new SymbolData(indexBars, indexSymbol, PriceComponent.Close); indexRoc = new ROC(new SMA(indexSymbolData, smoothingPeriod), momentumPeriod); symbolRoc = new ROC(new SMA(bars.Close, smoothingPeriod), momentumPeriod); spread = symbolRoc - indexRoc; Values = spread.Values; } } }

0
- ago
#7
Great.Thank you.
0
- ago
#8
Please point me to instructions on how to get the "Community" indicators into WL8.
I've gone to the repository and the instructions to make them available are over my head..
Thanks
0
- ago
#9
QUOTE:
I've gone to the repository and the instructions to make them available are over my head..

Go for it:

You can download the DLL for this library and save it into your WL8 installation folder from this link:

1. Download the file. Here's the page where you shall find the file link:
https://github.com/LucidDion/WL8ExtensionDemos
2. Copy it using Explorer. Typically it's under Program Files\Quantacula, LLC\WealthLab 8.

It's certainly not over anyone's head!
0
- ago
#10
Ok,
DLL (unblock checked) is copied into WL installation.
Now what?
0
Glitch8
 ( 11.27% )
- ago
#11
I updated the page to provide follow up info.

The next time you launch WL8 you should have access to the Community indicators in this folder:

0
- ago
#12
Sorry, No joy. I must be doing something wrong...
The DLL installs ok into the installation folder as far as I can tell.
0
- ago
#13
This is the installation file that I'm copying the DLL into...
0
- ago
#14
But what does the WL6 installer have to do with this? Again, the assumed path is C:\Program Files\Quantacula, LLC\WealthLab 8.
0
- ago
#15
"You can download the DLL for this library and save it into your WL8 installation folder from this link:"
0
- ago
#16
Ok. Thanks all. Got it.
0

Reply

Bookmark

Sort