Skip to main content

Hosted Ledgers Now Resolve Managed Price Includes

Published Last updated 10 min readMike ThriftMike Thrift
Hosted Ledgers Now Resolve Managed Price Includes
On this page

Let’s face it: your holdings are already perfectly recorded in your ledger. It’s the prices that keep you trapped in a cycle of endless retyping.

That asymmetry is the oldest, most frustrating chore in plain-text accounting. You write a purchase once, and it’s set in stone forever: 120 NWRB {41.80 USD, 2024-03-12} permanently locks in a quantity, a cost, and a date. Nothing that happens afterward changes those facts. A price, however, is the exact opposite—it’s correct for exactly one day, and then quietly becomes wrong. Worse, it’s wrong in a way no balance check will ever catch, because a ledger with stale prices still balances perfectly.

Historically, the Beancount way to handle this has been to fetch prices with a script and commit the output. It works, and a lot of folks have automated it. But at the end of the day, it's still a script you have to babysit, a cron job you maintain, and a file you constantly merge.

No more. For ledgers hosted on beancount.io, our engine now handles this resolution natively. This post covers exactly what just shipped, what we deliberately avoided touching, and—just as importantly—what we haven’t built yet.


What Shipped​

A hosted beancount.io ledger can now carry an include directive that points to a URL instead of a local filename:

; main.bean, in a hosted beancount.io ledger.
;
; This page is English, so the quote currency is USD. On another language of
; this site, use the currency in the list under the fence.
 
option "title" "Taxable brokerage"
option "operating_currency" "USD"
 
; Only the hosted engine resolves the URL form, and upstream `include` takes a
; file glob — so the line is shown commented out here and this file still
; loads if you copy it to your own machine. Uncomment it in a hosted ledger.
; include "https://beancount.io/prices/AAPL-USD"

Heads up: You’ll need to sign in before hitting that URL. Anonymous requests redirect to the login page. This page is English, so the example quotes US dollars — the currency English readers here most often keep books in. Once you're authenticated, open https://beancount.io/prices/AAPL-USD and confirm you're looking at standard price directives. Then add that line to your hosted ledger.

Reading another language, use that language's usual currency instead, and only when the catalog lists it as a quote:

The catalog at https://beancount.io/prices/ sits behind that same login. AAPL-USD itself is a direct Databento quote, not a cross. Other tier-1 stocks work the same way — swap the ticker, keep the quote currency for your language. ACME-USD returns a 404.

Upstream Beancount's include technically expects a filename, so a URL include is a strict hosted-engine behavior. It never pretends to be plain Beancount. Here is exactly what our engine does under the hood:

  • It materializes the feed as a read-only virtual file. The URL resolves through the engine's own include-resolution path—landing exactly where a local file would have—so every directive retains a real source location. Your original bytes are never rewritten. The file you wrote stays the file you wrote.
  • Strict payload validation. The fetched body is validated as price-only. We strictly allow price directives, comments, and four specific metadata keys (price-source, price-kind, observed-at, and provisional). Anything else rejects the entire body. There is no partial ingestion, meaning a rogue feed can never smuggle a transaction into your books.
  • Smart caching. Feeds are cached as an immutable revision with a moving pointer. Refresh cycles are driven by timestamps rather than cache expiry, ensuring that an upstream outage won't wipe out your last good revision.
  • Auditable freshness. Freshness is computed dynamically when the ledger is read (recent, stale, or unavailable) alongside the feed's reported observation time. A price you can't date is a price you can't audit.
  • Strictly read-only. Managed entries cannot be edited or deleted (attempting to do so throws an error naming the source). Furthermore, they don't count against your directive limits—we don't let feeds eat up your ledger's budget.

None of this changes what a price directive fundamentally means in Beancount. The engine's only job is to put correct, dated, and attributable prices in front of the loader.


Your Own Price Always Wins​

This is the dealbreaker for anyone who takes their ledger seriously, so let's be crystal clear:

For the same date and the same commodity pair (including its reciprocal), a price you wrote yourself always wins over the managed feed.

Not "usually," and not "only if you put your include last." This shadowing decision happens before the price map is built, meaning it is completely independent of where the include sits in your file. Put it at the top, put it at the bottom, or split it across three files—your handwritten price always wins.

The reciprocal rule is easy to miss but vital. A feed of AAPL-USD is a price of AAPL in USD. If you handwrote a price the other way around — USD in AAPL, same date — your entry still beats the feed. The same is true for whichever quote you included, CNY or JPY included.

Why this rule? Because a price in your own file is a conscious decision. It might be the exact close your broker printed on a statement you’re reconciling, a contemporaneous quote for a thinly-traded asset, or a specific figure your accountant demanded. A feed doesn't know your context. A system that silently overrides a human-authored figure stops being a ledger and becomes an opinion. The feed is there to fill gaps; it does not correct you.


