public decimal CalculateYTDPerformance(MonthlyPerformance current, MonthlyPerformance prior)
        {
            var currentPerformance     = current.Performance.HasValue ? current.Performance.Value : 0;
            var priorYTDNetPerformance = prior.YTDNetPerformance;

            return(currentPerformance + priorYTDNetPerformance);
        }
        public decimal CalculateITD(MonthlyPerformance current, MonthlyPerformance prior)
        {
            var convertedPriorYTD   = prior.ITD + 1;
            var convertedCurrentMTD = current.MTD.HasValue ? current.MTD.Value + 1 : 1;

            // return (convertedPriorYTD * convertedCurrentMTD) - 1;
            return(Math.Round((convertedPriorYTD * convertedCurrentMTD) - 1, 16));
        }
        public object CalculateMonthlyPerformance(List <MonthlyPerformance> obj)
        {
            try
            {
                var sorted = obj.OrderBy(x => x.PerformanceDate).ThenBy(x => x.RowId).ToList();

                var groupedByPortfolio = sorted.GroupBy(x => x.PortFolio).Select(x => new
                {
                    Portfolio  = x.Key,
                    YearlyData = x.ToList().GroupBy(y => y.PerformanceDate.Year)
                }).ToList();

                // var groupedByYear = sorted.GroupBy(x => x.PerformanceDate.Year).ToList();

                MonthlyPerformance priorData             = null;
                MonthlyPerformance priorDataForInception = priorData;

                decimal newDecimalValue = 0;

                Dictionary <int, int> quarterCount = new Dictionary <int, int>();
                InitializeQuarterDictionary(quarterCount);

                foreach (var portfolio in groupedByPortfolio)
                {
                    foreach (var group in portfolio.YearlyData)
                    {
                        foreach (var item in group)
                        {
                            if (item.MonthEndNav.HasValue)
                            {
                                if (priorData != null)
                                {
                                }
                            }

                            if (item.MTD.HasValue)
                            {
                                if (priorData != null)
                                {
                                    if (CheckForBeginningOfQuarter(item.PerformanceDate) &&
                                        quarterCount[item.PerformanceDate.Month] == 0)
                                    {
                                        // Beginning of quarter, hence value will be the same as MTD.
                                        newDecimalValue = item.MTD.HasValue ? item.MTD.Value : 0;

                                        if (CheckForChanges(item.QTD, newDecimalValue))
                                        {
                                            item.Modified = true;
                                        }

                                        item.QTD = newDecimalValue;
                                        quarterCount[item.PerformanceDate.Month] += 1;
                                    }
                                    else
                                    {
                                        if (CheckForBeginningOfQuarter(item.PerformanceDate))
                                        {
                                            quarterCount[item.PerformanceDate.Month] += 1;
                                        }

                                        // For QTD, determine the month offset of this quarter. If it is the beginning of the quarter for e.g (April for Q2), value will remain the same. Otherwise, calculated value will depend on the previous result.
                                        if (IfDatesLieInTheSameQuarter(priorData.PerformanceDate, item.PerformanceDate))
                                        {
                                            newDecimalValue = CalculateQTD(item, priorData);
                                        }
                                        else
                                        {
                                            newDecimalValue = item.MTD.HasValue ? item.MTD.Value : 0;
                                        }

                                        if (CheckForChanges(item.QTD, newDecimalValue))
                                        {
                                            item.Modified = true;
                                        }

                                        item.QTD = newDecimalValue;
                                    }
                                }
                                else
                                {
                                    newDecimalValue = item.MTD.HasValue ? item.MTD.Value : 0;
                                    if (CheckForChanges(item.QTD, newDecimalValue))
                                    {
                                        item.Modified = true;
                                    }

                                    if (CheckForBeginningOfQuarter(item.PerformanceDate))
                                    {
                                        quarterCount[item.PerformanceDate.Month] += 1;
                                    }

                                    item.QTD = newDecimalValue;
                                }

                                if (priorData != null)
                                {
                                    // As the data is grouped by year, so for the first iteration, value will remain the same. Otherwise, calculated value will depend on the previous result.
                                    newDecimalValue = CalculateYTD(item, priorData);
                                    if (CheckForChanges(item.YTD, newDecimalValue))
                                    {
                                        item.Modified = true;
                                    }

                                    item.YTD = newDecimalValue;
                                }
                                else
                                {
                                    newDecimalValue = item.MTD.HasValue ? item.MTD.Value : 0;
                                    if (CheckForChanges(item.YTD, newDecimalValue))
                                    {
                                        item.Modified = true;
                                    }

                                    item.YTD = newDecimalValue;
                                }

                                if (priorDataForInception != null)
                                {
                                    // For ITD, value will always be calculated based on the previous result.
                                    newDecimalValue = CalculateITD(item, priorDataForInception);
                                    if (CheckForChanges(item.ITD, newDecimalValue))
                                    {
                                        item.Modified = true;
                                    }

                                    item.ITD = newDecimalValue;
                                }
                                else
                                {
                                    newDecimalValue = item.MTD.HasValue ? item.MTD.Value : 0;
                                    if (CheckForChanges(item.ITD, newDecimalValue))
                                    {
                                        item.Modified = true;
                                    }

                                    item.ITD = newDecimalValue;
                                }
                            }

                            if (item.Performance.HasValue)
                            {
                                if (priorData != null)
                                {
                                    // For YTD, determine the month offset of this year. If it is the beginning of the year for e.g. (January), value will remain the same. Otherwise, calculated value will depend on the previous result.
                                    newDecimalValue = CalculateYTDPerformance(item, priorData);
                                    if (CheckForChanges(item.YTDNetPerformance, newDecimalValue))
                                    {
                                        item.Modified = true;
                                    }

                                    item.YTDNetPerformance = newDecimalValue;
                                }
                                else
                                {
                                    newDecimalValue = item.Performance.HasValue ? item.Performance.Value : 0;
                                    if (CheckForChanges(item.YTDNetPerformance, newDecimalValue))
                                    {
                                        item.Modified = true;
                                    }

                                    item.YTDNetPerformance = newDecimalValue;
                                }
                            }

                            priorData             = item;
                            priorDataForInception = item;

                            if (!CheckForBeginningOfQuarter(item.PerformanceDate))
                            {
                                ResetQuarterDictionary(quarterCount);
                            }
                        }

                        priorData = null;
                        ResetQuarterDictionary(quarterCount);
                    }

                    ResetQuarterDictionary(quarterCount);
                    priorData             = null;
                    priorDataForInception = null;
                }

                // return Utils.Wrap(true, groupedByYear.SelectMany(x => x.Select(y => y).ToList()), HttpStatusCode.OK, "Performance calculated successfully");
                return(Utils.Wrap(true, sorted, HttpStatusCode.OK, "Performance calculated successfully"));
            }
            catch
            {
                return(Utils.Wrap(false, null, HttpStatusCode.InternalServerError,
                                  "An error occured during calculation"));
            }
        }