Feature/refactor portfolio holding response (#4649)

* Refactor portfolio holding response

* maxPrice -> marketPriceMax
* minPrice -> marketPriceMin
* orders -> activities
This commit is contained in:
Thomas Kaul 2025-05-04 09:48:43 +02:00 committed by GitHub
parent 1bced96460
commit 3646fb7f77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 49 additions and 43 deletions

View File

@ -49,7 +49,7 @@ export class ImportService {
symbol
}: AssetProfileIdentifier): Promise<Activity[]> {
try {
const { firstBuyDate, historicalData, orders } =
const { activities, firstBuyDate, historicalData } =
await this.portfolioService.getHolding(dataSource, undefined, symbol);
const [[assetProfile], dividends] = await Promise.all([
@ -68,7 +68,7 @@ export class ImportService {
})
]);
const accounts = orders
const accounts = activities
.filter(({ Account }) => {
return !!Account;
})
@ -88,7 +88,7 @@ export class ImportService {
const value = new Big(quantity).mul(marketPrice).toNumber();
const date = parseDate(dateString);
const isDuplicate = orders.some((activity) => {
const isDuplicate = activities.some((activity) => {
return (
activity.accountId === Account?.id &&
activity.SymbolProfile.currency === assetProfile.currency &&

View File

@ -648,6 +648,7 @@ export class PortfolioService {
if (activities.length === 0) {
return {
activities: [],
averagePrice: undefined,
dataProviderInfo: undefined,
dividendInBaseCurrency: undefined,
@ -662,13 +663,12 @@ export class PortfolioService {
historicalData: [],
investment: undefined,
marketPrice: undefined,
maxPrice: undefined,
minPrice: undefined,
marketPriceMax: undefined,
marketPriceMin: undefined,
netPerformance: undefined,
netPerformancePercent: undefined,
netPerformancePercentWithCurrencyEffect: undefined,
netPerformanceWithCurrencyEffect: undefined,
orders: [],
quantity: undefined,
SymbolProfile: undefined,
tags: [],
@ -714,7 +714,7 @@ export class PortfolioService {
transactionCount
} = position;
const activitiesOfPosition = activities.filter(({ SymbolProfile }) => {
const activitiesOfHolding = activities.filter(({ SymbolProfile }) => {
return (
SymbolProfile.dataSource === dataSource &&
SymbolProfile.symbol === symbol
@ -748,12 +748,12 @@ export class PortfolioService {
);
const historicalDataArray: HistoricalDataItem[] = [];
let maxPrice = Math.max(
activitiesOfPosition[0].unitPriceInAssetProfileCurrency,
let marketPriceMax = Math.max(
activitiesOfHolding[0].unitPriceInAssetProfileCurrency,
marketPrice
);
let minPrice = Math.min(
activitiesOfPosition[0].unitPriceInAssetProfileCurrency,
let marketPriceMin = Math.min(
activitiesOfHolding[0].unitPriceInAssetProfileCurrency,
marketPrice
);
@ -793,27 +793,31 @@ export class PortfolioService {
quantity: currentQuantity
});
maxPrice = Math.max(marketPrice ?? 0, maxPrice);
minPrice = Math.min(marketPrice ?? Number.MAX_SAFE_INTEGER, minPrice);
marketPriceMax = Math.max(marketPrice ?? 0, marketPriceMax);
marketPriceMin = Math.min(
marketPrice ?? Number.MAX_SAFE_INTEGER,
marketPriceMin
);
}
} else {
// Add historical entry for buy date, if no historical data available
historicalDataArray.push({
averagePrice: activitiesOfPosition[0].unitPriceInAssetProfileCurrency,
averagePrice: activitiesOfHolding[0].unitPriceInAssetProfileCurrency,
date: firstBuyDate,
marketPrice: activitiesOfPosition[0].unitPriceInAssetProfileCurrency,
quantity: activitiesOfPosition[0].quantity
marketPrice: activitiesOfHolding[0].unitPriceInAssetProfileCurrency,
quantity: activitiesOfHolding[0].quantity
});
}
return {
firstBuyDate,
marketPrice,
maxPrice,
minPrice,
marketPriceMax,
marketPriceMin,
SymbolProfile,
tags,
transactionCount,
activities: activitiesOfHolding,
averagePrice: averagePrice.toNumber(),
dataProviderInfo: portfolioCalculator.getDataProviderInfos()?.[0],
dividendInBaseCurrency: dividendInBaseCurrency.toNumber(),
@ -842,7 +846,6 @@ export class PortfolioService {
]?.toNumber(),
netPerformanceWithCurrencyEffect:
position.netPerformanceWithCurrencyEffectMap?.['max']?.toNumber(),
orders: activitiesOfPosition,
quantity: quantity.toNumber(),
value: this.exchangeRateDataService.toCurrency(
quantity.mul(marketPrice ?? 0).toNumber(),
@ -881,8 +884,8 @@ export class PortfolioService {
}
const historicalDataArray: HistoricalDataItem[] = [];
let maxPrice = marketPrice;
let minPrice = marketPrice;
let marketPriceMax = marketPrice;
let marketPriceMin = marketPrice;
for (const [date, { marketPrice }] of Object.entries(
historicalData[aSymbol]
@ -892,15 +895,19 @@ export class PortfolioService {
value: marketPrice
});
maxPrice = Math.max(marketPrice ?? 0, maxPrice);
minPrice = Math.min(marketPrice ?? Number.MAX_SAFE_INTEGER, minPrice);
marketPriceMax = Math.max(marketPrice ?? 0, marketPriceMax);
marketPriceMin = Math.min(
marketPrice ?? Number.MAX_SAFE_INTEGER,
marketPriceMin
);
}
return {
marketPrice,
maxPrice,
minPrice,
marketPriceMax,
marketPriceMin,
SymbolProfile,
activities: [],
averagePrice: 0,
dataProviderInfo: undefined,
dividendInBaseCurrency: 0,
@ -918,7 +925,6 @@ export class PortfolioService {
netPerformancePercent: undefined,
netPerformancePercentWithCurrencyEffect: undefined,
netPerformanceWithCurrencyEffect: undefined,
orders: [],
quantity: 0,
tags: [],
transactionCount: undefined,

View File

@ -105,8 +105,8 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
public investmentPrecision = 2;
public marketDataItems: MarketData[] = [];
public marketPrice: number;
public maxPrice: number;
public minPrice: number;
public marketPriceMax: number;
public marketPriceMin: number;
public netPerformance: number;
public netPerformancePrecision = 2;
public netPerformancePercent: number;
@ -234,8 +234,8 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
historicalData,
investment,
marketPrice,
maxPrice,
minPrice,
marketPriceMax,
marketPriceMin,
netPerformance,
netPerformancePercent,
netPerformancePercentWithCurrencyEffect,
@ -297,8 +297,8 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit {
}
this.marketPrice = marketPrice;
this.maxPrice = maxPrice;
this.minPrice = minPrice;
this.marketPriceMax = marketPriceMax;
this.marketPriceMin = marketPriceMin;
this.netPerformance = netPerformance;
if (

View File

@ -106,11 +106,11 @@
[locale]="data.locale"
[ngClass]="{
'text-danger':
minPrice?.toFixed(2) === marketPrice?.toFixed(2) &&
maxPrice?.toFixed(2) !== minPrice?.toFixed(2)
marketPriceMin?.toFixed(2) === marketPrice?.toFixed(2) &&
marketPriceMax?.toFixed(2) !== marketPriceMin?.toFixed(2)
}"
[unit]="SymbolProfile?.currency"
[value]="minPrice"
[value]="marketPriceMin"
>Minimum Price</gf-value
>
</div>
@ -122,11 +122,11 @@
[locale]="data.locale"
[ngClass]="{
'text-success':
maxPrice?.toFixed(2) === marketPrice?.toFixed(2) &&
maxPrice?.toFixed(2) !== minPrice?.toFixed(2)
marketPriceMax?.toFixed(2) === marketPrice?.toFixed(2) &&
marketPriceMax?.toFixed(2) !== marketPriceMin?.toFixed(2)
}"
[unit]="SymbolProfile?.currency"
[value]="maxPrice"
[value]="marketPriceMax"
>Maximum Price</gf-value
>
</div>

View File

@ -411,8 +411,8 @@ export class DataService {
)
.pipe(
map((data) => {
if (data.orders) {
for (const order of data.orders) {
if (data.activities) {
for (const order of data.activities) {
order.createdAt = parseISO(order.createdAt as unknown as string);
order.date = parseISO(order.date as unknown as string);
}

View File

@ -8,6 +8,7 @@ import {
import { Tag } from '@prisma/client';
export interface PortfolioHoldingResponse {
activities: Activity[];
averagePrice: number;
dataProviderInfo: DataProviderInfo;
dividendInBaseCurrency: number;
@ -22,13 +23,12 @@ export interface PortfolioHoldingResponse {
historicalData: HistoricalDataItem[];
investment: number;
marketPrice: number;
maxPrice: number;
minPrice: number;
marketPriceMax: number;
marketPriceMin: number;
netPerformance: number;
netPerformancePercent: number;
netPerformancePercentWithCurrencyEffect: number;
netPerformanceWithCurrencyEffect: number;
orders: Activity[];
quantity: number;
SymbolProfile: EnhancedSymbolProfile;
tags: Tag[];