From 0b1cadabd91bdcd82ecd8b4257700469cd1f55c0 Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Mon, 9 Sep 2024 15:53:28 +0200 Subject: [PATCH] Refactor PortfolioSnapshotProcessor --- .../calculator/portfolio-calculator.ts | 13 +++--- ...folio-calculator-novn-buy-and-sell.spec.ts | 9 +--- .../portfolio-snapshot-queue-job.interface.ts | 1 + .../portfolio-snapshot.module.ts | 11 ++++- .../portfolio-snapshot.processor.ts | 42 ++++++++++--------- 5 files changed, 43 insertions(+), 33 deletions(-) diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 70b782a06..0d8c23dd7 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -160,7 +160,7 @@ export abstract class PortfolioCalculator { ): PortfolioSnapshot; @LogPerformance - private async computeSnapshot(): Promise { + public async computeSnapshot(): Promise { const lastTransactionPoint = last(this.transactionPoints); const transactionPoints = this.transactionPoints?.filter(({ date }) => { @@ -1018,6 +1018,7 @@ export abstract class PortfolioCalculator { let cachedPortfolioSnapshot: PortfolioSnapshot; let isCachedPortfolioSnapshotExpired = false; + const jobId = this.userId; try { const cachedPortfolioSnapshotValue = await this.redisCacheService.get( @@ -1056,12 +1057,13 @@ export abstract class PortfolioCalculator { this.portfolioSnapshotService.addJobToQueue({ data: { filters: this.filters, + userCurrency: this.currency, userId: this.userId }, name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, opts: { - ...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS - // jobId + ...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS, + jobId // priority } }); @@ -1072,12 +1074,13 @@ export abstract class PortfolioCalculator { const job = await this.portfolioSnapshotService.addJobToQueue({ data: { filters: this.filters, + userCurrency: this.currency, userId: this.userId }, name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, opts: { - ...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS - // jobId + ...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS, + jobId // priority } }); 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 859df340c..0f792dd8a 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 @@ -14,7 +14,6 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; -import { PortfolioSnapshotProcessor } from '@ghostfolio/api/services/portfolio-snapshot/portfolio-snapshot.processor'; import { PortfolioSnapshotService } from '@ghostfolio/api/services/portfolio-snapshot/portfolio-snapshot.service'; import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/portfolio-snapshot/portfolio-snapshot.service.mock'; import { parseDate } from '@ghostfolio/common/helper'; @@ -129,13 +128,7 @@ describe('PortfolioCalculator', () => { userId: userDummyData.id }); - const portfolioSnapshotProcessor = new PortfolioSnapshotProcessor( - null, - null - ); - - const portfolioSnapshot = - await portfolioSnapshotProcessor.computeSnapshot(); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); const investments = portfolioCalculator.getInvestments(); diff --git a/apps/api/src/services/portfolio-snapshot/interfaces/portfolio-snapshot-queue-job.interface.ts b/apps/api/src/services/portfolio-snapshot/interfaces/portfolio-snapshot-queue-job.interface.ts index 700fed657..24948e211 100644 --- a/apps/api/src/services/portfolio-snapshot/interfaces/portfolio-snapshot-queue-job.interface.ts +++ b/apps/api/src/services/portfolio-snapshot/interfaces/portfolio-snapshot-queue-job.interface.ts @@ -2,5 +2,6 @@ import { Filter } from '@ghostfolio/common/interfaces'; export interface IPortfolioSnapshotQueueJob { filters: Filter[]; + userCurrency: string; userId: string; } diff --git a/apps/api/src/services/portfolio-snapshot/portfolio-snapshot.module.ts b/apps/api/src/services/portfolio-snapshot/portfolio-snapshot.module.ts index 9f7ad2cd3..6fd4e7c38 100644 --- a/apps/api/src/services/portfolio-snapshot/portfolio-snapshot.module.ts +++ b/apps/api/src/services/portfolio-snapshot/portfolio-snapshot.module.ts @@ -1,3 +1,6 @@ +import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; +import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; @@ -27,12 +30,18 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor'; DataProviderModule, ExchangeRateDataModule, MarketDataModule, + OrderModule, PrismaModule, PropertyModule, RedisCacheModule, SymbolProfileModule ], - providers: [PortfolioSnapshotProcessor, PortfolioSnapshotService], + providers: [ + CurrentRateService, + PortfolioCalculatorFactory, + PortfolioSnapshotProcessor, + PortfolioSnapshotService + ], exports: [BullModule, PortfolioSnapshotService] }) export class PortfolioSnapshotQueueModule {} diff --git a/apps/api/src/services/portfolio-snapshot/portfolio-snapshot.processor.ts b/apps/api/src/services/portfolio-snapshot/portfolio-snapshot.processor.ts index 4bc9c4ab7..372040100 100644 --- a/apps/api/src/services/portfolio-snapshot/portfolio-snapshot.processor.ts +++ b/apps/api/src/services/portfolio-snapshot/portfolio-snapshot.processor.ts @@ -1,3 +1,8 @@ +import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { + PerformanceCalculationType, + PortfolioCalculatorFactory +} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; @@ -6,11 +11,9 @@ import { PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME, PORTFOLIO_SNAPSHOT_QUEUE } from '@ghostfolio/common/config'; -import { PortfolioSnapshot } from '@ghostfolio/common/models'; import { Process, Processor } from '@nestjs/bull'; import { Injectable, Logger } from '@nestjs/common'; -import * as Big from 'big.js'; import { Job } from 'bull'; import { addMilliseconds } from 'date-fns'; @@ -20,7 +23,9 @@ import { IPortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queu @Processor(PORTFOLIO_SNAPSHOT_QUEUE) export class PortfolioSnapshotProcessor { public constructor( + private readonly calculatorFactory: PortfolioCalculatorFactory, private readonly configurationService: ConfigurationService, + private readonly orderService: OrderService, private readonly redisCacheService: RedisCacheService ) {} @@ -34,7 +39,22 @@ export class PortfolioSnapshotProcessor { `PortfolioSnapshotProcessor (${PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME})` ); - const snapshot = await this.computeSnapshot(); + const { activities } = + await this.orderService.getOrdersForPortfolioCalculator({ + filters: job.data.filters, + userCurrency: job.data.userCurrency, + userId: job.data.userId + }); + + const portfolioCalculator = this.calculatorFactory.createCalculator({ + activities, + calculationType: PerformanceCalculationType.TWR, + currency: job.data.userCurrency, + filters: job.data.filters, + userId: job.data.userId + }); + + const snapshot = await portfolioCalculator.computeSnapshot(); Logger.log( `Portfolio snapshot calculation of user ${job.data.userId} has been completed`, @@ -68,20 +88,4 @@ export class PortfolioSnapshotProcessor { throw new Error(error); } } - - // TODO - public async computeSnapshot(): Promise { - return { - currentValueInBaseCurrency: new Big(0), - hasErrors: false, - historicalData: [], - positions: [], - totalFeesWithCurrencyEffect: new Big(0), - totalInterestWithCurrencyEffect: new Big(0), - totalInvestment: new Big(0), - totalInvestmentWithCurrencyEffect: new Big(0), - totalLiabilitiesWithCurrencyEffect: new Big(0), - totalValuablesWithCurrencyEffect: new Big(0) - }; - } }