Browse Source

Fix null handling and add error logger

pull/5027/head
Daniel Devaud 1 year ago
parent
commit
7de92569c1
  1. 93
      apps/api/src/app/portfolio/calculator/constantPortfolioReturn/portfolio-calculator.ts

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

@ -9,6 +9,7 @@ import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
import { HistoricalDataItem } from '@ghostfolio/common/interfaces'; import { HistoricalDataItem } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types'; import { DateRange } from '@ghostfolio/common/types';
import { Logger } from '@nestjs/common';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { import {
addDays, addDays,
@ -88,7 +89,7 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
start: Date; start: Date;
step?: number; step?: number;
}): Promise<HistoricalDataItem[]> { }): Promise<HistoricalDataItem[]> {
let marketMapTask = this.computeMarketMap({ in: [start, end] }); let marketMapTask = this.computeMarketMap({ gte: start, lte: end });
const timelineHoldings = await this.getHoldings(start, end); const timelineHoldings = await this.getHoldings(start, end);
const calculationDates = Object.keys(timelineHoldings) const calculationDates = Object.keys(timelineHoldings)
@ -186,42 +187,71 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
previousDate: string, previousDate: string,
holding: string, holding: string,
date: string, date: string,
totalInvestment, totalInvestment: Big,
timelineHoldings: { [date: string]: { [symbol: string]: Big } }, timelineHoldings: { [date: string]: { [symbol: string]: Big } },
netPerformanceInPercentage, netPerformanceInPercentage: Big,
netPerformanceInPercentageWithCurrencyEffect, netPerformanceInPercentageWithCurrencyEffect: Big,
newTotalInvestment newTotalInvestment: Big
) { ) {
const previousPrice = this.marketMap[previousDate][holding]; const previousPrice = this.marketMap[previousDate][holding];
const currentPrice = this.marketMap[date][holding]; const currentPrice = this.marketMap[date][holding] ?? previousPrice;
const previousPriceInBaseCurrency = const previousHolding = timelineHoldings[previousDate][holding];
await this.exchangeRateDataService.toCurrencyAtDate(
previousPrice.toNumber(), const priceInBaseCurrency = currentPrice
this.getCurrency(holding), ? new Big(
this.currency, await this.exchangeRateDataService.toCurrencyAtDate(
parseDate(previousDate) currentPrice?.toNumber() ?? 0,
this.getCurrency(holding),
this.currency,
parseDate(date)
)
)
: new Big(0);
if (previousHolding.eq(0)) {
return {
netPerformanceInPercentage: new Big(0),
netPerformanceInPercentageWithCurrencyEffect: new Big(0),
newTotalInvestment: newTotalInvestment.plus(
timelineHoldings[date][holding].mul(priceInBaseCurrency)
)
};
}
if (!currentPrice || !previousPrice) {
Logger.warn(
`Missing historical market data for ${holding} (${!currentPrice ? date : previousDate}})`,
'PortfolioCalculator'
); );
const portfolioWeight = totalInvestment return {
? timelineHoldings[previousDate][holding] netPerformanceInPercentage: new Big(0),
.mul(previousPriceInBaseCurrency) netPerformanceInPercentageWithCurrencyEffect: new Big(0),
.div(totalInvestment) newTotalInvestment: newTotalInvestment.plus(
timelineHoldings[date][holding].mul(priceInBaseCurrency)
)
};
}
const previousPriceInBaseCurrency = previousPrice
? new Big(
await this.exchangeRateDataService.toCurrencyAtDate(
previousPrice?.toNumber() ?? 0,
this.getCurrency(holding),
this.currency,
parseDate(previousDate)
)
)
: new Big(0);
const portfolioWeight = totalInvestment.toNumber()
? previousHolding.mul(previousPriceInBaseCurrency).div(totalInvestment)
: 0; : 0;
netPerformanceInPercentage = netPerformanceInPercentage.plus( netPerformanceInPercentage = netPerformanceInPercentage.plus(
currentPrice.div(previousPrice).minus(1).mul(portfolioWeight) currentPrice.div(previousPrice).minus(1).mul(portfolioWeight)
); );
const priceInBaseCurrency =
await this.exchangeRateDataService.toCurrencyAtDate(
currentPrice.toNumber(),
this.getCurrency(holding),
this.currency,
parseDate(date)
);
netPerformanceInPercentageWithCurrencyEffect = netPerformanceInPercentageWithCurrencyEffect =
netPerformanceInPercentageWithCurrencyEffect.plus( netPerformanceInPercentageWithCurrencyEffect.plus(
new Big(priceInBaseCurrency) priceInBaseCurrency
.div(new Big(previousPriceInBaseCurrency)) .div(previousPriceInBaseCurrency)
.minus(1) .minus(1)
.mul(portfolioWeight) .mul(portfolioWeight)
); );
@ -343,15 +373,18 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
} }
@LogPerformance @LogPerformance
private async computeMarketMap(dateQuery: { in: Date[] }) { private async computeMarketMap(dateQuery: { gte: Date; lte: Date }) {
const dataGatheringItems: IDataGatheringItem[] = this.activities.map( const dataGatheringItems: IDataGatheringItem[] = this.activities
(activity) => { .map((activity) => {
return { return {
symbol: activity.SymbolProfile.symbol, symbol: activity.SymbolProfile.symbol,
dataSource: activity.SymbolProfile.dataSource dataSource: activity.SymbolProfile.dataSource
}; };
} })
); .filter(
(gathering, i, arr) =>
arr.findIndex((t) => t.symbol === gathering.symbol) === i
);
const { values: marketSymbols } = await this.currentRateService.getValues({ const { values: marketSymbols } = await this.currentRateService.getValues({
dataGatheringItems, dataGatheringItems,
dateQuery dateQuery

Loading…
Cancel
Save