- ago
CODE:
          day_change = new ROC(bars_single.Close, 1); PlotTimeSeries(2 * day_change, "Day Change", "Day Change", Color.Green, PlotStyles.Line);


I thought this would simply multiply the value by 2 then plot it. It does multiply it by 2 but then there is a double label on every bar.

0
383
14 Replies

Reply

Bookmark

Sort
- ago
#1
It plots correctly for me, nothing gets duplicated. There must be something else in the code to what you're doing to cause this to you.

P.S. Not everyone would agree with me but "Double label on every bar when plotting multiplied TimeSeries" sounds more descriptive than "Possible Plot bug" as the topic title, so I edited it.
0
- ago
#2
I apologize. I should've included a pic not realizing it may not reproduce. Here's the pic:
0
- ago
#3
I run the code above and the plot doesn't get duplicated for me.
0
Glitch8
 ( 8.38% )
- ago
#4
If possible, post the full code or email it to support@wealth-lab.com. If we can reproduce it we can fix it!
0
Cone8
 ( 26.65% )
- ago
#6
Here's what you did -

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { public class MyStrategy123 : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) {           } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) {          TimeSeries day_change = new ROC(bars.Close, 1);          PlotTimeSeries(2 * day_change, "Day Change", "Day Change", Color.Green, PlotStyles.Line); } } }


Here's the right way to do it -

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript1 { public class MyStrategy123 : UserStrategyBase { //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) {          day_change = new ROC(bars.Close, 1);          PlotTimeSeries(2 * day_change, "Day Change", "Day Change", Color.Green, PlotStyles.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) { }       //declare private variables below       TimeSeries day_change; } }


I was certain we had put some code in to prevent re-plotting a plotted series. I'm not sure where that went!
1
- ago
#7
QUOTE:
put some code in to prevent re-plotting a plotted series.
Perhaps it would be even better to throw a soft error (i.e. warning) informing the user plotting shouldn't be placed in the Execute{} block in the first place.
1
Glitch8
 ( 8.38% )
- ago
#8
The series is created each pass in Execute via an arithmetic expression, so that's why it's not able to use our defensive code to avoid multiple plots.
0
- ago
#9
Actually the declaration is in the Initialize. I am not comfortable sharing my whole code. I'm sorry for the confusion this caused. You are correct that the Plot is in the Execute.

So putting the plot makes sense however this is happening with any series including the ones I need to build with each bar - e.g. an equity curve. So I could've used a different example. Look at this:

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript7 { public class MyStrategy : UserStrategyBase {       //declare private variables below       int benchmark_shares;       TimeSeries benchmark_equity; //create indicators and other objects here, this is executed prior to the main trading loop public override void Initialize(BarHistory bars) {          benchmark_equity = new TimeSeries(bars.DateTimes, 0);          StartIndex = 0;          //This line overwrites the loop in Execute so if you comment it out the line is labelled B & H.          PlotTimeSeries(benchmark_equity, "Init", "Init", Color.LightGreen, PlotStyles.Line);          //This line does not overwrite the 2 * B&H and plots as all 0          PlotTimeSeries(2 * benchmark_equity, "2 * Init", "2 Init", Color.LightGreen, PlotStyles.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) {          Transaction t_initial;          if (idx == StartIndex)          {             t_initial = PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, "Single");             benchmark_shares = (int)t_initial.Quantity;             benchmark_equity[idx] = CurrentEquity;             WriteToDebugLog("Benchmark shares: " + benchmark_shares);          }          else             benchmark_equity[idx] = CurrentCash + benchmark_shares * bars.Close[idx];          PlotTimeSeries(benchmark_equity, "B&H", "Equity", Color.LightGreen, PlotStyles.Line);          PlotTimeSeries(2 * benchmark_equity, "2 * B&H", "2 Equity", Color.LightGreen, PlotStyles.Line);       } } }


So when you have to build the Timeseries while executing, your safety net works if the series is not multiplied.

So is there a way to plot it without a 1000 labels or is it a bug?
0
Glitch8
 ( 8.38% )
- ago
#10
You can plot an after-the-fact computed TimeSeries in the Cleanup method. And, yes it's a bug in your code. Every time you multiply a TimeSeries by 2 it creates a new TimeSeries instance, which you are plotting again and again in Execute.

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript7 {    public class MyStrategy : UserStrategyBase    {       //declare private variables below       int benchmark_shares;       TimeSeries benchmark_equity;       //create indicators and other objects here, this is executed prior to the main trading loop       public override void Initialize(BarHistory bars)       {          benchmark_equity = new TimeSeries(bars.DateTimes, 0);          StartIndex = 0;       }       //execute the strategy rules here, this is executed once for each bar in the backtest history       public override void Execute(BarHistory bars, int idx)       {          Transaction t_initial;          if (idx == StartIndex)          {             t_initial = PlaceTrade(bars, TransactionType.Buy, OrderType.Market, 0, "Single");             benchmark_shares = (int)t_initial.Quantity;             benchmark_equity[idx] = CurrentEquity;             WriteToDebugLog("Benchmark shares: " + benchmark_shares);          }          else             benchmark_equity[idx] = CurrentCash + benchmark_shares * bars.Close[idx];       } public override void Cleanup(BarHistory bars) {          PlotTimeSeries(benchmark_equity, "B&H", "Equity", Color.LightGreen, PlotStyles.Line); PlotTimeSeries(2 * benchmark_equity, "2 * B&H", "2 Equity", Color.LightGreen, PlotStyles.Line); } } }
1
- ago
#11
Thank you for showing that to me. I have no idea how in the world I would've figured that out lol.

But, I did google search and find this page:

https://www.wealth-lab.com/Support/ApiReference/UserStrategyBase

Which leads to the next questions:

1) Why didn't putting the plot in PostExecute have the same effect as in Cleanup?

2) Why not just put all the plotting in the Cleanup?

Thanks.

p.s. I suspect the questions may lead to a new thread recommendation but if I may, I'd like to give an opinion on that that you can feel free to delete or move to a new thread lol:

Your team is amazing at answering questions and you are making an incredible product but you also spend a lot of time "cleaning up" posts. The OCD behind it is what leads to a great program, but seriously, your time is WAY more valuable than post cleanup. Once the search for the text body is functional, I don't think it really needs to be cleaned up as much. The search will find what people are looking for even if the thread title is wrong, and the flow of the discussion can lead sometimes to a greater understanding than a bunch of isolated questions. So if you can leave the cleanup to the search engine then maybe we can get our categories back and people can post in the wrong one 50% of the time and it'll be ok :)
0
- ago
#12
QUOTE:
2) Why not just put all the plotting in the Cleanup?
I think it's most efficient to place as much computation and plotting in Initialize as possible.

Now if there are TimeSeries values that must be adjusted during trading, then plotted, then you'll need to plot those in some post processing routine (like Cleanup). But I would try to avoid doing that, if possible, and do all your computations in Initialize whenever possible.

The more times the processor's on-chip cache has to cycle through your TimeSeries data (like in a post processing routine), the slower your strategy code will execute.
0
Cone8
 ( 26.65% )
- ago
#13
1) Remember that in WL7 Execute occurs once per bar. PostExecute occurs once per bar too. Cleanup is just once - after all processing is complete for a symbol.

If still in doubt, see QuickRef and examples in UserStrategyBase > Strategy Execution
1
- ago
#14
Got it. Thank you guys.
0

Reply

Bookmark

Sort