|
|
|
@ -16,13 +16,14 @@ import {
|
|
|
|
|
addDays,
|
|
|
|
|
addMilliseconds,
|
|
|
|
|
differenceInDays,
|
|
|
|
|
eachDayOfInterval,
|
|
|
|
|
format,
|
|
|
|
|
isBefore
|
|
|
|
|
} from 'date-fns';
|
|
|
|
|
import { cloneDeep, first, last, sortBy } from 'lodash';
|
|
|
|
|
|
|
|
|
|
export class TWRPortfolioCalculator extends PortfolioCalculator {
|
|
|
|
|
private chartDatesDescending: string[];
|
|
|
|
|
|
|
|
|
|
protected calculateOverallPerformance(
|
|
|
|
|
positions: TimelinePosition[]
|
|
|
|
|
): PortfolioSnapshot {
|
|
|
|
@ -820,31 +821,35 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
|
|
|
|
|
startDate = start;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const endDateString = format(endDate, DATE_FORMAT);
|
|
|
|
|
const startDateString = format(startDate, DATE_FORMAT);
|
|
|
|
|
|
|
|
|
|
const currentValuesAtDateRangeStartWithCurrencyEffect =
|
|
|
|
|
currentValuesWithCurrencyEffect[format(startDate, DATE_FORMAT)] ??
|
|
|
|
|
new Big(0);
|
|
|
|
|
currentValuesWithCurrencyEffect[startDateString] ?? new Big(0);
|
|
|
|
|
|
|
|
|
|
const investmentValuesAccumulatedAtStartDateWithCurrencyEffect =
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect[
|
|
|
|
|
format(startDate, DATE_FORMAT)
|
|
|
|
|
] ?? new Big(0);
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect[startDateString] ??
|
|
|
|
|
new Big(0);
|
|
|
|
|
|
|
|
|
|
const grossPerformanceAtDateRangeStartWithCurrencyEffect =
|
|
|
|
|
currentValuesAtDateRangeStartWithCurrencyEffect.minus(
|
|
|
|
|
investmentValuesAccumulatedAtStartDateWithCurrencyEffect
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const dates = eachDayOfInterval({
|
|
|
|
|
end: endDate,
|
|
|
|
|
start: startDate
|
|
|
|
|
}).map((date) => {
|
|
|
|
|
return format(date, DATE_FORMAT);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let average = new Big(0);
|
|
|
|
|
let dayCount = 0;
|
|
|
|
|
|
|
|
|
|
for (const date of dates) {
|
|
|
|
|
if (!this.chartDatesDescending) {
|
|
|
|
|
this.chartDatesDescending = Object.keys(chartDateMap).sort().reverse();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const date of this.chartDatesDescending) {
|
|
|
|
|
if (date > endDateString) {
|
|
|
|
|
continue;
|
|
|
|
|
} else if (date < startDateString) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect[date] instanceof Big &&
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect[date].gt(0)
|
|
|
|
@ -864,17 +869,14 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
netPerformanceWithCurrencyEffectMap[dateRange] =
|
|
|
|
|
netPerformanceValuesWithCurrencyEffect[
|
|
|
|
|
format(endDate, DATE_FORMAT)
|
|
|
|
|
]?.minus(
|
|
|
|
|
netPerformanceValuesWithCurrencyEffect[endDateString]?.minus(
|
|
|
|
|
// If the date range is 'max', take 0 as a start value. Otherwise,
|
|
|
|
|
// the value of the end of the day of the start date is taken which
|
|
|
|
|
// differs from the buying price.
|
|
|
|
|
dateRange === 'max'
|
|
|
|
|
? new Big(0)
|
|
|
|
|
: (netPerformanceValuesWithCurrencyEffect[
|
|
|
|
|
format(startDate, DATE_FORMAT)
|
|
|
|
|
] ?? new Big(0))
|
|
|
|
|
: (netPerformanceValuesWithCurrencyEffect[startDateString] ??
|
|
|
|
|
new Big(0))
|
|
|
|
|
) ?? new Big(0);
|
|
|
|
|
|
|
|
|
|
netPerformancePercentageWithCurrencyEffectMap[dateRange] = average.gt(0)
|
|
|
|
|