Feature/optimize portfolio snapshot computation by reusing date intervals (#3855)

* Optimize portfolio snapshot computation by reusing date intervals

* Update changelog
pull/3880/head
ceroma 2 months ago committed by GitHub
parent e715ce14e5
commit ecd75b5d8a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Set up a git-hook via `husky` to lint and format the changes before a commit
- Added the `typescript-eslint/recommended-type-checked` rule to the `eslint` configuration
### Changed
- Optimized the portfolio calculations by reusing date intervals
### Fixed
- Handled an exception in the historical market data gathering of derived currencies

@ -22,7 +22,7 @@ import {
import { cloneDeep, first, last, sortBy } from 'lodash';
export class TWRPortfolioCalculator extends PortfolioCalculator {
private chartDatesDescending: string[];
private chartDates: string[];
protected calculateOverallPerformance(
positions: TimelinePosition[]
@ -228,11 +228,11 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
const dateOfFirstTransaction = new Date(first(orders).date);
const unitPriceAtStartDate =
marketSymbolMap[format(start, DATE_FORMAT)]?.[symbol];
const endDateString = format(end, DATE_FORMAT);
const startDateString = format(start, DATE_FORMAT);
const unitPriceAtEndDate =
marketSymbolMap[format(end, DATE_FORMAT)]?.[symbol];
const unitPriceAtStartDate = marketSymbolMap[startDateString]?.[symbol];
const unitPriceAtEndDate = marketSymbolMap[endDateString]?.[symbol];
if (
!unitPriceAtEndDate ||
@ -278,7 +278,7 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
// Add a synthetic order at the start and the end date
orders.push({
date: format(start, DATE_FORMAT),
date: startDateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
itemType: 'start',
@ -292,7 +292,7 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
});
orders.push({
date: format(end, DATE_FORMAT),
date: endDateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
itemType: 'end',
@ -305,7 +305,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
unitPrice: unitPriceAtEndDate
});
let day = start;
let lastUnitPrice: Big;
const ordersByDate: { [date: string]: PortfolioOrderItem[] } = {};
@ -315,15 +314,23 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
ordersByDate[order.date].push(order);
}
while (isBefore(day, end)) {
const dateString = format(day, DATE_FORMAT);
if (!this.chartDates) {
this.chartDates = Object.keys(chartDateMap).sort();
}
for (const dateString of this.chartDates) {
if (dateString < startDateString) {
continue;
} else if (dateString > endDateString) {
break;
}
if (ordersByDate[dateString]?.length > 0) {
for (let order of ordersByDate[dateString]) {
order.unitPriceFromMarketData =
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice;
}
} else if (chartDateMap[dateString]) {
} else {
orders.push({
date: dateString,
fee: new Big(0),
@ -343,8 +350,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
const lastOrder = last(orders);
lastUnitPrice = lastOrder.unitPriceFromMarketData ?? lastOrder.unitPrice;
day = addDays(day, 1);
}
// Sort orders so that the start and end placeholder order are at the correct
@ -821,14 +826,14 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
startDate = start;
}
const endDateString = format(endDate, DATE_FORMAT);
const startDateString = format(startDate, DATE_FORMAT);
const rangeEndDateString = format(endDate, DATE_FORMAT);
const rangeStartDateString = format(startDate, DATE_FORMAT);
const currentValuesAtDateRangeStartWithCurrencyEffect =
currentValuesWithCurrencyEffect[startDateString] ?? new Big(0);
currentValuesWithCurrencyEffect[rangeStartDateString] ?? new Big(0);
const investmentValuesAccumulatedAtStartDateWithCurrencyEffect =
investmentValuesAccumulatedWithCurrencyEffect[startDateString] ??
investmentValuesAccumulatedWithCurrencyEffect[rangeStartDateString] ??
new Big(0);
const grossPerformanceAtDateRangeStartWithCurrencyEffect =
@ -839,14 +844,12 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
let average = new Big(0);
let dayCount = 0;
if (!this.chartDatesDescending) {
this.chartDatesDescending = Object.keys(chartDateMap).sort().reverse();
}
for (let i = this.chartDates.length - 1; i >= 0; i -= 1) {
const date = this.chartDates[i];
for (const date of this.chartDatesDescending) {
if (date > endDateString) {
if (date > rangeEndDateString) {
continue;
} else if (date < startDateString) {
} else if (date < rangeStartDateString) {
break;
}
@ -869,13 +872,13 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
}
netPerformanceWithCurrencyEffectMap[dateRange] =
netPerformanceValuesWithCurrencyEffect[endDateString]?.minus(
netPerformanceValuesWithCurrencyEffect[rangeEndDateString]?.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[startDateString] ??
: (netPerformanceValuesWithCurrencyEffect[rangeStartDateString] ??
new Big(0))
) ?? new Big(0);

Loading…
Cancel
Save