Salta al contenuto principale

Lotti, base di costo e metodi di booking in Beancount

Come Beancount registra i lotti quando vendi azioni o valute: base di costo, specifiche di lotto, booking STRICT, FIFO, LIFO e HIFO, prezzo vs costo, override per conto.

Il sistema di inventario di Beancount è una funzionalità potente per monitorare le attività che vengono acquistate e vendute nel tempo, come azioni, fondi comuni o valute estere. Consente un monitoraggio preciso della base di costo, essenziale per calcolare le plusvalenze e comprendere la performance del portafoglio. Questo tutorial copre i meccanismi fondamentali della gestione degli inventari nel tuo ledger.

Concetti Fondamentali​

Nel suo nucleo, la gestione dell'inventario ruota attorno al monitoraggio delle posizioni. Una "posizione" è semplicemente una quantità di una commodity detenuta in un conto. Beancount distingue tra due tipi fondamentali di posizioni.

Tipi di Posizione​

  1. Posizione semplice (senza costo): Si tratta di una registrazione di saldo standard. Rappresenta una quantità di una commodity senza alcun costo di acquisizione associato. È adatta per la liquidità o per semplici asserzioni di saldo.

    Assets:Bank:Checking      100.00 USD
  2. Posizione con base di costo: Questo tipo di posizione include non solo il numero di unità e la commodity, ma anche il costo al quale è stata acquisita. Questa è la base del monitoraggio dell'inventario. Il costo è specificato all'interno delle parentesi graffe {}.

    Assets:Invest:VTSAX      10 VTSAX {100.00 USD, "lot-1"}

    In questo esempio, deteniamo 10 unità di VTSAX. Ogni unità è stata acquisita a un costo di 100,00 USD. Questo specifico blocco di quote è identificato come un "lotto".

Operazioni sull'Inventario​

