public static double CalculateAnnuity( DateTime repaymentPeriodStartDate, DateTime firstInstallmentDate, int numberOfInstallments, int installmentFrequencyPeriod, SimpleUnitOfTime installmentFrequencyUnitOfTime, double ratePercentage, SimpleUnitOfTime rateUnitOfTime, bool isCompound, CalendarBasisKind calendarBasis, double principalAmount, bool adjustFirstInstallment = false) { DateTime d2 = firstInstallmentDate.AddPeriod(installmentFrequencyPeriod * (numberOfInstallments - 1), installmentFrequencyUnitOfTime); double dummyAnnuity = 100; double outstanding = 0; double basis = 0; double interest = 0; DateTime d1; while (d2 > firstInstallmentDate) { d1 = d2.AddPeriod(-installmentFrequencyPeriod, installmentFrequencyUnitOfTime); basis = outstanding + dummyAnnuity; interest = InterestCalculation.CalculateInterest(d2, d1, d1, ratePercentage, rateUnitOfTime.CharLiteral(), isCompound, calendarBasis, basis).Sum(it => it.Interest); outstanding = basis + interest; d2 = d1; } d1 = repaymentPeriodStartDate; if (adjustFirstInstallment) { var prevDate = firstInstallmentDate.AddPeriod(-installmentFrequencyPeriod, installmentFrequencyUnitOfTime); if (prevDate < repaymentPeriodStartDate) { d1 = prevDate; } } basis = outstanding + dummyAnnuity; interest = InterestCalculation.CalculateInterest(d2, d1, d1, ratePercentage, rateUnitOfTime.CharLiteral(), isCompound, calendarBasis, basis).Sum(it => it.Interest); outstanding = basis + interest; return(principalAmount / outstanding * dummyAnnuity); }
private static decimal Yearfrac(DateTime startDate, DateTime endDate, CalendarBasisKind dayCount) { decimal nbDaysInPeriod = (decimal)(endDate - startDate).Days; switch (dayCount) { case (CalendarBasisKind.CalendarAct360): return(nbDaysInPeriod / (decimal)360); case (CalendarBasisKind.CalendarAct365L): case (CalendarBasisKind.CalendarAct365Fixed): return(nbDaysInPeriod / (decimal)365); case (CalendarBasisKind.Calendar30A360): case (CalendarBasisKind.Calendar30E360): decimal result = (endDate.Year - startDate.Year) * 360 + (endDate.Month - startDate.Month) * 30 + (Math.Min(endDate.Day, 30) - Math.Min(startDate.Day, 30)); return(result / 360); default: return(GetActAct(startDate, endDate)); } }
public decimal MonthlyRate() { bool isCompound = false; CalendarBasisKind calendarBasis = CalendarBasisKind.CalendarActActISDA; double yearlyRate = 0; var ir = Conditions.InterestRates.FirstOrDefault(it => it.Kind == InterestRateKinds.RegularInterest); if (ir != null) { isCompound = ir.IsCompound; calendarBasis = ir.CalendarBasis; yearlyRate = Convert.ToDouble(ir.CalculatedRate / 100); } double monthlyRate = yearlyRate / 12; if (isCompound) { monthlyRate = Math.Pow(1 + yearlyRate, 1 / 12) - 1; } return(Convert.ToDecimal(monthlyRate)); }
public override void CalculateOffer(PriceCalculationParameters calculationParameters, OfferPriceCalculation priceCalculator, string feeCurrencyConversionMethod) { var ignore = priceCalculator.CalculatePrice(this, calculationParameters).Result; // isCompound i calendarBasis izvuci tokom CalculatePrice da dodatno opisu Napr bool isCompound = false; CalendarBasisKind calendarBasis = CalendarBasisKind.CalendarActActISDA; double yearlyRate = Convert.ToDouble(Napr) / 100; var ir = Conditions.InterestRates.FirstOrDefault(it => it.Kind == InterestRateKinds.RegularInterest); if (ir != null) { isCompound = ir.IsCompound; calendarBasis = ir.CalendarBasis; yearlyRate = Convert.ToDouble(ir.CalculatedRate); Napr = Convert.ToDecimal(yearlyRate); } var startDate = calculationParameters.RequestDate ?? DateTime.Today; List <InstallmentPlanRow> rows = new List <InstallmentPlanRow>(); List <FeeCondition> rowFeeList = new List <FeeCondition>(); List <FeeCondition> fees = Conditions.Fees; fees = FeeCalculation.PrepareFees(fees, Currency, feeCurrencyConversionMethod); decimal runningAmount = Math.Round(Amount, 2); DateTime runningDate = startDate; if (CalculationDate > DateTime.Today) { CalculationDate = runningDate; } else { runningDate = CalculationDate ?? DateTime.Today; } // SLOBA: Fee scheduling, and scheduling in general has to be improved in advanced calculator. decimal totalFeeAmount = 0; if (fees != null) { List <FeeCondition> feeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.EventTriggered && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); totalFeeAmount = Math.Round(FeeCalculation.CalculateFee(Amount, feeList), 4); } NumberOfInstallments = 1; /* Disbursment */ InstallmentPlanRow rowDisbursement = new InstallmentPlanRow(); rowDisbursement.Date = runningDate; rowDisbursement.Ordinal = 0; rowDisbursement.ActivityKind = ActivityKind.Disbursement; rowDisbursement.Description = "Loan disbursement"; rowDisbursement.Disbursement = Amount; rowDisbursement.StartingBalance = 0; rowDisbursement.OutstandingBalance = Amount; rowDisbursement.PrincipalRepayment = 0; rowDisbursement.InterestRepayment = 0; rowDisbursement.NetCashFlow = Amount - totalFeeAmount; rowDisbursement.Fee = totalFeeAmount; rowDisbursement.YearFrac = 0; rows.Add(rowDisbursement); int i = -1; InstallmentPlanRow rowInterest; var intrStartDate = startDate; runningDate = runningDate.AddMonths(1); while (runningDate <= MaturityDate.Value) { i++; var interest = Math.Round(InterestCalculation.CalculateInterest(intrStartDate, runningDate, runningDate, Convert.ToDouble(yearlyRate), 'Y', isCompound, calendarBasis, Convert.ToDouble(runningAmount)) .Sum(it => it.Interest), 2); rowInterest = new InstallmentPlanRow(); rowInterest.Ordinal = i + 1; rowInterest.Date = runningDate; rowInterest.ActivityKind = ActivityKind.Repayment; rowInterest.Description = "Interest and fee repayment"; rowInterest.InterestRepayment = Convert.ToDecimal(interest); rowInterest.PrincipalRepayment = 0; rowInterest.Annuity = rowInterest.InterestRepayment; rowInterest.StartingBalance = Math.Round(runningAmount, 2); rowInterest.OutstandingBalance = Math.Round(runningAmount, 2); #region Fee calculation if (fees != null) { decimal totalRowFee = 0; rowFeeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.Monthly && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); if (rowFeeList.Count > 0) { totalRowFee += FeeCalculation.CalculateFee(runningAmount, rowFeeList); } if ((i + 1) % 4 == 0) { rowFeeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.Quarterly && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); if (rowFeeList.Count > 0) { totalRowFee += FeeCalculation.CalculateFee(runningAmount, rowFeeList); } } if ((i + 1) % 6 == 0) { rowFeeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.Semiyearly && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); if (rowFeeList.Count > 0) { totalRowFee += FeeCalculation.CalculateFee(runningAmount, rowFeeList); } } if ((i + 1) % 12 == 0) { rowFeeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.Yearly && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); if (rowFeeList.Count > 0) { totalRowFee += FeeCalculation.CalculateFee(runningAmount, rowFeeList); } } rowInterest.Fee = Math.Round(totalRowFee, 4); } #endregion rowInterest.NetCashFlow = rowInterest.Disbursement - rowInterest.PrincipalRepayment - rowInterest.InterestRepayment - rowInterest.Fee - rowInterest.OtherExpenses; rowInterest.YearFrac = Convert.ToDecimal(InterestCalculation.YearFrac(startDate, runningDate)); //, calendarBasis); rows.Add(rowInterest); intrStartDate = runningDate; runningDate = runningDate.AddMonths(1); } i++; rowInterest = new InstallmentPlanRow(); rowInterest.Ordinal = i + 1; rowInterest.Date = runningDate; rowInterest.ActivityKind = ActivityKind.Repayment; rowInterest.Description = "Principal repayment"; rowInterest.InterestRepayment = 0; rowInterest.PrincipalRepayment = Amount; rowInterest.Annuity = Amount; rowInterest.StartingBalance = Amount; rowInterest.OutstandingBalance = 0; #region Fee calculation rowInterest.Fee = 0; #endregion rowInterest.NetCashFlow = rowInterest.Disbursement - rowInterest.PrincipalRepayment - rowInterest.InterestRepayment - rowInterest.Fee - rowInterest.OtherExpenses; rowInterest.YearFrac = Convert.ToDecimal(InterestCalculation.YearFrac(startDate, runningDate)); //, calendarBasis); rows.Add(rowInterest); NumberOfInstallments = 1; // arrangementRequest.InstallmentPlan = rows; CalculateAPR(rows); }
// SLOBA: term and fees parameters are inconsistently extracted from arrangementRequest public void CalculateInstallmentPlan(string feeCurrencyConversionMethod) { int term = Utility.GetMonthsFromPeriod(Term); List <InstallmentPlanRow> rows = new List <InstallmentPlanRow>(); List <FeeCondition> rowFeeList = new List <FeeCondition>(); List <FeeCondition> fees = Conditions.Fees; fees = FeeCalculation.PrepareFees(fees, Currency, feeCurrencyConversionMethod); decimal runningAmount = Math.Round(Amount, 2); DateTime runningDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 0, 0, 0, 0); if (CalculationDate > DateTime.Today) { CalculationDate = runningDate; } else { runningDate = CalculationDate ?? DateTime.Today; } DateTime startDate = runningDate; // SLOBA: Fee scheduling, and scheduling in general has to be improved in advanced calculator. decimal totalFeeAmount = 0; if (fees != null) { List <FeeCondition> feeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.EventTriggered && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); totalFeeAmount = Math.Round(FeeCalculation.CalculateFee(Amount, feeList), 4); } NumberOfInstallments = 1; bool isCompound = false; CalendarBasisKind calendarBasis = CalendarBasisKind.CalendarActActISDA; double yearlyRate = 0; var ir = Conditions.InterestRates.FirstOrDefault(it => it.Kind == InterestRateKinds.RegularInterest); if (ir != null) { isCompound = ir.IsCompound; calendarBasis = ir.CalendarBasis; yearlyRate = Convert.ToDouble(ir.CalculatedRate / 100); } // this is huge simplification. not good double monthlyRate = yearlyRate / 12; if (isCompound) { monthlyRate = Math.Pow(1 + yearlyRate, 1.0000000 / 12.0000000) - 1; } // SLOBA: Logic for calculating cash flow is done in manner that is later hard to extend. Also columns are hardcoded. // SLOBA: This is totally ok for basic calculator though /* Disbursment */ InstallmentPlanRow rowDisbursement = new InstallmentPlanRow(); rowDisbursement.Date = runningDate; rowDisbursement.Ordinal = 0; rowDisbursement.ActivityKind = ActivityKind.Disbursement; rowDisbursement.Description = "Loan disbursement"; rowDisbursement.Disbursement = Amount; rowDisbursement.StartingBalance = 0; rowDisbursement.OutstandingBalance = Amount; rowDisbursement.PrincipalRepayment = 0; rowDisbursement.InterestRepayment = 0; rowDisbursement.NetCashFlow = Amount - totalFeeAmount; rowDisbursement.Fee = totalFeeAmount; rowDisbursement.YearFrac = 0; rows.Add(rowDisbursement); for (var i = 0; i < term; i++) { decimal interest = Math.Round(runningAmount * Convert.ToDecimal(monthlyRate), 2); decimal principal = Math.Round(Annuity - interest, 2); if (i == term - 1) { // last ... corection for decimal places principal = Math.Round(runningAmount, 2); interest = Math.Round(Annuity - principal, 2); } InstallmentPlanRow rowInterest = new InstallmentPlanRow(); rowInterest.Ordinal = i + 1; runningDate = runningDate.AddMonths(1); rowInterest.Date = runningDate; rowInterest.ActivityKind = ActivityKind.Repayment; rowInterest.Description = "Anuity repayment"; rowInterest.InterestRepayment = interest; rowInterest.PrincipalRepayment = principal; rowInterest.Annuity = Annuity; rowInterest.StartingBalance = Math.Round(runningAmount, 2); runningAmount = (runningAmount - principal); rowInterest.OutstandingBalance = Math.Round(runningAmount, 2); #region Fee calculation if (fees != null) { decimal totalRowFee = 0; rowFeeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.Monthly && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); if (rowFeeList.Count > 0) { totalRowFee += FeeCalculation.CalculateFee(runningAmount, rowFeeList); } if ((i + 1) % 4 == 0) { rowFeeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.Quarterly && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); if (rowFeeList.Count > 0) { totalRowFee += FeeCalculation.CalculateFee(runningAmount, rowFeeList); } } if ((i + 1) % 6 == 0) { rowFeeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.Semiyearly && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); if (rowFeeList.Count > 0) { totalRowFee += FeeCalculation.CalculateFee(runningAmount, rowFeeList); } } if ((i + 1) % 12 == 0) { rowFeeList = fees.FindAll(f => f.Frequency == FeeConditionFrequency.Yearly && f.EffectiveDate <= DateTime.Today && f.Currencies.Contains(Currency)); if (rowFeeList.Count > 0) { totalRowFee += FeeCalculation.CalculateFee(runningAmount, rowFeeList); } } rowInterest.Fee = Math.Round(totalRowFee, 4); } #endregion rowInterest.NetCashFlow = rowInterest.Disbursement - rowInterest.PrincipalRepayment - rowInterest.InterestRepayment - rowInterest.Fee - rowInterest.OtherExpenses; rowInterest.YearFrac = Yearfrac(startDate, runningDate, calendarBasis); rows.Add(rowInterest); NumberOfInstallments += 1; } // arrangementRequest.InstallmentPlan = rows; CalculateAPR(rows); }
public static InterestCalculationResult CalculateInterest( DateTime date1, DateTime date2, DateTime date3, double ratePercentage, char rateUnitOfTime = 'Y', bool isCompound = true, CalendarBasisKind calendarBasis = CalendarBasisKind.CalendarActActISDA, double amount = 1, double?calaculationPrecision = null, bool useAnticipativeMethod = false // nije kao u PUB, vec znaci da se procenat primenjuje na osnovicu kakva ce biti na date2, za anticipativ kao u PUB, samo obrnuti datume, tako da je date1 > date2 ) { // TODO: Throw not implemented for unsupported methods InterestCalculationResult t = new InterestCalculationResult(); if (date3 == null) { date3 = date2; } if (rateUnitOfTime == 'G') { rateUnitOfTime = 'Y'; } int y1, M1, d1, y2, M2, d2, zeroyear = ZeroDate.Year; double s1, s2, daysincalendar, interestdays, BaseAmount = 0, interest = 0, ac; DateTime fd1, fd2; if (useAnticipativeMethod == false) { ac = 1; } else { ac = -1; } y1 = DatePart(Year, date1); M1 = DatePart(Month, date1); d1 = DatePart(Day, date1); y2 = DatePart(Year, date2); M2 = DatePart(Month, date2); d2 = DatePart(Day, date2); fd1 = DateAdd(Day, d1 - 1, DateAdd(Month, M1 - 1, DateAdd(Year, y1 - zeroyear, ZeroDate))); fd2 = DateAdd(Day, d2 - 1, DateAdd(Month, M2 - 1, DateAdd(Year, y2 - zeroyear, ZeroDate))); s1 = (date1 - fd1).TotalDays; s2 = (date2 - fd2).TotalDays; if (calendarBasis == CalendarBasisKind.Calendar30U360) { if ((IsEndOfFebruary(fd1) == true) && (IsEndOfFebruary(fd2) == true)) { d2 = 30; s2 = 0; } if (IsEndOfFebruary(fd1) == true) { d1 = 30; s1 = 0; } if (d2 == 31 && (d1 == 30 || d1 == 31)) { d2 = 30; } if (d1 == 31) { d1 = 30; } } else if (calendarBasis == CalendarBasisKind.Calendar30E360) { if (d1 == 31) { d1 = 30; } if (d2 == 31) { d2 = 30; } } else if (calendarBasis == CalendarBasisKind.Calendar30E360ISDA) { if (IsEndOfMonth(fd1) == true) { d1 = 30; if (IsEndOfFebruary(fd1) == true) { s1 = 0; } } if (IsEndOfMonth(fd2) == true) { if (!(IsEndOfFebruary(fd2) == true && date2 == date3)) // isLastPeriod = 1 { d2 = 30; if (IsEndOfFebruary(fd2) == true) { s2 = 0; } } } } else if (calendarBasis == CalendarBasisKind.Calendar30A360) // CHECK "30E+/360" { if (d1 == 31) { d1 = 30; } if (d2 == 31) { fd2 = DateAdd(Day, 1, fd2); y2 = fd2.Year; M2 = fd2.Month; d2 = 1; } } double perc, fract, d13, freq; char ut; DateTime dt; CalendarBasisKind[] actualMethods = { CalendarBasisKind.CalendarAct360, CalendarBasisKind.CalendarAct364, CalendarBasisKind.CalendarAct365Fixed, CalendarBasisKind.CalendarAct365L, CalendarBasisKind.CalendarActActAFB, CalendarBasisKind.CalendarActActICMA, CalendarBasisKind.CalendarActActISDA }; bool is30360 = (calendarBasis == CalendarBasisKind.Calendar30A360) || (calendarBasis == CalendarBasisKind.Calendar30E360) || (calendarBasis == CalendarBasisKind.Calendar30E360ISDA) || (calendarBasis == CalendarBasisKind.Calendar30U360); if (is30360) //CalendarBasis like '30%/360%' { if (rateUnitOfTime == 'Y') { daysincalendar = 360; } else if (rateUnitOfTime == 'Q') { daysincalendar = 90; } else if (rateUnitOfTime == 'M') { daysincalendar = 30; } else { daysincalendar = 1; } interestdays = (360 * (y2 - y1) + 30 * (M2 - M1) + (d2 - d1)) + (s2 - s1); t.Add(new DateSegment() { RowNum = 1, DateFrom = date1, DateTo = date2, DaysInPeriod = interestdays, DaysInCalendar = daysincalendar, Rate = ratePercentage, RateUnitOfTime = rateUnitOfTime, RateDays = daysincalendar, BaseAmount = amount, Interest = 0, AccumulatedBalance = amount }); //insert into t(DateFrom, DateTo, InterestDays, DaysInCalendar, BaseAmount, Interest) //values(date1, date2, cast(date1 as float), cast(date2 as float), cast(fd1 as float), cast(fd2 as float)) //insert into t(DateFrom, DateTo, InterestDays, DaysInCalendar, BaseAmount, Interest) //values(fd1, fd2, cast(date1 as float), cast(date2 as float), cast(fd1 as float), cast(fd2 as float)) } else if (calendarBasis == CalendarBasisKind.CalendarAct365Fixed || calendarBasis == CalendarBasisKind.CalendarAct360) //CalendarBasis in ('Actual/365', 'Actual/360') { if (calendarBasis == CalendarBasisKind.CalendarAct365Fixed) { daysincalendar = 365; } else { daysincalendar = 360; } fract = 1; ut = 'Y'; if (rateUnitOfTime == 'Q') { fract = 4; } else if (rateUnitOfTime == 'M') { fract = 12; } else if (rateUnitOfTime == 'D') { daysincalendar = 1; fract = 1; ut = 'D'; } // pretvaranje stope - videti sa UseAnticipativeMethod if (isCompound == true) { perc = (Math.Pow(1 + ratePercentage / 100 * ac, fract) - 1) * 100; } else { perc = ratePercentage * fract; } interestdays = DateDiff(Day, fd1, fd2) + (s2 - s1); t.Add(new DateSegment() { RowNum = 1, DateFrom = date1, DateTo = date2, DaysInPeriod = interestdays, DaysInCalendar = daysincalendar, Rate = perc, RateUnitOfTime = ut, RateDays = daysincalendar, BaseAmount = amount, Interest = 0, AccumulatedBalance = amount }); } else if (calendarBasis == CalendarBasisKind.CalendarAct365L) { d13 = DateDiff(Day, date1, date3); // + (s3 - s1) freq = Math.Round(365 / d13, 6); daysincalendar = 365; if (IsLeapYear(date3) == true && date3.Month >= 3) { daysincalendar = 366; } else if (Math.Abs(freq) > 1 && IsLeapYear(date3) == true) { daysincalendar = 366; } else if (Math.Abs(freq) <= 1) { if (date1.Month <= 2 && IsEndOfFebruary(date1) == false) //(dt.Month <= 2 && IsEndOfFebruary(date1) == false) { dt = date1; } else { dt = DateAdd(Year, 1, date1); } while (dt <= date3) { if (IsLeapYear(dt) == true) { daysincalendar = 366; break; } dt = DateAdd(Year, 1, dt); } } fract = 1; ut = 'Y'; if (rateUnitOfTime == 'Q') { fract = 4; } else if (rateUnitOfTime == 'M') { fract = 12; } else if (rateUnitOfTime == 'D') { fract = DateDiff(Day, fd1, DateAdd(Year, 1, fd1)); } // pretvaranje stope - videti sa UseAnticipativeMethod if (isCompound == true) { perc = (Math.Pow(1 + ratePercentage / 100 * ac, fract) - 1) * 100; } else { perc = ratePercentage * fract; } interestdays = DateDiff(Day, fd1, fd2) + (s2 - s1); t.Add(new DateSegment() { RowNum = 1, DateFrom = date1, DateTo = date2, DaysInPeriod = interestdays, DaysInCalendar = daysincalendar, Rate = perc, RateUnitOfTime = ut, RateDays = daysincalendar, BaseAmount = amount, Interest = 0, AccumulatedBalance = amount }); } else if (calendarBasis == CalendarBasisKind.CalendarActActICMA) { d13 = DateDiff(Day, date1, date3); // + (s3 - s1) freq = Math.Round(365 / d13, 6); daysincalendar = Math.Round(freq * d13, 0); fract = 1; ut = 'Y'; if (rateUnitOfTime == 'Q') { fract = 4; } else if (rateUnitOfTime == 'M') { fract = 12; } else if (rateUnitOfTime == 'D') { fract = DateDiff(Day, fd1, DateAdd(Year, 1, fd1)); } // pretvaranje stope - videti sa UseAnticipativeMethod if (isCompound == true) { perc = (Math.Pow(1 + ratePercentage / 100 * ac, fract) - 1) * 100; } else { perc = ratePercentage * fract; } interestdays = DateDiff(Day, fd1, fd2) + (s2 - s1); t.Add(new DateSegment() { RowNum = 1, DateFrom = date1, DateTo = date2, DaysInPeriod = interestdays, DaysInCalendar = d13, Rate = perc, RateUnitOfTime = ut, RateDays = daysincalendar, BaseAmount = amount, Interest = 0, AccumulatedBalance = amount }); } else if (actualMethods.Contains(calendarBasis))//CalendarBasis like 'Actual%' { if (rateUnitOfTime == 'Y') { foreach (DateSegment item in SplitToYearlySegments(date1, date2, rateUnitOfTime)) { t.Add(new DateSegment() { RowNum = item.RowNum, DateFrom = item.DateFrom, DateTo = item.DateTo, DaysInPeriod = item.DaysInPeriod, DaysInCalendar = item.DaysInCalendar, Rate = ratePercentage, RateUnitOfTime = rateUnitOfTime, RateDays = item.RateDays, BaseAmount = amount, Interest = 0, AccumulatedBalance = amount }); } } else //if (RateUnitOfTime == 'Q' || RateUnitOfTime == 'M') -- if RateUnitOfTime in ('Q', 'M') { foreach (DateSegment item in SplitToMonthlySegments(date1, date2, rateUnitOfTime)) { t.Add(new DateSegment() { RowNum = item.RowNum, DateFrom = item.DateFrom, DateTo = item.DateTo, DaysInPeriod = item.DaysInPeriod, DaysInCalendar = item.DaysInCalendar, Rate = ratePercentage, RateUnitOfTime = rateUnitOfTime, RateDays = item.RateDays, BaseAmount = amount, Interest = 0, AccumulatedBalance = amount }); } } } DateTime?dat = null; int sgn; if (date1 > date2) { sgn = -1; } else { sgn = 1; } if (isCompound == false) { double factor = (from it in t select(it.DaysInPeriod / it.RateDays * ratePercentage / 100)) .Sum(); double interestCoefficientBase = (Math.Pow((factor * ac + sgn), sgn * ac) * sgn - 1); interest = amount * interestCoefficientBase; if (factor != 0) { Parallel.ForEach(t, currenItem => { double interestCoefficient = (currenItem.DaysInPeriod / currenItem.RateDays * currenItem.Rate / 100) / factor * interestCoefficientBase; currenItem.InterestCoefficient = interestCoefficient; //currenItem.Interest = interestCoefficient * amount; currenItem.Interest = (currenItem.DaysInPeriod / currenItem.RateDays * currenItem.Rate / 100) / factor * interest; }); } for (int i = 0; i < t.Count; i++) { BaseAmount = t[i].AccumulatedBalance = (dat == null ? t[i].AccumulatedBalance : BaseAmount) + t[i].Interest; dat = t[i].DateFrom; } } else { for (int i = 0; i < t.Count; i++) { BaseAmount = (dat == null ? t[i].BaseAmount : BaseAmount + interest); dat = t[i].DateFrom; double interestCoefficient = (Math.Pow((t[i].Rate / 100 * ac + 1), t[i].DaysInPeriod * ac / t[i].RateDays) - 1); t[i].InterestCoefficient = interestCoefficient; interest = t[i].Interest = BaseAmount * interestCoefficient; t[i].BaseAmount = BaseAmount; t[i].AccumulatedBalance = BaseAmount + interest; } } return(t); }