El sistema de inventario de Beancount es una función poderosa para rastrear activos que se compran y venden con el tiempo, como acciones, fondos mutuos o monedas extranjeras. Permite un seguimiento preciso del costo base, que es esencial para calcular las ganancias de capital y entender el rendimiento de la cartera. Este tutorial cubre los conceptos fundamentales de la gestión de inventarios en su libro mayor.
Conceptos Básicos
En su esencia, la gestión de inventario gira en torno al seguimiento de posiciones. Una "posición" es simplemente una cantidad de una mercancía mantenida en una cuenta. Beancount distingue entre dos tipos fundamentales de posiciones.
Tipos de Posición
-
Posición Simple (Sin Costo): Esta es una contabilidad estándar de saldo. Representa una cantidad de una mercancía sin ningún costo de adquisición asociado. Es adecuada para efectivo o afirmaciones de saldo simples.
Assets:Bank:Checking 100.00 USD -
Posición con Costo Base: Este tipo de posición incluye no solo el número de unidades y la mercancía, sino también el costo al que fue adquirida. Esta es la base del seguimiento de inventarios. El costo se especifica dentro de llaves
{}.Assets:Invest:VTSAX 10 VTSAX {100.00 USD, "lot-1"}En este ejemplo, poseemos 10 unidades de
VTSAX. Cada unidad fue adquirida a un costo de $100.00 USD. Este lote específico de acciones se identifica como un "lote."
Operaciones de Inventario
Hay dos operaciones principales que puede realizar sobre un inventario:
-
Aumentos (Agregar al inventario): Cuando compra una mercancía, aumenta su inventario. Crea un nuevo lote con un número específico de unidades y un costo base.
2024-01-15 * "Buy shares" Assets:Invest:STOCK 50 STOCK {25.00 USD, "lot-1"} Assets:Bank:Checking -1250.00 USDAquí, compramos 50 unidades de
STOCKa un costo por unidad de $25.00 USD. Esto crea un lote en la cuentaAssets:Invest:STOCK. -
Reducciones (Eliminar del inventario): Cuando vende una mercancía, reduce su inventario. Debe especificar de qué lote está vendiendo. Esto se hace proporcionando información coincidente dentro de las llaves.
2024-01-20 * "Sell shares" Assets:Invest:STOCK -25 STOCK {25.00 USD} Assets:Bank:Checking 625.00 USDEn esta transacción, estamos vendiendo 25 unidades de
STOCKdel lote que fue comprado a $25.00 USD por unidad.
Métodos de Registro
Cuando reduce un inventario, Beancount necesita una regla para decidir de qué lote específico retirar si varios lotes coinciden con la reducción. Esta regla se llama "método de registro." Puede establecer un valor predeterminado para todo el archivo con una opción o asignar un método propio a una cuenta mediante la directiva open.
Beancount 3.2.3 acepta siete nombres de método: STRICT (el predeterminado), STRICT_WITH_SIZE, NONE, FIFO, LIFO, HIFO y AVERAGE. Seis de ellos están implementados; AVERAGE analiza pero genera un error en el momento en que tiene que registrar una reducción, como muestra la sección AVERAGE a continuación.
1. STRICT (Predeterminado)
El método STRICT es el predeterminado y el método de registro más seguro. Obliga a un emparejamiento explícito e inequívoco.
2024-01-01 open Assets:Invest:STOCK "STRICT"- Requiere coincidencia exacta de lote: El especificador de costo de la contabilización de reducción (
{...}) debe identificar un solo lote, ya sea por costo, fecha de adquisición, etiqueta o cualquier combinación de ellos. - Errores en coincidencias ambiguas: Si el especificador coincide con más de un lote, Beancount genera un
AmbiguousMatchErroren lugar de adivinar. - Excepción: Si una reducción elimina exactamente el número total de unidades que el especificador coincide, se permite un especificador vacío (
{}) y la reducción se divide entre esos lotes.
Este libro mayor contiene dos lotes y vende uno de ellos nombrando su costo, lo cual es 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:GainsSe carga sin errores, registra $300.00 de ganancia en Income:Gains, y deja 10 STK {100.00 USD} en la cuenta.
Reemplaza esa última contabilización con un especificador vacío y el mismo archivo falla:
; 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 informa Ambiguous matches for "-10 STK {}" y lista a los candidatos. Sin embargo, vender la posición completa está bien porque no queda nada para elegir:
; 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:GainsEso registra $800.00 de ganancia — $3,000.00 de ingresos contra $1,000.00 + $1,200.00 de base — y deja la cuenta vacía. Esta es una propiedad del propio STRICT, no algo para lo que debas cambiar a STRICT_WITH_SIZE.
2. FIFO (Primero en entrar, primero en salir)
El método FIFO registra automáticamente las reducciones contra los lotes disponibles más antiguos primero.
2024-01-01 open Assets:Invest:STOCK "FIFO"- Resolución automática: Resuelve la ambigüedad seleccionando los lotes que coinciden más antiguos.
- Coincidencia cronológica: Se asume que vendes los activos que has tenido por más tiempo. Varias autoridades fiscales consideran esto como el predeterminado cuando no identificas un lote.
3. LIFO (Último en entrar, primero en salir)
El método LIFO es el opuesto de FIFO. Registra las reducciones contra los lotes disponibles más recientes primero.
2024-01-01 open Assets:Invest:STOCK "LIFO"- Orden cronológico inverso: Selecciona las partidas coincidentes adquiridas más recientemente.
- El más nuevo, no el más caro: LIFO elige por fecha de adquisición solamente. Suele vender las acciones de mayor coste cuando los precios han estado subiendo, pero si la partida más nueva es la más barata — que es lo que muestra el ejemplo a continuación — LIFO realizará la mayor ganancia, no la menor. El método que siempre vende las acciones más caras es
HIFO, descrito a continuación.
4. HIFO (Highest-In, First-Out)
El método HIFO anota reducciones contra las partidas más caras disponibles primero, sea cual sea su fecha.
2024-01-01 open Assets:Invest:STOCK "HIFO"- Coincidencia clasificada por coste: Selecciona las partidas coincidentes con el coste base más alto.
- Ganancia realizada más pequeña: Para un precio de venta dado, vender las acciones de mayor coste realiza la ganancia más baja (o la pérdida mayor). Su uso depende de la jurisdicción: en Estados Unidos, por ejemplo, elegir una partida requiere identificación específica en el momento de la venta — así que trate este método como un mecanismo contable y confirme la elección fiscal por separado.
5. Comparando FIFO, LIFO y HIFO sobre las mismas partidas
Los tres métodos solo difieren cuando la partida más antigua, la más nueva y la más cara son tres partidas diferentes. Este libro arregla exactamente eso — la partida A es la más antigua, la partida C es la más nueva, y la partida intermedia B es la más cara — y luego vende 10 acciones de tres cuentas que solo difieren en su método de contabilización:
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:GainsSe carga sin errores y registra una ganancia total de $1,400.00, dividida así:
| Cuenta | Método | Partida anotada | Coste base | Ganancia realizada | Partidas restantes |
|---|---|---|---|---|---|
Assets:Broker:Fifo | FIFO | partida A, 2024-01-10 | $100.00 | $500.00 | 10 @ $120.00, 10 @ $90.00 |
Assets:Broker:Lifo | LIFO | partida C, 2024-03-10 | $90.00 | $600.00 | 10 @ $100.00, 10 @ $120.00 |
Assets:Broker:Hifo | HIFO | partida B, 2024-02-10 | $120.00 | $300.00 | 10 @ $100.00, 10 @ $90.00 |
La fila LIFO es la que merece atención: realizó la mayor ganancia de las tres, porque la partida más nueva también era la más barata.
6. STRICT_WITH_SIZE
STRICT_WITH_SIZE es STRICT más un criterio adicional para desempatar: cuando varias partidas coinciden pero exactamente una tiene la cantidad precisa de unidades que está retirando, esa partida es la elegida.
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:GainsEso registra $210.00 de ganancia contra el lote de $120.00. El archivo idéntico con "STRICT" en la línea open falla con Ambiguous matches for "-7 STK {}".
7. PROMEDIO (aceptado, pero no implementado)
AVERAGE es un nombre válido — option "booking_method" "AVERAGE" y open … "AVERAGE" ambos se analizan — pero Beancount 3.2.3 no tiene implementación detrás. Todo aquí se carga hasta la venta:
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:GainsEn el momento en que esa reducción debe registrarse, el cargador se detiene con:
AVERAGE method is not supportedNo planifiques un libro mayor alrededor de esto. Si quieres comportamiento de costo promedio hoy, mantén la posición en una cuenta NONE y calcula el promedio tú mismo, o rastrea cada lote y acepta ganancias a nivel de lote.
8. NINGUNO
El método NONE desactiva completamente la coincidencia de lotes.
2024-01-01 open Assets:Invest:STOCK "NONE"- Sin coincidencia de lotes: Beancount no intenta hacer coincidir reducciones con aumentos.
- Permite signos mixtos: Esto permite que una cuenta tenga saldos positivos y negativos de la misma mercancía simultáneamente. Este comportamiento es similar a cómo la herramienta Ledger CLI maneja las mercancías.
Especificación de Lotes
Un "lote" es un bloque específico de una mercancía adquirido en un momento y precio particular. Cuando creas o reduces una posición, puedes especificar sus atributos de lote en detalle.
Especificación Completa
Al aumentar un inventario (comprar), puedes especificar hasta tres atributos para el lote, separados por comas dentro de un solo par de llaves:
Assets:Invest:STOCK 10 STOCK {100.00 USD, 2024-01-15, "lot-identifier"}100.00 USD— la base de costo, expresada por unidad.2024-01-15— la fecha de adquisición. Beancount la completa a partir de la fecha de la transacción si la omites, por eso los mensajes de error arriba muestran una fecha en cada lote."lot-identifier"— una etiqueta de cadena opcional.
Aunque los tres son opcionales, proporcionar al menos la base de costo es práctica estándar. Las llaves deben permanecer en una línea, y los comentarios dentro de un ledger comienzan con ;, nunca #.
Métodos de Coincidencia
Al reducir un inventario (vender), usas la misma sintaxis para especificar de qué lote(s) vender.
-
Coincidir por costo: Este es el método más común.
Assets:Invest:STOCK -5 STOCK {100.00 USD} -
Coincidir por fecha: Si los costos son idénticos, puedes desambiguar usando la fecha de adquisición.
Assets:Invest:STOCK -5 STOCK {2024-01-15} -
Coincidir por etiqueta: Las etiquetas proporcionan una forma infalible de identificar un lote.
Assets:Invest:STOCK -5 STOCK {"lot-identifier"} -
Dejar el lote al método de registro: Un conjunto vacío de llaves
{}no nombra ningún lote, así que el método de registro de la cuenta elige. BajoFIFO,LIFOoHIFOeso es el lote más antiguo, más nuevo o más caro que coincida; bajo elSTRICTpredeterminado es unAmbiguousMatchErrora menos que la reducción vacíe exactamente los lotes coincidentes.Assets:Invest:STOCK -5 STOCK {}
Manejo de Precios
Es crucial entender la diferencia entre cost basis ({}) y price (@). Sirven para propósitos diferentes y no son intercambiables.
Precio vs Costo
{cost}: Define el costo de adquisición de un activo. Es parte del lote de inventario en sí y se usa para registrar reducciones y calcular ganancias de capital.@ price: Una anotación que registra un precio de mercado en el momento de una transacción. Se usa para conversiones de moneda o para anotar el valor de mercado en una fecha concreta.
Aquí están los tres escenarios:
-
Anotación de Precio (Conversión): Use
@para convertir de una moneda a otra.Assets:Forex 1000 USD @ 0.85 EUR -
Cost Basis (Adquisición): Use
{}al comprar un activo para establecer su costo.Assets:Invest 10 STOCK {100.00 USD} -
Ambos (Venta con Registro de Precio): Al vender un activo, use
{}para identificar el lote que se vende y@para registrar el precio de venta. Esto permite calcular automáticamente las ganancias de capital.Assets:Invest -10 STOCK {100.00 USD} @ 105.00 USDEsta entrada vende 10
STOCKdel lote que costó $100.00 cada uno, a un precio de venta de $105.00 cada uno.
Reglas de Uso del Precio
- Las anotaciones de precio (
@) no afectan cuál lote se registra. El emparejamiento de lotes se maneja exclusivamente mediante el cost basis ({}) y el método de registro de la cuenta. - El símbolo
@se usa solo para:
- Conversiones de moneda.
- Registrar el valor de mercado de un activo en el momento de una transacción.
- Proporcionar el precio de venta para cálculos de ganancias de capital.
Configuración
Puede configurar métodos de registro globalmente o por cuenta.
Método de Registro Global
Puede establecer un método de registro predeterminado para todo su archivo Beancount usando la directiva option.
option "booking_method" "STRICT"Los valores aceptados son "STRICT" (el predeterminado si no establece nada), "STRICT_WITH_SIZE", "NONE", "FIFO", "LIFO", "HIFO" y "AVERAGE". Cualquier otra cadena es rechazada en tiempo de carga con Error for option 'booking_method'. "AVERAGE" se acepta aquí y en open, pero registrar una reducción bajo él falla, como la sección AVERAGE anterior demuestra.
Anulación Por Cuenta
A menudo es útil tener métodos diferentes para distintas cuentas. Por ejemplo, puede querer FIFO para una cuenta de retiro pero STRICT para una cuenta de corretaje sujeta a impuestos para asegurarse de que está vendiendo lotes fiscales específicos. Puede establecer el método de registro cuando abre la cuenta.
2024-01-01 open Assets:Retirement:401K "FIFO"
2024-01-01 open Assets:Taxable:Stock "STRICT"Mejores Prácticas
-
Organización de Inventario: Para mantener su libro limpio y simple, se recomienda encarecidamente usar cuentas separadas para cada tipo de commodity que posea, y restringir cada una a esa commodity en su directiva
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 mezclar diferentes acciones o fondos en la misma cuenta, ya que complica la gestión del inventario. La lista de commodities en
openhace que Beancount rechace una contabilización errante en lugar de mezclar silenciosamente dos inventarios. -
Gestión de Lotes:
-
Use etiquetas significativas para los lotes, especialmente para transacciones específicas como la cosecha de pérdidas fiscales o las concesiones de acciones a empleados.
Assets:Invest:STOCK 10 STOCK {100.00 USD, "tax-loss-harvest-2024"} -
Documente sus operaciones con comentarios. Esto facilita la lectura y comprensión del libro mayor más adelante.
Assets:Invest:STOCK -10 STOCK {100.00 USD} @ 110.00 USD ; Gain: 10%
- Depuración: Si encuentra errores o comportamientos inesperados, Beancount proporciona herramientas para inspeccionar el estado de su inventario.
-
Examinar Estado del Inventario: Use
bea doctor context main.beancount 42para inspeccionar la transacción en la línea 42, incluyendo sus asientos y los saldos de cuenta afectados. Reemplace el nombre del archivo y el número de línea con la transacción que desea inspeccionar.Reemplace
<LINENO>con el número de línea justo después de una transacción para ver su efecto. -
Verificar Asociación de Lotes: La herramienta
bea checkvalida todo su archivo. Detectará cualquier error de contabilización, como coincidencias ambiguas de lotes en modoSTRICT.