پرش به محتوای اصلی

دقت و تلورانس‌ها

یاد بگیرید که چگونه سیستم‌های دقت و تلورانس Beancount به حفظ تعادل در حسابداری دوطرفه کمک می‌کنند، به‌ویژه هنگام کار با تراکنش‌های پیچیده شامل ارزهای متعدد و مقادیر کسری.

مدیریت دقت عددی یکی از ارکان حسابداری دوطرفه است. در دفترداری دیجیتال، به‌ویژه هنگام کار با ارزهای متعدد، قیمت سهام و سهام کسری، اختلافات کوچک گرد کردن می‌توانند به سرعت منجر به خطاهای خسته‌کننده در تراز شدن شوند. Beancount یک سیستم پیچیده اما بصری برای مدیریت دقت و تعیین تلورانس‌های قابل قبول فراهم می‌کند. این راهنما شما را با نحوه کار آن آشنا می‌شود. ⚙️

همه اعداد در این صفحه با Beancount 3.2.3 بررسی شده‌اند، از جمله مرزها: هر مثال مشخص می‌کند که چه مقدار خطای باقی‌مانده قابل قبول است و چه مقداری یک رقم و‌عث عدم تعادل است.

مفاهیم اصلی دقت

هدف اصلی Beancount اطمینان از تراز بودن هر تراکنش به صفر است. با این حال، محاسبات شامل قیمت‌ها یا هزینه‌ها اغلب نتایجی با ارقام اعشاری بیش از آنچه عملی است تولید می‌کنند. سیستم تلورانس اجازه اختلافات تعادلی کوچک را می‌دهد.

استنتاج خودکار تلورانس

به‌صورت پیش‌فرض، Beancount تلورانس لازم را برای هر تراکنش به‌صورت خودکار استنتاج می‌کند. این استنتاج به‌صورت جداگانه برای هر تراکنش و برای هر ارز جداگانه ودر محاسبه می‌شود.

این یک قانون ضرب است: تلورانس برای ارز برابر است با کوچک‌ترین رقم مشاهده شده در مبالغ آن ارز در دفتر، ضرب‌در گزینه‌ی tolerance_multiplier که به‌صورت پیش‌فرض 0.5 است. در آن پیش‌فرض، تلورانس برابر است با نیمه‌ی آخرین رقم معنادار.

برای مثال، این خرید را در نظر بگیرید:

2013-04-03 * "Buy Fund"
  Assets:Fund     10.22626 FUND {37.61 USD}
  Assets:Cash     -384.61 USD

Beancount تلورانس‌ها را به شرح زیر استنتاج می‌کند:

  • برای کالای FUND، عدد 10.22626 دارای ۵ رقم اعشار است. تلورانس نصف آخرین رقم است، بنابراین $0.00001 \div 2 = 0.000005$ FUND.
  • برای ارز USD، عدد -384.61 دارای ۲ رقم اعشار است. تلورانس نصف آخرین رقم است، بنابراین $0.01 \div 2 = 0.005$ USD.

پایان وجه نقد معیار تلورانس است: 10.22626 × 37.61 برابر 384.6096386 است، بنابراین این تراکنش 0.0003614 USD کمتر از صفر است و بارگذاری می‌شود. اگر این مبلغ را به -384.60 گرد کنید، شکاف به 0.0096386 USD می‌رسد که از تلورانس 0.005 فراتر and Beancount گزارش می‌دهد که Transaction does not balance.

قواعد وزن تراکنش

