diff --git a/apps/api/src/app/portfolio/calculator/mwr/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/mwr/portfolio-calculator.ts index 1b142d8b3..eb49b7cdb 100644 --- a/apps/api/src/app/portfolio/calculator/mwr/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/mwr/portfolio-calculator.ts @@ -16,7 +16,6 @@ export class MWRPortfolioCalculator extends PortfolioCalculator { dataSource, end, exchangeRates, - isChartMode = false, marketSymbolMap, start, step = 1, @@ -24,7 +23,6 @@ export class MWRPortfolioCalculator extends PortfolioCalculator { }: { end: Date; exchangeRates: { [dateString: string]: number }; - isChartMode?: boolean; marketSymbolMap: { [date: string]: { [symbol: string]: Big }; }; diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index 729547df2..dd9bcdebb 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -320,11 +320,9 @@ export abstract class PortfolioCalculator { investmentValuesWithCurrencyEffect, netPerformance, netPerformancePercentage, - netPerformancePercentageWithCurrencyEffect, netPerformancePercentageWithCurrencyEffectMap, netPerformanceValues, netPerformanceValuesWithCurrencyEffect, - netPerformanceWithCurrencyEffect, netPerformanceWithCurrencyEffectMap, timeWeightedInvestment, timeWeightedInvestmentValues, @@ -344,7 +342,6 @@ export abstract class PortfolioCalculator { end: this.endDate, exchangeRates: exchangeRatesByCurrency[`${item.currency}${this.currency}`], - isChartMode: true, start: this.startDate, symbol: item.symbol }); @@ -673,11 +670,10 @@ export abstract class PortfolioCalculator { const { historicalData } = this.snapshot; - const newChartData: HistoricalDataItem[] = []; + const chart: HistoricalDataItem[] = []; let netPerformanceAtStartDate: number; let netPerformanceWithCurrencyEffectAtStartDate: number; - let netPerformanceInPercentageWithCurrencyEffectAtStartDate: number; let totalInvestmentValuesWithCurrencyEffect: number[] = []; for (let historicalDataItem of historicalData) { @@ -689,9 +685,6 @@ export abstract class PortfolioCalculator { netPerformanceWithCurrencyEffectAtStartDate = historicalDataItem.netPerformanceWithCurrencyEffect; - - netPerformanceInPercentageWithCurrencyEffectAtStartDate = - historicalDataItem.netPerformanceInPercentageWithCurrencyEffect; } const netPerformanceSinceStartDate = @@ -713,7 +706,7 @@ export abstract class PortfolioCalculator { totalInvestmentValuesWithCurrencyEffect.length : 0; - newChartData.push({ + chart.push({ ...historicalDataItem, netPerformance: historicalDataItem.netPerformance - netPerformanceAtStartDate, @@ -733,7 +726,7 @@ export abstract class PortfolioCalculator { } } - return { chart: newChartData }; + return { chart }; } public getStartDate() { @@ -768,7 +761,6 @@ export abstract class PortfolioCalculator { dataSource, end, exchangeRates, - isChartMode, marketSymbolMap, start, symbol @@ -776,7 +768,6 @@ export abstract class PortfolioCalculator { chartDateMap: { [date: string]: boolean }; end: Date; exchangeRates: { [dateString: string]: number }; - isChartMode?: boolean; marketSymbolMap: { [date: string]: { [symbol: string]: Big }; }; diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts index db458fb3c..fba0ead84 100644 --- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts @@ -31,7 +31,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { let grossPerformanceWithCurrencyEffect = new Big(0); let hasErrors = false; let netPerformance = new Big(0); - let netPerformanceWithCurrencyEffect = new Big(0); let totalFeesWithCurrencyEffect = new Big(0); let totalInterestWithCurrencyEffect = new Big(0); let totalInvestment = new Big(0); @@ -76,11 +75,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { ); netPerformance = netPerformance.plus(currentPosition.netPerformance); - - netPerformanceWithCurrencyEffect = - netPerformanceWithCurrencyEffect.plus( - currentPosition.netPerformancePercentageWithCurrencyEffectMap['max'] - ); } else if (!currentPosition.quantity.eq(0)) { hasErrors = true; } @@ -123,7 +117,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { dataSource, end, exchangeRates, - isChartMode = false, marketSymbolMap, start, symbol @@ -131,7 +124,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { chartDateMap?: { [date: string]: boolean }; end: Date; exchangeRates: { [dateString: string]: number }; - isChartMode?: boolean; marketSymbolMap: { [date: string]: { [symbol: string]: Big }; }; @@ -211,11 +203,9 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { investmentValuesWithCurrencyEffect: {}, netPerformance: new Big(0), netPerformancePercentage: new Big(0), - netPerformancePercentageWithCurrencyEffect: new Big(0), netPerformancePercentageWithCurrencyEffectMap: {}, netPerformanceValues: {}, netPerformanceValuesWithCurrencyEffect: {}, - netPerformanceWithCurrencyEffect: new Big(0), netPerformanceWithCurrencyEffectMap: {}, timeWeightedInvestment: new Big(0), timeWeightedInvestmentValues: {}, @@ -263,12 +253,10 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { investmentValuesWithCurrencyEffect: {}, netPerformance: new Big(0), netPerformancePercentage: new Big(0), - netPerformancePercentageWithCurrencyEffect: new Big(0), netPerformancePercentageWithCurrencyEffectMap: {}, netPerformanceWithCurrencyEffectMap: {}, netPerformanceValues: {}, netPerformanceValuesWithCurrencyEffect: {}, - netPerformanceWithCurrencyEffect: new Big(0), timeWeightedInvestment: new Big(0), timeWeightedInvestmentValues: {}, timeWeightedInvestmentValuesWithCurrencyEffect: {}, @@ -319,46 +307,43 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { let day = start; let lastUnitPrice: Big; - if (isChartMode) { - const ordersByDate: { [date: string]: PortfolioOrderItem[] } = {}; + const ordersByDate: { [date: string]: PortfolioOrderItem[] } = {}; - for (const order of orders) { - ordersByDate[order.date] = ordersByDate[order.date] ?? []; - ordersByDate[order.date].push(order); - } + for (const order of orders) { + ordersByDate[order.date] = ordersByDate[order.date] ?? []; + ordersByDate[order.date].push(order); + } - while (isBefore(day, end)) { - const dateString = format(day, DATE_FORMAT); + while (isBefore(day, end)) { + const dateString = format(day, DATE_FORMAT); - if (ordersByDate[dateString]?.length > 0) { - for (let order of ordersByDate[dateString]) { - order.unitPriceFromMarketData = - marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice; - } - } else if (chartDateMap[dateString]) { - orders.push({ - date: dateString, - fee: new Big(0), - feeInBaseCurrency: new Big(0), - quantity: new Big(0), - SymbolProfile: { - dataSource, - symbol - }, - type: 'BUY', - unitPrice: marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice, - unitPriceFromMarketData: - marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice - }); + if (ordersByDate[dateString]?.length > 0) { + for (let order of ordersByDate[dateString]) { + order.unitPriceFromMarketData = + marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice; } + } else if (chartDateMap[dateString]) { + orders.push({ + date: dateString, + fee: new Big(0), + feeInBaseCurrency: new Big(0), + quantity: new Big(0), + SymbolProfile: { + dataSource, + symbol + }, + type: 'BUY', + unitPrice: marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice, + unitPriceFromMarketData: + marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice + }); + } - const lastOrder = last(orders); + const lastOrder = last(orders); - lastUnitPrice = - lastOrder.unitPriceFromMarketData ?? lastOrder.unitPrice; + lastUnitPrice = lastOrder.unitPriceFromMarketData ?? lastOrder.unitPrice; - day = addDays(day, 1); - } + day = addDays(day, 1); } // Sort orders so that the start and end placeholder order are at the correct @@ -681,44 +666,42 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { ); } - if (isChartMode) { - currentValues[order.date] = valueOfInvestment; + currentValues[order.date] = valueOfInvestment; - currentValuesWithCurrencyEffect[order.date] = - valueOfInvestmentWithCurrencyEffect; + currentValuesWithCurrencyEffect[order.date] = + valueOfInvestmentWithCurrencyEffect; - netPerformanceValues[order.date] = grossPerformance - .minus(grossPerformanceAtStartDate) - .minus(fees.minus(feesAtStartDate)); + netPerformanceValues[order.date] = grossPerformance + .minus(grossPerformanceAtStartDate) + .minus(fees.minus(feesAtStartDate)); - netPerformanceValuesWithCurrencyEffect[order.date] = - grossPerformanceWithCurrencyEffect - .minus(grossPerformanceAtStartDateWithCurrencyEffect) - .minus( - feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect) - ); + netPerformanceValuesWithCurrencyEffect[order.date] = + grossPerformanceWithCurrencyEffect + .minus(grossPerformanceAtStartDateWithCurrencyEffect) + .minus( + feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect) + ); - investmentValuesAccumulated[order.date] = totalInvestment; + investmentValuesAccumulated[order.date] = totalInvestment; - investmentValuesAccumulatedWithCurrencyEffect[order.date] = - totalInvestmentWithCurrencyEffect; + investmentValuesAccumulatedWithCurrencyEffect[order.date] = + totalInvestmentWithCurrencyEffect; - investmentValuesWithCurrencyEffect[order.date] = ( - investmentValuesWithCurrencyEffect[order.date] ?? new Big(0) - ).add(transactionInvestmentWithCurrencyEffect); + investmentValuesWithCurrencyEffect[order.date] = ( + investmentValuesWithCurrencyEffect[order.date] ?? new Big(0) + ).add(transactionInvestmentWithCurrencyEffect); - timeWeightedInvestmentValues[order.date] = - totalInvestmentDays > 0 - ? sumOfTimeWeightedInvestments.div(totalInvestmentDays) - : new Big(0); + timeWeightedInvestmentValues[order.date] = + totalInvestmentDays > 0 + ? sumOfTimeWeightedInvestments.div(totalInvestmentDays) + : new Big(0); - timeWeightedInvestmentValuesWithCurrencyEffect[order.date] = - totalInvestmentDays > 0 - ? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div( - totalInvestmentDays - ) - : new Big(0); - } + timeWeightedInvestmentValuesWithCurrencyEffect[order.date] = + totalInvestmentDays > 0 + ? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div( + totalInvestmentDays + ) + : new Big(0); } if (PortfolioCalculator.ENABLE_LOGGING) { @@ -760,11 +743,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { .minus(grossPerformanceAtStartDate) .minus(fees.minus(feesAtStartDate)); - const totalNetPerformanceWithCurrencyEffect = - grossPerformanceWithCurrencyEffect - .minus(grossPerformanceAtStartDateWithCurrencyEffect) - .minus(feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect)); - const timeWeightedAverageInvestmentBetweenStartAndEndDate = totalInvestmentDays > 0 ? sumOfTimeWeightedInvestments.div(totalInvestmentDays) @@ -810,15 +788,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { ) : new Big(0); - const netPerformancePercentageWithCurrencyEffect = - timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect.gt( - 0 - ) - ? totalNetPerformanceWithCurrencyEffect.div( - timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect - ) - : new Big(0); - const netPerformancePercentageWithCurrencyEffectMap: { [key: DateRange]: Big; } = {}; @@ -946,9 +915,9 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { Net performance: ${totalNetPerformance.toFixed( 2 )} / ${netPerformancePercentage.mul(100).toFixed(2)}% - Net performance with currency effect: ${totalNetPerformanceWithCurrencyEffect.toFixed( - 2 - )} / ${netPerformancePercentageWithCurrencyEffect.mul(100).toFixed(2)}%` + Net performance with currency effect: ${netPerformancePercentageWithCurrencyEffectMap[ + 'max' + ].toFixed(2)}%` ); } @@ -964,7 +933,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { investmentValuesAccumulatedWithCurrencyEffect, investmentValuesWithCurrencyEffect, netPerformancePercentage, - netPerformancePercentageWithCurrencyEffect, netPerformancePercentageWithCurrencyEffectMap, netPerformanceValues, netPerformanceValuesWithCurrencyEffect, @@ -987,7 +955,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator { totalGrossPerformanceWithCurrencyEffect, hasErrors: totalUnits.gt(0) && (!initialValue || !unitPriceAtEndDate), netPerformance: totalNetPerformance, - netPerformanceWithCurrencyEffect: totalNetPerformanceWithCurrencyEffect, timeWeightedInvestment: timeWeightedAverageInvestmentBetweenStartAndEndDate, timeWeightedInvestmentWithCurrencyEffect: diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 29ecfd423..9e3f7fdbc 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -4,6 +4,7 @@ import { DEFAULT_ROOT_URL } from '@ghostfolio/common/config'; import { Injectable } from '@nestjs/common'; import { DataSource } from '@prisma/client'; import { bool, cleanEnv, host, json, num, port, str, url } from 'envalid'; +import ms from 'ms'; @Injectable() export class ConfigurationService { @@ -20,7 +21,7 @@ export class ConfigurationService { API_KEY_FINANCIAL_MODELING_PREP: str({ default: '' }), API_KEY_OPEN_FIGI: str({ default: '' }), API_KEY_RAPID_API: str({ default: '' }), - CACHE_QUOTES_TTL: num({ default: 60 }), + CACHE_QUOTES_TTL: num({ default: ms('1 minute') / 1000 }), CACHE_TTL: num({ default: 1 }), DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }), DATA_SOURCE_IMPORT: str({ default: DataSource.YAHOO }), diff --git a/libs/common/src/lib/interfaces/symbol-metrics.interface.ts b/libs/common/src/lib/interfaces/symbol-metrics.interface.ts index 6977e7d4c..24c1e1db4 100644 --- a/libs/common/src/lib/interfaces/symbol-metrics.interface.ts +++ b/libs/common/src/lib/interfaces/symbol-metrics.interface.ts @@ -28,13 +28,11 @@ export interface SymbolMetrics { }; netPerformance: Big; netPerformancePercentage: Big; - netPerformancePercentageWithCurrencyEffect: Big; netPerformancePercentageWithCurrencyEffectMap: { [key: DateRange]: Big }; netPerformanceValues: { [date: string]: Big; }; netPerformanceValuesWithCurrencyEffect: { [date: string]: Big }; - netPerformanceWithCurrencyEffect: Big; netPerformanceWithCurrencyEffectMap: { [key: DateRange]: Big }; timeWeightedInvestment: Big; timeWeightedInvestmentValues: {