Система запасов Beancount — это мощная функция для отслеживания активов, которые покупаются и продаются с течением времени, таких как акции, взаимные фонды или иностранные валюты. Она позволяет точно отслеживать себестоимость, что необходимо для расчета прироста капитала и понимания эффективности портфеля. Это руководство охватывает основные механизмы управления запасами в вашей бухгалтерской книге.
Основные понятия
По своей сути управление запасами сводится к отслеживанию позиций. «Позиция» — это просто количество актива, хранящееся на счете. Beancount различает два фундаментальных типа позиций.
Типы позиций
-
Простая позиция (без себестоимости): Это стандартная проводка по балансу. Она представляет собой количество актива без связанной с ним стоимости приобретения. Она подходит для денежных средств или простых проверок баланса.
Assets:Bank:Checking 100.00 USD -
Позиция с себестоимостью: Этот тип позиции включает не только количество единиц и актив, но и стоимость, по которой он был приобретен. Это основа отслеживания запасов. Стоимость указывается в фигурных скобках
{}.Assets:Invest:VTSAX 10 VTSAX {100.00 USD, "lot-1"}В этом примере мы держим 10 единиц
VTSAX. Каждая единица была приобретена по цене $100.00 USD. Эта конкретная партия акций идентифицируется как «лот».
Операции с запасами
Существует две основные операции, которые можно выполнять с запасами:
-
Увеличение (добавление в запасы): Когда вы покупаете актив, вы увеличиваете свои запасы. Вы создаете новый лот с определенным количеством единиц и себестоимостью.
2024-01-15 * "Buy shares" Assets:Invest:STOCK 50 STOCK {25.00 USD, "lot-1"} Assets:Bank:Checking -1250.00 USDЗдесь мы покупаем 50 единиц
STOCKпо цене $25.00 USD за единицу. Это создает лот на счетеAssets:Invest:STOCK. -
Уменьшение (списание из запасов): Когда вы продаете актив, вы уменьшаете свои запасы. Вы должны указать, из какого лота вы продаете. Это делается путем указания соответствующей информации в фигурных скобках.
2024-01-20 * "Sell shares" Assets:Invest:STOCK -25 STOCK {25.00 USD} Assets:Bank:Checking 625.00 USDВ этой транзакции мы продаем 25 единиц
STOCKиз лота, который был куплен по цене $25.00 USD за единицу.
Методы учета
Когда вы уменьшаете запасы, Beancount нуждается в правиле, чтобы решить, из какого конкретного лота списывать, если несколько лотов соответствуют уменьшению. Это правило называется «методом учета». Вы можете установить значение по умолчанию для всего файла с помощью опции или назначить конкретному счету свой метод в директиве open.
Beancount 3.2.3 принимает семь названий методов: STRICT (по умолчанию), STRICT_WITH_SIZE, NONE, FIFO, LIFO, HIFO и AVERAGE. Шесть из них реализованы; AVERAGE разбирается, но выдает ошибку, как только ему нужно учесть уменьшение, как показано в разделе AVERAGE ниже.
1. STRICT (по умолчанию)
Метод STRICT — это метод по умолчанию и самый безопасный метод учета. Он обеспечивает явное и однозначное сопоставление.
2024-01-01 open Assets:Invest:STOCK "STRICT"- Требует точного совпадения лота: Спецификатор стоимости в проводке уменьшения (
{...}) должен идентифицировать один лот — по стоимости, по дате приобретения, по метке или по любой их комбинации. - Ошибка при неоднозначном совпадении: Если спецификатор соответствует более чем одному лоту, Beancount выдает
AmbiguousMatchErrorвместо того, чтобы угадывать. - Исключение: Если уменьшение точно снимает общее количество единиц, которым соответствует спецификатор, допускается пустой спецификатор (
{}), и уменьшение распределяется по этим лотам.
Эта бухгалтерская книга содержит два лота и продает один из них, указывая его стоимость, что однозначно:
1970-01-01 commodity STK
1970-01-01 open Assets:Broker:Strict STK "STRICT"
1970-01-01 open Assets:Broker:Cash USD
1970-01-01 open Income:Gains USD
2024-01-10 * "Buy the first lot"
Assets:Broker:Strict 10 STK {100.00 USD}
Assets:Broker:Cash -1000.00 USD
2024-02-10 * "Buy the second lot"
Assets:Broker:Strict 10 STK {120.00 USD}
Assets:Broker:Cash -1200.00 USD
; The cost identifies exactly one lot, so STRICT is satisfied.
2024-06-01 * "Sell the $120.00 lot"
Assets:Broker:Strict -10 STK {120.00 USD} @ 150.00 USD
Assets:Broker:Cash 1500.00 USD
Income:GainsОн загружается без ошибок, учитывает $300.00 прибыли на Income:Gains и оставляет 10 STK {100.00 USD} на счете.
Замените последнюю проводку на пустой спецификатор, и тот же файл не загрузится:
; Rejected under STRICT: "-10 STK {}" matches both lots.
2024-06-01 * "Sell 10 shares"
Assets:Broker:Strict -10 STK {} @ 150.00 USD
Assets:Broker:Cash 1500.00 USD
Income:GainsBeancount сообщает Ambiguous matches for "-10 STK {}" и перечисляет кандидатов. Однако продажа всей позиции допустима, потому что выбирать больше не из чего:
; Allowed under STRICT: -20 STK is the entire holding, so the empty
; specifier is split across both lots.
2024-06-01 * "Close the position"
Assets:Broker:Strict -20 STK {} @ 150.00 USD
Assets:Broker:Cash 3000.00 USD
Income:GainsЭто учитывает $800.00 прибыли — $3,000.00 выручки против $1,000.00 + $1,200.00 себестоимости — и обнуляет счет. Это свойство самого STRICT, а не то, для чего нужно переключаться на STRICT_WITH_SIZE.
2. FIFO (первым пришел — первым ушел)
Метод FIFO автоматически учитывает уменьшения против самых старых доступных лотов.
2024-01-01 open Assets:Invest:STOCK "FIFO"- Автоматическое разрешение: Он разрешает неоднозначность, выбирая самые старые соответствующие лоты.
- Хронологическое сопоставление: Предполагается, что вы продаете активы, которые держали дольше всего. Некоторые налоговые органы рассматривают это как метод по умолчанию, когда вы не идентифицировали лот.
3. LIFO (последним пришел — первым ушел)
Метод LIFO противоположен FIFO. Он учитывает уменьшения против самых новых доступных лотов.
2024-01-01 open Assets:Invest:STOCK "LIFO"- Обратный хронологический порядок: Он выбирает самые недавно приобретенные соответствующие лоты.
- Самый новый, а не самый дорогой: LIFO выбирает только по дате приобретения. Он продает акции с самой высокой себестоимостью, когда цены росли, но если ваш самый новый лот — самый дешевый — что и призван показать пример ниже — LIFO реализует наибольшую прибыль, а не наименьшую. Метод, который всегда продает самые дорогие акции, — это
HIFO, описанный далее.
4. HIFO (самый дорогой пришел — первым ушел)
Метод HIFO учитывает уменьшения против самых дорогих доступных лотов, независимо от их даты.
2024-01-01 open Assets:Invest:STOCK "HIFO"- Сопоставление по стоимости: Он выбирает соответствующие лоты с самой высокой себестоимостью.
- Наименьшая реализованная прибыль: Для данной цены продажи продажа акций с самой высокой себестоимостью реализует наименьшую прибыль (или наибольший убыток). Разрешено ли его использовать, зависит от юрисдикции — например, в США выбор лота вообще требует конкретной идентификации на момент продажи — поэтому относитесь к методу как к механизму учета и подтверждайте налоговый выбор отдельно.
5. Сравнение FIFO, LIFO и HIFO на одних и тех же лотах
Эти три метода различаются только тогда, когда самый старый, самый новый и самый дорогой лот — это три разных лота. Эта бухгалтерская книга устроена именно так — лот A самый старый, лот C самый новый, а средний лот B самый дорогой — а затем продает 10 акций с трех счетов, которые различаются только методом учета:
1970-01-01 commodity STK
1970-01-01 open Assets:Broker:Fifo STK "FIFO"
1970-01-01 open Assets:Broker:Lifo STK "LIFO"
1970-01-01 open Assets:Broker:Hifo STK "HIFO"
1970-01-01 open Assets:Broker:Cash USD
1970-01-01 open Income:Gains USD
; Lot A - the oldest, at $100.00 per share
2024-01-10 * "Buy lot A"
Assets:Broker:Fifo 10 STK {100.00 USD}
Assets:Broker:Lifo 10 STK {100.00 USD}
Assets:Broker:Hifo 10 STK {100.00 USD}
Assets:Broker:Cash -3000.00 USD
; Lot B - the most expensive, at $120.00 per share
2024-02-10 * "Buy lot B"
Assets:Broker:Fifo 10 STK {120.00 USD}
Assets:Broker:Lifo 10 STK {120.00 USD}
Assets:Broker:Hifo 10 STK {120.00 USD}
Assets:Broker:Cash -3600.00 USD
; Lot C - the newest, at $90.00 per share
2024-03-10 * "Buy lot C"
Assets:Broker:Fifo 10 STK {90.00 USD}
Assets:Broker:Lifo 10 STK {90.00 USD}
Assets:Broker:Hifo 10 STK {90.00 USD}
Assets:Broker:Cash -2700.00 USD
; Sell 10 shares out of each account at $150.00 and let each
; account's booking method choose which lot leaves.
2024-06-01 * "Sell 10 shares from each account"
Assets:Broker:Fifo -10 STK {} @ 150.00 USD
Assets:Broker:Lifo -10 STK {} @ 150.00 USD
Assets:Broker:Hifo -10 STK {} @ 150.00 USD
Assets:Broker:Cash 4500.00 USD
Income:GainsОн загружается без ошибок и учитывает $1,400.00 прибыли в общей сложности, распределяя следующим образом:
| Счет | Метод | Учтенный лот | Себестоимость | Реализованная прибыль | Оставшиеся лоты |
|---|---|---|---|---|---|
Assets:Broker:Fifo | FIFO | лот A, 2024-01-10 | $100.00 | $500.00 | 10 @ $120.00, 10 @ $90.00 |
Assets:Broker:Lifo | LIFO | лот C, 2024-03-10 | $90.00 | $600.00 | 10 @ $100.00, 10 @ $120.00 |
Assets:Broker:Hifo | HIFO | лот B, 2024-02-10 | $120.00 | $300.00 | 10 @ $100.00, 10 @ $90.00 |
Строка LIFO — та, на которую стоит обратить внимание: она реализовала наибольшую прибыль из трех, потому что самый новый лот был также самым дешевым.
6. STRICT_WITH_SIZE
STRICT_WITH_SIZE — это STRICT плюс один дополнительный критерий разрешения: когда несколько лотов соответствуют уменьшению, но ровно один из них содержит точно то количество единиц, которое вы списываете, выбирается именно этот лот.
1970-01-01 commodity STK
1970-01-01 open Assets:Broker:Sized STK "STRICT_WITH_SIZE"
1970-01-01 open Assets:Broker:Cash USD
1970-01-01 open Income:Gains USD
2024-01-10 * "Buy 10 shares"
Assets:Broker:Sized 10 STK {100.00 USD}
Assets:Broker:Cash -1000.00 USD
2024-02-10 * "Buy 7 shares"
Assets:Broker:Sized 7 STK {120.00 USD}
Assets:Broker:Cash -840.00 USD
; Only one lot holds exactly 7 units, so the empty specifier resolves.
2024-06-01 * "Sell 7 shares"
Assets:Broker:Sized -7 STK {} @ 150.00 USD
Assets:Broker:Cash 1050.00 USD
Income:GainsЭто учитывает $210.00 прибыли против лота за $120.00. Идентичный файл с "STRICT" в строке open завершается ошибкой Ambiguous matches for "-7 STK {}".
7. AVERAGE (принимается, но не реализован)
AVERAGE — допустимое имя — option "booking_method" "AVERAGE" и open … "AVERAGE" оба разбираются — но в Beancount 3.2.3 за ним нет реализации. Все здесь загружается до момента продажи:
1970-01-01 commodity STK
1970-01-01 open Assets:Broker:Avg STK "AVERAGE"
1970-01-01 open Assets:Broker:Cash USD
1970-01-01 open Income:Gains USD
2024-01-10 * "Buy 10 shares at $10.00"
Assets:Broker:Avg 10 STK {10.00 USD}
Assets:Broker:Cash -100.00 USD
2024-02-10 * "Buy 10 more at $8.00"
Assets:Broker:Avg 10 STK {8.00 USD}
Assets:Broker:Cash -80.00 USD
; An average-cost engine would book this at $9.00 per share. This one refuses.
2024-06-01 * "Sell 5 shares"
Assets:Broker:Avg -5 STK {}
Assets:Broker:Cash 45.00 USD
Income:GainsКак только это уменьшение должно быть учтено, загрузчик останавливается с:
AVERAGE method is not supportedНе планируйте свою бухгалтерскую книгу вокруг него. Если вам нужно поведение средней себестоимости сегодня, держите позицию на счете NONE и вычисляйте среднее самостоятельно, или отслеживайте каждый лот и принимайте прибыль на уровне лота.
8. NONE
Метод NONE полностью отключает сопоставление лотов.
2024-01-01 open Assets:Invest:STOCK "NONE"- Без сопоставления лотов: Beancount не пытается сопоставлять уменьшения с увеличениями.
- Допускает смешанные знаки: Это позволяет счету одновременно содержать как положительные, так и отрицательные остатки одного и того же актива. Такое поведение аналогично тому, как инструмент командной строки Ledger обрабатывает активы.
Спецификация лота
«Лот» — это конкретный блок актива, приобретенный в определенное время и по определенной цене. Когда вы создаете или уменьшаете позицию, вы можете подробно указать атрибуты лота.
Полная спецификация
При увеличении запасов (покупке) вы можете указать до трех атрибутов лота через запятую в одной паре фигурных скобок:
Assets:Invest:STOCK 10 STOCK {100.00 USD, 2024-01-15, "lot-identifier"}100.00 USD— себестоимость, выраженная за единицу.2024-01-15— дата приобретения. Beancount подставляет дату транзакции, если вы ее опускаете, поэтому в сообщениях об ошибках выше на каждом лоте указана дата."lot-identifier"— необязательная строковая метка.
Хотя все три атрибута необязательны, указание хотя бы себестоимости является стандартной практикой. Фигурные скобки должны оставаться на одной строке, а комментарии в бухгалтерской книге начинаются с ;, никогда с #.
Методы сопоставления
При уменьшении запасов (продаже) вы используете тот же синтаксис, чтобы указать, из какого лота (лотов) продавать.
-
Сопоставление по стоимости: Это самый распространенный метод.
Assets:Invest:STOCK -5 STOCK {100.00 USD} -
Сопоставление по дате: Если стоимости одинаковы, вы можете устранить неоднозначность по дате приобретения.
Assets:Invest:STOCK -5 STOCK {2024-01-15} -
Сопоставление по метке: Метки обеспечивают безошибочный способ идентификации лота.
Assets:Invest:STOCK -5 STOCK {"lot-identifier"} -
Оставить лот на усмотрение метода учета: Пустой набор фигурных скобок
{}не указывает ни на какой лот, поэтому метод учета счета выбирает его. ПриFIFO,LIFOилиHIFOэто самый старый, самый новый или самый дорогой соответствующий лот; при методе по умолчаниюSTRICTэтоAmbiguousMatchError, если только уменьшение не обнуляет соответствующие лоты точно.Assets:Invest:STOCK -5 STOCK {}
Обработка цены
Крайне важно понимать разницу между себестоимостью ({}) и ценой (@). Они служат разным целям и не взаимозаменяемы.
Цена против себестоимости
{cost}: Определяет стоимость приобретения актива. Она является частью самого лота запасов и используется для учета уменьшений и расчета прироста капитала.@ price: Аннотация, которая фиксирует рыночную цену на момент транзакции. Она используется для конвертации валют или для отметки рыночной стоимости на определенную дату.
Вот три сценария:
-
Аннотация цены (конвертация): Используйте
@для конвертации из одной валюты в другую.Assets:Forex 1000 USD @ 0.85 EUR -
Себестоимость (приобретение): Используйте
{}при покупке актива, чтобы установить его стоимость.Assets:Invest 10 STOCK {100.00 USD} -
Оба (продажа с фиксацией цены): При продаже актива используйте
{}для идентификации продаваемого лота и@для фиксации цены продажи. Это позволяет автоматически рассчитывать прирост капитала.Assets:Invest -10 STOCK {100.00 USD} @ 105.00 USDЭта запись продает 10
STOCKиз лота, который стоил $100.00 за единицу, по цене продажи $105.00 за единицу.
Правила использования цены
- Аннотации цены (
@) не влияют на то, какой лот учитывается. Сопоставление лотов осуществляется исключительно на основе себестоимости ({}) и метода учета счета. - Символ
@используется только для:
- Конвертации валют.
- Фиксации рыночной стоимости актива на момент транзакции.
- Указания цены продажи для расчета прироста капитала.
Конфигурация
Вы можете настроить методы учета глобально или для каждого счета отдельно.
Глобальный метод учета
Вы можете установить метод учета по умолчанию для всего файла Beancount с помощью директивы option.
option "booking_method" "STRICT"Допустимые значения: "STRICT" (по умолчанию, если ничего не указано), "STRICT_WITH_SIZE", "NONE", "FIFO", "LIFO", "HIFO" и "AVERAGE". Любая другая строка отклоняется при загрузке с сообщением Error for option 'booking_method'. "AVERAGE" принимается здесь и в open, но учет уменьшения под ним завершается ошибкой, как показано в разделе AVERAGE выше.
Переопределение для конкретного счета
Часто полезно иметь разные методы для разных счетов. Например, вы можете захотеть FIFO для пенсионного счета, но STRICT для налогооблагаемого брокерского счета, чтобы гарантировать продажу конкретных налоговых лотов. Вы можете установить метод учета при открытии счета.
2024-01-01 open Assets:Retirement:401K "FIFO"
2024-01-01 open Assets:Taxable:Stock "STRICT"Рекомендации
-
Организация запасов: Чтобы поддерживать бухгалтерскую книгу в чистоте и простоте, настоятельно рекомендуется использовать отдельные счета для каждого уникального актива и ограничивать каждый из них этим активом в директиве
open.; GOOD: separate accounts by commodity, each constrained to one 2024-01-01 open Assets:Invest:VTSAX VTSAX 2024-01-01 open Assets:Invest:VFIAX VFIAXИзбегайте смешивания разных акций или фондов на одном счете, так как это усложняет управление запасами. Список активов в
openзаставляет Beancount отклонять случайную проводку вместо того, чтобы молча смешивать два запаса. -
Управление лотами:
-
Используйте осмысленные метки для лотов, особенно для конкретных транзакций, таких как сбор налоговых убытков или гранты на акции для сотрудников.
Assets:Invest:STOCK 10 STOCK {100.00 USD, "tax-loss-harvest-2024"} -
Документируйте свои сделки комментариями. Это облегчит чтение и понимание вашей бухгалтерской книги в будущем.
Assets:Invest:STOCK -10 STOCK {100.00 USD} @ 110.00 USD ; Gain: 10%
- Отладка: Если вы столкнулись с ошибками или неожиданным поведением, Beancount предоставляет инструменты для проверки состояния ваших запасов.
-
Проверка состояния запасов: Используйте
bea doctor context main.beancount 42, чтобы проверить транзакцию на строке 42, включая ее проводки и затронутые остатки на счетах. Замените имя файла и номер строки на транзакцию, которую хотите проверить.Замените
<LINENO>на номер строки сразу после транзакции, чтобы увидеть ее эффект. -
Проверка сопоставления лотов: Инструмент
bea checkпроверяет весь ваш файл. Он выявит любые ошибки учета, такие как неоднозначное сопоставление лотов в режимеSTRICT.