From a5833566a8053dc3ae78573feba101626826cb98 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Thu, 2 May 2024 17:52:39 +0200 Subject: [PATCH] Feature/skip caching in portfolio calculator if active filters (#3348) * Skip caching if active filters * Update changelog --- CHANGELOG.md | 4 ++++ .../portfolio-calculator.factory.ts | 8 ++++++-- .../calculator/portfolio-calculator.ts | 20 ++++++++++++------- ...aln-buy-and-sell-in-two-activities.spec.ts | 1 + ...folio-calculator-baln-buy-and-sell.spec.ts | 1 + .../twr/portfolio-calculator-baln-buy.spec.ts | 1 + ...ator-btcusd-buy-and-sell-partially.spec.ts | 1 + .../twr/portfolio-calculator-fee.spec.ts | 1 + .../portfolio-calculator-googl-buy.spec.ts | 1 + .../twr/portfolio-calculator-item.spec.ts | 1 + .../portfolio-calculator-liability.spec.ts | 1 + ...-calculator-msft-buy-with-dividend.spec.ts | 1 + .../portfolio-calculator-no-orders.spec.ts | 1 + ...ulator-novn-buy-and-sell-partially.spec.ts | 1 + ...folio-calculator-novn-buy-and-sell.spec.ts | 1 + .../src/app/portfolio/portfolio.service.ts | 9 ++++++++- .../app/redis-cache/redis-cache.service.ts | 2 +- .../src/events/portfolio-changed.listener.ts | 4 +++- 18 files changed, 47 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f682d51db..50e732acb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added a form validation against the DTO in the platform management of the admin control panel - Added a form validation against the DTO in the tag management of the admin control panel +### Changed + +- Skipped the caching in the portfolio calculator if there are active filters (experimental) + ### Fixed - Fixed an issue in the calculation of the portfolio summary caused by future liabilities diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts index 4937f1008..762415d1e 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts @@ -32,6 +32,7 @@ export class PortfolioCalculatorFactory { calculationType, currency, dateRange = 'max', + hasFilters, isExperimentalFeatures = false, userId }: { @@ -40,9 +41,12 @@ export class PortfolioCalculatorFactory { calculationType: PerformanceCalculationType; currency: string; dateRange?: DateRange; + hasFilters: boolean; isExperimentalFeatures?: boolean; userId: string; }): PortfolioCalculator { + const useCache = !hasFilters && isExperimentalFeatures; + switch (calculationType) { case PerformanceCalculationType.MWR: return new MWRPortfolioCalculator({ @@ -50,7 +54,7 @@ export class PortfolioCalculatorFactory { activities, currency, dateRange, - isExperimentalFeatures, + useCache, userId, configurationService: this.configurationService, currentRateService: this.currentRateService, @@ -64,7 +68,7 @@ export class PortfolioCalculatorFactory { currency, currentRateService: this.currentRateService, dateRange, - isExperimentalFeatures, + useCache, userId, configurationService: this.configurationService, exchangeRateDataService: this.exchangeRateDataService, diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 568969603..e021eb2d4 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -56,14 +56,15 @@ export abstract class PortfolioCalculator { private currency: string; private currentRateService: CurrentRateService; private dataProviderInfos: DataProviderInfo[]; + private dateRange: DateRange; private endDate: Date; private exchangeRateDataService: ExchangeRateDataService; - private isExperimentalFeatures: boolean; private redisCacheService: RedisCacheService; private snapshot: PortfolioSnapshot; private snapshotPromise: Promise; private startDate: Date; private transactionPoints: TransactionPoint[]; + private useCache: boolean; private userId: string; public constructor({ @@ -74,8 +75,8 @@ export abstract class PortfolioCalculator { currentRateService, dateRange, exchangeRateDataService, - isExperimentalFeatures, redisCacheService, + useCache, userId }: { accountBalanceItems: HistoricalDataItem[]; @@ -85,16 +86,16 @@ export abstract class PortfolioCalculator { currentRateService: CurrentRateService; dateRange: DateRange; exchangeRateDataService: ExchangeRateDataService; - isExperimentalFeatures: boolean; redisCacheService: RedisCacheService; + useCache: boolean; userId: string; }) { this.accountBalanceItems = accountBalanceItems; this.configurationService = configurationService; this.currency = currency; this.currentRateService = currentRateService; + this.dateRange = dateRange; this.exchangeRateDataService = exchangeRateDataService; - this.isExperimentalFeatures = isExperimentalFeatures; this.activities = activities .map( @@ -129,6 +130,7 @@ export abstract class PortfolioCalculator { }); this.redisCacheService = redisCacheService; + this.useCache = useCache; this.userId = userId; const { endDate, startDate } = getInterval(dateRange); @@ -1047,11 +1049,13 @@ export abstract class PortfolioCalculator { } private async initialize() { - if (this.isExperimentalFeatures) { + if (this.useCache) { const startTimeTotal = performance.now(); const cachedSnapshot = await this.redisCacheService.get( - this.redisCacheService.getPortfolioSnapshotKey(this.userId) + this.redisCacheService.getPortfolioSnapshotKey({ + userId: this.userId + }) ); if (cachedSnapshot) { @@ -1074,7 +1078,9 @@ export abstract class PortfolioCalculator { ); this.redisCacheService.set( - this.redisCacheService.getPortfolioSnapshotKey(this.userId), + this.redisCacheService.getPortfolioSnapshotKey({ + userId: this.userId + }), JSON.stringify(this.snapshot), this.configurationService.get('CACHE_QUOTES_TTL') ); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts index 422cf8bff..340f16b87 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts @@ -123,6 +123,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts index dee8b2478..53ebdf19f 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts @@ -108,6 +108,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts index db8ce01b3..bab265887 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts @@ -93,6 +93,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts index 5a403eda1..eba5d4674 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts @@ -121,6 +121,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts index 97a77492b..88d7adb71 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts @@ -93,6 +93,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'USD', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts index c916a381d..690f1eb51 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts @@ -106,6 +106,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts index bf212f80b..422d119b2 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts @@ -93,6 +93,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'USD', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts index 3ae63c72a..d468e8e00 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts @@ -93,6 +93,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'USD', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts index 6948b4dbd..094c6cc2e 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts @@ -121,6 +121,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'USD', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts index 1dd74d7e5..6bb432bfc 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts @@ -71,6 +71,7 @@ describe('PortfolioCalculator', () => { activities: [], calculationType: PerformanceCalculationType.TWR, currency: 'CHF', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index d4451503a..f65d2ba61 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -108,6 +108,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts index 7850fb2bd..902f710ee 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -108,6 +108,7 @@ describe('PortfolioCalculator', () => { activities, calculationType: PerformanceCalculationType.TWR, currency: 'CHF', + hasFilters: false, userId: userDummyData.id }); diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 573c48a83..61906982b 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -277,9 +277,11 @@ export class PortfolioService { const portfolioCalculator = this.calculatorFactory.createCalculator({ activities, + dateRange, userId, calculationType: PerformanceCalculationType.TWR, currency: this.request.user.Settings.settings.baseCurrency, + hasFilters: filters?.length > 0, isExperimentalFeatures: this.request.user.Settings.settings.isExperimentalFeatures }); @@ -358,6 +360,7 @@ export class PortfolioService { userId, calculationType: PerformanceCalculationType.TWR, currency: userCurrency, + hasFilters: filters?.length > 0, isExperimentalFeatures: this.request.user?.Settings.settings.isExperimentalFeatures }); @@ -660,6 +663,7 @@ export class PortfolioService { }), calculationType: PerformanceCalculationType.TWR, currency: userCurrency, + hasFilters: true, isExperimentalFeatures: this.request.user.Settings.settings.isExperimentalFeatures }); @@ -931,6 +935,7 @@ export class PortfolioService { userId, calculationType: PerformanceCalculationType.TWR, currency: this.request.user.Settings.settings.baseCurrency, + hasFilters: filters?.length > 0, isExperimentalFeatures: this.request.user.Settings.settings.isExperimentalFeatures }); @@ -1085,7 +1090,7 @@ export class PortfolioService { ) ); - const { endDate, startDate } = getInterval(dateRange); + const { endDate } = getInterval(dateRange); const { activities } = await this.orderService.getOrders({ endDate, @@ -1123,6 +1128,7 @@ export class PortfolioService { userId, calculationType: PerformanceCalculationType.TWR, currency: userCurrency, + hasFilters: filters?.length > 0, isExperimentalFeatures: this.request.user.Settings.settings.isExperimentalFeatures }); @@ -1220,6 +1226,7 @@ export class PortfolioService { userId, calculationType: PerformanceCalculationType.TWR, currency: this.request.user.Settings.settings.baseCurrency, + hasFilters: false, isExperimentalFeatures: this.request.user.Settings.settings.isExperimentalFeatures }); diff --git a/apps/api/src/app/redis-cache/redis-cache.service.ts b/apps/api/src/app/redis-cache/redis-cache.service.ts index a313eadf1..53b177b4f 100644 --- a/apps/api/src/app/redis-cache/redis-cache.service.ts +++ b/apps/api/src/app/redis-cache/redis-cache.service.ts @@ -24,7 +24,7 @@ export class RedisCacheService { return this.cache.get(key); } - public getPortfolioSnapshotKey(userId: string) { + public getPortfolioSnapshotKey({ userId }: { userId: string }) { return `portfolio-snapshot-${userId}`; } diff --git a/apps/api/src/events/portfolio-changed.listener.ts b/apps/api/src/events/portfolio-changed.listener.ts index 0f8877127..4a6e3d386 100644 --- a/apps/api/src/events/portfolio-changed.listener.ts +++ b/apps/api/src/events/portfolio-changed.listener.ts @@ -17,7 +17,9 @@ export class PortfolioChangedListener { ); this.redisCacheService.remove( - this.redisCacheService.getPortfolioSnapshotKey(event.getUserId()) + this.redisCacheService.getPortfolioSnapshotKey({ + userId: event.getUserId() + }) ); } }