O sistema de inventário do Beancount é um recurso poderoso para rastrear ativos que são comprados e vendidos ao longo do tempo, como ações, fundos mútuos ou moedas estrangeiras. Ele permite um rastreamento preciso da base de custo, o que é essencial para calcular ganhos de capital e entender o desempenho do portfólio. Este tutorial aborda a mecânica central do gerenciamento de inventários no seu razão.
Conceitos Fundamentais
Em sua essência, o gerenciamento de inventário gira em torno do rastreamento de posições. Uma "posição" é simplesmente uma quantidade de uma commodity mantida em uma conta. O Beancount distingue entre dois tipos fundamentais de posições.
Tipos de Posição
-
Posição Simples (Sem Custo): Este é um lançamento de saldo padrão. Ele representa uma quantidade de uma commodity sem qualquer custo de aquisição associado. É adequado para dinheiro em caixa ou asserções de saldo simples.
Assets:Bank:Checking 100.00 USD -
Posição com Base de Custo: Este tipo de posição inclui não apenas o número de unidades e a commodity, mas também o custo pelo qual foi adquirida. Esta é a base do rastreamento de inventário. O custo é especificado dentro de chaves
{}.Assets:Invest:VTSAX 10 VTSAX {100.00 USD, "lot-1"}Neste exemplo, mantemos 10 unidades de
VTSAX. Cada unidade foi adquirida a um custo de $100,00 USD. Este lote específico de cotas é identificado como um "lote" (lot).
Operações de Inventário
Existem duas operações principais que você pode realizar em um inventário:
-
Aumentos (Adicionar ao inventário): Quando você compra uma commodity, você aumenta seu inventário. Você cria um novo lote com um número específico de unidades e uma base de custo.
2024-01-15 * "Buy shares" Assets:Invest:STOCK 50 STOCK {25.00 USD, "lot-1"} Assets:Bank:Checking -1250.00 USDAqui, compramos 50 unidades de
STOCKa um custo por unidade de $25,00 USD. Isso cria um lote na contaAssets:Invest:STOCK. -
Reduções (Remover do inventário): Quando você vende uma commodity, você reduz seu inventário. Você deve especificar de qual lote está vendendo. Isso é feito fornecendo informações correspondentes dentro das chaves.
2024-01-20 * "Sell shares" Assets:Invest:STOCK -25 STOCK {25.00 USD} Assets:Bank:Checking 625.00 USDNesta transação, estamos vendendo 25 unidades de
STOCKdo lote que foi comprado a $25,00 USD por unidade.
Métodos de Contabilização
Quando você reduz um inventário, o Beancount precisa de uma regra para decidir de qual lote específico retirar se vários lotes corresponderem à redução. Essa regra é chamada de "método de booking". Você pode definir um padrão para todo o arquivo com uma opção, ou dar a uma conta seu próprio método na diretiva open.
O Beancount 3.2.3 aceita sete nomes de métodos: STRICT (o padrão), STRICT_WITH_SIZE, NONE, FIFO, LIFO, HIFO e AVERAGE. Seis deles estão implementados; AVERAGE é analisado sintaticamente mas gera um erro no momento em que precisa fazer o booking de uma redução, como mostra a seção AVERAGE abaixo.
1. STRICT (Padrão)
O método STRICT é o padrão e o método de booking mais seguro. Ele impõe correspondência explícita e inequívoca.
2024-01-01 open Assets:Invest:STOCK "STRICT"- Requer Correspondência Exata de Lote: O especificador de custo do lançamento de redução (
{...}) deve identificar um único lote — por custo, por data de aquisição, por rótulo ou por qualquer combinação deles. - Erros em Correspondências Ambíguas: Se o especificador corresponder a mais de um lote, o Beancount gera um
AmbiguousMatchErrorem vez de adivinhar. - Exceção: Se uma redução remove exatamente o número total de unidades que o especificador corresponde, um especificador vazio (
{}) é permitido, e a redução é dividida entre esses lotes.
Este razão mantém dois lotes e vende um deles nomeando seu custo, o que é inequívoco:
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:GainsEle carrega sem erros, registra $300,00 de ganho em Income:Gains e deixa 10 STK {100.00 USD} na conta.
Substitua esse último lançamento por um especificador vazio e o mesmo arquivo falha:
; 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:GainsO Beancount reporta Ambiguous matches for "-10 STK {}" e lista os candidatos. Vender a posição inteira é aceitável, no entanto, porque não há nada entre o que escolher:
; 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:GainsIsso registra $800,00 de ganho — $3.000,00 de receita contra $1.000,00 + $1.200,00 de base — e deixa a conta vazia. Esta é uma propriedade do próprio STRICT, não algo para o qual você precisa mudar para STRICT_WITH_SIZE.
2. FIFO (Primeiro a Entrar, Primeiro a Sair)
O método FIFO registra automaticamente as reduções contra os lotes mais antigos disponíveis primeiro.
2024-01-01 open Assets:Invest:STOCK "FIFO"- Resolução Automática: Ele resolve a ambiguidade selecionando os lotes correspondentes mais antigos.
- Correspondência Cronológica: Você assume que está vendendo os ativos que manteve por mais tempo. Várias autoridades fiscais tratam isso como o padrão quando você não identificou um lote.
3. LIFO (Último a Entrar, Primeiro a Sair)
O método LIFO é o oposto do FIFO. Ele registra reduções contra os lotes mais recentes disponíveis primeiro.
2024-01-01 open Assets:Invest:STOCK "LIFO"- Ordem Cronológica Reversa: Ele seleciona os lotes correspondentes adquiridos mais recentemente.
- Mais recente, não mais caro: O LIFO escolhe apenas pela data de aquisição. Ele acaba vendendo as cotas de maior custo quando os preços têm subido, mas se seu lote mais recente for o mais barato — que é o que o exemplo abaixo foi construído para mostrar — o LIFO realizará o maior ganho, não o menor. O método que sempre vende as cotas mais caras é o
HIFO, descrito a seguir.
4. HIFO (Highest-In, First-Out)
O método HIFO registra reduções contra os lotes mais caros disponíveis primeiro, independentemente da data.
2024-01-01 open Assets:Invest:STOCK "HIFO"- Correspondência Classificada por Custo: Ele seleciona os lotes correspondentes com a maior base de custo.
- Menor Ganho Realizado: Para um determinado preço de venda, vender as cotas de maior custo realiza o menor ganho (ou a maior perda). Se você pode usá-lo é uma questão de jurisdição — nos Estados Unidos, por exemplo, escolher um lote exige identificação específica no momento da venda — então trate o método como um mecanismo de escrituração e confirme a eleição fiscal separadamente.
5. Comparando FIFO, LIFO e HIFO nos mesmos lotes
Os três métodos só diferem quando o lote mais antigo, o mais recente e o mais caro são três lotes diferentes. Este razão organiza exatamente isso — o lote A é o mais antigo, o lote C é o mais recente, e o lote intermediário B é o mais caro — e então vende 10 cotas de três contas que diferem apenas em seu método de booking:
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:GainsEle carrega com zero erros e registra $1.400,00 de ganho no total, divididos assim:
| Conta | Método | Lote registrado | Base de custo | Ganho realizado | Lotes restantes |
|---|---|---|---|---|---|
Assets:Broker:Fifo | FIFO | lote A, 2024-01-10 | $100.00 | $500.00 | 10 @ $120.00, 10 @ $90.00 |
Assets:Broker:Lifo | LIFO | lote C, 2024-03-10 | $90.00 | $600.00 | 10 @ $100.00, 10 @ $120.00 |
Assets:Broker:Hifo | HIFO | lote B, 2024-02-10 | $120.00 | $300.00 | 10 @ $100.00, 10 @ $90.00 |
A linha do LIFO é a que vale a pena encarar: ela realizou o maior ganho dos três, porque o lote mais recente também era o mais barato.
6. STRICT_WITH_SIZE
STRICT_WITH_SIZE é STRICT mais um desempate extra: quando vários lotes correspondem mas exatamente um deles contém precisamente o número de unidades que você está removendo, esse lote é escolhido.
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:GainsIsso registra $210,00 de ganho contra o lote de $120,00. O arquivo idêntico com "STRICT" na linha open falha com Ambiguous matches for "-7 STK {}".
7. AVERAGE (aceito, mas não implementado)
AVERAGE é um nome válido — option "booking_method" "AVERAGE" e open … "AVERAGE" ambos são analisados sintaticamente — mas o Beancount 3.2.3 não tem implementação por trás dele. Tudo aqui carrega até a venda:
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:GainsNo momento em que essa redução precisa ser registrada, o carregador para com:
AVERAGE method is not supportedNão planeje um razão em torno disso. Se você quer comportamento de custo médio hoje, mantenha a posição em uma conta NONE e calcule a média você mesmo, ou rastreie cada lote e aceite ganhos em nível de lote.
8. NONE
O método NONE desabilita completamente a correspondência de lotes.
2024-01-01 open Assets:Invest:STOCK "NONE"- Sem Correspondência de Lotes: O Beancount não tenta corresponder reduções a aumentos.
- Permite Sinais Mistos: Isso permite que uma conta mantenha saldos positivos e negativos da mesma commodity simultaneamente. Esse comportamento é semelhante à forma como a ferramenta de linha de comando Ledger lida com commodities.
Especificação de Lote
Um "lote" é um bloco específico de uma commodity adquirido em um determinado momento e preço. Quando você cria ou reduz uma posição, pode especificar seus atributos de lote em detalhes.
Especificação Completa
Ao aumentar um inventário (comprando), você pode especificar até três atributos para o lote, separados por vírgula dentro de um único par de chaves:
Assets:Invest:STOCK 10 STOCK {100.00 USD, 2024-01-15, "lot-identifier"}100.00 USD— a base de custo, expressa por unidade.2024-01-15— a data de aquisição. O Beancount a preenche a partir da data da transação quando você a omite, e é por isso que as mensagens de erro acima mostram uma data em cada lote."lot-identifier"— um rótulo de string opcional.
Embora todos os três sejam opcionais, fornecer pelo menos a base de custo é prática padrão. As chaves devem permanecer em uma linha, e comentários dentro de um razão começam com ;, nunca com #.
Métodos de Correspondência
Ao reduzir um inventário (vendendo), você usa a mesma sintaxe para especificar de qual(is) lote(s) vender.
-
Corresponder por custo: Este é o método mais comum.
Assets:Invest:STOCK -5 STOCK {100.00 USD} -
Corresponder por data: Se os custos forem idênticos, você pode desambiguar usando a data de aquisição.
Assets:Invest:STOCK -5 STOCK {2024-01-15} -
Corresponder por rótulo: Rótulos fornecem uma maneira infalível de identificar um lote.
Assets:Invest:STOCK -5 STOCK {"lot-identifier"} -
Deixar o lote para o método de booking: Um conjunto vazio de chaves
{}não nomeia nenhum lote, então o método de booking da conta escolhe. SobFIFO,LIFOouHIFOesse é o lote correspondente mais antigo, mais recente ou mais caro; sob o padrãoSTRICTé umAmbiguousMatchErrora menos que a redução esvazie os lotes correspondidos exatamente.Assets:Invest:STOCK -5 STOCK {}
Tratamento de Preço
É crucial entender a diferença entre base de custo ({}) e preço (@). Eles servem a propósitos diferentes e não são intercambiáveis.
Preço vs Custo
{cost}: Define o custo de aquisição de um ativo. É parte do próprio lote de inventário e é usado para registrar reduções e calcular ganhos de capital.@ price: Uma anotação que registra um preço de mercado no momento de uma transação. É usado para conversões de moeda ou para anotar o valor de mercado em uma data específica.
Aqui estão os três cenários:
-
Anotação de Preço (Conversão): Use
@para converter de uma moeda para outra.Assets:Forex 1000 USD @ 0.85 EUR -
Base de Custo (Aquisição): Use
{}ao comprar um ativo para estabelecer seu custo.Assets:Invest 10 STOCK {100.00 USD} -
Ambos (Venda com Registro de Preço): Ao vender um ativo, use
{}para identificar o lote sendo vendido e@para registrar o preço de venda. Isso permite o cálculo automatizado de ganhos de capital.Assets:Invest -10 STOCK {100.00 USD} @ 105.00 USDEste lançamento vende 10
STOCKdo lote que custou $100,00 cada, a um preço de venda de $105,00 cada.
Uma diretiva price autônoma fornece dados de referência para avaliação de mercado. Preços ao Vivo pode manter essas diretivas para ativos suportados em razões hospedados. Uma atualização deixa seus lotes, método de booking, custos de aquisição e receitas de venda registradas inalterados.
Regras de Uso do Preço
- Anotações de preço (
@) não afetam qual lote é registrado. A correspondência de lotes é tratada exclusivamente pela base de custo ({}) e pelo método de booking da conta. - O símbolo
@é usado apenas para:
- Conversões de moeda.
- Registrar o valor de mercado de um ativo no momento de uma transação.
- Fornecer o preço de venda para cálculos de ganhos de capital.
Configuração
Você pode configurar métodos de booking globalmente ou por conta.
Método Global de Registro
Você pode definir um método de booking padrão para todo o seu arquivo Beancount usando a diretiva option.
option "booking_method" "STRICT"Os valores aceitos são "STRICT" (o padrão quando você não define nada), "STRICT_WITH_SIZE", "NONE", "FIFO", "LIFO", "HIFO" e "AVERAGE". Qualquer outra string é rejeitada no momento do carregamento com Error for option 'booking_method'. "AVERAGE" é aceito aqui e em open, mas registrar uma redução sob ele falha, como mostra a seção AVERAGE acima.
Substituição por Conta
Frequentemente é útil ter métodos diferentes para contas diferentes. Por exemplo, você pode querer FIFO para uma conta de aposentadoria mas STRICT para uma conta de corretagem tributável para garantir que você está vendendo lotes fiscais específicos. Você pode definir o método de booking quando abre a conta.
2024-01-01 open Assets:Retirement:401K "FIFO"
2024-01-01 open Assets:Taxable:Stock "STRICT"Melhores Práticas
-
Organização de Inventário: Para manter seu razão limpo e simples, é altamente recomendável usar contas separadas para cada commodity única que você mantém, e restringir cada uma a essa commodity em sua diretiva
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 VFIAXEvite misturar diferentes ações ou fundos na mesma conta, pois isso complica o gerenciamento de inventário. A lista de commodities em
openfaz o Beancount rejeitar um lançamento perdido em vez de misturar silenciosamente dois inventários. -
Gerenciamento de Lotes:
-
Use rótulos significativos para lotes, especialmente para transações específicas como colheita de prejuízos fiscais ou concessões de ações de funcionários.
Assets:Invest:STOCK 10 STOCK {100.00 USD, "tax-loss-harvest-2024"} -
Documente suas negociações com comentários. Isso torna seu razão mais fácil de ler e entender mais tarde.
Assets:Invest:STOCK -10 STOCK {100.00 USD} @ 110.00 USD ; Gain: 10%
- Depuração: Se você encontrar erros ou comportamento inesperado, o Beancount fornece ferramentas para inspecionar o estado do seu inventário.
-
Examinar o Estado do Inventário: Use
bea doctor context main.beancount 42para inspecionar a transação na linha 42, incluindo seus lançamentos e os saldos das contas afetadas. Substitua o nome do arquivo e o número da linha pela transação que você quer inspecionar.Substitua
<LINENO>pelo número da linha logo após uma transação para ver seu efeito. -
Verificar Correspondência de Lotes: A ferramenta
bea checkvalida todo o seu arquivo. Ela capturará quaisquer erros de booking, como correspondências ambíguas de lotes no modoSTRICT.