Lean  $LEAN_TAG$
EulerSearchOptimizationStrategy.cs
1 /*
2  * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
3  * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14 */
15 
16 using System;
17 using System.Collections.Generic;
18 using System.Linq;
21 
23 {
24  /// <summary>
25  /// Advanced brute-force strategy with search in-depth for best solution on previous step
26  /// </summary>
28  {
29  private object _locker = new object();
30  private readonly HashSet<ParameterSet> _runningParameterSet = new HashSet<ParameterSet>();
31  private int _segmentsAmount = 4;
32 
33  /// <summary>
34  /// Initializes the strategy using generator, extremum settings and optimization parameters
35  /// </summary>
36  /// <param name="target">The optimization target</param>
37  /// <param name="constraints">The optimization constraints to apply on backtest results</param>
38  /// <param name="parameters">Optimization parameters</param>
39  /// <param name="settings">Optimization strategy settings</param>
40  public override void Initialize(Target target, IReadOnlyList<Constraint> constraints, HashSet<OptimizationParameter> parameters, OptimizationStrategySettings settings)
41  {
42  var stepSettings = settings as StepBaseOptimizationStrategySettings;
43  if (stepSettings == null)
44  {
45  throw new ArgumentNullException(nameof(settings),
46  "EulerSearchOptimizationStrategy.Initialize: Optimizations Strategy settings are required for this strategy");
47  }
48 
49  if (stepSettings.DefaultSegmentAmount != 0)
50  {
51  _segmentsAmount = stepSettings.DefaultSegmentAmount;
52  }
53 
54  base.Initialize(target, constraints, parameters, settings);
55  }
56 
57  /// <summary>
58  /// Checks whether new lean compute job better than previous and run new iteration if necessary.
59  /// </summary>
60  /// <param name="result">Lean compute job result and corresponding parameter set</param>
61  public override void PushNewResults(OptimizationResult result)
62  {
63  if (!Initialized)
64  {
65  throw new InvalidOperationException($"EulerSearchOptimizationStrategy.PushNewResults: strategy has not been initialized yet.");
66  }
67 
68  lock (_locker)
69  {
70  if (!ReferenceEquals(result, OptimizationResult.Initial) && string.IsNullOrEmpty(result?.JsonBacktestResult))
71  {
72  // one of the requested backtests failed
73  _runningParameterSet.Remove(result.ParameterSet);
74  return;
75  }
76 
77  // check if the incoming result is not the initial seed
78  if (result.Id > 0)
79  {
80  _runningParameterSet.Remove(result.ParameterSet);
81  ProcessNewResult(result);
82  }
83 
84  if (_runningParameterSet.Count > 0)
85  {
86  // we wait till all backtest end during each euler step
87  return;
88  }
89 
90  // Once all running backtests have ended, for the current collection of optimization parameters, for each parameter we determine if
91  // we can create a new smaller/finer optimization scope
92  if (Target.Current.HasValue && OptimizationParameters.OfType<OptimizationStepParameter>().Any(s => s.Step > s.MinStep))
93  {
94  var boundaries = new HashSet<OptimizationParameter>();
95  var parameterSet = Solution.ParameterSet;
96  foreach (var optimizationParameter in OptimizationParameters)
97  {
98  var optimizationStepParameter = optimizationParameter as OptimizationStepParameter;
99  if (optimizationStepParameter != null && optimizationStepParameter.Step > optimizationStepParameter.MinStep)
100  {
101  var newStep = Math.Max(optimizationStepParameter.MinStep.Value, optimizationStepParameter.Step.Value / _segmentsAmount);
102  var fractal = newStep * ((decimal)_segmentsAmount / 2);
103  var parameter = parameterSet.Value.First(s => s.Key == optimizationParameter.Name);
104  boundaries.Add(new OptimizationStepParameter(
105  optimizationParameter.Name,
106  Math.Max(optimizationStepParameter.MinValue, parameter.Value.ToDecimal() - fractal),
107  Math.Min(optimizationStepParameter.MaxValue, parameter.Value.ToDecimal() + fractal),
108  newStep,
109  optimizationStepParameter.MinStep.Value));
110  }
111  else
112  {
113  boundaries.Add(optimizationParameter);
114  }
115  }
116 
117  foreach (var staticParam in OptimizationParameters.OfType<StaticOptimizationParameter>())
118  {
119  boundaries.Add(staticParam);
120  }
121  OptimizationParameters = boundaries;
122  }
123  else if (!ReferenceEquals(result, OptimizationResult.Initial))
124  {
125  // we ended!
126  return;
127  }
128 
129  foreach (var parameterSet in Step(OptimizationParameters))
130  {
131  OnNewParameterSet(parameterSet);
132  }
133  }
134  }
135 
136  /// <summary>
137  /// Handles new parameter set
138  /// </summary>
139  /// <param name="parameterSet">New parameter set</param>
140  protected override void OnNewParameterSet(ParameterSet parameterSet)
141  {
142  _runningParameterSet.Add(parameterSet);
143  base.OnNewParameterSet(parameterSet);
144  }
145  }
146 }