diff options
author | John Wiegley <johnw@newartisans.com> | 2004-06-21 04:52:43 -0400 |
---|---|---|
committer | johnw <johnw@newartisans.com> | 2004-06-21 04:52:43 -0400 |
commit | c892e8c7ad0aaf6c47ff6e9075149a76188ae670 (patch) | |
tree | c21e7f6145722e430439b00785ebe63f609823bd | |
parent | 39ee2ae3d846b4bffa4e42ba4f3a9bc320ca9270 (diff) | |
download | fork-ledger-c892e8c7ad0aaf6c47ff6e9075149a76188ae670.tar.gz fork-ledger-c892e8c7ad0aaf6c47ff6e9075149a76188ae670.tar.bz2 fork-ledger-c892e8c7ad0aaf6c47ff6e9075149a76188ae670.zip |
fixes to price history support
-rw-r--r-- | README | 4 | ||||
-rw-r--r-- | amount.cc | 26 | ||||
-rw-r--r-- | ledger.cc | 60 | ||||
-rw-r--r-- | ledger.h | 6 | ||||
-rw-r--r-- | parse.cc | 12 | ||||
-rw-r--r-- | reports.cc | 35 |
6 files changed, 95 insertions, 48 deletions
@@ -1040,7 +1040,9 @@ launches =vi= to let you confirm that the entry looks appropriate. -B :: When printing accounts containing commodities, display the base price for the commodity, rather than the quantity of that commodity - (the default) or its current price (if -P is used). + (the default) or its current price (if =-P= or =-Q= is used). This + option causes only the price at time(s) of purchase to be + considered, not the current or historical price afterwards. -b DATE :: Only consider entries occuring on or after the given date. @@ -56,11 +56,14 @@ class gmp_amount : public amount virtual amount * copy() const; virtual amount * value(const amount *) const; - virtual amount * street(bool get_quotes) const; + virtual void set_value(const amount * val); + virtual amount * street(std::time_t * when = NULL, + bool get_quotes = false) const; + virtual bool has_price() const { return priced; } - virtual void set_value(const amount * val); + virtual amount * per_item_price() const; virtual bool is_zero() const; virtual bool is_negative() const; @@ -158,6 +161,19 @@ amount * gmp_amount::copy() const return new_amt; } +amount * gmp_amount::per_item_price() const +{ + if (! priced) + return NULL; + + gmp_amount * new_amt = new gmp_amount(); + + mpz_set(new_amt->quantity, price); + new_amt->quantity_comm = price_comm; + + return new_amt; +} + amount * gmp_amount::value(const amount * pr) const { if (pr) { @@ -199,9 +215,11 @@ amount * gmp_amount::value(const amount * pr) const } } -amount * gmp_amount::street(bool get_quotes) const +amount * gmp_amount::street(std::time_t * when, bool get_quotes) const { static std::time_t now = std::time(NULL); + if (! when) + when = &now; amount * amt = copy(); @@ -210,7 +228,7 @@ amount * gmp_amount::street(bool get_quotes) const int max = 10; while (--max >= 0) { - amount * price = amt->commdty()->price(&now, get_quotes); + amount * price = amt->commdty()->price(when, get_quotes); if (! price) break; @@ -31,7 +31,7 @@ void commodity::set_price(amount * price, std::time_t * when) amount * commodity::price(std::time_t * when, bool download) const { - if (conversion) + if (conversion || ! when) return conversion; std::time_t age; @@ -40,7 +40,7 @@ amount * commodity::price(std::time_t * when, bool download) const for (price_map::reverse_iterator i = history.rbegin(); i != history.rend(); i++) { - if (*when >= (*i).first) { + if (std::difftime(*when, (*i).first) >= 0) { age = (*i).first; price = (*i).second; break; @@ -48,9 +48,11 @@ amount * commodity::price(std::time_t * when, bool download) const } extern long pricing_leeway; + time_t now = time(NULL); // the time of the query if (download && ! sought && - (! price || (*when - age) > pricing_leeway)) { + std::difftime(now, *when) < pricing_leeway && + (! price || std::difftime(*when, age) > pricing_leeway)) { using namespace std; // Only consult the Internet once for any commodity @@ -59,7 +61,17 @@ amount * commodity::price(std::time_t * when, bool download) const char buf[256]; buf[0] = '\0'; - std::cout << "Consulting the Internet: " << symbol << std::endl; + 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); @@ -73,12 +85,12 @@ amount * commodity::price(std::time_t * when, bool download) const if (p) *p = '\0'; price = create_amount(buf); - const_cast<commodity *>(this)->set_price(price, when); + const_cast<commodity *>(this)->set_price(price, &now); extern string price_db; if (! price_db.empty()) { char buf[128]; - strftime(buf, 127, "%Y/%m/%d", localtime(when)); + strftime(buf, 127, "%Y/%m/%d %H:%M:%S", localtime(&now)); ofstream database(price_db.c_str(), ios_base::out | ios_base::app); database << "P " << buf << " " << symbol << " " << price->as_str() << endl; @@ -224,34 +236,30 @@ bool entry::finalize(bool do_compute) delete value; } - // If one transaction is of a different commodity than the others, - // and it has no per-unit price, determine its price by dividing - // the unit count into the value of the balance. - // - // NOTE: We don't do this for prefix-style or joined-symbol - // commodities. Also, do it for the last eligible commodity first, - // if it meets the criteria. + // If one transaction of a two-line transaction is of a different + // commodity than the others, and it has no per-unit price, + // determine its price by dividing the unit count into the value of + // the balance. This is done for the last eligible commodity. if (! balance.amounts.empty() && balance.amounts.size() == 2) { for (std::list<transaction *>::iterator x = xacts.begin(); x != xacts.end(); x++) { - if ((*x)->is_virtual) + if ((*x)->is_virtual || (*x)->cost->has_price()) continue; - if (! (*x)->cost->has_price() && - ! (*x)->cost->commdty()->prefix && - (*x)->cost->commdty()->separate) { - for (totals::iterator i = balance.amounts.begin(); - i != balance.amounts.end(); - i++) { - if ((*i).second->commdty() != (*x)->cost->commdty()) { - (*x)->cost->set_value((*i).second); - break; - } + for (totals::iterator i = balance.amounts.begin(); + i != balance.amounts.end(); + i++) + if ((*i).second->commdty() != (*x)->cost->commdty()) { + (*x)->cost->set_value((*i).second); + assert((*x)->cost->has_price()); + (*x)->cost->commdty()->set_price((*x)->cost->per_item_price(), + &date); + break; } - break; - } + + break; } } @@ -82,10 +82,12 @@ class amount virtual amount * copy() const = 0; virtual amount * value(const amount * pr = NULL) const = 0; - virtual amount * street(bool get_quotes) const = 0; + virtual void set_value(const amount * pr) = 0; + virtual amount * street(std::time_t * when = NULL, + bool get_quotes = false) const = 0; virtual bool has_price() const = 0; - virtual void set_value(const amount * pr) = 0; + virtual amount * per_item_price() const = 0; // Comparison @@ -420,7 +420,7 @@ int parse_ledger(book * ledger, std::istream& in, case 'P': { // a pricing entry in >> c; - time_t date; + std::time_t date; std::string symbol; in >> line; // the date @@ -429,6 +429,16 @@ int parse_ledger(book * ledger, std::istream& in, << ": Failed to parse date: " << line << std::endl; break; } + + int hour, min, sec; + in >> hour; // the time + in >> c; + in >> min; + in >> c; + in >> sec; + date = std::time_t(((unsigned long) date) + + hour * 3600 + min * 60 + sec); + in >> symbol; // the commodity in >> line; // the price @@ -274,7 +274,7 @@ void report_balances(std::ostream& out, regexps_list& regexps) } if (acct->checked == 1) { - amount * street = (*x)->cost->street(get_quotes); + amount * street = (*x)->cost->street(&end_date, get_quotes); if (cost_basis && street->commdty() == (*x)->cost->commdty() && (*x)->cost->has_price()) { @@ -362,7 +362,7 @@ void print_register_transaction(std::ostream& out, entry *ent, // Always display the street value, if prices have been // specified - amount * street = xact->cost->street(get_quotes); + amount * street = xact->cost->street(&ent->date, get_quotes); balance.credit(street); // If there are two transactions, use the one which does not @@ -411,7 +411,7 @@ 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(get_quotes); + street = (*y)->cost->street(&ent->date, get_quotes); out << std::right << street->as_str(true) << std::endl; delete street; } @@ -492,7 +492,7 @@ 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(get_quotes); + amount * street = (*x)->cost->street(&(*i)->date, get_quotes); balance.credit(street); if (period_sum) { @@ -544,12 +544,12 @@ static void equity_entry(account * acct, regexps_list& regexps, transaction * xact = new transaction(); xact->acct = const_cast<account *>(acct); - xact->cost = (*i).second->street(get_quotes); + xact->cost = (*i).second->street(&end_date, get_quotes); opening.xacts.push_back(xact); xact = new transaction(); xact->acct = main_ledger->find_account("Equity:Opening Balances"); - xact->cost = (*i).second->street(get_quotes); + xact->cost = (*i).second->street(&end_date, get_quotes); xact->cost->negate(); opening.xacts.push_back(xact); } @@ -833,7 +833,6 @@ int main(int argc, char * argv[]) case 'f': files.push_back(optarg); break; case 'C': cleared_only = true; break; case 'U': uncleared_only = true; break; - case 'B': cost_basis = true; break; case 'R': show_virtual = false; break; case 's': show_children = true; break; case 'S': show_sorted = true; break; @@ -871,6 +870,12 @@ int main(int argc, char * argv[]) price_db = optarg; break; + case 'B': + cost_basis = true; + get_quotes = false; + price_db = ""; + break; + case 'l': lower_limit = create_amount(optarg); break; @@ -920,14 +925,16 @@ 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 (price_db.empty()) - if (char * p = std::getenv("PRICE_HIST")) { - get_quotes = true; - price_db = p; - } + if (! cost_basis) { + if (price_db.empty()) + if (char * p = std::getenv("PRICE_HIST")) { + get_quotes = true; + price_db = p; + } - if (char * p = std::getenv("PRICE_EXP")) - pricing_leeway = std::atol(p) * 60; + if (char * p = std::getenv("PRICE_EXP")) + pricing_leeway = std::atol(p) * 60; + } // A ledger data file must be specified |