Browse Source

Bugfix/handling of cash positions (#7660)

* Fix handling of cash positions

* Update changelog
pull/7761/head^2
Thomas Kaul 1 week ago
committed by GitHub
parent
commit
82b243f9ed
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 5
      CHANGELOG.md
  2. 20
      apps/api/src/app/endpoints/public/public.service.ts
  3. 49
      apps/api/src/app/portfolio/portfolio.controller.ts
  4. 49
      apps/api/src/helper/portfolio.helper.ts
  5. 203
      apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts
  6. 53
      apps/client/src/app/pages/public/public-page.component.ts
  7. 24
      libs/common/src/lib/helper.ts
  8. 1
      libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts
  9. 6
      libs/ui/src/lib/services/data.service.ts

5
CHANGELOG.md

@ -13,6 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Upgraded `undici` from version `8.5.0` to `8.10.0` - Upgraded `undici` from version `8.5.0` to `8.10.0`
- Upgraded `uuid` from version `14.0.1` to `14.0.2` - Upgraded `uuid` from version `14.0.1` to `14.0.2`
### Fixed
- Fixed the cash positions being included in the by continent, by country and by sector charts on the allocations page and the public page
- Fixed the allocations in percentage exceeding 100% in the restricted view
## 3.64.0 - 2026-08-30 ## 3.64.0 - 2026-08-30
### Added ### Added

20
apps/api/src/app/endpoints/public/public.service.ts

@ -6,18 +6,14 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; import { DEFAULT_CURRENCY } from '@ghostfolio/common/config';
import { SubscriptionType } from '@ghostfolio/common/enums'; import { SubscriptionType } from '@ghostfolio/common/enums';
import { getSum } from '@ghostfolio/common/helper'; import { getSum, isCashPosition } from '@ghostfolio/common/helper';
import { import {
AccessSettings, AccessSettings,
PublicPortfolioResponse PublicPortfolioResponse
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { HttpException, Injectable } from '@nestjs/common'; import { HttpException, Injectable } from '@nestjs/common';
import { import { Type as ActivityType } from '@prisma/client';
AssetClass,
AssetSubClass,
Type as ActivityType
} from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@ -173,23 +169,19 @@ export class PublicService {
assetProfile: { assetProfile: {
...holding.assetProfile, ...holding.assetProfile,
assetClass: assetClass:
hasDetails || hasDetails || isCashPosition(holding.assetProfile)
holding.assetProfile.assetClass === AssetClass.LIQUIDITY
? holding.assetProfile.assetClass ? holding.assetProfile.assetClass
: undefined, : undefined,
assetClassLabel: assetClassLabel:
hasDetails || hasDetails || isCashPosition(holding.assetProfile)
holding.assetProfile.assetClass === AssetClass.LIQUIDITY
? holding.assetProfile.assetClassLabel ? holding.assetProfile.assetClassLabel
: undefined, : undefined,
assetSubClass: assetSubClass:
hasDetails || hasDetails || isCashPosition(holding.assetProfile)
holding.assetProfile.assetSubClass === AssetSubClass.CASH
? holding.assetProfile.assetSubClass ? holding.assetProfile.assetSubClass
: undefined, : undefined,
assetSubClassLabel: assetSubClassLabel:
hasDetails || hasDetails || isCashPosition(holding.assetProfile)
holding.assetProfile.assetSubClass === AssetSubClass.CASH
? holding.assetProfile.assetSubClassLabel ? holding.assetProfile.assetSubClassLabel
: undefined, : undefined,
holdings: holding.assetProfile.holdings?.map( holdings: holding.assetProfile.holdings?.map(

49
apps/api/src/app/portfolio/portfolio.controller.ts

@ -6,6 +6,7 @@ import {
hasNotDefinedValuesInObject, hasNotDefinedValuesInObject,
nullifyValuesInObject nullifyValuesInObject
} from '@ghostfolio/api/helper/object.helper'; } from '@ghostfolio/api/helper/object.helper';
import { convertValuesToPercentages } from '@ghostfolio/api/helper/portfolio.helper';
import { PerformanceLoggingInterceptor } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { PerformanceLoggingInterceptor } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor';
import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor'; import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor';
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor';
@ -15,6 +16,7 @@ import { ConfigurationService } from '@ghostfolio/api/services/configuration/con
import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper';
import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { UNKNOWN_KEY } from '@ghostfolio/common/config';
import { SubscriptionType } from '@ghostfolio/common/enums'; import { SubscriptionType } from '@ghostfolio/common/enums';
import { isCashPosition } from '@ghostfolio/common/helper';
import { import {
PortfolioDetails, PortfolioDetails,
PortfolioDividendsResponse, PortfolioDividendsResponse,
@ -44,7 +46,7 @@ import {
Version Version
} from '@nestjs/common'; } from '@nestjs/common';
import { REQUEST } from '@nestjs/core'; import { REQUEST } from '@nestjs/core';
import { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; import { DataSource } from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { StatusCodes, getReasonPhrase } from 'http-status-codes'; import { StatusCodes, getReasonPhrase } from 'http-status-codes';
@ -128,38 +130,7 @@ export class PortfolioController {
!hasScope(impersonationScopes, scopes.portfolioReadValues) || !hasScope(impersonationScopes, scopes.portfolioReadValues) ||
isRestrictedView(this.request.user) isRestrictedView(this.request.user)
) { ) {
const totalInvestment = holdings convertValuesToPercentages({ accounts, holdings, platforms });
.map(({ investment }) => {
return investment;
})
.reduce((a, b) => a + b, 0);
const totalValue = holdings
.filter(({ assetProfile }) => {
return (
assetProfile.assetClass !== AssetClass.LIQUIDITY &&
assetProfile.assetSubClass !== AssetSubClass.CASH
);
})
.map(({ valueInBaseCurrency }) => {
return valueInBaseCurrency;
})
.reduce((a, b) => {
return a + b;
}, 0);
for (const holding of holdings) {
holding.investment = holding.investment / totalInvestment;
holding.valueInPercentage = holding.valueInBaseCurrency / totalValue;
}
for (const [name, { valueInBaseCurrency }] of Object.entries(accounts)) {
accounts[name].valueInPercentage = valueInBaseCurrency / totalValue;
}
for (const [name, { valueInBaseCurrency }] of Object.entries(platforms)) {
platforms[name].valueInPercentage = valueInBaseCurrency / totalValue;
}
} }
if ( if (
@ -208,23 +179,19 @@ export class PortfolioController {
assetProfile: { assetProfile: {
...portfolioPosition.assetProfile, ...portfolioPosition.assetProfile,
assetClass: assetClass:
hasDetails || hasDetails || isCashPosition(portfolioPosition.assetProfile)
portfolioPosition.assetProfile.assetClass === AssetClass.LIQUIDITY
? portfolioPosition.assetProfile.assetClass ? portfolioPosition.assetProfile.assetClass
: undefined, : undefined,
assetClassLabel: assetClassLabel:
hasDetails || hasDetails || isCashPosition(portfolioPosition.assetProfile)
portfolioPosition.assetProfile.assetClass === AssetClass.LIQUIDITY
? portfolioPosition.assetProfile.assetClassLabel ? portfolioPosition.assetProfile.assetClassLabel
: undefined, : undefined,
assetSubClass: assetSubClass:
hasDetails || hasDetails || isCashPosition(portfolioPosition.assetProfile)
portfolioPosition.assetProfile.assetSubClass === AssetSubClass.CASH
? portfolioPosition.assetProfile.assetSubClass ? portfolioPosition.assetProfile.assetSubClass
: undefined, : undefined,
assetSubClassLabel: assetSubClassLabel:
hasDetails || hasDetails || isCashPosition(portfolioPosition.assetProfile)
portfolioPosition.assetProfile.assetSubClass === AssetSubClass.CASH
? portfolioPosition.assetProfile.assetSubClassLabel ? portfolioPosition.assetProfile.assetSubClassLabel
: undefined, : undefined,
...(hasDetails ...(hasDetails

49
apps/api/src/helper/portfolio.helper.ts

@ -1,5 +1,54 @@
import { PortfolioDetails } from '@ghostfolio/common/interfaces';
import { Type as ActivityType } from '@prisma/client'; import { Type as ActivityType } from '@prisma/client';
export function convertValuesToPercentages({
accounts,
holdings,
platforms
}: {
accounts: PortfolioDetails['accounts'];
holdings: PortfolioDetails['holdings'];
platforms: PortfolioDetails['platforms'];
}) {
const totalInvestment = holdings
.map(({ investment }) => {
return investment;
})
.reduce((a, b) => {
return a + b;
}, 0);
const totalValue = holdings
.map(({ valueInBaseCurrency }) => {
return valueInBaseCurrency;
})
.reduce((a, b) => {
return a + b;
}, 0);
for (const holding of holdings) {
holding.investment = totalInvestment
? holding.investment / totalInvestment
: 0;
holding.valueInPercentage = totalValue
? holding.valueInBaseCurrency / totalValue
: 0;
}
for (const account of Object.values(accounts)) {
account.valueInPercentage = totalValue
? account.valueInBaseCurrency / totalValue
: 0;
}
for (const platform of Object.values(platforms)) {
platform.valueInPercentage = totalValue
? platform.valueInBaseCurrency / totalValue
: 0;
}
}
export function getFactor(activityType: ActivityType) { export function getFactor(activityType: ActivityType) {
let factor: number; let factor: number;

203
apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts

@ -8,8 +8,10 @@ import { UserService } from '@ghostfolio/client/services/user/user.service';
import { MAX_TOP_HOLDINGS, UNKNOWN_KEY } from '@ghostfolio/common/config'; import { MAX_TOP_HOLDINGS, UNKNOWN_KEY } from '@ghostfolio/common/config';
import { import {
canOpenHoldingDetail, canOpenHoldingDetail,
convertValuesToPercentagesOfTotal,
getAssetProfileIdentifier, getAssetProfileIdentifier,
getCountryName getCountryName,
isCashPosition
} from '@ghostfolio/common/helper'; } from '@ghostfolio/common/helper';
import { import {
HoldingWithParents, HoldingWithParents,
@ -270,6 +272,20 @@ export class GfAllocationsPageComponent implements OnInit {
return UNKNOWN_KEY; return UNKNOWN_KEY;
} }
private extractValue({
valueInBaseCurrency,
valueInPercentage
}: {
valueInBaseCurrency?: PortfolioPosition['valueInBaseCurrency'];
valueInPercentage?: PortfolioPosition['valueInPercentage'];
}) {
return (
(isNumber(valueInBaseCurrency)
? valueInBaseCurrency
: valueInPercentage) ?? 0
);
}
private fetchPortfolioDetails() { private fetchPortfolioDetails() {
return this.dataService.fetchPortfolioDetails({ return this.dataService.fetchPortfolioDetails({
filters: this.userService.getFilters(), filters: this.userService.getFilters(),
@ -373,6 +389,8 @@ export class GfAllocationsPageComponent implements OnInit {
}; };
} }
let totalValueExcludingCashPositions = 0;
for (const position of this.portfolioDetails.holdings) { for (const position of this.portfolioDetails.holdings) {
const assetProfileIdentifier = getAssetProfileIdentifier( const assetProfileIdentifier = getAssetProfileIdentifier(
position.assetProfile position.assetProfile
@ -397,111 +415,104 @@ export class GfAllocationsPageComponent implements OnInit {
: (position.valueInBaseCurrency ?? 0) : (position.valueInBaseCurrency ?? 0)
}; };
// Prepare analysis data by continents, countries, holdings and sectors if (!isCashPosition(position.assetProfile)) {
// Prepare analysis data by continents, countries, holdings and sectors
if (position.assetProfile.countries.length > 0) { // except for cash
for (const country of position.assetProfile.countries) {
const { code, continent, weight } = country; totalValueExcludingCashPositions += this.extractValue(position);
const value =
(isNumber(position.valueInBaseCurrency) if (position.assetProfile.countries.length > 0) {
? position.valueInBaseCurrency for (const country of position.assetProfile.countries) {
: position.valueInPercentage) ?? 0; const { code, continent, weight } = country;
const value = this.extractValue(position);
const continentData = this.continents[continent];
if (continentData) {
continentData.value += weight * value;
} else {
this.continents[continent] = {
name: translate(continent),
value: weight * value
};
}
const countryData = this.countries[code];
if (countryData) {
countryData.value += weight * value;
} else {
this.countries[code] = {
name: getCountryName({ code }),
value: weight * value
};
}
}
} else {
const value = this.extractValue(position);
const continentData = this.continents[continent]; const continentData = this.continents[UNKNOWN_KEY];
if (continentData) { if (continentData) {
continentData.value += weight * value; continentData.value += value;
} else {
this.continents[continent] = {
name: translate(continent),
value: weight * value
};
} }
const countryData = this.countries[code]; const countryData = this.countries[UNKNOWN_KEY];
if (countryData) { if (countryData) {
countryData.value += weight * value; countryData.value += value;
} else {
this.countries[code] = {
name: getCountryName({ code }),
value: weight * value
};
} }
} }
} else {
const value =
(isNumber(position.valueInBaseCurrency)
? position.valueInBaseCurrency
: position.valueInPercentage) ?? 0;
const continentData = this.continents[UNKNOWN_KEY];
if (continentData) {
continentData.value += value;
}
const countryData = this.countries[UNKNOWN_KEY];
if (countryData) { if (position.assetProfile.holdings.length > 0) {
countryData.value += value; for (const {
} allocationInPercentage,
} name,
valueInBaseCurrency
if (position.assetProfile.holdings.length > 0) { } of position.assetProfile.holdings) {
for (const { const normalizedAssetName = this.normalizeAssetName(name);
allocationInPercentage, const value = isNumber(valueInBaseCurrency)
name, ? valueInBaseCurrency
valueInBaseCurrency : allocationInPercentage * (position.valueInPercentage ?? 0);
} of position.assetProfile.holdings) {
const normalizedAssetName = this.normalizeAssetName(name); const holdingData = this.topHoldingsMap[normalizedAssetName];
const value = isNumber(valueInBaseCurrency)
? valueInBaseCurrency if (holdingData) {
: allocationInPercentage * (position.valueInPercentage ?? 0); holdingData.value += value;
} else {
const holdingData = this.topHoldingsMap[normalizedAssetName]; this.topHoldingsMap[normalizedAssetName] = {
name,
if (holdingData) { value
holdingData.value += value; };
} else { }
this.topHoldingsMap[normalizedAssetName] = {
name,
value
};
} }
} }
}
if (position.assetProfile.sectors.length > 0) { if (position.assetProfile.sectors.length > 0) {
for (const sector of position.assetProfile.sectors) { for (const sector of position.assetProfile.sectors) {
const { name, weight } = sector; const { name, weight } = sector;
const value = const value = this.extractValue(position);
(isNumber(position.valueInBaseCurrency)
? position.valueInBaseCurrency const sectorData = this.sectors[name];
: position.valueInPercentage) ?? 0;
if (sectorData) {
sectorData.value += weight * value;
} else {
this.sectors[name] = {
name: translate(name),
value: weight * value
};
}
}
} else {
const value = this.extractValue(position);
const sectorData = this.sectors[name]; const sectorData = this.sectors[UNKNOWN_KEY];
if (sectorData) { if (sectorData) {
sectorData.value += weight * value; sectorData.value += value;
} else {
this.sectors[name] = {
name: translate(name),
value: weight * value
};
} }
} }
} else {
const value =
(isNumber(position.valueInBaseCurrency)
? position.valueInBaseCurrency
: position.valueInPercentage) ?? 0;
const sectorData = this.sectors[UNKNOWN_KEY];
if (sectorData) {
sectorData.value += value;
}
} }
if (this.holdings[assetProfileIdentifier].assetSubClass === 'ETF') { if (this.holdings[assetProfileIdentifier].assetSubClass === 'ETF') {
@ -510,10 +521,7 @@ export class GfAllocationsPageComponent implements OnInit {
const symbol = position.assetProfile.symbol; const symbol = position.assetProfile.symbol;
const value = const value = this.extractValue(position);
(isNumber(position.valueInBaseCurrency)
? position.valueInBaseCurrency
: position.valueInPercentage) ?? 0;
const symbolData = this.symbols[symbol]; const symbolData = this.symbols[symbol];
@ -533,6 +541,17 @@ export class GfAllocationsPageComponent implements OnInit {
} }
} }
if (this.showValuesInPercentage()) {
// The values are percentages of the whole portfolio, but the analysis
// data does not contain the cash positions
for (const values of [this.continents, this.countries, this.sectors]) {
convertValuesToPercentagesOfTotal({
values,
total: totalValueExcludingCashPositions
});
}
}
this.markets = this.portfolioDetails.markets; this.markets = this.portfolioDetails.markets;
if (this.portfolioDetails.marketsAdvanced) { if (this.portfolioDetails.marketsAdvanced) {

53
apps/client/src/app/pages/public/public-page.component.ts

@ -1,7 +1,9 @@
import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { UNKNOWN_KEY } from '@ghostfolio/common/config';
import { import {
convertValuesToPercentagesOfTotal,
getAssetProfileIdentifier, getAssetProfileIdentifier,
getCountryName getCountryName,
isCashPosition
} from '@ghostfolio/common/helper'; } from '@ghostfolio/common/helper';
import { import {
InfoItem, InfoItem,
@ -34,9 +36,7 @@ import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { ActivatedRoute, Router } from '@angular/router'; import { ActivatedRoute, Router } from '@angular/router';
import { AssetClass } from '@prisma/client';
import { StatusCodes } from 'http-status-codes'; import { StatusCodes } from 'http-status-codes';
import { isNumber } from 'lodash';
import { DeviceDetectorService } from 'ngx-device-detector'; import { DeviceDetectorService } from 'ngx-device-detector';
import { EMPTY } from 'rxjs'; import { EMPTY } from 'rxjs';
import { catchError } from 'rxjs/operators'; import { catchError } from 'rxjs/operators';
@ -178,6 +178,8 @@ export class GfPublicPageComponent implements OnInit {
} }
}; };
let totalValueExcludingCashPositions = 0;
for (const position of this.publicPortfolioDetails.holdings) { for (const position of this.publicPortfolioDetails.holdings) {
const assetProfileIdentifier = getAssetProfileIdentifier( const assetProfileIdentifier = getAssetProfileIdentifier(
position.assetProfile position.assetProfile
@ -191,39 +193,40 @@ export class GfPublicPageComponent implements OnInit {
value: position.allocationInPercentage value: position.allocationInPercentage
}; };
if (position.assetProfile.assetClass !== AssetClass.LIQUIDITY) { if (!isCashPosition(position.assetProfile)) {
// Prepare analysis data by continents, countries, holdings and sectors except for liquidity // Prepare analysis data by continents, countries, holdings and sectors
// except for cash
const value = position.valueInPercentage ?? 0;
totalValueExcludingCashPositions += value;
if (position.assetProfile.countries.length > 0) { if (position.assetProfile.countries.length > 0) {
for (const country of position.assetProfile.countries) { for (const country of position.assetProfile.countries) {
const { code, continent, weight } = country; const { code, continent, weight } = country;
if (this.continents[continent]?.value) { if (this.continents[continent]?.value) {
this.continents[continent].value += this.continents[continent].value += weight * value;
weight * (position.valueInBaseCurrency ?? 0);
} else { } else {
this.continents[continent] = { this.continents[continent] = {
name: translate(continent), name: translate(continent),
value: weight * (position.valueInBaseCurrency ?? 0) value: weight * value
}; };
} }
if (this.countries[code]?.value) { if (this.countries[code]?.value) {
this.countries[code].value += this.countries[code].value += weight * value;
weight * (position.valueInBaseCurrency ?? 0);
} else { } else {
this.countries[code] = { this.countries[code] = {
name: getCountryName({ code }), name: getCountryName({ code }),
value: weight * (position.valueInBaseCurrency ?? 0) value: weight * value
}; };
} }
} }
} else { } else {
this.continents[UNKNOWN_KEY].value += this.continents[UNKNOWN_KEY].value += value;
position.valueInBaseCurrency ?? 0;
this.countries[UNKNOWN_KEY].value += this.countries[UNKNOWN_KEY].value += value;
position.valueInBaseCurrency ?? 0;
} }
if (position.assetProfile.sectors.length > 0) { if (position.assetProfile.sectors.length > 0) {
@ -231,25 +234,22 @@ export class GfPublicPageComponent implements OnInit {
const { name, weight } = sector; const { name, weight } = sector;
if (this.sectors[name]?.value) { if (this.sectors[name]?.value) {
this.sectors[name].value += this.sectors[name].value += weight * value;
weight * (position.valueInBaseCurrency ?? 0);
} else { } else {
this.sectors[name] = { this.sectors[name] = {
name: translate(name), name: translate(name),
value: weight * (position.valueInBaseCurrency ?? 0) value: weight * value
}; };
} }
} }
} else { } else {
this.sectors[UNKNOWN_KEY].value += position.valueInBaseCurrency ?? 0; this.sectors[UNKNOWN_KEY].value += value;
} }
} }
const symbol = position.assetProfile.symbol; const symbol = position.assetProfile.symbol;
const value = isNumber(position.valueInBaseCurrency) const value = position.valueInPercentage ?? 0;
? position.valueInBaseCurrency
: (position.valueInPercentage ?? 0);
const symbolData = this.symbols[symbol]; const symbolData = this.symbols[symbol];
@ -264,5 +264,14 @@ export class GfPublicPageComponent implements OnInit {
}; };
} }
} }
// The values are percentages of the whole portfolio, but the analysis data
// does not contain the cash positions
for (const values of [this.continents, this.countries, this.sectors]) {
convertValuesToPercentagesOfTotal({
values,
total: totalValueExcludingCashPositions
});
}
} }
} }

24
libs/common/src/lib/helper.ts

@ -232,6 +232,22 @@ export function capitalize(aString: string) {
return aString.charAt(0).toUpperCase() + aString.slice(1).toLowerCase(); return aString.charAt(0).toUpperCase() + aString.slice(1).toLowerCase();
} }
export function convertValuesToPercentagesOfTotal({
total,
values
}: {
total: number;
values: { [key: string]: { value: number } };
}) {
if (!total) {
return;
}
for (const item of Object.values(values)) {
item.value = item.value / total;
}
}
export function downloadAsFile({ export function downloadAsFile({
content, content,
contentType = 'text/plain', contentType = 'text/plain',
@ -553,6 +569,14 @@ export function isAccountExcluded(account?: { tags?: { id: string }[] }) {
); );
} }
export function isCashPosition({
assetSubClass
}: {
assetSubClass?: AssetSubClass;
} = {}) {
return assetSubClass === AssetSubClass.CASH;
}
export function isCurrency(aCurrency: string) { export function isCurrency(aCurrency: string) {
if (!aCurrency) { if (!aCurrency) {
return false; return false;

1
libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts

@ -17,7 +17,6 @@ export interface PublicPortfolioResponse extends PublicPortfolioResponseV1 {
| 'dateOfFirstActivity' | 'dateOfFirstActivity'
| 'markets' | 'markets'
| 'netPerformancePercentWithCurrencyEffect' | 'netPerformancePercentWithCurrencyEffect'
| 'valueInBaseCurrency'
| 'valueInPercentage' | 'valueInPercentage'
>[]; >[];
latestActivities: (Pick< latestActivities: (Pick<

6
libs/ui/src/lib/services/data.service.ts

@ -788,12 +788,6 @@ export class DataService {
holding.assetProfile.assetSubClassLabel = translate( holding.assetProfile.assetSubClassLabel = translate(
holding.assetProfile.assetSubClass holding.assetProfile.assetSubClass
); );
holding.valueInBaseCurrency = isNumber(
holding.valueInBaseCurrency
)
? holding.valueInBaseCurrency
: holding.valueInPercentage;
} }
} }

Loading…
Cancel
Save