هنگام بررسی تراز بودن یک تراکنش، Beancount "وزنه" هر قید را محاسبه می‌کند. قواعد این محاسبه به این صورت است:

  1. مبلغ ساده: اگر یک قید فقط یک مبلغ داشته باشد (مثلاً Assets:Cash -100.00 USD)، وزن آن دقیقاً همان مبلغ است.
  2. قید قیمت: اگر قید قیمت هر واحد داشته باشد (مثلاً 10 FUND @ 38.46 USD)، وزن آن مبلغ × قیمت است.
  3. هزینه‌ی هر واحد: براکت‌ خصوصی هزینه یک واحد را نگه می‌دارد، بنابراین 10 FUND {384.61 USD} وزنش 10 × 384.61 = 3,846.10 USD است، نه 384.61 USD.
  4. هزینه‌ی کل: قوس دوگانه هزینه کل قید را نگه می‌دارد، بنابراین 10 FUND {{384.61 USD}} وزنش 384.61 USD است. Beancount آن را به هزینه‌ی واحد 38.461 USD تبدیل می‌کند وقتی که ذخیره می‌کند.
  5. هزینه و قیمت: اگر یک قید هم هزینه و هم قیمت هر واحد داشته باشد (مثلاً 10 FUND {384.61 USD} @ 400.00 USDفقط هزینه برای تراز استفاده می‌شود. قیمت برای گزارش‌دهی ثبت می‌شود، نه برای محاسبات دقیق.

قواعد 3 و 4 همان‌هایی هستند که باعث مشکلات بزرگ برای افراد می‌شوند‌ها‌در اینجا برای مقایسه کنار هم گذاشته شده‌اند در فایل که بارگذاری می‌شود:

1970-01-01 open Assets:Fund
1970-01-01 open Assets:Cash
 
; Per-unit cost: ten units at 384.61 each, so 3,846.10 USD leaves the
; cash account.
2013-04-03 * "Broker" "Buy at a per-unit cost"
  Assets:Fund     10 FUND {384.61 USD}
  Assets:Cash  -3846.10 USD
 
; Total cost: the braces double and 384.61 USD is the entire purchase.
; The lot is stored at 38.461 USD per unit.
2013-04-04 * "Broker" "Buy at a total cost"
  Assets:Fund      10 FUND {{384.61 USD}}
  Assets:Cash   -384.61 USD

حساب با 20 FUND در دو لات، 4,230.71 USD از پایه هزینه بین آنها به پایان می‌رسد.

قواعد استنتاج دقت

سیستم استنتاج خودکار از قواعد مشخصی پیروی می‌کند:

  1. فرمت عدد

    • مبالغ صحیح (مثلاً 10 USD) در استنتاج دقت دخالتی ندارند.
    • یک رقم اعشار کمترین دقتی است که یک مبلغ می‌تواند نشان دهد: 0.1 × 0.5 = 0.05 واحد. فراتر از آن به tolerance_multiplier یا پیش‌فرض اولیه نیاز دارید، که در زیر توضیح داده می‌شود.
    • هزینه‌ها و قیمت‌ها (مثل {37.61 USD}) به‌صورت پیش‌فرض از استنتاج تلورانس حذف می‌شوند. فقط مبالغ اصلی قیدها استفاده می‌شوند.
    • اگر قیدهای یک ارز دقت‌های مختلفی داشته باشند (مثلاً -10.10 USD و 5.123 USD)، Beancount از دقیق‌ترین (بزرگ‌ترین) تلورانس استفاده می‌کند. در این مورد، بر اساس -10.10 USD، تلورانس $0.005$ USD خواهد بود.
  2. پردازش پیش‌فرض شما می‌توانید تلورانس پیش‌فرض جهانی یا مرتبط با ارز را تنظیم کنید اگر تراکنش هیچ عددی با رقم اعشار برای استنتاج نداشته باشد.

    ; Sets a default tolerance for all currencies without explicit rules
    option "inferred_tolerance_default" "*:0.001"
     
    ; Sets a specific default tolerance for USD
    option "inferred_tolerance_default" "USD:0.003"
  3. ضرایب تلورانس گزینه‌ی tolerance_multiplier است و مقدار کسری از کوچک‌ترین رقم است که قابل قبول است — نه یک درصد اضافه. پیش‌فرض آن 0.5 است، بنابراین تنظیم 1.2 به معنای 20% آسان شدن نیست: هر تلورانس استنباط شده را 2.4 برابر مقدار پیش‌فرض می‌کند.

    option "tolerance_multiplier" "1.2"
     
    1970-01-01 open Assets:Cash
    1970-01-01 open Expenses:Fees
     
    ; The coarsest amount has two decimals, so the tolerance is
    ; 1.2 x 0.01 = 0.012 USD, and this residual of exactly 0.012 passes.
    ; At the default 0.5 the tolerance would be 0.005 and this would fail.
    2024-05-01 * "Bank" "Wire fee"
      Expenses:Fees      100.00 USD
      Assets:Cash       -99.988 USD

    نام قدیمی inferred_tolerance_multiplier همان مقدار را تنظیم می‌کند اما پیام Renamed to 'tolerance_multiplier'. را به عنوان خطای بارگذاری گزارش می‌دهد.

  4. استنتاج مبتنی بر هزینه اگرچه هزینه‌ها به‌طور معمول برای استنتاج تلورانس نادر در نظر گرفته می‌شوند، شما می‌توانید به Beancount بگویید از آنها استفاده کند. این در مواقعی مفید است که مبلغ نهایی (مثلاً برداشت نقدی) دقیق‌ترین عدد در تراکنش است.

    option "infer_tolerance_from_cost" "TRUE"

در اینجا پیش‌فرض ساده و بدون هیچ گزینه‌ای، در مرز دقیق آن:

1970-01-01 open Assets:Cash
1970-01-01 open Expenses:Fees
 
; Two decimals on the coarsest amount, so the tolerance is
; 0.5 x 0.01 = 0.005 USD. This residual is exactly 0.005 and passes;
; -99.994 would be 0.006 and would fail.
2024-05-01 * "Bank" "Wire fee"
  Expenses:Fees      100.00 USD
  Assets:Cash       -99.995 USD

تأیید تراز (Balance Assertions)

تأیید تراز (balance) برای بررسی اینکه تراز حساب شما با مقدار مشخصی در تاریخ خاصی مطابقت دارد استفاده می‌شود. آنها نیز دارای تلورانس مرتبط هستند.

فرمت اصلی

تلورانس برای یک تأیید تراز از تعداد اعشار عدد استنتاج می‌شود، اما دو برابر سخاوتمندانه‌تر از تراکنش است: tolerance_multiplier × 2 × the smallest digit. در پیش‌فرض، این دقیقاً یک واحد از آخرین رقم اعشاری است که نوشته‌اید.

; Asserts the balance is 4.271 RGAGX with a tolerance of +/-0.001
2015-05-08 balance Assets:Fund  4.271 RGAGX
 
; Asserts the balance is 4.27 RGAGX with a tolerance of +/-0.01
2015-05-08 balance Assets:Fund  4.27 RGAGX

مقایسه شامل مرز است: تفاوتی که دقیقاً برابر تلورانس باشد نیز قبول می‌شود. برای مثال دوم، هر ترالی از 4.26 تا 4.28 قبول می‌شود، و 4.2801 خطا می‌گیرد: Balance failed for 'Assets:Fund': expected 4.27 RGAGX != accumulated 4.2801 RGAGX (0.0101 too much).

1970-01-01 open Assets:Fund
1970-01-01 open Equity:Opening-Balances
 
1970-01-02 * "Broker" "Opening position"
  Assets:Fund                4.28 RGAGX
  Equity:Opening-Balances   -4.28 RGAGX
 
; 4.28 is 0.01 away from the asserted 4.27, which is the whole tolerance.
2015-05-08 balance Assets:Fund   4.27 RGAGX

تلورانس‌های صریح

اگر تلورانس استنتاج شده مناسب نباشد، می‌توانید با کاراکتر تیلد (~) یک تلورانس صریح مشخص کنید. این تنها نحو صریح تلورانس در Beancount است و فقط بر روی balance و‌عیسی اعمال می‌شود — استفاده از تیلد در یک ضبط در تراکنش یک خطای syntax است.

1970-01-01 open Assets:Fund
1970-01-01 open Equity:Opening-Balances
 
1970-01-02 * "Broker" "Opening position"
  Assets:Fund                4.281 RGAGX
  Equity:Opening-Balances   -4.281 RGAGX
 
; Asserts the balance is 4.271 RGAGX with a custom tolerance of
; +/-0.01 RGAGX, so anything from 4.261 to 4.281 passes.
2015-05-08 balance Assets:Fund   4.271 ~ 0.01 RGAGX

اگر مقدار را به 4.2811 برسانید، همان تأیید تراز با 0.0101 خطا می‌گیرد.

مدیریت گرد کردن

باقیمانده‌های کوچک از هزینه‌ها و قیمت‌ها طبیعی هستند. کاری که Beancount با آنها می‌کند دقیق‌تر از آن چیزی است که از پرس به نظر می‌رسد.

ردیابی خطای گرد کردن

گزینه‌ی account_rounding یک حساب را برای جذب باقیمانده‌ها مشخص می‌کند. این گزینه نام کامل حساب را می‌گیرد و دقیق‌اً همانطی که نوشته‌ایدا ذخیره می‌شود، بر خلاف گزینه‌های حساب الصافی هیچ پیشوند Equity اضافه نمی‌شود.

option "account_rounding" "Equity:Rounding"
 
1970-01-01 open Assets:Invest
1970-01-01 open Assets:Cash
1970-01-01 open Equity:Rounding
 
; 1.245 x 43.23 = 53.82135, so this is 0.00135 USD short of balancing.
2013-02-23 * "Broker" "Purchase"
  Assets:Invest     1.245 RGAGX {43.23 USD}
  Assets:Cash      -53.82 USD

در این تراکنش، 1.245×43.23=53.821351.245 \times 43.23 = 53.82135. تراکنش با $-0.00135$ USD نامتعادل است که در تلورانس استنتاج شده 0.005 USD است، بنابراین بارگذاری می‌شود.

در Beancount 3.2.3 هیچ چیزی به Equity:Rounding ثبت نمی‌شود. گزینه پردازش و ذخیره می‌شود، اما هیچ مرحله‌ای از راکتور، ثبت باقیمانده را درج نمی‌کند، بنابراین حساب با صفر به پایان می‌رسد و باقیمانده‌ی خارج از تلورانس همچنان خطا است به‌جای اینکه جمع‌آوری شود:

option "account_rounding" "Equity:Rounding"
 
1970-01-01 open Assets:Invest
1970-01-01 open Assets:Cash
1970-01-01 open Equity:Rounding
 
; 0.10135 USD out, far past the 0.005 tolerance. Setting
; account_rounding does not rescue it:
;   Transaction does not balance: (0.10135 USD)
2013-02-23 * "Broker" "Purchase"
  Assets:Invest     1.245 RGAGX {43.23 USD}
  Assets:Cash      -53.72 USD

پس با account_rounding به عنوان گزینه‌ای بی‌اثر در این نسخه برخورد کنید. اگر می‌خواهید باقیمانده ثبت شود به‌جای مورد تلورانس، خودتان سومین ثبت را بنویسید:

1970-01-01 open Assets:Invest
1970-01-01 open Assets:Cash
1970-01-01 open Equity:Rounding
 
2013-02-23 * "Broker" "Purchase"
  Assets:Invest      1.245 RGAGX {43.23 USD}
  Assets:Cash       -53.82 USD
  Equity:Rounding   -0.00135 USD

آن نسخه دقیقاً به صفر تراز می‌شود و گرد و غبار در حسابی که می‌توانید گزارش بگیرید قابل مشاهده است.

استنتاج دقت عددی

Beancount اعدادی را که می‌نویسید گرد نمی‌کند. گزینه‌ای به نام default_tolerance وجود ندارد — این گزینه وجود ندارد و بارگذاری با پیام Invalid option: 'default_tolerance' ناموفق است — و هیچ تنظیمی برای کوانتیزه کردن مقادیر ذخیره‌شده وجود ندارد.

  1. ذخیره همیشه دقیق است. اگر 53.82135 USD بنویسید، دفتر کل 53.82135 USD ذخیره می‌کند، هرچه تلورانس باشد. تلورانس تصمیم می‌گیرد که تراکنش پذیرفته شود، اما هرگز عدد را تغییر نمی‌دهد.

  2. نمایش تنظیمات جداگانه است. display_precision مشخص می‌کند که در نمایش هر ارز، هر چند رقم اعشار نمایش داده شود، و هیچ تغییری در مقدار ذخیره‌شده و بررسی تراز ایجاد نمی‌کند.

    option "display_precision" "USD:0.01"
     
    1970-01-01 open Assets:Cash
    1970-01-01 open Income:Interest
     
    ; Rendered as 53.82 USD, stored as 53.82135 USD.
    2024-06-30 * "Bank" "Interest"
      Assets:Cash          53.82135 USD
      Income:Interest     -53.82135 USD
  3. گرد کردن به عهده‌ی شماست. اگر می‌خواهید باقیمانده از محاسبات خارج نشود، مقدار را در منبع گرد کنید و تفاوت را صریح ثبت کنید، همانطور که در مثال سه‌ثبتی بالا نشان داده شد.

جزئیات پیاده‌سازی

چند نکته فنی روشن می‌سازد که Beancount چگونه این قابلیت اطمینان را به دست می‌آورد.

  1. نمایش عدد: Beancount از ماژول decimal پایتون استفاده می‌کند، نه ممیز شناور. زمینه پیش‌فرض دارای ۲۸ رقم مهم – هم‌رقم، هم رقم بعد از اعشار – که از خطاهای نمایش دودویی که معمولاً در ممیز شناور رخ می‌دهد جلوگیری می‌کند.

  2. کلاس DisplayContext": این کلاس داخلی تمام قارم‌بندی اعداد برای نمایش را مدیریت می‌کند. دقت هر ارز را از اعداد فایل شما استنتاج می‌کند مگر اینکه display_precision آن را محدود کند، و می‌تواند خروجی را با ستون‌های هم‌تراز و کاما صفحه‌آرایی کند.

  3. دقت در مقابل تلورانس: این دو مفهوم را باید به دقت متمایز کرد:

  • دقت به قالب پردازه یک عدد مربوط است (چند رقم اعشار نمایش داده می‌شود).
  • تلورانس به مقدار مجاز عدم تعادل در فرآیند بررسی استفاده می‌شود.

بهترین روش‌ها ✨

در اینجا چند توصیه عملی برای مدیریت دقت در دفتر کل شما ارائه شده است.

تنظیمات اولیه

برای بیشتر دفترهای جدید، این یک پیکربندی شروع قوی است:

; A floor for currencies that have no decimals to infer from
option "inferred_tolerance_default" "*:0.005"
 
; Leave the multiplier at its 0.5 default unless a real institution
; forces your hand; 1.2 would mean 2.4x the usual tolerance.
option "tolerance_multiplier" "0.5"

نکات رفع اشکال

اگر با خطاهای تراز مواجه شدید:

  • رقم اعشار به مبلغ یک قید اضافه کنید تا تلورانس محلی دقیق‌تری ایجاد مجموعه.
  • از تلورانس‌های صریح (~) برای تأییدهای تراست که به دلیل اختلافات پیش‌بینی‌شونده شکست می‌خورند استفاده کنید.
  • باقیمانده را به یک حساب مخصوص با یک سومین ورودی واقعی ثبت کنید و می‌توانید گزارش تهیه کنید که چند وقت یکبار رخ می‌دهد.
  • اگر با ارزهایی با الگوهای متفاوت (مثلاً ین ژاپن با بدون اعشار) سروکار دارید، مثال‌های پیش‌فرض‌های مرتبط با ارز تعیین کنید.

استراتژی انتقال

هنگام اعمال این مفاهیم به یک دفتر موجود و پیچیده:

  1. برای اعتبارسنجی فایل، با یک تلورانس جهانی سخاوتمندانه (مثلاً *:0.05) و tolerance_multiplier بالاتر شروع کنید.
  2. به‌تدریج تلورانس‌ها را محدودتر کنید و خطاهایی که ظاهر می‌شوند را نگاه کنید.
  3. در تراکنش‌های مشکل‌دار، رقم های اعشار به مقادیر اضافه کنید تا استنتاج بتواند کار خود را انجام دهد.
  4. مولازحساب گرد کردن را نظارت کنید. مانده‌ای بزرگ یا رشد‌یته ویتواند نشان‌دهنده یک مشکل سیستمی باشد.

منبع: https://beancount.io/fa/docs/Basics/precision