Ci sono due operazioni principali che puoi eseguire su un inventario:

  1. Aumenti (aggiunta all'inventario): Quando acquisti una commodity, aumenti il tuo inventario. Crei un nuovo lotto con un numero specifico di unità e una base di costo.

    2024-01-15 * "Buy shares"
      Assets:Invest:STOCK     50 STOCK {25.00 USD, "lot-1"}
      Assets:Bank:Checking   -1250.00 USD

    Qui acquistiamo 50 unità di STOCK a un costo per unità di 25,00 USD. Questo crea un lotto nel conto Assets:Invest:STOCK.

  2. Riduzioni (rimozione dall'inventario): Quando vendi una commodity, riduci il tuo inventario. Devi specificare da quale lotto stai vendendo. Questo si fa fornendo le informazioni corrispondenti all'interno delle parentesi graffe.

    2024-01-20 * "Sell shares"
      Assets:Invest:STOCK    -25 STOCK {25.00 USD}
      Assets:Bank:Checking    625.00 USD

    In questa transazione, stiamo vendendo 25 unità di STOCK dal lotto che è stato acquistato a 25,00 USD per unità.

Metodi di Registrazione​

Quando riduci un inventario, Beancount necessita di una regola per decidere da quale lotto specifico attingere se diversi lotti corrispondono alla riduzione. Questa regola è chiamata "metodo di prenotazione". Puoi impostare un valore predefinito per l'intero file con un'opzione, oppure assegnare a un conto il proprio metodo nella direttiva open.

Beancount 3.2.3 accetta sette nomi di metodo: STRICT (il valore predefinito), STRICT_WITH_SIZE, NONE, FIFO, LIFO, HIFO e AVERAGE. Sei di essi sono implementati; AVERAGE viene analizzato ma genera un errore nel momento in cui deve prenotare una riduzione, come mostra la sezione AVERAGE di seguito.

1. STRICT (Predefinito)​

Il metodo STRICT è il valore predefinito e il metodo di prenotazione più sicuro. Impone una corrispondenza esplicita e non ambigua.

2024-01-01 open Assets:Invest:STOCK "STRICT"
  • Richiede una corrispondenza esatta del lotto: Lo specificatore di costo della registrazione di riduzione ({...}) deve identificare un singolo lotto — per costo, per data di acquisizione, per etichetta o per qualsiasi combinazione di essi.
  • Errore in caso di corrispondenze ambigue: Se lo specificatore corrisponde a più di un lotto, Beancount genera un AmbiguousMatchError invece di indovinare.
  • Eccezione: Se una riduzione rimuove esattamente il numero totale di unità a cui corrisponde lo specificatore, è consentito uno specificatore vuoto ({}) e la riduzione viene suddivisa tra quei lotti.

Questo ledger contiene due lotti e ne vende uno indicandone il costo, che è inequivocabile:

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

Si carica senza errori, prenota 300,00 $ di plusvalenza su Income:Gains e lascia 10 STK {100.00 USD} nel conto.

Sostituisci quest'ultima registrazione con uno specificatore vuoto e lo stesso file fallisce:

; 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:Gains

Beancount segnala Ambiguous matches for "-10 STK {}" ed elenca i candidati. Vendere l'intera posizione va bene, però, perché non resta nulla tra cui scegliere:

; 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

Questo prenota 800,00 $ di plusvalenza — 3.000,00 $ di proventi contro 1.000,00 $ + 1.200,00 $ di base — e lascia il conto vuoto. Questa è una proprietà di STRICT stesso, non qualcosa per cui devi passare a STRICT_WITH_SIZE.

2. FIFO (First-In, First-Out)​

Il metodo FIFO prenota automaticamente le riduzioni sui lotti disponibili più vecchi per primi.

2024-01-01 open Assets:Invest:STOCK "FIFO"
  • Risoluzione automatica: Risolve l'ambiguità selezionando i lotti corrispondenti più vecchi.
  • Corrispondenza cronologica: Si presume che tu stia vendendo le attività che hai detenuto più a lungo. Diverse autorità fiscali lo considerano il valore predefinito quando non hai identificato un lotto.

3. LIFO (Last-In, First-Out)​

Il metodo LIFO è l'opposto di FIFO. Prenota le riduzioni sui lotti disponibili più recenti per primi.

2024-01-01 open Assets:Invest:STOCK "LIFO"
  • Ordine cronologico inverso: Seleziona i lotti corrispondenti acquisiti più di recente.
  • Più recente, non più costoso: LIFO seleziona solo in base alla data di acquisizione. Capita di vendere le quote a costo più alto quando i prezzi sono aumentati, ma se il tuo lotto più recente è anche il più economico — che è ciò che l'esempio seguente è costruito per mostrare — LIFO realizzerà la plusvalenza maggiore, non la minore. Il metodo che vende sempre le quote più costose è HIFO, descritto di seguito.

4. HIFO (Highest-In, First-Out)​

Il metodo HIFO prenota le riduzioni sui lotti disponibili più costosi per primi, indipendentemente dalla loro data.

2024-01-01 open Assets:Invest:STOCK "HIFO"
  • Corrispondenza ordinata per costo: Seleziona i lotti corrispondenti con la base di costo più alta.
  • Plusvalenza realizzata più piccola: Per un dato prezzo di vendita, vendere le quote a costo più alto realizza la plusvalenza più piccola (o la perdita più grande). Se puoi usarlo è una questione di giurisdizione — negli Stati Uniti, ad esempio, scegliere un lotto richiede comunque un'identificazione specifica al momento della vendita — quindi considera il metodo come un meccanismo contabile e conferma separatamente l'elezione fiscale.

5. Confronto tra FIFO, LIFO e HIFO sugli stessi lotti​

I tre metodi differiscono solo quando il lotto più vecchio, il più recente e il più costoso sono tre lotti diversi. Questo ledger organizza esattamente questa situazione — il lotto A è il più vecchio, il lotto C è il più recente e il lotto intermedio B è il più costoso — e poi vende 10 quote da tre conti che differiscono solo per il loro metodo di prenotazione:

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

Si carica senza errori e prenota 1.400,00 $ di plusvalenza in totale, suddivisa così:

ContoMetodoLotto prenotatoBase di costoPlusvalenza realizzataLotti rimanenti
Assets:Broker:FifoFIFOlotto A, 2024-01-10100,00 $500,00 $10 @ 120,00 $, 10 @ 90,00 $
Assets:Broker:LifoLIFOlotto C, 2024-03-1090,00 $600,00 $10 @ 100,00 $, 10 @ 120,00 $
Assets:Broker:HifoHIFOlotto B, 2024-02-10120,00 $300,00 $10 @ 100,00 $, 10 @ 90,00 $

La riga LIFO è quella su cui vale la pena soffermarsi: ha realizzato la plusvalenza più grande delle tre, perché il lotto più recente era anche il più economico.

6. STRICT_WITH_SIZE​

STRICT_WITH_SIZE è STRICT più un ulteriore criterio di risoluzione: quando diversi lotti corrispondono ma esattamente uno di essi contiene precisamente il numero di unità che stai rimuovendo, viene scelto quel lotto.

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

Questo prenota 210,00 $ di plusvalenza sul lotto da 120,00 $. Il file identico con "STRICT" sulla riga open fallisce con Ambiguous matches for "-7 STK {}".

7. AVERAGE (accettato, ma non implementato)​

AVERAGE è un nome valido — sia option "booking_method" "AVERAGE" che open … "AVERAGE" vengono analizzati — ma Beancount 3.2.3 non ha alcuna implementazione dietro di esso. Tutto qui si carica fino alla vendita:

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

Nel momento in cui quella riduzione deve essere prenotata, il caricatore si ferma con:

AVERAGE method is not supported

Non pianificare un ledger attorno ad esso. Se desideri un comportamento a costo medio oggi, mantieni la posizione in un conto NONE e calcola tu stesso la media, oppure monitora ogni lotto e accetta le plusvalenze a livello di lotto.

8. NONE​

Il metodo NONE disabilita completamente la corrispondenza dei lotti.

2024-01-01 open Assets:Invest:STOCK "NONE"
  • Nessuna corrispondenza dei lotti: Beancount non tenta di far corrispondere le riduzioni agli aumenti.
  • Consente segni misti: Questo permette a un conto di detenere simultaneamente saldi sia positivi che negativi della stessa commodity. Questo comportamento è simile a come lo strumento CLI Ledger gestisce le commodity.

Specifica del lotto​

Un "lotto" è un blocco specifico di una commodity acquisito in un particolare momento e a un particolare prezzo. Quando crei o riduci una posizione, puoi specificare i suoi attributi di lotto in dettaglio.

Specifica completa​

Quando aumenti un inventario (acquisto), puoi specificare fino a tre attributi per il lotto, separati da virgole all'interno di una singola coppia di parentesi graffe:

Assets:Invest:STOCK  10 STOCK {100.00 USD, 2024-01-15, "lot-identifier"}
  • 100.00 USD — la base di costo, espressa per unità.
  • 2024-01-15 — la data di acquisizione. Beancount la inserisce dalla data della transazione quando la ometti, motivo per cui i messaggi di errore sopra mostrano una data su ogni lotto.
  • "lot-identifier" — un'etichetta stringa opzionale.

Sebbene tutti e tre siano opzionali, fornire almeno la base di costo è una pratica standard. Le parentesi graffe devono rimanere su una riga e i commenti all'interno di un ledger iniziano con ;, mai con #.

Metodi di abbinamento​

Quando riduci un inventario (vendita), usi la stessa sintassi per specificare da quale lotto (o lotti) vendere.

  • Corrispondenza per costo: Questo è il metodo più comune.

    Assets:Invest:STOCK  -5 STOCK {100.00 USD}
  • Corrispondenza per data: Se i costi sono identici, puoi disambiguare usando la data di acquisizione.

    Assets:Invest:STOCK  -5 STOCK {2024-01-15}
  • Corrispondenza per etichetta: Le etichette forniscono un modo infallibile per identificare un lotto.

    Assets:Invest:STOCK  -5 STOCK {"lot-identifier"}
  • Lasciare il lotto al metodo di prenotazione: Un insieme vuoto di parentesi graffe {} non nomina alcun lotto, quindi è il metodo di prenotazione del conto a scegliere. Sotto FIFO, LIFO o HIFO è il lotto corrispondente più vecchio, più recente o più costoso; sotto il predefinito STRICT è un AmbiguousMatchError a meno che la riduzione non esaurisca esattamente i lotti corrispondenti.

    Assets:Invest:STOCK  -5 STOCK {}

Gestione dei prezzi​

È cruciale comprendere la differenza tra base di costo ({}) e prezzo (@). Servono a scopi diversi e non sono intercambiabili.

Prezzo vs Costo​

  • {cost}: Definisce il costo di acquisizione di un'attività. Fa parte del lotto di inventario stesso ed è utilizzato per prenotare le riduzioni e calcolare le plusvalenze.
  • @ price: Un'annotazione che registra un prezzo di mercato al momento di una transazione. È utilizzato per conversioni valutarie o per annotare il valore di mercato in una data particolare.

Ecco i tre scenari:

  1. Annotazione del prezzo (conversione): Usa @ per convertire da una valuta a un'altra.

    Assets:Forex     1000 USD @ 0.85 EUR
  2. Base di costo (acquisizione): Usa {} quando acquisti un'attività per stabilirne il costo.

    Assets:Invest    10 STOCK {100.00 USD}
  3. Entrambi (vendita con registrazione del prezzo): Quando vendi un'attività, usa {} per identificare il lotto in vendita e @ per registrare il prezzo di vendita. Questo consente il calcolo automatizzato delle plusvalenze.

    Assets:Invest    -10 STOCK {100.00 USD} @ 105.00 USD

    Questa registrazione vende 10 STOCK dal lotto che è costato 100,00 $ ciascuno, a un prezzo di vendita di 105,00 $ ciascuno.

Una direttiva price autonoma fornisce dati di riferimento per la valutazione di mercato. I Prezzi in tempo reale possono mantenere queste direttive per le attività supportate nei ledger ospitati. Un aggiornamento lascia invariati i tuoi lotti, il metodo di prenotazione, i costi di acquisizione e i proventi di vendita registrati.

Regole per l'Uso del Prezzo​

  1. Le annotazioni di prezzo (@) non influenzano quale lotto viene prenotato. La corrispondenza dei lotti è gestita esclusivamente dalla base di costo ({}) e dal metodo di prenotazione del conto.
  2. Il simbolo @ è utilizzato solo per:
  • Conversioni valutarie.
  • Registrare il valore di mercato di un'attività al momento di una transazione.
  • Fornire il prezzo di vendita per i calcoli delle plusvalenze.

Configurazione​

Puoi configurare i metodi di prenotazione a livello globale o per singolo conto.

Metodo di Registrazione Globale​

Puoi impostare un metodo di prenotazione predefinito per l'intero file Beancount usando la direttiva option.

option "booking_method" "STRICT"

I valori accettati sono "STRICT" (il valore predefinito quando non imposti nulla), "STRICT_WITH_SIZE", "NONE", "FIFO", "LIFO", "HIFO" e "AVERAGE". Qualsiasi altra stringa viene rifiutata al momento del caricamento con Error for option 'booking_method'. "AVERAGE" è accettato qui e su open, ma prenotare una riduzione sotto di esso fallisce, come mostra la sezione AVERAGE sopra.

Override per Account​

Spesso è utile avere metodi diversi per conti diversi. Ad esempio, potresti voler usare FIFO per un conto pensionistico ma STRICT per un conto di intermediazione imponibile per assicurarti di vendere lotti fiscali specifici. Puoi impostare il metodo di prenotazione quando apri il conto.

2024-01-01 open Assets:Retirement:401K "FIFO"
2024-01-01 open Assets:Taxable:Stock  "STRICT"

Migliori Pratiche​

  1. Organizzazione dell'inventario: Per mantenere il tuo ledger pulito e semplice, è altamente raccomandato usare conti separati per ogni commodity unica che detieni e vincolare ciascuno a quella commodity nella sua direttiva 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

    Evita di mescolare azioni o fondi diversi nello stesso conto, poiché complica la gestione dell'inventario. L'elenco delle commodity su open fa sì che Beancount rifiuti una registrazione estranea invece di mescolare silenziosamente due inventari.

  2. Gestione dei lotti:

  • Usa etichette significative per i lotti, specialmente per transazioni specifiche come la compensazione delle minusvalenze o le assegnazioni di azioni ai dipendenti.

    Assets:Invest:STOCK  10 STOCK {100.00 USD, "tax-loss-harvest-2024"}
  • Documenta le tue operazioni con commenti. Questo rende il tuo ledger più facile da leggere e comprendere in seguito.

    Assets:Invest:STOCK  -10 STOCK {100.00 USD} @ 110.00 USD ; Gain: 10%
  1. Debug: Se incontri errori o comportamenti imprevisti, Beancount fornisce strumenti per ispezionare lo stato del tuo inventario.
  • Esaminare lo stato dell'inventario: Usa bea doctor context main.beancount 42 per ispezionare la transazione alla riga 42, incluse le sue registrazioni e i saldi dei conti interessati. Sostituisci il nome del file e il numero di riga con la transazione che vuoi ispezionare.

    Sostituisci <LINENO> con il numero di riga subito dopo una transazione per vederne l'effetto.

  • Verificare la corrispondenza dei lotti: Lo strumento bea check convalida l'intero file. Catturerà eventuali errori di prenotazione, come corrispondenze ambigue di lotti in modalità STRICT.

Fonte: https://beancount.io/it/docs/Basics/inventories