From 6a6497b56d095768018236fba2ec0dbf04d6680f Mon Sep 17 00:00:00 2001 From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com> Date: Sat, 9 Apr 2022 10:16:13 +0200 Subject: [PATCH] Rename new portfolio calculation engine (#816) --- .../api/src/app/account/account.controller.ts | 6 ++--- ...olio-calculator-baln-buy-and-sell.spec.ts} | 10 +++---- ... => portfolio-calculator-baln-buy.spec.ts} | 10 +++---- ...=> portfolio-calculator-no-orders.spec.ts} | 10 +++---- ...w.spec.ts => portfolio-calculator.spec.ts} | 16 ++++++------ ...culator-new.ts => portfolio-calculator.ts} | 18 +++++-------- .../src/app/portfolio/portfolio.controller.ts | 26 ++++++++++--------- .../api/src/app/portfolio/portfolio.module.ts | 6 ++--- ...io.service-new.ts => portfolio.service.ts} | 22 ++++++++-------- 9 files changed, 61 insertions(+), 63 deletions(-) rename apps/api/src/app/portfolio/{portfolio-calculator-new-baln-buy-and-sell.spec.ts => portfolio-calculator-baln-buy-and-sell.spec.ts} (89%) rename apps/api/src/app/portfolio/{portfolio-calculator-new-baln-buy.spec.ts => portfolio-calculator-baln-buy.spec.ts} (88%) rename apps/api/src/app/portfolio/{portfolio-calculator-new-no-orders.spec.ts => portfolio-calculator-no-orders.spec.ts} (81%) rename apps/api/src/app/portfolio/{portfolio-calculator-new.spec.ts => portfolio-calculator.spec.ts} (84%) rename apps/api/src/app/portfolio/{portfolio-calculator-new.ts => portfolio-calculator.ts} (98%) rename apps/api/src/app/portfolio/{portfolio.service-new.ts => portfolio.service.ts} (98%) diff --git a/apps/api/src/app/account/account.controller.ts b/apps/api/src/app/account/account.controller.ts index 838009371..819fc5a0d 100644 --- a/apps/api/src/app/account/account.controller.ts +++ b/apps/api/src/app/account/account.controller.ts @@ -1,4 +1,4 @@ -import { PortfolioServiceNew } from '@ghostfolio/api/app/portfolio/portfolio.service-new'; +import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { UserService } from '@ghostfolio/api/app/user/user.service'; import { nullifyValuesInObject, @@ -35,7 +35,7 @@ export class AccountController { public constructor( private readonly accountService: AccountService, private readonly impersonationService: ImpersonationService, - private readonly portfolioServiceNew: PortfolioServiceNew, + private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser, private readonly userService: UserService ) {} @@ -92,7 +92,7 @@ export class AccountController { ); let accountsWithAggregations = - await this.portfolioServiceNew.getAccountsWithAggregations( + await this.portfolioService.getAccountsWithAggregations( impersonationUserId || this.request.user.id ); diff --git a/apps/api/src/app/portfolio/portfolio-calculator-new-baln-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/portfolio-calculator-baln-buy-and-sell.spec.ts similarity index 89% rename from apps/api/src/app/portfolio/portfolio-calculator-new-baln-buy-and-sell.spec.ts rename to apps/api/src/app/portfolio/portfolio-calculator-baln-buy-and-sell.spec.ts index 5dddc53fd..ea35cdd79 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator-new-baln-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator-baln-buy-and-sell.spec.ts @@ -3,7 +3,7 @@ import { parseDate } from '@ghostfolio/common/helper'; import Big from 'big.js'; import { CurrentRateServiceMock } from './current-rate.service.mock'; -import { PortfolioCalculatorNew } from './portfolio-calculator-new'; +import { PortfolioCalculator } from './portfolio-calculator'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { @@ -14,7 +14,7 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); -describe('PortfolioCalculatorNew', () => { +describe('PortfolioCalculator', () => { let currentRateService: CurrentRateService; beforeEach(() => { @@ -23,7 +23,7 @@ describe('PortfolioCalculatorNew', () => { describe('get current positions', () => { it.only('with BALN.SW buy and sell', async () => { - const portfolioCalculatorNew = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currentRateService, currency: 'CHF', orders: [ @@ -52,13 +52,13 @@ describe('PortfolioCalculatorNew', () => { ] }); - portfolioCalculatorNew.computeTransactionPoints(); + portfolioCalculator.computeTransactionPoints(); const spy = jest .spyOn(Date, 'now') .mockImplementation(() => parseDate('2021-12-18').getTime()); - const currentPositions = await portfolioCalculatorNew.getCurrentPositions( + const currentPositions = await portfolioCalculator.getCurrentPositions( parseDate('2021-11-22') ); diff --git a/apps/api/src/app/portfolio/portfolio-calculator-new-baln-buy.spec.ts b/apps/api/src/app/portfolio/portfolio-calculator-baln-buy.spec.ts similarity index 88% rename from apps/api/src/app/portfolio/portfolio-calculator-new-baln-buy.spec.ts rename to apps/api/src/app/portfolio/portfolio-calculator-baln-buy.spec.ts index de0f1f0bf..a6fe1af40 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator-new-baln-buy.spec.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator-baln-buy.spec.ts @@ -3,7 +3,7 @@ import { parseDate } from '@ghostfolio/common/helper'; import Big from 'big.js'; import { CurrentRateServiceMock } from './current-rate.service.mock'; -import { PortfolioCalculatorNew } from './portfolio-calculator-new'; +import { PortfolioCalculator } from './portfolio-calculator'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { @@ -14,7 +14,7 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); -describe('PortfolioCalculatorNew', () => { +describe('PortfolioCalculator', () => { let currentRateService: CurrentRateService; beforeEach(() => { @@ -23,7 +23,7 @@ describe('PortfolioCalculatorNew', () => { describe('get current positions', () => { it.only('with BALN.SW buy', async () => { - const portfolioCalculatorNew = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currentRateService, currency: 'CHF', orders: [ @@ -41,13 +41,13 @@ describe('PortfolioCalculatorNew', () => { ] }); - portfolioCalculatorNew.computeTransactionPoints(); + portfolioCalculator.computeTransactionPoints(); const spy = jest .spyOn(Date, 'now') .mockImplementation(() => parseDate('2021-12-18').getTime()); - const currentPositions = await portfolioCalculatorNew.getCurrentPositions( + const currentPositions = await portfolioCalculator.getCurrentPositions( parseDate('2021-11-30') ); diff --git a/apps/api/src/app/portfolio/portfolio-calculator-new-no-orders.spec.ts b/apps/api/src/app/portfolio/portfolio-calculator-no-orders.spec.ts similarity index 81% rename from apps/api/src/app/portfolio/portfolio-calculator-new-no-orders.spec.ts rename to apps/api/src/app/portfolio/portfolio-calculator-no-orders.spec.ts index 41e2ca381..18d6cb34d 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator-new-no-orders.spec.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator-no-orders.spec.ts @@ -3,7 +3,7 @@ import { parseDate } from '@ghostfolio/common/helper'; import Big from 'big.js'; import { CurrentRateServiceMock } from './current-rate.service.mock'; -import { PortfolioCalculatorNew } from './portfolio-calculator-new'; +import { PortfolioCalculator } from './portfolio-calculator'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { return { @@ -14,7 +14,7 @@ jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { }; }); -describe('PortfolioCalculatorNew', () => { +describe('PortfolioCalculator', () => { let currentRateService: CurrentRateService; beforeEach(() => { @@ -23,19 +23,19 @@ describe('PortfolioCalculatorNew', () => { describe('get current positions', () => { it('with no orders', async () => { - const portfolioCalculatorNew = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currentRateService, currency: 'CHF', orders: [] }); - portfolioCalculatorNew.computeTransactionPoints(); + portfolioCalculator.computeTransactionPoints(); const spy = jest .spyOn(Date, 'now') .mockImplementation(() => parseDate('2021-12-18').getTime()); - const currentPositions = await portfolioCalculatorNew.getCurrentPositions( + const currentPositions = await portfolioCalculator.getCurrentPositions( new Date() ); diff --git a/apps/api/src/app/portfolio/portfolio-calculator-new.spec.ts b/apps/api/src/app/portfolio/portfolio-calculator.spec.ts similarity index 84% rename from apps/api/src/app/portfolio/portfolio-calculator-new.spec.ts rename to apps/api/src/app/portfolio/portfolio-calculator.spec.ts index 72e3091f1..23f0a8a8d 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator-new.spec.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator.spec.ts @@ -1,9 +1,9 @@ import Big from 'big.js'; import { CurrentRateService } from './current-rate.service'; -import { PortfolioCalculatorNew } from './portfolio-calculator-new'; +import { PortfolioCalculator } from './portfolio-calculator'; -describe('PortfolioCalculatorNew', () => { +describe('PortfolioCalculator', () => { let currentRateService: CurrentRateService; beforeEach(() => { @@ -11,7 +11,7 @@ describe('PortfolioCalculatorNew', () => { }); describe('annualized performance percentage', () => { - const portfolioCalculatorNew = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currentRateService, currency: 'USD', orders: [] @@ -19,7 +19,7 @@ describe('PortfolioCalculatorNew', () => { it('Get annualized performance', async () => { expect( - portfolioCalculatorNew + portfolioCalculator .getAnnualizedPerformancePercent({ daysInMarket: NaN, // differenceInDays of date-fns returns NaN for the same day netPerformancePercent: new Big(0) @@ -28,7 +28,7 @@ describe('PortfolioCalculatorNew', () => { ).toEqual(0); expect( - portfolioCalculatorNew + portfolioCalculator .getAnnualizedPerformancePercent({ daysInMarket: 0, netPerformancePercent: new Big(0) @@ -40,7 +40,7 @@ describe('PortfolioCalculatorNew', () => { * Source: https://www.readyratios.com/reference/analysis/annualized_rate.html */ expect( - portfolioCalculatorNew + portfolioCalculator .getAnnualizedPerformancePercent({ daysInMarket: 65, // < 1 year netPerformancePercent: new Big(0.1025) @@ -49,7 +49,7 @@ describe('PortfolioCalculatorNew', () => { ).toBeCloseTo(0.729705); expect( - portfolioCalculatorNew + portfolioCalculator .getAnnualizedPerformancePercent({ daysInMarket: 365, // 1 year netPerformancePercent: new Big(0.05) @@ -61,7 +61,7 @@ describe('PortfolioCalculatorNew', () => { * Source: https://www.investopedia.com/terms/a/annualized-total-return.asp#annualized-return-formula-and-calculation */ expect( - portfolioCalculatorNew + portfolioCalculator .getAnnualizedPerformancePercent({ daysInMarket: 575, // > 1 year netPerformancePercent: new Big(0.2374) diff --git a/apps/api/src/app/portfolio/portfolio-calculator-new.ts b/apps/api/src/app/portfolio/portfolio-calculator.ts similarity index 98% rename from apps/api/src/app/portfolio/portfolio-calculator-new.ts rename to apps/api/src/app/portfolio/portfolio-calculator.ts index 3b8d30cf8..20b0a8709 100644 --- a/apps/api/src/app/portfolio/portfolio-calculator-new.ts +++ b/apps/api/src/app/portfolio/portfolio-calculator.ts @@ -1,11 +1,7 @@ import { TimelineInfoInterface } from '@ghostfolio/api/app/portfolio/interfaces/timeline-info.interface'; import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper'; -import { - ResponseError, - TimelinePosition, - UniqueAsset -} from '@ghostfolio/common/interfaces'; +import { ResponseError, TimelinePosition } from '@ghostfolio/common/interfaces'; import { Logger } from '@nestjs/common'; import { Type as TypeOfOrder } from '@prisma/client'; import Big from 'big.js'; @@ -36,7 +32,7 @@ import { import { TransactionPointSymbol } from './interfaces/transaction-point-symbol.interface'; import { TransactionPoint } from './interfaces/transaction-point.interface'; -export class PortfolioCalculatorNew { +export class PortfolioCalculator { private static readonly CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT = true; @@ -462,7 +458,7 @@ export class PortfolioCalculatorNew { } else if (!currentPosition.quantity.eq(0)) { Logger.warn( `Missing initial value for symbol ${currentPosition.symbol} at ${currentPosition.firstBuyDate}`, - 'PortfolioCalculatorNew' + 'PortfolioCalculator' ); hasErrors = true; } @@ -528,7 +524,7 @@ export class PortfolioCalculatorNew { Logger.error( `Failed to fetch info for date ${startDate} with exception`, error, - 'PortfolioCalculatorNew' + 'PortfolioCalculator' ); return null; } @@ -913,7 +909,7 @@ export class PortfolioCalculatorNew { ); const grossPerformancePercentage = - PortfolioCalculatorNew.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT || + PortfolioCalculator.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT || averagePriceAtStartDate.eq(0) || averagePriceAtEndDate.eq(0) || orders[indexOfStartOrder].unitPrice.eq(0) @@ -935,7 +931,7 @@ export class PortfolioCalculatorNew { : new Big(0); const netPerformancePercentage = - PortfolioCalculatorNew.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT || + PortfolioCalculator.CALCULATE_PERCENTAGE_PERFORMANCE_WITH_MAX_INVESTMENT || averagePriceAtStartDate.eq(0) || averagePriceAtEndDate.eq(0) || orders[indexOfStartOrder].unitPrice.eq(0) @@ -953,7 +949,7 @@ export class PortfolioCalculatorNew { ) .minus(1); - if (PortfolioCalculatorNew.ENABLE_LOGGING) { + if (PortfolioCalculator.ENABLE_LOGGING) { console.log( ` ${symbol} diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 4e8bce31d..ad06dbb52 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -38,7 +38,7 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { PortfolioPositionDetail } from './interfaces/portfolio-position-detail.interface'; import { PortfolioPositions } from './interfaces/portfolio-positions.interface'; -import { PortfolioServiceNew } from './portfolio.service-new'; +import { PortfolioService } from './portfolio.service'; @Controller('portfolio') export class PortfolioController { @@ -46,7 +46,7 @@ export class PortfolioController { private readonly accessService: AccessService, private readonly configurationService: ConfigurationService, private readonly exchangeRateDataService: ExchangeRateDataService, - private readonly portfolioServiceNew: PortfolioServiceNew, + private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser, private readonly userService: UserService ) {} @@ -57,7 +57,7 @@ export class PortfolioController { @Headers('impersonation-id') impersonationId: string, @Query('range') range ): Promise { - const historicalDataContainer = await this.portfolioServiceNew.getChart( + const historicalDataContainer = await this.portfolioService.getChart( impersonationId, range ); @@ -110,7 +110,7 @@ export class PortfolioController { let hasError = false; const { accounts, holdings, hasErrors } = - await this.portfolioServiceNew.getDetails( + await this.portfolioService.getDetails( impersonationId, this.request.user.id, range @@ -177,7 +177,7 @@ export class PortfolioController { ); } - let investments = await this.portfolioServiceNew.getInvestments( + let investments = await this.portfolioService.getInvestments( impersonationId ); @@ -206,8 +206,10 @@ export class PortfolioController { @Headers('impersonation-id') impersonationId: string, @Query('range') range ): Promise { - const performanceInformation = - await this.portfolioServiceNew.getPerformance(impersonationId, range); + const performanceInformation = await this.portfolioService.getPerformance( + impersonationId, + range + ); if ( impersonationId || @@ -230,7 +232,7 @@ export class PortfolioController { @Headers('impersonation-id') impersonationId: string, @Query('range') range ): Promise { - const result = await this.portfolioServiceNew.getPositions( + const result = await this.portfolioService.getPositions( impersonationId, range ); @@ -273,7 +275,7 @@ export class PortfolioController { hasDetails = user.subscription.type === 'Premium'; } - const { holdings } = await this.portfolioServiceNew.getDetails( + const { holdings } = await this.portfolioService.getDetails( access.userId, access.userId ); @@ -328,7 +330,7 @@ export class PortfolioController { ); } - let summary = await this.portfolioServiceNew.getSummary(impersonationId); + let summary = await this.portfolioService.getSummary(impersonationId); if ( impersonationId || @@ -362,7 +364,7 @@ export class PortfolioController { @Param('dataSource') dataSource, @Param('symbol') symbol ): Promise { - let position = await this.portfolioServiceNew.getPosition( + let position = await this.portfolioService.getPosition( dataSource, impersonationId, symbol @@ -407,6 +409,6 @@ export class PortfolioController { ); } - return await this.portfolioServiceNew.getReport(impersonationId); + return await this.portfolioService.getReport(impersonationId); } } diff --git a/apps/api/src/app/portfolio/portfolio.module.ts b/apps/api/src/app/portfolio/portfolio.module.ts index d4a172cba..7e6dfe88d 100644 --- a/apps/api/src/app/portfolio/portfolio.module.ts +++ b/apps/api/src/app/portfolio/portfolio.module.ts @@ -14,12 +14,12 @@ import { Module } from '@nestjs/common'; import { CurrentRateService } from './current-rate.service'; import { PortfolioController } from './portfolio.controller'; -import { PortfolioServiceNew } from './portfolio.service-new'; +import { PortfolioService } from './portfolio.service'; import { RulesService } from './rules.service'; @Module({ controllers: [PortfolioController], - exports: [PortfolioServiceNew], + exports: [PortfolioService], imports: [ AccessModule, ConfigurationModule, @@ -36,7 +36,7 @@ import { RulesService } from './rules.service'; providers: [ AccountService, CurrentRateService, - PortfolioServiceNew, + PortfolioService, RulesService ] }) diff --git a/apps/api/src/app/portfolio/portfolio.service-new.ts b/apps/api/src/app/portfolio/portfolio.service.ts similarity index 98% rename from apps/api/src/app/portfolio/portfolio.service-new.ts rename to apps/api/src/app/portfolio/portfolio.service.ts index e3b9e8536..a7dc8adf7 100644 --- a/apps/api/src/app/portfolio/portfolio.service-new.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -69,14 +69,14 @@ import { HistoricalDataItem, PortfolioPositionDetail } from './interfaces/portfolio-position-detail.interface'; -import { PortfolioCalculatorNew } from './portfolio-calculator-new'; +import { PortfolioCalculator } from './portfolio-calculator'; import { RulesService } from './rules.service'; const developedMarkets = require('../../assets/countries/developed-markets.json'); const emergingMarkets = require('../../assets/countries/emerging-markets.json'); @Injectable() -export class PortfolioServiceNew { +export class PortfolioService { public constructor( private readonly accountService: AccountService, private readonly currentRateService: CurrentRateService, @@ -170,7 +170,7 @@ export class PortfolioServiceNew { includeDrafts: true }); - const portfolioCalculator = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currency: this.request.user.Settings.currency, currentRateService: this.currentRateService, orders: portfolioOrders @@ -221,7 +221,7 @@ export class PortfolioServiceNew { userId }); - const portfolioCalculator = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currency: this.request.user.Settings.currency, currentRateService: this.currentRateService, orders: portfolioOrders @@ -321,7 +321,7 @@ export class PortfolioServiceNew { userId }); - const portfolioCalculator = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currency: userCurrency, currentRateService: this.currentRateService, orders: portfolioOrders @@ -514,7 +514,7 @@ export class PortfolioServiceNew { unitPrice: new Big(order.unitPrice) })); - const portfolioCalculator = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currency: positionCurrency, currentRateService: this.currentRateService, orders: portfolioOrders @@ -704,7 +704,7 @@ export class PortfolioServiceNew { userId }); - const portfolioCalculator = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currency: this.request.user.Settings.currency, currentRateService: this.currentRateService, orders: portfolioOrders @@ -781,7 +781,7 @@ export class PortfolioServiceNew { userId }); - const portfolioCalculator = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currency: this.request.user.Settings.currency, currentRateService: this.currentRateService, orders: portfolioOrders @@ -856,7 +856,7 @@ export class PortfolioServiceNew { }; } - const portfolioCalculator = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currency, currentRateService: this.currentRateService, orders: portfolioOrders @@ -969,7 +969,7 @@ export class PortfolioServiceNew { const daysInMarket = differenceInDays(new Date(), firstOrderDate); - const annualizedPerformancePercent = new PortfolioCalculatorNew({ + const annualizedPerformancePercent = new PortfolioCalculator({ currency: userCurrency, currentRateService: this.currentRateService, orders: [] @@ -1224,7 +1224,7 @@ export class PortfolioServiceNew { ) })); - const portfolioCalculator = new PortfolioCalculatorNew({ + const portfolioCalculator = new PortfolioCalculator({ currency: userCurrency, currentRateService: this.currentRateService, orders: portfolioOrders