Exemplo n.º 1
0
 def _cache_accounts_last_commodity_for_account_and_commodities(self):
     with self.slave_lock:
         try:
             self.pipe.send(
                 (CMD_GET_A_LCFA_C,
                  IFCHANGED if "accounts" in self.cache else UNCONDITIONAL))
             result = self.pipe.recv()
             if isinstance(result, BaseException):
                 raise result
             if result == UNCHANGED:
                 assert "accounts" in self.cache
             else:
                 accounts = result[0]
                 last_commodity_for_account = dict(
                     (acc, ledger.Amount(amt))
                     for acc, amt in list(result[1].items()))
                 all_commodities = [ledger.Amount(c) for c in result[2]]
                 self.cache["accounts"] = accounts
                 self.cache["last_commodity_for_account"] = (
                     last_commodity_for_account)
                 self.cache["all_commodities"] = all_commodities
         except BaseException:
             self.cache = {}
             self._start_slave()
             raise
Exemplo n.º 2
0
def prompt_for_amount(fdin, fdout, prompt, commodity_example):
    cols = get_terminal_width(fdin)
    line = prompt + ("" if not commodity_example else " '': %s" % commodity_example)
    print_line_ellipsized(fdout, cols, line)
    x = []
    match = commodity_example
    while True:
        char = read_one_character(fdin)
        if char in "\n\r\t":
            break
        elif char == "\x7f":
            if x: x.pop()
        else:
            x.append(char)
        inp = "".join(x)
        try:
            match = ledger.Amount(inp) * commodity_example
        except ArithmeticError:
            try:
                match = ledger.Amount(inp)
            except ArithmeticError:
                match = ""
        cols = get_terminal_width(fdin)
        go_cursor_up(fdout)
        blank_line(fdout, cols)
        go_cursor_up(fdout)
        line = prompt + " " + "'%s': %s" % (inp, match)
        print_line_ellipsized(fdout, cols, line)
    assert match is not None
    return match
Exemplo n.º 3
0
 def __init__(self, number, date, amount, acct):
     self.number = number
     self.date = date
     self.amount = amount
     quantity = ledger.Amount(amount.strip_annotations())
     self.price = self.amount.price() / quantity
     self.account = acct
Exemplo n.º 4
0
 def parse_ledger_bal(self, text):
     """Demands '--balance-format=++ %(account)\n%(amount)\n' format.
     Demands '--date-format=%Y-%m-%d' date format."""
     lines = [x.strip() for x in text.splitlines() if x.strip()]
     account = None
     for line in lines:
         if line.startswith("++ "):
             account = line[3:]
         else:
             amount = ledger.Amount(line)
             date = re.findall(r'\[\d\d\d\d-\d\d-\d\d]', line)
             assert len(date) < 2
             if date:
                 date = common.parse_date(date[0][1:-1])
             else:
                 date = None
             try:
                 lot = Lot(self.nextnum(),
                         date,
                         amount,
                         account)
                 self.lots.append(lot)
             except TypeError:
                 # At this point, we know the commodity does not have a price.
                 # So we ignore this.
                 pass
Exemplo n.º 5
0
    def get_quote(self, commodity, denominated_in):
        """Returns the price in the denominated_in currency,
        and the datetime.

        Args:
            commodity: a Ledger commodity
            denominated_in: a Ledger commodity

        Returns:
            price: ledger.Amount instance
            datetime: datetime.datetime instance
        """
        if not isinstance(commodity, ledger.Commodity):
            raise ValueError("commodity must be a Ledger commodity")
        if not isinstance(denominated_in, ledger.Commodity):
            raise ValueError("denominated_in must be a Ledger commodity")
        if str(commodity) not in ["BTC", "XBT"]:
            raise ValueError(
                "bitcoin charts can only provide quotes for BTC / XBT")

        data = json_from_uri(
            "https://api.bitcoincharts.com/v1/weighted_prices.json")
        try:
            k = "USD" if str(denominated_in) == "$" else str(denominated_in)
            amount = data[k].get("24h", data[k]["7d"])
        except KeyError:
            raise ValueError("bitcoin charts can't provide quotes in %s" %
                             denominated_in)
        a = ledger.Amount(amount)
        a.commodity = denominated_in
        d = datetime.datetime.now()
        return a, d
