stock portfolio alpha-level fixes

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@17 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 1997-11-01 02:23:13 +00:00
parent 2f0e6918aa
commit 4732ac577b
6 changed files with 175 additions and 69 deletions

21
README
View File

@ -39,16 +39,19 @@ sorry, no "make install" yet.
Status:
-------
As of version 0.9f:
As of version 0.9g:
---------------
Mutual fund and Stock Portfolio handling
is implemented, but is in alpha state: many features are
missing, and others are broken. Transfers between funds and
bank accounts are not properly supported. Also, tabbing between
fields for mutual funds does not work correctly. One planned
addition is an indication of the type of transaction (Buy,
Cap Gain, Dividend Reinvest, etc.) But it is not clear when
this will be added.
Bare-bones Mutual Fund and Stock Portfolio handling
is implemented.
Working Features:
-- transfers between bank account & fund work
-- save to disk, restore from disk.
Bugs:
-- tabbing between fields for mutual funds does not work correctly.
Planned additions:
-- Indicate type of transaction (Buy, Cap Gain, Dividend Reinvest, etc.)
--------
An alpha version of import from Quicken files is also present,

View File

@ -594,6 +594,7 @@ createCB( Widget mw, XtPointer cd, XtPointer cb )
String name = XmTextGetString(accData->name);
String desc = XmTextGetString(accData->desc);
#ifdef SHOULDNT_BE_BROKEN_ANYMORE
{
/* since portfolio & mutual not fully implemented, provide warning */
int warn = 0;
@ -615,6 +616,7 @@ Do you want to continue anyway?\n");
if (!do_it_anyway) return;
}
}
#endif /* SHOULDNT_BE_BROKEN_ANYMORE */
/* The account has to have a name! */
if( strcmp( name, "" ) == 0 ) {

View File

@ -275,6 +275,18 @@ insertTransaction( Account *acc, Transaction *trans )
\********************************************************************/
double xaccGetAmount (Account *acc, Transaction *trans)
{
double themount; /* amount */
themount = xaccGetShareAmount (acc, trans);
themount *= trans->share_price;
return themount;
}
/********************************************************************\
\********************************************************************/
double xaccGetShareAmount (Account *acc, Transaction *trans)
{
double themount; /* amount */
if (NULL == trans) return 0.0;
@ -287,7 +299,7 @@ double xaccGetAmount (Account *acc, Transaction *trans)
if ( trans->debit == ((struct _account *) acc) ) {
themount = - (trans->damount);
} else {
printf ("Internal Error: xaccGetAmount: missing double entry \n");
printf ("Internal Error: xaccGetShareAmount: missing double entry \n");
printf ("this error should not occur. Please report the problem. \n");
themount = 0.0; /* punt */
}
@ -297,7 +309,7 @@ double xaccGetAmount (Account *acc, Transaction *trans)
/********************************************************************\
\********************************************************************/
void xaccSetAmount (Account *acc, Transaction *trans, double themount)
void xaccSetShareAmount (Account *acc, Transaction *trans, double themount)
{
/* for a double-entry, determine if this is a credit or a debit */
if ( trans->credit == ((struct _account *) acc) ) {
@ -315,6 +327,17 @@ void xaccSetAmount (Account *acc, Transaction *trans, double themount)
/********************************************************************\
\********************************************************************/
void xaccSetAmount (Account *acc, Transaction *trans, double themount)
{
if (0.0 < trans->share_price) {
themount /= trans->share_price;
xaccSetShareAmount (acc, trans, themount);
}
}
/********************************************************************\
\********************************************************************/
double xaccGetBalance (Account *acc, Transaction *trans)
{
double themount; /* amount */
@ -379,11 +402,25 @@ double xaccGetShareBalance (Account *acc, Transaction *trans)
* xaccRecomputeBalance *
* recomputes the partial balances and the current balance for *
* this account. *
The current balance is always the current share balance times the
current share price. The share price for bank accounts is always 1.0,
so, for bank acccounts, the current balance is always equal to the current
share balance.
*
* The way the computation is done depends on whether the partial
* balances are for a monetary account (bank, cash, etc.) or a
* certificate account (stock portfolio, mutual fund). For bank
* accounts, the invarient amount is the dollar amount. For share
* accounts, the invarient amount is the number of shares. For
* share accounts, the share price fluctuates, and the current
* value of such an account is the number of shares times the current
* share price.
*
* Part of the complexity of this computatation stems from the fact
* xacc uses a double-entry system, meaning that one transaction
* appears in two accounts: one account is debited, and the other
* is credited. When the transaction represents a sale of shares,
* or a purchase of shares, some care must be taken to compute
* balances correctly. For a sale of shares, the stock account must
* be debited in shares, but the bank account must be credited
* in dollars. Thus, two different mechanisms must be used to
* compute balances, depending on account type.
* *
* Args: account -- the account for which to recompute balances *
* Return: void *
@ -394,33 +431,67 @@ xaccRecomputeBalance( Account * acc )
int i;
double dbalance = 0.0;
double dcleared_balance = 0.0;
Transaction *trans;
double share_balance = 0.0;
double share_cleared_balance = 0.0;
double amt = 0.0;
Transaction *trans, *last_trans;
Account *tracc;
if( NULL == acc ) return;
for( i=0; (trans=getTransaction(acc,i)) != NULL; i++ ) {
dbalance += xaccGetAmount (acc, trans);
/* compute both dollar and share balances */
amt = xaccGetShareAmount (acc, trans);
share_balance += amt;
dbalance += amt * (trans->share_price);
if( trans->reconciled != NREC ) {
dcleared_balance += xaccGetAmount (acc, trans);
share_cleared_balance += amt;
dcleared_balance += amt * (trans->share_price);
}
if (acc == (Account *) trans->credit) {
trans -> credit_share_balance = dbalance;
trans -> credit_share_cleared_balance = dcleared_balance;
trans -> credit_balance = trans->share_price * dbalance;
trans -> credit_cleared_balance = trans->share_price * dcleared_balance;
tracc = (Account *) trans->credit;
if (tracc == acc) {
/* For bank accounts, the invarient subtotal is the dollar
* amount. For stock accoounts, the invarient is the share amount */
if ( (PORTFOLIO == tracc->type) || ( MUTUAL == tracc->type) ) {
trans -> credit_share_balance = share_balance;
trans -> credit_share_cleared_balance = share_cleared_balance;
trans -> credit_balance = trans->share_price * share_balance;
trans -> credit_cleared_balance = trans->share_price * share_cleared_balance;
} else {
trans -> credit_share_balance = dbalance;
trans -> credit_share_cleared_balance = dcleared_balance;
trans -> credit_balance = dbalance;
trans -> credit_cleared_balance = dcleared_balance;
}
}
if (acc == (Account *) trans->debit) {
trans -> debit_share_balance = dbalance;
trans -> debit_share_cleared_balance = dcleared_balance;
trans -> debit_balance = trans->share_price * dbalance;
trans -> debit_cleared_balance = trans->share_price * dcleared_balance;
tracc = (Account *) trans->debit;
if (tracc == acc) {
if ( (PORTFOLIO == tracc->type) || ( MUTUAL == tracc->type) ) {
trans -> debit_share_balance = share_balance;
trans -> debit_share_cleared_balance = share_cleared_balance;
trans -> debit_balance = trans->share_price * share_balance;
trans -> debit_cleared_balance = trans->share_price * share_cleared_balance;
} else {
trans -> debit_share_balance = dbalance;
trans -> debit_share_cleared_balance = dcleared_balance;
trans -> debit_balance = dbalance;
trans -> debit_cleared_balance = dcleared_balance;
}
}
last_trans = trans;
}
acc -> balance = dbalance;
acc -> cleared_balance = dcleared_balance;
if ( (PORTFOLIO == acc->type) || ( MUTUAL == acc->type) ) {
acc -> balance = share_balance * (last_trans->share_price);
acc -> cleared_balance = share_cleared_balance * (last_trans->share_price);
} else {
acc -> balance = dbalance;
acc -> cleared_balance = dcleared_balance;
}
return;
}

View File

@ -79,7 +79,7 @@ Boolean havePixels = False;
void
refreshMainWindow( void )
{
int i,j,nrows;
int i,nrows;
char buf[BUFSIZE];
XtVaGetValues( accountlist, XmNrows, &nrows, NULL );
@ -91,14 +91,10 @@ refreshMainWindow( void )
String rows[3];
Transaction *trans=NULL;
Account *acc = getAccount( data, i );
double dbalance = 0.0;
double share_balance = 0.0;
double dbalance;
j=0;
while( (trans = getTransaction(acc,j++)) != NULL ) {
share_balance += xaccGetAmount (acc, trans);
dbalance = share_balance * trans->share_price;
}
xaccRecomputeBalance (acc);
dbalance = acc->balance;
if( 0.0 > dbalance )
sprintf( buf,"-$%.2f\0", DABS(dbalance) );

View File

@ -238,20 +238,47 @@ regRefresh( RegWindow *regData )
newData[row+1][RECN_CELL_C] = XtNewString("");
themount = xaccGetAmount (acc, trans);
/* hack alert -- share amounts should have three digits */
if( 0.0 > themount )
/* ----------------------------------- */
/* display depends on account type */
switch(acc->type)
{
sprintf( buf, "%.2f ", -themount );
newData[row][PAY_CELL_C] = XtNewString(buf);
newData[row][DEP_CELL_C] = XtNewString("");
}
else
{
sprintf( buf, "%.2f ", themount );
newData[row][PAY_CELL_C] = XtNewString("");
newData[row][DEP_CELL_C] = XtNewString(buf);
case BANK:
case CASH:
case ASSET:
case CREDIT:
case LIABILITY:
themount = xaccGetAmount (acc, trans);
if( 0.0 > themount )
{
sprintf( buf, "%.2f ", -themount );
newData[row][PAY_CELL_C] = XtNewString(buf);
newData[row][DEP_CELL_C] = XtNewString("");
}
else
{
sprintf( buf, "%.2f ", themount );
newData[row][PAY_CELL_C] = XtNewString("");
newData[row][DEP_CELL_C] = XtNewString(buf);
}
break;
case PORTFOLIO:
case MUTUAL:
themount = xaccGetShareAmount (acc, trans);
if( 0.0 > themount )
{
sprintf( buf, "%.3f ", -themount );
newData[row][PAY_CELL_C] = XtNewString(buf);
newData[row][DEP_CELL_C] = XtNewString("");
}
else
{
sprintf( buf, "%.3f ", themount );
newData[row][PAY_CELL_C] = XtNewString("");
newData[row][DEP_CELL_C] = XtNewString(buf);
}
break;
default:
fprintf( stderr, "Ineternal Error: Account type: %d is unknown!\n", acc->type);
}
newData[row+1][PAY_CELL_C] = XtNewString("");
@ -277,13 +304,11 @@ regRefresh( RegWindow *regData )
newData[row+1][PRIC_CELL_C] = XtNewString("");
newData[row][SHRS_CELL_C] = XtNewString("");
newData[row+1][SHRS_CELL_C] = XtNewString("");
/*
newData[row][ACTN_CELL_C] = XtNewString("");
newData[row+1][ACTN_CELL_C] = XtNewString("");
*/
/* newData[row][ACTN_CELL_C] = XtNewString(""); */
/* newData[row+1][ACTN_CELL_C] = XtNewString(""); */
break;
default:
fprintf( stderr, "Ineternal Error: Account type: %d is unknown!\n", regData->acc->type);
fprintf( stderr, "Ineternal Error: Account type: %d is unknown!\n", acc->type);
}
}
@ -384,9 +409,9 @@ regRecalculateBalance( RegWindow *regData )
(PORTFOLIO == acc->type) )
{
#ifdef USE_NO_COLOR
sprintf( buf, "%.2f ", share_balance );
sprintf( buf, "%.3f ", share_balance );
#else
sprintf( buf, "%.2f ", DABS(share_balance) );
sprintf( buf, "%.3f ", DABS(share_balance) );
/* Set the color of the text, depending on whether the
* balance is negative or positive */
@ -552,7 +577,7 @@ regSaveTransaction( RegWindow *regData, int position )
sscanf( amount, "%f", &val );
themount -= val;
xaccSetAmount (acc, trans, themount);
xaccSetShareAmount (acc, trans, themount);
/* Reset so there is only one field filled */
if( 0.0 > themount )
@ -897,7 +922,7 @@ regWindow( Widget parent, Account *acc )
case MUTUAL:
acc -> colWidths[PRIC_CELL_C] = 8; /* price */
acc -> colWidths[SHRS_CELL_C] = 8; /* share balance */
/* acc -> colWidths[ACTN_CELL_C] = 6; /* action (category) */
/* acc -> colWidths[ACTN_CELL_C] = 6; /* action (Buy/Sell)*/
break;
}
@ -953,7 +978,7 @@ regWindow( Widget parent, Account *acc )
case MUTUAL:
acc -> rows[0][PRIC_CELL_C] = "Price";
acc -> rows[0][SHRS_CELL_C] = "Tot Shrs";
/* acc -> rows[0][ACTN_CELL_C] = "Cat"; /* action */
/* acc -> rows[0][ACTN_CELL_C] = "Action"; /* action */
break;
}
@ -1251,22 +1276,24 @@ deleteCB( Widget mw, XtPointer cd, XtPointer cb )
{
RegWindow *regData = (RegWindow *)cd;
Account *acc = regData->acc;
Transaction *trans;
if( getTransaction(acc,regData->lastTrans) != NULL )
trans = getTransaction (acc, regData->lastTrans );
if( NULL != trans)
{
char *msg = "Are you sure you want\nto delete this transaction?";
if( verifyBox( toplevel, msg ) )
{
Transaction *trans;
trans = getTransaction (acc, regData->lastTrans );
Account * cred = (Account *) (trans->credit);
Account * deb = (Account *) (trans->debit);
/* remove the transaction from both accounts */
REMOVE_TRANS ((trans->credit), trans);
REMOVE_TRANS ((trans->debit), trans);
REMOVE_TRANS (cred, trans);
REMOVE_TRANS (deb, trans);
RECALC_BALANCE ((trans->debit));
RECALC_BALANCE ((trans->credit));
RECALC_BALANCE (deb);
RECALC_BALANCE (cred);
/* Delete the transaction */
freeTransaction (trans);

View File

@ -108,6 +108,13 @@ dateCB( Widget mw, XtPointer cd, XtPointer cb )
cbs->doit = False;
}
break;
case 0x0:
/* if delete key (for example) is hit, then input string */
/* will be an empty string. In such a case, allow the input */
cbs->doit = True;
break;
default:
/* only accept the input if it is a number */
cbs->doit = isNum(input);