28 desembre 2024

This commit is contained in:
Roger Oriol
2024-12-28 19:32:44 +01:00
parent 0443c308f8
commit 78892b4b6b
3 changed files with 182 additions and 17 deletions

124
commands/investments Executable file
View File

@@ -0,0 +1,124 @@
#!/usr/bin/env python3
from beancount import loader
from beancount.query import query
from beancount.parser import printer
import argparse
from tabulate import tabulate
from decimal import Decimal
from beancount.core.amount import Amount, add, sub, mul
from math import floor
from datetime import datetime, timedelta
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
def draw_line():
print('─' * 30)
def get_amount(inventory):
if inventory.get_only_position() == None:
return Amount(Decimal(0), "EUR").to_string()
result = inventory.get_only_position().units
return Amount(Decimal(round(result.number, 2)), result.currency).to_string()
def print_capital_gains(inventory):
if inventory.get_only_position() == None:
return Amount(Decimal(0), "EUR").to_string()
result = inventory.get_only_position().units
num = Amount(Decimal(round(result.number * -1, 2)), result.currency).to_string()
return f"{bcolors.OKGREEN if result.number <= 0 else bcolors.FAIL}{num}{bcolors.ENDC}"
def print_perc_capital_gains(inventory, init_invest):
if inventory.get_only_position() == None:
return Amount(Decimal(0), "EUR").to_string()
result = inventory.get_only_position().units
invest = init_invest.get_only_position().units
num = round((result.number * -1 / invest.number) * 100, 2)
return f"{bcolors.OKGREEN if result.number <= 0 else bcolors.FAIL}{num} %{bcolors.ENDC}"
def calc_contributions(contributions):
total = Decimal(0)
for c in contributions:
amount = c.position.units.number
if amount > 0:
total += amount
return total
def get_returns(init_invest, end_invest, contributions):
init = init_invest.get_only_position().units
end = end_invest.get_only_position().units
contr = calc_contributions(contributions)
result = sub(sub(end, init), Amount(contr, "EUR"))
return Amount(Decimal(round(result.number, 2)), result.currency).to_string()
def print_contributions(contributions):
total = calc_contributions(contributions)
return Amount(Decimal(round(total, 2)), "EUR").to_string()
def print_report(date, end_date, init_invest, end_invest, contributions, capital_gains):
print(f"{bcolors.BOLD}Investment returns (date={date}){bcolors.ENDC}")
draw_line()
print(tabulate([
[date, get_amount(init_invest)],
[end_date, get_amount(end_invest)]
], headers=['Date', 'Balance']))
print(tabulate([
["Contributions", print_contributions(contributions)],
["Returns", get_returns(init_invest, end_invest, contributions)],
["Capital gains", print_capital_gains(capital_gains)],
["Capital gains %", print_perc_capital_gains(capital_gains, init_invest)]
]))
def get_investments(entries, options, date, end_date):
initial_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {date} WHERE account ~ '^Assets:Invest'"
rtypes, rrows = query.run_query(
entries, options, initial_query)
end_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {end_date} WHERE account ~ '^Assets:Invest'"
rtypes, erows = query.run_query(
entries, options, end_query)
return rrows[0].position, erows[0].position
def get_contributions(entries, options, start_date, end_date):
contributions_query = f"SELECT position FROM date <= {end_date} WHERE account ~ '^Assets:Liquid:R4:EUR' AND date >= {start_date}"
rtypes, rrows = query.run_query(
entries, options, contributions_query)
return rrows
def get_capital_gains(entries, options, date, end_date):
q = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {end_date} WHERE account ~ '^Income:Invest:R4:CapitalGains' AND date >= {date}"
rtypes, rrows = query.run_query(
entries, options, q)
return rrows[0].position
def main():
parser = argparse.ArgumentParser(description='Generate investments report')
parser.add_argument('date', metavar='date', type=str, nargs=1,
help='Report date in ISO format (e.g. 1970-01-01)')
args = parser.parse_args()
date = args.date[0]
filename = "ledger/main.beancount"
entries, errors, options = loader.load_file(filename)
if errors:
printer.print_errors(errors)
d = date.split("-")
end_date = datetime(int(d[0]) + 1, int(d[1]), int(d[2]))
end_date = end_date.strftime("%Y-%m-%d")
init_invest, end_invest = get_investments(entries, options, date, end_date)
contributions = get_contributions(entries, options, date, end_date)
capital_gains = get_capital_gains(entries, options, date, end_date)
print_report(date, end_date, init_invest, end_invest, contributions, capital_gains)
main()