Exemplo n.º 6
0
    def entry_changed(self, w, *args):
        self._adjust_entry_size(w)

        if self.donotreact:
            return

        text = self.entry.get_text()
        i = text.find("@")
        if i != -1:
            price = text[i:] if text[i:] else None
            text = text[:i]
        else:
            price = None

        try:
            p = ledger.Amount(text)
        except ArithmeticError:
            self.set_amount_and_price(None, price, True)
            self.emit("changed")
            return

        if not str(p.commodity):
            p.commodity = self.default_commodity
        if str(p):
            self.set_amount_and_price(p, price, True)
        else:
            self.set_amount_and_price(None, price, True)

        self.emit("changed")
Exemplo n.º 7
0
def main():
    s = common.Settings.load_or_defaults(
        os.path.expanduser("~/.ledgerhelpers.ini"))
    j = journal.Journal.from_file(common.find_ledger_file(), None)
    accts, commodities = j.accounts_and_last_commodity_for_account()

    when = common.prompt_for_date(sys.stdin, sys.stdout, "When?",
                                  s.get("last_date", datetime.date.today()))
    if when == datetime.date.today():
        del s["last_date"]
    else:
        s["last_date"] = when

    asset1 = common.prompt_for_account(sys.stdin, sys.stdout, accts,
                                       "From where?",
                                       s.get("last_withdrawal_account", None))
    assert asset1, "Not an account: %s" % asset1
    s["last_withdrawal_account"] = asset1
    asset1_currency = commodities.get(asset1, ledger.Amount("$ 1"))

    asset2 = common.prompt_for_account(sys.stdin, sys.stdout, accts,
                                       "To where?",
                                       s.get("last_deposit_account", None))
    assert asset2, "Not an account: %s" % asset2
    s["last_deposit_account"] = asset2
    asset2_currency = commodities.get(asset2, ledger.Amount("$ 1"))

    amount1 = common.prompt_for_amount(sys.stdin, sys.stdout, "How much?",
                                       asset1_currency)

    amount2 = common.prompt_for_amount(sys.stdin, sys.stdout,
                                       "What was deposited?", asset2_currency)

    lines = j.generate_record("Withdrawal", when, None, "", [
        (asset1, -1 * amount1),
        (asset2, amount2),
    ])
    print "========== Record =========="
    print "\n".join(lines)
    save = common.yesno(
        sys.stdin, sys.stderr,
        "Hit ENTER or y to save it to the file, BACKSPACE or n to skip saving: "
    )
    if save:
        j.add_text_to_file(lines)
Exemplo n.º 8
0
def depreciate(amount, rate, t0, T, ndigits=2):
    """Return the depreciation between two points in time.

    This function returns positive values for depreciation and
    negative values for appreciation.

    """
    c, v = amount.commodity, amount.to_double()
    vt = round(v * (exp(-rate * t0) - exp(-rate * T)), ndigits)
    return ledger.Amount(c.symbol + str(vt))
Exemplo n.º 9
0
 def __render_json_balance(self, request, upr):
     if not upr.path == b'/accountbalance.json':
         return False
     query = urllib.parse.parse_qs(upr.query.decode("utf8"),
                                   strict_parsing=False)
     request.setHeader(b"content-type", b"application/json")
     if not "account" in query:
         return b"{}"
     qryaccts = query["account"]
     cur_amtsum = defaultdict(lambda: ledger.Amount(0, ""))
     for acct, amt in accounts_:
         if acct.startswith(qryaccts[0]):
             cur_amtsum[amt.currency] += amt
     return json.dumps({
         "account": qryaccts[0],
         "balance": list(map(str, cur_amtsum.values()))
     }).encode("utf-8")
