#!/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, sub, mul, add from math import floor 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 print_report(date, positions): print(f"{bcolors.BOLD}Portfolio (date={date}){bcolors.ENDC}") draw_line() print(f"{bcolors.BOLD}Positions{bcolors.ENDC}") print(tabulate(map(lambda p: [ p.account, p.volume.average().get_only_position().units.number.__round__(2), f"{p.volume.average().get_only_position().cost.number.__round__(2)} {p.volume.average().get_only_position().cost.currency}", f"{p.position.get_only_position().units.number.__round__(2)} {p.position.get_only_position().units.currency}"], positions) , headers=["Actiu", "Quantitat", "Últim preu", "Valor"])) total = Amount(Decimal(0), 'EUR') for p in positions: total = add(total, p.position.get_only_position().units) print(tabulate([ ["Total", "", "", f"{total.number.__round__(2)} {total.currency}"] ])) print(f"{bcolors.BOLD}Plusvalias / Minusvalias{bcolors.ENDC}") print(f"{bcolors.BOLD}Distribució geografica / sectors{bcolors.ENDC}") print(f"{bcolors.BOLD}Indicadors{bcolors.ENDC}") print(tabulate([ ["Alfa", 1], ["Beta", 1] ])) def get_positions(entries, options, date): balance_query = f"SELECT account, sum(position) as volume, convert(sum(position), \"EUR\") as position FROM date <= {date} WHERE account ~ '^Assets:Invest' GROUP BY account" rtypes, rrows = query.run_query( entries, options, balance_query) return rrows def main(): parser = argparse.ArgumentParser(description='Generate portfolio 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) positions = get_positions(entries, options, date) print_report(date, positions) main()