View File

@@ -24,3 +24,10 @@
2024-06-24 price IWVL 48.37 EUR
2024-06-24 price PLTR 24.21 USD
2024-06-24 price MSFT 448.325 USD
2024-12-28 price VANGL 52.621 EUR
2024-12-28 price VANSMCAP 360.4489 EUR
2024-12-28 price VANEMMK 210.0581 EUR
2024-12-28 price R4RF 15.229469 EUR
2024-12-28 price IWVL 41.3 EUR
2024-12-28 price XDEQ 68.24 EUR

View File

@@ -190,17 +190,51 @@
2024-12-20 * "Carrefour" "Paper d'embolicar"
Expenses:Supermercat 1.50 EUR
Assets:Liquid:Caixabank:Corrent
2024-12-21 * "Mercadona" "Compra super"
Expenses:Supermercat 7.20 EUR
Assets:Liquid:Caixabank:Corrent
2024-12-22 * "Mr Ji Sushi" "Dinar sushi"
Expenses:MenjarFora 49.30 EUR
Assets:Liquid:Caixabank:Corrent
2024-12-24 * "Zurich" "Nòmina desembre 2024"
Income:Work:Zurich:Salari -3474.41 EUR
Assets:Liquid:Caixabank:Corrent
2024-12-24 * "R4" "Enviament de diners R4"
Assets:Liquid:Caixabank:Corrent -1200 EUR
Assets:Liquid:R4:EUR
2024-12-25 * "Farmacia Pou" "Mayesta Laura"
Expenses:Medic 17.09 EUR
Assets:Liquid:Caixabank:Corrent
2024-12-25 * "City Arms" "Ratafia"
Expenses:MenjarFora 16 EUR
Assets:Liquid:Caixabank:Corrent
2024-12-27 * "Renta 4" "Compra de ISHARES EDGE MSCI WORLD VALUE"
Assets:Invest:ETF:IWVL 24 IWVL {41.35 EUR}
Assets:Liquid:R4:EUR -1007.40 EUR
Expenses:R4:Comissions 15 EUR
2024-12-27 * "EsclatOil" "Gasolina"
Expenses:Gasolina 25 EUR
Assets:Liquid:Caixabank:Corrent
2024-12-28 * "Aerobus" "Anada i tornada aeroport"
Expenses:Mobilitat 25 EUR
Assets:Benefits:Edenred:TargetaTransport
2024-12-28 * "L'Obrador" "Esmorzar"
Expenses:MenjarFora 13.30 EUR
Assets:Liquid:Caixabank:Corrent
2024-12-28 * "Eroski" "Gilette"
Expenses:Supermercat 18.84 EUR
Assets:Liquid:Caixabank:Corrent
2025-01-01 balance Assets:Liquid:Caixabank:Corrent 11078.39 EUR
2025-01-01 balance Assets:Liquid:R4:EUR 35.41 EUR
2025-01-01 balance Assets:Liquid:Caixabank:Corrent 13206.07 EUR
2025-01-01 balance Assets:Liquid:R4:EUR 228.01 EUR
2025-01-01 balance Assets:Invest:Fund:Vanguard:EMMK 14.99 VANEMMK
2025-01-01 balance Assets:Invest:Fund:Vanguard:GL 707.25 VANGL
2025-01-01 balance Assets:Invest:Fund:Vanguard:SMCAP 48.28 VANSMCAP
2025-01-01 balance Assets:Invest:ETF:IWVL 117 IWVL
2025-01-01 balance Assets:Invest:ETF:IWVL 141 IWVL
2025-01-01 balance Assets:Invest:Fixed:R4RF 1505.44135 R4RF
2025-01-01 balance Assets:Invest:ETF:XDEQ 70 XDEQ
2025-01-01 balance Assets:Benefits:Edenred:TicketsRestaurant 25.92 EUR
2025-01-01 balance Assets:Benefits:Edenred:TargetaTransport 122 EUR
2025-01-01 balance Assets:Benefits:Edenred:TargetaTransport 97 EUR
2025-01-01 balance Assets:Benefits:DZP:PPEZurich 2971.29 EUR
2025-01-01 balance Assets:PersonalProperty:VivendaPrincipal 0 EUR
2025-01-01 balance Assets:PersonalProperty:Cotxe 10000 EUR