Перейти к основному содержимому

Управляемые прайс-включения теперь разрешаются в размещённых реестрах

Опубликовано 9 мин чтенияMike ThriftMike Thrift
Управляемые прайс-включения теперь разрешаются в размещённых реестрах
Содержание страницы

Ваши активы уже в реестре. Цены — это то, что вы продолжаете вводить снова и снова.

Эта асимметрия — самая старая рутина в учёте на основе простого текста. Покупка записывается один раз и остаётся верной навсегда: 120 NWRB {41.80 USD, 2024-03-12} фиксирует количество, стоимость и дату, и ничто из того, что произойдёт позже, не меняет ни одно из трёх. Цена — наоборот: корректна один день, потом тихо становится неверной, и неверной так, что никакая сверка баланса этого не поймает, потому что устаревшая цена всё равно отлично балансируется. Собственный ответ Beancount всегда заключался в том, чтобы получать их инструментом и коммитить результат — это работает, и многие это автоматизировали. Но это всё ещё скрипт, которым владеете вы, запись в cron, которую вы обслуживаете, и файл, который вы сливаете.

Теперь движок реестра beancount.io сам выполняет это разрешение для реестров, размещённых у нас. Этот пост о том, что действительно вышло, чего оно намеренно не касается и — что не менее важно — что ещё не построено.

Что вышло

Размещённый реестр beancount.io может содержать include, целью которого является URL, а не имя файла:

; main.bean, in a hosted beancount.io ledger.
;
; The managed line is shown commented out on purpose: upstream `include` takes a
; file glob, so this file still loads if you copy it to your own machine. Only
; the hosted engine resolves the URL form.
 
option "title" "Taxable brokerage"
option "operating_currency" "USD"
 
include "accounts.bean"
; include "https://beancount.io/prices/ACME-USD"
 
include "transactions/purchases.bean"
include "transactions/sales.bean"

В upstream Beancount include принимает имя файла — «указанный путь может быть абсолютным или относительным именем файла» — это всё, что есть в спецификации, — поэтому include по URL не является простым Beancount и никогда не притворяется им. Это поведение размещённого движка, и вот что именно движок с ним делает:

  • Он материализует ленту как виртуальный файл, доступный только для чтения. URL разрешается через собственный путь разрешения include движка — ровно там, где оказался бы локальный файл, — поэтому каждая директива сохраняет реальное местоположение источника. Ваши байты никогда не перезаписываются. Файл, который вы написали, остаётся тем файлом, который вы написали.
  • Полученное тело валидируется как содержащее только цены. Директивы price, комментарии и четыре разрешённых ключа метаданных — price-source, price-kind, observed-at и provisional — и ничего больше. Всё, что сверх этого, отклоняет всё тело целиком. Частичного приёма нет, поэтому лента никогда не сможет протащить транзакцию в ваши книги.
  • Ленты кэшируются как неизменяемая ревизия плюс подвижный указатель. Обновление управляется временной меткой, а не истечением кэша, — значит, сбой у источника не может унести с собой вашу последнюю хорошую ревизию. Неудачное обновление никогда не заменяет хорошую ревизию пустотой.
  • Свежесть вычисляется при чтении реестра, а не хранится: recent, stale или unavailable — вместе со временем наблюдения, которое сообщила сама лента. Цена, которую вы не можете датировать, — это цена, которую вы не можете проверить.
  • Управляемые записи доступны только для чтения. Их редактирование или удаление отклоняется с ошибкой, называющей управляемый источник, и они не учитываются в лимитах директив — ленте не позволено расходовать бюджет вашего реестра.

Всё из этого списка работает внутри размещённого сервиса реестра. Ничто из этого не меняет того, что означает директива price: она по-прежнему устанавливает курс обмена между базовым товаром и товаром котировки — ровно так, как это определено в справочнике по языку. Задача движка — лишь подставить загрузчику корректные, датированные и атрибутированные цены.

Ваша собственная цена всегда побеждает

Это та часть, от которой зависит, годится ли лента для того, кто относится к своему реестру серьёзно, поэтому она формулируется точно.

Для одной и той же даты и одной и той же пары товаров — а также для обратной пары — цена, написанная вами самими, побеждает управляемую ленту, независимо от порядка include.

Не «обычно» и не «если поставить ваш include последним». Решение о затенении принимается до построения карты цен, поэтому оно не зависит от того, где include находится в файле. Переместите его в начало, переместите в конец, разбейте на три файла: ответ один и тот же.

; include "https://beancount.io/prices/ACME-USD"   ; hosted-engine form, again shown commented
 
; A price you wrote yourself, for the same date and pair.
; This one wins — above the include or below it, it makes no difference.
2026-09-16 price ACME 93.40 USD

(ACME — вымышленный эмитент из примера реестра ниже; число придумано, а не является рыночным наблюдением.)

Почему именно это правило, а не обратное: цена в вашем собственном файле — это решение. Это может быть цена закрытия, которую ваш брокер напечатал в выписке, с которой вы сверяетесь, котировка на тот момент по позиции с низкой ликвидностью или цифра, которую ваш бухгалтер попросил вас использовать. Лента ничего из этого не знает, а система, которая молча переопределяет созданную человеком цифру, перестала быть реестром и стала мнением. Лента заполняет пробелы; она вас не поправляет.

Цены меняют оценку и ничего больше

Второе заверение — структурное, а не вопрос политики, и его стоит показать на реальных числах, а не просто утверждать. Вот пример крипто-реестра — датированные лоты, стейкинг, майнинг, позиции в DeFi, эйрдропы:

Открыть Пример учёта криптовалют — партии с датами, стейкинг, DeFi и эйрдропы в новой вкладке

