From 2e8a0b4bdf3c67fec786197f8204ed8c5a03cb3e Mon Sep 17 00:00:00 2001 From: gcoue Date: Sat, 13 Jan 2024 16:50:52 +0100 Subject: [PATCH] fix(fetch): change credit card to negative amount (#147) * Change credit card to negative amount * Rollback source_finary.py * Change credit card to negative amount * [pre-commit.ci lite] apply automatic fixes * Add a flag to allow the potfolio restitution for each simulation step * Add a flag to allow the potfolio restitution for each simulation step * fix: correct the recurrence function to be more precise on Yearly recurrence * [pre-commit.ci lite] apply automatic fixes * style: minor refactoring --- finalynx/assistant.py | 16 +++++++++------- finalynx/fetch/source_finary.py | 14 ++++++++++---- finalynx/simulator/recurrence.py | 3 ++- finalynx/simulator/timeline.py | 2 +- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/finalynx/assistant.py b/finalynx/assistant.py index 606cbaf..ee80193 100644 --- a/finalynx/assistant.py +++ b/finalynx/assistant.py @@ -93,9 +93,6 @@ def __init__( self.buckets = buckets if buckets else [] self.envelopes = envelopes if envelopes else [] - # Storage for value of portfolio at each intermediate step - self.intermediate_value = [] - # Options that can either be set in the constructor or from the command line options, see --help self.ignore_orphans = ignore_orphans self.clear_cache = clear_cache @@ -128,6 +125,9 @@ def __init__( # Initialize the simulation timeline with the initial user events self._timeline = Timeline(simulation, self.portfolio, self.buckets) if simulation else None + # Store the portfolio renders for each simulation date (if enabled) + self._timeline_renders: List[Any] = [] + def add_source(self, source: SourceBaseLine) -> None: """Register a source, either defined in your own config or from the available Finalynx sources using `from finalynx.fetch.source_any import SourceAny`.""" @@ -241,9 +241,9 @@ def run(self) -> None: # Add the simulation summary to the performance panel in the console dict_panels["performance"].add(self.simulate()) - # If enabled by the user, print the each_step portfolio during the simulation + # If enabled by the user, print the portfolio at each simulation date if self.simulation.print_each_step: - for element in self.intermediate_value: + for element in self._timeline_renders: renders.append(element) # If enabled by the user, print the final portfolio after the simulation @@ -311,11 +311,13 @@ def append_worth(year: int, amount: float) -> None: self._timeline.goto(date(year, 12, 31)) if (year - date.today().year) % self.simulation.step_years == 0: + # Append the portfolio's worth to the Worth tree append_worth(year, self.portfolio.get_amount()) + + # Render each intermediate simulation step if self.simulation.print_each_step: - # Storage for each intermediate simulation step title = "Your portfolio in [bold]" + str(year) + "-12-31:[/]" - self.intermediate_value.append(Panel(self.render_mainframe(), title=title)) + self._timeline_renders.append(Panel(self.render_mainframe(), title=title)) # Run until the end date and append the final result self._timeline.run() diff --git a/finalynx/fetch/source_finary.py b/finalynx/fetch/source_finary.py index 55e7085..afb9870 100644 --- a/finalynx/fetch/source_finary.py +++ b/finalynx/fetch/source_finary.py @@ -84,7 +84,10 @@ def _authenticate(self) -> Optional[Session]: if os.path.exists(finary_uapi.constants.COOKIE_FILENAME): os.remove(finary_uapi.constants.COOKIE_FILENAME) if os.path.exists(finary_uapi.constants.CREDENTIAL_FILE): - if not Confirm.ask("Reuse saved credentials? Otherwise, they will also be deleted.", default=True): + if not Confirm.ask( + "Reuse saved credentials? Otherwise, they will also be deleted.", + default=True, + ): os.remove(finary_uapi.constants.CREDENTIAL_FILE) # Get the user credentials if there's no session yet (through environment variables or manual input) @@ -171,7 +174,10 @@ def _fetch_data(self, tree: Tree) -> None: raise ValueError("Finary signin failed.") # Call the API and parse the response into `FetchLine` instances - with console.status(f"[bold {TH().ACCENT}]Fetching investments from Finary...", spinner_style=TH().ACCENT): + with console.status( + f"[bold {TH().ACCENT}]Fetching investments from Finary...", + spinner_style=TH().ACCENT, + ): response = ff.get_holdings_accounts(session) if response["message"] == "OK": for dict_account in response["result"]: @@ -182,11 +188,11 @@ def _process_account(self, dict_account: Dict[str, Any], tree: Tree) -> None: node = tree.add(account_name if not dict_account["fiats"] else dict_account["institution"]["name"]) for item in dict_account["fiats"]: - subtype = dict_account["bank_account_type"]["subtype"] - if subtype == "credit": + if dict_account["bank_account_type"]["subtype"] == "credit": amount = -item["display_current_value"] else: amount = item["display_current_value"] + self._register_fetchline( tree_node=node, name=account_name, diff --git a/finalynx/simulator/recurrence.py b/finalynx/simulator/recurrence.py index a0d372c..fd0f747 100644 --- a/finalynx/simulator/recurrence.py +++ b/finalynx/simulator/recurrence.py @@ -36,7 +36,8 @@ def __init__( months = months if months is not None else 0 years = years if years is not None else 0 - self._delta = timedelta(days, weeks=4 * months + 52 * years) + # Add decimals to stay on the same day (otherwise Yearly goes to 30/12) + self._delta = timedelta(days, weeks=4.3452 * months + 52.1429 * years + 0.1429) def _next_date(self, current_date: date) -> date: return current_date + self._delta diff --git a/finalynx/simulator/timeline.py b/finalynx/simulator/timeline.py index 1f4fdb6..7651074 100644 --- a/finalynx/simulator/timeline.py +++ b/finalynx/simulator/timeline.py @@ -41,7 +41,7 @@ class Simulation: # Whether to print the final portfolio state in the console after the simulation print_final: bool = False - # Whether to print the portfolio state in the console on each step of the simulation + # Whether to print the final portfolio state in the console after the simulation print_each_step: bool = False # Display the portfolio's worth in the console every `step` years