Higher-level reporting API built on top of Beancount.query_text/2.
Each function generates a canned BQL
query and runs it through the configured engine, returning a neutral
Beancount.Query.Result. Reports therefore work against any engine that
implements Beancount.Engine.query/2.
A ledger argument may be either a list of directives (which is rendered
first) or raw .bean text.
Examples below use Beancount.Engine.Elixir so they run without bean-query.
Configure config :beancount_ex, engine: Beancount.Engine.Elixir to use these
reports through Beancount.balances/1 and friends.
Summary
Functions
Balance sheet: balances of Assets, Liabilities and Equity accounts.
Balances for every account.
Holdings: unit and cost positions held in Asset accounts.
Income statement: balances of Income and Expenses accounts.
Journal of postings for a single account, ordered by date.
Types
@type ledger() :: [Beancount.directive()] | binary()
@type result() :: {:ok, Beancount.Query.Result.t()} | {:error, Beancount.Result.t()}
Functions
Balance sheet: balances of Assets, Liabilities and Equity accounts.
Examples
iex> Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
iex> {:ok, %Beancount.Query.Result{}} = Beancount.Report.balance_sheet(Beancount.Report.sample_ledger())
Balances for every account.
BQL: SELECT account, sum(position) AS balance GROUP BY account ORDER BY account.
Examples
iex> Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
iex> {:ok, result} = Beancount.Report.balances(Beancount.Report.sample_ledger())
iex> result.columns
["account", "balance"]
Holdings: unit and cost positions held in Asset accounts.
Examples
ledger = [
Beancount.open(~D[2026-01-01], "Assets:Stocks", ["AAPL"], booking: "FIFO"),
Beancount.open(~D[2026-01-01], "Assets:Cash", ["USD"]),
Beancount.open(~D[2026-01-01], "Equity:Opening", ["USD"]),
Beancount.transaction(~D[2026-01-02], "*", nil, "Buy", [
Beancount.posting("Assets:Stocks", Decimal.new("10"), "AAPL",
cost: %{amount: Decimal.new("150"), currency: "USD"}
),
Beancount.posting("Assets:Cash", Decimal.new("-1500"), "USD")
])
]
Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
{:ok, %Beancount.Query.Result{columns: cols}} = Beancount.Report.holdings(ledger)
cols
# => ["account", "units", "cost"]
Income statement: balances of Income and Expenses accounts.
Examples
iex> Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
iex> {:ok, %Beancount.Query.Result{}} = Beancount.Report.income_statement(Beancount.Report.sample_ledger())
Journal of postings for a single account, ordered by date.
Examples
iex> Application.put_env(:beancount_ex, :engine, Beancount.Engine.Elixir)
iex> {:ok, %Beancount.Query.Result{columns: cols}} =
...> Beancount.Report.journal(Beancount.Report.sample_ledger(), "Assets:Bank")
iex> "date" in cols
true