Prices Move Valuation, and Nothing Else​

This next reassurance is structural rather than a policy choice, and it's best shown with real numbers. Take a look at our crypto example ledger, featuring dated lots, staking, DeFi positions, and airdrops:

Let's pull one specific entry. A governance-token airdrop arrives and is recorded as income at fair market value on the day it lands:

2024-03-20 * "Uniswap" "Receive UNI governance token airdrop"
  Assets:Crypto:Wallet:MetaMask:UNI       50.00 UNI {12.50 USD, 2024-03-20}
  Income:Crypto:Airdrops                -625.00 USD
 

That $625.00 of income, and the $12.50 per-unit basis attached to the lot, are now immutable facts about 2024-03-20. Every price directive in the ledger—whether managed, handwritten, or entirely missing—leaves both untouched.

Prices change market value; they never alter quantities, cost basis, cash flows, fees, or realized gains. This is exactly why a price feed is a safe tool to lean on: the absolute worst a bad price can do is temporarily misstate what a position is worth today. It can never corrupt the hard numbers you’ll put on your tax return.


Where a Wrong Price Model Actually Misleads You​

The stock and ETF example ledger illustrates the sharper version of this exact point:

It contains a 4-for-1 share split, recorded the correct way—as a quantity change that preserves total basis without touching any income accounts:

2025-07-15 * "Broker" "NWRB 4-for-1 share split — quantity change, not income"
  Assets:Brokerage:NWRB                   -120 NWRB {41.80 USD, 2024-03-12}
  Assets:Brokerage:NWRB                    480 NWRB {10.45 USD, 2024-03-12}
 

Both sides equal $5,016.00. The market value remains unchanged across the split ($7,440.00 either way), and the acquisition date in the braces survives—which is what keeps a 2026 sale of those shares classified as long-term.

The common trap is to record a split as a price event instead, leaning heavily on a "split-adjusted" price series to make the math work out. That only functions as long as every price you ever look at has been adjusted the exact same way. The moment an unadjusted figure hits your ledger—an old confirmation receipt, a screenshot, or a third-party feed that doesn't restate historicals—the position is suddenly valued at four times its actual worth. Worse, the share count in the ledger no longer matches your broker's statement, meaning your year-end balance assertions will silently fail.

This is the real argument for relying on a price feed with a declared source, a declared kind, and a visible observation time. It’s not just about convenience; it’s about knowing exactly what mathematical convention your imported numbers are using.

(A quick note on the embeds: the hosted ledger viewer renders account balances at cost and doesn't currently offer on-page valuation controls. The ledgers above are meant to showcase the underlying mechanics—the lots, the split, the sales. Both are public, and you can clone and run them locally.)


What Isn't Here Yet​

We believe a changelog is worse than useless if it overpromises. So here is the unvarnished truth about what we haven't built yet, with no attached timelines:

  • Authentication is mandatory. Anonymous requests to https://beancount.io/prices/<ALIAS> will bounce you to a login page.
  • No local CLI support. The local bea CLI reads files from disk, meaning a URL include will fail locally as an unmatched file glob. Adding loader support to the CLI is on our roadmap.
  • No API surface. We don't currently have a REST, GraphQL, or MCP field for managed prices.
  • No UI dashboard. There is no "connect-a-feed" screen and no freshness label in the UI yet. (The freshness data our engine computes currently has nowhere to be displayed).
  • No snapshots, exports, or manual refresh endpoints.

What we shipped today is strictly the engine layer: include resolution, validation, revision caching, precedence rules, and freshness computation. It’s the foundational infrastructure that everything else has to stand on, which is exactly why we built it first.


Where to Look Next​

Both of the ledgers embedded above are part of our example gallery—six fully worked patterns you can clone and run locally. (Both intentionally ship with static, checked-in price files, ensuring that a clone made two years from now produces the exact same report it does today). Everything else we ship lands directly on our changelog.

If you are perfectly happy keeping prices current with your own fetcher, stick with it. It remains the best answer for a strictly local ledger. Beancount's own price-fetching documentation and the maintained beanprice tool are the best places to start.

Keep the Boring Part Boring​

Prices are worth automating precisely because they’re the only part of a plain-text ledger that rots over time. Beancount.io is built to give you plain-text accounting that stays yours—auditable, version-controlled, and never rewritten behind your back. That was the baseline standard a managed feed had to meet before we were willing to ship it.

Start for free, and keep your books in files you can actually read.

Source: https://beancount.io/blog/2026/09/17/managed-price-includes-hosted-ledgers

Published: September 17, 2026

Last updated: September 19, 2026