Browse Source

Task/add asset profile to portfolio position interface (#6473)

* Add asset profile

* Update changelog
pull/6493/head
Thomas Kaul 3 days ago
committed by GitHub
parent
commit
b7d976d2ff
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 1
      apps/api/src/app/endpoints/public/public.controller.ts
  3. 31
      apps/api/src/app/portfolio/portfolio.service.ts
  4. 1
      apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts
  5. 45
      libs/common/src/lib/interfaces/portfolio-position.interface.ts
  6. 15
      libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts
  7. 155
      libs/ui/src/lib/mocks/holdings.ts

2
CHANGELOG.md

@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Included asset profile data in the endpoint `GET api/v1/portfolio/holdings`
- Included asset profile data in the holdings of the public page
- Reused the value component in the platform management of the admin control panel - Reused the value component in the platform management of the admin control panel
- Reused the value component in the tag management of the admin control panel - Reused the value component in the tag management of the admin control panel
- Upgraded `jsonpath` from version `1.1.1` to `1.2.1` - Upgraded `jsonpath` from version `1.1.1` to `1.2.1`

1
apps/api/src/app/endpoints/public/public.controller.ts

@ -167,6 +167,7 @@ export class PublicController {
allocationInPercentage: allocationInPercentage:
portfolioPosition.valueInBaseCurrency / totalValue, portfolioPosition.valueInBaseCurrency / totalValue,
assetClass: hasDetails ? portfolioPosition.assetClass : undefined, assetClass: hasDetails ? portfolioPosition.assetClass : undefined,
assetProfile: hasDetails ? portfolioPosition.assetProfile : undefined,
countries: hasDetails ? portfolioPosition.countries : [], countries: hasDetails ? portfolioPosition.countries : [],
currency: hasDetails ? portfolioPosition.currency : undefined, currency: hasDetails ? portfolioPosition.currency : undefined,
dataSource: portfolioPosition.dataSource, dataSource: portfolioPosition.dataSource,

31
apps/api/src/app/portfolio/portfolio.service.ts

@ -623,6 +623,27 @@ export class PortfolioService {
? 0 ? 0
: valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(), : valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(),
assetClass: assetProfile.assetClass, assetClass: assetProfile.assetClass,
assetProfile: {
assetClass: assetProfile.assetClass,
assetSubClass: assetProfile.assetSubClass,
countries: assetProfile.countries,
dataSource: assetProfile.dataSource,
holdings: assetProfile.holdings.map(
({ allocationInPercentage, name }) => {
return {
allocationInPercentage,
name,
valueInBaseCurrency: valueInBaseCurrency
.mul(allocationInPercentage)
.toNumber()
};
}
),
name: assetProfile.name,
sectors: assetProfile.sectors,
symbol: assetProfile.symbol,
url: assetProfile.url
},
assetSubClass: assetProfile.assetSubClass, assetSubClass: assetProfile.assetSubClass,
countries: assetProfile.countries, countries: assetProfile.countries,
dataSource: assetProfile.dataSource, dataSource: assetProfile.dataSource,
@ -1672,6 +1693,16 @@ export class PortfolioService {
allocationInPercentage: 0, allocationInPercentage: 0,
assetClass: AssetClass.LIQUIDITY, assetClass: AssetClass.LIQUIDITY,
assetSubClass: AssetSubClass.CASH, assetSubClass: AssetSubClass.CASH,
assetProfile: {
assetClass: AssetClass.LIQUIDITY,
assetSubClass: AssetSubClass.CASH,
countries: [],
dataSource: undefined,
holdings: [],
name: currency,
sectors: [],
symbol: currency
},
countries: [], countries: [],
dataSource: undefined, dataSource: undefined,
dateOfFirstActivity: undefined, dateOfFirstActivity: undefined,

1
apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts

@ -68,6 +68,7 @@ export class TransformDataSourceInResponseInterceptor<
'errors[*].dataSource', 'errors[*].dataSource',
'fearAndGreedIndex.CRYPTOCURRENCIES.dataSource', 'fearAndGreedIndex.CRYPTOCURRENCIES.dataSource',
'fearAndGreedIndex.STOCKS.dataSource', 'fearAndGreedIndex.STOCKS.dataSource',
'holdings[*].assetProfile.dataSource',
'holdings[*].dataSource', 'holdings[*].dataSource',
'items[*].dataSource', 'items[*].dataSource',
'SymbolProfile.dataSource', 'SymbolProfile.dataSource',

45
libs/common/src/lib/interfaces/portfolio-position.interface.ts

@ -3,19 +3,50 @@ import { Market, MarketAdvanced } from '@ghostfolio/common/types';
import { AssetClass, AssetSubClass, DataSource, Tag } from '@prisma/client'; import { AssetClass, AssetSubClass, DataSource, Tag } from '@prisma/client';
import { Country } from './country.interface'; import { Country } from './country.interface';
import { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface';
import { Holding } from './holding.interface'; import { Holding } from './holding.interface';
import { Sector } from './sector.interface'; import { Sector } from './sector.interface';
export interface PortfolioPosition { export interface PortfolioPosition {
activitiesCount: number; activitiesCount: number;
allocationInPercentage: number; allocationInPercentage: number;
/** @deprecated */
assetClass?: AssetClass; assetClass?: AssetClass;
/** @deprecated */
assetClassLabel?: string; assetClassLabel?: string;
assetProfile: Pick<
EnhancedSymbolProfile,
| 'assetClass'
| 'assetSubClass'
| 'countries'
| 'dataSource'
| 'holdings'
| 'name'
| 'sectors'
| 'symbol'
| 'url'
> & {
assetClassLabel?: string;
assetSubClassLabel?: string;
};
/** @deprecated */
assetSubClass?: AssetSubClass; assetSubClass?: AssetSubClass;
/** @deprecated */
assetSubClassLabel?: string; assetSubClassLabel?: string;
/** @deprecated */
countries: Country[]; countries: Country[];
currency: string; currency: string;
/** @deprecated */
dataSource: DataSource; dataSource: DataSource;
dateOfFirstActivity: Date; dateOfFirstActivity: Date;
dividend: number; dividend: number;
exchange?: string; exchange?: string;
@ -23,24 +54,38 @@ export interface PortfolioPosition {
grossPerformancePercent: number; grossPerformancePercent: number;
grossPerformancePercentWithCurrencyEffect: number; grossPerformancePercentWithCurrencyEffect: number;
grossPerformanceWithCurrencyEffect: number; grossPerformanceWithCurrencyEffect: number;
/** @deprecated */
holdings: Holding[]; holdings: Holding[];
investment: number; investment: number;
marketChange?: number; marketChange?: number;
marketChangePercent?: number; marketChangePercent?: number;
marketPrice: number; marketPrice: number;
markets?: { [key in Market]: number }; markets?: { [key in Market]: number };
marketsAdvanced?: { [key in MarketAdvanced]: number }; marketsAdvanced?: { [key in MarketAdvanced]: number };
/** @deprecated */
name: string; name: string;
netPerformance: number; netPerformance: number;
netPerformancePercent: number; netPerformancePercent: number;
netPerformancePercentWithCurrencyEffect: number; netPerformancePercentWithCurrencyEffect: number;
netPerformanceWithCurrencyEffect: number; netPerformanceWithCurrencyEffect: number;
quantity: number; quantity: number;
/** @deprecated */
sectors: Sector[]; sectors: Sector[];
/** @deprecated */
symbol: string; symbol: string;
tags?: Tag[]; tags?: Tag[];
type?: string; type?: string;
/** @deprecated */
url?: string; url?: string;
valueInBaseCurrency?: number; valueInBaseCurrency?: number;
valueInPercentage?: number; valueInPercentage?: number;
} }

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

@ -14,16 +14,31 @@ export interface PublicPortfolioResponse extends PublicPortfolioResponseV1 {
[symbol: string]: Pick< [symbol: string]: Pick<
PortfolioPosition, PortfolioPosition,
| 'allocationInPercentage' | 'allocationInPercentage'
/** @deprecated */
| 'assetClass' | 'assetClass'
| 'assetProfile'
/** @deprecated */
| 'countries' | 'countries'
| 'currency' | 'currency'
/** @deprecated */
| 'dataSource' | 'dataSource'
| 'dateOfFirstActivity' | 'dateOfFirstActivity'
| 'markets' | 'markets'
/** @deprecated */
| 'name' | 'name'
| 'netPerformancePercentWithCurrencyEffect' | 'netPerformancePercentWithCurrencyEffect'
/** @deprecated */
| 'sectors' | 'sectors'
/** @deprecated */
| 'symbol' | 'symbol'
/** @deprecated */
| 'url' | 'url'
| 'valueInBaseCurrency' | 'valueInBaseCurrency'
| 'valueInPercentage' | 'valueInPercentage'

155
libs/ui/src/lib/mocks/holdings.ts

@ -6,14 +6,35 @@ export const holdings: PortfolioPosition[] = [
allocationInPercentage: 0.042990776363386086, allocationInPercentage: 0.042990776363386086,
assetClass: 'EQUITY', assetClass: 'EQUITY',
assetClassLabel: 'Equity', assetClassLabel: 'Equity',
assetProfile: {
assetClass: 'EQUITY',
assetSubClass: 'STOCK',
countries: [
{
code: 'US',
continent: 'North America',
name: 'United States',
weight: 1
}
],
dataSource: 'YAHOO',
holdings: [],
sectors: [
{
name: 'Technology',
weight: 1
}
],
symbol: 'AAPL'
},
assetSubClass: 'STOCK', assetSubClass: 'STOCK',
assetSubClassLabel: 'Stock', assetSubClassLabel: 'Stock',
countries: [ countries: [
{ {
code: 'US', code: 'US',
weight: 1,
continent: 'North America', continent: 'North America',
name: 'United States' name: 'United States',
weight: 1
} }
], ],
currency: 'USD', currency: 'USD',
@ -49,14 +70,35 @@ export const holdings: PortfolioPosition[] = [
allocationInPercentage: 0.02377401948293552, allocationInPercentage: 0.02377401948293552,
assetClass: 'EQUITY', assetClass: 'EQUITY',
assetClassLabel: 'Equity', assetClassLabel: 'Equity',
assetProfile: {
assetClass: 'EQUITY',
assetSubClass: 'STOCK',
countries: [
{
code: 'DE',
continent: 'Europe',
name: 'Germany',
weight: 1
}
],
dataSource: 'YAHOO',
holdings: [],
sectors: [
{
name: 'Financial Services',
weight: 1
}
],
symbol: 'ALV.DE'
},
assetSubClass: 'STOCK', assetSubClass: 'STOCK',
assetSubClassLabel: 'Stock', assetSubClassLabel: 'Stock',
countries: [ countries: [
{ {
code: 'DE', code: 'DE',
weight: 1,
continent: 'Europe', continent: 'Europe',
name: 'Germany' name: 'Germany',
weight: 1
} }
], ],
currency: 'EUR', currency: 'EUR',
@ -92,14 +134,35 @@ export const holdings: PortfolioPosition[] = [
allocationInPercentage: 0.08038536990007467, allocationInPercentage: 0.08038536990007467,
assetClass: 'EQUITY', assetClass: 'EQUITY',
assetClassLabel: 'Equity', assetClassLabel: 'Equity',
assetProfile: {
assetClass: 'EQUITY',
assetSubClass: 'STOCK',
countries: [
{
code: 'US',
continent: 'North America',
name: 'United States',
weight: 1
}
],
dataSource: 'YAHOO',
holdings: [],
sectors: [
{
name: 'Consumer Discretionary',
weight: 1
}
],
symbol: 'AMZN'
},
assetSubClass: 'STOCK', assetSubClass: 'STOCK',
assetSubClassLabel: 'Stock', assetSubClassLabel: 'Stock',
countries: [ countries: [
{ {
code: 'US', code: 'US',
weight: 1,
continent: 'North America', continent: 'North America',
name: 'United States' name: 'United States',
weight: 1
} }
], ],
currency: 'USD', currency: 'USD',
@ -135,6 +198,15 @@ export const holdings: PortfolioPosition[] = [
allocationInPercentage: 0.19216416482928922, allocationInPercentage: 0.19216416482928922,
assetClass: 'LIQUIDITY', assetClass: 'LIQUIDITY',
assetClassLabel: 'Liquidity', assetClassLabel: 'Liquidity',
assetProfile: {
assetClass: 'LIQUIDITY',
assetSubClass: 'CASH',
countries: [],
dataSource: 'COINGECKO',
holdings: [],
sectors: [],
symbol: 'bitcoin'
},
assetSubClass: 'CRYPTOCURRENCY', assetSubClass: 'CRYPTOCURRENCY',
assetSubClassLabel: 'Cryptocurrency', assetSubClassLabel: 'Cryptocurrency',
countries: [], countries: [],
@ -166,14 +238,35 @@ export const holdings: PortfolioPosition[] = [
allocationInPercentage: 0.04307127421937313, allocationInPercentage: 0.04307127421937313,
assetClass: 'EQUITY', assetClass: 'EQUITY',
assetClassLabel: 'Equity', assetClassLabel: 'Equity',
assetProfile: {
assetClass: 'EQUITY',
assetSubClass: 'STOCK',
countries: [
{
code: 'US',
continent: 'North America',
name: 'United States',
weight: 1
}
],
dataSource: 'YAHOO',
holdings: [],
sectors: [
{
name: 'Technology',
weight: 1
}
],
symbol: 'MSFT'
},
assetSubClass: 'STOCK', assetSubClass: 'STOCK',
assetSubClassLabel: 'Stock', assetSubClassLabel: 'Stock',
countries: [ countries: [
{ {
code: 'US', code: 'US',
weight: 1,
continent: 'North America', continent: 'North America',
name: 'United States' name: 'United States',
weight: 1
} }
], ],
currency: 'USD', currency: 'USD',
@ -209,14 +302,35 @@ export const holdings: PortfolioPosition[] = [
allocationInPercentage: 0.18762679306394897, allocationInPercentage: 0.18762679306394897,
assetClass: 'EQUITY', assetClass: 'EQUITY',
assetClassLabel: 'Equity', assetClassLabel: 'Equity',
assetProfile: {
assetClass: 'EQUITY',
assetSubClass: 'STOCK',
countries: [
{
code: 'US',
continent: 'North America',
name: 'United States',
weight: 1
}
],
dataSource: 'YAHOO',
holdings: [],
sectors: [
{
name: 'Consumer Discretionary',
weight: 1
}
],
symbol: 'TSLA'
},
assetSubClass: 'STOCK', assetSubClass: 'STOCK',
assetSubClassLabel: 'Stock', assetSubClassLabel: 'Stock',
countries: [ countries: [
{ {
code: 'US', code: 'US',
weight: 1,
continent: 'North America', continent: 'North America',
name: 'United States' name: 'United States',
weight: 1
} }
], ],
currency: 'USD', currency: 'USD',
@ -252,6 +366,27 @@ export const holdings: PortfolioPosition[] = [
allocationInPercentage: 0.053051250766657634, allocationInPercentage: 0.053051250766657634,
assetClass: 'EQUITY', assetClass: 'EQUITY',
assetClassLabel: 'Equity', assetClassLabel: 'Equity',
assetProfile: {
assetClass: 'EQUITY',
assetSubClass: 'ETF',
countries: [
{
code: 'US',
continent: 'North America',
name: 'United States',
weight: 1
}
],
dataSource: 'YAHOO',
holdings: [],
sectors: [
{
name: 'Equity',
weight: 1
}
],
symbol: 'VTI'
},
assetSubClass: 'ETF', assetSubClass: 'ETF',
assetSubClassLabel: 'ETF', assetSubClassLabel: 'ETF',
countries: [ countries: [

Loading…
Cancel
Save