Pular para o conteúdo principal

Um Guia para Precisão e Tolerâncias no Beancount

Gerenciar a precisão numérica é uma pedra angular da contabilidade de partidas dobradas. Na escrituração contábil digital, especialmente ao lidar com múltiplas moedas, preços de ações e ações fracionárias, pequenas discrepâncias de arredondamento podem rapidamente levar a erros de balanceamento frustrantes. O Beancount fornece um sistema sofisticado, mas intuitivo, para lidar com a precisão e definir tolerâncias aceitáveis. Este guia irá explicar como ele funciona. ⚙️

Conceitos Essenciais de Precisão

precision

O objetivo principal do Beancount é garantir que cada transação seja balanceada a zero. No entanto, cálculos envolvendo preços ou custos frequentemente produzem resultados com mais casas decimais do que é prático registrar. O sistema de tolerância permite pequenos desequilíbrios aceitáveis.

Inferência Automática de Tolerância

Por padrão, o Beancount infere a tolerância necessária para cada transação automaticamente. Esta inferência é tratada individualmente para cada transação e calculada separadamente para cada moeda envolvida.

A regra é simples: a tolerância é metade do último dígito significativo dos números presentes nas lançamentos da transação.

Por exemplo, considere esta compra:

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

O Beancount infere as tolerâncias da seguinte forma:

  • Para a commodity FUND, o número 10.22626 tem 5 casas decimais. A tolerância é metade do último dígito, então 0.00001div2=0.0000050.00001 \\div 2 = 0.000005 FUND.
  • Para a commodity USD, o número -384.61 tem 2 casas decimais. A tolerância é metade do último dígito, então 0.01div2=0.0050.01 \\div 2 = 0.005 USD.

Regras de Peso da Transação

Ao verificar se uma transação está balanceada, o Beancount calcula o "peso" de cada lançamento. As regras para este cálculo são:

  1. Valor Simples: Se um lançamento tem apenas um valor (por exemplo, Assets:Cash -100.00 USD), seu peso é esse valor exato.
  2. Lançamento de Preço: Se um lançamento tem um preço por unidade (por exemplo, 10 FUND @ 38.46 USD), seu peso é valor × preço.
  3. Lançamento de Custo: Se um lançamento tem um custo total (por exemplo, 10 FUND {384.61 USD}), seu peso é o valor do custo total.
  4. Custo e Preço: Se um lançamento tem tanto um custo total quanto um preço por unidade (por exemplo, 10 FUND {384.61 USD} @ 38.46 USD), apenas o custo total é usado para balanceamento. O preço por unidade é tratado como um comentário ou memo.

Regras de Inferência de Precisão

O sistema de inferência automática segue algumas regras específicas:

  1. Formato do Número
  • Valores inteiros (por exemplo, 10 USD) não contribuem para a inferência de precisão.
  • A tolerância máxima que pode ser automaticamente inferida é 0.05 unidades (por exemplo, de um número como 10.1 USD). Se você precisar de uma tolerância maior, você deve especificá-la manualmente.
  • Custos e preços (por exemplo, {37.61 USD}) são excluídos da inferência de tolerância. Apenas os valores primários dos lançamentos são usados.
  • Se lançamentos para a mesma moeda têm diferentes precisões (por exemplo, -10.10 USD e 5.123 USD), o Beancount usa a tolerância mais grosseira (maior). Neste caso, seria baseado em -10.10 USD, resultando em uma tolerância de 0.0050.005 USD.
  1. Tratamento Padrão Você pode definir uma tolerância padrão global ou específica para uma moeda se uma transação não tiver números com casas decimais dos quais inferi-la.

    ; Define uma tolerância padrão para todas as moedas sem regras explícitas
    option "inferred_tolerance_default" "*:0.001"

    ; Define uma tolerância padrão específica para USD
    option "inferred_tolerance_default" "USD:0.003"
  2. Multiplicador de Tolerância Você pode aumentar globalmente todas as tolerâncias inferidas por um multiplicador fixo. Isso é útil para afrouxar as verificações em todo o seu arquivo sem alterar cada transação. Um multiplicador de 1.2 aumenta todas as tolerâncias inferidas em 20%.

    option "inferred_tolerance_multiplier" "1.2"
  3. Inferência Baseada em Custo Embora os custos sejam normalmente ignorados para inferência de tolerância, você pode instruir o Beancount a usá-los. Isso é útil quando o valor final (por exemplo, um saque em dinheiro) é o número mais preciso em uma transação.

    option "infer_tolerance_from_cost" "TRUE"

Asserções de Balanço

As asserções de balanço (balance) são usadas para verificar se o balanço da sua conta corresponde a um valor conhecido em uma data específica. Elas também têm uma tolerância associada.

Formato Básico

Semelhante às transações, a tolerância para uma asserção balance é inferida do número de casas decimais no valor.

; Assegura que o balanço é 4.271 RGAGX com uma tolerância de ±0.0005
2015-05-08 balance Assets:Fund 4.271 RGAGX

; Assegura que o balanço é 4.27 RGAGX com uma tolerância de ±0.005
2015-05-08 balance Assets:Fund 4.27 RGAGX

O balanço calculado deve estar dentro deste intervalo. Para o segundo exemplo, qualquer balanço entre 4.2654.265 e 4.2754.275 passaria na verificação.

