// COMPLETE THREAD

return.C -- performance tracking tool (fwd)

5 expanded posts ยท every known parent and child

NODE 2fce8695return.C -- performance tracking tool (fwd)
I have been using this program for a while and decided to share it
with the other readers. It is written in C++.

/***********************************************************************

This program calculates the total portfolio return.  It may be used
to find out an individual's stock picking performance and compare it
to some benchmark.

Right now it compiles under Unix, but I would expect it to work under
DOS and Win32 console interface. To compile it, type

	gcc -lm -lg++ -o return return.C

This program was written because I was not satisfied with the existing
portfolio tracking websites due to their extremely limited and incorrect
functionality.

It works by treating your investments as a "mutual fund". It tracks
the number of "shares" held. It means that additional cash infusions,
withdrawals, stock splits, sales of securities do not affect the per share
value. This is done so that the changing size of the portfolio would not
skew the estimate of the true performance of the stock picker. However,
dividends, fees and recorded capital appreciation do affect the per
share value.

Short sales are allowed by specifying a negative stock amount.

I strongly suggest that investors regularly record stock prices into their
transaction files (using the VAL operator) to monitor how they are doing.

USAGE:

	portfolio-return transaction-file-name TICKER=price TICKER=price ...

EXAMPLE

	portfolio-return MYSTOCKS.TXT MSFT=130 T=65.56

It reads a text file that contains the record of transactions, and 
prices, and requests to print out the portfolio value.

# This is a typical file used to calculate total return.
# This file contains comments, marked by "#" characters,
# and transaction info.
#
# Transaction info consists of records of the following form:
#
# INV Amount                    -- tells how much was invested in Category
# PUR Ticker numshares share_price   -- stock purchase info
# SAL Ticker numshares share_price   -- stock sale
# DIV Ticker Amount                  -- how much dividend was received
# WDR Amount                         -- cash withdrawal
# VAL Ticker Amount                  -- Value per share
# SPL Ticker new_to_old              -- stock split
# FEE amount                         -- various fees (like margin loan 
#					interest, commission etc)
# (negative FEE means incoming cash, from e.g interest on the cash held
# by the broker)
# PRN Comment                        -- Print portfolio with Comment
#

Happy investing.

Copyright (c) Igor Chudov 1997. 

	ichudov@algebra.com
	http://www.algebra.com/~ichudov

GNU Copyright applies. There is NO WARRANTY WHATSOEVER. By using this
program you agree to indemnify and hold it author harmless from any
liabilities resulting in connection with your use of the program.

You are allowed to copy this program freely provided that the copyright 
notice remains intact.

*/
 
#include <stdio.h>
#include <iostream.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
 
#define Money       double
#define StockTicker char *
#define Date        int
 
class Stock {
public:
   Stock( const StockTicker theTicker,
          int theQuantity = 0,
          Money theValue = 0.0 )
      : Ticker( strdup( theTicker ) ),
        Quantity( theQuantity ),
        Value( theValue )
        {
           // nothing
        }
 
   ~Stock( void ) { delete[] Ticker; }
   void  Purchase( int theQuantity )         { Quantity += theQuantity; }
   int   GetQuantity( void ) const           { return Quantity; };
   void  SetValue( Money theValue )          { Value = theValue; }
   Money GetValue( void ) const              { return Value; }
   const StockTicker GetTicker( void ) const { return Ticker; }
   void  Split( Money factor ) { Quantity *= factor, Value /= factor; }
private:
   Money Value;
   StockTicker Ticker;
   int Quantity;
};
 
typedef Stock * PStock;
 
class Portfolio {
public:
  Portfolio( void );
  ~Portfolio( void );
 
  // What can happen to the portfolios:
  // Add cash to the portfolio
  void Invest( Money Cash );
 
  // Purchase (or sell (even short) if Quantity is negative)
  void Purchase( const StockTicker Ticker, int Quantity, Money Value );
 
  // Dividend received, 1 success, 0 failure
  int Dividend( const StockTicker Ticker, Money DividendPerShare );
 
  // Split, factor is new # of shares to old # of shares, 1 success, 0 failure
  int Split( const StockTicker Ticker, Money factor );
 
  // Withdrawal
  void Withdraw( Money Amount );

  // Fee -- margin interest, commission etc
  void Fee( Money amount );
 
  // Change in Stock valuation
  int Valuation( StockTicker Ticker, Money theValue );
 
  /////////////////////////////
  // Equity = Cash + StockValue
  Money Equity( void ) const;
 