Exemplo n.º 10
0
def f2p(data, Posting):
    from re import escape
    postings = []
    for i in xrange(len(data.getlist('account'))):
        amount = data.getlist('amount')[i]
        commodity = data.getlist('commodity')[i]
        sign = data.getlist('dir')[i]
        if amount:
            if commodity and (commodity != '$'):
                amount = amount + ' ' + escape(commodity)
            else:
                amount = '$' + amount
            amount = ledger.Amount(amount)
            if sign == 'from':
                amount = -amount
        postings.append(Posting(data.getlist('account')[i], amount))
    return postings
Exemplo n.º 11
0
def main():
    args = parse_args()

    env = Environment(
        loader=FileSystemLoader(os.path.dirname(sys.argv[0])),
        autoescape=True)
    template = env.get_template('assets.html.j2')

    journal = ledger.read_journal(args.file)

    balances_by_date = {}  # type: Dict[date, Dict[AccountName, Dict[CommodityName, float]]]
    last_date = None
    balances = {}  # type: Dict[AccountName, Dict[CommodityName, float]]
    for post in sorted(journal.query(args.query),
                       key=lambda p: p.xact.date):
        date = post.xact.date
        account = post.account.fullname()
        commodity = post.amount.commodity.symbol.strip('"')
        amount = post.amount.to_double()

        if date != last_date:
            if last_date is not None:
                balances_by_date[last_date] = deepcopy(balances)
            last_date = date
        if account not in balances:
            balances[account] = {}  # type: Dict[CommodityName, float]
        if commodity not in balances[account]:
            balances[account][commodity] = 0
        balances[account][commodity] += amount
    balances_by_date[last_date] = deepcopy(balances)

    base_commodity = ledger.commodities.find(args.commodity)
    worth_by_date = {
        date: {
            account: amount_sum(date, base_commodity,
                (ledger.Amount('{:f}'.format(amount))
                       .with_commodity(ledger.commodities.find(commodity))
                 for commodity, amount in commodity_balances.items()))
            for account, commodity_balances in balances.items()}
        for date, balances in balances_by_date.items()}

    with file_or_std(args.output, sys.stdout) as f:
        print(template.render(
                balances=sorted(list(worth_by_date.items())),
                keys=sorted(list(balances.keys()))),
            file=f)
Exemplo n.º 12
0
    def get_quote(self,
                  commodity,
                  denominated_in,
                  commodity_is_currency_pair=False):
        """Returns the price in the appraised_as currency, and the datetime.

        Args:
            commodity: a Ledger commodity representing a non-currency
                       commodity
            denominated_in: a Ledger commodity

        Returns:
            price: ledger.Amount instance
            datetime: datetime.datetime instance
        """
        if not isinstance(commodity, ledger.Commodity):
            raise ValueError("commodity must be a Ledger commodity")
        if not isinstance(denominated_in, ledger.Commodity):
            raise ValueError("denominated_in must be a Ledger commodity")
        if commodity_is_currency_pair:
            source = str(commodity)
            source = source if source != "$" else "USD"
            target = str(denominated_in)
            target = target if target != "$" else "USD"
            pair = source + target
            s = yahoo_finance.Currency(pair)
            try:
                price, date = s.get_rate(), s.get_trade_datetime()
            except KeyError:
                raise ValueError("Yahoo! Finance can't find currency pair %s" %
                                 pair)
        else:
            if str(denominated_in) not in ["$", "USD"]:
                raise ValueError("Yahoo! Finance can't quote in %s" %
                                 denominated_in)
            s = yahoo_finance.Share(str(commodity))
            try:
                price, date = s.get_price(), s.get_trade_datetime()
            except KeyError:
                raise ValueError("Yahoo! Finance can't find commodity %s" %
                                 commodity)
        a = ledger.Amount(price)
        a.commodity = denominated_in
        d = datetime.datetime.strptime(date, '%Y-%m-%d %H:%M:%S UTC+0000')
        return a, d
