From: wendt@arizona.edu (Alan Lee Wendt)
Newsgroups: misc.invest
Subject: Program to calculate return on investment
Date: 1 Aug 87 19:56:24 GMT
Organization: U of Arizona CS Dept, Tucson

Here's a little program I cobbled up to calculate rate of return on
a portfolio.  Its input is lines, each containing a date, a tab
character, and an amount of money.  Investments should be positive
numbers and withdrawls negative.  If you still have money invested,
fake a withdrawl at the end of the file, with todays date and
the current value.  For example, in my magellan IRA fund, I deposited
$1000 last year on 7/3/86 and yesterday its value was 1305.12:

07/03/86<tab>1000.00
12/31/86<tab>10
07/30/87<tab>-1305.12

The $10 represents the IRA servicing fee which gets charged annually.

You can cat together several files and pipe them in.  The rate of return
is gotten by binary search.  The binary search is kind of interesting
because it runs out to the full precision of the machine, without any
machine-dependent code.  It stops when the floating point arithmetic
begins to break down.
#endif notdef

/*  rate of return of a portfolio	*/

#include <stdio.h>

double		deposits[500];
long		dates[500];

/* strtoday string into day number */

#define month (n[0])
#define day (n[1])
#define year (n[2])

static unsigned maxd[] = {
    0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
    };

static double dexp(d, exp)
    double d;
    register long exp;
    {
    static double result;

    result = 1.0;	    /* init multiplicative acc */

    if (exp < 0)	    /* exponent negative? */
	{
	d = 1/d;
	exp = -exp;
	}

    while (exp != 0) {
	if (exp & 1) result *= d;   /* fold this factor */
	exp >>= 1;	    /* shift exponent */
	d *= d;     /* square running multiplier */
	}

    return result;
    }

/*  convert "MM/DD/YY" or "MMDDYY" into # of days using Jan 1, 1601 = day 1
 *  ref: CACM 11, 657 (1968) - valid back to 24 Nov -4713
 */
long strtoday(dd)
    char *dd;
    {
    long		strtol();
    char		*ddend;
    int			c = 0, slash = 0;
    long		jdn;
    int			n[3];
    static int		m;

    jdn = strtol(dd, &ddend, 10);		/* convert mmddyy */
    month = jdn;

    if (*ddend == '/') {
	slash = 1;				/* got mm/dd/yy   */
	goto middle;
	}

    else if (*ddend) return -1;

    for (; c <= 2; c++) {
	if (slash) {
	    n[c] = strtol(dd, &ddend, 10);	/* convert a number */
	    if (*ddend != "//"[c])		/* check proper terminator */
baddy:		return -1;
middle:	    dd = ddend + 1;
	    }
	else {
	    n[2 - c] = jdn % 100;
	    jdn /= 100;
	    }
	}

    if (year <= 99) year += 1900;	/* correct for c */
    maxd[2] = 28;
    if ((!(year & 3) && (year % 100)) || !(year % 400)) 
	maxd[2] = 29;
    if (month < 1 || month > 12 || day < 1 || day > maxd[month]) goto baddy;

    m = (month <= 2) ? -1 : 0;
    year += m;
    jdn = (long)day - 2337888L;
    jdn += 1461L * ((long)year + 4800L) / 4L;
    jdn += 367L * (month - 2L - (long)m * 12L) / 12L;
    jdn -= 3L * (((long)year + 4900L) / 100L) / 4L;

    return (double)jdn;
    }

main()
    {
    long	maxday = 0;
    int		ndep = 0;
    char	bf[200];
    double	limit[2], rate, testtot, atof();
    int		which, i;

    while (scanf("%s %lf\n", bf, &deposits[ndep]) > 0) {
	dates[ndep] = strtoday(bf);
	if (maxday < dates[ndep]) maxday = dates[ndep];
	ndep++;
	}

    /*  Calculate daily rate of return by binary search	*/
    limit[1] = 1.1;		/* 10 percent every day	*/
    limit[0] = 0;		/* throw it all away	*/
    for (;;) {
	rate = (limit[1] + limit[0]) / 2;
	testtot = 0;
	for (i = 0; i < ndep; i++)
	    testtot += (deposits[i] * dexp(rate, maxday - dates[i]));

	which = (0 < testtot);

	if (limit[0] >= limit[1] || limit[which] == rate) {
	    rate = 100.0 * (dexp(rate, 365) - 1.0);
	    printf("%.6f %% (annualized)\n", rate);
	    exit(0);
	    }

	limit[which] = rate;
	}
    }
Newsgroups: misc.invest