  Money EquityPerShare( void ) const { return Equity()/NumShares; }
 
  int GetNumShares( void ) const { return NumShares; }
 
  void Print( ostream & os, const char * comment = 0 );
 
protected:
 
  void Revaluate( void );
 
  int FindStock( const StockTicker Ticker );
 
private:
 
  Stock ** Stocks;
  int NumberStocks;
  int MaxNumberStocks;
  Money Return;
  Money LastDate;
  Money Cash;
  Money NumShares;
};
 
Portfolio::Portfolio( void )
   : NumberStocks( 0 ),
     MaxNumberStocks( 100 ),
     Cash( 0.0 ),
     NumShares( 0 ),
     Return( 0.0 ),
     LastDate( 0 )
{
   Stocks = new PStock[ MaxNumberStocks ];
}
 
Portfolio::~Portfolio( void )
{
   delete[] Stocks;
}
 
void Portfolio::Invest( Money theCash )
{
//cout << "investing " << theCash << endl;
 
   if( NumShares != 0 )
     {
       NumShares += theCash/EquityPerShare();
       Cash += theCash;
     }
   else
     {
       Cash = theCash;
       NumShares = Cash;
     }
}
 
 
void Portfolio::Withdraw( Money Amount )
{
   Invest( -Amount );
}
 
void Portfolio::Fee( Money Amount )
{
   Cash -= Amount;
}
 
int Portfolio::FindStock( const StockTicker Ticker )
{
  for( int i = 0; i < NumberStocks; i++ )
    if( !strcmp( Ticker, Stocks[i]->GetTicker() ) )
      {
        return i;
        break;
      }
  return -1;
}
 
void Portfolio::Purchase( const StockTicker Ticker,
                          int Quantity,
                          Money Value )
{
   int found = FindStock( Ticker );
 
   if( found == -1 ) // need to add a stock
     {
       if( NumberStocks == MaxNumberStocks ) // need to resize
         {
            Stock ** NewStocks = new PStock[ MaxNumberStocks * 2 ];
            memcpy( NewStocks, Stocks, sizeof( Stock ) * MaxNumberStocks );
            delete[] Stocks;
            Stocks = NewStocks;
            MaxNumberStocks *= 2;
         }
       found = NumberStocks++;
       Stocks[found] = new Stock( Ticker, Quantity, Value );
     }
   else
     {
        Stocks[found]->Purchase( Quantity );
        Stocks[found]->SetValue( Value );
     }
 
   Cash -= Quantity * Value;
}
 
int Portfolio::Dividend( const StockTicker Ticker, Money DividendPerShare )
{
  int found = FindStock( Ticker );
 
  if( found == -1 )
     return 0;
 
  Cash += DividendPerShare * Stocks[found]->GetQuantity();
}
 
int Portfolio::Split( const StockTicker Ticker, Money Factor )
{
  int found = FindStock( Ticker );
 
  if( found == -1 )
     return 0;
 
  Stocks[found]->Split( Factor );
}
 
 
int Portfolio::Valuation( StockTicker Ticker, Money theValue )
{
  int found = FindStock( Ticker );
  if( found == -1 )
     return 0; // failure
 
  Stocks[found]->SetValue( theValue );
 
  return 1; // success
}
 
 
Money Portfolio::Equity( void ) const
{
   Money e = Cash;
 
   for( int i =0; i < NumberStocks; i++ )
      e += Stocks[i]->GetQuantity() * Stocks[i]->GetValue();
 
   return e ;
}
 
void Portfolio::Print( ostream & os, const char * comment )
{
  os << endl << "Portfolio: " << (comment ? comment : "" ) << endl;
 
  for( int i = 0; i < NumberStocks; i++ )
     os << Stocks[i]->GetTicker() << " "
        << Stocks[i]->GetQuantity() << " "
        << Stocks[i]->GetValue() << ", Total = "
        << Stocks[i]->GetValue() * Stocks[i]->GetQuantity() << endl;
  os << "Cash: " << Cash << endl;
 
  cout << "Equity = " << Equity() << endl;
  cout << "Number of Shares = " << GetNumShares() << endl;
  cout << "Share Value = " << EquityPerShare() << endl;
}
 
