Salta al contingut principal

Precisió i Toleràncies

Apreneu com el sistema de precisió i toleràncies de Beancount ajuda a mantenir l'equilibri en la comptabilitat de doble entrada, especialment quan es tracten transaccions complexes amb múltiples monedes i valors fraccionaris.

Gestionar la precisió numèrica és una pedra angular de la comptabilitat de doble entrada. En la comptabilitat digital, especialment quan es tracta amb múltiples monedes, preus de borsa i accions fraccionàries, petites discrepàncies d'arrodoniment poden conduir ràpidament a frustrants errors de quadrament. Beancount proporciona un sistema sofisticat però intuïtiu per gestionar la precisió i establir toleràncies acceptables. Aquesta guia us explicarà com funciona. ⚙️

Cada número d'aquesta pàgina s'ha comprovat amb Beancount 3.2.3, incloent-hi els límits: cada exemple indica quin residual s'accepta i quin és una xifra massa lluny.

Conceptes Clau de Precisió

L'objectiu principal de Beancount és assegurar que cada transacció quadri a zero. Tanmateix, els càlculs que impliquen preus o costos sovint produeixen resultats amb més decimals dels que és pràctic registrar. El sistema de toleràncies permet petits desequilibris acceptables.

Inferència Automàtica de Toleràncies

Per defecte, Beancount infereix automàticament la tolerància necessària per a cada transacció. Aquesta inferència es gestiona individualment per a cada transacció i es calcula separadament per a cada moneda implicada.

La regla és una multiplicació: la tolerància per a una moneda és la xifra més petita vista en els imports d'aquella moneda, multiplicada per l'opció tolerance_multiplier, que per defecte és 0.5. Amb aquest valor per defecte, la tolerància és la meitat de l'última xifra significativa.

Per exemple, considereu aquesta compra:

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

Beancount infereix les toleràncies de la manera següent:

  • Per a la matèria primera FUND, el número 10.22626 té 5 decimals. La tolerància és la meitat de l'última xifra, així que $0.00001 \div 2 = 0.000005$ FUND.
  • Per a la moneda USD, el número -384.61 té 2 decimals. La tolerància és la meitat de l'última xifra, així que $0.01 \div 2 = 0.005$ USD.

La part de caixa és contra la qual es mesura la tolerància: 10.22626 × 37.61 és 384.6096386, així que aquesta transacció és 0.0003614 USD curta de zero i carrega. Arrodoniu la part de caixa a -384.60 i el desfasament esdevé 0.0096386 USD, superant la tolerància de 0.005, i Beancount informa Transaction does not balance.

Regles de Pes de Transacció

Quan es comprova si una transacció quadra, Beancount calcula el "pes" de cada assentament. Les regles per a aquest càlcul són:

  1. Import Simple: Si un assentament només té un import (p. ex., Assets:Cash -100.00 USD), el seu pes és aquest import exacte.
  2. Assentament amb Preu: Si un assentament té un preu per unitat (p. ex., 10 FUND @ 38.46 USD), el seu pes és amount × price.
  3. Cost per Unitat: Les claus simples contenen el cost d'una unitat, així que 10 FUND {384.61 USD} pesa 10 × 384.61 = 3,846.10 USD, no pas 384.61 USD.
  4. Cost Total: Les claus dobles contenen el cost de tot l'assentament, així que 10 FUND {{384.61 USD}} pesa 384.61 USD. Beancount el converteix a un cost per unitat de 38.461 USD quan emmagatzema el lot.
  5. Cost i Preu: Si un assentament té tant un cost com un preu per unitat (p. ex., 10 FUND {384.61 USD} @ 400.00 USD), només el cost s'utilitza per al quadrament. El preu es registra per a informes, no per a l'aritmètica.

Les regles 3 i 4 són les que costen una tarda a la gent, així que aquí les teniu una al costat de l'altra en un fitxer que carrega:

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

