Browse Source

Various fixes:

* Fix net performance in "max" date range
* Fix unit test
pull/3393/head
Reto Kaul 1 year ago
parent
commit
b1e72dbbd7
  1. 51
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  2. 14
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts
  3. 15
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
  4. 20
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts

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

@ -36,7 +36,7 @@ import {
min,
subDays
} from 'date-fns';
import { first, last, sortBy, sum, uniq, uniqBy } from 'lodash';
import { first, isNumber, last, sortBy, sum, uniq, uniqBy } from 'lodash';
export abstract class PortfolioCalculator {
protected static readonly ENABLE_LOGGING = false;
@ -144,24 +144,11 @@ export abstract class PortfolioCalculator {
positions: TimelinePosition[]
): PortfolioSnapshot;
private async computeSnapshot(
start: Date,
end?: Date
): Promise<PortfolioSnapshot> {
private async computeSnapshot(): Promise<PortfolioSnapshot> {
const lastTransactionPoint = last(this.transactionPoints);
let endDate = end;
if (!endDate) {
endDate = new Date();
if (lastTransactionPoint) {
endDate = max([endDate, parseDate(lastTransactionPoint.date)]);
}
}
const transactionPoints = this.transactionPoints?.filter(({ date }) => {
return isBefore(parseDate(date), endDate);
return isBefore(parseDate(date), this.endDate);
});
if (!transactionPoints.length) {
@ -208,7 +195,7 @@ export abstract class PortfolioCalculator {
for (let i = 0; i < transactionPoints.length; i++) {
if (
!isBefore(parseDate(transactionPoints[i].date), start) &&
!isBefore(parseDate(transactionPoints[i].date), this.startDate) &&
firstTransactionPoint === null
) {
firstTransactionPoint = transactionPoints[i];
@ -219,8 +206,8 @@ export abstract class PortfolioCalculator {
let exchangeRatesByCurrency =
await this.exchangeRateDataService.getExchangeRatesByCurrency({
currencies: uniq(Object.values(currencies)),
endDate: endOfDay(endDate),
startDate: this.getStartDate(),
endDate: endOfDay(this.endDate),
startDate: this.startDate,
targetCurrency: this.currency
});
@ -231,8 +218,8 @@ export abstract class PortfolioCalculator {
} = await this.currentRateService.getValues({
dataGatheringItems,
dateQuery: {
gte: this.getStartDate(),
lt: endDate
gte: this.startDate,
lt: this.endDate
}
});
@ -256,14 +243,13 @@ export abstract class PortfolioCalculator {
}
}
const endDateString = format(endDate, DATE_FORMAT);
const endDateString = format(this.endDate, DATE_FORMAT);
const chartStartDate = this.getStartDate();
const daysInMarket = differenceInDays(endDate, chartStartDate) + 1;
const daysInMarket = differenceInDays(this.endDate, this.startDate);
let chartDateMap = this.getChartDateMap({
endDate,
startDate: chartStartDate,
endDate: this.endDate,
startDate: this.startDate,
step: Math.round(daysInMarket / Math.min(daysInMarket, MAX_CHART_ITEMS))
});
@ -357,12 +343,12 @@ export abstract class PortfolioCalculator {
} = this.getSymbolMetrics({
chartDateMap,
marketSymbolMap,
start,
dataSource: item.dataSource,
end: endDate,
end: this.endDate,
exchangeRates:
exchangeRatesByCurrency[`${item.currency}${this.currency}`],
isChartMode: true,
start: this.startDate,
symbol: item.symbol
});
@ -710,7 +696,7 @@ export abstract class PortfolioCalculator {
!isBefore(parseDate(historicalDataItem.date), subDays(start, 1)) &&
!isAfter(parseDate(historicalDataItem.date), end)
) {
if (!netPerformanceAtStartDate) {
if (!isNumber(netPerformanceAtStartDate)) {
netPerformanceAtStartDate = historicalDataItem.netPerformance;
netPerformanceWithCurrencyEffectAtStartDate =
@ -1039,10 +1025,7 @@ export abstract class PortfolioCalculator {
'PortfolioCalculator'
);
} else {
this.snapshot = await this.computeSnapshot(
this.startDate,
this.endDate
);
this.snapshot = await this.computeSnapshot();
this.redisCacheService.set(
this.redisCacheService.getPortfolioSnapshotKey({
@ -1061,7 +1044,7 @@ export abstract class PortfolioCalculator {
);
}
} else {
this.snapshot = await this.computeSnapshot(this.startDate, this.endDate);
this.snapshot = await this.computeSnapshot();
}
}
}

14
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts

@ -149,13 +149,13 @@ describe('PortfolioCalculator', () => {
},
netPerformanceWithCurrencyEffect: new Big('23.05'),
netPerformanceWithCurrencyEffectMap: {
'1d': new Big('8.45'), // wrong
'1y': new Big('23.05'), // wrong
'5y': new Big('23.05'), // wrong
max: new Big('23.05'), // ok: 2 * (148.9 - 136.6) - 1.55
mtd: new Big('23.05'), // wrong
wtd: new Big('12.25'), // wrong: 2 * (148.9 - 142) - 1.55
ytd: new Big('23.05') // wrong
'1d': new Big('10.00'), // 2 * (148.9 - 143.9) -> no fees in this time period
'1y': new Big('23.05'), // 2 * (148.9 - 136.6) - 1.55
'5y': new Big('23.05'), // 2 * (148.9 - 136.6) - 1.55
max: new Big('23.05'), // 2 * (148.9 - 136.6) - 1.55
mtd: new Big('24.60'), // 2 * (148.9 - 136.6) -> no fees in this time period
wtd: new Big('13.80'), // 2 * (148.9 - 142.0) -> no fees in this time period
ytd: new Big('23.05') // 2 * (148.9 - 136.6) - 1.55
},
marketPrice: 148.9,
marketPriceInBaseCurrency: 148.9,

15
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts

@ -120,6 +120,21 @@ describe('PortfolioCalculator', () => {
});
expect(portfolioSnapshot.historicalData[0]).toEqual({
date: '2022-03-06',
investmentValueWithCurrencyEffect: 0,
netPerformance: 0,
netPerformanceInPercentage: 0,
netPerformanceInPercentageWithCurrencyEffect: 0,
netPerformanceWithCurrencyEffect: 0,
netWorth: 0,
totalAccountBalance: 0,
totalInvestment: 0,
totalInvestmentValueWithCurrencyEffect: 0,
value: 0,
valueWithCurrencyEffect: 0
});
expect(portfolioSnapshot.historicalData[1]).toEqual({
date: '2022-03-07',
investmentValueWithCurrencyEffect: 151.6,
netPerformance: 0,

20
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts

@ -857,23 +857,14 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
'mtd',
'wtd',
'ytd'
// TODO
// ...eachYearOfInterval({ end, start })
// .filter((date) => {
// return !isThisYear(date);
// })
// .map((date) => {
// return format(date, 'yyyy');
// })
]) {
// TODO: getIntervalFromDateRange(dateRange, start)
let { endDate, startDate } = getIntervalFromDateRange(dateRange);
if (isBefore(startDate, start)) {
startDate = addDays(start, 1);
startDate = start;
}
const currentValuesAtStartDateWithCurrencyEffect =
const currentValuesAtDateRangeStartWithCurrencyEffect =
currentValuesWithCurrencyEffect[format(startDate, DATE_FORMAT)] ??
new Big(0);
@ -882,9 +873,8 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
format(startDate, DATE_FORMAT)
] ?? new Big(0);
// TODO: Rename?
const grossPerformanceAtStartDateWithCurrencyEffect2 =
currentValuesAtStartDateWithCurrencyEffect.minus(
const grossPerformanceAtDateRangeStartWithCurrencyEffect =
currentValuesAtDateRangeStartWithCurrencyEffect.minus(
investmentValuesAccumulatedAtStartDateWithCurrencyEffect
);
@ -905,7 +895,7 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
) {
average = average.add(
investmentValuesAccumulatedWithCurrencyEffect[date].add(
grossPerformanceAtStartDateWithCurrencyEffect2
grossPerformanceAtDateRangeStartWithCurrencyEffect
)
);

Loading…
Cancel
Save