public double? Forecast(TimeSeries source, int horizon, ForecastSettings settings)
        {
            var i = source.timeseries.Count - 1; //это означает, что хотим получить прогноз для последнего значения в ряду
            var counter = i % timestampNumber;
            List<double> inputVector = createInputVector(i, source, settings, maxValues[counter], minValues[counter], timestampNumber);

            if (inputVector == null) return null; //не получилось
            if (networkSet.Count <= counter) return null;

            networkSet[counter].propagate(inputVector);

            var output = networkSet[counter].Outputs.First();
            output = output*(maxValues[counter] - minValues[counter]) + minValues[counter];

            return output;
        }
        public onNeuralPredictionFilter(FilterParameters parameters, DateTime trainTill, DataExchange exchange = null)
        {
            this.exchange = exchange;
            this.waitUntil = trainTill;
            this.timeSeries = new TimeSeries(0);

            settings = new ForecastSettings();
            for (int i = 0; i < 5; i++)
            {
                settings.energyLags.Add(i + 1);
            }

            model = new MultipleNeuralNetworksModel();
            this.parameters = parameters;
            parameters.Values["model"] = model;
        }
        /// <summary>
        /// Извлечь выходные данные для обучения.
        /// </summary>
        /// <param name="counter"></param>
        /// <param name="_ts"></param>
        /// <param name="_fs"></param>
        /// <param name="_maxValue"></param>
        /// <param name="_minValue"></param>
        /// <returns></returns>
        private List<double> createOutputVector(int counter, TimeSeries source, double maxValue, double minValue)
        {
            List<double> OutputVector = new List<double>();

            var energyValue = source.timeseries[counter];
            var normalizedValue = maxValue != minValue ? (energyValue - minValue) / (maxValue - minValue) : 0.5;
            OutputVector.Add(normalizedValue);

            return OutputVector;
        }
        /// <summary>
        /// Извлечь входной вектор для обучения
        /// </summary>
        /// <param name="counter">Порядковый номер значения во временном ряду, которое будет прогнозироваться.</param>
        /// <param name="source">Временной ряд, из которого брать значения.</param>
        /// <param name="settings">Настройки прогнозирования.</param>
        /// <param name="_maxValue">Максимальное значение для данного времени суток.</param>
        /// <param name="_minValue">Минимальное значение для данного времени суток.</param>
        /// <param name="timestampNumber">Количество отсчетов в день.</param>
        /// <returns></returns>
        private List<double> createInputVector(int counter, TimeSeries source, ForecastSettings settings, double _maxValue, double _minValue, int timestampNumber)
        {
            //вычисляем нижнюю границу, т.е. минимальное количество ретроспективных значений,
            //необходимое для осуществления прогноза
            var minLength = settings.energyLags.Max() * timestampNumber;

            //если доступно значений меньше, чем нужно, то ничего не получится
            if (counter < minLength) return null;

            List<double> InputVector = new List<double>();

            InputVector.Add(1.0); //это вот точно здесь нужно? зачем?

            for (int j = 0; j < settings.energyLags.Count; j++)
            {
                var energyValue = source.timeseries[counter - (settings.energyLags[j] * timestampNumber)];
                var normalizedValue = _maxValue != _minValue ? (energyValue - _minValue)/(_maxValue - _minValue) : 0.5;
                InputVector.Add(normalizedValue);
            }

            return InputVector;
        }