public static IEnumerable<AmortizedInstallment> Amortization(Money amount, int annualCompoundings, decimal rate, decimal minPayRate, Money paymentFloor, PayoffMode payMode) { decimal ratePerPeriod = rate / annualCompoundings; Money remaining = amount; var baseAmortization = from p in Enumerable.Range (1, int.MaxValue) let interest = remaining * ratePerPeriod let subBalance = remaining + interest let basePay = remaining * minPayRate let minPay = payMode == PayoffMode.PercentPlusInterest ? basePay + interest : basePay let adjustedPay = minPay < paymentFloor ? paymentFloor : minPay let actualPay = adjustedPay > subBalance ? subBalance : adjustedPay select new AmortizedInstallment { Installment = p, Interest = interest, Payment = actualPay, BeforePayment = remaining += interest, Balance = remaining -= actualPay }; return baseAmortization.TakeWhile (x => x.BeforePayment > 0); }
public Money ConvertToLocal(Money amount) { if (amount.CurrencyCode == NSLocale.CurrentLocale.CurrencyCode) return amount; if (Rates.ContainsKey(NSLocale.CurrentLocale.CurrencyCode)) return Money.NewMoney(amount.Value * Rates[NSLocale.CurrentLocale.CurrencyCode], NSLocale.CurrentLocale.CurrencyCode); // In this app, we're going to fail-back to the current amount rather than raise an exception return amount; }
public Money ConvertToGiven(Money amount, string currencyCode) { if (amount.CurrencyCode.Equals(currencyCode, StringComparison.OrdinalIgnoreCase)) return amount; if (!Rates.ContainsKey (currencyCode)) return amount; Money asBase = ConvertToBase(amount); return new Money (asBase.Value * Rates[currencyCode], currencyCode); }
public Money ConvertToBase(Money amount) { if (amount.CurrencyCode == BaseCurrency) return amount; if (Rates.ContainsKey(amount.CurrencyCode)) return Money.NewMoney(amount.Value * (1 / Rates[amount.CurrencyCode]), BaseCurrency); // Can't convert to base? We'll return the original amount, the upstream code will need to handle exception return amount; }
public ConsequenceRequest(Money amount, TriggerType mode) { this.InitialAmount = amount; this.TriggerMode = mode; }
public override ConsequenceResult Calculate(ConsequenceRequest request) { if (request.InitialAmount == 0 || request.InitialAmount < LowerThreshold || request.InitialAmount > UpperThreshold) return null; try { Money localizedMinPayment = ExchangeRates.CurrentRates.ConvertToGiven(MinimumPayment, request.InitialAmount.CurrencyCode); var amortization = Financials.Amortization (request.InitialAmount, CompoundingsPerYear (Compounding), PercentAsDecimal (Rate), PercentAsDecimal (MinPayPercent), localizedMinPayment, PayoffMode); int installments = 0; Money totalInterest = new Money(0, request.InitialAmount.CurrencyCode); foreach (var i in amortization) { installments++; totalInterest += i.Interest; } Money payoff = request.InitialAmount + totalInterest; return new ConsequenceResult (this, request, payoff, new TabularResult ( request.Summary, String.Format ("Amortization of a {0} loan at {1}%", request.InitialAmount, Rate), this), FormatCaption (this.Caption, new Dictionary<string,string> { {"Periods", installments.ToString()}, {"Interest", totalInterest.ToString()} } ), this.Image, (payoff >= LowerResultLimit && payoff <= UpperResultLimit)); } catch (Exception ex) { Console.WriteLine("{0} thrown when computing loan payoff: {1}", ex.GetType().Name, ex.Message); return new ConsequenceResult(this, request, null, "Oops, something went wrong in this calculator", this.Image, false); } }