From 2ad91e5796581882bdf9d8090b8414a24d16be31 Mon Sep 17 00:00:00 2001 From: ceroma <678940+ceroma@users.noreply.github.com> Date: Wed, 2 Oct 2024 06:59:57 -0300 Subject: [PATCH] Feature/optimize portfolio calculations with smarter date interval selection (#3829) * Optimize portfolio calculations with smarter date interval selection * Update changelog --- CHANGELOG.md | 1 + .../calculator/twr/portfolio-calculator.ts | 42 ++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78862da6d..92f82935a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Optimized the portfolio calculations with smarter date interval selection - Improved the language localization for German (`de`) ## 2.111.0 - 2024-09-28 diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts index 3b64cd185..f5e301cba 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts @@ -16,13 +16,14 @@ import { addDays, addMilliseconds, differenceInDays, - eachDayOfInterval, format, isBefore } from 'date-fns'; import { cloneDeep, first, last, sortBy } from 'lodash'; export class TWRPortfolioCalculator extends PortfolioCalculator { + private chartDatesDescending: string[]; + protected calculateOverallPerformance( positions: TimelinePosition[] ): PortfolioSnapshot { @@ -820,31 +821,35 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { startDate = start; } + const endDateString = format(endDate, DATE_FORMAT); + const startDateString = format(startDate, DATE_FORMAT); + const currentValuesAtDateRangeStartWithCurrencyEffect = - currentValuesWithCurrencyEffect[format(startDate, DATE_FORMAT)] ?? - new Big(0); + currentValuesWithCurrencyEffect[startDateString] ?? new Big(0); const investmentValuesAccumulatedAtStartDateWithCurrencyEffect = - investmentValuesAccumulatedWithCurrencyEffect[ - format(startDate, DATE_FORMAT) - ] ?? new Big(0); + investmentValuesAccumulatedWithCurrencyEffect[startDateString] ?? + new Big(0); const grossPerformanceAtDateRangeStartWithCurrencyEffect = currentValuesAtDateRangeStartWithCurrencyEffect.minus( investmentValuesAccumulatedAtStartDateWithCurrencyEffect ); - const dates = eachDayOfInterval({ - end: endDate, - start: startDate - }).map((date) => { - return format(date, DATE_FORMAT); - }); - let average = new Big(0); let dayCount = 0; - for (const date of dates) { + if (!this.chartDatesDescending) { + this.chartDatesDescending = Object.keys(chartDateMap).sort().reverse(); + } + + for (const date of this.chartDatesDescending) { + if (date > endDateString) { + continue; + } else if (date < startDateString) { + break; + } + if ( investmentValuesAccumulatedWithCurrencyEffect[date] instanceof Big && investmentValuesAccumulatedWithCurrencyEffect[date].gt(0) @@ -864,17 +869,14 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { } netPerformanceWithCurrencyEffectMap[dateRange] = - netPerformanceValuesWithCurrencyEffect[ - format(endDate, DATE_FORMAT) - ]?.minus( + netPerformanceValuesWithCurrencyEffect[endDateString]?.minus( // If the date range is 'max', take 0 as a start value. Otherwise, // the value of the end of the day of the start date is taken which // differs from the buying price. dateRange === 'max' ? new Big(0) - : (netPerformanceValuesWithCurrencyEffect[ - format(startDate, DATE_FORMAT) - ] ?? new Big(0)) + : (netPerformanceValuesWithCurrencyEffect[startDateString] ?? + new Big(0)) ) ?? new Big(0); netPerformancePercentageWithCurrencyEffectMap[dateRange] = average.gt(0)