- ago
I am building StrategyRunner code in BacktestBegin method. I have a few questions.

First the easy one.

1. I can't figure out how to use PositionSize to set to Contracts/Shares = 1. I only see how to change % equity.

2. I would like to know which parameters are passed from stratName in RunBacktest (stratName) and which ones have to be set. E.g. Is position size passed (doesn't seem like it in my testing.) It also looks like data range is not passed and will default to 10 years if not explicitly set. What about the parameter values that are set for the indicators used in stratName?

3. Is there a way to show a chart of the StrategyRunner price history with trades and indicators for a symbol run?

4. I am trying to set the data range for StrategyRunner to 1 year. This is to match the data range in stratName. It appears to be backtesting on 2 years of data. Here's the code I used. Did I do something wrong?

CODE:
      public override void BacktestBegin()       {          StrategyRunner sr = new StrategyRunner();          sr.DataRange = new DataRange(DataRangeTypes.YearRange, 0, DateTime.Now.Date.AddYears(-1), DateTime.Now.Date);;

0
1,172
Solved
28 Replies

Reply

Bookmark

Sort
- ago
#1
QUOTE:
1. I can't figure out how to use PositionSize to set to Contracts/Shares = 1. I only see how to change % equity.

It's documented, have you reviewed the "Wealth-Lab Framework" API section?
https://www.wealth-lab.com/Support/ApiReference/PositionSize

QUOTE:
2. I would like to know which parameters are passed

You're creating a new object and therefore should initialize it explicitly to make certain.

QUOTE:
It appears to be backtesting on 2 years of data.

What makes you think so? It appears to work correctly for me.
0
- ago
#2
QUOTE:
It's documented, have you reviewed the "Wealth-Lab Framework" API section?
https://www.wealth-lab.com/Support/ApiReference/PositionSize

No, I didn't. Had no idea I should look in API section for details on something that I expected to be documented in QS. Nevertheless, I had already tried all the various permutations and can't get the syntax right. When I enter
CODE:
         sr.PositionSize.PositionSizeType.
I can't figure out how to get to the "Quantity" option. It doesn't exist as a method and sr.PositionSize.PositionSizeType ("Quantity") doesn't work either. Maybe I'm not interpreting the documentation correctly.

It would save me a lot of time if you could show me at least one correctly formed command to buy 1 Contract/Share. Maybe it's actually obvious, but I've spent at least 2 hours trying to puzzle this out.
0
Glitch8
 ( 10.94% )
- ago
#3
It's documented in the web site API doc, and in the WL7 QuickRef for the PositionSize class, what you are looking for is the PositionSize.Amount property ...

https://www.wealth-lab.com/Support/ApiReference/PositionSize
0
- ago
#4
QUOTE:
What makes you think so? It appears to work correctly for me.

Because I have the Debug log data that shows it is buying positions nearly 2 years ago. Is the code I provided to set the timeframe well-formed or is there an error in it? Are you saying you use my code line and get only one year of data?
0
- ago
#5
I used the QuickRef sample code.
0
- ago
#6
QUOTE:
It's documented in the web site API doc, and in the WL7 QuickRef for the PositionSize class, what you are looking for is the PositionSize.Amount property ...

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


I'm clearly lost. PositionSize.Amount according to documentation appears to only refer to a % Equity Sizing. What is the rest of the syntax after
CODE:
PositionSize.Amount

that converts to quantity vs. percentage?

Can someone *please* write one complete, well-formed line of code for me so I can see the big picture of how this works?
0
- ago
#7
QUOTE:
I used the QuickRef sample code.

For how many years? Did you try my code to see if you get one year of data or two? Is my code well-formed to generate only one year of data?
0
- ago
#8
QUOTE:
that converts to quantity vs. percentage?

Have you seen the QuickRef > PositionSize > Amount?
0
Glitch8
 ( 10.94% )
- ago
#9
Here's a complete working example using 1 share per position. (I used the second PositionSize constructor to more easily construct the PositionSize instance in one line.)

CODE:
//Initialize public override void Initialize(BarHistory bars) {          StrategyRunner sr = new StrategyRunner();          sr.Symbols.Add("AAPL");          sr.DataRange = new DataRange(DataRangeType.RecentYears, 1);          sr.PositionSize = new PositionSize(PositionSizeType.Quantity, 1);          Backtester result = sr.RunBacktest("Neo Master");          TimeSeries equityCurve = result.EquityCurve;          WriteToDebugLog("Backtest Range: " + equityCurve.StartDate.ToShortDateString() + " to " + equityCurve.EndDate.ToShortDateString());          foreach(Position position in result.Positions)             WriteToDebugLog(position.ToString()); }
0
- ago
#10
Thank you @Glitch. I didn't understand that there were two separate values that had to be set. I figured this out after your previous post and re-reading the Amount documentation. I must say I (and maybe only I) went in a different direction based on the QS doc.

CODE:
         sr.PositionSize.PositionSizeType = PositionSizeTypes.Quantity;          sr.PositionSize.Amount = 1;


I was unable to find example code of this or your "Set to Quantity" function documented. I now see that it is implied in the API documentation and usage may have been clear to a more experience C# programmer than I.
0
- ago
#11
Lest my open question gets lost in this increasingly complex thread, I'll repeat it here:

Does this code look well-formed to generate exactly one year of backtest data?

CODE:
         sr.DataRange = new DataRange(DataRangeTypes.YearRange, 0, DateTime.Now.Date.AddYears(-1), DateTime.Now.Date);
0
Glitch8
 ( 10.94% )
- ago
#12
Yes, that looks fine, you could also just use the RecentYears, 1.

One thing to look out for though, different Strategies have different StartIndices, and Building Block Strategies automatically set a StartIndex based on the longest period of any selected indicator.

So the resulting Equity Curve will be shortened by the amount of that StartIndex. If you're using a 200 day moving average for example, you might want to add another year to your backtest data range to compensate.
0
- ago
#13
@Glitch
1. it is a C# not a BB strategy
2. Longest MA is 30 bars. Data history appears off by a year, so I don't think it has to do with StartIndex.

Where can I find usage / example for RecentYears? I have tried QR, Help, API and Google search and can't find it.
0
Glitch8
 ( 10.94% )
- ago
#14
It's just another one of the enumerated types:

new DataRange(DataRangeTypes.RecentYears, 1)

And I notice you keep mentioning QS, were you an old Quantacula Studio user??
0
- ago
#15
@Glitch Got it. Interestingly, that works differently than the original construction and appears to be pulling in one year of historical data. I will do more checking to confirm, but it definitely has a different result than the previous construction.

QUOTE:
And I notice you keep mentioning QS, were you an old Quantacula Studio user??

Unfortunately, no. ;)
I'm meaning to write QR (QuickRef). Sorry for the confusion and thanks for the catch. I'll try to stop doing that.
0
- ago
#16
One other open question from this thread is whether it is possible to display a chart the StrategyRunner backtest results. Would be very helpful for troubleshooting / QA to make sure the selected strategy is operating as expected.
0
Glitch8
 ( 10.94% )
- ago
#17
No, that's out of scope for the StrategyRunner.
0
- ago
#18
Though you can plot any chart you want with the 3rd party ScottPlot component:

https://www.wealth-lab.com/Discussion/Build-9-Sneak-Preview-6131

They even have a cookbook with examples on plotting OHLC charts:
https://scottplot.net/cookbook/4.0/#plottypes-finance-ohlc-with-gaps

Strictly as a DIY project, of course - your usage would be unsupported.
1
- ago
#19
Thanks for that suggestion, Eugene. I took a quick look at ScottPlot. I am looking for the classic WL post-backtest chart that shows indicators and trades. Want to use for troubleshooting. Doesn't look like ScottPlot is designed for that.
0
- ago
#20
QUOTE:
You're creating a new object and therefore should initialize it explicitly to make certain.


@Eugene, in case I wasn't completely clear I am referring to parameters in "My Strategy" to be run by StrategyRunner("My Strategy"). I have 3 different SMA series that are used to generate signals. Each, of course, has its own period parameter. I have the period parameter value set in "MY Strategy" through the UI, and these are also the default values in the Parameter setting in code.

Are you suggesting I set the "My Strategy" parameters in the StrategyRunner code? Or do I misunderstand? I haven't seen how to do this in anything I've come across so far related to StrategyRunner.

A question related to troubleshooting: is StrategyRunner able to access the values of these "My Strategy" SMA series values at each bar?
0
Glitch8
 ( 10.94% )
- ago
#21
If you need to run with different sets of parameters, the easiest way i can think to do that would to save the strategy with a different name and change the parameter defaults for each version.

Let me spend a little time, there might be another solution but i need some time to mock it up and see if it works.
0
Glitch8
 ( 10.94% )
- ago
#22
Here's an example of how you could use StrategyRunner to run a Strategy having changed the parameters. It's using a part of the framework we haven't had a chance to document yet, but it's on the to do list (StrategyFactory).

CODE:
//Initialize public override void Initialize(BarHistory bars) {          //Find the Strategy using the StrategyFactory          Strategy s = StrategyFactory.FindStrategy("RSI2");          StrategyBase sb = s.CreateInstance();          if (s == null)             throw new ArgumentException("Strategy not found: RSI2");         //set up the StrategyRunner          StrategyRunner sr = new StrategyRunner();          sr.PositionSize = new PositionSize(PositionSizeTypes.PctOfEquity, 10);          sr.DataRange = new DataRange(DataRangeTypes.RecentYears, 2);          sr.Symbols.Add("BA");          //Run with default parameters          Backtester result = sr.RunBacktest(sb);          WriteToDebugLog("Profit Run 1: " + result.NetProfit.ToString("N2"));          //Run with different parameters          sb.Parameters[2].Value = 40.0;          result = sr.RunBacktest(sb);          WriteToDebugLog("Profit Run 2: " + result.NetProfit.ToString("N2")); }
0
- ago
#23
CODE:
sb.Parameters[2].Value = 40.0;
@Glitch this is very interesting. In this example, sb.Parameters[2] the third parameter in the RSI2 Strategy? If so, it's clear.
I appreciate you ginning this up for me but I wasn't actually looking to *change* the parameters of "My Strategy". I was responding to @Eugene's reply to me in Post #1 above
QUOTE:

2. I would like to know which parameters are passed

You're creating a new object and therefore should initialize it explicitly to make certain.

I wanted to know if StrategyRunner would use the parameters (with the exception of Data Range and Position.Amount) from "MyStrategy "or If it required them to be set in the StrategyRunner code. @Eugene seemed to imply that "to be safe" I should set all the "My Strategy" parameters in the StrategyRunner code. I wanted to confirm this was what he meant, and if it was, how I could do that.

You answered the second part with your example, so now I see how to do it.

But I would still like to know if it's *necessary* or *highly recommended* to add parameter values that are already set as defaults in "My Strategy.".

I initially assumed the default case would be that StrategyRunner would use the values set in the Strategy Parameter section of Strategy Settings in "My Strategy".


0
Glitch8
 ( 10.94% )
- ago
#24
It will use whatever values you set in the parameter Settings, yes. So, unless you want to test out different variations, really no need to change them.
0
Best Answer
- ago
#25
Thank you! One question you didn't answer is whether I can capture indicator values or bar data at certain bars from the backtest. (Last line of Post #20 above.)
0
- ago
#26
QUOTE:
One question you didn't answer

This blatantly inquisitive style of discussion makes me shiver 👎 - but now even more than in WL6 days 😂

While the debug output of "donor" strategies is suppressed by the Backtester, you can assign an indicator's value to a Position object's Tag property in the source strategy. For example, at the time of creation. Since Tag accepts any object it can take any value or even a group of values. Say a Tuple or other complex data structure if you need something more beyond a simple double value:
CODE:
LastPosition.Tag = myIndicator[idx];

In any case you'd have to cast it back to the original type:
CODE:
Backtester result = sr.RunBacktest(sb); double indicatorVal = (double)result.Positions[0].Tag;


It's C# 101 so since you do LINQ I assume you master it already.
https://www.dotnetperls.com/cast
0
Glitch8
 ( 10.94% )
- ago
#27
All of the BarHistory data used in the backtest is available in the Backtester.Symbols property. For indicators, if you created them using the Series method (rsi = RSI.Series(bars.Close, 20)) then they will be in the BarHistory.Cache property. You could also add any other information you need into a BarHistory.Cache and access it after the StrategyRunner completes the backtest.
1
- ago
#28
@Eugene Sorry I offended. I should have worded it differently. I do appreciate @Glitch and your help. And I clearly require help.
0

Reply

Bookmark

Sort