diff --git a/pypmanager/const.py b/pypmanager/const.py new file mode 100644 index 00000000..8c3bb14c --- /dev/null +++ b/pypmanager/const.py @@ -0,0 +1,3 @@ +"""Constants.""" + +NUMBER_FORMATTER = ",.0f" diff --git a/pypmanager/holding.py b/pypmanager/holding.py index 7eb4978a..7e7cebfc 100644 --- a/pypmanager/holding.py +++ b/pypmanager/holding.py @@ -1,10 +1,12 @@ """Handle securities.""" from dataclasses import dataclass from datetime import date +from typing import cast import numpy as np import pandas as pd +from pypmanager.const import NUMBER_FORMATTER from pypmanager.data_loader import TransactionTypeValues from pypmanager.security import MutualFund @@ -18,15 +20,15 @@ def _calculate_aggregates(data: pd.DataFrame, security_name: str) -> pd.DataFram df["realized_pnl"] = 0.0 df["cumulative_invested_amount"] = 0.0 - cumulative_buy_amount = 0.0 - cumulative_buy_volume = 0.0 - cumulative_invested_amount = 0.0 - average_price = 0.0 + cumulative_buy_amount: float = 0.0 + cumulative_buy_volume: float | None = 0.0 + cumulative_invested_amount: float = 0.0 + average_price: float | None = 0.0 for index, row in df.iterrows(): - amount = abs(row["amount"]) - no_traded = abs(row["no_traded"]) - commission = abs(row["commission"]) + amount = cast(float, abs(row["amount"])) + no_traded = cast(float, abs(row["no_traded"])) + commission = cast(float, abs(row["commission"])) if row["transaction_type"] == TransactionTypeValues.BUY.value: cumulative_buy_volume += no_traded @@ -177,3 +179,30 @@ def invested_amount(self) -> float | None: return None return self.average_price * self.current_holdings + + @property + def cli_table_row(self) -> list[str]: + """Represent the holding for CLI reports.""" + invested_amount = ( + f"{self.invested_amount:{NUMBER_FORMATTER}}" + if self.invested_amount + else None + ) + + current_holdings = ( + f"{self.current_holdings:{NUMBER_FORMATTER}}" + if self.current_holdings + else None + ) + + return [ + self.name, + invested_amount, + current_holdings, + f"{self.current_price}", + f"{self.date_market_value}", + f"{self.total_pnl:{NUMBER_FORMATTER}}", + f"{self.realized_pnl:{NUMBER_FORMATTER}}", + f"{self.unrealized_pnl:{NUMBER_FORMATTER}}", + f"{self.total_transactions}", + ] diff --git a/pypmanager/portfolio.py b/pypmanager/portfolio.py index 9039314e..a13c97a8 100644 --- a/pypmanager/portfolio.py +++ b/pypmanager/portfolio.py @@ -3,6 +3,7 @@ from dataclasses import dataclass +from pypmanager.const import NUMBER_FORMATTER from pypmanager.holding import Holding @@ -40,3 +41,18 @@ def unrealized_pnl(self) -> float: return sum( s.unrealized_pnl for s in self.holdings if s.unrealized_pnl is not None ) + + @property + def cli_table_row_total(self) -> list[str]: + """Represent totals for CLI reports.""" + return [ + "Total", + f"{self.invested_amount:{NUMBER_FORMATTER}}", + "", + "", + "", + f"{self.total_pnl:{NUMBER_FORMATTER}}", + f"{self.unrealized_pnl:{NUMBER_FORMATTER}}", + f"{self.realized_pnl:{NUMBER_FORMATTER}}", + "", + ] diff --git a/pypmanager/reports/cmd_line.py b/pypmanager/reports/cmd_line.py index d4b13d56..677a520a 100644 --- a/pypmanager/reports/cmd_line.py +++ b/pypmanager/reports/cmd_line.py @@ -5,8 +5,6 @@ from pypmanager.holding import Holding from pypmanager.portfolio import Portfolio -NUMBER_FORMATTER = ",.0f" - TABLE_HEADER = [ "Name", "Invested", @@ -34,46 +32,10 @@ def print_pretty_table(holdings: list[Holding]) -> None: table.align["Name"] = "l" for security_data in sorted_holdings: - invested_amount = ( - f"{security_data.invested_amount:{NUMBER_FORMATTER}}" - if security_data.invested_amount - else None - ) - - current_holdings = ( - f"{security_data.current_holdings:{NUMBER_FORMATTER}}" - if security_data.current_holdings - else None - ) - - table.add_row( - [ - security_data.name, - invested_amount, - current_holdings, - f"{security_data.current_price}", - f"{security_data.date_market_value}", - f"{security_data.total_pnl:{NUMBER_FORMATTER}}", - f"{security_data.realized_pnl:{NUMBER_FORMATTER}}", - f"{security_data.unrealized_pnl:{NUMBER_FORMATTER}}", - f"{security_data.total_transactions}", - ], - ) + table.add_row(security_data.cli_table_row) portfolio = Portfolio(holdings=holdings) - table.add_row( - [ - "Total", - f"{portfolio.invested_amount:{NUMBER_FORMATTER}}", - "", - "", - "", - f"{portfolio.total_pnl:{NUMBER_FORMATTER}}", - f"{portfolio.unrealized_pnl:{NUMBER_FORMATTER}}", - f"{portfolio.realized_pnl:{NUMBER_FORMATTER}}", - "", - ], - ) + table.add_row(portfolio.cli_table_row_total) print(table)