diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 84ad648189..c84afc1354 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -371,6 +371,7 @@ export abstract class PortfolioCalculator { averageInvestmentValuesWithCurrencyEffect: { [date: string]: Big }; currentValues: { [date: string]: Big }; currentValuesWithCurrencyEffect: { [date: string]: Big }; + dividendValuesWithCurrencyEffect: { [date: string]: Big }; investmentValuesAccumulated: { [date: string]: Big }; investmentValuesAccumulatedWithCurrencyEffect: { [date: string]: Big }; investmentValuesWithCurrencyEffect: { [date: string]: Big }; @@ -406,6 +407,7 @@ export abstract class PortfolioCalculator { averageInvestmentWithCurrencyEffect, currentValues, currentValuesWithCurrencyEffect, + dividendValuesWithCurrencyEffect, dividendYieldPercent, dividendYieldPercentWithCurrencyEffect, grossPerformance, @@ -453,6 +455,7 @@ export abstract class PortfolioCalculator { averageInvestmentValuesWithCurrencyEffect: {}, currentValues: {}, currentValuesWithCurrencyEffect: {}, + dividendValuesWithCurrencyEffect: {}, investmentValuesAccumulated: {}, investmentValuesAccumulatedWithCurrencyEffect: {}, investmentValuesWithCurrencyEffect: {}, @@ -465,6 +468,7 @@ export abstract class PortfolioCalculator { averageInvestmentValuesWithCurrencyEffect, currentValues, currentValuesWithCurrencyEffect, + dividendValuesWithCurrencyEffect, investmentValuesAccumulated, investmentValuesAccumulatedWithCurrencyEffect, investmentValuesWithCurrencyEffect, @@ -548,13 +552,6 @@ export abstract class PortfolioCalculator { } } - const totalDividendValueWithCurrencyEffectByDate = - this.getTotalDividendValueWithCurrencyEffectByDate({ - chartDates, - exchangeRatesByCurrency, - holdings: positions - }); - const assetProfileIdentifiers = Object.keys(valuesByAssetProfileIdentifier); for (const dateString of chartDates) { @@ -569,6 +566,10 @@ export abstract class PortfolioCalculator { assetProfileValues.currentValuesWithCurrencyEffect?.[dateString] ?? new Big(0); + const dividendValueWithCurrencyEffect = + assetProfileValues.dividendValuesWithCurrencyEffect?.[dateString] ?? + new Big(0); + const investmentValueAccumulated = assetProfileValues.investmentValuesAccumulated?.[dateString] ?? new Big(0); @@ -631,8 +632,10 @@ export abstract class PortfolioCalculator { accumulatedValuesByDate[dateString] ?.totalCurrentValueWithCurrencyEffect ?? new Big(0) ).add(currentValueWithCurrencyEffect), - totalDividendValueWithCurrencyEffect: - totalDividendValueWithCurrencyEffectByDate[dateString], + totalDividendValueWithCurrencyEffect: ( + accumulatedValuesByDate[dateString] + ?.totalDividendValueWithCurrencyEffect ?? new Big(0) + ).add(dividendValueWithCurrencyEffect), totalInvestmentValue: ( accumulatedValuesByDate[dateString]?.totalInvestmentValue ?? new Big(0) @@ -870,12 +873,6 @@ export abstract class PortfolioCalculator { return this.dataProviderInfos; } - public async getDividendInBaseCurrency() { - await this.snapshotPromise; - - return this.getDividendInBaseCurrencyOfHoldings(this.snapshot.positions); - } - protected getDividendInBaseCurrencyOfHoldings( holdings: PortfolioSnapshotHolding[] ) { @@ -894,6 +891,7 @@ export abstract class PortfolioCalculator { averageInvestmentWithCurrencyEffect: new Big(0), currentValues: {}, currentValuesWithCurrencyEffect: {}, + dividendValuesWithCurrencyEffect: {}, dividendYieldPercent: new Big(0), dividendYieldPercentWithCurrencyEffect: new Big(0), grossPerformance: new Big(0), @@ -959,7 +957,10 @@ export abstract class PortfolioCalculator { const currentExchangeRate = exchangeRates[format(new Date(), DATE_FORMAT)]; const currentValues: { [date: string]: Big } = {}; const currentValuesWithCurrencyEffect: { [date: string]: Big } = {}; + const dividendValuesWithCurrencyEffect: { [date: string]: Big } = {}; let dividends = new Big(0); + let dividendsAtStartDateWithCurrencyEffect = new Big(0); + let dividendsWithCurrencyEffect = new Big(0); let fees = new Big(0); let feesAtStartDate = new Big(0); let feesAtStartDateWithCurrencyEffect = new Big(0); @@ -1203,12 +1204,12 @@ export abstract class PortfolioCalculator { } if (activity.type === 'DIVIDEND') { - // The amount of a dividend in the base currency is the same with and - // without currency effect, like the dividend of the holding - dividends = dividends.plus( - activity.quantity - .mul(activity.unitPrice) - .mul(exchangeRateAtActivityDate ?? 1) + const dividend = activity.quantity.mul(activity.unitPrice); + + dividends = dividends.plus(dividend.mul(currentExchangeRate ?? 1)); + + dividendsWithCurrencyEffect = dividendsWithCurrencyEffect.plus( + dividend.mul(exchangeRateAtActivityDate ?? 1) ); } @@ -1221,7 +1222,7 @@ export abstract class PortfolioCalculator { valueOfInvestmentWithCurrencyEffect .minus(totalInvestmentWithCurrencyEffect) .plus(grossPerformanceFromSellsWithCurrencyEffect) - .plus(dividends); + .plus(dividendsWithCurrencyEffect); grossPerformance = newGrossPerformance; @@ -1229,6 +1230,7 @@ export abstract class PortfolioCalculator { newGrossPerformanceWithCurrencyEffect; if (activity.itemType === 'start') { + dividendsAtStartDateWithCurrencyEffect = dividendsWithCurrencyEffect; feesAtStartDate = fees; feesAtStartDateWithCurrencyEffect = feesWithCurrencyEffect; grossPerformanceAtStartDate = grossPerformance; @@ -1243,6 +1245,11 @@ export abstract class PortfolioCalculator { currentValuesWithCurrencyEffect[activity.date] = valueOfInvestmentWithCurrencyEffect; + dividendValuesWithCurrencyEffect[activity.date] = + dividendsWithCurrencyEffect.minus( + dividendsAtStartDateWithCurrencyEffect + ); + netPerformanceValues[activity.date] = grossPerformance .minus(grossPerformanceAtStartDate) .minus(fees.minus(feesAtStartDate)); @@ -1316,6 +1323,7 @@ export abstract class PortfolioCalculator { return { currentValues, currentValuesWithCurrencyEffect, + dividendValuesWithCurrencyEffect, initialValue, investmentValuesAccumulated, investmentValuesAccumulatedWithCurrencyEffect, @@ -1788,77 +1796,6 @@ export abstract class PortfolioCalculator { return chartDateMap; } - private getTotalDividendValueWithCurrencyEffectByDate({ - chartDates, - exchangeRatesByCurrency, - holdings - }: { - chartDates: string[]; - exchangeRatesByCurrency: { - [currencyPair: string]: { [dateString: string]: number }; - }; - holdings: PortfolioCalculatorHolding[]; - }): { [date: string]: Big } { - // Take the dividend from the same holdings as the portfolio summary, so - // that the response shows one dividend only - const assetProfileIdentifiersIncludedInHoldings = new Set( - holdings - .filter(({ includeInHoldings }) => { - return includeInHoldings; - }) - .map(({ dataSource, symbol }) => { - return getAssetProfileIdentifier({ dataSource, symbol }); - }) - ); - - const dividendActivities = this.activities.filter( - ({ assetProfile, type }) => { - return ( - type === 'DIVIDEND' && - assetProfileIdentifiersIncludedInHoldings.has( - getAssetProfileIdentifier(assetProfile) - ) - ); - } - ); - - const totalDividendValueWithCurrencyEffectByDate: { [date: string]: Big } = - {}; - - let index = 0; - let totalDividendValueWithCurrencyEffect = new Big(0); - - // The activities and the chart dates are sorted by date, so one pass over - // both gives the dividends received up to each chart date - for (const chartDate of chartDates) { - while ( - index < dividendActivities.length && - dividendActivities[index].date <= chartDate - ) { - const { assetProfile, date, quantity, unitPrice } = - dividendActivities[index]; - - totalDividendValueWithCurrencyEffect = - totalDividendValueWithCurrencyEffect.plus( - quantity - .mul(unitPrice) - .mul( - exchangeRatesByCurrency[ - `${assetProfile.currency}${this.currency}` - ]?.[date] ?? 1 - ) - ); - - index++; - } - - totalDividendValueWithCurrencyEffectByDate[chartDate] = - totalDividendValueWithCurrencyEffect; - } - - return totalDividendValueWithCurrencyEffectByDate; - } - @LogPerformance private async initialize(attempt = 1) { const startTimeTotal = performance.now(); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy-with-dividend.spec.ts new file mode 100644 index 0000000000..46dbe493bf --- /dev/null +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy-with-dividend.spec.ts @@ -0,0 +1,166 @@ +import { + activityDummyData, + assetProfileDummyData, + userDummyData +} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; +import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; +import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; +import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock'; +import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; +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 { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service.mock'; +import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service'; +import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock'; +import { parseDate } from '@ghostfolio/common/helper'; +import { Activity } from '@ghostfolio/common/interfaces'; +import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; + +import { Big } from 'big.js'; + +jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { + return { + CurrentRateService: jest.fn().mockImplementation(() => { + return CurrentRateServiceMock; + }) + }; +}); + +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + +jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { + return { + RedisCacheService: jest.fn().mockImplementation(() => { + return RedisCacheServiceMock; + }) + }; +}); + +jest.mock( + '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service', + () => { + return { + ExchangeRateDataService: jest.fn().mockImplementation(() => { + return ExchangeRateDataServiceMock; + }) + }; + } +); + +describe('PortfolioCalculator', () => { + let configurationService: ConfigurationService; + let currentRateService: CurrentRateService; + let exchangeRateDataService: ExchangeRateDataService; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; + let redisCacheService: RedisCacheService; + + beforeEach(() => { + PortfolioSnapshotServiceMock.reset(); + RedisCacheServiceMock.reset(); + + configurationService = new ConfigurationService(); + + currentRateService = new CurrentRateService(null, null, null); + + exchangeRateDataService = new ExchangeRateDataService( + null, + null, + null, + null + ); + + portfolioSnapshotService = new PortfolioSnapshotService(null, null); + + redisCacheService = new RedisCacheService(null, null); + + portfolioCalculatorFactory = new PortfolioCalculatorFactory( + configurationService, + currentRateService, + exchangeRateDataService, + portfolioSnapshotService, + redisCacheService + ); + }); + + describe('get current positions', () => { + it('with GOOGL buy and dividend', async () => { + jest.useFakeTimers().setSystemTime(parseDate('2023-07-10').getTime()); + + const activities: Activity[] = [ + { + ...activityDummyData, + assetProfile: { + ...assetProfileDummyData, + currency: 'USD', + dataSource: 'YAHOO', + name: 'Alphabet Inc.', + symbol: 'GOOGL' + }, + date: new Date('2023-01-03'), + feeInAssetProfileCurrency: 1, + feeInBaseCurrency: 0.9238, + quantity: 1, + type: 'BUY', + unitPriceInAssetProfileCurrency: 89.12 + }, + { + ...activityDummyData, + assetProfile: { + ...assetProfileDummyData, + currency: 'USD', + dataSource: 'YAHOO', + name: 'Alphabet Inc.', + symbol: 'GOOGL' + }, + date: new Date('2023-01-03'), + feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, + quantity: 1, + type: 'DIVIDEND', + unitPriceInAssetProfileCurrency: 5 + } + ]; + + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ + activities, + calculationType: PerformanceCalculationType.ROAI, + currency: 'CHF', + userId: userDummyData.id + }); + + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); + + // The asset performance takes the dividend at the current exchange rate + // (0.8854), the net performance at the exchange rate of the payment date + // (0.9238) + expect(portfolioSnapshot.positions).toMatchObject([ + { + dividendInBaseCurrency: new Big('5').mul(0.9238), + grossPerformance: new Big('32.33').mul(0.8854), + grossPerformanceWithCurrencyEffect: new Big('25.394774'), + netPerformance: new Big('31.33').mul(0.8854), + netPerformanceWithCurrencyEffectMap: { + max: new Big('24.470974') + } + } + ]); + + expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject({ + dividendInBaseCurrency: 4.619, + netPerformance: new Big('31.33').mul(0.8854).toNumber(), + netPerformanceWithCurrencyEffect: 24.470974 + }); + }); + }); +}); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts index aa70435965..bdf5105ad5 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-fee-and-dividend.spec.ts @@ -122,9 +122,9 @@ describe('PortfolioCalculator', () => { { // The first activity of this asset profile is a fee, which is not an // investment activity. Thus the holding is not included in the - // holdings of the portfolio summary, and its dividend is not part of - // the dividend of the chart. But its fee and its dividend are part of - // the net performance + // holdings of the portfolio summary. But its fee and its dividend are + // part of the net performance, and thus its dividend is part of the + // dividend of the chart ...activityDummyData, assetProfile: { ...assetProfileDummyData, @@ -180,8 +180,8 @@ describe('PortfolioCalculator', () => { ).toEqual(['MSFT']); expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject({ - dividendInBaseCurrency: 0.62, - dividendInPercentageWithCurrencyEffect: 0.0020764954116149776, + dividendInBaseCurrency: 5.62, + dividendInPercentageWithCurrencyEffect: 0.01882242615044544, netPerformance: 18.87, netPerformanceInPercentage: 0.06319914260834618 }); @@ -189,8 +189,8 @@ describe('PortfolioCalculator', () => { // The portfolio summary takes the dividend of the date range max expect(performanceByDateRange).toMatchObject({ max: { - dividendInBaseCurrency: 0.62, - dividendInPercentageWithCurrencyEffect: 0.002076495411614967, + dividendInBaseCurrency: 5.62, + dividendInPercentageWithCurrencyEffect: 0.01882242615044535, netPerformance: 18.87, netPerformanceInPercentage: 0.06319914260834586 } @@ -327,8 +327,8 @@ describe('PortfolioCalculator', () => { }, { // The holding has no market price, thus it has no value. Its dividend - // is part of the dividend of the chart, but not part of the net - // performance (unlike the dividend in the scenario above) + // is not part of the net performance (unlike the dividend in the + // scenario above), and thus not part of the dividend of the chart ...activityDummyData, assetProfile: { ...assetProfileDummyData, @@ -364,7 +364,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.hasErrors).toBe(false); expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject({ - dividendInBaseCurrency: 5.62, + dividendInBaseCurrency: 0.62, dividendInPercentageWithCurrencyEffect: 0, netPerformance: 14.87, netPerformanceInPercentage: 0.0498023980172818 @@ -372,7 +372,7 @@ describe('PortfolioCalculator', () => { expect(performanceByDateRange).toMatchObject({ max: { - dividendInBaseCurrency: 5.62, + dividendInBaseCurrency: 0.62, dividendInPercentageWithCurrencyEffect: 0, netPerformance: 14.87, netPerformanceInPercentage: 0.049802398017281556 diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts index c0b7337350..c0261d4e22 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -403,6 +403,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { const { currentValues, currentValuesWithCurrencyEffect, + dividendValuesWithCurrencyEffect, initialValue, investmentValuesAccumulated, investmentValuesAccumulatedWithCurrencyEffect, @@ -736,6 +737,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { averageInvestmentValuesWithCurrencyEffect, currentValues, currentValuesWithCurrencyEffect, + dividendValuesWithCurrencyEffect, dividendYieldPercent, dividendYieldPercentWithCurrencyEffect, grossPerformancePercentage, diff --git a/apps/api/src/app/portfolio/interfaces/holding-performance.interface.ts b/apps/api/src/app/portfolio/interfaces/holding-performance.interface.ts index 0c35ab96be..61da17e71a 100644 --- a/apps/api/src/app/portfolio/interfaces/holding-performance.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/holding-performance.interface.ts @@ -17,6 +17,9 @@ export interface HoldingPerformance { currentValuesWithCurrencyEffect: { [date: string]: Big; }; + dividendValuesWithCurrencyEffect: { + [date: string]: Big; + }; dividendYieldPercent: Big; dividendYieldPercentWithCurrencyEffect: Big; grossPerformance: Big; diff --git a/apps/api/src/app/portfolio/interfaces/holding-valuation.interface.ts b/apps/api/src/app/portfolio/interfaces/holding-valuation.interface.ts index 9e13fb70b4..06ae50005d 100644 --- a/apps/api/src/app/portfolio/interfaces/holding-valuation.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/holding-valuation.interface.ts @@ -5,6 +5,7 @@ import { HoldingValuationItem } from './holding-valuation-item.interface'; export interface HoldingValuation { currentValues: { [date: string]: Big }; currentValuesWithCurrencyEffect: { [date: string]: Big }; + dividendValuesWithCurrencyEffect: { [date: string]: Big }; initialValue?: Big; investmentValuesAccumulated: { [date: string]: Big }; investmentValuesAccumulatedWithCurrencyEffect: { [date: string]: Big }; diff --git a/apps/api/src/app/portfolio/portfolio.service.spec.ts b/apps/api/src/app/portfolio/portfolio.service.spec.ts index 19af3615bc..dca03b6139 100644 --- a/apps/api/src/app/portfolio/portfolio.service.spec.ts +++ b/apps/api/src/app/portfolio/portfolio.service.spec.ts @@ -865,7 +865,6 @@ describe('PortfolioService', () => { function createPortfolioCalculator() { return { - getDividendInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), getFeesInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), getInterestInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), getLiabilitiesInBaseCurrency: jest.fn().mockResolvedValue(new Big(0)), diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index d906fd6aef..a3ed2f9cf4 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -2140,6 +2140,7 @@ export class PortfolioService { const { currentValueInBaseCurrency, + dividendInBaseCurrency, dividendPercentageWithCurrencyEffect, netPerformance, netPerformancePercentage, @@ -2154,9 +2155,6 @@ export class PortfolioService { const dateOfFirstActivity = portfolioCalculator.getStartDate(); - const dividendInBaseCurrency = - await portfolioCalculator.getDividendInBaseCurrency(); - const fees = await portfolioCalculator.getFeesInBaseCurrency(); const interest = await portfolioCalculator.getInterestInBaseCurrency(); @@ -2237,6 +2235,7 @@ export class PortfolioService { cash, currentValueInBaseCurrency, dateOfFirstActivity, + dividendInBaseCurrency, dividendPercentageWithCurrencyEffect, excludedAccountsAndActivities, netPerformance, @@ -2248,7 +2247,6 @@ export class PortfolioService { activityCount: activities.filter(({ type }) => { return ['BUY', 'SELL'].includes(type); }).length, - dividendInBaseCurrency: dividendInBaseCurrency.toNumber(), // TODO: Remove the fallback to 0 with the next release, when each // cached portfolio snapshot contains the dividend yield dividendYieldPercent: dividendYieldPercent?.toNumber() ?? 0, diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index 06b0d7845c..5629965006 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -333,6 +333,7 @@ export class GfAnalysisPageComponent implements OnInit { index, { date, + dividendInPercentageWithCurrencyEffect, netPerformanceInPercentageWithCurrencyEffect, totalInvestmentValueWithCurrencyEffect, valueInPercentage, @@ -363,7 +364,9 @@ export class GfAnalysisPageComponent implements OnInit { if (isNumber(netPerformanceInPercentageWithCurrencyEffect)) { this.performanceDataItemsInPercentage.push({ date, - value: netPerformanceInPercentageWithCurrencyEffect + value: + netPerformanceInPercentageWithCurrencyEffect - + (dividendInPercentageWithCurrencyEffect ?? 0) }); } } diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html index c9cc8d93c0..3eb3624da2 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -171,7 +171,7 @@ /> -