Перейти до основного вмісту

Партії Beancount, базова вартість і методи списання

Як Beancount веде партії, коли ви продаєте акції чи валюту: базова вартість, специфікації партій, методи STRICT, FIFO, LIFO та HIFO, ціна проти собівартості, перевизначення для окремих рахунків.

Система інвентарю Beancount — це потужна функція для відстеження активів, які купуються та продаються з часом, як-от акції, пайові фонди чи іноземні валюти. Вона дозволяє точно відстежувати базу витрат, що є важливим для розрахунку приросту капіталу та розуміння ефективності портфеля. Цей підручник охоплює основні механізми управління запасами у вашому журналі.

Основні поняття​

У своїй основі управління запасами обертається навколо відстеження позицій. "Позиція" — це просто кількість певного товару, що утримується на рахунку. Beancount розрізняє два фундаментальні типи позицій.

Типи позицій​

  1. Проста позиція (без собівартості): Це стандартний запис балансу. Вона представляє кількість товару без будь-якої пов'язаної вартості придбання. Підходить для готівки або простих перевірок балансу.

    Assets:Bank:Checking      100.00 USD
  2. Позиція з базою витрат: Цей тип позиції включає не лише кількість одиниць і товар, але й вартість, за якою їх було придбано. Це основа відстеження запасів. Вартість вказується у фігурних дужках {}.

    Assets:Invest:VTSAX      10 VTSAX {100.00 USD, "lot-1"}

    У цьому прикладі ми утримуємо 10 одиниць VTSAX. Кожна одиниця була придбана за ціною $100.00 USD. Ця конкретна партія акцій ідентифікується як "лот".

Операції з запасами​

Існує дві основні операції, які можна виконувати з інвентарем:

  1. Збільшення (додавання до інвентарю): Коли ви купуєте товар, ви збільшуєте свій інвентар. Ви створюєте новий лот із певною кількістю одиниць і базою витрат.

    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.

  2. Зменшення (видалення з інвентарю): Коли ви продаєте товар, ви зменшуєте свій інвентар. Ви повинні вказати, з якого лоту ви продаєте. Це робиться шляхом надання відповідної інформації у фігурних дужках.

    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:Gains

Beancount повідомляє 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:FifoFIFOlot A, 2024-01-10$100.00$500.0010 @ $120.00, 10 @ $90.00
Assets:Broker:LifoLIFOlot C, 2024-03-10$90.00$600.0010 @ $100.00, 10 @ $120.00
Assets:Broker:HifoHIFOlot B, 2024-02-10$120.00$300.0010 @ $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: Анотація, яка фіксує ринкову ціну на момент транзакції. Вона використовується для конвертації валют або для зазначення ринкової вартості на певну дату.

Ось три сценарії:

  1. Анотація ціни (конвертація): Використовуйте @ для конвертації з однієї валюти в іншу.

    Assets:Forex     1000 USD @ 0.85 EUR
  2. База витрат (придбання): Використовуйте {} при купівлі активу, щоб встановити його вартість.

    Assets:Invest    10 STOCK {100.00 USD}
  3. Обидва (продаж із записом ціни): При продажу активу використовуйте {} для ідентифікації лоту, що продається, і @ для запису ціни продажу. Це дозволяє автоматично розрахувати приріст капіталу.

    Assets:Invest    -10 STOCK {100.00 USD} @ 105.00 USD

    Цей запис продає 10 STOCK з лоту, який коштував $100.00 кожен, за ціною продажу $105.00 кожен.

Окрема директива price надає довідкові дані для ринкової оцінки. Живі ціни можуть підтримувати ці директиви для підтримуваних активів у розміщених журналах. Оновлення залишає ваші лоти, метод бронювання, витрати на придбання та зафіксовані надходження від продажу без змін.

Правила використання ціни​

  1. Анотації цін (@) не впливають на те, який лот бронюється. Відповідність лотів обробляється виключно базою витрат ({}) і методом бронювання рахунку.
  2. Символ @ використовується лише для:
  • Конвертації валют.
  • Запису ринкової вартості активу на момент транзакції.
  • Надання ціни продажу для розрахунку приросту капіталу.

Конфігурація​

Ви можете налаштувати методи бронювання глобально або на рівні окремого рахунку.

Глобальний метод обліку​

Ви можете встановити типовий метод бронювання для всього вашого файлу 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"

Кращі практики​

  1. Організація інвентарю: Щоб підтримувати ваш журнал чистим і простим, настійно рекомендується використовувати окремі рахунки для кожного унікального товару, який ви утримуєте, і обмежувати кожен із них цим товаром у його директиві 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 відхилити зайвий запис замість того, щоб мовчки змішати два інвентарі.

  2. Управління лотами:

  • Використовуйте змістовні мітки для лотів, особливо для конкретних транзакцій, як-от збір податкових збитків або надання акцій співробітникам.

    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%
  1. Налагодження: Якщо ви зіткнулися з помилками або неочікуваною поведінкою, Beancount надає інструменти для перевірки стану вашого інвентарю.
  • Перегляд стану інвентарю: Використовуйте bea doctor context main.beancount 42, щоб переглянути транзакцію в рядку 42, включно з її записами та балансами порушених рахунків. Замініть ім'я файлу та номер рядка на транзакцію, яку хочете переглянути.

    Замініть <LINENO> на номер рядка одразу після транзакції, щоб побачити її ефект.

  • Перевірка відповідності лотів: Інструмент bea check перевіряє весь ваш файл. Він виявить будь-які помилки бронювання, як-от неоднозначні відповідності лотів у режимі STRICT.

Джерело: https://beancount.io/uk/docs/Basics/inventories