public class MortgageFunctions{ // Private Static Constants private static final int SIGNIFICANTDIGITS = 7; private static final double MONTHLY = 6; private static final double SEMIMONTHLY = 12; private static final double BIWEEKLY = 13.028; private static final double WEEKLY = 26.053; private static final double SNI_MONTHLY = Round(1./MONTHLY,SIGNIFICANTDIGITS); private static final double SNI_SEMIMONTHLY = Round(1./SEMIMONTHLY,SIGNIFICANTDIGITS); private static final double SNI_BIWEEKLY = Round(1./BIWEEKLY,SIGNIFICANTDIGITS); private static final double SNI_WEEKLY = Round(1./WEEKLY,SIGNIFICANTDIGITS); // Public Constants public static final int MORTGAGETYPE_MONTHLY = 1; public static final int MORTGAGETYPE_SEMIMONTHLY = 2; public static final int MORTGAGETYPE_BIWEEKLY = 3; public static final int MORTGAGETYPE_WEEKLY = 4; public static final int MORTGAGETYPE_VARIABLE = 5; public static final int CALCULATEUSING_TERM = 1; public static final int CALCULATEUSING_PAYMENT = 2; public static final int GRAPHVALUES_LIMIT = 25; // Private attributes (variables) private double MortgageType; private double Principal; private double InterestRate; private double TermInYears; private double AccumulationFactorToUse; private double InterestConversionPeriod; private double Payment; private double OutStandingPrincipal; private double PrincipalAmount; private double InterestAmount; private double TotalInterest; private boolean PaymentWillCoverInterest = true; private double GraphValues[][] = new double[GRAPHVALUES_LIMIT][2]; // // Main constructor // public MortgageFunctions(int mortgageType, double principal, double interestRate, double termInYears, double payment, int calculateUsing){ double discountFactor; double accumulationFactor; double interestRatePerConversionPeriod; double numberOfInterestConversionPeriods; // Initialize MortgageType = mortgageType; Principal = principal; InterestRate = interestRate; TermInYears = termInYears; Payment = payment; OutStandingPrincipal = Principal; // Select the type of Mortgage ... Set the AccumulationFactorToUse // and the InterestConversionPeriod switch (mortgageType) { case MORTGAGETYPE_MONTHLY: AccumulationFactorToUse = SNI_MONTHLY; InterestConversionPeriod = MONTHLY; break; case MORTGAGETYPE_SEMIMONTHLY: AccumulationFactorToUse = SNI_SEMIMONTHLY; InterestConversionPeriod = SEMIMONTHLY; break; case MORTGAGETYPE_BIWEEKLY: AccumulationFactorToUse = SNI_BIWEEKLY; InterestConversionPeriod = BIWEEKLY; break; case MORTGAGETYPE_WEEKLY: AccumulationFactorToUse = SNI_WEEKLY; InterestConversionPeriod = WEEKLY; break; default: AccumulationFactorToUse = SNI_MONTHLY; InterestConversionPeriod = MONTHLY; } // Calculate the interest rate per conversion period ... based on the type of mortgage interestRatePerConversionPeriod = Round(InterestRate / 2.,SIGNIFICANTDIGITS); // if we are going to calculate the TERM based on the payment ... lets find it first if (calculateUsing == CALCULATEUSING_PAYMENT){ TermInYears = CalculateAmortizationPeriodRemaining(Principal,Payment); // IF the payment will not cover the intereset ... return know if (!PaymentWillCoverInterest) return; } // Now we can calculate the number of interest conversion perions numberOfInterestConversionPeriods = Round(TermInYears * 2.,SIGNIFICANTDIGITS); /* ** Calculate Payment **/ // Calculate the discount factor discountFactor = CalculateDiscountFactor(interestRatePerConversionPeriod, numberOfInterestConversionPeriods); // Calculation the accumulation factor accumulationFactor = CalculateAccumulationFactor(interestRatePerConversionPeriod,AccumulationFactorToUse); // Calculation the payment and return Payment = Round((Principal/discountFactor),SIGNIFICANTDIGITS) * accumulationFactor; // Calculation of total interest along with the Graph Values TotalInterest = 0.; double t; int paymentsInAYear = (int) java.lang.Math.round(InterestConversionPeriod*2); int payments=0; int graphIndex = 0; while(OutStandingPrincipal>0){ ApplyPayment(); TotalInterest += InterestAmount; payments++; if (payments == paymentsInAYear){ GraphValues[graphIndex][0] = PrincipalAmount; GraphValues[graphIndex][1] = InterestAmount; graphIndex++; payments = 0; } } if (graphIndex < 24){ for (;graphIndex<25;graphIndex++){ GraphValues[graphIndex][0] = 0.; GraphValues[graphIndex][1] = 0.; } } OutStandingPrincipal = Principal; } // Get what the payment is going to be. public double getPayment( ){ return Payment; } // Get how long the term is public double getTerm(){ return TermInYears; } // Get indicator to determine if payment will cover interest public boolean getWillPaymentCoverInterest(){ return PaymentWillCoverInterest; } // Get what the total interest will be out public double getTotalInterest(){ return TotalInterest; } // Apply Payment ... Returns outstanding balance. public double ApplyPayment(){ // Get the interest factor double interestFactor = getInterestFactor(); // Make sure payment will cover interest if ((Payment - Round(OutStandingPrincipal * interestFactor,2)) <= .01){ PaymentWillCoverInterest = false; return -1.; } // Calculate effect of making payment InterestAmount = Round(OutStandingPrincipal * interestFactor,2); PrincipalAmount = Payment - InterestAmount; OutStandingPrincipal = OutStandingPrincipal - PrincipalAmount; // Return the outstanding balance. return OutStandingPrincipal; } // Calculate Approximate Amortization period remaining on a mortgage & and the total interest public double CalculateAmortizationPeriodRemaining(double remainingMortgage, double payment){ int numberOfInterestConversionPeriods=0; double interestFactor; // Get the interest factor interestFactor = getInterestFactor(); // Make sure payment will cover interest if ((payment - Round(remainingMortgage * interestFactor,2)) <= .01){ PaymentWillCoverInterest = false; return -1.; } // WHILE there is enough of the mortgage to extract a payment. while (remainingMortgage > 0){ InterestAmount = Round(remainingMortgage * interestFactor,2); PrincipalAmount = payment - InterestAmount; remainingMortgage = remainingMortgage - PrincipalAmount; numberOfInterestConversionPeriods++; } // Return the number years remaining based on the InterestConversionPeriod return Round(numberOfInterestConversionPeriods/(InterestConversionPeriod*2.),2); } // get the Graph Values public double[][] getGraphValues(){ return GraphValues; } // Calculate the discount factor. private double CalculateDiscountFactor(double interestRatePerConversionPeriod, double numberOfInterestConversionPeriods){ double interestRate = Round(interestRatePerConversionPeriod/100.,SIGNIFICANTDIGITS); return Round((1.- java.lang.Math.pow(1. + interestRate,-numberOfInterestConversionPeriods)) / interestRate,SIGNIFICANTDIGITS); } // Calculate the accumulation factor private double CalculateAccumulationFactor(double interestRatePerConversionPeriod, double accumulationFactorToUse){ double interestRate = Round(interestRatePerConversionPeriod/100.,SIGNIFICANTDIGITS); return Round((java.lang.Math.pow((1. + interestRate),accumulationFactorToUse) - 1.) / interestRate,SIGNIFICANTDIGITS); } // Return the interest factor private double getInterestFactor(){ return Round(java.lang.Math.pow( 1 + ((InterestRate/2)/100),AccumulationFactorToUse) - 1.,SIGNIFICANTDIGITS); } // Utility functions public static double Round(double number, int significantDigits){ long rounded; double result; int factor=1; // Set up the number of significant digits to save. while(significantDigits>0){ factor*=10; significantDigits--; } // Calculate the rounded number. rounded = java.lang.Math.round(number*factor); result = ((double) rounded) /factor; return result; } }