diff --git a/commands/balance-sheet b/commands/balance-sheet
index d09513c..d7be5ed 100755
--- a/commands/balance-sheet
+++ b/commands/balance-sheet
@@ -26,7 +26,7 @@ def draw_line():
print('─' * 30)
-def get_last_month_timestamps(date):
+def get_month_to_date_timestamps(date):
month = int(date.split("-")[1])
year = int(date.split("-")[0])
d = datetime(year, month, 1)
@@ -35,6 +35,14 @@ def get_last_month_timestamps(date):
return start_date, end_date.strftime("%Y-%m-%d")
+def get_last_year_timestamps(date):
+ date_parts = date.split("-")
+ day = int(date_parts[2])
+ month = int(date_parts[1])
+ year = int(date_parts[0])
+ return f"{year-1}-{month:02d}-{day:02d}", date
+
+
def get_sum_balances(balances, account_prefix):
sum = 0
for account, balance in balances.items():
@@ -64,7 +72,8 @@ def get_debt_to_assets_ratio(balances, max):
def get_emergency_fund_ratio(balances, expenses, low, mid):
liquid = 0
- living_expenses = expenses[0].position.get_only_position().units.number
+ living_expenses = expenses[0].position.get_only_position(
+ ).units.number / 12
for account, balance in balances.items():
if account.startswith("Assets:Liquid"):
liquid = balance if liquid == 0 else liquid + balance
@@ -72,7 +81,7 @@ def get_emergency_fund_ratio(balances, expenses, low, mid):
) == None else liquid.get_only_position().units
result = round(total_liquid.number / living_expenses, 2)
color = bcolors.FAIL if result < low else bcolors.OKGREEN if result > mid else bcolors.WARNING
- return f"{color}{result}{bcolors.ENDC}"
+ return f"{color}{result} mth{bcolors.ENDC}"
def get_investment_assets_to_net_worth_ratio(balances, min):
@@ -95,18 +104,19 @@ def get_liquid_assets_to_net_worth_ratio(balances, min):
return f"{bcolors.FAIL if result < min else bcolors.OKGREEN}{result} %{bcolors.ENDC}"
-def get_savings_ratio(balances, gross_monthly_income, monthly_savings, min):
- result = round((monthly_savings.number / gross_monthly_income) * 100, 2)
+def get_savings_ratio(balances, net_yearly_income, yearly_savings, min):
+ result = round((yearly_savings.number /
+ net_yearly_income) * 100, 2)
return f"{bcolors.FAIL if result < min else bcolors.OKGREEN}{result} %{bcolors.ENDC}"
-def get_debt_service_ratio(balances, gross_monthly_income, debt_payments, max):
- result = round((debt_payments.number / gross_monthly_income) * 100, 2)
+def get_debt_service_ratio(balances, net_yearly_income, debt_payments, max):
+ result = round((debt_payments.number / net_yearly_income) * 100, 2)
return f"{bcolors.FAIL if result >= max else bcolors.OKGREEN}{result} %{bcolors.ENDC}"
-def get_non_mortgage_debt_service_ratio(balances, gross_monthly_income, mortgage_payments, max):
- result = round((mortgage_payments.number / gross_monthly_income) * 100, 2)
+def get_non_mortgage_debt_service_ratio(balances, net_yearly_income, mortgage_payments, max):
+ result = round((mortgage_payments.number / net_yearly_income) * 100, 2)
return f"{bcolors.FAIL if result >= max else bcolors.OKGREEN}{result} %{bcolors.ENDC}"
@@ -117,11 +127,11 @@ def get_solvency_ratio(balances, min):
return f"{bcolors.FAIL if result < min else bcolors.OKGREEN}{result} %{bcolors.ENDC}"
-def get_interest_coverage_ratio(gross_monthly_income, expenses, debt_payments, mortgage_payments, min):
+def get_interest_coverage_ratio(net_monthly_income, expenses, debt_payments, mortgage_payments, min):
living_expenses = expenses[0].position.get_only_position().units.number
interest = debt_payments.number + mortgage_payments.number
interest = interest if interest > 0 else 1
- result = round((gross_monthly_income - living_expenses) / interest, 2)
+ result = round((net_monthly_income - living_expenses) / interest, 2)
return f"{bcolors.FAIL if result < min else bcolors.OKGREEN}{result}{bcolors.ENDC}"
@@ -138,7 +148,7 @@ def get_position_as_str(inventory):
return Amount(Decimal(round(position.units.number, 2)), position.units.currency).to_string()
-def print_report(date, balances, expenses, income, debt_payments, mortgage_payments, savings):
+def print_report(date, balances, expenses, net_monthly_income, net_yearly_income, debt_payments, mortgage_payments, savings):
print(f"{bcolors.BOLD}Balance Sheet (date={date}){bcolors.ENDC}")
draw_line()
print(f"{bcolors.BOLD}Assets{bcolors.ENDC}")
@@ -202,8 +212,10 @@ def print_report(date, balances, expenses, income, debt_payments, mortgage_payme
balances["Liabilities:Hipoteca:VivendaPrincipal"] * Decimal(-1))],
["Hipoteques en vivenda d'inversió",
Amount(Decimal(0), "EUR").to_string()],
- ["Crèdit", get_position_as_str(
+ ["Targetes de crèdit", get_position_as_str(
balances["Liabilities:Credit:Caixabank:TargetaCredit"] * Decimal(-1))],
+ ["Línies de crèdit per inversió", get_position_as_str(
+ balances["Liabilities:Credit:Renta4:PolissaCredit"] * Decimal(-1))],
["Factures impagades", get_position_as_str(
balances["Liabilities:Factures:FacturesPendents"] * Decimal(-1))],
["Préstecs personals", Amount(Decimal(0), "EUR").to_string()],
@@ -225,19 +237,19 @@ def print_report(date, balances, expenses, income, debt_payments, mortgage_payme
["Debt-to-Assets Ratio",
get_debt_to_assets_ratio(balances, 50), "50 %"],
["Emergency Fund", get_emergency_fund_ratio(
- balances, expenses, 3, 6), "3-6"],
+ balances, expenses, 3, 6), "3-6 mth"],
["Investment Assets to Net Worth Ratio",
get_investment_assets_to_net_worth_ratio(balances, 50), "50 %"],
["Liquid Assets to Net Worth Ratio",
get_liquid_assets_to_net_worth_ratio(balances, 15), "15 %"],
["Savings Ratio", get_savings_ratio(
- balances, income, savings, 20), "20 %"],
+ balances, net_yearly_income, savings, 20), "20 %"],
["Debt-Service Ratio",
- get_debt_service_ratio(balances, income, debt_payments, 35), "35 %"],
+ get_debt_service_ratio(balances, net_yearly_income, debt_payments, 35), "35 %"],
["Non-Mortgage Debt-Service Ratio",
- get_non_mortgage_debt_service_ratio(balances, income, mortgage_payments, 15), "15 %"],
+ get_non_mortgage_debt_service_ratio(balances, net_yearly_income, mortgage_payments, 15), "15 %"],
["Interest Coverage Ratio", get_interest_coverage_ratio(
- income, expenses, debt_payments, mortgage_payments, 1.5), "1.5"]
+ net_yearly_income, expenses, debt_payments, mortgage_payments, 1.5), "1.5"]
]))
@@ -253,7 +265,7 @@ def get_balances(entries, options, date):
def get_expenses(entries, options, date):
- start_date, end_date = get_last_month_timestamps(date)
+ start_date, end_date = get_last_year_timestamps(date)
expenses_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
end_date} WHERE account ~ 'Expenses:' AND date >= {start_date}"
rtypes, rrows = query.run_query(
@@ -262,17 +274,27 @@ def get_expenses(entries, options, date):
def get_income(entries, options, date):
- start_date, end_date = get_last_month_timestamps(date)
+ start_date, end_date = get_month_to_date_timestamps(date)
income_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
end_date} WHERE account ~ '^(Income:Work|Income:Savings|Income:Invest)' AND date >= {start_date}"
rtypes, rrows = query.run_query(
entries, options, income_query)
- return rrows
+ net_monthly_income = rrows[0].position.get_only_position(
+ ).units.number * -1
+
+ start_date, end_date = get_last_year_timestamps(date)
+ income_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
+ end_date} WHERE account ~ '^(Income:Work|Income:Savings|Income:Invest)' AND date >= {start_date}"
+ rtypes, rrows = query.run_query(
+ entries, options, income_query)
+ net_yearly_income = rrows[0].position.get_only_position(
+ ).units.number * -1
+ return net_monthly_income, net_yearly_income
def get_debt_payments(entries, options, date):
# FIX: Agafar nomes els pagaments de deute, enlloc de també les addicions de deute
- start_date, end_date = get_last_month_timestamps(date)
+ start_date, end_date = get_last_year_timestamps(date)
debt_payments_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
end_date} WHERE account ~ 'Expenses:R4:Interessos' AND date >= {start_date}"
mortgage_payments_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
@@ -289,13 +311,20 @@ def get_debt_payments(entries, options, date):
def get_savings(entries, options, date):
- start_date, end_date = get_last_month_timestamps(date)
- savings_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
+ start_date, end_date = get_last_year_timestamps(date)
+ investments_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
end_date} WHERE account ~ '^Assets:Invest:' AND date >= {start_date}"
rtypes, rrows = query.run_query(
- entries, options, savings_query)
+ entries, options, investments_query)
result = rrows[0].position.get_only_position().units if len(
rrows) > 0 else Amount(Decimal(0), "EUR")
+ liabilities_query = f"SELECT convert(sum(position), \"EUR\") as position FROM date <= {
+ end_date} WHERE account ~ '^Liabilities:Credit:Renta4:' AND date >= {start_date}"
+ rtypes, rrows = query.run_query(
+ entries, options, liabilities_query)
+ liabilities = rrows[0].position.get_only_position().units if len(
+ rrows) > 0 else Amount(Decimal(0), "EUR")
+ result = add(result, liabilities)
return result
@@ -316,13 +345,12 @@ def main():
balances = get_balances(entries, options, date)
expenses = get_expenses(entries, options, date)
- income = get_income(entries, options, date)
- gross_monthly_income = income[0].position.get_only_position(
- ).units.number * -1
+ net_monthly_income, net_yearly_income = get_income(
+ entries, options, date)
debt_payments, mortgage_payments = get_debt_payments(
entries, options, date)
savings = get_savings(entries, options, date)
- print_report(date, balances, expenses, gross_monthly_income,
+ print_report(date, balances, expenses, net_monthly_income, net_yearly_income,
debt_payments, mortgage_payments, savings)
diff --git a/ledger/transactions/2025/12.beancount b/ledger/transactions/2025/12.beancount
index 6641f99..f4f57ce 100644
--- a/ledger/transactions/2025/12.beancount
+++ b/ledger/transactions/2025/12.beancount
@@ -127,8 +127,37 @@
2025-12-14 * "La Marató" "Donació La Marató de TV3"
Expenses:Donatiu 20 EUR
Assets:Liquid:Caixabank:Corrent
+2025-12-14 * "Miquel Albareda" "Factures novembre"
+ Income:Other:Caixabank:Transferencia -49.23 EUR
+ Assets:Liquid:Caixabank:Corrent 49.23 EUR
+ Expenses:FacturesUtilitats -49.23 EUR
+ Equity:FacturesUtilitatsMiquel 49.23 EUR
+2025-12-15 * "Plusfresc" "Compra de la setmana"
+ Expenses:Supermercat 30.09 EUR
+ Assets:Liquid:Caixabank:Corrent
+2025-12-18 * "Naturgy" "Factura gas"
+ Expenses:FacturesUtilitats 29.66 EUR
+ Assets:Liquid:Caixabank:Corrent
+2025-12-18 * "Don Zangano" "Esmorzar"
+ Expenses:MenjarFora 5.10 EUR
+ Assets:Benefits:Edenred:TicketsRestaurant
+2025-12-18 * "Aerobus" "Bitllet anada i tornada aeroport"
+ Expenses:Mobilitat 12.85 EUR
+ Assets:Benefits:Edenred:TargetaTransport
+2025-12-18 * "Burger King" "Sopar aeroport"
+ Expenses:MenjarFora 12.15 EUR
+ Assets:Benefits:Edenred:TicketsRestaurant
+2025-12-19 * "TradeRepublic" "Tancament compte TradeRepublic"
+ Income:Savings:TradeRepublic:RentabilitatEstalvis -0.01 EUR
+ Assets:Liquid:Caixabank:Corrent
+2025-12-20 * "Amazon" "Valissa DGT"
+ Expenses:Altres 41.99 EUR
+ Assets:Liquid:Caixabank:Corrent
+2025-12-20 * "Che Argentino" "Sopar asador argentino palma"
+ Expenses:MenjarFora 51.70 EUR
+ Assets:Benefits:Edenred:TicketsRestaurant
-2026-01-01 balance Assets:Liquid:Caixabank:Corrent 11919.33 EUR
+2026-01-01 balance Assets:Liquid:Caixabank:Corrent 11866.83 EUR
2026-01-01 balance Assets:Liquid:R4:EUR 0 EUR
2026-01-01 balance Assets:Invest:Fund:Vanguard:EMMK 14.99 VANEMMK
2026-01-01 balance Assets:Invest:Fund:Vanguard:GL 776.93 VANGL
@@ -136,8 +165,8 @@
2026-01-01 balance Assets:Invest:ETF:IWVL 430 IWVL
2026-01-01 balance Assets:Invest:Fixed:R4RF 1518.57004 R4RF
2026-01-01 balance Assets:Invest:ETF:XDEQ 264 XDEQ
-2026-01-01 balance Assets:Benefits:Edenred:TicketsRestaurant 114.87 EUR
-2026-01-01 balance Assets:Benefits:Edenred:TargetaTransport 76.50 EUR
+2026-01-01 balance Assets:Benefits:Edenred:TicketsRestaurant 45.92 EUR
+2026-01-01 balance Assets:Benefits:Edenred:TargetaTransport 63.65 EUR
2026-01-01 balance Assets:Benefits:DZP:PPEZurich 4048.45 EUR
2026-01-01 balance Assets:PersonalProperty:VivendaPrincipal 0 EUR
2026-01-01 balance Assets:PersonalProperty:Cotxe 8174 EUR
diff --git a/reports/balance-sheet-report-2025-12-21.txt b/reports/balance-sheet-report-2025-12-21.txt
new file mode 100644
index 0000000..7bcbb03
--- /dev/null
+++ b/reports/balance-sheet-report-2025-12-21.txt
@@ -0,0 +1,71 @@
+[1mBalance Sheet (date=2025-12-21)[0m
+──────────────────────────────
+[1mAssets[0m
+ [1mLiquids[0m
+----------------- ------------
+Corrent 11866.83 EUR
+Estalvi 0 EUR
+Compte d'inversió 0 EUR
+Total líquids 11866.83 EUR
+----------------- ------------
+ [1mInversions[0m
+---------------- -------------
+Fons d'inversió 70353.30 EUR
+ETFs 39129.40 EUR
+Accions 0 EUR
+Renta fixa 23712.25 EUR
+Total inversions 133194.95 EUR
+---------------- -------------
+ [1mPropietat personal[0m
+---------------------------- -----------
+Vivenda principal 0 EUR
+Cotxes 8174.00 EUR
+Joies, Art, Col·leccionables 50.00 EUR
+Metalls preciosos 0 EUR
+Altres propietats 0 EUR
+Total propietats 8224.00 EUR
+---------------------------- -----------
+ [1mDeutes[0m
+----------------- -----
+Deutes per cobrar
+Total deutes 0 EUR
+----------------- -----
+ [1mBeneficis laborals[0m
+----------------------------- -----------
+Tickets Restaurant 45.92 EUR
+Targeta Transport 63.65 EUR
+Pla Pensions Empleados Zurich 4048.45 EUR
+Total beneficis 4158.02 EUR
+----------------------------- -----------
+------------ -------------
+[1mTotal Assets 157443.80 EUR
+------------ -------------
+──────────────────────────────
+[1mLiabilites[0m
+-------------------------------- ------------
+Hipoteques en vivenda principal
+Hipoteques en vivenda d'inversió 0 EUR
+Targetes de crèdit 445.91 EUR
+Línies de crèdit per inversió 19971.26 EUR
+Factures impagades
+Préstecs personals 0 EUR
+Impostos no pagats
+Altres passius 0 EUR
+-------------------------------- ------------
+------------- -------------
+[1mTotal passius[0m [1m-20417.17 EUR[0m
+------------- -------------
+──────────────────────────────
+[1mNet Worth 137026.63 EUR[0m
+──────────────────────────────
+[1mFinancial Ratios[0m
+------------------------------------ -------- -------
+Debt-to-Assets Ratio [92m12.97 %[0m 50 %
+Emergency Fund [93m4.18 mth[0m 3-6 mth
+Investment Assets to Net Worth Ratio [92m97.20 %[0m 50 %
+Liquid Assets to Net Worth Ratio [92m105.86 %[0m 15 %
+Savings Ratio [92m35.58 %[0m 20 %
+Debt-Service Ratio [92m0.96 %[0m 35 %
+Non-Mortgage Debt-Service Ratio [92m0.00 %[0m 15 %
+Interest Coverage Ratio [92m33.34[0m 1.5
+------------------------------------ -------- -------
diff --git a/reports/balsheet/20231217/balsheet.html b/reports/balsheet/20231217/balsheet.html
deleted file mode 100644
index 51f490c..0000000
--- a/reports/balsheet/20231217/balsheet.html
+++ /dev/null
@@ -1,259 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Assets
-
-
-
-| Account |
-EUR |
-Other |
-
-
-
-| Assets |
- |
- |
-
-
-| Assets:Benefits |
- |
- |
-
-
-| Assets:Benefits:Edenred |
- |
- |
-
-
-| Assets:Benefits:Edenred:TarjetaTransport |
-40 |
- |
-
-
-| Assets:Benefits:Edenred:TicketsRestaurant |
-209 |
- |
-
-
-| Assets:Debt |
- |
- |
-
-
-| Assets:Debt:DeutesPerCobrar |
- |
- |
-
-
-| Assets:Invest |
- |
- |
-
-
-| Assets:Invest:R4 |
- |
- |
-
-
-| Assets:Invest:R4:Amundi |
- |
- |
-
-
-| Assets:Invest:Fund:Amundi:MSCIWRLD |
-20436.50810 |
- |
-
-
-| Assets:Invest:Fund:Amundi:SUSTINC |
-709.77780 |
- |
-
-
-| Assets:Invest:R4:BNP |
- |
- |
-
-
-| Assets:Invest:Fund:BNP:DISTECH |
- |
-788.20245 USD |
-
-
-| Assets:Invest:R4:Fidelity |
- |
- |
-
-
-| Assets:Invest:Fund:Fidelity:GLTECH |
-14143.9382 |
- |
-
-
-| Assets:Invest:Stock:MSFT |
- |
-1367.2 USD |
-
-
-| Assets:Invest:Stock:PLTR |
- |
-160.250 USD |
-
-
-| Assets:Invest:R4:Vanguard |
- |
- |
-
-
-| Assets:Invest:Fund:Vanguard:EMMK |
-2664.81727 |
- |
-
-
-| Assets:Liquid |
- |
- |
-
-
-| Assets:Liquid:Caixabank |
- |
- |
-
-
-| Assets:Liquid:Caixabank:Corrent |
-18903.80 |
- |
-
-
-| Assets:Liquid:Estalvi:Caixabank |
-12666.49 |
- |
-
-
-| Assets:Liquid:R4 |
- |
- |
-
-
-| Assets:Liquid:R4:EUR |
-44.04 |
- |
-
-
-| Assets:PersonalProperty |
- |
- |
-
-
-| Assets:PersonalProperty:AltresPropietats |
- |
- |
-
-
-| Assets:PersonalProperty:Cotxe |
-10000 |
- |
-
-
-| Assets:PersonalProperty:JoiesArtCollecionables |
-1250 |
- |
-
-
-| Assets:PersonalProperty:MetallsPreciosos |
- |
- |
-
-
-| Assets:PersonalProperty:VivendaPrincipal |
- |
- |
-
-
- |
-81068.37137 |
-2315.65245 USD |
-
-
-
-
-
-
-
-
-
-
Liabilities
-
-
-
-| Account |
-EUR |
-Other |
-
-
-
-| Liabilities |
- |
- |
-
-
- |
- |
- |
-
-
-
-
-
-
-
-
Equity
-
-
-
-| Account |
-EUR |
-Other |
-
-
-
-| Equity |
- |
- |
-
-
-| Equity:Opening-Balances |
--80819.37 |
- |
-
-
-| Equity:Opening-Balances:USD |
- |
--2315.652 USD |
-
-
- |
--80819.37 |
--2315.652 USD |
-
-
-
-
-
-
-
-
-
-