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);
            }
        }