Files
contabilitat/commands/investments
2024-12-28 19:32:44 +01:00

124 lines
4.7 KiB
Python
Executable File

#!/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()