Exemplo n.º 13
0
 def __init__(self, display=True):
     Gtk.Grid.__init__(self)
     self.amount = None
     self.entry = Gtk.Entry()
     self.entry.set_width_chars(8)
     if display:
         self.display = Gtk.Label()
     else:
         self.display = None
     self.entry.set_alignment(1.0)
     self.attach(self.entry, 0, 0, 1, 1)
     if self.display:
         self.attach(self.display, 1, 0, 1, 1)
         self.display.set_halign(Gtk.Align.END)
         self.display.set_justify(Gtk.Justification.RIGHT)
     self.set_column_spacing(4)
     self.donotreact = False
     self.entry.connect("changed", self.entry_changed)
     self.set_default_commodity(ledger.Amount("$ 1").commodity)
     self.set_activates_default = self.entry.set_activates_default
Exemplo n.º 14
0
    def entry_changed(self, w, *args):
        self._adjust_entry_size(w)

        if self.donotreact:
            return

        text = self.entry.get_text()

        try:
            p = ledger.Amount(text)
        except ArithmeticError:
            self.set_amount(None, True)
            self.emit("changed")
            return

        if not str(p.commodity):
            p.commodity = self.default_commodity
        if str(p):
            self.set_amount(p, True)
        else:
            self.set_amount(None, True)

        self.emit("changed")
Exemplo n.º 15
0
from __future__ import print_function

import ledger

eur = ledger.commodities.find_or_create('EUR')

total_eur = ledger.Amount("0.00 EUR")
total_gbp = ledger.Amount("0.00 GBP")
total = ledger.Amount("0.00 EUR")

for post in ledger.read_journal("test/regress/78AB4B87.dat").query("^income:"):
    print(post.amount)
    print(post.amount.commodity)
    if post.amount.commodity == "EUR":
        total_eur += post.amount
    elif post.amount.commodity == "GBP":
        total_gbp += post.amount

    a = post.amount.value(eur)
    if a:
        print("Total is presently: (%s)" % total)
        print("Converted to EUR:   (%s)" % a)
        total += a
        print("Total is now:       (%s)" % total)
    else:
        print("Cannot convert '%s'" % post.amount)
    print()

print(total)
Exemplo n.º 16
0
def discount(amount, rate, time, ndigits=2):
    """Return the amount discounted by continuous rate and time."""
    c, v = amount.commodity, amount.to_double()
    vt = round(v * exp(-rate * time), ndigits)
    return ledger.Amount(c.symbol + str(vt))
Exemplo n.º 17
0
 def commodity(self, label, create=False):
     pool = ledger.Amount("$ 1").commodity.pool()
     if create:
         return pool.find_or_create(label)
     else:
         return pool.find(label)
Exemplo n.º 18
0
Arquivo: demo.py Projeto: xnox/ledger
for symbol in comms.iterkeys():
    pass
for commodity in comms.itervalues():
    pass
#for symbol, commodity in comms.iteritems():
#    pass
#for symbol, commodity in comms:
#    pass

# Another important thing about commodities is that they remember if they've
# been exchanged for another commodity, and what the conversion rate was on
# that date.  You can record specific conversion rates for any date using the
# `exchange' method.

comms.exchange(eur, ledger.Amount('$0.77'))  # Trade 1 EUR for $0.77
comms.exchange(eur, ledger.Amount('$0.66'), datetime.now())

# For the most part, however, you won't be interacting with commodities
# directly, except maybe to look at their `symbol'.

assertEqual('$', usd.symbol)
assertEqual('$', comms['$'].symbol)

###############################################################################
#
# AMOUNTS & BALANCES
#
# Ledger deals with two basic numerical values: Amount and Balance objects.
# An Amount is an infinite-precision rational with an associated commodity
# (even if it is the null commodity, which is called an "uncommoditized
Exemplo n.º 19
0
#assert(eurofix.isBalanced())

