/* -*- Mode:MACSYMA; Fonts:(CPTFONTB) -*- */

eval_when([translate,batch,demo],
mdefine(funlhs,exp)::=ev(buildq([funlhs,exp],buildq([lh:funlhs,rh:ev(exp)],
lh:=rh)),eval),

/* The amortization formula is based the sum of a geometric sequence.
 */

present_value(starting_value,payment,rate,time):=
 starting_value*(rate+1)^time - payment * ((rate+1)^time-1) / rate);

/* There are two things one wants to know when considering a loan:
   (a) how much will the payments be.
   (b) what is the actual interest rate being paid once you account
       for "points" (i.e. money-up-front) and monthing compounding.
 */

mdefine(payment('starting_value,'rate,'time),
 /* We get the formula by solving for the payment assuming a present_value
    of zero. i.e. full payment of the loan by the given time */
 rhs(first(solve(present_value('starting_value,'payment,'rate,'time),
                 'payment))));


monthly_payment(starting_value,yearly_percentage_rate,years):=
 payment(starting_value,
         yearly_percentage_rate/100/12,
         12*years);

/* In the equation for present value we cannot be solve directly
   for the rate R, so instead we approximate.
 */

mdefine(rate_approx('starting_value,'payment,'rate_approx,'time),
   'rate_approx -
        present_value('starting_value,'payment,'rate_approx,'time) /
        diff(present_value('starting_value,'payment,'rate_approx,'time),
             'rate_approx));

apr(mort_amount,points,payment,stated_rate,years):=
 block([starting_value : mort_amount - mort_amount * points/100,
        mpr: stated_rate/100/12,temp],
        while ( temp:rate_approx(starting_value,
                                 payment,
                                 mpr,
                                 years*12),
                 abs(temp - mpr) > ratepsilon)
	do (print("MONTHLY PRECENTAGE APPROXIMATELY =",TEMP*100),
            mpr: temp),
	((mpr+1)^12-1)*100);


run_loop():=
 block([ma:read("Mortgage amount"),pay,ypr,yrs,pnts,apr,ins],
       loop,
       ypr:float(read("Percentage")),
       yrs:read("Years"),
       pnts:read("Points"),
       ins:float(read("Insurance factor (or zero)")),
       print("Calculations for",ma,"at",ypr,"for",yrs,"years. with",pnts,
             "points"),
       pay:monthly_payment(ma,ypr,yrs) + ma*ins/12 ,
       print("Monthly Payment =",pay),
       apr:apr(ma,pnts,pay,ypr,yrs),
       print("Actual Rate (APR) =",apr),
       go(loop));