El compte acaba amb 20 FUND en dos lots, 4,230.71 USD de base de cost entre tots dos.

Regles d'Inferència de Precisió

El sistema d'inferència automàtica segueix unes regles específiques:

  1. Format del Número
  • Els imports enters (p. ex., 10 USD) no contribueixen a la inferència de precisió.
  • Un decimal és la precisió més grollera que un import pot implicar: 0.1 × 0.5 = 0.05 unitats. Més enllà necessiteu tolerance_multiplier o un valor per defecte per moneda, tots dos explicats més avall.
  • Els costos i preus (p. ex., {37.61 USD}) estan exclosos de la inferència de tolerància per defecte. Només s'utilitzen els imports principals dels assentaments.
  • Si els assentaments per a la mateixa moneda tenen precisions diferents (p. ex., -10.10 USD i 5.123 USD), Beancount utilitza la tolerància més grollera (més gran). En aquest cas, es basaria en -10.10 USD, donant una tolerància de $0.005$ USD.
  1. Gestió per Defecte Podeu establir una tolerància per defecte global o específica per moneda si una transacció no té números amb decimals a partir dels quals inferir-la.

    ; 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"
  2. Multiplicador de Tolerància L'opció és tolerance_multiplier, i és la fracció de la xifra més petita que compta com a tolerable — no un percentatge afegit al damunt. El seu valor per defecte és 0.5, així que establir 1.2 no afluixa les comprovacions un 20%: fa que cada tolerància inferida sigui 2.4 vegades la per defecte.

    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

    El nom més antic inferred_tolerance_multiplier estableix el mateix valor però informa Renamed to 'tolerance_multiplier'. com a error de càrrega.

  3. Inferència Basada en el Cost Tot i que normalment els costos s'ignoren per a la inferència de tolerància, podeu indicar a Beancount que els utilitzi. Això és útil quan l'import final (p. ex., una retirada de caixa) és el número més precís d'una transacció.

    option "infer_tolerance_from_cost" "TRUE"

Aquí teniu el valor per defecte simple, sense cap opció, al seu límit exacte:

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

Assertions de Saldo

Les assertions de saldo (balance) s'utilitzen per verificar que el saldo del vostre compte coincideix amb un valor conegut en una data específica. També tenen una tolerància associada.

Format Bàsic

La tolerància per a una assertió de balance s'infereix del nombre de decimals de l'import, però és dues vegades més generosa que la utilitzada dins d'una transacció: tolerance_multiplier × 2 × the smallest digit. Amb el multiplicador per defecte, és exactament una unitat de l'últim decimal que heu escrit.

; 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

La comparació és inclusiva: una diferència exactament igual a la tolerància encara passa. Per al segon exemple, qualsevol saldo de $4.26$ a $4.28$ passa la comprovació, i 4.2801 falla amb 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

Toleràncies Explícites

Si la tolerància inferida no és adequada, podeu especificar-ne una explícitament utilitzant el caràcter titlla (~). Aquesta és l'única sintaxi de tolerància explícita que té Beancount, i només funciona en directives balance — una titlla dins d'un assentament de transacció és un error de sintaxi.

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

Pugeu la participació a 4.2811 i la mateixa assertió falla per 0.0101.

Gestió de l'Arrodoniment

Els residuals petits de l'aritmètica de costos i preus són normals. El que Beancount fa amb ells és més restringit del que sembla.

Seguiment d'Errors d'Arrodoniment

L'opció account_rounding nomena un compte destinat a absorbir residuals. Pren un nom de compte complet i s'emmagatzema exactament com l'escriviu — no s'hi afegeix cap prefix d'equitat, a diferència de les opcions de compte d'equitat.

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

En aquesta transacció, 1.245×43.23=53.821351.245 \times 43.23 = 53.82135. La transacció està desequilibrada per $-0.00135$ USD, que està dins de la tolerància inferida de 0.005 USD, així que carrega.