void ReadHistory( Portfolio & portfolio, FILE * f )
{
   while( !feof( f ) )
     {
        char buf[2048];
        buf[0] = 0;
        fgets( buf, sizeof( buf ), f );
 
        //cout << buf;
        char * p = strchr( buf, '#' );
        if( p != 0 ) *p = 0;  // Comment #
 
        for( p = buf; *p; p++ ) *p = toupper( *p );
 
        if( !strncmp( buf, "INV", 3 ) )
         {
            //cout << "investing" << endl;
 
            float amount;
            if( sscanf( buf+4, "%f", &amount ) == 1 )
               portfolio.Invest( amount );
            else
               fprintf( stderr, "Invalid transaction: %s\n", buf );
         }
        else if( !strncmp( buf, "WDR", 3 ) )
         {
            float amount;
            if( sscanf( buf+4, "%f", &amount ) == 1 )
               portfolio.Invest( -amount );
            else
               fprintf( stderr, "Invalid transaction: %s\n", buf );
         }
        else if( !strncmp( buf, "PUR", 3 ) )
         {
            float price;
            int numshares;
            char ticker[2048];
 
            if( sscanf( buf+4, "%s %d %f", &ticker, &numshares, &price ) == 3 )
              portfolio.Purchase( ticker, numshares, price );
            else
              fprintf( stderr, "Invalid transaction: %s\n", buf );
         }
        else if( !strncmp( buf, "FEE", 3 ) )
         {
            float amount;
 
            if( sscanf( buf+4, "%f", &amount ) == 1 )
              portfolio.Fee( amount );
            else
              fprintf( stderr, "Invalid transaction: %s\n", buf );
         }
        else if( !strncmp( buf, "SAL", 3 ) )
         {
            float price;
            int numshares;
            char ticker[2048];
 
            if( sscanf( buf+4, "%s %d %f", &ticker, &numshares, &price ) == 3 )
              portfolio.Purchase( ticker, -numshares, price );
            else
              fprintf( stderr, "Invalid transaction: %s\n", buf );
         }
        else if( !strncmp( buf, "DIV", 3 ) )
         {
            float div;
            char ticker[2048];
            if( sscanf( buf+4, "%s %f", &ticker, &div ) == 2 )
              portfolio.Dividend( ticker, div );
            else
              fprintf( stderr, "Invalid transaction: %s\n", buf );
         }
        else if( !strncmp( buf, "VAL", 3 ) )
         {
            float val;
            char ticker[2048];
            if( sscanf( buf+4, "%s %f", &ticker, &val ) == 2 )
              portfolio.Valuation( ticker, val );
            else
              fprintf( stderr, "Invalid transaction: %s\n", buf );
         }
        else if( !strncmp( buf, "SPL", 3 ) )
         {
            float factor;
            char ticker[2048];
            if( sscanf( buf+4, "%s %f", &ticker, &factor ) == 2 )
              portfolio.Split( ticker, factor );
            else
              fprintf( stderr, "Invalid transaction: %s\n", buf );
         }
        else if( !strncmp( buf, "PRN", 3 ) )
         {
              portfolio.Print( cout, buf + 4 );
         }
     }
}
 
int main( int argc, char *argv[] )
{
   Portfolio portfolio;
 
   FILE * input;
   if( argc >= 2 )
   {
      if( (input = fopen( argv[1], "r" )) == 0 )
      {
         fprintf( stderr, "Can't open %s.\n"
               "Usage: %s activity-file TICK=val TICK1=val ...\n",
               argv[1], argv[0] );
         exit( 1 );
      }
   }
   else
   {
      input = stdin;
   }

   ReadHistory( portfolio, input );
 
   for( argc--; argc > 1; argc-- )
      // process arguments of form "TICKER=value"
     {
       char buf[ 2048 ];
       strcpy( buf, argv[argc] );

       for( char * p = buf; *p; p++ ) *p = toupper( *p );
 
       char * pvalue = strchr( buf, '=' );
 
       if( pvalue == 0 )
         {
           cerr << "Wrong argument: " << argv[argc]
                << ". Must be of form TICKER=value" << endl;
           continue;
         }
 
       *pvalue++=0;
 
       float value;
 
       if( sscanf( pvalue, "%f", &value ) != 1 )
       {
          cerr << "Wrong argument: " << argv[argc]
               << ". Must be of form TICKER=value" << endl;
          continue;
       }
 
       if( !portfolio.Valuation( buf, value ) )
       {
          cerr << "Ticker " << buf << " not found in the portfolio!" << endl;
       }
     }
 
   portfolio.Print( cout, "Final Result" );
 
   printf( "\n\n"
"Copyright (C) Igor Chudov, ichudov@algebra.com,\n"
"	http://www.algebra.com/~ichudov\n\n"
"No warranty is provided with this free program. GNU Copyright applies.\n" );

}
NODE f7750da4Re: return.C -- performance tracking tool (fwd)
Igor Chudov @ home wrote:
> 
> I have been using this program for a while and decided to share it
> with the other readers. It is written in C++.