Tolerâncias Explícitas

Se a tolerância inferida não for adequada, você pode especificar uma explicitamente usando o caractere til (~).

; Assegura que o balanço é 4.271 RGAGX com uma tolerância customizada de ±0.01 RGAGX
2015-05-08 balance Assets:Fund 4.271 ~ 0.01 RGAGX

Aqui, a asserção passará se o balanço calculado estiver entre 4.2614.261 e 4.2814.281 RGAGX.

Gerenciamento de Arredondamento

Para casos onde pequenos resíduos de cálculos são esperados e aceitáveis, o Beancount fornece ferramentas para gerenciá-los sistematicamente.

Rastreamento de Erros de Arredondamento

Você pode designar uma conta especial para coletar automaticamente erros de arredondamento. Isso mantém suas transações perfeitamente balanceadas, direcionando pequenas quantias restantes para um único lugar.

Primeiro, habilite a opção e abra a conta:

option "account_rounding" "Equity:RoundingError"
2000-01-01 open Equity:RoundingError

Agora, o Beancount adicionará automaticamente uma terceira perna a qualquer transação que não balanceie dentro de sua tolerância, lançando a diferença em Equity:RoundingError.

2013-02-23 * "Compra"
Assets:Invest 1.245 RGAGX {43.23 USD}
Assets:Cash -53.82 USD

Nesta transação, 1.245times43.23=53.821351.245 \\times 43.23 = 53.82135. A transação está desbalanceada em 0.00135-0.00135 USD. Com a opção de arredondamento habilitada, o Beancount internamente trata como:

2013-02-23 * "Compra"
Assets:Invest 1.245 RGAGX {43.23 USD}
Assets:Cash -53.82 USD
Equity:RoundingError -0.00135 USD ; Adicionado automaticamente

Precisão Numérica Inferida

O Beancount também pode usar as configurações de tolerância para arredondar automaticamente os números antes mesmo de serem inseridos nas estruturas de dados do livro razão.

  1. Nenhuma Tolerância Especificada: Se nenhuma tolerância for definida, os números são usados em sua precisão total. Nenhum arredondamento ocorre.

  2. Com Tolerância Padrão: Se você definir uma tolerância padrão, os números serão quantizados para esse nível.

    option "default_tolerance" "USD:0.001"

    Com esta configuração, um número como 53.82135 USD seria arredondado e armazenado como 53.821 USD.

  3. Com Conta de Arredondamento: Se tanto uma tolerância padrão quanto uma conta de arredondamento estiverem ativas, o Beancount quantiza o número e captura o resíduo.

    option "default_tolerance" "USD:0.01"
    option "account_rounding" "Equity:RoundingError"

    Um número como 53.82135 USD seria armazenado como 53.82 USD, e o resíduo de -0.00135 USD seria lançado em Equity:RoundingError.

Detalhes da Implementação

Alguns pontos técnicos esclarecem como o Beancount alcança esta confiabilidade.

  1. Representação Numérica: O Beancount usa o módulo decimal do Python, não números de ponto flutuante. Isso permite até 28 casas decimais de precisão e evita os erros de representação binária comuns aos floats.

  2. Classe DisplayContext: Esta classe interna lida com toda a formatação de números para fins de exibição. Ela respeita as configurações de precisão específicas da moeda e pode formatar a saída com colunas alinhadas e vírgulas.

  3. Precisão vs. Tolerância: É crucial distinguir estes dois conceitos:

  • Precisão se refere ao formato de exibição de um número (quantas casas decimais são mostradas).
  • Tolerância é a margem para desequilíbrio usada durante as verificações de validação.

Melhores Práticas ✨

Aqui estão algumas recomendações práticas para gerenciar a precisão em seu livro razão.

Configuração Inicial

Para a maioria dos novos livros razão, esta é uma configuração inicial robusta:

; Um padrão razoável para a maioria das moedas (por exemplo, USD, EUR)
option "inferred_tolerance_default" "*:0.005"

; Um buffer de 10% em todas as tolerâncias inferidas
option "inferred_tolerance_multiplier" "1.1"

; Uma conta para capturar toda a poeira de arredondamento
option "account_rounding" "Equity:RoundingError"
2000-01-01 open Equity:RoundingError

Dicas de Solução de Problemas

Se você encontrar erros de balanceamento:

  • Adicione casas decimais ao valor de um lançamento para criar uma inferência de tolerância local mais precisa.
  • Use tolerâncias explícitas (~) em asserções balance que falham devido a discrepâncias previsíveis.
  • Rastreie erros de arredondamento em uma conta dedicada para ver onde e com que frequência eles ocorrem.
  • Considere definir padrões específicos para cada moeda se você lida frequentemente com moedas que têm convenções diferentes (por exemplo, JPY não tem decimais).

Estratégia de Migração

Ao aplicar estes conceitos a um livro razão existente e confuso:

  1. Comece com uma tolerância global generosa (por exemplo, *:0.05) e um multiplicador alto para fazer o arquivo ser validado.
  2. Gradualmente aperte as tolerâncias e corrija os erros que aparecem.
  3. Adicione dígitos explícitos aos valores em transações problemáticas para deixar a inferência fazer seu trabalho.
  4. Monitore o balanço da conta de arredondamento. Um balanço grande ou em rápido crescimento pode sinalizar um problema sistêmico que precisa de investigação.