diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README | 18 | ||||
-rw-r--r-- | amount.cc | 8 | ||||
-rw-r--r-- | ledger.cc | 16 | ||||
-rw-r--r-- | ledger.h | 6 | ||||
-rw-r--r-- | reports.cc | 67 |
6 files changed, 86 insertions, 31 deletions
@@ -4,7 +4,7 @@ OBJS = $(patsubst %.cc,%.o,$(CODE)) CXX = g++ CFLAGS = #-Wall -ansi -pedantic 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 LIBS = -L/sw/lib -lgmpxx -lgmp -lpcre @@ -991,6 +991,15 @@ above to: ledger -e 2004/1/1 equity -^Income -^Expenses > /tmp/balances </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 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 "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 :: 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. 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 good choice. -PRICE_EXP :: +<verbatim>PRICE_EXP</verbatim> :: The number of minutes before pricing data becomes out-of-date. The default is one day. Use =-L= to temporarily decrease or increase the value. @@ -58,7 +58,8 @@ class gmp_amount : public amount virtual amount * value(const amount *) const; virtual void set_value(const amount * val); 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 { 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); if (! when) @@ -228,7 +230,7 @@ amount * gmp_amount::street(std::time_t * when, bool get_quotes) const int max = 10; while (--max >= 0) { - amount * price = amt->commdty()->price(when, get_quotes); + amount * price = amt->commdty()->price(when, use_history, download); if (! price) break; @@ -29,9 +29,10 @@ void commodity::set_price(amount * price, std::time_t * when) 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; std::time_t age; @@ -61,17 +62,6 @@ amount * commodity::price(std::time_t * when, bool download) const char buf[256]; 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 (feof(fp) || ! fgets(buf, 255, fp)) { fclose(fp); @@ -64,7 +64,8 @@ class commodity ~commodity(); 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; @@ -84,7 +85,8 @@ class amount virtual amount * value(const amount * pr = NULL) const = 0; virtual void set_value(const amount * pr) = 0; 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 amount * per_item_price() const = 0; @@ -274,7 +274,9 @@ void report_balances(std::ostream& out, regexps_list& regexps) } 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 && street->commdty() == (*x)->cost->commdty() && (*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 // 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); // 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.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; delete street; } @@ -492,7 +496,9 @@ void print_register(std::ostream& out, const std::string& acct_name, if (period == PERIOD_NONE) { print_register_transaction(out, *i, *x, balance); } 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); if (period_sum) { @@ -544,12 +550,16 @@ static void equity_entry(account * acct, regexps_list& regexps, transaction * xact = new transaction(); 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); xact = new transaction(); 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(); opening.xacts.push_back(xact); } @@ -577,8 +587,39 @@ void equity_ledger(std::ostream& out, regexps_list& regexps) 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 // requirements +// 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 limit; regexps_list regexps; + bool no_history = false; std::vector<std::string> files; @@ -798,7 +840,7 @@ int main(int argc, char * argv[]) int c; 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)) { case 'b': have_beginning = true; @@ -872,8 +914,10 @@ int main(int argc, char * argv[]) case 'B': cost_basis = true; + // fall through... + case 'T': + no_history = true; get_quotes = false; - price_db = ""; break; case 'l': @@ -925,7 +969,7 @@ int main(int argc, char * argv[]) // If a price history file is specified with the environment // variable PRICE_HIST, add it to the list of ledger files to read. - if (! cost_basis) { + if (! no_history) { if (price_db.empty()) if (char * p = std::getenv("PRICE_HIST")) { 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, regexps, command == "equity"); @@ -991,6 +1035,9 @@ int main(int argc, char * argv[]) else if (command == "equity") { equity_ledger(std::cout, regexps); } + else if (command == "price" || command == "prices") { + price_report(std::cout, regexps); + } else if (command == "entry") { add_new_entry(index, argc, argv); } |