#### Variante 2: ein Posting für jede Ware
gewinn_transactions = []
for pp in problematic_transaction.postings:
    if pp.account in inventory_accounts_ and pp.account in acct_currency_amt_dict and not pp.post_posting_assert_amount is None and pp.post_posting_assert_amount.currency in acct_currency_amt_dict[pp.account]:
        gt = ledger.Transaction("GEWINN %s" % pp.post_posting_assert_amount.currency, problematic_transaction.date)
        diff = round(pp.post_posting_assert_amount.quantity - acct_currency_amt_dict[pp.account][pp.post_posting_assert_amount.currency].quantity,4)
        if diff == 0:
            continue
        if diff > 0:
            gt.addDescription("WARNING: commoditiy difference is positive!!!!! WARNING")
            gt.addDescription("WARNING: looks like an inventory count mistake or undocumented commodity donation")
        einkaufspreis = acct_currency_amt_dict[pp.account][pp.post_posting_assert_amount.currency].perunitprice
        verkaufspreis = pp.amount.perunitprice
        gt.addPosting(ledger.Posting(pp.account, ledger.Amount(diff,pp.post_posting_assert_amount.currency).addPerUnitPrice(einkaufspreis)))
        #add comment: % gewinn
        gumsatz = verkaufspreis.quantity * diff
        geinkaufspreis = gt.postings[0].amount.totalprice.quantity
        revenue_acct = revenue_accounts_[inventory_accounts_.index(pp.account)]
        gt.addPosting(ledger.Posting(revenue_acct, None).addComment("(%.2f%% Gewinn)" % (  100*(1.0+(geinkaufspreis/gumsatz))  )))
        gt.addPosting(ledger.Posting(register_account_, ledger.Amount(gumsatz * -1,verkaufspreis.currency)))
        gt.unelideJokerPostings()
        gewinn_transactions.append(gt)

register_assert_euro_postings = [p for p in problematic_transaction.postings if p.account == register_account_ and p.post_posting_assert_amount.currency == default_currency_]
register_previousassert_euro_postings = [p for p in journal[last_good_inventur_transaction_index].postings if p.account == register_account_ and p.post_posting_assert_amount.currency == default_currency_]

if len(register_assert_euro_postings) == 1:
    register_assert_euro = register_assert_euro_postings[0].post_posting_assert_amount.quantity
    if len(register_previousassert_euro_postings) == 1:
Exemplo n.º 20
0
    (
        r"[0-9]+(\.[0-9]+)?", number
    ),  # Arbitrary numbers. Values must be positive, and values <1 must be written with a zero before the decimal place (ex: 0.5, not .5)
    (r"\n+", endofline),  # newlines = end of statement
    (r"#.*", comment),  # comments start with hashes (#)
    (r"\s+", None),  # whitespace, which is ignored
])

# housekeeping vars
linenum = 0

# stores variable state
var_dict = {}

# zero, used later in subz
zero = ledger.Amount(0)

# to strip the $ off of variables
re_devar = re.compile("\$(\w+)")

# read in the command files line by line
for cmdfile_index in range(4, len(sys.argv)):
    cmdfile = sys.argv[cmdfile_index]

    with open(cmdfile, 'r') as f:
        for line in f:
            linenum += 1

            # parse it
            tokens, remainder = scanner.scan(line)
            if remainder:
