- ago
Few months ago, I came across a somewhat special way of detecting divergences via Youtube (https://www.youtube.com/watch?v=hUhU6ysOB2Q). Consequently, I decided to test this indicator in Tradingview, just to verify its reliability. Interestingly, with some inverse ETFs and the VIX, this indicator shows a pretty useful output. Especially on the VIX, the top on October 23 was pointed out quite well, which turned out to be an excellent entry opportunity.

With the help of ChatGPT, I've converted the code (with some adjustments) to WL8, but being too lazy to make a real indicator out of it, due to some paintings in the price range. Therefore I simply publish the code as a strategy, but without trading signals. Maybe this will lead to any further ideas?


CODE:
using WealthLab.Backtest; using WealthLab.Core; using WealthLab.Indicators; namespace Youtube.DivergenceIndicator {    public class MyStrategy : UserStrategyBase    {       private int maxBarDistance = 50;       private int rsiPeriod = 9;       private double rsiOverbought = 70.0;       private double rsiOversold = 30.0;       private TimeSeries bullishDivergences;       private TimeSeries bearishDivergences;       private IndicatorBase rsiValue;       private IndicatorBase swingLowRSI;       private IndicatorBase swingHighRSI;       public override void Initialize(BarHistory bars)       {          var checkFirstLow = double.NaN;          var initialLowPrice = double.NaN;          var initialLowRSI = double.NaN;          var initialLowIndex = -1;          var checkFirstHigh = double.NaN;          var initialHighPrice = double.NaN;          var initialHighRSI = double.NaN;          var initialHighIndex = -1;          bullishDivergences = new TimeSeries(bars.DateTimes);          bearishDivergences = new TimeSeries(bars.DateTimes);          rsiValue = new RSI(bars.Close, rsiPeriod);          swingLowRSI = new Lowest(rsiValue, 5);          swingHighRSI = new Highest(rsiValue, 5);          for (int idx = 1; idx < bars.Count; idx++)          {             SaveLowestLowRSIOversold(bars, idx, ref checkFirstLow, ref initialLowPrice, ref initialLowRSI, ref initialLowIndex);             SaveHighestHighRSIOverbought(bars, idx, ref checkFirstHigh, ref initialHighPrice, ref initialHighRSI, ref initialHighIndex);             initialLowPrice = CheckForSecondLowWithinMaxDistanceAndLowerThanFirst(bars, idx, initialLowPrice, initialLowRSI, initialLowIndex);             initialHighPrice = CheckForSecondHighWithinMaxDistanceAndHigherThanFirst(bars, idx, initialHighPrice, initialHighRSI, initialHighIndex);          }          PlotTimeSeries(bullishDivergences, "Bullish Divergences", "Divergences", WLColor.Green, PlotStyle.Histogram);          PlotTimeSeries(bearishDivergences, "Bearish Divergences", "Divergences", WLColor.Red, PlotStyle.Histogram);       }       private void SaveLowestLowRSIOversold(          BarHistory bars, int idx, ref double checkFirstLow,          ref double initialLowPrice, ref double initialLowRSI, ref int initialLowIndex)       {          // Save lowest low while RSI is oversold, and store it when market leaves oversold condition          if (rsiValue[idx] < rsiOversold || rsiValue[idx - 1] < rsiOversold)          {             if (!double.IsNaN(initialLowPrice))                initialLowPrice = double.NaN;             if (double.IsNaN(checkFirstLow) || bars.Low[idx] < checkFirstLow)             {                checkFirstLow = bars.Low[idx];                initialLowIndex = idx;                initialLowRSI = swingLowRSI[idx];             }          }          else          {             // RSI is no longer OS, save lowest price during OS condition and reset temporary low             if (!double.IsNaN(checkFirstLow))                initialLowPrice = checkFirstLow;             checkFirstLow = double.NaN;          }       }       private void SaveHighestHighRSIOverbought(          BarHistory bars, int idx, ref double checkFirstHigh,          ref double initialHighPrice, ref double initialHighRSI, ref int initialHighIndex)       {          // Save highest high while RSI is overbought, and store it when market leaves OB condition          if (rsiValue[idx] > rsiOverbought || rsiValue[idx - 1] > rsiOverbought)          {             if (!double.IsNaN(initialHighPrice))                initialHighPrice = double.NaN;             if (double.IsNaN(checkFirstHigh) || bars.High[idx] > checkFirstHigh)             {                checkFirstHigh = bars.High[idx];                initialHighIndex = idx;                initialHighRSI = swingHighRSI[idx];             }          }          else          {             // RSI is no longer OB, save highest price during OB condition and reset temporary high             if (!double.IsNaN(checkFirstHigh))                initialHighPrice = checkFirstHigh;             checkFirstHigh = double.NaN;          }       }       private double CheckForSecondLowWithinMaxDistanceAndLowerThanFirst(          BarHistory bars, int idx, double initialLowPrice, double initialLowRSI, int initialLowIndex)       {          // Check for a second low that is lower than the first, and with a higher RSI value, and within our max distance          if (bars.Low[idx - 1] < initialLowPrice && bars.Low[idx] > bars.Low[idx - 1] && swingLowRSI[idx] > initialLowRSI && idx - initialLowIndex <= maxBarDistance)          {             bullishDivergences[idx] = 1;             DrawLine(initialLowIndex, initialLowPrice, idx - 1, bars.Low[idx - 1], WLColor.DarkGreen, 2);             SetTextDrawingOptions(WLColor.DarkGreen, WLColor.Black, 1);             DrawBarAnnotation("Bull", idx, false, WLColor.White, 9, true, null, false);             initialLowPrice = double.NaN;          }          else          {             bullishDivergences[idx] = 0;          }          return initialLowPrice;       }       private double CheckForSecondHighWithinMaxDistanceAndHigherThanFirst(          BarHistory bars, int idx, double initialHighPrice, double initialHighRSI, int initialHighIndex)       {          // Check for a second high that is higher than the first, and with a lower RSI value, and within our max distance          if (bars.High[idx - 1] > initialHighPrice && bars.High[idx] < bars.High[idx - 1] && swingHighRSI[idx] < initialHighRSI && idx - initialHighIndex <= maxBarDistance)          {             bearishDivergences[idx] = 1;             DrawLine(initialHighIndex, initialHighPrice, idx - 1, bars.High[idx - 1], WLColor.DarkRed, 2);             SetTextDrawingOptions(WLColor.DarkRed, WLColor.Black, 1);             DrawBarAnnotation("Bear", idx, true, WLColor.White, 9, true, null, false);             initialHighPrice = double.NaN;          }          else          {             bearishDivergences[idx] = 0;          }          return initialHighPrice;       }       public override void Execute(BarHistory bars, int idx)       {          if (!HasOpenPosition(bars, PositionType.Long))          {          }          else          {          }       }    } }
1
1,086
Solved
3 Replies

Closed

Bookmark

Sort
Cone8
 ( 4.98% )
- ago
#1
Here's an easier way -



0
Best Answer
- ago
#2
Thanks @Springroll for building this script.
I often use it in Trading view and thought it would be nice to have it in WL..



0
- ago
#3
Perhaps you have seen this Div indicator .
https://www.tradingview.com/v/680R1I3Z/
This one uses multiple indicators and weights them for strength. Very interesting concept.
I may put in the "wish list" someday, a request for the current WL divergence indicator to be made into a building block and also add that it have an optimizable source indicator option.
1

Closed

Bookmark

Sort