|
|
@ -1,4 +1,5 @@ |
|
|
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; |
|
|
import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; |
|
|
|
|
|
import { PortfolioCalculatorPosition } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-calculator-position.interface'; |
|
|
import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface'; |
|
|
import { PortfolioOrder } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-order.interface'; |
|
|
import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface'; |
|
|
import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface'; |
|
|
import { TransactionPointSymbol } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point-symbol.interface'; |
|
|
import { TransactionPointSymbol } from '@ghostfolio/api/app/portfolio/interfaces/transaction-point-symbol.interface'; |
|
|
@ -34,7 +35,7 @@ import { |
|
|
ResponseError, |
|
|
ResponseError, |
|
|
SymbolMetrics |
|
|
SymbolMetrics |
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
import { PortfolioSnapshot, TimelinePosition } from '@ghostfolio/common/models'; |
|
|
import { PortfolioSnapshot } from '@ghostfolio/common/models'; |
|
|
import { GroupBy } from '@ghostfolio/common/types'; |
|
|
import { GroupBy } from '@ghostfolio/common/types'; |
|
|
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; |
|
|
import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; |
|
|
|
|
|
|
|
|
@ -176,7 +177,7 @@ export abstract class PortfolioCalculator { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
protected abstract calculateOverallPerformance( |
|
|
protected abstract calculateOverallPerformance( |
|
|
positions: TimelinePosition[] |
|
|
positions: PortfolioCalculatorPosition[] |
|
|
): PortfolioSnapshot; |
|
|
): PortfolioSnapshot; |
|
|
|
|
|
|
|
|
@LogPerformance |
|
|
@LogPerformance |
|
|
@ -312,9 +313,7 @@ export abstract class PortfolioCalculator { |
|
|
const errors: ResponseError['errors'] = []; |
|
|
const errors: ResponseError['errors'] = []; |
|
|
let hasAnySymbolMetricsErrors = false; |
|
|
let hasAnySymbolMetricsErrors = false; |
|
|
|
|
|
|
|
|
const positions: (TimelinePosition & { |
|
|
const positions: PortfolioCalculatorPosition[] = []; |
|
|
includeInHoldings: boolean; |
|
|
|
|
|
})[] = []; |
|
|
|
|
|
|
|
|
|
|
|
const accumulatedValuesByDate: { |
|
|
const accumulatedValuesByDate: { |
|
|
[date: string]: { |
|
|
[date: string]: { |
|
|
@ -326,6 +325,7 @@ export abstract class PortfolioCalculator { |
|
|
totalInvestmentValueWithCurrencyEffect: Big; |
|
|
totalInvestmentValueWithCurrencyEffect: Big; |
|
|
totalNetPerformanceValue: Big; |
|
|
totalNetPerformanceValue: Big; |
|
|
totalNetPerformanceValueWithCurrencyEffect: Big; |
|
|
totalNetPerformanceValueWithCurrencyEffect: Big; |
|
|
|
|
|
totalNetWorthValueWithCurrencyEffect: Big; |
|
|
totalTimeWeightedInvestmentValue: Big; |
|
|
totalTimeWeightedInvestmentValue: Big; |
|
|
totalTimeWeightedInvestmentValueWithCurrencyEffect: Big; |
|
|
totalTimeWeightedInvestmentValueWithCurrencyEffect: Big; |
|
|
}; |
|
|
}; |
|
|
@ -340,6 +340,7 @@ export abstract class PortfolioCalculator { |
|
|
investmentValuesWithCurrencyEffect: { [date: string]: Big }; |
|
|
investmentValuesWithCurrencyEffect: { [date: string]: Big }; |
|
|
netPerformanceValues: { [date: string]: Big }; |
|
|
netPerformanceValues: { [date: string]: Big }; |
|
|
netPerformanceValuesWithCurrencyEffect: { [date: string]: Big }; |
|
|
netPerformanceValuesWithCurrencyEffect: { [date: string]: Big }; |
|
|
|
|
|
netWorthValuesWithCurrencyEffect: { [date: string]: Big }; |
|
|
timeWeightedInvestmentValues: { [date: string]: Big }; |
|
|
timeWeightedInvestmentValues: { [date: string]: Big }; |
|
|
timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big }; |
|
|
timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big }; |
|
|
}; |
|
|
}; |
|
|
@ -356,6 +357,11 @@ export abstract class PortfolioCalculator { |
|
|
|
|
|
|
|
|
const valueInBaseCurrency = marketPriceInBaseCurrency.mul(item.quantity); |
|
|
const valueInBaseCurrency = marketPriceInBaseCurrency.mul(item.quantity); |
|
|
|
|
|
|
|
|
|
|
|
const isCashInBaseCurrency = |
|
|
|
|
|
item.assetSubClass === AssetSubClass.CASH && |
|
|
|
|
|
item.currency === this.currency && |
|
|
|
|
|
item.symbol === this.currency; |
|
|
|
|
|
|
|
|
const { |
|
|
const { |
|
|
currentValues, |
|
|
currentValues, |
|
|
currentValuesWithCurrencyEffect, |
|
|
currentValuesWithCurrencyEffect, |
|
|
@ -396,7 +402,24 @@ export abstract class PortfolioCalculator { |
|
|
|
|
|
|
|
|
hasAnySymbolMetricsErrors = hasAnySymbolMetricsErrors || hasErrors; |
|
|
hasAnySymbolMetricsErrors = hasAnySymbolMetricsErrors || hasErrors; |
|
|
|
|
|
|
|
|
valuesBySymbol[item.symbol] = { |
|
|
// Cash in the base currency cannot generate a currency effect and thus
|
|
|
|
|
|
// contributes nothing but its balance to the performance calculation. It
|
|
|
|
|
|
// is therefore excluded from the value and the investment, while still
|
|
|
|
|
|
// contributing to the net worth.
|
|
|
|
|
|
valuesBySymbol[item.symbol] = isCashInBaseCurrency |
|
|
|
|
|
? { |
|
|
|
|
|
currentValues: {}, |
|
|
|
|
|
currentValuesWithCurrencyEffect: {}, |
|
|
|
|
|
investmentValuesAccumulated: {}, |
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect: {}, |
|
|
|
|
|
investmentValuesWithCurrencyEffect: {}, |
|
|
|
|
|
netPerformanceValues: {}, |
|
|
|
|
|
netPerformanceValuesWithCurrencyEffect: {}, |
|
|
|
|
|
netWorthValuesWithCurrencyEffect: currentValuesWithCurrencyEffect, |
|
|
|
|
|
timeWeightedInvestmentValues: {}, |
|
|
|
|
|
timeWeightedInvestmentValuesWithCurrencyEffect: {} |
|
|
|
|
|
} |
|
|
|
|
|
: { |
|
|
currentValues, |
|
|
currentValues, |
|
|
currentValuesWithCurrencyEffect, |
|
|
currentValuesWithCurrencyEffect, |
|
|
investmentValuesAccumulated, |
|
|
investmentValuesAccumulated, |
|
|
@ -405,7 +428,8 @@ export abstract class PortfolioCalculator { |
|
|
netPerformanceValues, |
|
|
netPerformanceValues, |
|
|
netPerformanceValuesWithCurrencyEffect, |
|
|
netPerformanceValuesWithCurrencyEffect, |
|
|
timeWeightedInvestmentValues, |
|
|
timeWeightedInvestmentValues, |
|
|
timeWeightedInvestmentValuesWithCurrencyEffect |
|
|
timeWeightedInvestmentValuesWithCurrencyEffect, |
|
|
|
|
|
netWorthValuesWithCurrencyEffect: currentValuesWithCurrencyEffect |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
positions.push({ |
|
|
positions.push({ |
|
|
@ -431,6 +455,7 @@ export abstract class PortfolioCalculator { |
|
|
? (grossPerformanceWithCurrencyEffect ?? null) |
|
|
? (grossPerformanceWithCurrencyEffect ?? null) |
|
|
: null, |
|
|
: null, |
|
|
includeInHoldings: item.includeInHoldings, |
|
|
includeInHoldings: item.includeInHoldings, |
|
|
|
|
|
includeInPerformance: !isCashInBaseCurrency, |
|
|
investment: totalInvestment, |
|
|
investment: totalInvestment, |
|
|
investmentWithCurrencyEffect: totalInvestmentWithCurrencyEffect, |
|
|
investmentWithCurrencyEffect: totalInvestmentWithCurrencyEffect, |
|
|
marketPrice: |
|
|
marketPrice: |
|
|
@ -508,6 +533,10 @@ export abstract class PortfolioCalculator { |
|
|
symbolValues.netPerformanceValuesWithCurrencyEffect?.[dateString] ?? |
|
|
symbolValues.netPerformanceValuesWithCurrencyEffect?.[dateString] ?? |
|
|
new Big(0); |
|
|
new Big(0); |
|
|
|
|
|
|
|
|
|
|
|
const netWorthValueWithCurrencyEffect = |
|
|
|
|
|
symbolValues.netWorthValuesWithCurrencyEffect?.[dateString] ?? |
|
|
|
|
|
new Big(0); |
|
|
|
|
|
|
|
|
const timeWeightedInvestmentValue = |
|
|
const timeWeightedInvestmentValue = |
|
|
symbolValues.timeWeightedInvestmentValues?.[dateString] ?? new Big(0); |
|
|
symbolValues.timeWeightedInvestmentValues?.[dateString] ?? new Big(0); |
|
|
|
|
|
|
|
|
@ -526,7 +555,7 @@ export abstract class PortfolioCalculator { |
|
|
?.totalCashValueWithCurrencyEffect ?? new Big(0) |
|
|
?.totalCashValueWithCurrencyEffect ?? new Big(0) |
|
|
).add( |
|
|
).add( |
|
|
cashSymbols.has(symbol) |
|
|
cashSymbols.has(symbol) |
|
|
? currentValueWithCurrencyEffect |
|
|
? netWorthValueWithCurrencyEffect |
|
|
: new Big(0) |
|
|
: new Big(0) |
|
|
), |
|
|
), |
|
|
totalCurrentValue: ( |
|
|
totalCurrentValue: ( |
|
|
@ -552,6 +581,10 @@ export abstract class PortfolioCalculator { |
|
|
accumulatedValuesByDate[dateString] |
|
|
accumulatedValuesByDate[dateString] |
|
|
?.totalNetPerformanceValueWithCurrencyEffect ?? new Big(0) |
|
|
?.totalNetPerformanceValueWithCurrencyEffect ?? new Big(0) |
|
|
).add(netPerformanceValueWithCurrencyEffect), |
|
|
).add(netPerformanceValueWithCurrencyEffect), |
|
|
|
|
|
totalNetWorthValueWithCurrencyEffect: ( |
|
|
|
|
|
accumulatedValuesByDate[dateString] |
|
|
|
|
|
?.totalNetWorthValueWithCurrencyEffect ?? new Big(0) |
|
|
|
|
|
).add(netWorthValueWithCurrencyEffect), |
|
|
totalTimeWeightedInvestmentValue: ( |
|
|
totalTimeWeightedInvestmentValue: ( |
|
|
accumulatedValuesByDate[dateString] |
|
|
accumulatedValuesByDate[dateString] |
|
|
?.totalTimeWeightedInvestmentValue ?? new Big(0) |
|
|
?.totalTimeWeightedInvestmentValue ?? new Big(0) |
|
|
@ -576,6 +609,7 @@ export abstract class PortfolioCalculator { |
|
|
totalInvestmentValueWithCurrencyEffect, |
|
|
totalInvestmentValueWithCurrencyEffect, |
|
|
totalNetPerformanceValue, |
|
|
totalNetPerformanceValue, |
|
|
totalNetPerformanceValueWithCurrencyEffect, |
|
|
totalNetPerformanceValueWithCurrencyEffect, |
|
|
|
|
|
totalNetWorthValueWithCurrencyEffect, |
|
|
totalTimeWeightedInvestmentValue, |
|
|
totalTimeWeightedInvestmentValue, |
|
|
totalTimeWeightedInvestmentValueWithCurrencyEffect |
|
|
totalTimeWeightedInvestmentValueWithCurrencyEffect |
|
|
} = values; |
|
|
} = values; |
|
|
@ -602,7 +636,7 @@ export abstract class PortfolioCalculator { |
|
|
netPerformance: totalNetPerformanceValue.toNumber(), |
|
|
netPerformance: totalNetPerformanceValue.toNumber(), |
|
|
netPerformanceWithCurrencyEffect: |
|
|
netPerformanceWithCurrencyEffect: |
|
|
totalNetPerformanceValueWithCurrencyEffect.toNumber(), |
|
|
totalNetPerformanceValueWithCurrencyEffect.toNumber(), |
|
|
netWorth: totalCurrentValueWithCurrencyEffect.toNumber(), |
|
|
netWorth: totalNetWorthValueWithCurrencyEffect.toNumber(), |
|
|
totalCashInBaseCurrency: totalCashValueWithCurrencyEffect.toNumber(), |
|
|
totalCashInBaseCurrency: totalCashValueWithCurrencyEffect.toNumber(), |
|
|
totalInvestment: totalInvestmentValue.toNumber(), |
|
|
totalInvestment: totalInvestmentValue.toNumber(), |
|
|
totalInvestmentValueWithCurrencyEffect: |
|
|
totalInvestmentValueWithCurrencyEffect: |
|
|
@ -619,7 +653,7 @@ export abstract class PortfolioCalculator { |
|
|
return includeInHoldings; |
|
|
return includeInHoldings; |
|
|
}) |
|
|
}) |
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
|
.map(({ includeInHoldings, ...rest }) => { |
|
|
.map(({ includeInHoldings, includeInPerformance, ...rest }) => { |
|
|
return rest; |
|
|
return rest; |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|