commit aa4571b09cc9771697fa67e27203957585897533 Author: Roger Oriol Pérez Date: Sun Dec 10 11:42:13 2023 +0100 created foundation for ledger diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eba74f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +venv/ \ No newline at end of file diff --git a/commands/balance-sheet b/commands/balance-sheet new file mode 100755 index 0000000..7410ab3 --- /dev/null +++ b/commands/balance-sheet @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "TO DO" \ No newline at end of file diff --git a/commands/cash-flow-statement b/commands/cash-flow-statement new file mode 100755 index 0000000..7410ab3 --- /dev/null +++ b/commands/cash-flow-statement @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "TO DO" \ No newline at end of file diff --git a/commands/check b/commands/check new file mode 100755 index 0000000..c33c315 --- /dev/null +++ b/commands/check @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +bean-check ledger/main.beancount \ No newline at end of file diff --git a/commands/income-statement b/commands/income-statement new file mode 100755 index 0000000..7410ab3 --- /dev/null +++ b/commands/income-statement @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +echo "TO DO" \ No newline at end of file diff --git a/commands/serve b/commands/serve new file mode 100755 index 0000000..948e915 --- /dev/null +++ b/commands/serve @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +fava ledger/main.beancount -p 8080 \ No newline at end of file diff --git a/ledger/accounts.beancount b/ledger/accounts.beancount new file mode 100644 index 0000000..e9c6d90 --- /dev/null +++ b/ledger/accounts.beancount @@ -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 \ No newline at end of file diff --git a/ledger/budget.beancount b/ledger/budget.beancount new file mode 100644 index 0000000..2df760a --- /dev/null +++ b/ledger/budget.beancount @@ -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 diff --git a/ledger/commodities.beancount b/ledger/commodities.beancount new file mode 100644 index 0000000..1036d59 --- /dev/null +++ b/ledger/commodities.beancount @@ -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" \ No newline at end of file diff --git a/ledger/main.beancount b/ledger/main.beancount new file mode 100644 index 0000000..869df2e --- /dev/null +++ b/ledger/main.beancount @@ -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/*" \ No newline at end of file diff --git a/ledger/plugins/__pycache__/amortize_over.cpython-311.pyc b/ledger/plugins/__pycache__/amortize_over.cpython-311.pyc new file mode 100644 index 0000000..79aff24 Binary files /dev/null and b/ledger/plugins/__pycache__/amortize_over.cpython-311.pyc differ diff --git a/ledger/plugins/amortize_over.py b/ledger/plugins/amortize_over.py new file mode 100644 index 0000000..6e0330b --- /dev/null +++ b/ledger/plugins/amortize_over.py @@ -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 \ No newline at end of file diff --git a/ledger/trading/2024_01.beancount b/ledger/trading/2024_01.beancount new file mode 100644 index 0000000..7d8a0f7 --- /dev/null +++ b/ledger/trading/2024_01.beancount @@ -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 \ No newline at end of file diff --git a/ledger/transactions/2024_01.beancount b/ledger/transactions/2024_01.beancount new file mode 100644 index 0000000..57e61a9 --- /dev/null +++ b/ledger/transactions/2024_01.beancount @@ -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 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..750fb45 --- /dev/null +++ b/requirements.txt @@ -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