A Beancount 3.2.3 no es publica res a Equity:Rounding. L'opció s'analitza i s'emmagatzema, però cap etapa del carregador insereix l'assentament residual, així que el compte acaba a zero i un residual que està fora de tolerància encara és un error en lloc de ser escombrat:

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

Així que tracteu account_rounding com a inert en aquesta versió. Si voleu que un residual es registri en lloc de ser tolerat, escriviu el tercer assentament vosaltres mateixos:

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

Aquesta versió quadra exactament a zero, i la pols és visible en un compte sobre el qual podeu informar.

Precisió Numèrica Inferida

Beancount no arrodoneix els números que escriviu. No hi ha cap opció default_tolerance — no existeix i falla la càrrega amb Invalid option: 'default_tolerance' — i cap configuració quantifica els imports emmagatzemats.

  1. L'emmagatzematge sempre és exacte. Escriviu 53.82135 USD i el llibre major manté 53.82135 USD, siguin quines siguin les vostres configuracions de tolerància. La tolerància decideix si una transacció és acceptada; mai edita un número.

  2. La visualització és una configuració separada. display_precision fixa quants dígits fraccionaris es mostren per a una moneda, i no canvia res del valor emmagatzemat ni de la comprovació de saldo.

    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. L'arrodoniment és un assentament que heu d'escriure. Si voleu treure el residual de l'aritmètica, arrodoniu l'import al codi font i registreu la diferència explícitament, com a l'exemple de tres assentaments anterior.

Detalls d'Implementació

Uns quants punts tècnics clarifiquen com Beancount aconsegueix aquesta fiabilitat.

  1. Representació de Números: Beancount utilitza el mòdul decimal de Python, no números de coma flotant. El context per defecte porta 28 dígits significatius — dígits totals, no dígits després del punt — cosa que evita els errors de representació binària comuns als floats.

  2. Classe DisplayContext: Aquesta classe interna gestiona tot el format de números per a finalitats de visualització. Infereix la precisió de cada moneda a partir dels números del vostre fitxer tret que display_precision la fixi, i pot formatar la sortida amb columnes alineades i comes.

  3. Precisió vs. Tolerància: És crucial distingir aquests dos conceptes:

  • Precisió es relaciona amb el format de visualització d'un número (quants decimals es mostren).
  • Tolerància és el marge per a desequilibri utilitzat durant les comprovacions de verificació.

Bones Pràctiques ✨

Aquí teniu algunes recomanacions pràctiques per gestionar la precisió al vostre llibre major.

Configuració Inicial

Per a la majoria de llibres majors nous, aquesta és una configuració inicial robusta:

; 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"

Consells de Resolució de Problemes

Si trobeu errors de quadrament:

  • Afegiu dígits decimals a l'import d'un assentament per crear una inferència de tolerància local més ajustada i precisa.
  • Utilitzeu toleràncies explícites (~) en assertions de balance que fallen a causa de discrepàncies previsibles.
  • Registreu el residual en un compte dedicat amb un tercer assentament real, per poder informar de la freqüència amb què passa.
  • Considereu establir valors per defecte específics per moneda si tracteu sovint amb monedes que tenen convencions diferents (p. ex., el JPY no té decimals).

Estratègia de Migració

Quan apliqueu aquests conceptes a un llibre major existent i desordenat:

  1. Comenceu amb una tolerància global generosa (p. ex., *:0.05) i un tolerance_multiplier més alt per aconseguir que el fitxer es validi.
  2. Gradualment, ajusteu les toleràncies i corregiu els errors que apareguin.
  3. Afegiu dígits explícits als imports de les transaccions problemàtiques perquè la inferència faci la seva feina.
  4. Vigileu el saldo del compte d'arrodoniment. Un saldo gran o que creix ràpidament pot indicar un problema sistèmic que necessita investigació.

Font: https://beancount.io/ca/docs/Basics/precision