kazuna8
 ( 46.86% )
- ago
I like the concept of StrategyRunner and Backtester but I'm rather interested in automating the optimization.

I think Backtester cannot be used for optimization because:
1. There is no way to set the parameters.
2. No parallelism.

Any plan to support optimization in StrategyRunner?
So that I can implement the results filter in the code.
1
881
Solved
7 Replies

Reply

Bookmark

Sort
Glitch8
 ( 11.81% )
- ago
#1
No, no plans for this. Optimization would occur at some level ABOVE this class. In other words, maybe in your own custom extension that’s intended to replace the Optimization built into WL7.
0
kazuna8
 ( 46.86% )
- ago
#2
All right.

So Symbol by Symbol optimization + the results filter would be still a solution, then.

https://www.wealth-lab.com/Discussion/Symbol-by-Symbol-optimization-results-filter-7025
0
- ago
#3
It can happen as a 'side effect' if this request makes it to the top of the queue:
https://www.wealth-lab.com/Discussion/Advanced-filtering-of-optimization-results-7015
Provided we succeed with getting the Syncfusion free license mentioned here:
https://www.wealth-lab.com/Discussion/Filter-optimization-results-6482
0
kazuna8
 ( 46.86% )
- ago
#4
Hopefully the filtering of optimization results feature request makes it as this is crucial for me to be able to optimize more symbols (tens of symbols to hundreds of symbols).
0
- ago
#5
While there is no direct way to set parameters there are workarounds...

For example, you could use Globals or a Settings file to pass parameters to your strategy. It requires a little code modification to the Called Strategy to grab the param values and assign them, but I've tested both methods and they work for me :)

Here are some code snippets, you would need to modify the parameter names and strategy names etc accordingly, but it might help as a staring point

These where created to work with the Simple Channel Breakout 50 WL strategy (Called Strategy) as an example. I made the entry and exit values optimizable then converted it to a C# code strategy. From there I made the necessary mods to the code.

The Calling Strategy was based on the sample included in the QuickRef for the StrategyRunner helper class.

Have fun!

Code Snippet from My Called Strategy - to be run by sr.RunBacktest("My Called Strategy") in the calling strategy.

