28 desembre 2024
This commit is contained in:
124
commands/investments
Executable file
124
commands/investments
Executable 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()
|
||||
@@ -23,4 +23,11 @@
|
||||
2024-06-24 price FIGLTECH 48.37 EUR
|
||||
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-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
|
||||
@@ -1,11 +1,11 @@
|
||||
2024-12-01 balance Assets:Liquid:Caixabank:Corrent 12580.17 EUR
|
||||
2024-12-01 balance Assets:Liquid:R4:EUR 1035.41 EUR
|
||||
2024-12-01 balance Assets:Invest:Fund:Vanguard:EMMK 14.99 VANEMMK
|
||||
2024-12-01 balance Assets:Invest:Fund:Vanguard:GL 688.32 VANGL
|
||||
2024-12-01 balance Assets:Invest:Fund:Vanguard:SMCAP 48.28 VANSMCAP
|
||||
2024-12-01 balance Assets:Invest:ETF:IWVL 117 IWVL
|
||||
2024-12-01 balance Assets:Invest:Fixed:R4RF 1505.44135 R4RF
|
||||
2024-12-01 balance Assets:Invest:ETF:XDEQ 70 XDEQ
|
||||
2024-12-01 balance Assets:Invest:Fund:Vanguard:EMMK 14.99 VANEMMK
|
||||
2024-12-01 balance Assets:Invest:Fund:Vanguard:GL 688.32 VANGL
|
||||
2024-12-01 balance Assets:Invest:Fund:Vanguard:SMCAP 48.28 VANSMCAP
|
||||
2024-12-01 balance Assets:Invest:ETF:IWVL 117 IWVL
|
||||
2024-12-01 balance Assets:Invest:Fixed:R4RF 1505.44135 R4RF
|
||||
2024-12-01 balance Assets:Invest:ETF:XDEQ 70 XDEQ
|
||||
2024-12-01 balance Assets:Benefits:Edenred:TicketsRestaurant 37.68 EUR
|
||||
2024-12-01 balance Assets:Benefits:Edenred:TargetaTransport 94.50 EUR
|
||||
2024-12-01 balance Assets:Benefits:DZP:PPEZurich 2971.29 EUR
|
||||
@@ -40,7 +40,7 @@
|
||||
Expenses:MarcaPersonal 1.43 EUR
|
||||
Assets:Liquid:Caixabank:Corrent
|
||||
2024-12-02 * "Renta 4" "Compra de VANGUARD GLOBAL STOCK INDEX (EUR) ACC"
|
||||
Assets:Invest:Fund:Vanguard:GL 18.93 VANGL {52.8324 EUR}
|
||||
Assets:Invest:Fund:Vanguard:GL 18.93 VANGL {52.8324 EUR}
|
||||
Assets:Liquid:R4:EUR -1000 EUR
|
||||
Income:Invest:R4:CapitalGains
|
||||
2024-12-03 * "Aigues de Barcelona" "Factura aigua"
|
||||
@@ -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: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:Fixed:R4RF 1505.44135 R4RF
|
||||
2025-01-01 balance Assets:Invest:ETF:XDEQ 70 XDEQ
|
||||
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 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
|
||||
|
||||
Reference in New Issue
Block a user