this is not a financial mailing list.
and this code is not C++... it just needs a C++ compiler to
compile. real C++ code doesn't use fprintf, scanf, nor strcmp...

$0.02

  alx
NODE 9d24959eRe: return.C -- performance tracking tool (fwd)
--Boundary..3989.1071713780.multipart/signed
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

In <34F2CF5D.8276D7FB@infomaniak.ch>, on 02/24/98 
   at 02:47 PM, Alexandre Maret <amaret@infomaniak.ch> said:

>Igor Chudov @ home wrote:
>> 
>> I have been using this program for a while and decided to share it
>> with the other readers. It is written in C++.

>this is not a financial mailing list.
>and this code is not C++... it just needs a C++ compiler to
>compile. real C++ code doesn't use fprintf, scanf, nor strcmp...

Let's not forget that *real* C++ apps are bloated several time that of
comparable C apps (god forbid anyone write some tight ASM code).

$1.00 <== Inflation

-- 
---------------------------------------------------------------
William H. Geiger III  http://users.invweb.net/~whgiii
Geiger Consulting    Cooking With Warp 4.0

Author of E-Secure - PGP Front End for MR/2 Ice
PGP & MR/2 the only way for secure e-mail.
OS/2 PGP 2.6.3a at: http://users.invweb.net/~whgiii/pgpmr2.html                        
---------------------------------------------------------------
 
Tag-O-Matic: Get OS/2 - the best Windows tip around!


--Boundary..3989.1071713780.multipart/signed
Content-Type: application/octet-stream; name="pgp00002.pgp"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="pgp00002.pgp"
Content-Description: "PGP signature"

LS0tLS1CRUdJTiBQR1AgTUVTU0FHRS0tLS0tClZlcnNpb246IDIuNi4zYS1z
aGExCkNvbW1lbnQ6IFJlZ2lzdGVyZWRfVXNlcl9FLVNlY3VyZV92MS4xYjFf
RVMwMDAwMDAKCmlRQ1ZBd1VBTlBMRmJZOUNvMW4rYUxoaEFRSFE3Z1FBdEo4
UHYxVUlPSEJzMkJ4YWlvN21wRDNpWmVPZDN5WGMKNk4vc1k5ZCtZUDVvSnhZ
VG9QTkhzMitwclc4cDNlQ09FWjJwcWs5VmNReE56TUlNMExYc01LRFZ1NmMv
YXBTdApBMkhFYVZGd2tBU3FhMERwN3Nucm8rUEREd0FGSHFVMzhkNnVKWDZk
Vi9vQk9qWjIvZDMvT3ptVXZ3cC93RXVFCldOeno0SEE5Y0xzPQo9OU9BUwot
LS0tLUVORCBQR1AgTUVTU0FHRS0tLS0t
--Boundary..3989.1071713780.multipart/signed--
NODE 7e4d2953Re: return.C -- performance tracking tool (fwd)
William H. Geiger III wrote:
>    at 02:47 PM, Alexandre Maret <amaret@infomaniak.ch> said:
> >Igor Chudov @ home wrote:
> >> 
> >> I have been using this program for a while and decided to share it
> >> with the other readers. It is written in C++.
> 
> >this is not a financial mailing list.
> >and this code is not C++... it just needs a C++ compiler to
> >compile. real C++ code doesn't use fprintf, scanf, nor strcmp...

Excuse me, mah friend, it is C++ in its pure form, with classes and all.

> Let's not forget that *real* C++ apps are bloated several time that of
> comparable C apps (god forbid anyone write some tight ASM code).

Not this one. But you have a good point.

	- Igor.
NODE 75d664e2Re: return.C -- performance tracking tool (fwd)
Alexandre Maret wrote:
> Igor Chudov @ home wrote:
> > I have been using this program for a while and decided to share it
> > with the other readers. It is written in C++.
> 
> this is not a financial mailing list.

This is not a gun mailing list, not a chemical mailing list, not
a flame mailing list, but all of these things are also discussed.

> and this code is not C++... it just needs a C++ compiler to
> compile. real C++ code doesn't use fprintf, scanf, nor strcmp...

It is the purest form of C++. As my grandma used to say, take your eyes
in your hands and take a look.

	- Igor.