- ago
Is there an eqivalent to PlotSeriesFillBand from WL6 in WL7 available, so that a hysteresis band can be used?
0
1,262
Solved
27 Replies

Reply

Bookmark

Sort
- ago
#1
To find an answer to this question (whatever it may be) and any other "WL7 equivalent" questions, please find this topic: "Quick WL6.9 to WL7 Translation Guide" in "Sticky Posts" section.
0
- ago
#2
Well, if I could find a reference in the transaltion guide PDF, then I would not have asked this question.

So I try again: Is there an eqivalent to PlotSeriesFillBand from WL6 in WL7, so that a hysteresis band can be used?
0
- ago
#3
What do you mean it couldn't be found? To stress, "whatever the result may be" 🤷:

0
- ago
#4
It may be have been documented in the PDF but none of it is available in my WL7 Build 9 code editor ;-)

0
- ago
#5
The highlighted fragment ("---" circled in red) means there is no equivalent in WL7.

Did I say "whatever the result may be"? ;)
0
- ago
#6
Hey Springroll,
I created this as a replacement for PlotSeriesFillBand. Use Color.Transparent if you just want to fill one side (above/below).
Enjoy!

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript26 {    public class FillGapBtwnSeriesWithColor    {       public class ChartPoint : IChartPoint       {          public int XIndex { get; set; }          public double YValue { get; set; }          public ChartPoint(int x, Double y)          {             XIndex = x; YValue = y;          }       }       UserStrategyBase obj;       private int bar;       private double Value, Value1, PrevValue, Level, Level1, PrevLevel;       public void FillGapBtwnSeries(UserStrategyBase obj, TimeSeries ts1, TimeSeries ts2, Color fillClrAbv, Color fillClrBlw, string pane)       {          PrevValue = ts1[0];          PrevLevel = ts2[0];          for (bar = ts1.FirstValidIndex + 1; bar < ts1.Count; bar++)          {             Value = ts1[bar];             Value1 = ts1[bar -1];             Level = ts2[bar];             Level1 = ts2[bar -1];             if (Value >= Level && PrevValue >= PrevLevel)             {                List<IChartPoint> points = new List<IChartPoint>()                {                 new ChartPoint(bar-1, Math.Min(PrevValue, PrevLevel)),                 new ChartPoint(bar-1, Value1),                 new ChartPoint(bar, Value),                 new ChartPoint(bar, Math.Min(PrevValue, Level))                };                obj.FillPolygon(points, fillClrAbv, pane);             }             if (Value <= Level && PrevValue <= PrevLevel)             {                List<IChartPoint> points = new List<IChartPoint>()                {                 new ChartPoint(bar-1, Math.Max(PrevValue, PrevLevel)),                 new ChartPoint(bar-1, Value1),                 new ChartPoint(bar, Value),                 new ChartPoint(bar, Math.Max(PrevValue, Level))                };                obj.FillPolygon(points, fillClrBlw, pane);             }             PrevValue = Value;             PrevLevel = Level;          }       }    }    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) {          FillGapBtwnSeriesWithColor fgbs = new FillGapBtwnSeriesWithColor();          TimeSeries cls = bars.Close;          // Color the gap between 2 Moving Averages          TimeSeries ma1 = new EMA(cls, 10);          TimeSeries ma2 = new EMA(cls, 20);          PlotTimeSeriesLine(ma1, ma1.Description, "Price", Color.Blue, 1, LineStyles.Solid);          PlotTimeSeriesLine(ma2, ma2.Description, "Price", Color.Red, 1, LineStyles.Solid);          fgbs.FillGapBtwnSeries(this, ma1, ma2, Color.PowderBlue, Color.LightPink, "Price");       } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { } //declare private variables below } }




Limitation: There is no 'Plot Behind Bars' option available (yet) so the colors overlap the bars; be sure to vote for it in the Wish List and bump it up!
0
Best Answer
Glitch8
 ( 11.81% )
- ago
#7
There is a “Cloud” Series Style contained in the Ichimoku Cloud extension that works like this.
0
- ago
#8
Solved it on this way to create a 5% hysteresis band.

CODE:
SMA sma = SMA.Series(bars.Close, 20); SMA smaUpper = SMA.Series((bars.Close * 1.05), 20); SMA smaLower = SMA.Series((bars.Close * 0.95), 20);
0
- ago
#9
Or you can simply use the built-in indicators EnvelopeUpper and EnvelopeLower. They also let you have a choice of the moving average type.
0
- ago
#10
I have seen these envelop indicators, but they are limited to only four MA's.

I use a high-pass filter MA (to reduce the lag). High-pass filtering is my preferred method to measure movements in leveraged ETFs.
0
- ago
#11
@Sammy_G

QUOTE:
Limitation: There is no 'Plot Behind Bars' option available (yet) so the colors overlap the bars; be sure to vote for it in the Wish List and bump it up!

No need in voting. You can already accomplish said effect by using FromArgb:

CODE:
PlotTimeSeriesLine(ma1, ma1.Description, "Price", Color.FromArgb(30, Color.Blue), 1, LineStyles.Solid); PlotTimeSeriesLine(ma2, ma2.Description, "Price", Color.FromArgb(30, Color.Red), 1, LineStyles.Solid); fgbs.FillGapBtwnSeries(this, ma1, ma2, Color.FromArgb(150, Color.PowderBlue), Color.FromArgb(150, Color.LightPink), "Price");


0
- ago
#12
@Springroll

QUOTE:
I have seen these envelop indicators, but they are limited to only four MA's.

We could look into extending the Envelope* to cover other moving average types. What filters do you have in mind?
0
- ago
#13
@Eugene

QUOTE:

What filters do you have in mind?


Without favoring any particular one, just take any moving averages that are based on Ehlers highpass filter (I don't know how many of them are in WL7).
0
- ago
#14
@Sammy_G
QUOTE:

I created this as a replacement for PlotSeriesFillBand. Use Color.Transparent if you just want to fill one side (above/below).


Nice extension. Helps to better visualize the content!
1
- ago
#15
@Eugene:
QUOTE:
You can already accomplish said effect by using FromArgb


Reducing a color's alpha/intensity so that one can visualize the bars only works within a narrow range. If it's too high the bars get hidden. If its too low you can't read the indicators names/values. So bool PlotBehindBars is still a good concept, IMHO.
0
- ago
#16
QUOTE:
... bool PlotBehindBars is still a good concept,...
I think where filling is involved, I would always do the filling behind the bars. Therefore, no special Boolean condition needs to be involved.
0
- ago
#17
@Springroll

QUOTE:
Without favoring any particular one, just take any moving averages that are based on Ehlers highpass filter (I don't know how many of them are in WL7).

At least 6 indicators from TASC library match your criteria (Ehlers high pass filter). But they sound too arcane for the average Joe to be listed near SMA, EMA, WMA, and SMMA in the Envelope* dropdown. Sorry.
0
mrsic8
 ( 10.26% )
- ago
#18
Hello,
after one year I can't still not found PlotSeriesFillBand Method in WL8?
The alternatives are too complicated here.

Could someone please make a code snippet for FillBand without 50 line of code. It should look like in the image. Or even better in Build 13. Thanks.



0
- ago
#19
I updated the Reply# 6 solution for WL8 and recoded it as an extension method (static) in a WL Utility class, WLUtil. You can include this utility class in Community.Components if you like. It's slightly easier to call as an extension method; see the MyStrategy example.
CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Collections.Generic; namespace WealthScript2 {    public static class WLUtil //WL Utility static class    {       protected struct ChartPoint : IChartPoint       {          public int XIndex { get; set; }          public double YValue { get; set; }          public ChartPoint(int x, double y)          {             XIndex = x;             YValue = y;          }       }       public static void FillGapBtwnSeries(UserStrategyBase usb, TimeSeries ts1, TimeSeries ts2, WLColor fillClrAbv, WLColor fillClrBlw, string pane = "Price", byte opacity = 150)       {          double Value, Value1, Level, Level1;          double PrevValue = ts1[0];          double PrevLevel = ts2[0];          for (int bar = ts1.FirstValidIndex+1; bar < ts1.Count; bar++)          {             Value = ts1[bar];             Value1 = ts1[bar-1];             Level = ts2[bar];             Level1 = ts2[bar-1];             if (Value >= Level && PrevValue >= PrevLevel)             {                List<IChartPoint> points = new List<IChartPoint>()                {                   new ChartPoint(bar-1, Math.Min(PrevValue, PrevLevel)),                   new ChartPoint(bar-1, Value1),                   new ChartPoint(bar, Value),                   new ChartPoint(bar, Math.Min(PrevValue, Level))                };                usb.FillPolygon(points, WLColor.FromArgb(opacity,fillClrAbv), pane, true);             }             if (Value <= Level && PrevValue <= PrevLevel)             {                List<IChartPoint> points = new List<IChartPoint>()                {                   new ChartPoint(bar-1, Math.Max(PrevValue, PrevLevel)),                   new ChartPoint(bar-1, Value1),                   new ChartPoint(bar, Value),                   new ChartPoint(bar, Math.Max(PrevValue, Level))                };                usb.FillPolygon(points, WLColor.FromArgb(opacity,fillClrBlw), pane, true);             }             PrevValue = Value;             PrevLevel = Level;          }       }    } //end of WLUtil class    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)       {          // Color the gap between two moving averages          EMA ma1 = new EMA(bars.Close, 10);          EMA ma2 = new EMA(bars.Close, 20);          PlotIndicatorLine(ma1,WLColor.Blue,1);          PlotIndicatorLine(ma2,WLColor.Red,1);          WLUtil.FillGapBtwnSeries(this, ma1, ma2, WLColor.PowderBlue, WLColor.LightPink);       }       //execute the strategy rules here, this is executed once for each bar in the backtest history       public override void Execute(BarHistory bars, int idx) { } } }
0
Glitch8
 ( 11.81% )
- ago
#20
There's a trick to plotting in a Bands style - you need to assign the Bars instance to the indicators, like this. Unfortunately, in the framework there's no way for that Bars instance to get assigned automatically ...

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Collections.Generic; 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) {          bbl = BBLower.Series(bars.Close, 20, 2);          bbu = BBUpper.Series(bars.Close, 20, 2);          bbl.Bars = bars;          bbu.Bars = bars;          PlotIndicator(bbl, WLColor.Pink, PlotStyle.Bands);          PlotIndicator(bbu, WLColor.Pink); } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { }       //declare private variables below       private BBLower bbl;       private BBUpper bbu; } }
0
- ago
#21
QUOTE:
There's a trick to plotting ... Bands ... - you need to assign the Bars instance to the indicators,...

Slow down. You're typing too fast. Are we talking about the assignment lines in yellow below? Is this documented anywhere?

Does said indicator have to be defined as a "band-type" indicator (with companion indicator bands defined in its indicator coding), or will this technique work with any indicator (such as the EMA indicator in the example above, Reply# 19)?

QUOTE:
Unfortunately,... there's no way for that Bars instance to get assigned automatically ...
It would be nice if this assignment wasn't so cryptic. I'm not even sure what's happening.
0
Glitch8
 ( 11.81% )
- ago
#22
Yes, and no it isn’t documented. It will only work with a band-style indicator.
0
- ago
#23
QUOTE:
It will only work with a band-style indicator.

So if I changed the above Reply# 20 code from ...
CODE:
private BBLower bbl; private BBUpper bbu;
to this below ...
CODE:
private IndicatorBase bbl; private IndicatorBase bbu;
band plotting would fail because IndicatorBase is not defined to have companion bands by itself? (And most readers won't follow our discussion unless they have coded an indicator with companion bands to know what we are talking about....)

I think "information hiding" should work for the user. In this weird design, it seem to add unexpected behavior instead. I guess I'm okay with this if the compiler throws an error if there's a datatype misalignment here that would lead to run-time failure.
0
Cone8
 ( 25.44% )
- ago
#24
We can beef up the PlotStyle.Bands explanation and make this the Code example for the QuickRef > PlotStyle
0
mrsic8
 ( 10.26% )
- ago
#25
Thanks superticker. I will try out.

@Cone, is a good idea.

0
- ago
#26
QUOTE:
beef up the PlotStyle.Bands explanation

That's a start.

You could add a IndicatorBandBase datatype that inherits from IndicatorBase. But the question remains, "How to use information hiding to 'hide' the assignments discussed in Replies# 20 and 21?" And how do you best do it without the user knowing about it?

We should spend a few days thinking about this problem. The fundamental problem is that WL8 wants to make each indicator autonomous (inheriting from IndicatorBase) when we need a "combination indicator" type (i.e. IndicatorBandBase) that's not autonomous. And we want to hide this new combo-indicator type from the user.
0
Glitch8
 ( 11.81% )
- ago
#27
We don’t need a new class, everything is working fine as is.
0

Reply

Bookmark

Sort