|
|
@ -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,15 +415,16 @@ export class GfAllocationsPageComponent implements OnInit { |
|
|
: (position.valueInBaseCurrency ?? 0) |
|
|
: (position.valueInBaseCurrency ?? 0) |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
if (!isCashPosition(position.assetProfile)) { |
|
|
// Prepare analysis data by continents, countries, holdings and sectors
|
|
|
// Prepare analysis data by continents, countries, holdings and sectors
|
|
|
|
|
|
// except for cash
|
|
|
|
|
|
|
|
|
|
|
|
totalValueExcludingCashPositions += this.extractValue(position); |
|
|
|
|
|
|
|
|
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; |
|
|
const value = |
|
|
const value = this.extractValue(position); |
|
|
(isNumber(position.valueInBaseCurrency) |
|
|
|
|
|
? position.valueInBaseCurrency |
|
|
|
|
|
: position.valueInPercentage) ?? 0; |
|
|
|
|
|
|
|
|
|
|
|
const continentData = this.continents[continent]; |
|
|
const continentData = this.continents[continent]; |
|
|
|
|
|
|
|
|
@ -430,10 +449,7 @@ export class GfAllocationsPageComponent implements OnInit { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
const value = |
|
|
const value = this.extractValue(position); |
|
|
(isNumber(position.valueInBaseCurrency) |
|
|
|
|
|
? position.valueInBaseCurrency |
|
|
|
|
|
: position.valueInPercentage) ?? 0; |
|
|
|
|
|
|
|
|
|
|
|
const continentData = this.continents[UNKNOWN_KEY]; |
|
|
const continentData = this.continents[UNKNOWN_KEY]; |
|
|
|
|
|
|
|
|
@ -475,10 +491,7 @@ export class GfAllocationsPageComponent implements OnInit { |
|
|
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 |
|
|
|
|
|
: position.valueInPercentage) ?? 0; |
|
|
|
|
|
|
|
|
|
|
|
const sectorData = this.sectors[name]; |
|
|
const sectorData = this.sectors[name]; |
|
|
|
|
|
|
|
|
@ -492,10 +505,7 @@ export class GfAllocationsPageComponent implements OnInit { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} else { |
|
|
} else { |
|
|
const value = |
|
|
const value = this.extractValue(position); |
|
|
(isNumber(position.valueInBaseCurrency) |
|
|
|
|
|
? position.valueInBaseCurrency |
|
|
|
|
|
: position.valueInPercentage) ?? 0; |
|
|
|
|
|
|
|
|
|
|
|
const sectorData = this.sectors[UNKNOWN_KEY]; |
|
|
const sectorData = this.sectors[UNKNOWN_KEY]; |
|
|
|
|
|
|
|
|
@ -503,6 +513,7 @@ export class GfAllocationsPageComponent implements OnInit { |
|
|
sectorData.value += value; |
|
|
sectorData.value += value; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (this.holdings[assetProfileIdentifier].assetSubClass === 'ETF') { |
|
|
if (this.holdings[assetProfileIdentifier].assetSubClass === 'ETF') { |
|
|
this.totalValueInEtf += this.holdings[assetProfileIdentifier].value; |
|
|
this.totalValueInEtf += this.holdings[assetProfileIdentifier].value; |
|
|
@ -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) { |
|
|
|