CODE:
   public MyStrategy() : base()    {       // Select the transfer method by commenting out one of the below       // use settings Manager to get param values from file       getParamsFromSettingsManager();              // or use global to get param values       getParamsFromGlobal();    }    public void getParamsFromGlobal()    {       string StrategyKey = "MyStrategyKey";       string ParamKey = "Percentage";       double Percentage = HasGlobal(StrategyKey + ParamKey) ? (double)GetGlobal(StrategyKey + ParamKey) : 2.25;       ParamKey = "exitPercentage";       double exitPercentage = HasGlobal(StrategyKey + ParamKey) ? (double)GetGlobal(StrategyKey + ParamKey) : 1.25;       AddParameter("Percentage", ParameterTypes.Double, Percentage, 0, 10, 0.01);       AddParameter("exitPercentage", ParameterTypes.Double, exitPercentage, 0, 10, 0.01);    }    public static SettingsManager Param { get; set; } = new SettingsManager(WLHost.Instance.DataFolder.ToString() + "PassParams.ini", false);    public void getParamsFromSettingsManager()    {       double Percentage = Param.Get("Percentage", 2.25);       double exitPercentage = Param.Get("exitPercentage", 1.25);       AddParameter("Percentage", ParameterTypes.Double, Percentage, 0, 10, 0.01);       AddParameter("exitPercentage", ParameterTypes.Double, exitPercentage, 0, 10, 0.01);    }


Code from My Calling Strategy File - runs the sr.RunBacktest("My Called Strategy")
CODE:
   //Backtest Completed (executes once)    public override void BacktestComplete()    {       // Set up Strategy Runner       // ------------------       StrategyRunner sr = new StrategyRunner();       sr.DataSet = DataSetFactory.FindDataSet("DOW 30"); // !IMPORTANT --> Dataset name is CaSeSenSiTiVe       sr.DataRange.DataRangeType = DataRangeTypes.RecentYears;       sr.DataRange.RecentValue = 10; // most recent 10 years adjust as needed       sr.PositionSize.StartingCapital = 100000000; // define starting capital       sr.PositionSize.PositionSizeType = PositionSizeTypes.PctOfEquity;       double pEquity = 2.5; // define % equity       sr.PositionSize.Amount = pEquity; // set position size to 5% of equity adjsut as needed              // set paramters for strategy via a Global       // ------------------       double Percentage = 2.55; // parameter 1 to be sent to strategy       double exitPercentage = 1.55; // parameter 2 to be sent to stratgey              string StrategyKey = "MyStrategyKey"; // anything you like, just make it unique       string ParamKey = "Percentage"; // a string, suggest you use the parameter name       SetGlobal(StrategyKey + ParamKey, Percentage); // set the global key for the first paramter       ParamKey = "exitPercentage"; // change the key name for next parameter       SetGlobal(StrategyKey + ParamKey, exitPercentage); // set the second parameter       // Set Parameters for Strategy via a File (and use SettingsManager to get Params in Strategy       // -------------------       string ParamFile = WLHost.Instance.DataFolder.ToString() + "PassParams.ini";       if (File.Exists(ParamFile))       {          File.Delete(ParamFile); // just to be safe, kill the file if it exits       }       // write the settings file directly. For some reason using SettingsManaget.Set does not write to file in this use case       // besure to use the same file structre as a settings file. Key=Value       string[] Params = { "Percentage=" + Percentage.ToString("N2"), "exitPercentage=" + exitPercentage.ToString("N2") };       File.WriteAllLines(ParamFile, Params);       Thread.Sleep(2000); // Wait to allow settings file to update - crude but effective       try       {          // now run the backtester          Backtester bt = sr.RunBacktest("My Strategy Name"); // set strategy          WriteToDebugLog("My Backtest Parameters: " + pEquity.ToString("N2") + " | " + Percentage.ToString("N2") + " | " + exitPercentage.ToString("N2"));          WriteToDebugLog("My Results: " + bt.NetProfit.ToString("N2") + " | " + bt.Metrics.PositionCount.ToString("N") + " | " + bt.Metrics.NSFPositionCount.ToString("N"));       }       catch (Exception e)       {          WriteToDebugLog(e.Message.ToString());       }    }
1
Best Answer
kazuna8
 ( 46.86% )
- ago
#6
Wow, that's clever!

It solves the first issue.
QUOTE:
1. There is no way to set the parameters.


But the second issue remains
QUOTE:
2. No parallelism.

0
- ago
#7
Correct

The second is non-trivial.

You could possibly multithread the whole thing passing the new Var's to each new thread via an object where you would create the StrategyRunner set the parameters and call RunBacktest, but there are a lot of complications to consider.

- each thread uses the same object to pass its paramters to the Called Strategy... so you would need a way to be sure the previous params have been read, prior to changing for a new run. The Called Strategy only reads in the initialize method, so changes after this should be ok.

- reporting: the debug window only updates at the end of a backtest run of the Calling Strategy. So you would need to complete your entire loop through your parameters (or loop within loops etc) before you get any feedback. You could potentially write to a file or WLLog but multithreading can create issues here as well, especially with file access.

- colating the bt results: perhaps you could set up a private list(of Backtester) to populate with the bt once the bt.RunBacktest is called. Or transfer the results/metrics.

But really, why go to all that trouble. If you want to run optimizations, why not build an optimzer extension and leverage off the work the WL Team have already done managing all these issues?

I haven't looked at building an optimizer yet but everything else I've look at seems pretty straight forward (although, not always well documented :) ). If you have questions the WL team seem pretty quick to respond and very helpful in my experience.


quick update:
Further to the above Code I suggest adding an exception message loop after the sr.RunBacktest Call to print any exceptions that might have been hit in the strategy to the debug window. Might save you some time toubleshooting.

CODE:
               Backtester bt = sr.RunBacktest("My Strategy Name");                if (bt.ExceptionMessages.Count > 0)                {                   foreach(string eXmessage in bt.ExceptionMessages)                   {                   WriteToDebugLog(eXmessage);                   }                }
1

Reply

Bookmark

Sort