for solving the error for additional data series that are configures with optimizer UI parameters the following code bypasses the problem, all that is necessary is to set the properties once. The new solution no longer wastes the setup period, it works instantly. The explanation why this is necessary is below. Use at your own risk and no warranty.
public static class StrategyOptimizationParameterInitializer {
public static void InitializeParameters(Strategy strategy, string[] parameterNames) {
bool isSuccessful = true;
foreach(var parameterName in parameterNames) {
bool hasSetValue = false;
foreach(var parameter in strategy.OptimizationParameters) {
if(!parameter.Name.Equals(parameterName)) {
continue;
}
if(!parameter.Min.Equals(parameter.Max) || parameter.EnumValues.Length > 1) {
strategy.Print("Parameter: " + parameterName + " is set to more than one value, it will not be initialized");
} else {
object value = parameter.EnumValues.Length > 0 ? parameter.EnumValues[0] : parameter.Min;
System.Reflection.PropertyInfo propertyInfo = strategy.GetType().GetProperty(parameterName);
propertyInfo.SetValue(strategy, value, null);
hasSetValue = true;
}
break;
}
if(!hasSetValue) {
strategy.Print("Parameter: " + parameterName + " was not set, check if it's name is correct or values are set properly");
isSuccessful = false;
}
}
if(!isSuccessful) {
throw new Exception("Failed to initialize strategy parameters");
}
}
}
} else if (State == State.Configure) {
if(Category == Category.Optimize || Category == Category.MultiObjective || Category == Category.WalkForward) {
if(Optimizer.NumberOfIterations > 0) {
StrategyOptimizationParameterInitializer.InitializeParameters(this, new string[]{"Period"});
}
}
If something goes wrong the strategy won't run but will let the user know in the NT output window.
The workaround does not allow for optimizing the parameter, it has to be constant throughout the run.
The problem is the strategy analyzer starts a dry run and doesn't initialize parameters and as a consequence the error occurs when the real testing starts.
Outdated solution, no longer applies:
Also for tests with a lot of data it is faster to recompile the strategy with constant values instead of this solution, because at least 1 period where NT prepares the data for the tests will be wasted.
namespace NinjaTrader.NinjaScript.Strategies {
public class SomeStrategy : Strategy {
private StaticSettings cachedSettings = StaticSettings.Instance();
protected class StaticSettings {
public bool Initialized = false;
public int Period;
private static StaticSettings instance = null;
private StaticSettings() {
}
public static StaticSettings Instance() {
if(instance == null) {
instance = new StaticSettings();
}
return instance;
}
}
...
} else if (State == State.Configure) {
int settingsPeriod = Period;
if(Category == Category.Optimize) {
bool isDryRun = Optimizer.NumberOfIterations > 0;
lock(cachedSettings) {
if(!isDryRun){
cachedSettings.Period = Period;
cachedSettings.Initialized = true;
} else if(cachedSettings.Initialized) {
settingsPeriod = cachedSettings.Period;
}
}
}
AddDataSeries(BarsPeriodType.Minute, settingsPeriod);
Back testing procedure:
1. Set dynamic property e.g. Period
4. Run test until failure
5. Run test again
How it works:
First a dry run launches to create the bars for testing, but NT does not make the strategy analyzer settings available to it, so the dynamic data series parameter will be different.
Then the real testing starts and iterations that are not the dry will copy their settings a static class. Unfortunately an exception occurs and the testing ends.
On the restart the dry run will use the values from the cache that are the same as the settings from the strategy analyzer.
It would be better to directly load the properties on the first run, but unfortunately if it is possible, I've not discovered how to do so.
Another caveat is that once something is recompiled the static settings cache is lost and the procedure has to be restarted.
Edit:
simplified code & logic
Edit X:
added
} else if (State == State.Terminated) {
SettingsInitialized = false;
}
Edit X+1:
removed SettingsInitialized
Edit X+2:
changed to dynamically setting properties

Comment