private static decimal CalculateFirstInstallmentInterest(Installment installment, IScheduleConfiguration configuration) { var daysInPeriod = configuration.PeriodPolicy.GetNumberOfDays(installment, configuration.DateShiftPolicy); var daysInYear = configuration.YearPolicy.GetNumberOfDays(installment.ExpectedDate); var interest = installment.OLB * configuration.InterestRate / 100 * daysInPeriod / daysInYear; //if schedule is flat if (configuration.CalculationPolicy.GetType() == typeof(FlatInstallmentCalculationPolicy)) { var numberOfPeriods = (decimal) (configuration.PeriodPolicy.GetNumberOfPeriodsInYear( configuration.PreferredFirstInstallmentDate, configuration.YearPolicy)); interest = configuration.Amount * configuration.InterestRate / numberOfPeriods / 100; if (configuration.ChargeActualInterestForFirstInstallment) { var nextDate = configuration.PeriodPolicy.GetNextDate(configuration.StartDate); var numerator = (installment.ExpectedDate - configuration.StartDate).Days; var denominator = (nextDate - configuration.StartDate).Days; interest = interest * numerator / denominator; } } return(configuration.RoundingPolicy.Round(interest.Value)); }
public void Calculate(Installment installment, IScheduleConfiguration configuration) { var annuity = configuration.RoundingPolicy.Round(FindAnnuity(configuration)); installment.InterestsRepayment = CalculateInterest(installment, configuration, installment.OLB.Value); installment.CapitalRepayment = annuity - installment.InterestsRepayment; }
private static IInstallment BuildNext(IInstallment previous, IScheduleConfiguration configuration) { if (previous == null) { throw new ArgumentException("Previous installment cannot be null."); } if (previous.Number == configuration.NumberOfInstallments) { return(null); } var installment = new Installment { Number = previous.Number + 1, StartDate = previous.EndDate, EndDate = configuration.PeriodPolicy.GetNextDate(previous.EndDate), Olb = previous.Olb - previous.Principal, }; if (configuration.GracePeriod < installment.Number) { configuration.CalculationPolicy.Calculate(installment, configuration); } return(installment); }
public void Calculate(IInstallment installment, IScheduleConfiguration configuration) { var annuity = configuration.RoundingPolicy.Round(FindAnnuity(configuration)); installment.Interest = CalculateInterest(installment, configuration, installment.Olb); installment.Principal = annuity - installment.Interest; }
public List <IInstallment> BuildSchedule(IScheduleConfiguration configuration) { if (configuration.PeriodPolicy == null) { throw new ArgumentException("Period policy cannot be null."); } if (configuration.YearPolicy == null) { throw new ArgumentException("Year policy cannot be null."); } if (configuration.RoundingPolicy == null) { throw new ArgumentException("Rounding policy cannot be null."); } if (configuration.CalculationPolicy == null) { throw new ArgumentException("Installment calculation policy cannot be null."); } if (configuration.AdjustmentPolicy == null) { throw new ArgumentException("Adjustment policy cannot be null."); } if (configuration.DateShiftPolicy == null) { throw new ArgumentException("Date shift policy cannot be null."); } if (configuration.GracePeriod >= configuration.NumberOfInstallments) { throw new ArgumentException("Grace period should be less than the number of installments."); } var installment = BuildFirst(configuration); var result = new List <IInstallment> { installment }; while ((installment = BuildNext(installment, configuration)) != null) { result.Add(installment); } configuration.AdjustmentPolicy.Adjust(result, configuration); // CalculationPolicy interest during grace period if (configuration.ChargeInterestDuringGracePeriod) { for (var i = 0; i < configuration.GracePeriod; i++) { result[i].Interest = CalculateInterest(result[i], configuration); } } // Initialize RepaymentDate's foreach (var i in result) { i.RepaymentDate = configuration.DateShiftPolicy.ShiftDate(i.EndDate); } return(result); }
public void SetUp() { _configuration = new ScheduleConfiguration { Amount = 3000, }; }
public void Calculate(IInstallment installment, IScheduleConfiguration configuration) { var number = configuration.NumberOfInstallments - configuration.GracePeriod; installment.Principal = configuration.RoundingPolicy.Round(configuration.Amount / number); installment.Interest = CalculateInterest(installment, configuration, installment.Olb); }
public void Calculate(Installment installment, IScheduleConfiguration configuration) { var number = configuration.NumberOfInstallments - configuration.GracePeriod; installment.CapitalRepayment = configuration.RoundingPolicy.Round(configuration.Amount / number); installment.InterestsRepayment = CalculateInterest(installment, configuration, installment.OLB.Value); }
protected decimal CalculateInterest(IInstallment installment, IScheduleConfiguration configuration, decimal amount) { var daysInPeriod = configuration.PeriodPolicy.GetNumberOfDays(installment.EndDate); var daysInYear = configuration.YearPolicy.GetNumberOfDays(installment.EndDate); var interest = amount * configuration.InterestRate / 100 * daysInPeriod / daysInYear; return configuration.RoundingPolicy.Round(interest); }
private static Installment BuildNext(Installment previous, IScheduleConfiguration configuration) { if (previous == null) { throw new ArgumentException("Previous installment cannot be null."); } if (previous.Number == configuration.NumberOfInstallments) { return(null); } var installment = new Installment { Number = previous.Number + 1, StartDate = previous.ExpectedDate, ExpectedDate = configuration.PeriodPolicy.GetNextDate(previous.ExpectedDate), InterestsRepayment = 0m, CapitalRepayment = 0m, OLB = previous.OLB - previous.CapitalRepayment, FeesUnpaid = 0 }; if (configuration.GracePeriod < installment.Number) { configuration.CalculationPolicy.Calculate(installment, configuration); } return(installment); }
/// <nodoc /> public ScheduleConfiguration(IScheduleConfiguration template, PathRemapper pathRemapper) { Contract.Assume(template != null); MaxProcesses = template.MaxProcesses; MaxLightProcesses = template.MaxLightProcesses; MaxIO = template.MaxIO; MaxChooseWorkerCpu = template.MaxChooseWorkerCpu; MaxChooseWorkerCacheLookup = template.MaxChooseWorkerCacheLookup; MaxCacheLookup = template.MaxCacheLookup; MaxMaterialize = template.MaxMaterialize; EnvironmentFingerprint = template.EnvironmentFingerprint; DisableProcessRetryOnResourceExhaustion = template.DisableProcessRetryOnResourceExhaustion; StopOnFirstError = template.StopOnFirstError; LowPriority = template.LowPriority; EnableLazyOutputMaterialization = template.EnableLazyOutputMaterialization; ForceSkipDependencies = template.ForceSkipDependencies; UseHistoricalPerformanceInfo = template.UseHistoricalPerformanceInfo; RequiredOutputMaterialization = template.RequiredOutputMaterialization; TreatDirectoryAsAbsentFileOnHashingInputContent = template.TreatDirectoryAsAbsentFileOnHashingInputContent; MaximumRamUtilizationPercentage = template.MaximumRamUtilizationPercentage; MinimumTotalAvailableRamMb = template.MinimumTotalAvailableRamMb; AllowCopySymlink = template.AllowCopySymlink; AdaptiveIO = template.AdaptiveIO; ReuseOutputsOnDisk = template.ReuseOutputsOnDisk; UseHistoricalRamUsageInfo = template.UseHistoricalRamUsageInfo; VerifyCacheLookupPin = template.VerifyCacheLookupPin; PinCachedOutputs = template.PinCachedOutputs; CanonicalizeFilterOutputs = template.CanonicalizeFilterOutputs; ForceUseEngineInfoFromCache = template.ForceUseEngineInfoFromCache; UnsafeDisableGraphPostValidation = template.UnsafeDisableGraphPostValidation; ProcessRetries = template.ProcessRetries; UnsafeLazySymlinkCreation = template.UnsafeLazySymlinkCreation; UnexpectedSymlinkAccessReportingMode = template.UnexpectedSymlinkAccessReportingMode; StoreOutputsToCache = template.StoreOutputsToCache; EnableLazyWriteFileMaterialization = template.EnableLazyWriteFileMaterialization; WriteIpcOutput = template.WriteIpcOutput; OutputMaterializationExclusionRoots = pathRemapper.Remap(template.OutputMaterializationExclusionRoots); IncrementalScheduling = template.IncrementalScheduling; GraphAgnosticIncrementalScheduling = template.GraphAgnosticIncrementalScheduling; ComputePipStaticFingerprints = template.ComputePipStaticFingerprints; LogPipStaticFingerprintTexts = template.LogPipStaticFingerprintTexts; CreateHandleWithSequentialScanOnHashingOutputFiles = template.CreateHandleWithSequentialScanOnHashingOutputFiles; OutputFileExtensionsForSequentialScanHandleOnHashing = new List <PathAtom>(template.OutputFileExtensionsForSequentialScanHandleOnHashing.Select(pathRemapper.Remap)); TelemetryTagPrefix = template.TelemetryTagPrefix; MasterCpuMultiplier = template.MasterCpuMultiplier; MasterCacheLookupMultiplier = template.MasterCacheLookupMultiplier; SkipHashSourceFile = template.SkipHashSourceFile; }
public void Adjust(List<Installment> schedule, IScheduleConfiguration configuration) { schedule[configuration.GracePeriod].CapitalRepayment += GetAdjustment(schedule, configuration); for (var i = configuration.GracePeriod + 1; i < schedule.Count; i++) { schedule[i].OLB = schedule[i - 1].OLB - schedule[i - 1].CapitalRepayment; } }
public void Adjust(List<IInstallment> schedule, IScheduleConfiguration configuration) { schedule[configuration.GracePeriod].Principal += GetAdjustment(schedule, configuration); for (var i = configuration.GracePeriod + 1; i < schedule.Count; i++) { schedule[i].Olb = schedule[i - 1].Olb - schedule[i - 1].Principal; } }
public ChooseWorkerCacheLookup( LoggingContext loggingContext, IScheduleConfiguration scheduleConfig, IReadOnlyList <Worker> workers, IPipQueue pipQueue) : base(loggingContext, workers, pipQueue, DispatcherKind.ChooseWorkerCacheLookup, scheduleConfig.MaxChooseWorkerCacheLookup, scheduleConfig.ModuleAffinityEnabled()) { m_workerBalancedLoadFactors = ReadOnlyArray <double> .FromWithoutCopy(0.5, 1, 2, 3); }
public void Adjust(List <IInstallment> schedule, IScheduleConfiguration configuration) { schedule[configuration.GracePeriod].Principal += GetAdjustment(schedule, configuration); for (var i = configuration.GracePeriod + 1; i < schedule.Count; i++) { schedule[i].Olb = schedule[i - 1].Olb - schedule[i - 1].Principal; } }
public void Adjust(List <Installment> schedule, IScheduleConfiguration configuration) { schedule[configuration.GracePeriod].CapitalRepayment += GetAdjustment(schedule, configuration); for (var i = configuration.GracePeriod + 1; i < schedule.Count; i++) { schedule[i].OLB = schedule[i - 1].OLB - schedule[i - 1].CapitalRepayment; } }
public List<Installment> BuildTranche(IEnumerable<Installment> schedule, IScheduleBuilder scheduleBuilder, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var rhc = (IScheduleConfiguration)scheduleConfiguration.Clone(); rhc.Amount = trancheConfiguration.Amount; rhc.NumberOfInstallments = trancheConfiguration.NumberOfInstallments; rhc.GracePeriod = trancheConfiguration.GracePeriod; rhc.InterestRate = trancheConfiguration.InterestRate; rhc.StartDate = trancheConfiguration.StartDate; rhc.PreferredFirstInstallmentDate = trancheConfiguration.PreferredFirstInstallmentDate; var lhc = (IScheduleConfiguration)rhc.Clone(); lhc.Amount = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); if (!trancheConfiguration.ApplyNewInterestRateToOlb) { lhc.InterestRate = scheduleConfiguration.InterestRate; } var lhs = scheduleBuilder.BuildSchedule(lhc); var rhs = scheduleBuilder.BuildSchedule(rhc); var result = new List<Installment>(); // Merge the two schedules var max = Math.Max(lhs.Count, rhs.Count); for (var i = 0; i < max; i++) { var lhi = i >= lhs.Count ? null : lhs[i]; var rhi = i >= rhs.Count ? null : rhs[i]; Installment installment; if (lhi == null) { installment = rhi; } else if (rhi == null) { installment = lhi; } else { installment = new Installment { Number = lhi.Number, StartDate = lhi.StartDate, ExpectedDate = lhi.ExpectedDate, //RepaymentDate = lhi.RepaymentDate, CapitalRepayment = lhi.CapitalRepayment + rhi.CapitalRepayment, InterestsRepayment = lhi.InterestsRepayment + rhi.InterestsRepayment, OLB = lhi.OLB + rhi.OLB, }; } result.Add(installment); } result[0].InterestsRepayment += GetExtraInterest(schedule, scheduleConfiguration, trancheConfiguration); return result; }
public void Adjust(List <Installment> schedule, IScheduleConfiguration configuration) { schedule[schedule.Count - 1].CapitalRepayment += GetAdjustment(schedule, configuration); if (configuration.CalculationPolicy.GetType() == typeof(FlatInstallmentCalculationPolicy)) { schedule[schedule.Count - 1].InterestsRepayment += GetAdjustmentInterestRepayment(schedule, configuration); } }
/// <summary> /// Constructor /// </summary> public LocalWorker(IScheduleConfiguration scheduleConfig, IDetoursEventListener detoursListener) : base(workerId: 0, name: "#0 (Local)") { TotalProcessSlots = scheduleConfig.MaxProcesses; TotalCacheLookupSlots = scheduleConfig.MaxCacheLookup; TotalMaterializeInputSlots = scheduleConfig.MaxMaterialize; Start(); m_detoursListener = detoursListener; }
public ChooseWorkerCacheLookup( LoggingContext loggingContext, IScheduleConfiguration scheduleConfig, bool distributeCacheLookups, IReadOnlyList <Worker> workers, IPipQueue pipQueue) : base(loggingContext, workers, pipQueue, DispatcherKind.ChooseWorkerCacheLookup, scheduleConfig.MaxChooseWorkerCacheLookup, scheduleConfig.ModuleAffinityEnabled()) { m_distributeCacheLookups = distributeCacheLookups; }
private decimal GetExtraInterest(IEnumerable<Installment> schedule, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var days = (trancheConfiguration.StartDate - GetLastEndDate(schedule, trancheConfiguration)).Days; var daysInYear = scheduleConfiguration.YearPolicy.GetNumberOfDays(trancheConfiguration.StartDate); var olb = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); var interest = olb * scheduleConfiguration.InterestRate / 100 * days / daysInYear; return scheduleConfiguration.RoundingPolicy.Round(interest); }
private decimal GetExtraInterest(IEnumerable <Installment> schedule, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var days = (trancheConfiguration.StartDate - GetLastEndDate(schedule, trancheConfiguration)).Days; var daysInYear = scheduleConfiguration.YearPolicy.GetNumberOfDays(trancheConfiguration.StartDate); var olb = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); var interest = olb * scheduleConfiguration.InterestRate / 100 * days / daysInYear; return(scheduleConfiguration.RoundingPolicy.Round(interest)); }
/// <summary> /// Constructor /// </summary> public LocalWorker(IScheduleConfiguration scheduleConfig, IPipQueue pipQueue, IDetoursEventListener detoursListener, PipExecutionContext context) : base(workerId: 0, name: "#0 (Local)", context: context) { TotalProcessSlots = scheduleConfig.EffectiveMaxProcesses; TotalCacheLookupSlots = scheduleConfig.MaxCacheLookup; TotalLightSlots = scheduleConfig.MaxLightProcesses; TotalMaterializeInputSlots = scheduleConfig.MaxMaterialize; m_detoursListener = detoursListener; m_pipQueue = pipQueue; Start(); }
public decimal GetAdjustmentInterestRepayment(List <Installment> schedule, IScheduleConfiguration configuration) { var numberOfPeriods = (decimal) (configuration.PeriodPolicy.GetNumberOfPeriodsInYear(configuration.PreferredFirstInstallmentDate, configuration.YearPolicy)); return (configuration.RoundingPolicy.Round((configuration.Amount * configuration.InterestRate / numberOfPeriods / 100) * configuration.NumberOfInstallments) - schedule.Sum(i => i.InterestsRepayment.Value)); }
public void Calculate(IInstallment installment, IScheduleConfiguration configuration) { var number = configuration.NumberOfInstallments - configuration.GracePeriod; var numberOfPeriods = configuration.PeriodPolicy.GetNumberOfPeriodsInYear(installment.EndDate, configuration.YearPolicy); var interestRate = (double)configuration.InterestRate / 100 / numberOfPeriods; var numerator = interestRate * (double)configuration.Amount; var denominator = 1 - 1 / Math.Pow(1 + interestRate, number); var total = configuration.RoundingPolicy.Round((decimal)(numerator / denominator)); installment.Interest = CalculateInterest(installment, configuration, installment.Olb); installment.Principal = total - installment.Interest; }
/// <summary> /// Finding total for all Annuity policy (30/360, Fact/360, Fact/Fact) /// </summary> /// <param name="configuration"></param> /// <returns>total annuity</returns> private decimal FindAnnuity(IScheduleConfiguration configuration) { var number = configuration.NumberOfInstallments - configuration.GracePeriod; var numberOfPeriods = configuration.PeriodPolicy.GetNumberOfPeriodsInYear(configuration.PreferredFirstInstallmentDate, configuration.YearPolicy); var interestRate = (double)configuration.InterestRate / 100 / numberOfPeriods; // at first we are trying to calculate standard annuity for 30/360 using standard formula. var numerator = (decimal)interestRate * configuration.Amount; var denominator = 1 - 1 / Math.Pow(1 + interestRate, number); var annuity = 0.0M; if (configuration.InterestRate == 0) annuity = configuration.Amount / number; else annuity = numerator / (decimal)denominator; // In order to define the annuity amount for the other types Period and Year policy // we need to increase the standard annuity, build schedule according defined amount // and if scheduled is not balanced, repeat the procedure again // remainder it is surplus amount, which is left after building schedule using calculated annuity // remainder = remainder/numberOfInstallemnts * interestRate/100 // left remainder // should be divided by number of installments in order to proportionally spread between installments // but because we need to count interest also that amount should be multiplied by interest rate / 100 var remainder = 0m; var counter = 0; var installment = new Installment {OLB = configuration.Amount}; var endDate = configuration.PreferredFirstInstallmentDate; do { // loop is only for building schedule and determining the remainder for (var i = 1; i <= configuration.NumberOfInstallments; ++i) { installment.Number = i; installment.StartDate = i != 1 ? installment.ExpectedDate : configuration.StartDate; endDate = i == 1 ? configuration.PreferredFirstInstallmentDate : configuration.PeriodPolicy.GetNextDate(endDate); installment.ExpectedDate = configuration.DateShiftPolicy.ShiftDate(endDate); if (i <= configuration.GracePeriod) continue; installment.InterestsRepayment = CalculateInterest(installment, configuration, installment.OLB.Value); installment.CapitalRepayment = annuity - installment.InterestsRepayment; installment.OLB -= installment.CapitalRepayment; } remainder = installment.OLB.Value; installment.OLB = configuration.Amount; ++counter; annuity += (remainder * configuration.InterestRate / (decimal)numberOfPeriods / 100 / number); } while (Math.Abs(remainder) > 0.01m && counter < 1000); return annuity; }
/// <summary> /// Finding total for all Annuity policy (30/360, Fact/360, Fact/Fact) /// </summary> /// <param name="configuration"></param> /// <returns>total annuity</returns> private decimal FindAnnuity(IScheduleConfiguration configuration) { var number = configuration.NumberOfInstallments - configuration.GracePeriod; var numberOfPeriods = configuration.PeriodPolicy.GetNumberOfPeriodsInYear(configuration.PreferredFirstInstallmentDate, configuration.YearPolicy); var interestRate = (double)configuration.InterestRate / 100 / numberOfPeriods; // at first we are trying to calculate standard annuity for 30/360 using standard formula. var numerator = (decimal)interestRate * configuration.Amount; var denominator = 1 - 1 / Math.Pow(1 + interestRate, number); var annuity = numerator / (decimal)denominator; // In order to define the annuity amount for the other types Period and Year policy // we need to increase the standard annuity, build schedule according defined amount // and if scheduled is not balanced, repeat the procedure again // remainder it is surplus amount, which is left after building schedule using calculated annuity // remainder = remainder/numberOfInstallemnts * interestRate/100 // left remainder // should be divided by number of installments in order to proportionally spread between installments // but because we need to count interest also that amount should be multiplied by interest rate / 100 var remainder = 0m; var counter = 0; var installment = new Installment { OLB = configuration.Amount }; var endDate = configuration.PreferredFirstInstallmentDate; do { // loop is only for building schedule and determining the remainder for (var i = 1; i <= configuration.NumberOfInstallments; ++i) { installment.Number = i; installment.StartDate = i != 1 ? installment.ExpectedDate : configuration.StartDate; endDate = i == 1 ? configuration.PreferredFirstInstallmentDate : configuration.PeriodPolicy.GetNextDate(endDate); installment.ExpectedDate = configuration.DateShiftPolicy.ShiftDate(endDate); if (i <= configuration.GracePeriod) { continue; } installment.InterestsRepayment = CalculateInterest(installment, configuration, installment.OLB.Value); installment.CapitalRepayment = annuity - installment.InterestsRepayment; installment.OLB -= installment.CapitalRepayment; } remainder = installment.OLB.Value; installment.OLB = configuration.Amount; ++counter; annuity += (remainder * configuration.InterestRate / (decimal)numberOfPeriods / 100 / number); } while (Math.Abs(remainder) > 0.01m && counter < 1000); return(annuity); }
/// <summary> /// Constructor. /// </summary> public LocalWorkerWithRemoting( IScheduleConfiguration scheduleConfig, ISandboxConfiguration sandboxConfig, IPipQueue pipQueue, IDetoursEventListener detoursListener, PipExecutionContext pipExecutionContext) : base(scheduleConfig, pipQueue, detoursListener, pipExecutionContext) { m_localExecutionSemaphore = new SemaphoreSlim(scheduleConfig.MaxProcesses, scheduleConfig.MaxProcesses); m_remotingThreshold = (int)(scheduleConfig.MaxProcesses * scheduleConfig.RemotingThresholdMultiplier); m_processCanRunRemoteTags = scheduleConfig.ProcessCanRunRemoteTags.Select(t => StringTable.AddString(t)).ToHashSet(); m_processMustRunLocalTags = scheduleConfig.ProcessMustRunLocalTags.Select(t => StringTable.AddString(t)).ToHashSet(); m_sandboxConfig = sandboxConfig; }
public List<IInstallment> BuildSchedule(IScheduleConfiguration configuration) { if (configuration.PeriodPolicy == null) throw new ArgumentException("Period policy cannot be null."); if (configuration.YearPolicy == null) throw new ArgumentException("Year policy cannot be null."); if (configuration.RoundingPolicy == null) throw new ArgumentException("Rounding policy cannot be null."); if (configuration.CalculationPolicy == null) throw new ArgumentException("Installment calculation policy cannot be null."); if (configuration.AdjustmentPolicy == null) throw new ArgumentException("Adjustment policy cannot be null."); if (configuration.DateShiftPolicy == null) throw new ArgumentException("Date shift policy cannot be null."); if (configuration.GracePeriod >= configuration.NumberOfInstallments) throw new ArgumentException("Grace period should be less than the number of installments."); var installment = BuildFirst(configuration); var result = new List<IInstallment> { installment }; while ((installment = BuildNext(installment, configuration)) != null) { result.Add(installment); } configuration.AdjustmentPolicy.Adjust(result, configuration); // CalculationPolicy interest during grace period if (configuration.ChargeInterestDuringGracePeriod) { for (var i = 0; i < configuration.GracePeriod; i++) { result[i].Interest = CalculateInterest(result[i], configuration); } } // Caluclate interest of the first installment if the maturity // is less than or greater than a period (week, month, etc.) var firstInstallment = result[0]; var periodEndDate = configuration.PeriodPolicy.GetNextDate(firstInstallment.StartDate); var actualEndDate = firstInstallment.EndDate; if (periodEndDate != actualEndDate) { var numerator = (decimal) (firstInstallment.EndDate.Date - firstInstallment.StartDate.Date).Days; var denominator = configuration.PeriodPolicy.GetNumberOfDays(firstInstallment.EndDate); firstInstallment.Interest = configuration.RoundingPolicy.Round(firstInstallment.Interest * numerator / denominator); } // Initialize RepaymentDate's foreach (var i in result) { i.RepaymentDate = configuration.DateShiftPolicy.ShiftDate(i.EndDate); } return result; }
protected decimal CalculateInterest(IInstallment installment, IScheduleConfiguration configuration, decimal amount) { var daysInPeriod = configuration.PeriodPolicy.GetNumberOfDays(installment.EndDate);//, configuration.DateShiftPolicy); var daysInYear = configuration.YearPolicy.GetNumberOfDays(installment.EndDate); var interest = installment.Olb * configuration.InterestRate / 100 * daysInPeriod / daysInYear; //if schedule is flat if (configuration.CalculationPolicy.GetType() == typeof(FlatInstallmentCalculationPolicy)) { var numberOfPeriods = (decimal) (configuration.PeriodPolicy.GetNumberOfPeriodsInYear( configuration.PreferredFirstInstallmentDate, configuration.YearPolicy)); interest = configuration.Amount*configuration.InterestRate/numberOfPeriods/100; } return configuration.RoundingPolicy.Round(interest); }
private static IInstallment BuildFirst(IScheduleConfiguration configuration) { var installment = new Installment { Number = 1, StartDate = configuration.StartDate, EndDate = configuration.PreferredFirstInstallmentDate, Olb = configuration.Amount, }; if (configuration.GracePeriod == 0) { configuration.CalculationPolicy.Calculate(installment, configuration); } return installment; }
private static IInstallment BuildFirst(IScheduleConfiguration configuration) { var installment = new Installment { Number = 1, StartDate = configuration.StartDate, EndDate = configuration.PreferredFirstInstallmentDate, Olb = configuration.Amount, }; if (configuration.GracePeriod == 0) { configuration.CalculationPolicy.Calculate(installment, configuration); } return(installment); }
private static decimal CalculateInterest(Installment installment, IScheduleConfiguration configuration) { var daysInPeriod = configuration.PeriodPolicy.GetNumberOfDays(installment.ExpectedDate);//, configuration.DateShiftPolicy); var daysInYear = configuration.YearPolicy.GetNumberOfDays(installment.ExpectedDate); var interest = installment.OLB * configuration.InterestRate / 100 * daysInPeriod / daysInYear; //if schedule is flat if (configuration.CalculationPolicy.GetType() == typeof(FlatInstallmentCalculationPolicy)) { var numberOfPeriods = (decimal) (configuration.PeriodPolicy.GetNumberOfPeriodsInYear( configuration.PreferredFirstInstallmentDate, configuration.YearPolicy)); interest = configuration.Amount * configuration.InterestRate / numberOfPeriods / 100; } return(configuration.RoundingPolicy.Round(interest.Value)); }
public List<Installment> BuildSchedule(IScheduleConfiguration configuration) { if (configuration.PeriodPolicy == null) throw new ArgumentException("Period policy cannot be null."); if (configuration.YearPolicy == null) throw new ArgumentException("Year policy cannot be null."); if (configuration.RoundingPolicy == null) throw new ArgumentException("Rounding policy cannot be null."); if (configuration.CalculationPolicy == null) throw new ArgumentException("Installment calculation policy cannot be null."); if (configuration.AdjustmentPolicy == null) throw new ArgumentException("Adjustment policy cannot be null."); if (configuration.DateShiftPolicy == null) throw new ArgumentException("Date shift policy cannot be null."); if (configuration.GracePeriod >= configuration.NumberOfInstallments) throw new ArgumentException("Grace period should be less than the number of installments."); var installment = BuildFirst(configuration); var result = new List<Installment> { installment }; while ((installment = BuildNext(installment, configuration)) != null) { result.Add(installment); } configuration.AdjustmentPolicy.Adjust(result, configuration); // CalculationPolicy interest during grace period if (configuration.ChargeInterestDuringGracePeriod) { for (var i = 0; i < configuration.GracePeriod; i++) { result[i].InterestsRepayment = CalculateInterest(result[i], configuration); } } // if the difference between start date and first installment date less or greater than period if (configuration.GracePeriod == 0 && configuration.ChargeInterestDuringGracePeriod) { result[0].InterestsRepayment = CalculateFirstInstallmentInterest(result[0], configuration); } // Initialize RepaymentDate's var startDate = configuration.StartDate; foreach (var i in result) { i.ExpectedDate = configuration.DateShiftPolicy.ShiftDate(i.ExpectedDate); i.StartDate = startDate; startDate = i.ExpectedDate; } return result; }
public void FlatSchedule_Setup() { _configuration = new ScheduleConfiguration { NumberOfInstallments = 5, Amount = 5000, InterestRate = 24m, StartDate = new DateTime(2013, 1, 1), PreferredFirstInstallmentDate = new DateTime(2013, 2, 1), PeriodPolicy = new Monthly30DayPeriodPolicy(), YearPolicy = new ThreeHundredSixtyDayYearPolicy(), RoundingPolicy = new TwoDecimalRoundingPolicy(), CalculationPolicy = new FlatInstallmentCalculationPolicy(), AdjustmentPolicy = new LastInstallmentAdjustmentPolicy(), DateShiftPolicy = new NoDateShiftPolicy(), }; _builder = new ScheduleBuilder(); }
private static IInstallment BuildNext(IInstallment previous, IScheduleConfiguration configuration) { if (previous == null) throw new ArgumentException("Previous installment cannot be null."); if (previous.Number == configuration.NumberOfInstallments) return null; var installment = new Installment { Number = previous.Number + 1, StartDate = previous.EndDate, EndDate = configuration.PeriodPolicy.GetNextDate(previous.EndDate), Olb = previous.Olb - previous.Principal, }; if (configuration.GracePeriod < installment.Number) { configuration.CalculationPolicy.Calculate(installment, configuration); } return installment; }
public void AnnuitySchedule_Setup() { _configuration = new ScheduleConfiguration { NumberOfInstallments = 12, Amount = 100000, InterestRate = 36m, StartDate = new DateTime(2013, 12, 10), PreferredFirstInstallmentDate = new DateTime(2014, 1, 10), PeriodPolicy = new MonthlyPeriodPolicy(), YearPolicy = new ThreeHundredSixtyDayYearPolicy(), RoundingPolicy = new IntegerRoundingPolicy(), CalculationPolicy = new AnnuityInstallmentCalculationPolicy(), AdjustmentPolicy = new LastInstallmentAdjustmentPolicy(), DateShiftPolicy = new NoDateShiftPolicy(), }; _builder = new ScheduleBuilder(); }
/// <summary> /// Creates instance /// </summary> public PipQueue(LoggingContext loggingContext, IConfiguration config) { Contract.Requires(config != null); m_scheduleConfig = config.Schedule; // If adaptive IO is enabled, then start with the half of the maxIO. var ioLimit = m_scheduleConfig.AdaptiveIO ? (m_scheduleConfig.MaxIO + 1) / 2 : m_scheduleConfig.MaxIO; m_chooseWorkerLightQueue = new ChooseWorkerQueue(this, 1); m_chooseWorkerCacheLookupQueue = new ChooseWorkerQueue(this, m_scheduleConfig.MaxChooseWorkerCacheLookup); m_chooseWorkerCpuQueue = m_scheduleConfig.ModuleAffinityEnabled() ? new NestedChooseWorkerQueue(this, m_scheduleConfig.MaxChooseWorkerCpu, config.Distribution.BuildWorkers.Count + 1) : new ChooseWorkerQueue(this, m_scheduleConfig.MaxChooseWorkerCpu); m_queuesByKind = new Dictionary <DispatcherKind, DispatcherQueue>() { { DispatcherKind.IO, new DispatcherQueue(this, ioLimit) }, { DispatcherKind.DelayedCacheLookup, new DispatcherQueue(this, maxParallelDegree: 1) }, { DispatcherKind.ChooseWorkerCacheLookup, m_chooseWorkerCacheLookupQueue }, { DispatcherKind.ChooseWorkerLight, m_chooseWorkerLightQueue }, { DispatcherKind.CacheLookup, new DispatcherQueue(this, m_scheduleConfig.MaxCacheLookup) }, { DispatcherKind.ChooseWorkerCpu, m_chooseWorkerCpuQueue }, { DispatcherKind.CPU, new DispatcherQueue(this, m_scheduleConfig.EffectiveMaxProcesses, useWeight: true) }, { DispatcherKind.Materialize, new DispatcherQueue(this, m_scheduleConfig.MaxMaterialize) }, { DispatcherKind.Light, new DispatcherQueue(this, m_scheduleConfig.MaxLightProcesses) }, { DispatcherKind.SealDirs, new DispatcherQueue(this, m_scheduleConfig.MaxSealDirs) }, }; m_hasAnyChange = new ManualResetEventSlim(initialState: true /* signaled */); Tracing.Logger.Log.PipQueueConcurrency( loggingContext, ioLimit, m_scheduleConfig.MaxChooseWorkerCacheLookup, m_scheduleConfig.MaxCacheLookup, m_scheduleConfig.MaxChooseWorkerCpu, m_scheduleConfig.EffectiveMaxProcesses, m_scheduleConfig.MaxMaterialize, m_scheduleConfig.MaxLightProcesses, m_scheduleConfig.OrchestratorCacheLookupMultiplier.ToString(), m_scheduleConfig.OrchestratorCpuMultiplier.ToString()); }
private static Installment BuildFirst(IScheduleConfiguration configuration) { var installment = new Installment { Number = 1, StartDate = configuration.StartDate, ExpectedDate = configuration.PreferredFirstInstallmentDate, OLB = configuration.Amount, CapitalRepayment = 0m, InterestsRepayment = 0m, FeesUnpaid = 0 }; if (configuration.GracePeriod == 0) { configuration.CalculationPolicy.Calculate(installment, configuration); } return installment; }
private static Installment BuildFirst(IScheduleConfiguration configuration) { var installment = new Installment { Number = 1, StartDate = configuration.StartDate, ExpectedDate = configuration.PreferredFirstInstallmentDate, OLB = configuration.Amount, CapitalRepayment = 0m, InterestsRepayment = 0m, FeesUnpaid = 0 }; if (configuration.GracePeriod == 0) { configuration.CalculationPolicy.Calculate(installment, configuration); } return(installment); }
public void BuildEngine_Setup() { _configuration = new ScheduleConfiguration { Amount = 10000, GracePeriod = 0, InterestRate = 0.24m, NumberOfInstallments = 5, StartDate = new DateTime(2013, 1, 1), PreferredFirstInstallmentDate = new DateTime(2013, 2, 5), ChargeInterestDuringGracePeriod = true, PeriodPolicy = new MonthlyPeriodPolicy(), YearPolicy = new ActualNumberOfDayYearPolicy(), RoundingPolicy = new TwoDecimalRoundingPolicy(), CalculationPolicy = new FlatInstallmentCalculationPolicy(), AdjustmentPolicy = new LastInstallmentAdjustmentPolicy(), DateShiftPolicy = new NoDateShiftPolicy(), }; _builder = new ScheduleBuilder(); }
private static Installment BuildNext(Installment previous, IScheduleConfiguration configuration) { if (previous == null) throw new ArgumentException("Previous installment cannot be null."); if (previous.Number == configuration.NumberOfInstallments) return null; var installment = new Installment { Number = previous.Number + 1, StartDate = previous.ExpectedDate, ExpectedDate = configuration.PeriodPolicy.GetNextDate(previous.ExpectedDate), InterestsRepayment = 0m, CapitalRepayment = 0m, OLB = previous.OLB - previous.CapitalRepayment, FeesUnpaid = 0 }; if (configuration.GracePeriod < installment.Number) { configuration.CalculationPolicy.Calculate(installment, configuration); } return installment; }
/// <summary> /// Creates instance /// </summary> public PipQueue(IScheduleConfiguration config) { Contract.Requires(config != null); m_config = config; // If adaptive IO is enabled, then start with the half of the maxIO. var ioLimit = config.AdaptiveIO ? (config.MaxIO + 1) / 2 : config.MaxIO; m_chooseWorkerCacheLookupQueue = new ChooseWorkerQueue(this, config.MaxChooseWorkerCacheLookup); m_chooseWorkerCpuQueue = new ChooseWorkerQueue(this, config.MaxChooseWorkerCpu); m_queuesByKind = new Dictionary<DispatcherKind, DispatcherQueue>() { {DispatcherKind.IO, new DispatcherQueue(this, ioLimit)}, {DispatcherKind.ChooseWorkerCacheLookup, m_chooseWorkerCacheLookupQueue}, {DispatcherKind.CacheLookup, new DispatcherQueue(this, config.MaxCacheLookup)}, {DispatcherKind.ChooseWorkerCpu, m_chooseWorkerCpuQueue}, {DispatcherKind.CPU, new DispatcherQueue(this, config.MaxProcesses)}, {DispatcherKind.Materialize, new DispatcherQueue(this, config.MaxMaterialize)}, {DispatcherKind.Light, new DispatcherQueue(this, config.MaxLightProcesses)} }; m_hasAnyChange = new ManualResetEventSlim(initialState: true /* signaled */); Tracing.Logger.Log.PipQueueConcurrency( Events.StaticContext, ioLimit, config.MaxChooseWorkerCacheLookup, config.MaxCacheLookup, config.MaxChooseWorkerCpu, config.MaxProcesses, config.MaxMaterialize, config.MaxLightProcesses, config.MasterCacheLookupMultiplier.ToString(), config.MasterCpuMultiplier.ToString()); }
public void Adjust(List<Installment> schedule, IScheduleConfiguration configuration) { schedule[schedule.Count - 1].CapitalRepayment += GetAdjustment(schedule, configuration); }
/// <nodoc /> public ScheduleConfiguration(IScheduleConfiguration template, PathRemapper pathRemapper) { Contract.Assume(template != null); MaxProcesses = template.MaxProcesses; MaxLightProcesses = template.MaxLightProcesses; MaxIO = template.MaxIO; MaxChooseWorkerCpu = template.MaxChooseWorkerCpu; MaxChooseWorkerCacheLookup = template.MaxChooseWorkerCacheLookup; MaxCacheLookup = template.MaxCacheLookup; MaxMaterialize = template.MaxMaterialize; EnvironmentFingerprint = template.EnvironmentFingerprint; DisableProcessRetryOnResourceExhaustion = template.DisableProcessRetryOnResourceExhaustion; StopOnFirstError = template.StopOnFirstError; LowPriority = template.LowPriority; EnableLazyOutputMaterialization = template.EnableLazyOutputMaterialization; ForceSkipDependencies = template.ForceSkipDependencies; UseHistoricalPerformanceInfo = template.UseHistoricalPerformanceInfo; RequiredOutputMaterialization = template.RequiredOutputMaterialization; TreatDirectoryAsAbsentFileOnHashingInputContent = template.TreatDirectoryAsAbsentFileOnHashingInputContent; MaximumRamUtilizationPercentage = template.MaximumRamUtilizationPercentage; MinimumTotalAvailableRamMb = template.MinimumTotalAvailableRamMb; MinimumDiskSpaceForPipsGb = template.MinimumDiskSpaceForPipsGb; MaximumAllowedMemoryPressureLevel = template.MaximumAllowedMemoryPressureLevel; AllowCopySymlink = template.AllowCopySymlink; AdaptiveIO = template.AdaptiveIO; ReuseOutputsOnDisk = template.ReuseOutputsOnDisk; UseHistoricalRamUsageInfo = template.UseHistoricalRamUsageInfo; VerifyCacheLookupPin = template.VerifyCacheLookupPin; PinCachedOutputs = template.PinCachedOutputs; CanonicalizeFilterOutputs = template.CanonicalizeFilterOutputs; ForceUseEngineInfoFromCache = template.ForceUseEngineInfoFromCache; UnsafeDisableGraphPostValidation = template.UnsafeDisableGraphPostValidation; ProcessRetries = template.ProcessRetries; StoreOutputsToCache = template.StoreOutputsToCache; EnableLazyWriteFileMaterialization = template.EnableLazyWriteFileMaterialization; WriteIpcOutput = template.WriteIpcOutput; OutputMaterializationExclusionRoots = pathRemapper.Remap(template.OutputMaterializationExclusionRoots); IncrementalScheduling = template.IncrementalScheduling; ComputePipStaticFingerprints = template.ComputePipStaticFingerprints; LogPipStaticFingerprintTexts = template.LogPipStaticFingerprintTexts; CreateHandleWithSequentialScanOnHashingOutputFiles = template.CreateHandleWithSequentialScanOnHashingOutputFiles; OutputFileExtensionsForSequentialScanHandleOnHashing = new List <PathAtom>(template.OutputFileExtensionsForSequentialScanHandleOnHashing.Select(pathRemapper.Remap)); TelemetryTagPrefix = template.TelemetryTagPrefix; MasterCpuMultiplier = template.MasterCpuMultiplier; MasterCacheLookupMultiplier = template.MasterCacheLookupMultiplier; SkipHashSourceFile = template.SkipHashSourceFile; UnsafeDisableSharedOpaqueEmptyDirectoryScrubbing = template.UnsafeDisableSharedOpaqueEmptyDirectoryScrubbing; UnsafeLazySODeletion = template.UnsafeLazySODeletion; UseFixedApiServerMoniker = template.UseFixedApiServerMoniker; InputChanges = pathRemapper.Remap(template.InputChanges); CacheOnly = template.CacheOnly; EnableSetupCostWhenChoosingWorker = template.EnableSetupCostWhenChoosingWorker; MaxSealDirs = template.MaxSealDirs; EnableHistoricCommitMemoryProjection = template.EnableHistoricCommitMemoryProjection; MaximumCommitUtilizationPercentage = template.MaximumCommitUtilizationPercentage; DelayedCacheLookupMinMultiplier = template.DelayedCacheLookupMinMultiplier; DelayedCacheLookupMaxMultiplier = template.DelayedCacheLookupMaxMultiplier; MaxRetriesDueToLowMemory = template.MaxRetriesDueToLowMemory; MaxRetriesDueToRetryableFailures = template.MaxRetriesDueToRetryableFailures; EnableLessAggresiveMemoryProjection = template.EnableLessAggresiveMemoryProjection; ManageMemoryMode = template.ManageMemoryMode; }
private List<Installment> AssembleRescheduling(Loan loan, ScheduleConfiguration rescheduleConfiguration, IScheduleConfiguration scheduleConfiguration) { var copyOfLoan = loan.Copy();; var schedule = copyOfLoan.InstallmentList; // Build a new combined schedule // 1. To close all active installments before date of rescheduling. // Get the part of the schedule that comes before the rescheduling date... var newSchedule = from installment in schedule where installment.ExpectedDate <= rescheduleConfiguration.StartDate select installment; // Get overpaid principal = sum of paid principal after the rescheduling date... var overpaidPrincipal = ( from installment in schedule where installment.PaidDate > rescheduleConfiguration.StartDate select installment ).Sum(installment => installment.PaidCapital.Value); //Add overpaid principal to paid principal of the last installment before the rescheduling if (newSchedule.Any()) newSchedule.Last().PaidCapital += overpaidPrincipal; // Close all active installments before date of rescheduling var olbDifference = 0m; foreach (var installment in newSchedule) { installment.OLB += olbDifference; olbDifference += installment.CapitalRepayment.Value - installment.PaidCapital.Value; installment.CapitalRepayment = installment.PaidCapital; installment.InterestsRepayment = installment.PaidInterests; } // 2. To store amounts of interest paid, those for installments after date of rescheduling. var overpaidInterest = ( from installment in schedule where installment.ExpectedDate > rescheduleConfiguration.StartDate select installment ).Sum(installment => installment.PaidInterests.Value); // 3. To get total of first calculated interest. It will be interest between last closed installment and date of rescheduling // plus interest between date of rescheduling and first repayment date // To calculate extra interest for used days. // For the case when date of rescheduling < date of first installment var currentOlb = loan.CalculateActualOlb().Value; var usedDays = 0; if (newSchedule.Any()) { usedDays = (rescheduleConfiguration.StartDate - newSchedule.Last().ExpectedDate).Days; } var daysInYear = scheduleConfiguration.YearPolicy.GetNumberOfDays(rescheduleConfiguration.StartDate); var extraInterest = currentOlb * scheduleConfiguration.InterestRate / 100 * usedDays / daysInYear; // To calculate interest between date of rescheduling and first repayment date. var daysTillRepayment = (rescheduleConfiguration.PreferredFirstInstallmentDate - rescheduleConfiguration.StartDate).Days; decimal firstInterest = 0; if (rescheduleConfiguration.GracePeriod == 0 || rescheduleConfiguration.ChargeInterestDuringGracePeriod) firstInterest = currentOlb*rescheduleConfiguration.InterestRate/100*daysTillRepayment/ scheduleConfiguration.PeriodPolicy.GetNumberOfDays( rescheduleConfiguration.PreferredFirstInstallmentDate); copyOfLoan.Amount = currentOlb; copyOfLoan.InterestRate = rescheduleConfiguration.InterestRate/100; copyOfLoan.NbOfInstallments = rescheduleConfiguration.NumberOfInstallments; copyOfLoan.GracePeriod = rescheduleConfiguration.GracePeriod; copyOfLoan.StartDate = rescheduleConfiguration.StartDate; copyOfLoan.FirstInstallmentDate = rescheduleConfiguration.PreferredFirstInstallmentDate; copyOfLoan.Product.ChargeInterestWithinGracePeriod = rescheduleConfiguration.ChargeInterestDuringGracePeriod; rescheduleConfiguration.RoundingPolicy = scheduleConfiguration.RoundingPolicy; var rescheduled = SimulateScheduleCreation(copyOfLoan); // Adjust the new schedule's installment numbers var increment = newSchedule.Count(); foreach (var installment in rescheduled) { installment.Number += increment; } // Distribute the extra and overpaid interest if (rescheduleConfiguration.GracePeriod > 0 && !rescheduleConfiguration.ChargeInterestDuringGracePeriod) rescheduled[rescheduleConfiguration.GracePeriod].InterestsRepayment += rescheduleConfiguration.RoundingPolicy.Round(extraInterest); else rescheduled.First().InterestsRepayment = rescheduleConfiguration.RoundingPolicy.Round(firstInterest + extraInterest); foreach (var installment in rescheduled) { if (installment.InterestsRepayment < overpaidInterest) { installment.PaidInterests = installment.InterestsRepayment; overpaidInterest -= installment.InterestsRepayment.Value; } else { installment.PaidInterests = overpaidInterest; break; } } var result = new List<Installment>(); result.AddRange(newSchedule); result.AddRange(rescheduled); return result; }
public IEnumerable<IInstallment> AssembleTranche( IEnumerable<IInstallment> schedule, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration, IScheduleBuilder scheduleBuilder, ITrancheBuilder trancheBuilder) { // Build a new combined schedule var trancheSchedule = trancheBuilder.BuildTranche(schedule, scheduleBuilder, scheduleConfiguration, trancheConfiguration); // Get an interested paid in advance, whereas "in advance" means after the new tranche date var overpaidInterest = ( from installment in schedule where installment.RepaymentDate > trancheConfiguration.StartDate select installment ).Sum(installment => installment.PaidInterest); // Get the part of the schedule that comes before the tranche date... var newSchedule = from installment in schedule where installment.RepaymentDate <= trancheConfiguration.StartDate select installment; // ...and force close it (set expected equal to paid) var olbDifference = 0m; foreach (var installment in newSchedule) { installment.Olb += olbDifference; olbDifference += installment.Principal - installment.PaidPrincipal; if (!(installment.Principal == installment.PaidPrincipal && installment.Interest == installment.PaidInterest)) { installment.LastPaymentDate = trancheConfiguration.StartDate; } installment.Principal = installment.PaidPrincipal; installment.Interest = installment.PaidInterest; } // Adjust the new schedule's installment numbers var increment = newSchedule.Count(); foreach (var installment in trancheSchedule) { installment.Number += increment; } var result = new List<IInstallment>(); result.AddRange(newSchedule); // Distribute the overpaid interest foreach (var installment in trancheSchedule) { if (installment.Interest < overpaidInterest) { installment.PaidInterest = installment.Interest; overpaidInterest -= installment.Interest; } else { installment.PaidInterest = overpaidInterest; break; } } result.AddRange(trancheSchedule); return result; }
private static decimal CalculateFirstInstallmentInterest(Installment installment, IScheduleConfiguration configuration) { var daysInPeriod = configuration.PeriodPolicy.GetNumberOfDays(installment, configuration.DateShiftPolicy); var daysInYear = configuration.YearPolicy.GetNumberOfDays(installment.ExpectedDate); var interest = installment.OLB * configuration.InterestRate / 100 * daysInPeriod / daysInYear; //if schedule is flat if (configuration.CalculationPolicy.GetType() == typeof(FlatInstallmentCalculationPolicy)) { var numberOfPeriods = (decimal) (configuration.PeriodPolicy.GetNumberOfPeriodsInYear( configuration.PreferredFirstInstallmentDate, configuration.YearPolicy)); interest = configuration.Amount*configuration.InterestRate/numberOfPeriods/100; if (configuration.ChargeActualInterestForFirstInstallment) { var nextDate = configuration.PeriodPolicy.GetNextDate(configuration.StartDate); var numerator = (installment.ExpectedDate - configuration.StartDate).Days; var denominator = (nextDate - configuration.StartDate).Days; interest = interest*numerator/denominator; } } return configuration.RoundingPolicy.Round(interest.Value); }
public void Adjust(List<IInstallment> schedule, IScheduleConfiguration configuration) { schedule[schedule.Count - 1].Principal += GetAdjustment(schedule, configuration); }
public decimal GetAdjustment(List<IInstallment> schedule, IScheduleConfiguration configuration) { return configuration.Amount - schedule.Sum(i => i.Principal); }
public IEnumerable<IInstallment> AssembleRescheduling( IEnumerable<IInstallment> schedule, IScheduleConfiguration scheduleConfiguration, IScheduleConfiguration rescheduleConfiguration, IScheduleBuilder scheduleBuilder, decimal currentOlb) { // Build a new combined schedule // 1. To close all active installments before date of rescheduling. // Get the part of the schedule that comes before the rescheduling date... var newSchedule = from installment in schedule where installment.RepaymentDate <= rescheduleConfiguration.StartDate select installment; // Get overpaid principal = sum of paid principal after the rescheduling date... var overpaidPrincipal = ( from installment in schedule where installment.RepaymentDate > rescheduleConfiguration.StartDate select installment ).Sum(installment => installment.PaidPrincipal); //Add overpaid principal to paid principal of the last installment before the rescheduling if (newSchedule.Any()) newSchedule.Last().PaidPrincipal += overpaidPrincipal; // Close all active installments before date of rescheduling var olbDifference = 0m; foreach (var installment in newSchedule) { installment.Olb += olbDifference; olbDifference += installment.Principal - installment.PaidPrincipal; installment.Principal = installment.PaidPrincipal; installment.Interest = installment.PaidInterest; } // 2. To store amounts of interest paid, those for installments after date of rescheduling. var overpaidInterest = ( from installment in schedule where installment.RepaymentDate > rescheduleConfiguration.StartDate select installment ).Sum(installment => installment.PaidInterest); // 3. To get total of first calculated interest. It will be interest between last closed installment and date of rescheduling // plus interest between date of rescheduling and first repayment date // To calculate extra interest for used days. // For the case when date of rescheduling < date of first installment var usedDays = 0; if (newSchedule.Any()) { usedDays = (rescheduleConfiguration.StartDate - newSchedule.Last().EndDate).Days; } var daysInYear = scheduleConfiguration.YearPolicy.GetNumberOfDays(rescheduleConfiguration.StartDate); var extraInterest = currentOlb*scheduleConfiguration.InterestRate/100*usedDays/daysInYear; // To calculate interest between date of rescheduling and first repayment date. var daysTillRepayment = (rescheduleConfiguration.PreferredFirstInstallmentDate - rescheduleConfiguration.StartDate).Days; decimal firstInterest = 0; if (rescheduleConfiguration.GracePeriod == 0 || rescheduleConfiguration.ChargeInterestDuringGracePeriod) firstInterest = currentOlb*rescheduleConfiguration.InterestRate/100*daysTillRepayment/daysInYear; // 4. We generate new schedule according to new parametrs. rescheduleConfiguration.Amount = currentOlb; rescheduleConfiguration.AdjustmentPolicy = scheduleConfiguration.AdjustmentPolicy; rescheduleConfiguration.CalculationPolicy = scheduleConfiguration.CalculationPolicy; rescheduleConfiguration.DateShiftPolicy = scheduleConfiguration.DateShiftPolicy; rescheduleConfiguration.PeriodPolicy = scheduleConfiguration.PeriodPolicy; rescheduleConfiguration.RoundingPolicy = scheduleConfiguration.RoundingPolicy; rescheduleConfiguration.YearPolicy = scheduleConfiguration.YearPolicy; var rescheduled = scheduleBuilder.BuildSchedule(rescheduleConfiguration); // Adjust the new schedule's installment numbers var increment = newSchedule.Count(); foreach (var installment in rescheduled) { installment.Number += increment; } // Distribute the extra and overpaid interest if (rescheduleConfiguration.GracePeriod > 0 && !rescheduleConfiguration.ChargeInterestDuringGracePeriod) rescheduled[rescheduleConfiguration.GracePeriod].Interest += rescheduleConfiguration.RoundingPolicy.Round(extraInterest); else rescheduled.First().Interest = rescheduleConfiguration.RoundingPolicy.Round(firstInterest + extraInterest); foreach (var installment in rescheduled) { if (installment.Interest < overpaidInterest) { installment.PaidInterest = installment.Interest; overpaidInterest -= installment.Interest; } else { installment.PaidInterest = overpaidInterest; break; } } var result = new List<IInstallment>(); result.AddRange(newSchedule); result.AddRange(rescheduled); return result; }
private IEnumerable<Installment> BuildTranche(IEnumerable<Installment> schedule,Loan loan, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var copyOfLoan = loan.Copy(); loan.Amount = trancheConfiguration.Amount; loan.NbOfInstallments = trancheConfiguration.NumberOfInstallments; loan.GracePeriod = trancheConfiguration.GracePeriod; loan.InterestRate = trancheConfiguration.InterestRate/100; loan.StartDate = trancheConfiguration.StartDate; loan.FirstInstallmentDate = trancheConfiguration.PreferredFirstInstallmentDate; var rhs = SimulateScheduleCreation(loan); loan.Amount = schedule.Sum(i => i.CapitalRepayment.Value - i.PaidCapital.Value); if (!trancheConfiguration.ApplyNewInterestRateToOlb) { loan.InterestRate = copyOfLoan.InterestRate; } var lhs = SimulateScheduleCreation(loan); var result = new List<Installment>(); // Merge the two schedules var max = Math.Max(lhs.Count, rhs.Count); for (var i = 0; i < max; i++) { var lhi = i >= lhs.Count ? null : lhs[i]; var rhi = i >= rhs.Count ? null : rhs[i]; Installment installment; if (lhi == null) { installment = rhi; } else if (rhi == null) { installment = lhi; } else { installment = new Installment { Number = lhi.Number, StartDate = lhi.StartDate, ExpectedDate = lhi.ExpectedDate, //RepaymentDate = lhi.RepaymentDate, CapitalRepayment = lhi.CapitalRepayment + rhi.CapitalRepayment, InterestsRepayment = lhi.InterestsRepayment + rhi.InterestsRepayment, OLB = lhi.OLB + rhi.OLB, }; } result.Add(installment); } result[0].InterestsRepayment += GetExtraInterest(schedule, scheduleConfiguration, trancheConfiguration); return result; }
private List<Installment> AssembleTranche(Loan loan, IScheduleConfiguration scheduleConfiguration, ITrancheConfiguration trancheConfiguration) { var schedule = loan.InstallmentList; var trancheSchedule = BuildTranche(schedule, loan, scheduleConfiguration, trancheConfiguration); // Get an interested paid in advance, whereas "in advance" means after the new tranche date var overpaidInterest = ( from installment in schedule where installment.ExpectedDate > trancheConfiguration.StartDate select installment ).Sum(installment => installment.PaidInterests.Value); // Get the part of the schedule that comes before the tranche date... var newSchedule = from installment in schedule where installment.ExpectedDate <= trancheConfiguration.StartDate select installment; // ...and force close it (set expected equal to paid) var olbDifference = 0m; foreach (var installment in newSchedule) { installment.OLB += olbDifference; olbDifference += installment.CapitalRepayment.Value - installment.PaidCapital.Value; if (!(installment.CapitalRepayment == installment.PaidCapital && installment.InterestsRepayment == installment.PaidInterests)) { installment.PaidDate = trancheConfiguration.StartDate; } installment.CapitalRepayment = installment.PaidCapital; installment.InterestsRepayment = installment.PaidInterests; } // Adjust the new schedule's installment numbers var increment = newSchedule.Count(); foreach (var installment in trancheSchedule) { installment.Number += increment; } var result = new List<Installment>(); result.AddRange(newSchedule); // Distribute the overpaid interest foreach (var installment in trancheSchedule) { if (installment.InterestsRepayment < overpaidInterest) { installment.PaidInterests = installment.InterestsRepayment; overpaidInterest -= installment.InterestsRepayment.Value; } else { installment.PaidInterests = overpaidInterest; break; } } result.AddRange(trancheSchedule); return result; }
public decimal GetAdjustment(List<Installment> schedule, IScheduleConfiguration configuration) { return configuration.Amount - schedule.Sum(i => i.CapitalRepayment.Value); }