Beancounts voorraadsysteem is een krachtige functie voor het volgen van activa die in de loop van de tijd worden gekocht en verkocht, zoals aandelen, beleggingsfondsen of vreemde valuta's. Het maakt nauwkeurige tracking van de kostprijs mogelijk, wat essentieel is voor het berekenen van vermogenswinsten en het begrijpen van portefeuilleprestaties. Deze tutorial behandelt de kernmechanismen van het beheren van voorraden in je grootboek.
Kernbegrippen
In essentie draait voorraadbeheer om het volgen van posities. Een "positie" is simpelweg een hoeveelheid van een commodity die in een rekening wordt aangehouden. Beancount onderscheidt twee fundamentele soorten posities.
Positietypen
-
Eenvoudige positie (geen kostprijs): Dit is een standaard balansboeking. Het vertegenwoordigt een hoeveelheid van een commodity zonder enige bijbehorende aanschafkosten. Het is geschikt voor contant geld of eenvoudige balansasserties.
Assets:Bank:Checking 100.00 USD -
Positie met kostprijs: Dit type positie bevat niet alleen het aantal eenheden en de commodity, maar ook de kostprijs waartegen deze is verworven. Dit is de basis van voorraadtracking. De kostprijs wordt gespecificeerd binnen accolades
{}.Assets:Invest:VTSAX 10 VTSAX {100.00 USD, "lot-1"}In dit voorbeeld houden we 10 eenheden van
VTSAXaan. Elke eenheid is verworven tegen een kostprijs van $100,00 USD. Deze specifieke batch aandelen wordt geïdentificeerd als een "lot".
Voorraadbewerkingen
Er zijn twee primaire bewerkingen die je op een voorraad kunt uitvoeren:
-
Augmentaties (toevoegen aan voorraad): Wanneer je een commodity koopt, vul je je voorraad aan. Je creëert een nieuw lot met een specifiek aantal eenheden en een kostprijs.
2024-01-15 * "Buy shares" Assets:Invest:STOCK 50 STOCK {25.00 USD, "lot-1"} Assets:Bank:Checking -1250.00 USDHier kopen we 50 eenheden van
STOCKtegen een kostprijs van $25,00 USD per eenheid. Dit creëert een lot in de rekeningAssets:Invest:STOCK. -
Reducties (verwijderen uit voorraad): Wanneer je een commodity verkoopt, verminder je je voorraad. Je moet specificeren uit welk lot je verkoopt. Dit doe je door overeenkomende informatie in de accolades op te geven.
2024-01-20 * "Sell shares" Assets:Invest:STOCK -25 STOCK {25.00 USD} Assets:Bank:Checking 625.00 USDIn deze transactie verkopen we 25 eenheden van
STOCKuit het lot dat is gekocht tegen $25,00 USD per eenheid.
Boekingmethoden
Wanneer je een voorraad reduceert, heeft Beancount een regel nodig om te beslissen uit welk specifiek lot te putten als meerdere loten overeenkomen met de reductie. Deze regel wordt de "bookingsmethode" genoemd. Je kunt een standaard instellen voor het hele bestand met een optie, of één rekening zijn eigen methode geven op de open-richtlijn.
Beancount 3.2.3 accepteert zeven methodenamen: STRICT (de standaard), STRICT_WITH_SIZE, NONE, FIFO, LIFO, HIFO en AVERAGE. Zes ervan zijn geïmplementeerd; AVERAGE wordt geparseerd maar geeft een fout op het moment dat het een reductie moet boeken, zoals de sectie AVERAGE hieronder laat zien.
1. STRICT (Standaard)
De STRICT-methode is de standaard en de veiligste bookingsmethode. Het dwingt expliciete en ondubbelzinnige matching af.
2024-01-01 open Assets:Invest:STOCK "STRICT"- Vereist exacte lotovereenkomst: De kostenspecificatie van de reductieboeking (
{...}) moet één enkel lot identificeren — op kostprijs, op aanschafdatum, op label, of op een combinatie daarvan. - Fouten bij dubbelzinnige overeenkomsten: Als de specificatie overeenkomt met meer dan één lot, geeft Beancount een
AmbiguousMatchErrorin plaats van te gokken. - Uitzondering: Als een reductie precies het totale aantal eenheden verwijdert dat de specificatie matcht, is een lege specificatie (
{}) toegestaan, en de reductie wordt verdeeld over die loten.
Dit grootboek bevat twee loten en verkoopt er één door de kostprijs te benoemen, wat ondubbelzinnig is:
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:GainsHet laadt zonder fouten, boekt $300,00 winst naar Income:Gains, en laat 10 STK {100.00 USD} in de rekening achter.
Vervang die laatste boeking door een lege specificatie en hetzelfde bestand faalt:
; 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:GainsBeancount rapporteert Ambiguous matches for "-10 STK {}" en somt de kandidaten op. De hele positie verkopen is echter prima, omdat er niets meer te kiezen valt:
; 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:GainsDat boekt $800,00 winst — $3.000,00 opbrengst tegen $1.000,00 + $1.200,00 kostprijs — en laat de rekening leeg achter. Dit is een eigenschap van STRICT zelf, niet iets waarvoor je naar STRICT_WITH_SIZE moet overschakelen.
2. FIFO (First-In, First-Out)
De FIFO-methode boekt reducties automatisch tegen de oudste beschikbare loten eerst.
2024-01-01 open Assets:Invest:STOCK "FIFO"- Automatische resolutie: Het lost dubbelzinnigheid op door de oudste overeenkomende loten te selecteren.
- Chronologische matching: Je gaat ervan uit dat je de activa verkoopt die je het langst hebt aangehouden. Verschillende belastingautoriteiten behandelen dit als de standaard wanneer je geen lot hebt geïdentificeerd.
3. LIFO (Last-In, First-Out)
De LIFO-methode is het tegenovergestelde van FIFO. Het boekt reducties tegen de nieuwste beschikbare loten eerst.
2024-01-01 open Assets:Invest:STOCK "LIFO"- Omgekeerde chronologische volgorde: Het selecteert de meest recent verworven overeenkomende loten.
- Nieuwste, niet duurste: LIFO kiest alleen op basis van aanschafdatum. Het verkoopt toevallig de aandelen met de hoogste kostprijs wanneer de prijzen zijn gestegen, maar als je nieuwste lot je goedkoopste is — wat het onderstaande voorbeeld wil aantonen — realiseert LIFO de grootste winst, niet de kleinste. De methode die altijd de duurste aandelen verkoopt is
HIFO, hierna beschreven.
4. HIFO (Highest-In, First-Out)
De HIFO-methode boekt reducties tegen de duurste beschikbare loten eerst, ongeacht hun datum.
2024-01-01 open Assets:Invest:STOCK "HIFO"- Op kostprijs gerangschikte matching: Het selecteert de overeenkomende loten met de hoogste kostprijs.
- Kleinste gerealiseerde winst: Voor een gegeven verkoopprijs realiseert het verkopen van de aandelen met de hoogste kostprijs de kleinste winst (of het grootste verlies). Of je het mag gebruiken is een jurisdictievraag — in de Verenigde Staten bijvoorbeeld vereist het kiezen van een lot überhaupt specifieke identificatie op het moment van verkoop — dus behandel de methode als een boekhoudmechanisme en bevestig de belastingkeuze afzonderlijk.
5. Vergelijking van FIFO, LIFO en HIFO op dezelfde lots
De drie methoden verschillen alleen wanneer het oudste, het nieuwste en het duurste lot drie verschillende loten zijn. Dit grootboek regelt precies dat — lot A is het oudste, lot C is het nieuwste, en het middelste lot B is het duurste — en verkoopt vervolgens 10 aandelen uit drie rekeningen die alleen in hun bookingsmethode verschillen:
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:GainsHet laadt met nul fouten en boekt in totaal $1.400,00 winst, als volgt verdeeld:
| Rekening | Methode | Geboekt lot | Kostprijs | Gerealiseerde winst | Resterende loten |
|---|---|---|---|---|---|
Assets:Broker:Fifo | FIFO | lot A, 2024-01-10 | $100,00 | $500,00 | 10 @ $120,00, 10 @ $90,00 |
Assets:Broker:Lifo | LIFO | lot C, 2024-03-10 | $90,00 | $600,00 | 10 @ $100,00, 10 @ $120,00 |
Assets:Broker:Hifo | HIFO | lot B, 2024-02-10 | $120,00 | $300,00 | 10 @ $100,00, 10 @ $90,00 |
De LIFO-rij is het bekijken waard: het realiseerde de grootste winst van de drie, omdat het nieuwste lot ook het goedkoopste was.
6. STRICT_WITH_SIZE
STRICT_WITH_SIZE is STRICT plus één extra tie-breaker: wanneer meerdere loten overeenkomen maar precies één ervan precies het aantal eenheden bevat dat je verwijdert, wordt dat lot gekozen.
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:GainsDat boekt $210,00 winst tegen het lot van $120,00. Het identieke bestand met "STRICT" op de open-regel faalt met Ambiguous matches for "-7 STK {}".
7. GEMIDDELDE (geaccepteerd, maar niet geïmplementeerd)
AVERAGE is een geldige naam — option "booking_method" "AVERAGE" en open … "AVERAGE" worden beide geparseerd — maar Beancount 3.2.3 heeft er geen implementatie achter. Alles hier laadt tot de verkoop:
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:GainsOp het moment dat die reductie geboekt moet worden, stopt de loader met:
AVERAGE method is not supportedPlan hier geen grootboek omheen. Als je vandaag gemiddelde-kostprijsgedrag wilt, houd de positie dan in een NONE-rekening en bereken het gemiddelde zelf, of volg elk lot en accepteer winsten op lotniveau.
8. GEEN
De NONE-methode schakelt lotmatching volledig uit.
2024-01-01 open Assets:Invest:STOCK "NONE"- Geen lotmatching: Beancount probeert reducties niet aan augmentaties te koppelen.
- Staat gemengde tekens toe: Dit staat een rekening toe om zowel positieve als negatieve saldi van dezelfde commodity tegelijkertijd aan te houden. Dit gedrag is vergelijkbaar met hoe de Ledger CLI-tool commodities behandelt.
Lotspecificatie
Een "lot" is een specifiek blok van een commodity dat op een bepaald tijdstip en tegen een bepaalde prijs is verworven. Wanneer je een positie creëert of reduceert, kun je de lotattributen in detail specificeren.
Volledige specificatie
Bij het augmenteren van een voorraad (kopen), kun je tot drie attributen voor het lot specificeren, kommagescheiden binnen één paar accolades:
Assets:Invest:STOCK 10 STOCK {100.00 USD, 2024-01-15, "lot-identifier"}100.00 USD— de kostprijs, uitgedrukt per eenheid.2024-01-15— de aanschafdatum. Beancount vult deze in vanuit de transactiedatum wanneer je die weglaat, wat de reden is dat de bovenstaande foutmeldingen een datum bij elk lot tonen."lot-identifier"— een optioneel tekenreekslabel.
Hoewel alle drie optioneel zijn, is het opgeven van ten minste de kostprijs standaardpraktijk. De accolades moeten op één regel blijven, en opmerkingen in een grootboek beginnen met ;, nooit met #.
Matchingsmethoden
Bij het reduceren van een voorraad (verkopen), gebruik je dezelfde syntaxis om te specificeren uit welk(e) lot(en) je verkoopt.
-
Matchen op kostprijs: Dit is de meest gebruikte methode.
Assets:Invest:STOCK -5 STOCK {100.00 USD} -
Matchen op datum: Als de kostprijzen identiek zijn, kun je onderscheiden met behulp van de aanschafdatum.
Assets:Invest:STOCK -5 STOCK {2024-01-15} -
Matchen op label: Labels bieden een waterdichte manier om een lot te identificeren.
Assets:Invest:STOCK -5 STOCK {"lot-identifier"} -
Het lot overlaten aan de bookingsmethode: Een lege set accolades
{}benoemt geen lot, dus de bookingsmethode van de rekening kiest. OnderFIFO,LIFOofHIFOis dat het oudste, nieuwste of duurste overeenkomende lot; onder de standaardSTRICTis het eenAmbiguousMatchError, tenzij de reductie de overeenkomende loten precies leegmaakt.Assets:Invest:STOCK -5 STOCK {}
Prijsverwerking
Het is cruciaal om het verschil te begrijpen tussen kostprijs ({}) en prijs (@). Ze dienen verschillende doelen en zijn niet uitwisselbaar.
Prijs vs Kosten
{cost}: Definieert de aanschafkosten van een actief. Het maakt deel uit van het voorraadlot zelf en wordt gebruikt voor het boeken van reducties en het berekenen van vermogenswinsten.@ price: Een annotatie die een marktprijs vastlegt op het moment van een transactie. Het wordt gebruikt voor valutaconversies of om de marktwaarde op een bepaalde datum te noteren.
Hier zijn de drie scenario's:
-
Prijsannotatie (conversie): Gebruik
@om van de ene valuta naar de andere te converteren.Assets:Forex 1000 USD @ 0.85 EUR -
Kostprijs (aanschaf): Gebruik
{}bij het kopen van een actief om de kostprijs vast te stellen.Assets:Invest 10 STOCK {100.00 USD} -
Beide (verkoop met prijsregistratie): Gebruik bij het verkopen van een actief
{}om het verkochte lot te identificeren en@om de verkoopprijs vast te leggen. Dit maakt geautomatiseerde berekening van vermogenswinsten mogelijk.Assets:Invest -10 STOCK {100.00 USD} @ 105.00 USDDeze boeking verkoopt 10
STOCKuit het lot dat $100,00 per stuk kostte, tegen een verkoopprijs van $105,00 per stuk.
Een op zichzelf staande price-richtlijn levert referentiegegevens voor marktwaardering. Live prijzen kunnen deze richtlijnen onderhouden voor ondersteunde activa in gehoste grootboeken. Een verversing laat je loten, bookingsmethode, aanschafkosten en vastgelegde verkoopopbrengsten onveranderd.
Regels voor Prijsgebruik
- Prijsannotaties (
@) beïnvloeden niet welk lot wordt geboekt. Lotmatching wordt uitsluitend afgehandeld door de kostprijs ({}) en de bookingsmethode van de rekening. - Het
@-symbool wordt alleen gebruikt voor:
- Valutaconversies.
- Het vastleggen van de marktwaarde van een actief op het moment van een transactie.
- Het leveren van de verkoopprijs voor berekeningen van vermogenswinsten.
Configuratie
Je kunt bookingsmethoden globaal of per rekening configureren.
Globale Boekingswijze
Je kunt een standaard bookingsmethode voor je hele Beancount-bestand instellen met de option-richtlijn.
option "booking_method" "STRICT"De geaccepteerde waarden zijn "STRICT" (de standaard wanneer je niets instelt), "STRICT_WITH_SIZE", "NONE", "FIFO", "LIFO", "HIFO" en "AVERAGE". Elke andere tekenreeks wordt bij het laden afgewezen met Error for option 'booking_method'. "AVERAGE" wordt hier en op open geaccepteerd, maar het boeken van een reductie ermee faalt, zoals de sectie AVERAGE hierboven laat zien.
Per-Rekening Override
Het is vaak nuttig om verschillende methoden voor verschillende rekeningen te hebben. Je wilt bijvoorbeeld FIFO voor een pensioenrekening maar STRICT voor een belastbare brokerage-rekening om er zeker van te zijn dat je specifieke belastingloten verkoopt. Je kunt de bookingsmethode instellen wanneer je de rekening opent.
2024-01-01 open Assets:Retirement:401K "FIFO"
2024-01-01 open Assets:Taxable:Stock "STRICT"Best Practices
-
Voorraadorganisatie: Om je grootboek schoon en eenvoudig te houden, is het sterk aanbevolen om aparte rekeningen te gebruiken voor elke unieke commodity die je aanhoudt, en elke rekening te beperken tot die commodity op de
open-richtlijn.; GOOD: separate accounts by commodity, each constrained to one 2024-01-01 open Assets:Invest:VTSAX VTSAX 2024-01-01 open Assets:Invest:VFIAX VFIAXVermijd het mixen van verschillende aandelen of fondsen in dezelfde rekening, omdat dit voorraadbeheer bemoeilijkt. De commoditylijst op
openzorgt ervoor dat Beancount een verdwaalde boeking afwijst in plaats van stilzwijgend twee voorraden te mixen. -
Lotbeheer:
-
Gebruik betekenisvolle labels voor loten, vooral voor specifieke transacties zoals tax-loss harvesting of aandelenbonussen van werknemers.
Assets:Invest:STOCK 10 STOCK {100.00 USD, "tax-loss-harvest-2024"} -
Documenteer je transacties met opmerkingen. Dit maakt je grootboek later gemakkelijker te lezen en te begrijpen.
Assets:Invest:STOCK -10 STOCK {100.00 USD} @ 110.00 USD ; Gain: 10%
- Debuggen: Als je fouten of onverwacht gedrag tegenkomt, biedt Beancount tools om de status van je voorraad te inspecteren.
-
Voorraadstatus onderzoeken: Gebruik
bea doctor context main.beancount 42om de transactie op regel 42 te inspecteren, inclusief de boekingen en de betrokken rekeningsaldi. Vervang de bestandsnaam en het regelnummer door de transactie die je wilt inspecteren.Vervang
<LINENO>door het regelnummer direct na een transactie om het effect ervan te zien. -
Lotmatching verifiëren: De
bea check-tool valideert je hele bestand. Het zal eventuele boekingsfouten opsporen, zoals dubbelzinnige lotovereenkomsten inSTRICT-modus.