Browse Source

Improve handling of excluded holdings

pull/7828/head
Thomas Kaul 2 days ago
parent
commit
cce9ab1c55
  1. 7
      apps/api/src/app/activities/activities.service.ts
  2. 8
      apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts
  3. 12
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  4. 48
      apps/api/src/app/portfolio/portfolio.service.ts
  5. 21
      libs/ui/src/lib/activities-table/activities-table.component.ts

7
apps/api/src/app/activities/activities.service.ts

@ -759,7 +759,8 @@ export class ActivitiesService {
filters,
userCurrency,
userId,
withCash = false
withCash = false,
withExcludedAccountsAndActivities = false
}: {
/** Optional filters to apply to the activities. */
filters?: Filter[];
@ -769,13 +770,15 @@ export class ActivitiesService {
userId: string;
/** Whether to include cash activities in the result. */
withCash?: boolean;
/** Whether to include activities that are excluded from analysis. */
withExcludedAccountsAndActivities?: boolean;
}) {
const [activities, splits] = await Promise.all([
this.getActivities({
filters,
userCurrency,
userId,
withExcludedAccountsAndActivities: false // TODO
withExcludedAccountsAndActivities
}),
this.assetProfileSplitService.getSplitsByUserId({ userId })
]);

8
apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts

@ -34,7 +34,8 @@ export class PortfolioCalculatorFactory {
calculationType,
currency,
filters = [],
userId
userId,
usePortfolioSnapshotCache = true
}: {
accountBalanceItems?: HistoricalDataItem[];
activities: Activity[];
@ -42,6 +43,7 @@ export class PortfolioCalculatorFactory {
currency: string;
filters?: Filter[];
userId: string;
usePortfolioSnapshotCache?: boolean;
}): PortfolioCalculator {
switch (calculationType) {
case PerformanceCalculationType.MWR:
@ -51,6 +53,7 @@ export class PortfolioCalculatorFactory {
currency,
filters,
userId,
usePortfolioSnapshotCache,
configurationService: this.configurationService,
currentRateService: this.currentRateService,
exchangeRateDataService: this.exchangeRateDataService,
@ -65,6 +68,7 @@ export class PortfolioCalculatorFactory {
currency,
filters,
userId,
usePortfolioSnapshotCache,
configurationService: this.configurationService,
currentRateService: this.currentRateService,
exchangeRateDataService: this.exchangeRateDataService,
@ -79,6 +83,7 @@ export class PortfolioCalculatorFactory {
currency,
filters,
userId,
usePortfolioSnapshotCache,
configurationService: this.configurationService,
currentRateService: this.currentRateService,
exchangeRateDataService: this.exchangeRateDataService,
@ -93,6 +98,7 @@ export class PortfolioCalculatorFactory {
currency,
filters,
userId,
usePortfolioSnapshotCache,
configurationService: this.configurationService,
currentRateService: this.currentRateService,
exchangeRateDataService: this.exchangeRateDataService,

12
apps/api/src/app/portfolio/calculator/portfolio-calculator.ts

@ -91,6 +91,7 @@ export abstract class PortfolioCalculator {
private startDate: Date;
private transactionPoints: TransactionPoint[];
private userId: string;
private usePortfolioSnapshotCache: boolean;
public constructor({
accountBalanceItems,
@ -102,7 +103,8 @@ export abstract class PortfolioCalculator {
filters,
portfolioSnapshotService,
redisCacheService,
userId
userId,
usePortfolioSnapshotCache = true
}: {
accountBalanceItems: HistoricalDataItem[];
activities: Activity[];
@ -114,6 +116,7 @@ export abstract class PortfolioCalculator {
portfolioSnapshotService: PortfolioSnapshotService;
redisCacheService: RedisCacheService;
userId: string;
usePortfolioSnapshotCache?: boolean;
}) {
this.accountBalanceItems = accountBalanceItems;
this.configurationService = configurationService;
@ -176,6 +179,7 @@ export abstract class PortfolioCalculator {
this.portfolioSnapshotService = portfolioSnapshotService;
this.redisCacheService = redisCacheService;
this.userId = userId;
this.usePortfolioSnapshotCache = usePortfolioSnapshotCache;
const { endDate, startDate } = getIntervalFromDateRange({
dateRange: 'max',
@ -187,7 +191,11 @@ export abstract class PortfolioCalculator {
this.computeTransactionPoints();
this.snapshotPromise = this.initialize();
this.snapshotPromise = this.usePortfolioSnapshotCache
? this.initialize()
: this.computeSnapshot().then((snapshot) => {
this.snapshot = snapshot;
});
// Mark the rejection as handled to prevent an unhandled promise rejection
// in case the snapshot promise is never awaited. Consumers awaiting it

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

@ -895,12 +895,36 @@ export class PortfolioService {
const user = await this.userService.user({ id: userId });
const userCurrency = this.getUserCurrency(user);
const { activities } =
const holdingFilters: Filter[] = [
{ id: dataSource, type: 'DATA_SOURCE' },
{ id: symbol, type: 'SYMBOL' }
];
const { activities: allActivitiesOfHolding } =
await this.activitiesService.getActivitiesForPortfolioCalculator({
userCurrency,
userId
userId,
filters: holdingFilters,
withExcludedAccountsAndActivities: true
});
if (allActivitiesOfHolding.length === 0) {
return undefined;
}
const hasExcludedActivities = allActivitiesOfHolding.some((activity) => {
return this.isExcludedFromAnalysis(activity);
});
const activities = hasExcludedActivities
? allActivitiesOfHolding
: (
await this.activitiesService.getActivitiesForPortfolioCalculator({
userCurrency,
userId
})
).activities;
if (activities.length === 0) {
return undefined;
}
@ -927,7 +951,9 @@ export class PortfolioService {
activities,
userId,
calculationType: this.getUserPerformanceCalculationType(user),
currency: userCurrency
currency: userCurrency,
filters: hasExcludedActivities ? holdingFilters : undefined,
usePortfolioSnapshotCache: !hasExcludedActivities
});
const transactionPoints = portfolioCalculator.getTransactionPoints();
@ -2033,12 +2059,7 @@ export class PortfolioService {
const nonExcludedActivities: Activity[] = [];
for (const activity of activities) {
if (
(activity.account && isAccountExcluded(activity.account)) ||
activity.tags?.some(({ id }) => {
return id === TAG_ID_EXCLUDE_FROM_ANALYSIS;
})
) {
if (this.isExcludedFromAnalysis(activity)) {
excludedActivities.push(activity);
} else {
nonExcludedActivities.push(activity);
@ -2204,6 +2225,15 @@ export class PortfolioService {
};
}
private isExcludedFromAnalysis(activity: Activity) {
return (
isAccountExcluded(activity.account) ||
activity.tags?.some(({ id }) => {
return id === TAG_ID_EXCLUDE_FROM_ANALYSIS;
}) === true
);
}
private getSumOfActivityType({
activities,
activityType,

21
libs/ui/src/lib/activities-table/activities-table.component.ts

@ -1,13 +1,6 @@
import {
DEFAULT_PAGE_SIZE,
TAG_ID_EXCLUDE_FROM_ANALYSIS
} from '@ghostfolio/common/config';
import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config';
import { ConfirmationDialogType } from '@ghostfolio/common/enums';
import {
getLocale,
isAccountExcluded,
isDraftActivity
} from '@ghostfolio/common/helper';
import { getLocale, isDraftActivity } from '@ghostfolio/common/helper';
import {
Activity,
AssetProfileIdentifier
@ -286,7 +279,6 @@ export class GfActivitiesTableComponent implements AfterViewInit, OnInit {
public canClickActivity(activity: Activity) {
return (
this.hasPermissionToOpenDetails &&
this.isExcludedFromAnalysis(activity) === false &&
isDraftActivity(activity) === false &&
['BUY', 'DIVIDEND', 'SELL'].includes(activity.type)
);
@ -306,15 +298,6 @@ export class GfActivitiesTableComponent implements AfterViewInit, OnInit {
);
}
public isExcludedFromAnalysis(activity: Activity) {
return (
isAccountExcluded(activity.account) ||
activity.tags?.some(({ id }) => {
return id === TAG_ID_EXCLUDE_FROM_ANALYSIS;
}) === true
);
}
public onChangePage(page: PageEvent) {
this.pageChanged.emit(page);
}

Loading…
Cancel
Save