سیستم موجودی Beancount یک ویژگی قدرتمند برای ردیابی داراییهایی است که در طول زمان خرید و فروش میشوند، مانند سهام، صندوقهای سرمایهگذاری مشترک، یا ارزهای خارجی. این قابلیت اجازه میدهد تا پایه هزینه به طور دقیق ردیابی شود که برای محاسبه سود سرمایه و درک عملکرد پرتفوی ضروری است. این آموزش اصول اصلی مدیریت موجودیها در دفتر حساب شما را پوشش میدهد.
مفاهیم اصلی
در اصل، مدیریت موجودی حول ردیابی موقعیتها میچرخد. «موقعیت» به سادگی مقدار یک کالا است که در یک حساب نگهداری میشود. Beancount بین دو نوع موقعیت بنیادی تفاوت قائل میشود.
انواع موقعیتها
-
موقعیت ساده (بدون هزینه): این یک ثبت استاندارد موجودی است. نمایانگر مقدار یک کالا بدون هیچ هزینه اکتساب مرتبط است. این مناسب نقدینگی یا تأییدیههای موجودی ساده است.
Assets:Bank:Checking 100.00 USD -
موقعیت با پایه هزینه: این نوع موقعیت شامل تعداد واحدها و کالا و همچنین هزینهای است که با آن خریداری شده است. این اساس ردیابی موجودی است. هزینه درون آکولادها
{}مشخص شده است.Assets:Invest:VTSAX 10 VTSAX {100.00 USD, "lot-1"}در این مثال، ما ۱۰ واحد از
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در اینجا، ما ۵۰ واحد از
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در این معامله، ما ۲۵ واحد از
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بدون خطا بارگذاری میشود، ۳۰۰.۰۰ دلار سود به 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این ۸۰۰.۰۰ دلار سود ثبت میکند — ۳۰۰۰.۰۰ دلار درآمد در مقابل ۱۰۰۰.۰۰ دلار + ۱۲۰۰.۰۰ دلار بهای تمامشده — و حساب را خالی میگذارد. این خاصیت خود 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 گرانترین است — سپس ۱۰ سهم از سه حساب که فقط در روش ثبت آنها متفاوتاند، فروخته میشود:
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بدون هیچ خطایی بارگذاری میشود و مجموعاً ۱,۴۰۰.۰۰ دلار سود ثبت میکند، تقسیمبندی شده به این صورت:
| حساب | روش | دسته ثبتشده | هزینه مبنا | سود تحققیافته | دستههای باقیمانده |
|---|---|---|---|---|---|
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این مبلغ ۲۱۰.۰۰ دلار سود را در برابر دسته ۱۲۰.۰۰ دلاری ثبت میکند. فایل مشابه با "STRICT" در خط open با خطای Ambiguous matches for "-7 STK {}" مواجه میشود.
7. میانگین (پذیرفته شده، اما پیادهسازی نشده)
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 مطلقاً تطابق دسته را غیرفعال میکند.
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: یادداشتی است که قیمت بازار را در زمان معامله ثبت میکند. این یادداشت برای تبدیل ارز یا ثبت ارزش بازار در یک تاریخ خاص استفاده میشود.
در اینجا سه سناریو آورده شده است:
-
یادداشت قیمت (تبدیل): برای تبدیل از یک ارز به ارز دیگر از
@استفاده کنید.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از دستهای که هر کدام ۱۰۰.۰۰ دلار هزینه داشتهاند را به قیمت فروش هر کدام ۱۰۵.۰۰ دلار میفروشد.
قوانین استفاده از قیمت
- یادداشتهای قیمت (
@) تاثیری ندارد که کدام دسته ثبت میشود. تطبیق دسته به طور انحصاری توسط هزینه مبنا ({}) و روش ثبت حساب انجام میشود. - نماد
@فقط برای موارد زیر استفاده میشود:
- تبدیلهای ارزی.
- ثبت ارزش بازار یک دارایی در زمان معامله.
- ارائه قیمت فروش برای محاسبات سود سرمایه.
پیکربندی
میتوانید روشهای ثبت را به صورت جهانی یا به تفکیک حساب تنظیم کنید.
روش ثبت جهانی
میتوانید روش ثبت پیشفرض را برای کل فایل 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برای بررسی تراکنش در خط ۴۲، شامل ثبتها و مانده حسابهای متأثر استفاده کنید. نام فایل و شماره خط را با تراکنشی که میخواهید بررسی کنید جایگزین کنید.<LINENO>را با شماره خطی که دقیقاً بعد از یک تراکنش است جایگزین کنید تا اثر آن را ببینید. -
تأیید تطابق دستهها: ابزار
bea checkکل فایل شما را تأیید میکند. این ابزار هرگونه خطای ثبت، مانند تطابقهای مبهم دستهها در حالتSTRICTرا شناسایی خواهد کرد.