Exemplo n.º 21
0
def main():
    journal, s = gui.load_journal_and_settings_for_gui()
    accts, unused_commodities = journal.accounts_and_last_commodity_for_account(
    )

    saleacct = common.prompt_for_account(
        sys.stdin, sys.stdout, accts,
        "Which account was the sold commodity stored in?",
        s.get("last_sellstock_account", None))
    assert saleacct, "Not an account: %s" % saleacct
    s["last_sellstock_account"] = saleacct

    commissionsaccount = common.prompt_for_account(
        sys.stdin, sys.stdout, accts,
        "Which account to account for commissions?",
        s.get("last_commissions_account", None))
    assert commissionsaccount, "Not an account: %s" % commissionsaccount
    s["last_commissions_account"] = commissionsaccount

    gainslossesacct = common.prompt_for_account(
        sys.stdin, sys.stdout, accts,
        "Which account to credit gains and losses?",
        s.get("last_gainslosses_account",
              "Capital:Recognized gains and losses"))
    assert gainslossesacct, "Not an account: %s" % gainslossesacct
    s["last_gainslosses_account"] = gainslossesacct

    target_amount = common.prompt_for_amount(
        sys.stdin, sys.stdout, "How many units of what commodity?",
        ledger.Amount("$ 1"))
    target_sale_price = common.prompt_for_amount(
        sys.stdin, sys.stdout, "What is the sale price of the commodity?",
        ledger.Amount("$ 1"))
    commission = common.prompt_for_amount(
        sys.stdin, sys.stdout, "What was the commission of the trade?",
        ledger.Amount("$ 1"))

    all_lots = Lots()
    lots_text = subprocess.check_output([
        'ledger', 'bal', '--lots', '--lot-dates', '--lot-prices',
        '--date-format=%Y-%m-%d', '--sort=date',
        '--balance-format=++ %(account)\n%(amount)\n', saleacct
    ])
    all_lots.parse_ledger_bal(lots_text)

    print("=========== Read ===========")
    for l in all_lots:
        print(l)

    lots_produced = all_lots.subtract(target_amount)

    print("========= Computed =========")
    for l in lots_produced:
        print(l)

    print("=========== Left ===========")
    for l in all_lots:
        print(l)

    lines = []
    tpl = "%s {%s}%s @ %s"
    datetpl = ' [%s]'
    for l in lots_produced:
        m = -1 * l.amount
        if m.commodity.details.date:
            datetext = datetpl % m.commodity.details.date.strftime("%Y-%m-%d")
        else:
            datetext = ''
        lines.append((l.account,
                      tpl % (m.strip_annotations(), m.commodity.details.price,
                             datetext, target_sale_price)))
        diff = (l.price - target_sale_price) * l.amount
        lines.append((gainslossesacct, diff))
    totalsale = target_sale_price * sum(l.amount.number()
                                        for l in lots_produced)
    lines.append((saleacct, totalsale - commission))
    lines.append((commissionsaccount, commission))

    lines = journal.generate_record(
        "Sale of %s" % (target_amount),
        datetime.date.today(),
        None,
        "",
        lines,
    )
    print("========== Record ==========")
    print("\n".join(lines))
    save = common.yesno(
        sys.stdin, sys.stderr,
        "Hit ENTER or y to save it to the file, BACKSPACE or n to skip saving: "
    )
    if save:
        journal.add_text_to_file(lines)
Exemplo n.º 22
0
# There are a few built-in commodities: null, %, h, m and s
assertEqual([u'', u'$', u'%', u'EUR', u'XCD', u'h', u'm', u's'],
            sorted(pool.keys()))

for symbol in pool.iterkeys():
    pass
for commodity in pool.itervalues():
    pass

# jww (2009-11-19): Not working: missing conversion from std::pair
#for symbol, commodity in pool.iteritems(): pass
#for symbol, commodity in pool: pass

# This creates a price exchange entry, trading EUR for $0.77 each at the
# current time.
pool.exchange(eur, ledger.Amount('$0.77'))

# AMOUNTS & BALANCES

# When two amounts are multipied or divided, the result carries the commodity
# of the first term.  So, 1 EUR / $0.77 == roughly 1.2987 EUR
amt = ledger.Amount('$100.12')
market = ((ledger.Amount('1 EUR') / ledger.Amount('$0.77')) * amt)

# An amount's "precision" is a notional thing only.  Since Ledger uses
# rational numbers throughout, and only renders to decimal form for printing
# to the user, the meaning of amt.precision should not be relied on as
# meaningful.  It only controls how much precision unrounded numbers (those
# for which keep_precision is True, and thus that ignore display_precision)
# are rendered into strings.  This is the case, btw, for all uncommoditized
# amounts.