public override void Optimize() { bool fFirstRun = (_form == null); _rgParameterDefinitions = new ParameterDefinitions(this.Strategy, fFirstRun); if (fFirstRun) { _form = new StochasticsOptionsDialog(); } _form.InitializeParameters(_rgParameterDefinitions); DateTime dateStartLast = _dateStartLast; _dateStartLast = Strategy.BackTestFrom; if (!_form.WalkForward || Strategy.BackTestFrom <= dateStartLast) { if (_form.ShowDialog(Form.ActiveForm) != DialogResult.OK) { return; } } #if !NT7 _nPopulationSize = _form.PopulationSize; _cMaxGenerations = _form.MaxGenerations; _fitnessGainMax = _form.FitnessGain; _nPopulationSize = 10; //_form.PercentAnnealing; _nMinimumPerformce = _form.MinimumPerformance; #endif int cParams = _rgParameterDefinitions.Count; _rgParameterRunCounts = new int [cParams] []; _rgParameterRunTotals = new double [cParams] []; _rgParameterRunAverage = new double [cParams] []; decimal cCombinationsActual = _rgParameterDefinitions.CountCombinations; long cCombinations = (long)Math.Min(cCombinationsActual, (decimal)long.MaxValue); for (int ipd = 0; ipd < _rgParameterDefinitions.Count; ipd++) { ParameterDefinition pd = _rgParameterDefinitions [ipd]; int cValues = pd.CountValues; _rgParameterRunCounts [ipd] = new int [cValues]; _rgParameterRunTotals [ipd] = new double [cValues]; _rgParameterRunAverage [ipd] = new double [cValues]; } Dictionary <ParameterSet, bool> setChildren = new Dictionary <ParameterSet, bool> (); List <ParameterSet> rgChildren = new List <ParameterSet> (); int fitnessGainMin = 1; int cAnnealing = _nPopulationSize * _percentAnnealing / 100; // create an initial generation of aliens int cIterations = 0; while (rgChildren.Count < _nPopulationSize) { ParameterSet child = CreateAlien(); if (setChildren.ContainsKey(child)) { continue; } setChildren.Add(child, true); rgChildren.Add(child); } DateTime timeStart = DateTime.Now; ParameterSet bestChild = null; int iGeneration = 0; try { Strategy.Print( string.Format( "{0}: PH Stochastic Optimizer Start @ {1}, combinations: {2:N0}", Strategy.Instrument.FullName, timeStart, cCombinationsActual ) ); double diffMax = 0; double diffCurr = 0; int fitnessGain = fitnessGainMin; ParameterSet bestPrev = null; for (iGeneration = 0; iGeneration < _cMaxGenerations; iGeneration++) { // score the new generation ScoreGeneration(rgChildren); rgChildren.Sort(); if (bestChild == null) { bestChild = rgChildren [0]; } else if (bestChild.Performance < rgChildren [0].Performance) { bestChild = rgChildren [0]; } if (bestPrev != null) { if (double.IsNaN(bestPrev.Performance) || bestChild.Performance > bestPrev.Performance) { if (fitnessGain < FitnessGainMax) { fitnessGain++; } } else if (fitnessGain > fitnessGainMin) { fitnessGain--; } } bestPrev = bestChild; cIterations += rgChildren.Count; TimeSpan diff = DateTime.Now - timeStart; double iterPerSec = cIterations / diff.TotalSeconds; Strategy.Print(string.Format( "{0}: gen {1}/{2}, {3:N1} ips, max PERF: {4:N2}, gain={5}\t{6}", Strategy.Instrument.FullName, iGeneration + 1, _cMaxGenerations, iterPerSec, bestChild.Performance, fitnessGain, bestChild == null ? "" : _rgParameterDefinitions.ToString(bestChild))); if (bestChild != null && bestChild.Performance > this._nMinimumPerformce) { Strategy.Print(string.Format("{0}: Minimum performance reached.", Strategy.Instrument.FullName)); return; } if (iGeneration == _cMaxGenerations - 1) { break; } // initialize a new generation rgChildren.Clear(); int cCollisions = _nPopulationSize; while (cCollisions > 0 && rgChildren.Count < _nPopulationSize) { int iParam = _rand.Next(cParams); int cValues = _rgParameterDefinitions [iParam].CountValues; int [] rgParams = new int [cParams]; for (int iParamFuzz = 0; iParamFuzz < cParams; iParamFuzz++) { rgParams [iParamFuzz] = bestChild.GetParam(iParamFuzz); } rgParams [iParam] = MutateParam(fitnessGain, cValues, rgParams [iParam]); ParameterSet child = new ParameterSet(rgParams); if (setChildren.ContainsKey(child)) { cCollisions--; } else { setChildren.Add(child, true); rgChildren.Add(child); } } double loopFitnessGain = fitnessGain; if (rgChildren.Count < _nPopulationSize) { // pre-calculate the parameter value weights double [] [] rgrgWeights = new double [cParams] []; double [] rgTotalWeights = new double [cParams]; for (int iParam = 0; iParam < cParams; iParam++) { int cValues = _rgParameterDefinitions [iParam].CountValues; rgrgWeights [iParam] = new double [cValues]; double [] rgAverages = _rgParameterRunAverage [iParam]; // get the range of PERF values double minPerformance = double.PositiveInfinity; double maxPerformance = double.NegativeInfinity; for (int i = 0; i < cValues; i++) { double performance = rgAverages [i]; if (minPerformance > performance) { minPerformance = performance; } if (maxPerformance < performance) { maxPerformance = performance; } } // weight the procreation probabilities double totalWeight = 0; //if (maxPerformance != minPerformance) { for (int iValue = 0; iValue < cValues; iValue++) { double average = rgAverages [iValue]; if (double.IsNaN(average) || double.IsInfinity(average)) { average = maxPerformance; } double weight = Math.Pow((average - minPerformance) / (maxPerformance - minPerformance), loopFitnessGain); if (double.IsNaN(weight)) { weight = 0.0; } weight += 0.001; rgrgWeights [iParam] [iValue] = weight; totalWeight += weight; } } rgTotalWeights [iParam] = totalWeight; } cCollisions = _nPopulationSize; while (cCollisions > 0 && rgChildren.Count < _nPopulationSize && setChildren.Count < cCombinations) { // create a new set of genes int [] rgParams = new int [cParams]; for (int iParam = 0; iParam < cParams; iParam++) { int cValues = _rgParameterDefinitions [iParam].CountValues; double [] rgWeights = rgrgWeights [iParam]; double weightRandom = _rand.NextDouble() * rgTotalWeights [iParam]; int iValueRandom = 0; while (iValueRandom < cValues && weightRandom > rgWeights [iValueRandom]) { weightRandom -= rgWeights [iValueRandom]; iValueRandom++; } rgParams [iParam] = iValueRandom; } // create the new child, and make sure it's unique ParameterSet child = new ParameterSet(rgParams); if (setChildren.ContainsKey(child)) { if (loopFitnessGain > 1) { loopFitnessGain--; } cCollisions--; } else { setChildren.Add(child, true); rgChildren.Add(child); } } } } } catch (AbortOptimizationException) { Strategy.Print("Optimization Aborted..."); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e); Strategy.Print(e.ToString()); //throw; } finally { #if NT7 WaitForIterationsCompleted(true); #endif DateTime timeEnd = DateTime.Now; TimeSpan tsDuration = timeEnd - timeStart; if (iGeneration > 0) { Strategy.Print(string.Format( "{0}: PH Optimizer End @ {1}, duration: {2} ({3} per iteration)", Strategy.Instrument.FullName, timeEnd, tsDuration, TimeSpan.FromTicks(tsDuration.Ticks / iGeneration) ) ); } if (bestChild != null) { Dump(bestChild); } } }
public override void Optimize() { DNA dnaBestEver = null; try { // initialize the parameter definition bool fFirstRun = (_form == null); _rgParameterDefinitions = new ParameterDefinitions(this.Strategy, fFirstRun); if (fFirstRun) { _form = new GeneticOptionsDialog(); } _form.InitializeParameters(_rgParameterDefinitions); DateTime dateStartLast = _dateStartLast; _dateStartLast = Strategy.BackTestFrom; if (!_form.WalkForward || Strategy.BackTestFrom <= dateStartLast) { if (_form.ShowDialog(Form.ActiveForm) != DialogResult.OK) { #if NT7 WaitForIterationsCompleted(true); #endif return; } } #if !NT7 _nPopulationSize = _form.PopulationSize; _cMaxGenerations = _form.MaxGenerations; _mutationRate = _form.MutationRate; _mutationStrength = _form.MutationStrength; _fitnessGain = _form.FitnessGain; _percentAliens = _form.Aliens; _stabilitySize = _form.StabilitySize; _resetSize = _form.ResetSize; _nMinimumPerformce = _form.MinimumPerformance; #endif int cAliens = (int)Math.Ceiling(_nPopulationSize * _percentAliens); int nStabilitySize = (int)Math.Ceiling(_nPopulationSize * _stabilitySize); int nResetSize = _nPopulationSize - (int)Math.Ceiling(_nPopulationSize * _resetSize); DateTime timeStart = DateTime.Now; int cParams = _rgParameterDefinitions.Count; decimal cCombinationsActual = _rgParameterDefinitions.CountCombinations; long cCombinations = (long)Math.Min(cCombinationsActual, (decimal)long.MaxValue); Strategy.Print( string.Format( "{0}: PH Genetic Optimizer Start @ {1}, combinations: {2:N0}", Strategy.Instrument.FullName, timeStart, cCombinationsActual ) ); List <DNA> rgChildren = new List <DNA> (); Dictionary <DNA, bool> setChildren = new Dictionary <DNA, bool> (); // create an initial generation of aliens int cIterations = 0; double stabilityScorePrev = double.NaN; List <DNA> rgParents = new List <DNA> (); int iGeneration; for (iGeneration = 1; iGeneration <= _cMaxGenerations; iGeneration++) { // fill the rest of this generation with aliens while (rgChildren.Count < _nPopulationSize && setChildren.Count < cCombinations) { DNA child = CreateAlien(0); if (setChildren.ContainsKey(child)) { continue; } setChildren.Add(child, true); rgChildren.Add(child); } DNA dnaBestSinceReset = null; try { // score the new generation ScoreGeneration(rgChildren); //if (rgParents.Count > nPopulationSize) // rgParents.RemoveRange (nPopulationSize, rgParents.Count - nPopulationSize); rgParents.AddRange(rgChildren); rgParents.Sort(); dnaBestSinceReset = rgParents [0]; } finally { if (rgParents.Count > 0 && dnaBestSinceReset != null && (dnaBestEver == null || dnaBestEver.Performance < dnaBestSinceReset.Performance)) { dnaBestEver = dnaBestSinceReset; } } double stabilityScore = 0.0; int cStabilityIndividuals = (int)Math.Min(rgParents.Count, nStabilitySize); if (cStabilityIndividuals < 1) { cStabilityIndividuals = 1; } for (int i = 0; i < cStabilityIndividuals; i++) { double scoreParent = rgParents [i].Performance; if (scoreParent > double.NegativeInfinity) { stabilityScore += rgParents [i].Performance; } } cIterations += rgChildren.Count; TimeSpan diff = DateTime.Now - timeStart; double iterPerSec = cIterations / diff.TotalSeconds; Strategy.Print(string.Format( "{0}: gen {1}/{2}, {3:N1} ips, max PERF: {4:N2}, stability PERF: {5:N2}\t{6}", Strategy.Instrument.FullName, iGeneration, _cMaxGenerations, iterPerSec, dnaBestSinceReset.Performance, stabilityScore / cStabilityIndividuals, rgParents.Count == 0 ? "" : _rgParameterDefinitions.ToString(dnaBestSinceReset))); if (dnaBestEver != null) { Strategy.Print(dnaBestEver.Performance + ", " + _nMinimumPerformce); } if (dnaBestEver != null && dnaBestEver.Performance > _nMinimumPerformce) { Strategy.Print(string.Format("{0}: Minimum performance reached.", Strategy.Instrument.FullName)); return; } if (iGeneration == _cMaxGenerations) { break; } if (setChildren.Count >= cCombinations) { break; } if (stabilityScore == stabilityScorePrev) { //rgParents.RemoveRange (1, rgParents.Count - 1); rgParents.Clear(); rgChildren.Clear(); Strategy.Print(string.Format( "{0}: reset", Strategy.Instrument.FullName ) ); //stabilityScore = double.NaN; continue; } // get the range of PERF values double minPerformance = double.MaxValue; double maxPerformance = double.MinValue; for (int i = 0; i < rgParents.Count; i++) { double performance = rgParents [i].Performance; if (performance == double.NegativeInfinity) { continue; } if (minPerformance > performance) { minPerformance = performance; } if (maxPerformance < performance) { maxPerformance = performance; } } // weight the procreation probabilities if (maxPerformance != minPerformance) { for (int i = 0; i < rgParents.Count; i++) { DNA parent = rgParents [i]; double performance = parent.Performance; if (performance == double.NegativeInfinity) { parent.Weight = 0; } else { double weight = (parent.Performance - minPerformance) / (maxPerformance - minPerformance); #if true parent.Weight = Math.Pow(weight, _fitnessGain) + 0.001; #else parent.Weight = (Math.Pow(weight, fitnessGain / (iGeneration - parent.Generation)) + 0.001); #endif } } } double totalWeight = 0; for (int i = 0; i < rgParents.Count; i++) { totalWeight += rgParents [i].Weight; } // initialize a new generation rgChildren.Clear(); // a certain percentage of the new population are aliens: int cAliensThisGeneration; if (stabilityScore == stabilityScorePrev) { cAliensThisGeneration = nResetSize; } else { cAliensThisGeneration = cAliens; } while (rgChildren.Count < cAliensThisGeneration && setChildren.Count < cCombinations) { DNA child = CreateAlien(iGeneration); if (setChildren.ContainsKey(child)) { continue; } setChildren.Add(child, true); rgChildren.Add(child); } // fuzz each param individually for (int iParam = 0; iParam < cParams; iParam++) { int cValues = _rgParameterDefinitions [iParam].CountValues; for (int iFuzz = 0; iFuzz < 5; iFuzz++) { int [] rgParams = new int [cParams]; for (int iParamFuzz = 0; iParamFuzz < cParams; iParamFuzz++) { rgParams [iParamFuzz] = dnaBestSinceReset.GetParam(iParamFuzz); } rgParams [iParam] = MutateParam(_mutationStrength, cValues, rgParams [iParam]); DNA child = new DNA(rgParams, dnaBestSinceReset.Generation + 1); if (!setChildren.ContainsKey(child)) { setChildren.Add(child, true); rgChildren.Add(child); } } } while (rgChildren.Count < _nPopulationSize - cAliensThisGeneration && setChildren.Count < cCombinations) { if (UserAbort) { throw new AbortOptimizationException(); } // find parents rendomly according to weighted fitness double weightA = _rand.NextDouble() * totalWeight; int iParentA = 0; while (iParentA < rgParents.Count && weightA > rgParents [iParentA].Weight) { weightA -= rgParents [iParentA].Weight; iParentA++; } double weightB = _rand.NextDouble() * totalWeight; int iParentB = 0; while (iParentB < rgParents.Count && weightB > rgParents [iParentB].Weight) { weightB -= rgParents [iParentB].Weight; iParentB++; } // these are the parents: DNA parentA = rgParents [iParentA]; DNA parentB = rgParents [iParentB]; // create a new set of genes int [] rgParams = new int [cParams]; for (int iParam = 0; iParam < cParams; iParam++) { // Take an attribute from parents DNA parent = (_rand.Next(100) < 50) ? parentA : parentB; rgParams [iParam] = parent.GetParam(iParam); // Should we mutate? int cValues = _rgParameterDefinitions [iParam].CountValues; if (cValues > 1 && _rand.NextDouble() < _mutationRate) { rgParams [iParam] = MutateParam(_mutationStrength, cValues, rgParams [iParam]); } } // create the new child, and make sure it's unique //int iGenerationChild = iGeneration; //int iGenerationChild = 1 + Math.Min (parentA.Generation, parentB.Generation); int iGenerationChild = (parentA.Generation + parentB.Generation) / 2; DNA child = new DNA(rgParams, iGenerationChild); if (!setChildren.ContainsKey(child)) { setChildren.Add(child, true); rgChildren.Add(child); } } stabilityScorePrev = stabilityScore; } DateTime timeEnd = DateTime.Now; TimeSpan tsDuration = timeEnd - timeStart; Strategy.Print(string.Format( "{0}: PH Optimizer End @ {1}, duration: {2} ({3} per iteration)", Strategy.Instrument.FullName, timeEnd, tsDuration, TimeSpan.FromTicks(tsDuration.Ticks / iGeneration) ) ); } catch (AbortOptimizationException) { Strategy.Print("Optimization Aborted..."); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e); Strategy.Print(e.ToString()); //throw; } finally { if (dnaBestEver != null) { Dump(dnaBestEver); } } #if NT7 WaitForIterationsCompleted(true); #endif }