public void Optimise(DateTime fromDate, DateTime toDate) { _stakingService.Evaluate(fromDate, toDate); var history = _marketDataCache.TakeUntil(toDate).ToArray(); // Build 2d array where each cell is sized to has equal data points and probability var xData = history.Select(_xSelector).ToArray(); var yData = history.Select(_ySelector).ToArray(); var grid = new Grid <List <decimal> >(xData, yData, _parameters.Partitions); // Place each data point in appropriate cell var marketDataValues = _ratingService.CalculateMarketDataValues(history); foreach (var data in history) { var x = _xSelector(data); var y = _ySelector(data); var cell = grid[x, y]; marketDataValues.TryGetValue(data.Date, out var value); cell.Add(value); } // Determine the average value of each cell var averages = grid .Where(x => x.Any()) .Select(GetAverage) .Distinct() .ToArray(); var minValue = Convert.ToInt32(Math.Round(averages.Min(), MidpointRounding.ToNegativeInfinity)); var maxValue = Convert.ToInt32(Math.Round(averages.Max(), MidpointRounding.ToPositiveInfinity)); var range = maxValue - minValue; // Search for optimal buy threshold var potentials = Enumerable.Range(minValue, range) .SelectMany(t => Enumerable.Range(2, 8) .Select(p => new ClusteringParameters { Partitions = p, Threshold = -t, Grid = grid })); var optimal = _searcher.Maximum(potentials, fromDate, toDate); _parameters = (ClusteringParameters)optimal; }