pricing fixes, added price command
This commit is contained in:
parent
c892e8c7ad
commit
f077b655d0
6 changed files with 86 additions and 31 deletions
2
Makefile
2
Makefile
|
|
@ -4,7 +4,7 @@ OBJS = $(patsubst %.cc,%.o,$(CODE))
|
||||||
CXX = g++
|
CXX = g++
|
||||||
CFLAGS = #-Wall -ansi -pedantic
|
CFLAGS = #-Wall -ansi -pedantic
|
||||||
DFLAGS = -O3 -fomit-frame-pointer
|
DFLAGS = -O3 -fomit-frame-pointer
|
||||||
DFLAGS = #-g -DDEBUG=1
|
#DFLAGS = -g -DDEBUG=1
|
||||||
INCS = -I/sw/include -I/usr/include/gcc/darwin/3.3/c++ -I/usr/include/gcc/darwin/3.3/c++/ppc-darwin
|
INCS = -I/sw/include -I/usr/include/gcc/darwin/3.3/c++ -I/usr/include/gcc/darwin/3.3/c++/ppc-darwin
|
||||||
LIBS = -L/sw/lib -lgmpxx -lgmp -lpcre
|
LIBS = -L/sw/lib -lgmpxx -lgmp -lpcre
|
||||||
|
|
||||||
|
|
|
||||||
18
README
18
README
|
|
@ -991,6 +991,15 @@ above to:
|
||||||
ledger -e 2004/1/1 equity -^Income -^Expenses > /tmp/balances
|
ledger -e 2004/1/1 equity -^Income -^Expenses > /tmp/balances
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
*** price
|
||||||
|
|
||||||
|
This commands displays the last known current price for a given
|
||||||
|
commodity, using the specified end date for the cutoff (default is the
|
||||||
|
present moment). It takes a list of regexps, which can match the
|
||||||
|
commodities used in the ledger file. This command is helpful to
|
||||||
|
quickly seeing the last current price for a specific commodity, or all
|
||||||
|
commodities referenced by a ledger.
|
||||||
|
|
||||||
*** entry
|
*** entry
|
||||||
|
|
||||||
The three most laborious tasks of keeping a ledger are: adding new
|
The three most laborious tasks of keeping a ledger are: adding new
|
||||||
|
|
@ -1156,6 +1165,11 @@ launches =vi= to let you confirm that the entry looks appropriate.
|
||||||
Sort the ledger after reading it. This may affect "register" and
|
Sort the ledger after reading it. This may affect "register" and
|
||||||
"print" output.
|
"print" output.
|
||||||
|
|
||||||
|
-T ::
|
||||||
|
Show only commodities totals, do not convert to the basis cost or
|
||||||
|
the current market value. This disables the effect of =-B=, =-P=
|
||||||
|
and =-Q=.
|
||||||
|
|
||||||
-U ::
|
-U ::
|
||||||
Show only uncleared transactions. The default is to consider both.
|
Show only uncleared transactions. The default is to consider both.
|
||||||
|
|
||||||
|
|
@ -1168,11 +1182,11 @@ LEDGER ::
|
||||||
A colon-separated list of files to be parsed whenever ledger is run.
|
A colon-separated list of files to be parsed whenever ledger is run.
|
||||||
Easier than typing =-f= all the time.
|
Easier than typing =-f= all the time.
|
||||||
|
|
||||||
PRICE_HIST ::
|
<verbatim>PRICE_HIST</verbatim> ::
|
||||||
The ledger file used to hold pricing data. =~/.pricedb= would be a
|
The ledger file used to hold pricing data. =~/.pricedb= would be a
|
||||||
good choice.
|
good choice.
|
||||||
|
|
||||||
PRICE_EXP ::
|
<verbatim>PRICE_EXP</verbatim> ::
|
||||||
The number of minutes before pricing data becomes out-of-date. The
|
The number of minutes before pricing data becomes out-of-date. The
|
||||||
default is one day. Use =-L= to temporarily decrease or increase
|
default is one day. Use =-L= to temporarily decrease or increase
|
||||||
the value.
|
the value.
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@ class gmp_amount : public amount
|
||||||
virtual amount * value(const amount *) const;
|
virtual amount * value(const amount *) const;
|
||||||
virtual void set_value(const amount * val);
|
virtual void set_value(const amount * val);
|
||||||
virtual amount * street(std::time_t * when = NULL,
|
virtual amount * street(std::time_t * when = NULL,
|
||||||
bool get_quotes = false) const;
|
bool use_history = false,
|
||||||
|
bool download = false) const;
|
||||||
|
|
||||||
virtual bool has_price() const {
|
virtual bool has_price() const {
|
||||||
return priced;
|
return priced;
|
||||||
|
|
@ -215,7 +216,8 @@ amount * gmp_amount::value(const amount * pr) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
amount * gmp_amount::street(std::time_t * when, bool get_quotes) const
|
amount * gmp_amount::street(std::time_t * when,
|
||||||
|
bool use_history, bool download) const
|
||||||
{
|
{
|
||||||
static std::time_t now = std::time(NULL);
|
static std::time_t now = std::time(NULL);
|
||||||
if (! when)
|
if (! when)
|
||||||
|
|
@ -228,7 +230,7 @@ amount * gmp_amount::street(std::time_t * when, bool get_quotes) const
|
||||||
|
|
||||||
int max = 10;
|
int max = 10;
|
||||||
while (--max >= 0) {
|
while (--max >= 0) {
|
||||||
amount * price = amt->commdty()->price(when, get_quotes);
|
amount * price = amt->commdty()->price(when, use_history, download);
|
||||||
if (! price)
|
if (! price)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
16
ledger.cc
16
ledger.cc
|
|
@ -29,9 +29,10 @@ void commodity::set_price(amount * price, std::time_t * when)
|
||||||
conversion = price;
|
conversion = price;
|
||||||
}
|
}
|
||||||
|
|
||||||
amount * commodity::price(std::time_t * when, bool download) const
|
amount * commodity::price(std::time_t * when,
|
||||||
|
bool use_history, bool download) const
|
||||||
{
|
{
|
||||||
if (conversion || ! when)
|
if (conversion || ! when || ! use_history)
|
||||||
return conversion;
|
return conversion;
|
||||||
|
|
||||||
std::time_t age;
|
std::time_t age;
|
||||||
|
|
@ -61,17 +62,6 @@ amount * commodity::price(std::time_t * when, bool download) const
|
||||||
char buf[256];
|
char buf[256];
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
|
|
||||||
cout << "Consulting the Internet for " << symbol << endl;
|
|
||||||
strftime(buf, 127, "%Y/%m/%d %H:%M:%S", localtime(when));
|
|
||||||
cout << " when: " << buf << endl;
|
|
||||||
if (price) {
|
|
||||||
strftime(buf, 127, "%Y/%m/%d %H:%M:%S", localtime(&age));
|
|
||||||
cout << " age: " << buf << endl;
|
|
||||||
cout << " diff (when, age): " << difftime(*when, age) << endl;
|
|
||||||
} else {
|
|
||||||
cout << " diff (now, when): " << difftime(now, *when) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (FILE * fp = popen((string("getquote ") + symbol).c_str(), "r")) {
|
if (FILE * fp = popen((string("getquote ") + symbol).c_str(), "r")) {
|
||||||
if (feof(fp) || ! fgets(buf, 255, fp)) {
|
if (feof(fp) || ! fgets(buf, 255, fp)) {
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
|
|
||||||
6
ledger.h
6
ledger.h
|
|
@ -64,7 +64,8 @@ class commodity
|
||||||
~commodity();
|
~commodity();
|
||||||
|
|
||||||
void set_price(amount * price, std::time_t * when = NULL);
|
void set_price(amount * price, std::time_t * when = NULL);
|
||||||
amount * price(std::time_t * when = NULL, bool download = false) const;
|
amount * price(std::time_t * when = NULL,
|
||||||
|
bool use_history = false, bool download = false) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<const std::string, commodity *> commodities_map;
|
typedef std::map<const std::string, commodity *> commodities_map;
|
||||||
|
|
@ -84,7 +85,8 @@ class amount
|
||||||
virtual amount * value(const amount * pr = NULL) const = 0;
|
virtual amount * value(const amount * pr = NULL) const = 0;
|
||||||
virtual void set_value(const amount * pr) = 0;
|
virtual void set_value(const amount * pr) = 0;
|
||||||
virtual amount * street(std::time_t * when = NULL,
|
virtual amount * street(std::time_t * when = NULL,
|
||||||
bool get_quotes = false) const = 0;
|
bool use_history = false,
|
||||||
|
bool download = false) const = 0;
|
||||||
|
|
||||||
virtual bool has_price() const = 0;
|
virtual bool has_price() const = 0;
|
||||||
virtual amount * per_item_price() const = 0;
|
virtual amount * per_item_price() const = 0;
|
||||||
|
|
|
||||||
67
reports.cc
67
reports.cc
|
|
@ -274,7 +274,9 @@ void report_balances(std::ostream& out, regexps_list& regexps)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acct->checked == 1) {
|
if (acct->checked == 1) {
|
||||||
amount * street = (*x)->cost->street(&end_date, get_quotes);
|
amount * street = (*x)->cost->street(have_ending ? &end_date : NULL,
|
||||||
|
cost_basis || get_quotes,
|
||||||
|
get_quotes);
|
||||||
if (cost_basis &&
|
if (cost_basis &&
|
||||||
street->commdty() == (*x)->cost->commdty() &&
|
street->commdty() == (*x)->cost->commdty() &&
|
||||||
(*x)->cost->has_price()) {
|
(*x)->cost->has_price()) {
|
||||||
|
|
@ -362,7 +364,8 @@ void print_register_transaction(std::ostream& out, entry *ent,
|
||||||
// Always display the street value, if prices have been
|
// Always display the street value, if prices have been
|
||||||
// specified
|
// specified
|
||||||
|
|
||||||
amount * street = xact->cost->street(&ent->date, get_quotes);
|
amount * street = xact->cost->street(&ent->date, cost_basis || get_quotes,
|
||||||
|
get_quotes);
|
||||||
balance.credit(street);
|
balance.credit(street);
|
||||||
|
|
||||||
// If there are two transactions, use the one which does not
|
// If there are two transactions, use the one which does not
|
||||||
|
|
@ -411,7 +414,8 @@ void print_register_transaction(std::ostream& out, entry *ent,
|
||||||
out << std::left << truncated((*y)->acct_as_str(), 22) << " ";
|
out << std::left << truncated((*y)->acct_as_str(), 22) << " ";
|
||||||
|
|
||||||
out.width(12);
|
out.width(12);
|
||||||
street = (*y)->cost->street(&ent->date, get_quotes);
|
street = (*y)->cost->street(&ent->date, cost_basis || get_quotes,
|
||||||
|
get_quotes);
|
||||||
out << std::right << street->as_str(true) << std::endl;
|
out << std::right << street->as_str(true) << std::endl;
|
||||||
delete street;
|
delete street;
|
||||||
}
|
}
|
||||||
|
|
@ -492,7 +496,9 @@ void print_register(std::ostream& out, const std::string& acct_name,
|
||||||
if (period == PERIOD_NONE) {
|
if (period == PERIOD_NONE) {
|
||||||
print_register_transaction(out, *i, *x, balance);
|
print_register_transaction(out, *i, *x, balance);
|
||||||
} else {
|
} else {
|
||||||
amount * street = (*x)->cost->street(&(*i)->date, get_quotes);
|
amount * street = (*x)->cost->street(&(*i)->date,
|
||||||
|
cost_basis || get_quotes,
|
||||||
|
get_quotes);
|
||||||
balance.credit(street);
|
balance.credit(street);
|
||||||
|
|
||||||
if (period_sum) {
|
if (period_sum) {
|
||||||
|
|
@ -544,12 +550,16 @@ static void equity_entry(account * acct, regexps_list& regexps,
|
||||||
|
|
||||||
transaction * xact = new transaction();
|
transaction * xact = new transaction();
|
||||||
xact->acct = const_cast<account *>(acct);
|
xact->acct = const_cast<account *>(acct);
|
||||||
xact->cost = (*i).second->street(&end_date, get_quotes);
|
xact->cost = (*i).second->street(have_ending ? &end_date : NULL,
|
||||||
|
cost_basis || get_quotes,
|
||||||
|
get_quotes);
|
||||||
opening.xacts.push_back(xact);
|
opening.xacts.push_back(xact);
|
||||||
|
|
||||||
xact = new transaction();
|
xact = new transaction();
|
||||||
xact->acct = main_ledger->find_account("Equity:Opening Balances");
|
xact->acct = main_ledger->find_account("Equity:Opening Balances");
|
||||||
xact->cost = (*i).second->street(&end_date, get_quotes);
|
xact->cost = (*i).second->street(have_ending ? &end_date : NULL,
|
||||||
|
cost_basis || get_quotes,
|
||||||
|
get_quotes);
|
||||||
xact->cost->negate();
|
xact->cost->negate();
|
||||||
opening.xacts.push_back(xact);
|
opening.xacts.push_back(xact);
|
||||||
}
|
}
|
||||||
|
|
@ -577,8 +587,39 @@ void equity_ledger(std::ostream& out, regexps_list& regexps)
|
||||||
equity_entry((*i).second, regexps, out);
|
equity_entry((*i).second, regexps, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Report on the price of any commodities matching REGEXPS. This can
|
||||||
|
// be used to see what something was worth at a specific time.
|
||||||
|
//
|
||||||
|
|
||||||
|
void price_report(std::ostream& out, regexps_list& regexps)
|
||||||
|
{
|
||||||
|
if (! have_ending) {
|
||||||
|
end_date = std::time(NULL);
|
||||||
|
have_ending = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (commodities_map_iterator i = main_ledger->commodities.begin();
|
||||||
|
i != main_ledger->commodities.end();
|
||||||
|
i++)
|
||||||
|
if (regexps.empty() || matches(regexps, (*i).first)) {
|
||||||
|
amount * price = (*i).second->price(have_ending ? &end_date : NULL,
|
||||||
|
cost_basis || get_quotes,
|
||||||
|
get_quotes);
|
||||||
|
if (price && ! price->is_zero()) {
|
||||||
|
out.width(20);
|
||||||
|
out << std::right << price->as_str() << " " << (*i).first
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
// Add a new entry, using hueristic logic to simplify the entry
|
// Add a new entry, using hueristic logic to simplify the entry
|
||||||
// requirements
|
// requirements
|
||||||
|
//
|
||||||
|
|
||||||
void add_new_entry(int index, int argc, char **argv)
|
void add_new_entry(int index, int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
|
@ -789,6 +830,7 @@ int main(int argc, char * argv[])
|
||||||
std::string prices;
|
std::string prices;
|
||||||
std::string limit;
|
std::string limit;
|
||||||
regexps_list regexps;
|
regexps_list regexps;
|
||||||
|
bool no_history = false;
|
||||||
|
|
||||||
std::vector<std::string> files;
|
std::vector<std::string> files;
|
||||||
|
|
||||||
|
|
@ -798,7 +840,7 @@ int main(int argc, char * argv[])
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while (-1 != (c = getopt(argc, argv,
|
while (-1 != (c = getopt(argc, argv,
|
||||||
"+b:e:d:cCUhBRV:f:i:p:PL:Q:vsSEnFMGl:N:"))) {
|
"+b:e:d:cCUhBRV:f:i:p:PL:Q:TvsSEnFMGl:N:"))) {
|
||||||
switch (char(c)) {
|
switch (char(c)) {
|
||||||
case 'b':
|
case 'b':
|
||||||
have_beginning = true;
|
have_beginning = true;
|
||||||
|
|
@ -872,8 +914,10 @@ int main(int argc, char * argv[])
|
||||||
|
|
||||||
case 'B':
|
case 'B':
|
||||||
cost_basis = true;
|
cost_basis = true;
|
||||||
|
// fall through...
|
||||||
|
case 'T':
|
||||||
|
no_history = true;
|
||||||
get_quotes = false;
|
get_quotes = false;
|
||||||
price_db = "";
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
|
|
@ -925,7 +969,7 @@ int main(int argc, char * argv[])
|
||||||
// If a price history file is specified with the environment
|
// If a price history file is specified with the environment
|
||||||
// variable PRICE_HIST, add it to the list of ledger files to read.
|
// variable PRICE_HIST, add it to the list of ledger files to read.
|
||||||
|
|
||||||
if (! cost_basis) {
|
if (! no_history) {
|
||||||
if (price_db.empty())
|
if (price_db.empty())
|
||||||
if (char * p = std::getenv("PRICE_HIST")) {
|
if (char * p = std::getenv("PRICE_HIST")) {
|
||||||
get_quotes = true;
|
get_quotes = true;
|
||||||
|
|
@ -962,7 +1006,7 @@ int main(int argc, char * argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! price_db.empty())
|
if (! no_history && ! price_db.empty())
|
||||||
entry_count += parse_ledger_file(main_ledger, price_db,
|
entry_count += parse_ledger_file(main_ledger, price_db,
|
||||||
regexps, command == "equity");
|
regexps, command == "equity");
|
||||||
|
|
||||||
|
|
@ -991,6 +1035,9 @@ int main(int argc, char * argv[])
|
||||||
else if (command == "equity") {
|
else if (command == "equity") {
|
||||||
equity_ledger(std::cout, regexps);
|
equity_ledger(std::cout, regexps);
|
||||||
}
|
}
|
||||||
|
else if (command == "price" || command == "prices") {
|
||||||
|
price_report(std::cout, regexps);
|
||||||
|
}
|
||||||
else if (command == "entry") {
|
else if (command == "entry") {
|
||||||
add_new_entry(index, argc, argv);
|
add_new_entry(index, argc, argv);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue