created foundation for ledger
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
venv/
|
||||
2
commands/balance-sheet
Executable file
2
commands/balance-sheet
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
echo "TO DO"
|
||||
2
commands/cash-flow-statement
Executable file
2
commands/cash-flow-statement
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
echo "TO DO"
|
||||
2
commands/check
Executable file
2
commands/check
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
bean-check ledger/main.beancount
|
||||
2
commands/income-statement
Executable file
2
commands/income-statement
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
echo "TO DO"
|
||||
2
commands/serve
Executable file
2
commands/serve
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
fava ledger/main.beancount -p 8080
|
||||
65
ledger/accounts.beancount
Normal file
65
ledger/accounts.beancount
Normal file
@@ -0,0 +1,65 @@
|
||||
1970-01-01 open Assets:Liquid:Caixabank:Corrent EUR
|
||||
1970-01-01 open Assets:Liquid:Caixabank:Estalvi EUR
|
||||
1970-01-01 open Assets:Liquid:R4:EUR EUR
|
||||
1970-01-01 open Assets:Invest:R4:Vanguard:EMMK VANEMMK
|
||||
1970-01-01 open Assets:Invest:R4:Amundi:MSCIWRLD AMNDMSCIWRLD
|
||||
1970-01-01 open Assets:Invest:R4:BNP:DISTECH BNPDISTECH
|
||||
1970-01-01 open Assets:Invest:R4:Fidelity:GLTECH FIGLTECH
|
||||
1970-01-01 open Assets:Invest:R4:Amundi:SUSTINC AMNDSUSINC
|
||||
1970-01-01 open Assets:Invest:R4:PLTR PLTR
|
||||
1970-01-01 open Assets:Invest:R4:MSFT MSFT
|
||||
1970-01-01 open Assets:Benefits:Edenred:TicketsRestaurant EUR
|
||||
1970-01-01 open Assets:Benefits:Edenred:TarjetaTransport EUR
|
||||
1970-01-01 open Assets:PersonalProperty:VivendaPrincipal EUR
|
||||
1970-01-01 open Assets:PersonalProperty:Cotxe EUR
|
||||
1970-01-01 open Assets:PersonalProperty:JoiesArtCollecionables EUR
|
||||
1970-01-01 open Assets:PersonalProperty:MetallsPreciosos EUR
|
||||
1970-01-01 open Assets:PersonalProperty:AltresPropietats EUR
|
||||
1970-01-01 open Assets:Debt:DeutesPerCobrar EUR
|
||||
|
||||
1970-01-01 open Liabilities:Credit:Caixabank:TargetaCredit EUR
|
||||
1970-01-01 open Liabilities:Factures:FacturesPendents EUR
|
||||
1970-01-01 open Liabilities:Taxes:IRPF EUR
|
||||
;1970-01-01 open Liabilities:Hipoteca:VivendaPrincipal EUR
|
||||
|
||||
1970-01-01 open Income:Work:Zurich:Salari EUR
|
||||
1970-01-01 open Income:Work:Zurich:TicketsRestaurant EUR
|
||||
1970-01-01 open Income:Work:Zurich:TarjetaTransport EUR
|
||||
1970-01-01 open Income:Work:Zurich:SeguroMedic EUR
|
||||
1970-01-01 open Income:Work:Zurich:Gimnas EUR
|
||||
1970-01-01 open Income:Other:Caixabank:Transferencia EUR
|
||||
1970-01-01 open Income:Other:Caixabank:Bizum EUR
|
||||
1970-01-01 open Income:Savings:Caixabank:RentabilitatEstalvis EUR
|
||||
1970-01-01 open Income:Invest:R4:Dividends EUR
|
||||
1970-01-01 open Income:Invest:R4:CapitalGains EUR
|
||||
|
||||
1970-01-01 open Expenses:R4:Comissions EUR
|
||||
1970-01-01 open Expenses:Taxes:IRPF EUR
|
||||
1970-01-01 open Expenses:Taxes:BeneficisDividends EUR
|
||||
1970-01-01 open Expenses:Taxes:BeneficisDividendsOrigen EUR
|
||||
1970-01-01 open Expenses:Taxes:ImpostCirculacio EUR
|
||||
1970-01-01 open Expenses:Insurance:Cotxe EUR
|
||||
1970-01-01 open Expenses:Lloguer EUR
|
||||
1970-01-01 open Expenses:FacturesUtilitats EUR
|
||||
1970-01-01 open Expenses:Internet EUR
|
||||
1970-01-01 open Expenses:Gasolina EUR
|
||||
1970-01-01 open Expenses:MantenimentCotxe EUR
|
||||
1970-01-01 open Expenses:Roba EUR
|
||||
1970-01-01 open Expenses:Educació EUR
|
||||
1970-01-01 open Expenses:Medic EUR
|
||||
1970-01-01 open Expenses:Vacances EUR
|
||||
1970-01-01 open Expenses:NintendoOnline EUR
|
||||
1970-01-01 open Expenses:Perruqueria EUR
|
||||
1970-01-01 open Expenses:AmazonPrime EUR
|
||||
1970-01-01 open Expenses:CarnetJove EUR
|
||||
1970-01-01 open Expenses:Supermercat EUR
|
||||
1970-01-01 open Expenses:Gimnàs EUR
|
||||
1970-01-01 open Expenses:Parking EUR
|
||||
1970-01-01 open Expenses:Mobilitat EUR
|
||||
1970-01-01 open Expenses:MarcaPersonal EUR
|
||||
1970-01-01 open Expenses:MenjarFora EUR
|
||||
1970-01-01 open Expenses:Entreteniment EUR
|
||||
1970-01-01 open Expenses:Altres EUR
|
||||
|
||||
1970-01-01 open Equity:Opening-Balances EUR
|
||||
1970-01-01 open Equity:Opening-Balances:USD USD
|
||||
24
ledger/budget.beancount
Normal file
24
ledger/budget.beancount
Normal file
@@ -0,0 +1,24 @@
|
||||
2024-01-01 custom "budget" Expenses:Lloguer "monthly" 600.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:FacturesUtilitats "monthly" 80.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Internet "monthly" 50.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Gasolina "monthly" 50.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Roba "monthly" 80.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Perruqueria "monthly" 16.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Supermercat "monthly" 180.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Parking "monthly" 122.09 EUR
|
||||
2024-01-01 custom "budget" Expenses:Mobilitat "monthly" 125.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Entreteniment "monthly" 60.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:MenjarFora "monthly" 250.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Altres "monthly" 150.00 EUR
|
||||
|
||||
2024-01-01 custom "budget" Expenses:MantenimentCotxe "yearly" 180.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Educació "yearly" 200.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Medic "yearly" 400.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Vacances "yearly" 2000.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Taxes:ImpostCirculacio "yearly" 55.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:NintendoOnline "yearly" 35.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:AmazonPrime "yearly" 50.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Insurance:Cotxe "yearly" 520.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:CarnetJove "yearly" 10.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:Gimnàs "yearly" 800.00 EUR
|
||||
2024-01-01 custom "budget" Expenses:MarcaPersonal "yearly" 150.00 EUR
|
||||
19
ledger/commodities.beancount
Normal file
19
ledger/commodities.beancount
Normal file
@@ -0,0 +1,19 @@
|
||||
1970-01-01 commodity EUR
|
||||
name: "Euro"
|
||||
1970-01-01 commodity USD
|
||||
name: "US Dollar"
|
||||
1970-01-01 commodity VANEMMK
|
||||
name: "VANGUARD EM MK ST IX INV (EUR)"
|
||||
1970-01-01 commodity AMNDMSCIWRLD
|
||||
name: "Amundi Index MSCI World AE (EUR) INC"
|
||||
2024-01-01 commodity AMNDSUSINC
|
||||
name: "AMUNDI FUNDS GLOBAL E A2 (EUR) D C / Amundi Fds Glb EQ Sust Inc A2 EUR Qti D"
|
||||
1970-01-01 commodity BNPDISTECH
|
||||
name: "BNP Disrupting Technology C (USD) ACC"
|
||||
1970-01-01 commodity FIGLTECH
|
||||
name: "FIDELITY GLOBAL TECHNOLOGY A (EUR)"
|
||||
1970-01-01 commodity PLTR
|
||||
name: "Palantir Technologies Inc"
|
||||
1970-01-01 commodity MSFT
|
||||
name: "MSFT"
|
||||
price: "USD:google/NASDAQ:MSFT"
|
||||
16
ledger/main.beancount
Normal file
16
ledger/main.beancount
Normal file
@@ -0,0 +1,16 @@
|
||||
* Plugins
|
||||
option "insert_pythonpath" "True"
|
||||
plugin "plugins.amortize_over"
|
||||
plugin "beancount.plugins.implicit_prices"
|
||||
|
||||
* Options
|
||||
option "title" "Roger Oriol Ledger"
|
||||
option "operating_currency" "EUR"
|
||||
option "inferred_tolerance_default" "*:0.001"
|
||||
|
||||
* Imports
|
||||
include "accounts.beancount"
|
||||
include "commodities.beancount"
|
||||
include "budget.beancount"
|
||||
include "trading/*"
|
||||
include "transactions/*"
|
||||
BIN
ledger/plugins/__pycache__/amortize_over.cpython-311.pyc
Normal file
BIN
ledger/plugins/__pycache__/amortize_over.cpython-311.pyc
Normal file
Binary file not shown.
143
ledger/plugins/amortize_over.py
Normal file
143
ledger/plugins/amortize_over.py
Normal file
@@ -0,0 +1,143 @@
|
||||
# Copyright (c) 2017 Cary Kempston
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from beancount.core.data import Transaction
|
||||
from beancount.core.amount import Amount
|
||||
|
||||
from datetime import date
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
__plugins__ = ('amortize_over',)
|
||||
|
||||
|
||||
AmortizationError = namedtuple('AmortizationError', 'source message entry')
|
||||
|
||||
|
||||
def amortize_over(entries, unused_options_map):
|
||||
"""Repeat a transaction based on metadata.
|
||||
|
||||
Args:
|
||||
entries: A list of directives. We're interested only in the
|
||||
Transaction instances.
|
||||
unused_options_map: A parser options dict.
|
||||
Returns:
|
||||
A list of entries and a list of errors.
|
||||
|
||||
Example use:
|
||||
|
||||
This plugin will convert the following transactions
|
||||
|
||||
2017-06-01 * "Pay car insurance"
|
||||
Assets:Bank:Checking -600.00 USD
|
||||
Assets:Prepaid-Expenses
|
||||
|
||||
2017-06-01 * "Amortize car insurance over six months"
|
||||
amortize_months: 3
|
||||
Assets:Prepaid-Expenses -600.00 USD
|
||||
Expenses:Insurance:Auto
|
||||
|
||||
into the following transactions over six months:
|
||||
|
||||
2017/06/01 * Pay car insurance
|
||||
Assets:Bank:Checking -600.00 USD
|
||||
Assets:Prepaid-Expenses 600.00 USD
|
||||
|
||||
2017/06/01 * Amortize car insurance over six months
|
||||
Assets:Prepaid-Expenses -200.00 USD
|
||||
Expenses:Insurance:Auto 200.00 USD
|
||||
|
||||
2017/07/01 * Amortize car insurance over six months
|
||||
Assets:Prepaid-Expenses -200.00 USD
|
||||
Expenses:Insurance:Auto 200.00 USD
|
||||
|
||||
2017/08/01 * Amortize car insurance over six months
|
||||
Assets:Prepaid-Expenses -200.00 USD
|
||||
Expenses:Insurance:Auto 200.00 USD
|
||||
|
||||
Note that transactions are not included past today's date. For example,
|
||||
if the above transactions are processed on a date of 2017/07/25, the
|
||||
transaction dated 2017/08/01 is not included.
|
||||
"""
|
||||
new_entries = []
|
||||
errors = []
|
||||
|
||||
for entry in entries:
|
||||
if isinstance(entry, Transaction) and 'amortize_months' in entry.meta:
|
||||
a_entires, a_errors = amortize_transaction(entry)
|
||||
new_entries.extend(a_entires)
|
||||
errors.extend(a_errors)
|
||||
else:
|
||||
# Always replicate the existing entries - unless 'amortize_months'
|
||||
# is in the metadata
|
||||
new_entries.append(entry)
|
||||
|
||||
return new_entries, errors
|
||||
|
||||
|
||||
def split_amount(amount, periods):
|
||||
if periods == 1:
|
||||
return [amount]
|
||||
amount_this_period = amount / periods
|
||||
amount_this_period = amount_this_period.quantize(amount)
|
||||
return [amount_this_period] + split_amount(amount - amount_this_period, periods - 1)
|
||||
|
||||
|
||||
def amortize_transaction(entry):
|
||||
|
||||
new_entries = []
|
||||
errors = []
|
||||
|
||||
if len(entry.postings) != 2:
|
||||
error = AmortizationError(
|
||||
entry.meta,
|
||||
'Amortized transactions must have exactly two postings.',
|
||||
entry
|
||||
)
|
||||
errors.append(error)
|
||||
return new_entries, errors
|
||||
|
||||
periods = entry.meta['amortize_months']
|
||||
|
||||
amount = abs(entry.postings[0].units.number)
|
||||
currency = entry.postings[0].units.currency
|
||||
|
||||
monthly_amounts = split_amount(amount, periods)
|
||||
|
||||
for (n_month, monthly_number) in enumerate(monthly_amounts):
|
||||
new_postings = []
|
||||
for posting in entry.postings:
|
||||
new_monthly_number = monthly_number
|
||||
if posting.units.number < 0:
|
||||
new_monthly_number = -monthly_number
|
||||
new_posting = posting._replace(units=Amount(number=new_monthly_number,
|
||||
currency=currency))
|
||||
new_postings.append(new_posting)
|
||||
|
||||
new_narration = f'{entry.narration} ({n_month + 1}/{periods})'
|
||||
new_entry = entry._replace(
|
||||
narration=new_narration,
|
||||
postings=new_postings,
|
||||
date=entry.date + relativedelta(months=n_month),
|
||||
)
|
||||
if new_entry.date <= date.today():
|
||||
new_entries.append(new_entry)
|
||||
return new_entries, errors
|
||||
6
ledger/trading/2024_01.beancount
Normal file
6
ledger/trading/2024_01.beancount
Normal file
@@ -0,0 +1,6 @@
|
||||
;2021-07-19 price AMNDEMWRLD 99.326565 EUR
|
||||
;2021-07-19 price AMNDMSCIWRLD 204.929967 EUR
|
||||
;2021-07-19 price BNPDISTECH 1567.214485 EUR
|
||||
;2021-07-19 price JPMTECH 6.101629 EUR
|
||||
;2021-07-19 price PLTR 5.994 EUR
|
||||
;2021-07-19 price IRNT 0.2185 EUR
|
||||
15
ledger/transactions/2024_01.beancount
Normal file
15
ledger/transactions/2024_01.beancount
Normal file
@@ -0,0 +1,15 @@
|
||||
2024-01-01 * "Balanç inicial EUR"
|
||||
Assets:Liquid:Caixabank:Corrent 18903.80 EUR
|
||||
Assets:Liquid:Caixabank:Estalvi 12666.49 EUR
|
||||
Assets:Liquid:R4:EUR 44.04 EUR
|
||||
Assets:Invest:R4:Amundi:MSCIWRLD 86.005 AMNDMSCIWRLD {237.62 EUR}
|
||||
Assets:Invest:R4:Vanguard:EMMK 14.99 VANEMMK {177.773 EUR}
|
||||
Assets:Invest:R4:Fidelity:GLTECH 344.47 FIGLTECH {41.06 EUR}
|
||||
Assets:Invest:R4:Amundi:SUSTINC 11.295 AMNDSUSINC {62.84 EUR}
|
||||
Equity:Opening-Balances:USD 2315.65 USD {0.93 EUR}
|
||||
Equity:Opening-Balances
|
||||
2024-01-01 * "Balanç inicial USD"
|
||||
Assets:Invest:R4:BNP:DISTECH 0.359 BNPDISTECH {2195.55 USD}
|
||||
Assets:Invest:R4:PLTR 10 PLTR {16.025 USD}
|
||||
Assets:Invest:R4:MSFT 4 MSFT {341.8 USD}
|
||||
Equity:Opening-Balances:USD
|
||||
50
requirements.txt
Normal file
50
requirements.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
Babel==2.13.1
|
||||
beancount==2.3.6
|
||||
beautifulsoup4==4.12.2
|
||||
blinker==1.7.0
|
||||
bottle==0.12.25
|
||||
cachetools==5.3.2
|
||||
certifi==2023.11.17
|
||||
chardet==5.2.0
|
||||
charset-normalizer==3.3.2
|
||||
cheroot==10.0.0
|
||||
click==8.1.7
|
||||
fava==1.26.2
|
||||
fava-plugins==1.0
|
||||
Flask==3.0.0
|
||||
flask-babel==4.0.0
|
||||
google-api-core==2.14.0
|
||||
google-api-python-client==2.109.0
|
||||
google-auth==2.25.1
|
||||
google-auth-httplib2==0.1.1
|
||||
googleapis-common-protos==1.61.0
|
||||
httplib2==0.22.0
|
||||
idna==3.6
|
||||
iniconfig==2.0.0
|
||||
itsdangerous==2.1.2
|
||||
jaraco.functools==4.0.0
|
||||
Jinja2==3.1.2
|
||||
lxml==4.9.3
|
||||
markdown2==2.4.11
|
||||
MarkupSafe==2.1.3
|
||||
more-itertools==10.1.0
|
||||
packaging==23.2
|
||||
pdfminer2==20151206
|
||||
pluggy==1.3.0
|
||||
ply==3.11
|
||||
protobuf==4.25.1
|
||||
pyasn1==0.5.1
|
||||
pyasn1-modules==0.3.0
|
||||
pyparsing==3.1.1
|
||||
pytest==7.4.3
|
||||
python-dateutil==2.8.2
|
||||
python-magic==0.4.27
|
||||
pytz==2023.3.post1
|
||||
requests==2.31.0
|
||||
rsa==4.9
|
||||
simplejson==3.19.2
|
||||
six==1.16.0
|
||||
soupsieve==2.5
|
||||
uritemplate==4.1.1
|
||||
urllib3==2.1.0
|
||||
Werkzeug==3.0.1
|
||||
Reference in New Issue
Block a user