Возьмём одну запись из него. Приходит эйрдроп токена управления и записывается как доход по справедливой рыночной стоимости на день получения:

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

Эти $625.00 дохода и база $12.50 за единицу, привязанная к лоту, теперь являются фактами о 2024-03-20. Любая директива price в реестре — управляемая, написанная вручную или вовсе отсутствующая — оставляет и то, и другое нетронутым. Цены меняют рыночную стоимость; они никогда не меняют количества, базу затрат, денежные потоки, комиссии или реализованные прибыли. Именно поэтому лента цен — это то, с чем в принципе безопасно принимать помощь: худшее, что может сделать неверная цена, — исказить то, сколько позиция стоит сегодня, и она никогда не сможет испортить число, которое вы поставите в налоговой декларации.

Где неверная модель цен действительно вводит в заблуждение

Пример реестра акций и ETF демонстрирует более острую версию того же:

Открыть Пример учёта стоимости акций и ETF — идентифицируемые партии, сплит 4 к 1, продажи конкретных партий в новой вкладке

Он содержит дробление акций 4 к 1, и дробление записано правильным образом — как изменение количества, сохраняющее общую базу и не затрагивающее никакой счёт доходов:

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}

Обе стороны равны $5,016.00. Рыночная стоимость при дроблении не меняется — 120 акций по $62.00 днём ранее, 480 акций по $15.50 на следующий день, $7,440.00 в обоих случаях — и дата приобретения в фигурных скобках сохраняется, что и делает продажу этих акций в 2026 году долгосрочной.

Распространённая ошибка — записать дробление как ценовое событие и опереться на «скорректированный на дробление» ряд, чтобы оценка сошлась. Это работает лишь до тех пор, пока каждая цена, которую вы когда-либо видите, скорректирована одинаково. В тот момент, когда появляется нескорректированная цифра — старое подтверждение, скриншот, сторонний ряд, который ничего не пересчитывает, — позиция оценивается вчетверо против своей стоимости, а количество акций в реестре больше не совпадает с выпиской брокера, поэтому проверка на конец года, которая поймала бы это, не может сработать.

Вот настоящий аргумент в пользу ленты цен с объявленным источником, объявленным видом и видимым временем наблюдения: не удобство, а знание того, по какой конвенции было вычислено число, которое вы только что импортировали. Собственный файл цен примера реестра намеренно нескорректирован и говорит об этом, а две его директивы, охватывающие дробление, написаны как проверка, которую можно проверить глазами.

Одно честное замечание о переходе в любой из этих встроенных просмотров: размещённый просмотрщик реестра отображает остатки по счетам по стоимости, и не предлагает никакого управления оценкой на странице. Реестры выше нужны, чтобы показать вам реестры — лоты, дробление, продажи конкретных лотов — а не рыночную оценку, которую просмотрщик сейчас не рисует. Оба публичны, и оба можно клонировать и запустить локально.

Чего здесь ещё нет

Запись в changelog стоит меньше, чем ничего, если она позволяет вам поверить в то, чего нет, поэтому вот другая половина — прямо и без каких-либо дат.

  • Прайс-эндпоинт не публичен. Анонимный запрос к https://beancount.io/prices/<ALIAS> перенаправляется на страницу входа. Публичного каталога псевдонимов нет.
  • Так что это не то, что вы можете сегодня вставить в свой собственный файл. Движок разрешает include; маршрут, который он разрешает, ещё не открыт. Когда откроется, это будет отдельная запись в changelog.
  • Локальный CLI bea не разрешает include по URL. Он читает файлы с диска, поэтому include по URL локально падает как файловая маска, не совпавшая ни с одним файлом. Поддержка в загрузчике CLI — обозначенное последующее действие.
  • Поверхности API нет. Ни поля REST, GraphQL или MCP для управляемых цен.
  • Поверхности дашборда нет. Ни экрана подключения ленты, ни метки свежести в интерфейсе; вычисленной движком свежести пока негде отображаться.
  • Снимки и экспорт не построены, как и каталог инструментов или эндпоинт ручного обновления.

Что вышло — это слой движка: разрешение include, валидация, кэш ревизий, правило приоритета и вычисление свежести. Это та часть, на которую должно опираться всё остальное, и та часть, которую труднее всего менять позже, — поэтому она пошла первой.

Куда смотреть дальше

Оба реестра выше — часть галереи примеров, шесть проработанных шаблонов, которые можно клонировать и запустить локально; оба этих реестра намеренно поставляются со статическими, закоммиченными файлами цен, чтобы клон, сделанный через два года, по-прежнему выдавал тот же отчёт, что и сегодня. Всё остальное, что мы выпускаем, попадает в changelog.

Если вы всё ещё поддерживаете цены в актуальном состоянии собственным получателем, это остаётся правильным ответом для локального реестра, а документация Beancount по получению цен вместе с поддерживаемым инструментом beanprice — то, с чего стоит начать.

Пусть скучная часть остаётся скучной

Причина, по которой цены стоит автоматизировать, в том, что это единственная часть реестра на основе простого текста, которая устаревает сама по себе. Beancount.io даёт вам учёт на основе простого текста, который остаётся вашим — проверяемым, версионируемым и никогда не перезаписываемым у вас за спиной, — а это ровно тот стандарт, которому должна была соответствовать управляемая лента, прежде чем мы решились её выпустить. Начните бесплатно и держите свои книги в файлах, которые вы можете прочитать.

Поделиться этой статьёй

Подписаться на эту тему

  • RSS
  • Atom

Источник: https://beancount.io/ru/blog/2026/09/17/managed-price-includes-hosted-ledgers

Опубликовано: 17 сентября 2026 г.