Core Accounting Plugins¶
beancount-blue provides four specialized plugins for Beancount that automate common, complex bookkeeping workflows:
- Amortize: Spread large or recurring expenses across multiple months.
- UK Capital Gains: HMRC-compliant capital gains calculations and lot adjustments.
- Clear Residual Lots: Clear fractional lot dust before closing investment accounts.
- Auto-Tagger: Automatically apply tags to transactions based on participating accounts.
Amortize¶
The amortize plugin aggregates expenses posted to designated accounts and spreads them evenly over a configurable number of months.
Key Features¶
- Creates a monthly adjusting transaction that debits/credits the expense account and offsets against an
Equity:Amortizationholding account. - Tags all generated adjusting transactions with
#amort. - If a transaction has a tag (e.g.
#holiday-2026), the adjustments are grouped by that tag, keeping distinct events separated. - Fully configurable amortization period (in months) and decimal precision per account.
Configuration Example¶
Add the plugin to your ledger:
plugin "beancount_blue.amortize" "{
'accounts': {
'Expenses:Renovation': {
'months': 12,
'decimals': 2,
},
'Expenses:Insurance': {
'months': 12,
'decimals': 2,
}
}
}"
2023-01-15 * "Annual Home Insurance"
Expenses:Insurance 1200.00 GBP
Assets:Bank -1200.00 GBP
Resulting Behavior¶
The £1,200.00 expense recorded in January is amortized over 12 months (£100.00/month from January to December) using an equity holding account (Equity:Amortization:Insurance), ensuring your monthly income and expense reports reflect true monthly consumption.
UK Capital Gains¶
The calc_gains plugin automates capital gains tax calculations for investment and trading portfolios according to UK HMRC regulations.
Key Features¶
- Section 104 Holding Pools: Implements the average-cost pool method (
cost_avg) for shares and securities. - Lot Rebalancing (
lots_adjust): Automatically liquidates previous inventory positions and generates matching capital gains/loss postings to your designated income or equity account. - Cost Basis Tracking: Accurately adjusts the cost basis of holdings following acquisitions and redemptions.
Configuration Example¶
option "booking_method" "NONE"
plugin "beancount_blue.calc_gains" "{
'accounts': {
'Assets:Investments:GIA': {
'method': 'cost_avg',
'counterAccount': 'Income:CapitalGains',
'lots_adjust': True
}
}
}"
2023-01-25 * "Buy Share A"
Assets:Investments:GIA 10 VUSA {{ 50.00 GBP }}
Assets:Bank -50.00 GBP
2023-01-26 * "Buy Share A"
Assets:Investments:GIA 10 VUSA {{ 90.00 GBP }}
Assets:Bank -90.00 GBP
2023-02-25 * "Sell Share A"
Assets:Investments:GIA -4 VUSA {{ 40.00 GBP }}
Assets:Bank 40.00 GBP
Clear Residual Lots¶
When using Beancount's NONE booking method, selling assets might not clear the original purchase lots with exact floating-point precision. This leaves tiny fractional "dust" positions (e.g. 0.000001 LOT) that prevent accounts from being cleanly closed and clutter Fava reports.
The clear_residual_lots plugin detects pending account closures and automatically injects a balancing transaction immediately before the close directive to zero out any residual lots.
Configuration Example¶
Pass the balancing account name as the plugin argument:
plugin "beancount_blue.clear_residual_lots" "Equity:Gains"
2020-01-01 open Assets:Investments:Crypto
...
2024-12-30 close Assets:Investments:Crypto
Auto-Tagger¶
The tag plugin automatically applies tags to transactions whenever specific accounts are involved, simplifying filtering, reporting, and categorization.
Configuration Example¶
plugin "beancount_blue.tag" "{
'accounts': {
'Expenses:Groceries': 'groceries',
'Expenses:Entertainment': 'fun',
'Income:Salary': 'taxable'
}
}"
2024-03-01 * "Tesco"
Expenses:Groceries 45.00 GBP
Assets:Current:Monzo -45.00 GBP
; This transaction will automatically receive the #groceries tag.
API Reference¶
beancount_blue.amortize¶
Amortize expenses over a period of months.
This plugin will amortize all transactions in an Expense account in one aggregate transaction across multiple months.
Key features
- It creates a single transaction each month to adjust the net expense to the amortized amount. It uses the Equity account if it needs to adjust the net expense over the time period.
- It tags all adjustments with #amort so they can be filter out all amortization adjustments.
- If the transaction has a tag, then the adjustments grouped by the tag and have both #amort and the transaction tag. This allows you to divide up different holidays by tag, for example.
- You can configure the decimals for rounding and number of months.
This is best explained through a demonstration.
Example book:
; Configure the Expenses:Renovation account to be amortized over 12 months.
;
; It will use the Equity:Amortization:Renovation account as the holding account.
;
plugin "beancount_blue.amortize" "{
'accounts': {
'Expenses:Renovation': {
'months': 12,
'decimals': 2,
},
}
}"
2023-01-15 * "Assorted Purchase"
Expenses:Renovation 1000.00 GBP
Assets:Bank -1000.00 GBP
2023-01-25 * "Assorted Purchase 2"
Expenses:Renovation 200.00 GBP
Assets:Bank -200.00 GBP
2023-02-15 * "Assorted Purchase 3"
Expenses:Renovation 360.00 GBP
Assets:Bank -360.00 GBP
What will happen as a result of the above
- The first two transactions in January are aggregated (1200 GBP) and then divided up over 12 months, so 100 GBP a month from Jan 2023 to Dec 2023.
- The transaction in February is divided up over 12 months, so 30 GBP a month from Feb 2023 to Jan 2024.
amortize(entries, _, config_str)
¶
Amortize expenses over a period of months.
This function is the entry point for the Beancount plugin. It takes the existing entries, the Beancount options, and a configuration string.
The configuration string should be a Python dictionary literal that specifies which accounts to amortize and over how many months.
Example configuration:
.. code-block:: beancount
plugin "beancount_blue.amortize" "{
'accounts': {
'Expenses:Software': {'months': 12},
'Expenses:Subscriptions': {'months': 12},
}
}"
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
Entries
|
A list of beancount entries. |
required |
_
|
Any
|
The Beancount options map (not used). |
required |
config_str
|
str
|
A string containing the configuration for the plugin. |
required |
Returns:
| Type | Description |
|---|---|
tuple[Entries, list[AmortizeError]]
|
A tuple of the modified entries and a list of errors. |
Source code in beancount_blue/amortize.py
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | |
beancount_blue.calc_gains¶
Calculate capital gains.
Account
¶
An account that holds securities.
Source code in beancount_blue/calc_gains.py
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | |
__init__(account, config)
¶
Initialize the account.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
account
|
str
|
The name of the account. |
required |
config
|
dict[str, Any]
|
The configuration for the account. |
required |
Source code in beancount_blue/calc_gains.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | |
add_posting(postingId, entry, posting)
¶
Add a posting to the account.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
postingId
|
PostingID
|
The ID of the posting. |
required |
entry
|
Transaction
|
The entry containing the posting. |
required |
posting
|
Posting
|
The posting to add. |
required |
Returns:
| Type | Description |
|---|---|
str | None
|
An error message if there was an error, otherwise None. |
Source code in beancount_blue/calc_gains.py
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | |
process(entries)
¶
Process the entries as configured.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
Entries
|
The set of entries |
required |
Source code in beancount_blue/calc_gains.py
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 | |
GainsCalculatorError
¶
Bases: NamedTuple
An error that occurred during capital gains calculation.
Source code in beancount_blue/calc_gains.py
33 34 35 36 37 38 | |
Trade
¶
Bases: NamedTuple
A trade in a security.
Source code in beancount_blue/calc_gains.py
21 22 23 24 25 26 27 28 29 30 | |
calc_gains(entries, _, config_str)
¶
Calculate capital gains for UK tax purposes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
Entries
|
A list of beancount entries. |
required |
config_str
|
str
|
A string containing the configuration for the plugin. |
required |
Returns:
| Type | Description |
|---|---|
tuple[list[Directive], list[GainsCalculatorError]]
|
A tuple of the modified entries and a list of errors. |
Source code in beancount_blue/calc_gains.py
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 | |
get_realizing_cost_consideration(trades)
¶
Calculate the average cost of a list of trades.
This function implements the "average cost" method of calculating capital
gains. It averages the cost of all lots purchased and uses that average
cost to determine the gain or loss on a sale.
Args:
trades: A list of trades.
Returns:
A list of cost basis for all realizing trades.
Source code in beancount_blue/calc_gains.py
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
beancount_blue.clear_residual_lots¶
Automatically clear residual lots from closed accounts.
This plugin is designed to solve a specific problem that can occur when using the 'NONE' booking method in Beancount. With this method, sales of assets do not always perfectly clear the original purchase lots, which can leave small residual amounts in the account's inventory. This can cause issues with some tools, like Fava, which may continue to display accounts that should be closed.
This plugin solves this by creating a balancing transaction to clear out any remaining lots just before the account is closed.
Example configuration:
.. code-block:: beancount
plugin "beancount_blue.clear_residual_lots" "Equity:Gains"
clear_residual_lots(entries, _, config_str)
¶
The main plugin function.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
Entries
|
The full list of Beancount entries. |
required |
_
|
Any
|
The Beancount options map. |
required |
config_str
|
str
|
The string provided in the plugin configuration, which should be the name of the balancing account. |
required |
Returns: A tuple of (new_entries, errors).
Source code in beancount_blue/clear_residual_lots.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | |
beancount_blue.tag¶
Tag transactions based on account.
This plugin automatically adds tags to transactions based on the accounts they involve. This can be useful for categorizing transactions and for generating reports.
For example, you can configure the plugin to add the tag "shopping" to any transaction that involves the account "Expenses:Shopping".
Example configuration:
.. code-block:: beancount
plugin "beancount_blue.tag" "{
'accounts': {
'Expenses:Shopping': 'shopping',
'Expenses:Groceries': 'groceries'
}
}"
tag(entries, _, config_str)
¶
Tag transactions based on account.
This function is the entry point for the Beancount plugin. It takes the existing entries, the Beancount options, and a configuration string.
The configuration string should be a Python dictionary literal that maps account names to the tags that should be applied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
Entries
|
A list of beancount entries. |
required |
_
|
Any
|
The Beancount options map (not used). |
required |
config_str
|
str
|
A string containing the configuration for the plugin. |
required |
Returns:
| Type | Description |
|---|---|
tuple[Entries, list[Any]]
|
A tuple of the modified entries and a list of errors. |
Source code in beancount_blue/tag.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | |