From: chedley@carthago.intel.com (CHEDLEY_AOURIRI)
Newsgroups: misc.invest
Subject: Amortization schedule (Re: C program (Re: Computing rate of return on montly investments...)
Date: 7 Apr 92 19:12:08 GMT
Reply-To: chedley@carthago.intel.com (CHEDLEY_AOURIRI)
Organization: Intel-Corp,_Hillsboro,_Oregon

In article <1992Apr3.221826.3144@e2big.mko.dec.com>, rac@omega.enet.dec.com (Ray Chibbaro) writes:
|> Great Job Mark (and Chedley for reposting)!!!!! 
|> 
|> Many thanks for the tool.  Any chance there is one that
|> works out a motgage amortz schedule in your posession???
|> 
Yes. I have an old program, courtesy of a fellow misc.invest'or 
that computes loan principal and interest payment schedules. 
It is mostly useful to verify amortization and prepayment
schedules of a fixed rate loan.
But you can easily tailor it to other amortizations.

Again, this is freeware, so use it at your own risk.
The following version works fine under UNIX-V.4. 
-- 
..CHEDLEY..
..!{uunet|tektronix|ogicse}!littlei!chedley    chedley@carthago.intel.com     
------------------------------------------------------------------------
Standard Disclaim: The above statements and opinions are strictly mine,
and do not represent any company or organization's position.
......................................................................
------------------------CUT HERE-----------------------------------
/*
 * To compile,  type: cc prepay.c
 * prepay.c
 * Author: Dennis Bednar,
 * Date: 09/08/1988
 * E-mail: uunet!virtech!dennis
 * Virtual Technologies Inc.
 * P. O. Box 876
 * Sterling VA 22170
 *
 * Heres a neat program for showing you a monthly breakdown of principal
 * and interest paid for a typical mortgage or auto loan over a
 * long period of time.  It is mostly useful for verifying an annual
 * statement of interest and principal paid at the end of each year,
 * for income tax purposes.  It was primarily designed to allow
 * variable monthly payments, ie the payment for one month might be
 * $500, the next month it might be $600. But it will also work on
 * simpler cases when the same amount is paid every month.
 * 
 * All input comes from standard input, so run it as "prepay <infile".
 * The comments below in this source file should be self-
 * explanatory for describing the input data.
 *
 * Analyze pre-payments of mortgage loan. If you know how much
 * per period you are paying, and it is usually more than the
 * minimum amount required, then this program is for you!
 * It shows you the principal and interest per period, and the
 * amount owed after each period.
 * It also shows yearly only, yearly subtotal, and total for
 * all of the periods. 
 * Computed to nearest whole cent, which is what your loan company
 * would do (see the function round_penny())!
 * Also allows a few months of "negative amoritization", whereby
 * the monthly payment isn't sufficient to cover the interest,
 * accrued for that month.
 * I have tested it against actual data from my own mortgage
 * loan, and the numbers reported by this program were correct.
 *
 * input is from stdin in the following form:
 * # at line begin is comment line
 * first line contains
borrow	annual_interest_rate	periods_per_year	cur_month cur_yr
 * where
 *	borrow = amount borrowed, do not supply dollar signs
 *	interest rate per year (10.375 means 10 3/8% per year)
 *		do not supply percent signs
 *	periods_per_year is usually 12 meaning monthly payments
 *	cur_period = current period of the year for first payment,
 *		where 1 = first period of the year.
 *	(if 12 months, cur_period = 4 means that first payment is on April)
 *	cur_yr = the current year of the first payment
 * For example, borrowing $100,000 at 10% annual interest, with monthly
 * payments beginning on Jan 1988 would be:
100000	10			12			1	88
 *
 * Successive lines represent a series of normal payments or prepayments:
payment	number
 * where
 *	payment = amount you paid per period (principal + interest only)
 *		it does not include real estate taxes, hazard insurance,
 *		nor PMI.
 *	number = number of consecutive payments of amount 'payment' paid
 *		This may be a huge number (360) to force the loan to 'run out'
 *		until the balance owed is zero.
 *		Usually it is the number of consecutive months of 'payment'.
 * For example,
1000	3
1100	2
1200	360
 * says the first 3 payments were $1,000, the next two were $1,100, and for 
 * the remainder of the loan, the payments were $1,200. If you do not
 * pick a large enough payment, the loan will not be paid off fully.
 *
 */
/* includes */
#include <stdio.h>

/* defines */
#define FLOAT double

/* fw refs to non int functions */
FLOAT	round_penny();

/* externs */
extern	FLOAT	atof();

/* globals */
char	*cmd;

main( argc, argv )
	char	*argv[];
{
	FLOAT	loan,		/* amount borrowed */
		rate,		/* yearly rate */
		prin,		/* principal */
		rateper,	/* rate per period */
		pmt,		/* payment, P+I only */
		thisint,	/* interest for this period only */
		totowe,		/* total owed after interest added */
		totint,		/* total interest paid */
		totprin,	/* total principal paid */
		totpaid,	/* total paid */
		lastyrprin,	/* total last year principal */
		lastyrint,	/* total last year interest */
		lastyrpaid,	/* total last year paid */
		totyrprin,	/* total yearly principal */
		totyrint,	/* total yearly interest */
		totyrpaid,	/* total yearly paid */
		futowe;		/* future owed */
	int	times,		/* number of times this payment is made */
		i,		/* loop thru number of consecutive pers */
		peryr,		/* periods per year, usually 12 (monthly) */
		cur_mon,	/* month number of 1st pmt, 1=jan */
		pmtno,		/* payment number */
		cur_yr,		/* current year */
		lineno;		/* line number */
	char	buf[200];

	cmd = argv[0];		/* in case of error */

	printf("\t\t--- Tax Consequences Of a Loan ---\n");
	lineno = 0;

	while(1)
	{
		if (fgets(buf, sizeof buf, stdin) == NULL)
			exit(0);
		++lineno;
		if (iscomment(buf))
			continue;
		if (sscanf(buf, "%lf %lf %d %d %d", &loan, &rate, &peryr, &cur_mon, &cur_yr ) != 5)
			error("Line %d: Expected 5 items: <loan, rate, periods/yr, monthno, year>", lineno);
		else
			break;
	}


	cur_yr %= 100;	/* make 1988 into just '88' */
#ifdef DEBUG
	printf("rate = %lf, period_per_yr = %lf\n", rate, peryr);
#endif
	rateper = (rate/(FLOAT)peryr)/100.0;

	totint = totprin = totpaid = 0.0;
	lastyrprin = lastyrint = lastyrpaid = 0.0;
	pmtno = 0;


	while( fgets(buf, sizeof(buf), stdin) != (char *)NULL)
		{
		++lineno;
		if (iscomment(buf))
			continue;
		if (sscanf(buf, "%lf %d", &pmt, &times ) != 2)
			error("line %d: 2 numbers expected: <payment, number>", lineno);
#ifdef DEBUG
		printf("pmt = %lf, times = %d\n", pmt, times);
#endif
		for (i = 0; i < times; ++i)
			{
			thisint = loan * rateper;	/* monthly int */
			thisint = round_penny( thisint );
			totowe = loan + thisint;	/* before pmt */
			if (pmt > totowe)	/* last payment */
				pmt = totowe;
			futowe = loan + thisint - pmt;
			prin = loan - futowe;
			totprin += prin;
			totint += thisint;
			totpaid += pmt;
			++pmtno;
			if ((pmtno == 1) || (cur_mon == 1))
				pr_hdr();	/* introduce years */
			printf("%3d %2d-%2d %10.2f %10.2f %1.1s %10.2f %1.1s %10.2f %10.2f\n",
				pmtno, cur_mon, cur_yr, loan, prin, "+", thisint, "=",
				pmt, futowe );
			loan = futowe;
			if ((++cur_mon > peryr) || (loan < .001))
				{
				cur_mon = 1;
				if (++cur_yr > 99)
					cur_yr = 0;	/* wrap from 1999 to 2000 */
				totyrprin = totprin - lastyrprin;
				totyrint  = totint  - lastyrint;
				totyrpaid = totpaid - lastyrpaid;
				
				printf("%3s %5.5s %10.10s %10.2f %1.1s %10.2f %1.1s %10.2f\n",
				"YR", "-----", "-------------", totyrprin, "+", totyrint, "=",
				totyrpaid );
				printf("%3s %5.5s %10.10s %10.2f %1.1s %10.2f %1.1s %10.2f\n",
				"SUB", "-----", "-------------", totprin, "+", totint, "=",
				totpaid );
				/* remember subtotal numbers till next year */
				/* next yr total - old year subtotal = gain */
				lastyrprin = totprin;
				lastyrint  = totint;
				lastyrpaid = totpaid;
				}
			if (loan < 0.001)
				break;
			}
		if (loan < 0.001)
			break;
		}
	printf("%3s %5.5s %10.10s %10.2f %1.1s %10.2f %1.1s %10.2f\n",
	"TOT", "-----", "---------------", totprin, "+", totint, "=",
	totpaid );
	printf("--- In %d Years and %d Extra Months\n", pmtno/peryr, pmtno%peryr); 
}


/* 
 * round to nearest whole penny.
 */
FLOAT
round_penny( f )
	FLOAT	f;		/* input */
{
	FLOAT	trunc;		/* answer */
	char	buf[100];

	/* brute force way */
	sprintf(buf, "%.2f", f);
	trunc = atof( buf );
	return trunc;
}

/*
 * return 1 if this line is a comment line
 */
iscomment( cp )
	char	*cp;
{
	if ((*cp == '#') || (*cp == ' ') || (*cp == '\t') || (*cp == '\n'))
		return 1;
	else
		return 0;
}


#define MANYARGS msg, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
typedef char	*CHARSTAR;

/*
 * print error message and exit
 * Error message does *not* have a newline at the end.
 */
error(MANYARGS)
	CHARSTAR	MANYARGS;
{
	extern	char	*cmd;
	char	buffer[BUFSIZ];
	sprintf(buffer, MANYARGS);
	fprintf(stderr, "%s: error: %s. Exitting.\n", cmd, buffer);
	exit(1);
}

/* 
 * print header line
 */
pr_hdr()
{
	printf("%3s %5.5s %10.10s %10.10s %1.1s %10.10s %1.1s %10.10s %10.10s\n",
	"Num", "Date", "WasOwe", "Principal", "+", "Interest", "= ", "Payment", "NowOwe");
}