Browse Source

Fix Constant portfolio Rate of return

pull/5027/head
Dan 1 year ago
parent
commit
969aa2ae4a
  1. 96
      apps/api/src/app/portfolio/calculator/constantPortfolioReturn/portfolio-calculator.ts
  2. 17
      apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts

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

@ -55,52 +55,40 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
if (!withTimeWeightedReturn) {
return item;
} else {
let itemResult = await item;
let dates = itemResult.map((item) => parseDate(item.date));
let timeWeighted = await this.getTimeWeightedChartData({
step,
end: endDate,
start: startDate
dates
});
return item.then((data) => {
return data.map((item) => {
let timeWeightedItem = timeWeighted.find(
(timeWeightedItem) => timeWeightedItem.date === item.date
);
if (timeWeightedItem) {
item.timeWeightedPerformance =
timeWeightedItem.netPerformanceInPercentage;
item.timeWeightedPerformanceWithCurrencyEffect =
timeWeightedItem.netPerformanceInPercentageWithCurrencyEffect;
}
return item;
});
return itemResult.map((item) => {
let timeWeightedItem = timeWeighted.find(
(timeWeightedItem) => timeWeightedItem.date === item.date
);
if (timeWeightedItem) {
item.timeWeightedPerformance =
timeWeightedItem.netPerformanceInPercentage;
item.timeWeightedPerformanceWithCurrencyEffect =
timeWeightedItem.netPerformanceInPercentageWithCurrencyEffect;
}
return item;
});
}
}
@LogPerformance
private async getTimeWeightedChartData({
end = new Date(Date.now()),
start,
step = 1
dates
}: {
end?: Date;
start: Date;
step?: number;
dates?: Date[];
}): Promise<HistoricalDataItem[]> {
dates = dates.sort((a, b) => a.getTime() - b.getTime());
const start = dates[0];
const end = dates[dates.length - 1];
let marketMapTask = this.computeMarketMap({ gte: start, lte: end });
const timelineHoldings = await this.getHoldings(start, end);
const calculationDates = Object.keys(timelineHoldings)
.filter((date) => {
let parsed = parseDate(date);
return (
isAfter(parsed, subDays(start, 1)) &&
isBefore(parsed, addDays(end, 1))
);
})
.sort((a, b) => parseDate(a).getTime() - parseDate(b).getTime());
let data: HistoricalDataItem[] = [];
const startString = format(start, DATE_FORMAT);
@ -135,9 +123,9 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
let previousNetPerformanceInPercentage = new Big(0);
let previousNetPerformanceInPercentageWithCurrencyEffect = new Big(0);
for (let i = 1; i < calculationDates.length; i++) {
const date = calculationDates[i];
const previousDate = calculationDates[i - 1];
for (let i = 1; i < dates.length; i++) {
const date = format(dates[i], DATE_FORMAT);
const previousDate = format(dates[i - 1], DATE_FORMAT);
const holdings = timelineHoldings[previousDate];
let newTotalInvestment = new Big(0);
let netPerformanceInPercentage = new Big(0);
@ -158,24 +146,28 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
netPerformanceInPercentageWithCurrencyEffect,
newTotalInvestment
));
totalInvestment = newTotalInvestment;
}
totalInvestment = newTotalInvestment;
previousNetPerformanceInPercentage =
previousNetPerformanceInPercentage.mul(
netPerformanceInPercentage.plus(1)
);
previousNetPerformanceInPercentage = previousNetPerformanceInPercentage
.plus(1)
.mul(netPerformanceInPercentage.plus(1))
.minus(1);
previousNetPerformanceInPercentageWithCurrencyEffect =
previousNetPerformanceInPercentageWithCurrencyEffect.mul(
netPerformanceInPercentageWithCurrencyEffect.plus(1)
);
previousNetPerformanceInPercentageWithCurrencyEffect
.plus(1)
.mul(netPerformanceInPercentageWithCurrencyEffect.plus(1))
.minus(1);
data.push({
date,
netPerformanceInPercentage:
previousNetPerformanceInPercentage.toNumber(),
netPerformanceInPercentage: previousNetPerformanceInPercentage
.mul(100)
.toNumber(),
netPerformanceInPercentageWithCurrencyEffect:
previousNetPerformanceInPercentageWithCurrencyEffect.toNumber()
previousNetPerformanceInPercentageWithCurrencyEffect
.mul(100)
.toNumber()
});
}
@ -210,8 +202,9 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
if (previousHolding.eq(0)) {
return {
netPerformanceInPercentage: new Big(0),
netPerformanceInPercentageWithCurrencyEffect: new Big(0),
netPerformanceInPercentage: netPerformanceInPercentage,
netPerformanceInPercentageWithCurrencyEffect:
netPerformanceInPercentageWithCurrencyEffect,
newTotalInvestment: newTotalInvestment.plus(
timelineHoldings[date][holding].mul(priceInBaseCurrency)
)
@ -223,8 +216,9 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
'PortfolioCalculator'
);
return {
netPerformanceInPercentage: new Big(0),
netPerformanceInPercentageWithCurrencyEffect: new Big(0),
netPerformanceInPercentage: netPerformanceInPercentage,
netPerformanceInPercentageWithCurrencyEffect:
netPerformanceInPercentageWithCurrencyEffect,
newTotalInvestment: newTotalInvestment.plus(
timelineHoldings[date][holding].mul(priceInBaseCurrency)
)
@ -242,7 +236,7 @@ export class CPRPortfolioCalculator extends TWRPortfolioCalculator {
: new Big(0);
const portfolioWeight = totalInvestment.toNumber()
? previousHolding.mul(previousPriceInBaseCurrency).div(totalInvestment)
: 0;
: new Big(0);
netPerformanceInPercentage = netPerformanceInPercentage.plus(
currentPrice.div(previousPrice).minus(1).mul(portfolioWeight)

17
apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts

@ -337,24 +337,9 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
value: netPerformanceInPercentageWithCurrencyEffect
});
if ((this.timeWeightedPerformance ?? 'N') !== 'N') {
let lastPerformance = 0;
if (index > 0) {
lastPerformance = new Big(
chart[index - 1].timeWeightedPerformance
)
.div(100)
.plus(1)
.mul(
new Big(chart[index].timeWeightedPerformance).div(100).plus(1)
)
.minus(1)
.mul(100)
.toNumber();
}
chart[index].timeWeightedPerformance = lastPerformance;
this.performanceDataItemsTimeWeightedInPercentage.push({
date,
value: lastPerformance
value: chart[index].timeWeightedPerformance
});
}
}

Loading…
Cancel
Save