Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Support reciprocal unit cost syntax for low-value currencies #2501

Copy link
Copy link
@gnidan

Description

@gnidan
Issue body actions

Problem

The current @ syntax requires expressing unit cost as the value of 1 unit of the commodity being purchased. For low-value currencies, this creates precision problems.

Concrete example: I recently used a payment app (Peanut/Mercado Pago) in Argentina and am now trying to reconcile my books. The app reported rates like 1 USD = 1479.42 ARS (this rate varies per transaction) and, while the app reported transaction totals rounded to cents, it tracked sub-cent balances internally. After a week of transactions, cumulative rounding errors were around $0.05 because I was only capturing the rounded totals.

The issue is that each canonical rate was something like 1 USD = 1479.42 ARS (2 decimal places), but hledger forces me to express this as 1 ARS = 0.0006759... USD (which needs 7+ decimals to preserve equivalent precision).

Current workarounds and their limitations:

expenses:food  10000 ARS @ 0.00067594 USD    # loses precision, cognitively annoying
expenses:food  10000 ARS @@ 6.76 USD         # loses sub-cent amounts, cumulative error
assets:cash  -49.816820 USD @ 1479.42 ARS    # requires computing high-precision USD amount first
expenses:food  73700 ARS

The @@ approach doesn't really solve it because it only records the rounded total from my statement, not the actual exchange rate that was used. Multiple transactions with rounded totals accumulate error over time.

The swapped-posting approach requires manually computing the high-precision USD amount (or leaving it blank and having hledger infer it), which is an extra step and makes the posting less intuitive to read.

Proposal

Add reciprocal unit cost syntax. A few options:

EDIT: Realized my initial option 1 didn't specify the target currency. Updated options:

Option 1: @/ RATE COMMODITY/$

expenses:food  10000 ARS @/ 1479.42 ARS/$
assets:cash

Option 2: = (most clear semantically, but may conflict with balance assertions)

expenses:food  10000 ARS @ $1 = 1479.42 ARS
assets:cash

Semantics for option 1: AMOUNT COMMODITY @/ RATE COMMODITY/TARGET means the cost is AMOUNT / RATE in TARGET currency. This preserves the exchange rate precision as naturally expressed, preventing cumulative errors.

Why this matters

Exchange rates are often quoted in the reciprocal direction from what @ requires. This particularly affects:

  • Low-value/high-inflation currencies (ARS, JPY, IDR, KRW, et al.)
  • Importing from financial apps/statements that report reciprocal rates
  • Anyone tracking expenses in a weak currency but maintaining balance sheets in a strong reference currency

Draft documentation

Reciprocal unit cost: The @/ syntax specifies how many units of the commodity equal one unit of target currency:

AMOUNT COMMODITY @/ RATE COMMODITY/TARGET

This is equivalent to @ (1/RATE) TARGET but preserves the precision of the exchange rate as typically quoted. Example: 10000 ARS @/ 1479.42 ARS/$ equals 10000 / 1479.42 = 6.759405... USD.

Open questions

  • Syntax: @/ RATE COMMODITY/TARGET vs @ X TARGET = Y COMMODITY (though = likely conflicts with balance assertions)?
  • Should there be a reciprocal total cost @@/ as well? (This use case is less clear to me)
  • Are there any parser/compatibility concerns that affect potential solutions?

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-WISHSome kind of improvement request or proposal.Some kind of improvement request or proposal.journalThe journal file format, and its features.The journal file format, and its features.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.