// TODO: refactor
        private IEnumerable <SupportAndResistanceValue> PartialGap(double priceRangeStdDev)
        {
            List <SupportAndResistanceValue> pGap = new List <SupportAndResistanceValue>();

            for (int i = 0; i < _data.Count - 1; i++)
            {
                double nextLowDiffCurrHigh = _data.Low[i + 1] - _data.High[i];
                double nextHighDiffCurrLow = _data.Low[i] - _data.High[i + 1];

                if (nextLowDiffCurrHigh > priceRangeStdDev * 2)
                {
                    bool include = true;
                    for (int j = i + 2; j < _data.Count; j++)
                    {
                        if (_data.High[j] < _data.High[i] || _data.Low[j] < _data.High[i])
                        {
                            include = false;
                            break;
                        }
                    }
                    if (include)
                    {
                        SupportAndResistanceValue value = new SupportAndResistanceValue(_data.High[i], _data.Date[i], SupportAndResistanceValueType.GapResistance);
                        pGap.Add(value);
                    }
                }
                else if (nextHighDiffCurrLow > priceRangeStdDev * 2)
                {
                    bool include = true;
                    for (int j = i + 2; j < _data.Count; j++)
                    {
                        if (_data.High[j] > _data.Low[i] || _data.Low[j] > _data.Low[i])
                        {
                            include = false;
                            break;
                        }
                    }
                    if (include)
                    {
                        SupportAndResistanceValue value = new SupportAndResistanceValue(_data.Low[i], _data.Date[i], SupportAndResistanceValueType.GapSupport);
                        pGap.Add(value);
                    }
                }
            }

            return(pGap);
        }
        private List <SupportAndResistanceValue> FindGaps(ref List <double> volumeProfile, ref List <double> priceChain)
        {
            List <SupportAndResistanceValue> gapSR = new List <SupportAndResistanceValue>();

            if (!volumeProfile.Exists(d => d.AlmostEqualRelative(0.0, AbsoluteError)))
            {
                return(gapSR);
            }

            List <int> gapUp, gapDown;

            _data.FindGaps(out gapUp, out gapDown);

            gapSR.AddRange(gapUp.Select(j =>
            {
                double val    = _data.Low[j];
                DateTime date = _data.Date[j];
                SupportAndResistanceValue srVal = new SupportAndResistanceValue(val, date, SupportAndResistanceValueType.GapSupport);
                return(srVal);
            }));

            gapSR.AddRange(gapDown.Select(j =>
            {
                double val    = _data.High[j];
                DateTime date = _data.Date[j];
                SupportAndResistanceValue srVal = new SupportAndResistanceValue(val, date, SupportAndResistanceValueType.GapResistance);
                return(srVal);
            }));

            int i = 0;

            while (i < volumeProfile.Count)
            {
                if (volumeProfile[i].AlmostEqualRelative(0.0, AbsoluteError))
                {
                    volumeProfile.RemoveAt(i);
                    priceChain.RemoveAt(i);
                }
                else
                {
                    i++;
                }
            }
            return(gapSR);
        }
        private static SupportAndResistanceValueViewModel Map(SupportAndResistanceValue srValue)
        {
            SupportAndResistanceValueViewModel viewModel = new SupportAndResistanceValueViewModel(srValue.Value.CustomRound(), srValue.Date);

            return(viewModel);
        }
        public SupportAndResistance GetSupportAndResistance(double?currentPriceParam = null, double?percentRangeParam = null)
        {
            double percentRange = currentPriceParam ?? 0.4;
            double currentPrice = percentRangeParam ?? _data.Close.Last();

            Tuple <int, double> highMax = _data.High.MaximumAndIndex();
            Tuple <int, double> lowMin  = _data.Low.MinimumAndIndex();

            double        increment;
            List <double> priceChainResult    = GeneratePriceChain(highMax.Item2, lowMin.Item2, out increment);
            List <double> volumeProfileResult = VolumeAddition(priceChainResult);

            priceChainResult.RemoveAt(priceChainResult.Count - 1);

            List <double> priceChain = priceChainResult.ToList(), volumeProfile = volumeProfileResult.ToList();
            List <SupportAndResistanceValue> srValues = FindGaps(ref volumeProfile, ref priceChain);

            PriceBounds bounds = UpAndDownPrice(highMax.Item2, lowMin.Item2, percentRange, currentPrice);

            List <double> localPrices;
            List <double> localVolume;

            SRpoints(bounds.UpPrice, bounds.DownPrice, priceChain, volumeProfile, increment, SRPointsLocalization.TwoLocal,
                     out localPrices, out localVolume);

            List <double> idenSR = IdenticalVolumeFilter(ref localPrices, ref localVolume);

            double priceRangeStdDev = _data.GetPriceRangeStdDev();
            ////////////////////////////////////
            // SRLocalHighFilter mat lab method
            List <Tuple <int, double> > srPoints = ApplyLocalFilters(localPrices, idenSR, priceRangeStdDev);

            //global max is always resistence, and global min is always support
            if (srPoints.All(i => !i.Item2.Equals(highMax.Item2)))
            {
                srPoints.Add(highMax);
            }
            if (srPoints.All(i => !i.Item2.Equals(lowMin.Item2)))
            {
                srPoints.Add(lowMin);
            }
            ////////////////////////////////////

            CrossOverFilter(ref srPoints);

            ////////////////////////////////////
            // TODO: consider move to FindGaps
            IEnumerable <SupportAndResistanceValue> gaps = PartialGap(priceRangeStdDev);

            srValues.AddRange(gaps);
            ////////////////////////////////////

            srValues.AddRange(srPoints.Select((d, i) =>
            {
                DateTime date = _data.Date[d.Item1];
                SupportAndResistanceValueType type = d.Item2 >= currentPrice
                                        ? SupportAndResistanceValueType.MajorResistance
                                        : SupportAndResistanceValueType.MajorSupport;
                SupportAndResistanceValue srVal = new SupportAndResistanceValue(d.Item2, date, type);
                return(srVal);
            }));

            SupportAndResistance result = new SupportAndResistance(srValues);

            return(result);
        }