Browse Source

Refactor time weighted graph

pull/5027/head
Daniel Devaud 1 year ago
parent
commit
f3cb92a704
  1. 98
      apps/api/src/app/portfolio/calculator/constantPortfolioReturn/portfolio-calculator.ts
  2. 2
      apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts
  3. 4
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  4. 51
      apps/api/src/app/portfolio/portfolio.service.ts

98
apps/api/src/app/portfolio/calculator/constantPortfolioReturn/portfolio-calculator.ts

@ -1,14 +1,14 @@
import { getFactor } from '@ghostfolio/api/helper/portfolio.helper';
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
import {
HistoricalDataItem,
SymbolMetrics,
UniqueAsset
} from '@ghostfolio/common/interfaces';
import { PortfolioSnapshot, TimelinePosition } from '@ghostfolio/common/models';
getFactor,
getInterval
} from '@ghostfolio/api/helper/portfolio.helper';
import { MAX_CHART_ITEMS } from '@ghostfolio/common/config';
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
import { HistoricalDataItem } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types';
import { Big } from 'big.js';
import { addDays, eachDayOfInterval, format } from 'date-fns';
import { addDays, differenceInDays, eachDayOfInterval, format } from 'date-fns';
import { PortfolioOrder } from '../../interfaces/portfolio-order.interface';
import { TWRPortfolioCalculator } from '../twr/portfolio-calculator';
@ -17,44 +17,60 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
private holdings: { [date: string]: { [symbol: string]: Big } } = {};
private holdingCurrencies: { [symbol: string]: string } = {};
protected calculateOverallPerformance(
positions: TimelinePosition[]
): PortfolioSnapshot {
return super.calculateOverallPerformance(positions);
}
protected getSymbolMetrics({
dataSource,
end,
exchangeRates,
isChartMode = false,
marketSymbolMap,
start,
step = 1,
symbol
public async getChart({
dateRange = 'max',
withDataDecimation = true,
withTimeWeightedReturn = false
}: {
end: Date;
exchangeRates: { [dateString: string]: number };
isChartMode?: boolean;
marketSymbolMap: {
[date: string]: { [symbol: string]: Big };
};
start: Date;
step?: number;
} & UniqueAsset): SymbolMetrics {
return super.getSymbolMetrics({
dataSource,
end,
exchangeRates,
isChartMode,
marketSymbolMap,
start,
dateRange?: DateRange;
withDataDecimation?: boolean;
withTimeWeightedReturn?: boolean;
}): Promise<HistoricalDataItem[]> {
const { endDate, startDate } = getInterval(dateRange, this.getStartDate());
const daysInMarket = differenceInDays(endDate, startDate) + 1;
const step = withDataDecimation
? Math.round(daysInMarket / Math.min(daysInMarket, MAX_CHART_ITEMS))
: 1;
let item = super.getChartData({
step,
symbol
end: endDate,
start: startDate
});
if (!withTimeWeightedReturn) {
return item;
}
if (withTimeWeightedReturn) {
let timeWeighted = await this.getTimeWeightedChartData({
step,
end: endDate,
start: startDate
});
return item.then((data) => {
return data.map((item) => {
let timeWeightedItem = timeWeighted.find(
(timeWeightedItem) => timeWeightedItem.date === item.date
);
if (timeWeightedItem) {
item.timeWeightedPerformance =
timeWeightedItem.timeWeightedPerformance;
item.timeWeightedPerformanceWithCurrencyEffect =
timeWeightedItem.timeWeightedPerformanceWithCurrencyEffect;
}
return item;
});
});
}
return item;
}
public override async getChartData({
private async getTimeWeightedChartData({
end = new Date(Date.now()),
start,
step = 1

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

@ -64,7 +64,7 @@ export class PortfolioCalculatorFactory {
redisCacheService: this.redisCacheService
});
case PerformanceCalculationType.TWR:
return new TWRPortfolioCalculator({
return new CPRPortfolioCalculator({
accountBalanceItems,
activities,
currency,

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

@ -424,10 +424,12 @@ export abstract class PortfolioCalculator {
public async getChart({
dateRange = 'max',
withDataDecimation = true
withDataDecimation = true,
withTimeWeightedReturn = false
}: {
dateRange?: DateRange;
withDataDecimation?: boolean;
withTimeWeightedReturn?: boolean;
}): Promise<HistoricalDataItem[]> {
const { endDate, startDate } = getInterval(dateRange, this.getStartDate());

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

@ -1282,18 +1282,9 @@ export class PortfolioService {
let currentNetWorth = 0;
let items = await portfolioCalculator.getChart({
dateRange
});
items = await this.calculatedTimeWeightedPerformance(
calculateTimeWeightedPerformance,
activities,
dateRange,
userId,
userCurrency,
filters,
items
);
withTimeWeightedReturn: calculateTimeWeightedPerformance
});
const itemOfToday = items.find(({ date }) => {
return date === format(new Date(), DATE_FORMAT);
@ -1342,44 +1333,6 @@ export class PortfolioService {
};
}
private async calculatedTimeWeightedPerformance(
calculateTimeWeightedPerformance: boolean,
activities: Activity[],
dateRange: string,
userId: string,
userCurrency: string,
filters: Filter[],
items: HistoricalDataItem[]
) {
if (calculateTimeWeightedPerformance) {
const portfolioCalculatorCPR = this.calculatorFactory.createCalculator({
activities,
dateRange,
userId,
calculationType: PerformanceCalculationType.CPR,
currency: userCurrency,
hasFilters: filters?.length > 0,
isExperimentalFeatures:
this.request.user.Settings.settings.isExperimentalFeatures
});
let timeWeightedInvestmentItems = await portfolioCalculatorCPR.getChart({
dateRange
});
items = items.map((item) => {
let matchingItem = timeWeightedInvestmentItems.find(
(timeWeightedInvestmentItem) =>
timeWeightedInvestmentItem.date === item.date
);
item.timeWeightedPerformance = matchingItem.netPerformanceInPercentage;
item.timeWeightedPerformanceWithCurrencyEffect =
matchingItem.netPerformanceInPercentageWithCurrencyEffect;
return item;
});
}
return items;
}
@LogPerformance
public async getReport(impersonationId: string): Promise<PortfolioReport> {
const userId = await this.getUserId(impersonationId, this.request.user.id);

Loading…
Cancel
Save