/*************************************************************************** fin.c - description ------------------- begin : Thursday June 15 2000 email : tboldt@attglobal.net Author : Terry D. Boldt ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ /* * Functions to compute financial equations and amortization schedules * 6-15-2000 * */ /* * Financial Calculator * * This version for use WITH ANSI.SYS display driver * * This is a complete financial computation utility to solve for the * five * standard financial values: n, %i, PV, PMT and FV * * n == number of payment periods * %i == nominal interest rate, NAR, charged * PV == Present Value * PMT == Periodic Payment * FV == Future Value * * In addition, two additional parameters may be specified: * * 1) Compounding Frequency per year, CF. The compounding frequency * per year may be discrete or continuous and may be different from * the Payment Frequency per year * * 2) Payment Frequency per year, PF. Payments may be made at the * beginning or the end of the payment period. * * When an amortization schedule is desired, the financial * transaction Effective Date, ED, and Initial Payment Date, IP, must * also be entered. * * Canadian and European style mortgages can be handled in a simple, * straight-forward manner. Standard financial sign conventions are * used: * * "Money paid out is Negative, Money received is Positive" * * Time value of money: * * If you borrow money, you can expect to pay rent or interest for its use; * conversely you expect to receive rent interest on money you loan or invest. * When you rent property, equipment, etc., rental payments are normal; this * is also true when renting or borrowing money. Therefore, money is * considered to have a "time value". Money available now, has a greater value * than money available at some future date because of its rental value or the * interest that it can produce during the intervening period. * * Simple Interest: * * If you loaned $800 to a friend with an agreement that at the end of one * year he would would repay you $896, the "time value" you placed on your * $800 (principal) was $96 (interest) for the one year period (term) of the * loan. This relationship of principal, interest, and time (term) is most * frequently expressed as an Annual Percentage Rate (APR). In this case the * APR was 12.0% [(96/800)*100]. This example illustrates the four basic * factors involved in a simple interest case. The time period (one year), * rate (12.0% APR), present value of the principal ($800) and the future * value of the principal including interest ($896). * * Compound Interest: * * In many cases the interest charge is computed periodically during the term * of the agreement. For example, money left in a savings account earns * interest that is periodically added to the principal and in turn earns * additional interest during succeeding periods. The accumulation of interest * during the investment period represents compound interest. If the loan * agreement you made with your friend had specified a "compound interest * rate" of 12% (compounded monthly) the $800 principal would have earned * $101.46 interest for the one year period. The value of the original $800 * would be increased by 1% the first month to $808 which in turn would be * increased by 1% to 816.08 the second month, reaching a future value of * $901.46 after the twelfth iteration. The monthly compounding of the nominal * annual rate (NAR) of 12% produces an effective Annual Percentage Rate (APR) * of 12.683% [(101.46/800)*100]. Interest may be compounded at any regular * interval; annually, semiannually, monthly, weekly, daily, even continuously * (a specification in some financial models). * * Periodic Payments: * * When money is loaned for longer periods of time, it is customary for the * agreement to require the borrower to make periodic payments to the lender * during the term of the loan. The payments may be only large enough to repay * the interest, with the principal due at the end of the loan period (an * interest only loan), or large enough to fully repay both the interest and * principal during the term of the loan (a fully amoritized loan). Many loans * fall somewhere between, with payments that do not fully cover repayment of * both the principal and interst. These loans require a larger final payment * (balloon) to complete their amortization. Payments may occur at the * beginning or end of a payment period. If you and your friend had agreed on * monthly repayment of the $800 loan at 12% NAR compounded monthly, twelve * payments of $71.08 for a total of $852.96 would be required to amortize the * loan. The $101.46 interest from the annual plan is more than the $52.96 * under the monthly plan because under the monthly plan your friend would not * have had the use of $800 for a full year. * * Financial Transactions: * * The above paragraphs introduce the basic factors that govern most * financial transactions; the time period, interest rate, present value, * payments and the future value. In addition, certain conventions must be * adhered to: the interest rate must be relative to the compounding frequency * and payment periods, and the term must be expressed as the total number of * payments (or compounding periods if there are no payments). Loans, leases, * mortgages, annuities, savings plans, appreciation, and compound growth are * among the many financial problems that can be defined in these terms. Some * transactions do not involve payments, but all of the other factors play a * part in "time value of money" transactions. When any one of the five (four * - if no payments are involved) factors is unknown, it can be derived from * formulas using the known factors. * * Standard Financial Conventions Are: * * Money RECEIVED is a POSITIVE value and is represented by an arrow * above * the line * * Money PAID OUT is a NEGATIVE value and is represented by an arrow * below * the line. * * If payments are a part of the transaction, the number of payments * must * equal the number of periods (n). * * Payments may be represented as occurring at the end or beginning of * the * periods. * * Diagram to visualize the positive and negative cash flows (cash * flow * diagrams): * * Amounts shown above the line are positive, received, and amounts * shown below the line are negative, paid out. * * 1) * FV* * 1 2 3 4 . . . . . . . . . n ³ * Period ÚÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ * ³ * * PV * * Appreciation * Depreciation * Compound Growth * Savings Account * * **************************************************************************** * * 2) FV * PV = 0 * ³ * Period ÚÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÙ * ³ 1 ³ 2 ³ 3 ³ 4 ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ n * * PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT * * Annuity (series of payments) * Pension Fund * Savings Plan * Sinking Fund * * **************************************************************************** * * 3) * PV * ³ FV=0 * Period ÀÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄÂÄÄÄ¿ * 1 ³ 2 ³ 3 ³ 4 ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ n ³ * * PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT * * Amortization * Direct Reduction Loan * Mortgage (fully amortized) * * **************************************************************************** * * 4) * FV* * PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT PMT ³ + * PMT * 1 ³ 2 ³ 3 ³ 4 ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ . ³ n ³ * Period ÚÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÁÄÄÄÙ * ³ * * PV * * Annuity * Lease (with buy back or residual)* * Loan or Mortgage (with balloon)* * * **************************************************************************** * * First lets discuss interest before discussing the financial * equation. Most financial transactions utilize a nominal interest * rate, NAR, i.e., the interest rate per year. The NAR must be * converted to the interest rate per payment interval and the * compounding accounted for before it can be used in computing an * interest payment. After this conversion process, the interest * used is the effective interest rate, EIR. In converting NAR to * EIR, there are two concepts to discuss first, the Compounding * Frequency and the Payment Frequency and * whether the interest is * coumpounded in discrete intervals or continuously. The * compounding Frequency, CF, is simply the number of times per * year, the monies in the financial transaction are compounded. In * the U.S., monies are usually compounded daily on bank deposits, * and monthly on loans. Somtimes Long term deposits are compounded * quarterly or weekly. * * The Payment Frequency, PF, is simply how often during a year * payments are made in the transaction. Payments are usually * scheduled on a regular basis and can be made at the beginning or * end of the payment period. If made at the beginning of the * payment period, interest must be applied to the payment as well * as any previous money paid or money still owed. * * Normal values for CF and PF are: * 1 == annual * 2 == semi-annual * 3 == tri-annual * 4 == quaterly * 6 == bi-monthly * 12 == monthly * 24 == semi-monthly * 26 == bi-weekly * 52 == weekly * 360 == daily * 365 == daily * * a) the Compounding Frequency per year, CF, need not be identical * to the Payment Frequency per year, PF, and/or, * * b) Interest may be compounded in either discrete intervals or continuously * compounded. * * c) Also, payments may be made at the beginning of the payment * period or at the end of the payment period. * * CF and PF are defaulted to 1. The default is for discrete interest * intervals and payments are defaulted to the end of the payment * period. * * When a solution for n, PV, PMT or FV is required, the nominal interest * rate, i, must first be converted to the effective interest rate per payment * period. This rate, ieff, is then used to compute the selected variable. To * convert i to ieff, the following expressions are used: * * Discrete interest periods: * * 19) ieff = (1 + i/CF)^(CF/PF) - 1 * * Continuous Interest * * 20) ieff = e^(i/PF) - 1 = exp(i/PF) - 1 * * When interest is computed, the computation produces the effective interest * rate, ieff. This value must then be converted to the nominal interest rate. * Function _I below returns the nominal interest rate NOT the effective * interest rate. ieff is converted to i using the following expressions: * * Discrete Case: * * i = CF*[(1+ieff)^(PF/CF) - 1] * * Continuous Case: * * i = ln[(1+ieff)^PF] * * **************************************************************************** * * NOTE: in the equations below for the financial transaction, all * interest rates are the effective interest rate, ieff. The symbol * will be shortned to just 'i'. * * **************************************************************************** * * The basic financial equation used is: * * 1) PV*(1 + i)^n + PMT*(1 + iX)*[(1+i)^n - 1]/i + FV = 0 * Where: X = 0 for end of period payments, and * X = 1 for beginning of period payments * * **************************************************************************** * * NOTE: this equation is derived in the following manner: * * Start with the basic equation to find the balance or Present * Value, PV[1], after one payment period. Note PV[1] is the Present * value after on payment and PV[0] is the initial Present * Value. PV[0] will be shortened to just PV. * * The interest due at the end of the first payment period is: * * ID[1] = (PV + X * PMT) * i * where: X = 0 for end of period payments, and * X = 1 for beginning of period payments. * * Thus: * PV[1] = PV + (PMT + ID[1]) * = PV + (PMT + (PV + X * PMT) * i) * = PV * (1 + i) + PMT * (1 + Xi) * * This equation works for all of the money diagrams shown * above. The Present Value, money received or paid, is modified by * a payment made at the beginning of a payment period and * multiplied by the effective interest rate to compute the interest * due during the payment period. The interest due is then added to * the payment to obtain the amount to be added to the Present Value * to compute the new Present Value. * * For diagram 1): PV < 0, PMT == 0, PV[1] < 0 * For diagram 2): PV == 0, PMT < 0, PV[1] < 0 * For Diagram 3): PV > 0, PMT < 0, PV[1] >= 0 or PV[1] <= 0 * For Diagram 4): PV < 0, PMT > 0, PV[1] <= 0 or PV[1] >= 0 * * X may be 0 or 1 for any diagram. * * For the standard loan, PV is the money borrowed, PMT is the * periodic payment to repay the loan and i is the effective * interest rate agreed upon. * * To calculate the Present Value after the second payment period, * the above calculation is applied iteratively to PV_1: * * PV[2] = PV[1] + (PMT + (PV[1] + X * PMT) * i) * = PV[1] * (1 + i) + PMT * (1 + iX) * = (PV * (1 + i) + PMT * (1 + iX)) * (1 + i) + PMT * (1 + iX) * = PV * (1 + i)^2 + PMT * (1 + iX) * (1 + i) * + PMT * (1 + iX) * * Similarly: * * PV[3] = PV[2] + (PMT + (PV[2] + X * PMT) * i) * = PV[2] * (1 + i) + PMT * (1 + iX) * = PV * (1 + i)^2 + PMT * (1 + iX) * (1 + i) * + PMT * (1+ iX)) * ( 1 + i) * + PMT * (1+ iX) * = PV * (1 + i)^3 + PMT * (1 + iX) * (1 + i)^2 * + PMT * (1 + iX) * (1 + i)^2 * + PMT * (1 + iX) * (1 + i) * + PMT * (1 + iX) * * And for the n'th payment: * * PV[n] = PV[n-1] + (PMT + (PV[n-1] + X * PMT) * i) * PV[n] = PV * (1 + i)^n + PMT * (1 + iX) * (1 + i)^(n-1) * + PMT * (1 + iX) * (1 + i)^(n-2) + * . * . * . * + PMT * (1 + iX) * (1 + i) * + PMT * (1 + iX) * PV[n] = PV * (1 + i)^n + PMT * (1 + iX) * [(1 + i)^(n-1) + ... * + (1 + i) + 1] * * **************************************************************************** * * The sum of the finite series: * * 1 + k + (k^2) + (k^3) + ... + (k^n) = (1-k^(n+1))/(1-k) * * as can be seen by the following. Let S(n) be the series sum. Then * * S(n) - k * S(n) = 1 - k^(n+1) * * and solving for S(n): * * S(n) = [1-k^(n+1)]/[1-k] = 1 + k + (k^2) + (k^3) + ... + (k^n) * * **************************************************************************** * * PV[n] = PV * (1 + i)^n + PMT * (1 + iX) * [(1 + i)^(n-1) + ... * + (1 + i) + 1] * = PV * (1 + i)^n + PMT * (1 + iX) * [1 - (1 + i)^n]/[1 - (1 + i)] * = PV * (1 + i)^n + PMT * (1 + iX) * [1 - (1 + i)^n]/[-i] * = PV * (1 + i)^n + PMT * (1 + iX) * [(1 + i)^n - 1]/i * * The formaula for PV[n] can be proven using mathematical induction. * * or: * * PV * (1 + i)^n + PMT * [(1 + i)^n - 1]/i - PV[n] = 0 * * If after n payments, the remaining balance is repaid as a lump * sum, the lump sum is known as the Future Value, FV[n]. Since * FV[n] is negative if paid and positive if received, FV[n] is the * negative of PV[n]. Since n is assumed to be the last payment, * FV[n] will be shortened to simply FV. * * Setting: FV = -PV[N] * * 1) PV*(1 + i)^n + PMT*(1 + iX)*[(1 + i)^n - 1]/i + FV = 0 * * Up to this point, we have said nothing about the value of * PMT. PMT can be any value mutually agreed upon by the lender and * the borrower. From the equation for PV[1]: * * PV[1] = PV + (PMT + (PV + X * PMT) * i), * * Several things can be said about PMT. * * 1. If PMT = PV * i, and X = 0 (end of period payments): * * The payment is exactly equal to the interest due and PV[1] = * PV. In this case, the borrower must make larger future * payments to reduce the balance due, or make a single payment, * after some agreed upon number of payments, with PMT = PV to * completely pay off the loan. This is an interest only payment * with a balloon payment at the end. * * 2. If PMT < PV * i, and X = 0 * * The payment is insufficient to cover even the interest charged * and the balance due grows * * 3. If PMT > PV * i, and X = 0 * * The payment is sufficient to cover the interest charged with a * residual amount to be applied to reduce the balance due. The * larger the residual amount, the faster the loan is repaid. For * most mortgages or other loans made today, the lender and * borrower agree upon a certain number of repayment periods and * the interest to be charged per payment period. The interest * may be multiplied by 12 and stated as an annual interest * rate. Then the lender and borrower want to compute a periodic * payment, PMT, which will reduce the balance due to zero after * the agreed upon number of payment have been made. If N is the * agreed upon number of periodic payments, then we want to use: * * PV * (1 + i)^N + PMT*(1 +iX)*[(1 + i)^N - 1]/i + FV = 0 * * with FV = 0 to compute PMT: * * PMT = -[PV * i * (1 + i)^(N - X)]/[(1 + i)^N - 1] * * The value of PMT computed will reduce the balance due to zero * after N periodic payments. * * **************************************************************************** * * * With a simple alegebraic re-arrangement, The financial Equation becomes: * * 2) [PV + PMT*(1 + iX)/i][(1 + i)^n - 1] + PV + FV = 0 * * or * * 3) (PV + C)*A + PV + FV = 0 * * where: * 4) A = (1 + i)^n - 1 * * 5) B = (1 + iX)/i * * 6) C = PMT*B * * The form of equation 3) simplifies the calculation procedure for all five * variables, which are readily solved as follows: * * 7) n = ln[(C - FV)/(C + PV)]/ln((1 + i) * * 8) PV = -[FV + A*C]/(A + 1) * * 9) PMT = -[FV + PV*(A + 1)]/[A*B] * * 10) FV = -[PV + A*(PV + C)] * * Equations 4), 5) and 6) are computed by functions: * * _A * _B * _C * * respectively. Equations 7), 8), 9) and 10) are computed by functions: * * _N * _PV * _PMT * _FV * * respectively. * * The solution for interest is broken into two cases: * * PMT == 0 * i = [FV/PV]^(1/n) - 1 * * PMT != 0 * * Since equation 3) cannot be solved explicitly for i in this * case, an iterative technique must be employed. Newton's * method, using exact expressions for the function of i and its * derivative, are employed. The expressions are: * * 12) i[k+1] = i[k] - f(i[k])/f'(i[k]) * where: i[k+1] == (k+1)st iteration of i * i[k] == kth iteration of i * and: * * 13) f(i) = A*(PV+C) + PV + FV * * 14) f'(i) = n*D*(PV+C) - (A*C)/i * * 15) D = (1 + i)^(n-1) = (A+1)/(1+i) * * To start the iterative solution for i, an initial guess must be made * for the value of i. The closer this guess is to the actual value, * the fewer iterations will have to be made, and the greater the * probability that the required solution will be obtained. The initial * guess for i is obtained as follows: * * if PMT*FV >= 0, then PV case * if PMT*FV < 0, then FV case * * PV case: * | n*PMT + PV + FV | * 16) i[0] = | ----------------| * | n*PV | * * = abs[(n*PMT + PV + FV)/(n*PV)] * * FV case: * a) PV != 0 * * | FV - n*PMT | * 17) i[0] = |---------------------------| * | 3*[PMT*(n-1)^2 + PV - FV] | * * = abs[(FV-n*PMT)/(3*(PMT*(n-1)^2+PV-FV))] * b) PV == 0 * * | FV + n*PMT | * 18) i[0] = |---------------------------| * | 3*[PMT*(n-1)^2 + PV - FV] | * * = abs[(FV+n*PMT)/(3*(PMT*(n-1)^2+PV-FV))] * * **************************************************************************** * Constant payment to principal loan * * In this loan, each total payment is different, with each * succeeding payment less than the preceding payment. Each payment * is the total of the constant amount to the principal plus the * interest for the period. The constant payment to the principal is * computed as: * * C = -PV / N * * Where PV is the loan amount to be repaid in N payments * (periods). Note that the constant payment to principal could be * any value agreed to by the two parties involved. * * Thus the principal after the first payment is: * PV[1] = PV[0] + C = PV + C * after the second payment, the principal is: * PV[2] = PV[1] + C = PV[0] + 2C * In general, the remaining principal after n payments is: * PV[n] = PV[0] + nC = PV + nC * * If the effective interest per payment period is i, then the * interest for the first payment is: * * I[1] = -i*PV[0] = -i*PV * and for the second: * I[2] = -i * PV[1] * and in general, for the n'th payment the interest is: * I[n] = -i * PV[n-1] * = -i * (PV + (n-1)C) * The total payment for any period, n, is: * P[n] = C + I[n] * = C + i * (PV + (n-1)C) * = C(1 + i) - i * (PV + nC) * The total interest paid to period n is: * T[n] = I[1] + I[2] + I[3] + ... + I[n] * T[n] = sum(j = 1 to n: I[j]) * T[n] = sum(j = 1 to n: -i * (PV + (j-1)C)) * T[n] = sum(j=1 to n: -i*PV) + sum(j=1 to n: iC) + sum(j=1 to n: -iCj) * T[n] = -i*n*PV + i*n*C - i*C*sum(j=1 to n:j) * sum(j=1 to n:j) = n(n+1)/2 * T[n] = -i*n*(PV + C) - i*C*n(n+1)/2 * T[n] = -i*n*(PV + (C*(n - 1)/2)) * * Note: substituing for C = -PV/N, in the equations for PV[n], I[n], * P[n], and T[n] would give the following equations: * * PV[n] = PV*(1 - n/N) * I[n] = -i*PV*(1 + N - n)/N * P[n] = -i*PV*(2 + N - n)/N * T[n] = -i*n*PV*(2*N - n + 1)/(2*N) * * Using these equations for the calculations would eliminate the * dependence on C, but only if C is always defined as above and * would eliminate the possibility of another value for C. If the * value of C was less than -PV/N then a balloon payment would be * due at the final payment and this is a possible alternative for * some people. * * **************************************************************************** * * Amortization Schedules. * * Financial Transactions have an effective Date, ED, and an Initial Payment * Date, IP. ED may or may not be the same as IP, but IP is always the same * or later than ED. Most financial transaction calculators assume that * IP is equal to ED for beginning of period payments or at the end of the * first payment period for end of period payments. * * This is not always true. IP may be delayed for financial reasons * such as cash flow or accounting calendar. The subsequent payments * then follow the agreed upon periodicity. Since money has a time * value, the "delayed" IP must be accounted for. Computing an * "Effective PV", pve, is one means of handling a delayed IP. * * EDj == the Julian Day Number of ED, and * IPj == the Julian Day Number of IP in the following. * * pve is be computed as: * * pve = pv*(1 + i)^(s*PF/d*CF) * * Where: d = length of the payment period in days, and * s = IPj - EDj - d*X * * Computing an amortization Schedule for a given financial transaction is * simply applying the basic equation iteratively for each payment period: * * PV[n] = PV[n-1] + (PMT + (PV[n-1] + X * PMT) * i) * * At the end of each iteration, PV[n] is rounded to the nearest cent. For * each payment period, the interest due may be computed separately as: * * ID[n] = (PMT + (PV[n-1] + X * PMT) * i) * * and rounded to the nearest cent. PV[n] then becomes: * * PV[n] = PV[n-1] + PMT + ID[n] * * For those cases where a yearly summary only is desired, it is not * necessary to compute each transaction for each payment period, * rather the PV may be computed for the beginning of each year, * PV[yr], and the FV computed for the end of the year, FV[yr]. The * interest paid during the year is the computed as: * * ID[yr] = (NP * PMT) + PV[yr] + FV[yr] * * Since the final payment may not be equal to the periodic payment, * the final payment must be computed separately as follows. Two * derivations are given below for the final payment equation. Both * derivations are given below since one or the other may be clearer * to some readers. Both derivations are essentially the same, they * just have different starting points. The first is the fastest. * * 1) final_pmt == final payment @ payment n == int(n) * from above the basic financial equation: * PV[n] = PV[n-1]*(1 + i) + final_pmt * (1 + iX), * i == effective interest rate * * solving for final_pmt, we have: * * final_pmt * (1 + iX) = PV[n] - PV[n-1]*(1 + i) * = FV[n-1]*(1 + i) - FV[n] * final_pmt = FV[n-1]*(1+i)/(1 + iX) - FV[n]/(1 + iX) * * final_pmt = FV[n-1]*(1 + i) - FV[n], * for X == 0, end of period payments * * = FV[n-1] - FV[n]/(1 + i), * for X == 1, beginning of period payments * * 2) final_pmt == final payment @ payment n == int(n) * i[n] == interest due @ payment n * i[n] = (PV[n-1] + X * final_pmt) * i, i == effective interest rate * = (X * final_pmt - FV[n]) * i * * Now the final payment is the sum of the interest due, plus * the present value at the next to last payment plus any * residual future value after the last payment: * * final_pmt = -i[n] - PV[n-1] - FV[n] * = FV[n-1] - i[n] - FV[n] * = FV[n-1] - (X *final_pmt - FV[n-1])*i - FV[n] * = FV[n-1]*(1 + i) - X*final_pmt*i - FV[n] * * solving for final_pmt: * final_pmt*(1 + iX) = FV[n-1]*(1 + i) - FV[n] * final_pmt = FV[n-1]*(1 + i)/(1 + iX) - FV[n]/(1 + iX) * * final_pmt = FV[n-1]*(1 + i) - FV[n], * for X == 0, end of period payments * * = FV[n-1] - FV[n]/(1 + i), * for X == 1, beginning of period payments * *============================================================================ * * The amortization schedule is computed for four different situations: * * 1) The original financial data is used. This ignores any possible * agjustment to the Present value due to any delay in the initial * payment. This is quite common in mortgages where end of period * payments are used and the first payment is scheduled for the end * of the first whole period, i.e., any partial payment period from * ED to the beginning of the next payment period is ignored. * * 2) The original periodic payment is used, the Present Value is * adjusted for the delayed Initial Payment. The total number of * payments remains the same. The final payment is adjusted to bring * the balance into agreement with the agreed upon final Future * Value. * * 3) A new periodic payment is computed based upon the adjusted * Present Value, the agreed originally upon number of total * payments and the agreed upon Future Value. The new periodic * payments are computed to minimize the final payment in accordance * with the Future Value after the last payment. * * 4) The original periodic payment is retained and a new number of * total payments is computed based upon the adjusted Present Value * and the agreed upon Future Value. * * The amortization schedule may be computed and displayed in three manners: * * 1. The payment *, interest paid, principal paid and remaining PV * for each payment period are computed and displayed. At the end of * each year a summary is computed and displayed and the total * interest paid is diplayed at the end. * * 2. A summary is computed and displayed for each year. The * interest paid during the year is computed and displayed as well * as the remaining balance at years end. The total interest paid * is diplayed at the end. * * 3. An amortization schedule is computed for a common method of * advanced payment of principal is computed and displayed. In this * amortization, the principal for the next payment is computed and * added into the current payment. This method will cut the number * of total payments in half and will cut the interest paid almost * in half. For mortgages, this method of prepayment has the * advantage of keeping the total payments small during the initial * payment periods The payments grow until the last payment period * when presumably the borrower can afford larger payments. * * =========================================================================== * NOTE: For Payment Frequencies, PF, semi-monthly or less, i.e., PF * == 12 or PF == 24, a 360 day calendar year and 30 day month are * used. For Payment Frequencies, PF, greater than semi-monthly, PF * > 24, the actual number of days per year and per payment period * are used. The actual values are computed using the built-in * 'julian_day_number' function * * **************************************************************************** * * Note: in the following examples, the user input is preceded by the * prompt "<>". The result of evaluating the input expression is then * displayed. I have taken the liberty of including comments in the * example input/output sessions by preceding with ' *'. Thus, for * the line: <>n=5 *set number of periods the comment that setting the * number of periods is not really input and the true input is only: * <>n=5 * * Example 1: Simple Interest * Find annual simple interest rate (%) for an $800 loan to be repayed at the * end of one year with a single payment of $896. * <>d * <>CF=PF=1 * 1.00 * <>n=1 * 1.00 * <>pv=-800 * -800.00 * <>fv=896 * 896.00 * <>I * 12.00 * * Example 2: Compound Interest * Find the future value of $800 after one year at a nominal rate of 12% * compounded monthly. No payments are specified, so the payment frequency is * set equal to the compounding frequency at the default values. * <>d * <>n=12 * 12.00 * <>i=12 * 12.00 * <>pv=-800 * -800.00 * <>FV * 901.46 * * Example 3: Periodic Payment: * Find the monthly end-of-period payment required to fully amortize the loan * in Example 2. A fully amortized loan has a future value of zero. * <>fv=0 * 0.00 * <>PMT * 71.08 * * Example 4: Conventional Mortgage * * Find the number of monthly payments necessary to fully amortize a * loan of $100,000 at a nominal rate of 13.25% compounded monthly, if * monthly end-of-period payments of $1125.75 are made. * * <>d * <>i=13.25 * 13.25 * <>pv=100000 * 100,000.00 * <>pmt=-1125.75 * -1,125.75 * <>_N(i,pv,pmt,fv,CF,PF,disc,bep) * 360.10 * <>N * 360 * * Example 5: Final Payment * Using the data in example 4, find the amount of the final payment if n is * changed to 360. The final payment will be equal to the regular payment plus * any balance, future value, remaining at the end of period number 360. * <>n=360 * 360.00 * <>FV * -108.87 * <>pmt+fv * -1,234.62 * * Using the data from this loan, compute the amortization schedule * when the Effective date of the loan is June 6, 1996 and the * initial payment is made on August 1, 1996. Ignore any change in * the PV due to the delayed initial payment caused by the partial * payment period from June 6 to July 1. * * <>ED = 06/06/1996 * Effective Date set: 06/06/1996 ( 2450241 ) * <>IP = 08/01/1996 * Initial Payment Date set: 08/01/1996 ( 2450297 ) * <>a * Effective Date: 06/06/96 * Initial Payment Date: 08/01/96 * The amortization options are: * The Old Present Value (pv) was: 100,000.00 * The Old Periodic Payment (pmt) was: -1,125.75 * The Old Future Value (fv) was: -108.87 * 1: Amortize with Original Transaction Values * and balloon final payment: -1,125.75 * * The New Present Value (pve) is: 100,919.30 * The New Periodic Payment (pmt) is: -1,136.10 * 2: Amortize with Original Periodic Payment * and balloon final payment: -49,023.68 * 3: Amortize with New Periodic Payment * and balloon final payment: -1,132.57 * 4: Amortize with Original Periodic Payment, * new number of total payments (n): 417 * and final payment: -2,090.27 * * Enter choice 1, 2, 3 or 4: <> * * Press '1' * Amortization Schedule: * Yearly, y, per Payment, p, or Advanced Payment, a, Amortization * Enter choice y, p or a: * <> * * Press 'y' * Enter Filename for Amortization Schedule. * (null string uses Standard Output): * Press enter to display output on screen * * Amortization Table * Effective Date: Thu Jun 06 00:00:00 1996 * Initial Payment Date: Thu Aug 01 00:00:00 1996 * Compounding Frequency per year: 12 * Payment Frequency per year: 12 * Compounding: Discrete * Payments: End of Period * Payments (359): -1,125.75 * Final payment: -1,125.75 * Nominal Annual Interest Rate: 13.25 * Effective Interest Rate Per Payment Period: 0.0110417 * Present Value: 100,000.00 * Year Interest Ending Balance * 1996 -5,518.42 -99,889.67 * 1997 -13,218.14 -99,598.81 * 1998 -13,177.17 -99,266.98 * 1999 -13,130.43 -98,888.41 * 2000 -13,077.11 -98,456.52 * 2001 -13,016.28 -97,963.80 * 2002 -12,946.88 -97,401.68 * 2003 -12,867.70 -96,760.38 * 2004 -12,777.38 -96,028.76 * 2005 -12,674.33 -95,194.09 * 2006 -12,556.76 -94,241.85 * 2007 -12,422.64 -93,155.49 * 2008 -12,269.63 -91,916.12 * 2009 -12,095.06 -90,502.18 * 2010 -11,895.91 -88,889.09 * 2011 -11,668.70 -87,048.79 * 2012 -11,409.50 -84,949.29 * 2013 -11,113.78 -82,554.07 * 2014 -10,776.41 -79,821.48 * 2015 -10,391.53 -76,704.01 * 2016 -9,952.43 -73,147.44 * 2017 -9,451.49 -69,089.93 * 2018 -8,879.99 -64,460.92 * 2019 -8,227.99 -59,179.91 * 2020 -7,484.16 -53,155.07 * 2021 -6,635.56 -46,281.63 * 2022 -5,667.43 -38,440.06 * 2023 -4,562.94 -29,494.00 * 2024 -3,302.89 -19,287.89 * 2025 -1,865.36 -7,644.25 * 2026 -236.00 -108.87 * * Total Interest: -305,270.00 * * NOTE: The amortization table leaves the FV as it was when the amortization * function was entered. Thus, a balance of 108.87 is due at the end of the * table. To completely pay the loan, set fv to 0.0: * <>fv=0 * 0.0 * <>a * Effective Date: 06/06/96 * Initial Payment Date: 08/01/96 * The amortization options are: * The Old Present Value (pv) was: 100,000.00 * The Old Periodic Payment (pmt) was: -1,125.75 * The Old Future Value (fv) was: 0.00 * 1: Amortize with Original Transaction Values * and balloon final payment: -1,234.62 * * The New Present Value (pve) is: 100,919.30 * The New Periodic Payment (pmt) is: -1,136.12 * 2: Amortize with Original Periodic Payment * and balloon final payment: -49,132.55 * 3: Amortize with New Periodic Payment * and balloon final payment: -1,148.90 * 4: Amortize with Original Periodic Payment, * new number of total payments (n): 417 * and final payment: -2,199.14 * * Enter choice 1, 2, 3 or 4: <> * Press '1' * Amortization Schedule: * Yearly, y, per Payment, p, or Advanced Payment, a, Amortization * Enter choice y, p or a: * <> * Press 'y' * Enter Filename for Amortization Schedule. * (null string uses Standard Output): * Press enter to display output on screen * * Amortization Table * Effective Date: Thu Jun 06 00:00:00 1996 * Initial Payment Date: Thu Aug 01 00:00:00 1996 * Compounding Frequency per year: 12 * Payment Frequency per year: 12 * Compounding: Discrete * Payments: End of Period * Payments (359): -1,125.75 * Final payment: -1,234.62 * Nominal Annual Interest Rate: 13.25 * Effective Interest Rate Per Payment Period: 0.0110417 * Present Value: 100,000.00 * Year Interest Ending Balance * 1996 -5,518.42 -99,889.67 * 1997 -13,218.14 -99,598.81 * 1998 -13,177.17 -99,266.98 * 1999 -13,130.43 -98,888.41 * 2000 -13,077.11 -98,456.52 * 2001 -13,016.28 -97,963.80 * 2002 -12,946.88 -97,401.68 * 2003 -12,867.70 -96,760.38 * 2004 -12,777.38 -96,028.76 * 2005 -12,674.33 -95,194.09 * 2006 -12,556.76 -94,241.85 * 2007 -12,422.64 -93,155.49 * 2008 -12,269.63 -91,916.12 * 2009 -12,095.06 -90,502.18 * 2010 -11,895.91 -88,889.09 * 2011 -11,668.70 -87,048.79 * 2012 -11,409.50 -84,949.29 * 2013 -11,113.78 -82,554.07 * 2014 -10,776.41 -79,821.48 * 2015 -10,391.53 -76,704.01 * 2016 -9,952.43 -73,147.44 * 2017 -9,451.49 -69,089.93 * 2018 -8,879.99 -64,460.92 * 2019 -8,227.99 -59,179.91 * 2020 -7,484.16 -53,155.07 * 2021 -6,635.56 -46,281.63 * 2022 -5,667.43 -38,440.06 * 2023 -4,562.94 -29,494.00 * 2024 -3,302.89 -19,287.89 * 2025 -1,865.36 -7,644.25 * 2026 -344.87 0.00 * * Total Interest: -305,378.87 * * Example 6: Balloon Payment * On long term loans, small changes in the periodic payments can generate * large changes in the future value. If the monthly payment in example 5 is * rounded down to $1125, how much addtional (balloon) payment will be due * with the final regular payment. * <>pmt=-1125 * -1,125 * <>FV * -3,579.99 * * Example 7: Canadian Mortgage * Find the monthly end-of-period payment necessary to fully amortize a 25 year * $85,000 loan at 11% compounded semi-annually. * <>d * <>CF=2 * 2.00 * <>n=300 * 300.00 * <>i=11 * 11.00 * <>pv=85000 * 85,000.00 * <>PMT * -818.15 * * Example 8: European Mortgage * The "effective annual rate (EAR)" is used in some countries (especially * in Europe) in lieu of the nominal rate commonly used in the United States * and Canada. For a 30 year $90,000 mortgage at 14% (EAR), compute the monthly * end-of-period payments. When using an EAR, the compounding frequency is * set to 1. * <>d * <>CF=1 * 1.00 * <>n=30*12 * 360.00 * <>i=14 * 14.00 * <>pv=90000 * 90,000.00 * <>PMT * -1,007.88 * * Example 9: Bi-weekly Savings * Compute the future value, fv, of bi-weekly savings of $100 for 3 years at a * nominal annual rate of 5.5% compounded daily. (Set payment to * beginning-of-period, bep = TRUE) * <>d * <>bep=TRUE * 1.00 * <>CF=365 * 365.00 * <>PF=26 * 26.00 * <>n=3*26 * 78.00 * <>i=5.5 * 5.50 * <>pmt=-100 * -100.00 * <>FV * 8,489.32 * * Example 10: Present Value - Annuity Due * What is the present value of $500 to be received at the beginning of each * quarter over a 10 year period if money is being discounted at 10% nominal * annual rate compounded monthly? * <>d * <>bep=TRUE * 1.00 * <>PF=4 * 4.00 * <>n=4*10 * 40.00 * <>i=10 * 10.00 * <>pmt=500 * 500.00 * <>PV * -12,822.64 * * Example 11: Effective Rate - 365/360 Basis * Compute the effective annual rate (%APR) for a nominal annual rate of 12% * compounded on a 365/360 basis used by some Savings & Loan Associations. * <>d * <>n=365 * 365.00 * <>CF=365 * 365.00 * <>PF=360 * 360.00 * <>i=12 * 12.00 * <>pv=-100 * -100.00 * <>FV * 112.94 * <>fv+pv * 12.94 * * Example 12: Mortgage with "Points" * * What is the true APR of a 30 year, $75,000 loan at a nominal rate * of 13.25% compounded monthly, with monthly end-of-period payments, * if 3 "points" are charged? The pv must be reduced by the dollar * value of the points and/or any lenders fees to establish an * effective pv. Because payments remain the same, the true APR will * be higher than the nominal rate. Note, first compute the payments * on the pv of the loan amount. * * <>d * <>CF=PF=1 * 1.00 * <>n=30*12 * 360.00 * <>i=13.25/12 * 1.10 * <>pv=75000 * 75,000.00 * <>PMT * -844.33 * <>pv -= pv*.03 * 72,750.00 * <>CF=PF=12 * 12.00 * <>I * 13.69 * * Example 13: Equivalent Payments * Find the equivalent monthly payment required to amortize a 20 year $40,000 * loan at 10.5% nominal annual rate compounded monthly, with 10 annual * payments of $5029.71 remaining. Compute the pv of the remaining annual * payments, then change n, the number of periods, and the payment frequency, * PF, to a monthly basis and compute the equivalent monthly pmt. * <>d * <>PF=1 * 1.00 * <>n=10 * 10.00 * <>i=10.5 * 10.50 * <>pmt=-5029.71 * -5,029.71 * <>PV * 29,595.88 * <>PF=12 * 12.00 * <>n=120 * 120.00 * <>PMT * -399.35 * * Example 14: Perpetuity - Continuous Compounding * If you can purchase a single payment annuity with an initial investment of * $60,000 that will be invested at 15% nominal annual rate compounded * continuously, what is the maximum monthly return you can receive without * reducing the $60,000 principal? If the principal is not disturbed, the * payments can go on indefinitely (a perpetuity). Note that the term,n, of * a perpetuity is immaterial. It can be any non-zero value. * <>d * <>disc=FALSE * 0.00 * <>n=12 * 12.00 * <>CF=1 * 1.00 * <>i=15 * 15.00 * <>fv=60000 * 60,000.00 * <>pv=-60000 * -60,000.00 * <>PMT * 754.71 * * references: * 1. PPC ROM User's Manual * pages 148 - 164 * */ #include #include #include #include #if defined(G_OS_WIN32) && !defined(_MSC_VER) #include #endif #include #include #define FIN_STATICS #include "finvar.h" #include "finproto.h" #include "fin_static_proto.h" /* return 'x' rounded to 'places' past decimal if 'places' < 0, return * 'x' */ static double rnd (double x, unsigned places) { double r; char buf[50]; /* make buffer large enough */ sprintf (buf, "%.*f", (int) places, x); r = strtod(buf, NULL); return r; } /* rnd */ /* return absolute value of 'x' this function is provided by a macro * in C */ static double dabs (double x) { return (x >= 0.0) ? x : -x; } /* dabs */ /* Compute constant used in calculations */ static double _A (double eint, unsigned per) { return pow ((1.0 + eint), (double) per) - 1.0; } /* _A */ /* Compute constant used in calculations */ static double _B (double eint, unsigned beg) { /* if eint == 0.0, all processing _must_ stop or a recursive loop will start. */ g_return_val_if_fail(eint != 0.0, 0.0); return (1.0 + eint * (double) beg) / eint; } /* _B */ /* Compute constant used in calculations */ static double _C (double eint, double pmt, unsigned beg) { g_return_val_if_fail(eint != 0.0, 0.0); return pmt * _B(eint, beg); } /* _C */ /* compute Number of Periods from preset data */ unsigned fi_calc_num_payments (fi_ptr fi) { return fi->npp = (unsigned) rnd (_fi_calc_num_payments (fi->ir, fi->pv, fi->pmt, fi->fv, fi->CF, fi->PF, fi->disc, fi->bep), 0); } /* fi_calc_num_payments */ /* Compute number of periods from: * 1. Nominal Interest * 2. Present Value * 3. Periodic Payment * 4. Future Value */ double _fi_calc_num_payments (double nint, /* nominal interest rate */ double pv, /* present value */ double pmt, /* periodic payment */ double fv, /* future value */ unsigned CF, /* compounding frequency */ unsigned PF, /* payment frequency */ unsigned disc, /* discrete/continuous compounding */ unsigned bep) /* beginning/end of period payment */ { double eint = eff_int (nint / 100.0, CF, PF, disc); double CC = _C (eint, pmt, bep); CC = (CC - fv) / (CC + pv); return (CC > 0.0) ? log (CC) / log (1.0 + eint) : 0.0; } /* _fi_calc_num_payments */ /* compute Interest from preset data */ double fi_calc_interest (fi_ptr fi) { if (fi->npp) fi->ir = _fi_calc_interest (fi->npp, fi->pv, fi->pmt, fi->fv, fi->CF, fi->PF, fi->disc, fi->bep); return fi->ir; } /* fi_calc_interest */ double ratio = 1e4; /* ratio used in iterative solution for interest */ /* Compute Nominal Interest from: * 1. Number of periods * 2. Present Value * 3. Periodic Payment * 4. Future Value */ double _fi_calc_interest (unsigned per,/* number of periods */ double pv, /* present value */ double pmt, /* periodic payment */ double fv, /* future value */ unsigned CF, /* compounding frequency */ unsigned PF, /* payment frequency */ unsigned disc, /* discrete/continuous compounding */ unsigned bep) /* beginning/end of period payment */ { double eint; double a, dik; int ri; if (pmt == 0.0) eint = pow ((dabs (fv) / dabs (pv)), (1.0 / (double) per)) - 1.0; else { if ((pmt * fv) < 0.0) { if (pv) a = -1.0; else a = 1.0; eint = dabs ((fv + a * (double) per * pmt) / (3.0 * (((double) per - 1.0) * ((double) per - 1.0) * pmt + pv - fv))); } else { if ((pv * pmt) < 0.0) { eint = dabs (((double) per * pmt + pv + fv) / ((double) per * pv)); } else { a = dabs (pmt / (dabs (pv) + dabs (fv))); eint = a + 1.0 / (a * (double) per * (double) per * (double) per); } } do { dik = fi (per, eint, pv, pmt, fv, bep) / fip (per, eint, pv, pmt, fv, bep); eint -= dik; (void) modf (ratio * (dik / eint), &a); ri = (unsigned) a; } while (ri); } /* endif */ return 100.0 * nom_int (eint, CF, PF, disc); } /* _fi_calc_interest */ /* compute Present value from preset data */ double fi_calc_present_value (fi_ptr fi) { return fi->pv = rnd (_fi_calc_present_value (fi->npp, fi->ir, fi->pmt, fi->fv, fi->CF, fi->PF, fi->disc, fi->bep), fi->prec); } /* fi_calc_present_value */ /* Compute Present Value from: * 1. Number of periods * 2. Nominal Interest * 3. Periodic Payment * 4. Future Value */ double _fi_calc_present_value (unsigned per, /* number of periods */ double nint, /* nominal interest rate */ double pmt, /* periodic payment */ double fv, /* future value */ unsigned CF, /* compounding frequency */ unsigned PF, /* payment frequency */ unsigned disc, /* discrete/continuous compounding */ unsigned bep) /* beginning/end of period payment */ { double eint = eff_int (nint / 100.0, CF, PF, disc); double AA = _A (eint, per); double CC = _C (eint, pmt, bep); return -(fv + (AA * CC)) / (AA + 1.0); } /* _fi_calc_present_value */ /* compute Periodic Payment from preset data */ double fi_calc_payment (fi_ptr fi) { return fi->pmt = rnd (_fi_calc_payment (fi->npp, fi->ir, fi->pv, fi->fv, fi->CF, fi->PF, fi->disc, fi->bep), fi->prec); } /* fi_calc_payment */ /* Compute Periodic Payment from: * 1. Number of periods * 2. Nominal Interest * 3. Present Value * 4. Future Value */ double _fi_calc_payment (unsigned per, /* number of periods */ double nint, /* nominal interest rate */ double pv, /* present value */ double fv, /* future value */ unsigned CF, /* compounding frequency */ unsigned PF, /* payment frequency */ unsigned disc,/* discrete/continuous compounding */ unsigned bep) /* beginning/end of period payment */ { double eint = eff_int (nint / 100.0, CF, PF, disc); double AA = _A (eint, per); double BB = _B (eint, bep); g_return_val_if_fail(BB != 0.0, 0.0); return -(fv + pv * (AA + 1.0)) / (AA * BB); } /* _fi_calc_payment */ /* compute Future Value from preset data */ double fi_calc_future_value (fi_ptr fi) { return fi->fv = rnd (_fi_calc_future_value (fi->npp, fi->ir, fi->pv, fi->pmt, fi->CF, fi->PF, fi->disc, fi->bep), fi->prec); } /* fi_calc_future_value */ /* Compute Future Value from: * 1. Number of periods * 2. Nominal Interest * 3. Present Value * 4. Periodic Payments */ double _fi_calc_future_value (unsigned per, /* number of periods */ double nint, /* nominal interest rate */ double pv, /* present value */ double pmt, /* periodic payment */ unsigned CF, /* compounding frequency */ unsigned PF, /* payment frequency */ unsigned disc, /* discrete/continuous compounding */ unsigned bep) /* beginning/end of period payment */ { double eint = eff_int (nint / 100.0, CF, PF, disc); double AA = _A (eint, per); double CC = _C (eint, pmt, bep); return -(pv + AA * (pv + CC)); } /* _fi_calc_future_value */ /* compute Nominal Interest Rate from Effective Interest Rate */ static double nom_int (double eint, unsigned CF, unsigned PF, unsigned disc) { double nint; if (disc) { if (CF == PF) { nint = CF * eint; } else { nint = CF * (pow ((1.0 + eint), ((double) PF / (double) CF)) - 1.0); } /* * endif */ } else nint = log (pow (1.0 + eint, PF)); return nint; } /* nom_int */ /* Compute Effective Interest Rate from Nominal Interest Rate */ static double eff_int (double nint, unsigned CF, unsigned PF, unsigned disc) { double eint; if (disc) { if (CF == PF) { eint = nint / (double) CF; } else { eint = pow ((1.0 + nint / (double) CF), ((double) CF / (double) PF)) - 1.0; } /* endif */ } else eint = exp (nint / (double) PF) - 1.0; return eint; } /* eff_int */ /* calculation used in interest computation */ static double fi (unsigned per, double eint, double pv, double pmt, double fv, unsigned bep) { return _A (eint, per) * (pv + _C (eint, pmt, bep)) + pv + fv; } /* fi */ /* calculation used in interest computation */ static double fip (unsigned per, double eint, double pv, double pmt, double fv, unsigned bep) { double AA = _A (eint, per); double CC = _C (eint, pmt, bep); double D = (AA + 1.0) / (1.0 + eint); g_return_val_if_fail(CC != 0.0, 0.0); return (double) per * (pv + CC) * D - (AA * CC) / eint; } /* fip */ void set_default (fi_ptr fi) { /* flag whether accrueing interest at beginning or end of period * FALSE --> end * TRUE --> beginning * default to end of period payment s */ fi->bep = FALSE; /* flag for discrete or continuous interest * TRUE --> discrete * FALSE --> continuous * default to discrete interest */ fi->disc = TRUE; /* set compounding, CF, and payment, PF, frequency per year * default to monthly payments and compounding */ fi->CF = fi->PF = 12; /* standard loan quantities: * number of periods: n */ fi->npp = 0; /* annual interest: i */ fi->ir = 0.0; /* Present Value: pv */ fi->pv = 0.0; /* Payment: pmt */ fi->pmt = 0.0; /* Future Value: fv */ fi->fv = 0.0; } /* set_default */ /* compute Julian Day Number from calendar date */ unsigned long julian_day_number (unsigned year, unsigned month, unsigned day) { /* Gregorian/Julian Calendar Flag. * TRUE == Julian * FALSE == Gregorian */ unsigned gregorian = TRUE; /* assume we are dealing with current dates */ double yr; double pfac = 0.6; unsigned long ljdn; yr = year + (month - 3.0) / 12.0; ljdn = (long) (367.0 * yr + pfac) - (2 * (long) (yr)) + (long) (yr / 4.0) + (long) day + 1721117L; if (gregorian) ljdn += -(long) (yr / 100.0) + (long) (yr / 400.0) + 2; return ljdn; } /* julian_day_number */ amort_sched_ptr Amortization_init (amort_sched_ptr amortsched) { unsigned n = amortsched->n; double nint = amortsched->nint; double pv = amortsched->pv; double pmt = amortsched->pmt; double fv = amortsched->fv; double eint; double new_pmt; double pve; unsigned CF = amortsched->CF; unsigned PF = amortsched->PF; unsigned disc = amortsched->disc; unsigned bep = amortsched->bep; unsigned new_n; unsigned prec = amortsched->prec; unsigned long s, d, days_to_yr_end, Eff_Date_jdn = julian_day_number (amortsched->year_E, amortsched->month_E, amortsched->day_E), Init_Date_jdn = julian_day_number (amortsched->year_I, amortsched->month_I, amortsched->day_I); amortsched->Eff_Date_jdn = Eff_Date_jdn; amortsched->Init_Date_jdn = Init_Date_jdn; amortsched->yday_E = Eff_Date_jdn - julian_day_number (amortsched->year_E, 1, 1); amortsched->yday_I = Init_Date_jdn - julian_day_number (amortsched->year_I, 1, 1); amortsched->eint = eint = eff_int (nint / 100.0, CF, PF, disc); amortsched->fv_case = dabs (fv) > dabs (pv); amortsched->bp = bep ? 1.0 : 0.0; if (PF > 24) { /* Payment frequency per year greater than bi-monthly * use actual number of days */ s = Init_Date_jdn - Eff_Date_jdn; days_to_yr_end = julian_day_number (amortsched->year_I + 1, 1, 0) - Init_Date_jdn; d = 366 / PF; } else { /* Payment frequency per year bi-monthly or less * use 30 days/month, 360 days/year */ if (Eff_Date_jdn == Init_Date_jdn) { s = 0; } else { s = ((amortsched->year_I - amortsched->year_E) * 360) + ((amortsched->month_I - amortsched->month_E) * 30) + amortsched->day_I - amortsched->day_E; } /* endif */ days_to_yr_end = 390 - (amortsched->month_I * 30) - amortsched->day_I; d = 360 / PF; } /* endif */ if (!bep) { /* ordinary annuity */ s -= d; } /* endif */ amortsched->yr_pmt = (days_to_yr_end + d) / d; if (pmt == 0.0) { amortsched->pve = pv; } else { amortsched->pve = rnd (pv * pow ((1.0 + eint), ((double) (s * PF) / (double) (d * CF))), prec); } /* endif */ pve = amortsched->pve; /* compute new data to fully amortize loan: * new periodic payment, new_pmt * * option 1: Amortize with original transaction - ignore interest * due to delayed initial payment * * option 2: Amortize with new pv, pve == original pv adjusted for * delayed initial payment, original payment, original fv and * original total number of payments, adjust final payment * * option 3: amortize with new pv, pve, and new payments adjusted to * minimize final payment, keep original number of payments and * original fv * * option 4: amortize with new pv, pve, original payments and new * number of payments to keep original final fv */ /* option 3, compute new periodic payment */ amortsched->new_pmt = new_pmt = rnd (_fi_calc_payment (n, nint, pve, fv, CF, PF, disc, bep), prec); /* option 4: compute new number of total payments, new_n */ amortsched->new_n = new_n = (unsigned) rnd (_fi_calc_num_payments (nint, pve, pmt, fv, CF, PF, disc, bep), 0); /* following used in QTAwk to insure integer value, not needed in C */ /* n = int(n); */ /* compute payment for constant payment to principal loan and final * payment for original loan amount include interest due */ amortsched->cpmt1 = rnd (-pv / n, prec); amortsched->final_pmt_opt_1 = -pv - amortsched->cpmt1 * (n - 1); amortsched->final_pmt_opt_1 *= eint + 1; /* compute payment for constant payment to principal loan and final * payment for delayed loan amount include interest due */ amortsched->cpmt2 = rnd (-pve / n, prec); amortsched->final_pmt_opt_2 = -pve - amortsched->cpmt2 * (n - 1); amortsched->final_pmt_opt_2 *= eint + 1; if (bep) { amortsched->final_pmt_opt_3 = rnd (_fi_calc_future_value (n - 1, nint, pv, pmt, CF, PF, disc, bep) - (fv / (1.0 + eint)), prec); amortsched->final_pmt_opt_4 = rnd (_fi_calc_future_value (n - 1, nint, pve, pmt, CF, PF, disc, bep) - (fv / (1.0 + eint)), prec); amortsched->final_pmt_opt_5 = rnd (_fi_calc_future_value (n - 1, nint, pve, new_pmt, CF, PF, disc, bep) - (fv / (1.0 + eint)), prec); if (new_n) amortsched->final_pmt_opt_6 = rnd (_fi_calc_future_value (new_n - 1, nint, pve, pmt, CF, PF, disc, bep) - (fv / (1.0 + eint)), prec); else amortsched->final_pmt_opt_6 = 0.0; } else { amortsched->final_pmt_opt_3 = rnd (_fi_calc_future_value (n - 1, nint, pv, pmt, CF, PF, disc, bep) * (1.0 + eint) - fv, prec); amortsched->final_pmt_opt_4 = rnd (_fi_calc_future_value (n - 1, nint, pve, pmt, CF, PF, disc, bep) * (1.0 + eint) - fv, prec); amortsched->final_pmt_opt_5 = rnd (_fi_calc_future_value (n - 1, nint, pve, new_pmt, CF, PF, disc, bep) * (1.0 + eint) - fv, prec); if (new_n) amortsched->final_pmt_opt_6 = rnd (_fi_calc_future_value (new_n - 1, nint, pve, pmt, CF, PF, disc, bep) * (1.0 + eint) - fv, prec); else amortsched->final_pmt_opt_6 = 0.0; } /* endif */ /* compute delayed interest */ amortsched->delayed_int = pv - amortsched->pve; return amortsched; } /* Amortization_init */ amort_sched_ptr Amortization_Schedule (amort_sched_ptr amortsched) { unsigned n = amortsched->n; double nint = amortsched->nint; double pv = amortsched->pv; double pmt = amortsched->pmt; double fv = amortsched->fv; double eint = amortsched->eint; unsigned CF = amortsched->CF; unsigned PF = amortsched->PF; unsigned disc = amortsched->disc; unsigned bep = amortsched->bep; double cpmt = 0; double final_pmt = 0; char summary = amortsched->summary; unsigned option = amortsched->option; unsigned yr_pmt = amortsched->yr_pmt; unsigned fv_case = amortsched->fv_case; unsigned prec = amortsched->prec; unsigned j, s, yr, per_cnt, pmt_cnt = 0, k = 0, sum_prt; int jj; unsigned long d; double yr_fv, sum_int, yr_int, prin, adv_pmt, pmt_int, hpv = 0.0; yearly_summary_ptr yrly_sum; amort_sched_yr_ptr amortyr; sched_pmt_ptr pmtsched = NULL; sum_int = yr_int = 0.0; switch (option) { case 1: amortsched->cpmt = cpmt = amortsched->cpmt1; /* re-compute final payment without interest */ amortsched->final_pmt = final_pmt = -pv - cpmt * (n - 1); summary = (summary == 'y') ? 'x' : 'o'; break; case 2: amortsched->cpmt = cpmt = amortsched->cpmt2; pv = amortsched->pve; /* re-compute final payment without interest */ amortsched->final_pmt = final_pmt = -pv - cpmt * (n - 1); summary = (summary == 'y') ? 'x' : 'o'; break; case 3: amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_3; break; case 4: pv = amortsched->pve; amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_4; break; case 5: pv = amortsched->pve; pmt = amortsched->new_pmt; amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_5; break; case 6: n = amortsched->new_n; pv = amortsched->pve; amortsched->final_pmt = final_pmt = amortsched->final_pmt_opt_6; break; } /* endswitch */ yr = amortsched->year_I; sum_prt = TRUE; switch (summary) { case 'a': /* variable advanced prepayment schedule. prepayment equals next * period principal. */ amortsched->schedule.first_yr = amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr)); for (per_cnt = 0, s = 1, j = n; pv != fv; j -= 2, per_cnt++) { /* basic equation to compute interest this payment period */ pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec); /* sum yearly interest paid */ yr_int += pmt_int; /* sum total interest paid */ sum_int += pmt_int; /* compute principal paid this payment period and round to nearest cent */ if (dabs (pmt) > dabs (pv)) { prin = -pv; pmt = prin + pmt_int; adv_pmt = 0.0; pv = fv; } else { prin = rnd (pmt - pmt_int, prec); /* compute remaining pv and round to nearest cent */ pv = rnd (pv + prin, prec); /* compute principal for next payment cycle and round to nearest cent */ adv_pmt = rnd (pmt + (pv + (amortsched->bp * pmt)) * eint, prec); if (dabs (pv) >= dabs (adv_pmt)) { /* remaining pv greater than advanced principal payment * compute remaining pv and round to nearest cent */ pv = rnd (pv + adv_pmt, prec); } else { /* remaining pv less than advanced principal payment reduce * advanced pricipla payment to remaining pv */ adv_pmt = -pv; /* and set remaining pv to fv */ pv = fv; } /* ## endif */ } /* # endif */ if (sum_prt) { jj = (j < yr_pmt) ? j + 1 : yr_pmt; amortyr->payments = pmtsched = (sched_pmt_ptr) calloc (jj, sizeof (sched_pmt)); pmt_cnt = 0; sum_prt = FALSE; } /* endif */ pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->principal = prin; pmtsched->advanced_pmt = adv_pmt; pmtsched->total_pmt = pmt + adv_pmt; pmtsched->balance = pv; pmtsched++; pmt_cnt++; if (!--yr_pmt) { yr_pmt = PF; amortyr->year = yr++; amortyr->interest_pd = yr_int; amortyr->principal_pd = pv - hpv; amortyr->yr_end_balance = pv; amortyr->total_interest_pd = sum_int; amortyr->num_periods = pmt_cnt; amortyr->next_yr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr)); amortyr = amortyr->next_yr; hpv = pv; yr_int = 0.0; sum_prt = TRUE; } /* endif */ } /* endfor */ if (dabs (pv) > 0.0) { /* basic equation to compute interest this payment period */ pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec); /* sum yearly interest paid */ yr_int += pmt_int; /* sum total interest paid */ sum_int += pmt_int; /* compute principal paid this payment period and round to nearest cent */ prin = rnd (pmt - pmt_int, prec); final_pmt = pmt; /* compute remaining pv and round to nearest cent */ pv = rnd (pv + prin, prec); /* Set advanced principal payment to remaining pv */ adv_pmt = -pv; amortyr->final_pmt = final_pmt += adv_pmt; /* and set remaining pv to fv */ pv = fv; if (pmtsched) { pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->principal = prin; pmtsched->advanced_pmt = adv_pmt; pmtsched->total_pmt = final_pmt; pmtsched->balance = pv; } per_cnt++; pmt_cnt++; } /* endif */ if (dabs (yr_int) > 0.0) { amortyr->year = yr++; amortyr->interest_pd = yr_int; amortyr->principal_pd = pv - hpv; amortyr->total_interest_pd = sum_int; amortyr->num_periods = pmt_cnt; } /* endif */ amortsched->total_periods = per_cnt; break; case 'f': /* fixed prepaymet schedule prepayment specified by user */ amortsched->schedule.first_yr = amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr)); /* set advnaced payment */ adv_pmt = amortsched->fixed_pmt; for (per_cnt = 0, s = 1, j = n; j && (pv != fv); j--, per_cnt++) { /* basic equation to compute interest this payment period */ pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec); /* sum yearly interest paid */ yr_int += pmt_int; /* sum total interest paid */ sum_int += pmt_int; /* compute principal paid this payment period and round to nearest cent */ if (dabs (pmt) > dabs (pv)) { prin = -pv; pmt = prin + pmt_int; adv_pmt = 0.0; pv = 0.0; } else { prin = rnd (pmt - pmt_int, prec); /* compute remaining pv and round to nearest cent */ pv = rnd (pv + prin, prec); if (dabs (pv) >= dabs (adv_pmt)) { /* remaining pv greater than advanced principal payment * compute remaining pv and round to nearest cent */ pv = rnd (pv + adv_pmt, prec); } else { /* remaining pv less than advanced principal payment reduce * advanced pricipal payment to remaining pv and set * remaining pv to fv */ adv_pmt = -pv; pv = fv; } /*## endif */ } /* # endif */ if (sum_prt) { jj = (j < yr_pmt) ? j + 1 : yr_pmt; amortyr->payments = pmtsched = (sched_pmt_ptr) calloc (jj, sizeof (sched_pmt)); pmt_cnt = 0; sum_prt = FALSE; } else { (amortyr->num_periods)++; } /* ## endif */ pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->principal = prin; pmtsched->advanced_pmt = adv_pmt; pmtsched->total_pmt = pmt + adv_pmt; pmtsched->balance = pv; pmt_cnt++; pmtsched++; if (!--yr_pmt) { yr_pmt = PF; amortyr->year = yr++; amortyr->interest_pd = yr_int; amortyr->principal_pd = pv - hpv; amortyr->yr_end_balance = pv; amortyr->total_interest_pd = sum_int; amortyr->num_periods = pmt_cnt; amortyr->next_yr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr)); amortyr = amortyr->next_yr; hpv = pv; yr_int = 0.0; sum_prt = TRUE; } /* ## endif */ } /* ## endfor */ if (pv != fv) { /* # basic equation to compute interest this payment period */ pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec); /* # sum yearly interest paid */ yr_int += pmt_int; /* # sum total interest paid */ sum_int += pmt_int; /* # compute principal paid this payment period and round to nearest cent */ prin = rnd (pmt - pmt_int, prec); final_pmt = pmt; /* # compute remaining pv and round to nearest cent */ pv = rnd (pv + prin, prec); /* # Set advanced principal payment to remaining pv */ adv_pmt = -pv; amortyr->final_pmt = final_pmt += adv_pmt; /* # and set remaining pv to fv */ pv = fv; if (pmtsched) { pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->principal = prin; pmtsched->advanced_pmt = adv_pmt; pmtsched->total_pmt = final_pmt; pmtsched->balance = pv; } per_cnt++; pmt_cnt++; } /* # endif */ if (dabs (yr_int) > 0.0) { amortyr->year = yr++; amortyr->interest_pd = yr_int; amortyr->principal_pd = pv - hpv; amortyr->total_interest_pd = sum_int; amortyr->num_periods = pmt_cnt; } /* endif */ amortsched->total_periods = per_cnt; break; case 'o': /* Constant payment to principal use constant payment equal to * original pv divided by number of periods. constant payment to * pricipal could be amount specified by user. */ amortsched->schedule.first_yr = amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr)); amortsched->total_periods = n; d = yr_pmt; for (s = 1, j = n - 1; j; j--, k++) { pmt_int = -rnd (pv * eint, prec); /* sum yearly interest paid */ yr_int += pmt_int; /* sum total interest paid */ sum_int += pmt_int; pv = rnd (pv + cpmt, prec); if (sum_prt) { jj = (j < yr_pmt) ? j + 1 : yr_pmt; amortyr->payments = pmtsched = (sched_pmt_ptr) calloc (jj, sizeof (sched_pmt)); amortyr->num_periods = jj; k = 0; sum_prt = FALSE; } /* endif */ pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->total_pmt = cpmt + pmt_int; pmtsched->balance = pv; pmtsched++; if (!--yr_pmt) { yr_pmt = PF; amortyr->year = yr++; amortyr->interest_pd = yr_int; amortyr->principal_pd = d * cpmt; amortyr->yr_end_balance = pv; amortyr->total_interest_pd = sum_int; amortyr->next_yr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr)); amortyr = amortyr->next_yr; d = PF; yr_int = 0.0; sum_prt = TRUE; } /* endif */ } /* endfor */ if (pv) { pmt_int = -rnd (pv * eint, prec); /* sum yearly interest paid */ yr_int += pmt_int; /* sum total interest paid */ sum_int += pmt_int; if (pmtsched) { pmtsched->period_num = s++; pmtsched->interest = -pmt_int; pmtsched->total_pmt = -pv + pmt_int; pmtsched->balance = 0.0; } amortyr->final_pmt = -pv - pmt_int; } /* endif */ if (dabs (yr_int) > 0.0) { amortyr->year = yr++; amortyr->interest_pd = yr_int; amortyr->principal_pd = -pv + k * cpmt; amortyr->total_interest_pd = sum_int; } /* endif */ break; case 'p': /* normal amortization schedule interest, principal and balance * per payment period */ amortsched->schedule.first_yr = amortyr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr)); amortsched->total_periods = n; hpv = pv; for (s = 1, j = n - 1; j; j--) { /* basic equation for computing interest paid in payment period */ pmt_int = -rnd ((pv + (amortsched->bp * pmt)) * eint, prec); /* sum yearly interest paid */ yr_int += pmt_int; /* sum total interest paid */ sum_int += pmt_int; /* compute principal paid this payment period */ prin = rnd (pmt - pmt_int, prec); /* compute remaining pv and round to nearest cent */ pv = rnd (pv + prin, prec); if (sum_prt) { jj = (j < yr_pmt) ? j + 1 : yr_pmt; amortyr->payments = pmtsched = (sched_pmt_ptr) calloc (jj, sizeof (sched_pmt)); amortyr->num_periods = jj; sum_prt = FALSE; } /* endif */ if (fv_case) { pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->balance = pv; pmtsched++; } else { pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->principal = prin; pmtsched->balance = pv; pmtsched++; } /* endif */ if (!--yr_pmt) { yr_pmt = PF; amortyr->year = yr++; amortyr->interest_pd = yr_int; if (!fv_case) { amortyr->principal_pd = pv - hpv; } /* endif */ amortyr->yr_end_balance = pv; amortyr->total_interest_pd = sum_int; amortyr->next_yr = (amort_sched_yr_ptr) calloc (1, sizeof (amort_sched_yr)); amortyr = amortyr->next_yr; hpv = pv; yr_int = 0.0; sum_prt = TRUE; } /* * endif */ } /* * endfor */ /* determine if payment due at beginning or end of period in order * to correctly compute final payment, interest and principal */ if (bep) { /* paying remainder at beginning of period compute final payment */ final_pmt = -pv - fv / (1 + eint); /* then compute interest paid with final final payment */ pmt_int = -rnd ((pv + final_pmt) * eint, prec); /* then compute the principal paid */ prin = final_pmt + pmt_int; } else { /* basic equation for computing interest paid in payment period * for payment at end of period */ pmt_int = -rnd (pv * eint, prec); /* compute principal paid this payment period */ prin = -pv; /* compute the final payment note the final payment may be * computed either of two ways both are equivalent */ final_pmt = prin + pmt_int; } /* * endif */ pv = -fv; /* sum yearly interest paid */ yr_int += pmt_int; /* sum total interest paid */ sum_int += pmt_int; if (sum_prt) { amortyr->payments = pmtsched = (sched_pmt_ptr) calloc (1, sizeof (sched_pmt)); amortyr->num_periods = 1; } /* endif */ amortyr->final_pmt = final_pmt; if (fv_case) { pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->balance = pv; } else { pmtsched->period_num = s++; pmtsched->interest = pmt_int; pmtsched->principal = prin; pmtsched->balance = pv; } /* endif */ if (dabs (yr_int) > 0.0) { amortyr->year = yr++; amortyr->interest_pd = yr_int; amortyr->total_interest_pd = sum_int; if (!bep) { amortyr->principal_pd = -hpv; } /* endif */ } /* endif */ break; case 'x': /* constant payment to principal - annual summary */ /* compute number of years to summarize */ j = n / PF; if (yr_pmt < PF) j++; amortsched->total_periods = j; amortsched->schedule.summary = yrly_sum = (yearly_summary_ptr) calloc (j, sizeof (yearly_summary)); jj = 0; for (j = n, sum_prt = 0; j > 0; j -= yr_pmt, yr_pmt = PF, sum_prt++) { if (j <= PF) { s = jj + j; yr_pmt = j; yr_fv = rnd (pv + cpmt * (s - 1), prec) + final_pmt; } else { s = jj + yr_pmt; yr_fv = rnd (pv + cpmt * s, prec); } /* endif */ prin = -eint * jj * (pv + (cpmt * (jj - 1) / 2.0)); yr_int = -eint * s * (pv + (cpmt * (s - 1) / 2.0)); yr_int = rnd (yr_int - prin, prec); jj += yr_pmt; sum_int += yr_int; yrly_sum[sum_prt].year = yr++; yrly_sum[sum_prt].interest = yr_int; yrly_sum[sum_prt].end_balance = yr_fv; } /* endfor */ break; case 'y': /* normal amortization - annual summary */ /* compute number of years to summarize */ j = n / PF; if (yr_pmt < PF) j++; if (n > (j * PF)) j++; amortsched->total_periods = j; amortsched->schedule.summary = yrly_sum = (yearly_summary_ptr) calloc (j, sizeof (yearly_summary)); hpv = pv; for (jj = n, j = 0; jj > 0; jj -= yr_pmt, yr_pmt = PF, j++) { if (jj <= (int)PF) { yr_fv = fv; yr_int = rnd (((jj - 1) * pmt) + hpv + final_pmt, prec); } else { yr_fv = -rnd (_fi_calc_future_value (yr_pmt, nint, hpv, pmt, CF, PF, disc, bep), prec); yr_int = rnd ((yr_pmt * pmt) + hpv - yr_fv, prec); } /* * endif */ sum_int += yr_int; yrly_sum[j].year = yr++; yrly_sum[j].interest = yr_int; yrly_sum[j].end_balance = yr_fv; hpv = yr_fv; } /* * endfor */ break; } /* * endswitch */ amortsched->total_interest = sum_int; return amortsched; } /* Amortization_Schedule */ /* function to free dynamically allocated memory used for amortization schedule */ void Amortization_free (amort_sched_ptr amortsched) { amort_sched_yr_ptr amortyr, prst_yr; switch (amortsched->summary) { case 'a': case 'f': case 'o': case 'p': for (amortyr = amortsched->schedule.first_yr; amortyr; amortyr = prst_yr) { if (amortyr->payments) free (amortyr->payments); prst_yr = amortyr->next_yr; free (amortyr); } /* endfor */ break; case 'y': free (amortsched->schedule.summary); break; } /* endswitch */ amortsched->schedule.first_yr = NULL; } /* amort_free */