- ago
I have the following code:

CODE:
namespace WealthScript3 { 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) { } //execute the strategy rules here, this is executed once for each bar in the backtest history public override void Execute(BarHistory bars, int idx) { WriteToDebugLog(idx.ToString() + " " + bars.Symbol); } //declare private variables below } }


With Strategy Settings set to Portfolio Backtest, and the selected dataset has two symbols: AAPL and TSLA. The results I got from the Debug Log is shown below:

--TSLA--
0 TSLA
1 TSLA
2 TSLA
3 TSLA
4 TSLA
5 TSLA
6 TSLA
7 TSLA
--AAPL--
0 AAPL
1 AAPL
2 AAPL
3 AAPL
4 AAPL
5 AAPL
6 AAPL
7 AAPL

My thoughts; for WL7, it should execute all symbols in parallel bar-by-bar and I was expecting the simulation results should be like the following instead.

--TSLA--
--AAPL--
0 TSLA
0 AAPL
1 TSLA
1 AAPL
2 TSLA
2 AAPL
3 TSLA
3 AAPL
..
..
..
Am I not understand how WL7 work correctly or done something wrong here or does the Debug Log sorts the results by symbol?
0
1,064
Solved
16 Replies

Reply

Bookmark

Sort
- ago
#1
I think it's a debug log that groups on a by symbol bases.
2
Best Answer
- ago
#2
Thanks. That's a possible explanation. I hope it would not do that as that would destroy time dependency of output variables.

Edited: I think I understand it now, like you said it displays the results symbol by symbol in a list (sequential order) rather (for more intuitively) the results should be displayed in column basis where rows are in time.
0
Glitch8
 ( 9.56% )
- ago
#3
Replikant is right, the Debug Log organizes the output by symbol after the backtest..
0
- ago
#4
QUOTE:
organizes the output by symbol after the backtest.
Please don't do that, or, at least make it a user preference. What you have now is a report, not a log,
0
Glitch8
 ( 9.56% )
- ago
#5
"You can please some of the people some of the time ..."

The best way to affect change is to submit a #FeatureRequest.
1
- ago
#6
I would create my own function like WriteToDebugLogByTime(string text). It adds a value to a global array and then prints it somewhere in BacktestComplete().
0
Glitch8
 ( 9.56% )
- ago
#7
Good solution, but an option for the Debug Log to work either way is definately doable, if someone wanted to sumbit that request.
0
- ago
#8
For me, a raw Debug Log similar to that in WL6 would be more beneficial in debugging and understanding how the code work. I have been struggle in trying to understand on how some of the code in WL7 work and looking at the outputs in the debug log from WriteToDebugLog can be confusing.
0
- ago
#9
Vote for this feature request:
https://www.wealth-lab.com/Discussion/A-Chronological-Debug-Output-Preference-6902
1
Cone8
 ( 26.99% )
- ago
#10
Incidentally, the workaround is quite simple:

1. Declare a static list and instantiate it at the start of the backtest
2. Instead of using WriteToDebugLog, save the string to the list
3. WriteToDebugLog the contents of the list at Backtest complete.

CODE:
using WealthLab.Backtest; using System; using WealthLab.Core; using WealthLab.Indicators; using System.Drawing; using System.Collections.Generic; namespace WealthScript3 {    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)       {       }       //execute the strategy rules here, this is executed once for each bar in the backtest history       public override void Execute(BarHistory bars, int idx)       {          // WriteToDebugLog(idx.ToString() + " " + bars.Symbol);          // instead, add it to the log list          _log.Add(idx.ToString() + " " + bars.Symbol);       }        public override void BacktestBegin() {          _log = new List<string>(); } public override void BacktestComplete() {          foreach (string item in _log)             WriteToDebugLog(item); } //declare private variables below       //a static instance will be available for all symbols static List<string> _log;    } }
2
- ago
#11
And you could do exactly the same thing using StringBuilder instead:
CODE:
static StringBuilder _log = new StringBuilder(); //static List<string> _log;
And then have StringBuilder write the output into the Windows clipboard or WriteToDebugLog() in BacktestComplete. The StringBuilder solution would be a little more efficient since there wouldn't be so many independent strings involved that have to be garbage collected. One can simply include a '\n' in the appended StringBuilder appends to separate the lines. But both methods do the same thing; they're just a little different under the hood.
1
- ago
#12
Thanks.
0
Cone8
 ( 26.99% )
- ago
#13
It has to be static and so would your StringBuilder if you used it for this purpose. An instance of the Strategy is created for each symbol, that's the whole point. You need "share" the instance of the List so that all are writing to it synchronously.

There's no sharing between Strategy windows; each has their own instance of Backtester.
1
- ago
#14
QUOTE:
An instance of the Strategy is created for each symbol,

So all the "private" MyStrategy field variables are duplicated except what's static (such as List<string> or StringBuilder). Only those declared "static" are shared between symbol instances. Thanks for that clarification. Reply# 11 has been corrected.

There really should be a Backtesting chapter in a tutorial describing these details because I think many people are coming from the WL6 world.
1
Glitch8
 ( 9.56% )
- ago
#15
Yes. maybe that would be a good article for our blog page.
2
- ago
#16
QUOTE:
a good article for our blog page.

Yes, yes!

The most difficult confusion I had was when to cache a variable in BarHistory. I thought whenever you moved a TimeSeries from Initialize() to Execute you had to cache it in BarHistory. But now I'm realizing you do not because the strategy has its own "private" copy of the TimeSeries declared in the MyStrategy block.

Of course if you want to use that same TimeSeries in PreExecute, you do have to cache it anyway in BarHistory because PreExecute has to access all the BarHistory's for every stock in the dataset.

But the above distinction is not spelled out anywhere, and it needs to be along with a diagram showing the hierarchy of all the variable declarations so the "scoping" of the variables is better understood.

And then there are a few users that don't know how to control the scoping the their C# variables with the appropriate placement of their declarations. I've seen some code where they inadvertently declared the same variable twice (one instance in MyStrategy and another in Initialize). So a chapter on scoping/visibility is also in order.
2

Reply

Bookmark

Sort