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

Управління запасами

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

Система обліку запасів 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:FifoFIFOпартія A, 2024-01-10$100.00$500.0010 @ $120.00, 10 @ $90.00
Assets:Broker:LifoLIFOпартія C, 2024-03-10$90.00$600.0010 @ $100.00, 10 @ $120.00
Assets:Broker:HifoHIFOпартія 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 CLI обробляє товари.

Специфікація лоту

"Лот" — це конкретний блок товару, придбаний у певний час і за певною ціною. Коли ви створюєте або зменшуєте позицію, ви можете детально вказати її атрибути лоту.

Повна специфікація

Коли ви збільшуєте інвентар (купуєте), ви можете вказати до трьох атрибутів лоту, розділених комами в одному наборі фігурних дужок:

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 за одиницю.

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

  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