|
|
@ -3,6 +3,8 @@ import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfac
|
|
|
|
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
|
|
|
|
import { DATE_FORMAT, parseDate, resetHours } from '@ghostfolio/common/helper';
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
DataProviderInfo,
|
|
|
|
DataProviderInfo,
|
|
|
|
|
|
|
|
HistoricalDataItem,
|
|
|
|
|
|
|
|
InvestmentItem,
|
|
|
|
ResponseError,
|
|
|
|
ResponseError,
|
|
|
|
SymbolMetrics,
|
|
|
|
SymbolMetrics,
|
|
|
|
TimelinePosition
|
|
|
|
TimelinePosition
|
|
|
@ -14,16 +16,11 @@ import Big from 'big.js';
|
|
|
|
import {
|
|
|
|
import {
|
|
|
|
addDays,
|
|
|
|
addDays,
|
|
|
|
addMilliseconds,
|
|
|
|
addMilliseconds,
|
|
|
|
addMonths,
|
|
|
|
|
|
|
|
addYears,
|
|
|
|
|
|
|
|
differenceInDays,
|
|
|
|
differenceInDays,
|
|
|
|
endOfDay,
|
|
|
|
endOfDay,
|
|
|
|
format,
|
|
|
|
format,
|
|
|
|
isBefore,
|
|
|
|
isBefore,
|
|
|
|
isSameDay,
|
|
|
|
isSameDay,
|
|
|
|
isSameMonth,
|
|
|
|
|
|
|
|
isSameYear,
|
|
|
|
|
|
|
|
set,
|
|
|
|
|
|
|
|
subDays
|
|
|
|
subDays
|
|
|
|
} from 'date-fns';
|
|
|
|
} from 'date-fns';
|
|
|
|
import { cloneDeep, first, isNumber, last, sortBy, uniq } from 'lodash';
|
|
|
|
import { cloneDeep, first, isNumber, last, sortBy, uniq } from 'lodash';
|
|
|
@ -32,10 +29,6 @@ import { CurrentRateService } from './current-rate.service';
|
|
|
|
import { CurrentPositions } from './interfaces/current-positions.interface';
|
|
|
|
import { CurrentPositions } from './interfaces/current-positions.interface';
|
|
|
|
import { PortfolioOrderItem } from './interfaces/portfolio-calculator.interface';
|
|
|
|
import { PortfolioOrderItem } from './interfaces/portfolio-calculator.interface';
|
|
|
|
import { PortfolioOrder } from './interfaces/portfolio-order.interface';
|
|
|
|
import { PortfolioOrder } from './interfaces/portfolio-order.interface';
|
|
|
|
import {
|
|
|
|
|
|
|
|
Accuracy,
|
|
|
|
|
|
|
|
TimelineSpecification
|
|
|
|
|
|
|
|
} from './interfaces/timeline-specification.interface';
|
|
|
|
|
|
|
|
import { TransactionPointSymbol } from './interfaces/transaction-point-symbol.interface';
|
|
|
|
import { TransactionPointSymbol } from './interfaces/transaction-point-symbol.interface';
|
|
|
|
import { TransactionPoint } from './interfaces/transaction-point.interface';
|
|
|
|
import { TransactionPoint } from './interfaces/transaction-point.interface';
|
|
|
|
|
|
|
|
|
|
|
@ -179,7 +172,15 @@ export class PortfolioCalculator {
|
|
|
|
this.transactionPoints = transactionPoints;
|
|
|
|
this.transactionPoints = transactionPoints;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async getChartData(start: Date, end = new Date(Date.now()), step = 1) {
|
|
|
|
public async getChartData({
|
|
|
|
|
|
|
|
end = new Date(Date.now()),
|
|
|
|
|
|
|
|
start,
|
|
|
|
|
|
|
|
step = 1
|
|
|
|
|
|
|
|
}: {
|
|
|
|
|
|
|
|
end?: Date;
|
|
|
|
|
|
|
|
start: Date;
|
|
|
|
|
|
|
|
step?: number;
|
|
|
|
|
|
|
|
}): Promise<HistoricalDataItem[]> {
|
|
|
|
const symbols: { [symbol: string]: boolean } = {};
|
|
|
|
const symbols: { [symbol: string]: boolean } = {};
|
|
|
|
|
|
|
|
|
|
|
|
const transactionPointsBeforeEndDate =
|
|
|
|
const transactionPointsBeforeEndDate =
|
|
|
@ -203,13 +204,15 @@ export class PortfolioCalculator {
|
|
|
|
dates.push(resetHours(end));
|
|
|
|
dates.push(resetHours(end));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const item of transactionPointsBeforeEndDate[firstIndex - 1].items) {
|
|
|
|
if (transactionPointsBeforeEndDate.length > 0) {
|
|
|
|
dataGatheringItems.push({
|
|
|
|
for (const item of transactionPointsBeforeEndDate[firstIndex - 1].items) {
|
|
|
|
dataSource: item.dataSource,
|
|
|
|
dataGatheringItems.push({
|
|
|
|
symbol: item.symbol
|
|
|
|
dataSource: item.dataSource,
|
|
|
|
});
|
|
|
|
symbol: item.symbol
|
|
|
|
currencies[item.symbol] = item.currency;
|
|
|
|
});
|
|
|
|
symbols[item.symbol] = true;
|
|
|
|
currencies[item.symbol] = item.currency;
|
|
|
|
|
|
|
|
symbols[item.symbol] = true;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const { dataProviderInfos, values: marketSymbols } =
|
|
|
|
const { dataProviderInfos, values: marketSymbols } =
|
|
|
@ -248,6 +251,7 @@ export class PortfolioCalculator {
|
|
|
|
|
|
|
|
|
|
|
|
const accumulatedValuesByDate: {
|
|
|
|
const accumulatedValuesByDate: {
|
|
|
|
[date: string]: {
|
|
|
|
[date: string]: {
|
|
|
|
|
|
|
|
investmentValueWithCurrencyEffect: Big;
|
|
|
|
totalCurrentValue: Big;
|
|
|
|
totalCurrentValue: Big;
|
|
|
|
totalCurrentValueWithCurrencyEffect: Big;
|
|
|
|
totalCurrentValueWithCurrencyEffect: Big;
|
|
|
|
totalInvestmentValue: Big;
|
|
|
|
totalInvestmentValue: Big;
|
|
|
@ -263,7 +267,8 @@ export class PortfolioCalculator {
|
|
|
|
[symbol: string]: {
|
|
|
|
[symbol: string]: {
|
|
|
|
currentValues: { [date: string]: Big };
|
|
|
|
currentValues: { [date: string]: Big };
|
|
|
|
currentValuesWithCurrencyEffect: { [date: string]: Big };
|
|
|
|
currentValuesWithCurrencyEffect: { [date: string]: Big };
|
|
|
|
investmentValues: { [date: string]: Big };
|
|
|
|
investmentValuesAccumulated: { [date: string]: Big };
|
|
|
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect: { [date: string]: Big };
|
|
|
|
investmentValuesWithCurrencyEffect: { [date: string]: Big };
|
|
|
|
investmentValuesWithCurrencyEffect: { [date: string]: Big };
|
|
|
|
netPerformanceValues: { [date: string]: Big };
|
|
|
|
netPerformanceValues: { [date: string]: Big };
|
|
|
|
netPerformanceValuesWithCurrencyEffect: { [date: string]: Big };
|
|
|
|
netPerformanceValuesWithCurrencyEffect: { [date: string]: Big };
|
|
|
@ -276,7 +281,8 @@ export class PortfolioCalculator {
|
|
|
|
const {
|
|
|
|
const {
|
|
|
|
currentValues,
|
|
|
|
currentValues,
|
|
|
|
currentValuesWithCurrencyEffect,
|
|
|
|
currentValuesWithCurrencyEffect,
|
|
|
|
investmentValues,
|
|
|
|
investmentValuesAccumulated,
|
|
|
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect,
|
|
|
|
investmentValuesWithCurrencyEffect,
|
|
|
|
investmentValuesWithCurrencyEffect,
|
|
|
|
netPerformanceValues,
|
|
|
|
netPerformanceValues,
|
|
|
|
netPerformanceValuesWithCurrencyEffect,
|
|
|
|
netPerformanceValuesWithCurrencyEffect,
|
|
|
@ -296,7 +302,8 @@ export class PortfolioCalculator {
|
|
|
|
valuesBySymbol[symbol] = {
|
|
|
|
valuesBySymbol[symbol] = {
|
|
|
|
currentValues,
|
|
|
|
currentValues,
|
|
|
|
currentValuesWithCurrencyEffect,
|
|
|
|
currentValuesWithCurrencyEffect,
|
|
|
|
investmentValues,
|
|
|
|
investmentValuesAccumulated,
|
|
|
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect,
|
|
|
|
investmentValuesWithCurrencyEffect,
|
|
|
|
investmentValuesWithCurrencyEffect,
|
|
|
|
netPerformanceValues,
|
|
|
|
netPerformanceValues,
|
|
|
|
netPerformanceValuesWithCurrencyEffect,
|
|
|
|
netPerformanceValuesWithCurrencyEffect,
|
|
|
@ -318,8 +325,13 @@ export class PortfolioCalculator {
|
|
|
|
symbolValues.currentValuesWithCurrencyEffect?.[dateString] ??
|
|
|
|
symbolValues.currentValuesWithCurrencyEffect?.[dateString] ??
|
|
|
|
new Big(0);
|
|
|
|
new Big(0);
|
|
|
|
|
|
|
|
|
|
|
|
const investmentValue =
|
|
|
|
const investmentValueAccumulated =
|
|
|
|
symbolValues.investmentValues?.[dateString] ?? new Big(0);
|
|
|
|
symbolValues.investmentValuesAccumulated?.[dateString] ?? new Big(0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const investmentValueAccumulatedWithCurrencyEffect =
|
|
|
|
|
|
|
|
symbolValues.investmentValuesAccumulatedWithCurrencyEffect?.[
|
|
|
|
|
|
|
|
dateString
|
|
|
|
|
|
|
|
] ?? new Big(0);
|
|
|
|
|
|
|
|
|
|
|
|
const investmentValueWithCurrencyEffect =
|
|
|
|
const investmentValueWithCurrencyEffect =
|
|
|
|
symbolValues.investmentValuesWithCurrencyEffect?.[dateString] ??
|
|
|
|
symbolValues.investmentValuesWithCurrencyEffect?.[dateString] ??
|
|
|
@ -341,6 +353,10 @@ export class PortfolioCalculator {
|
|
|
|
] ?? new Big(0);
|
|
|
|
] ?? new Big(0);
|
|
|
|
|
|
|
|
|
|
|
|
accumulatedValuesByDate[dateString] = {
|
|
|
|
accumulatedValuesByDate[dateString] = {
|
|
|
|
|
|
|
|
investmentValueWithCurrencyEffect: (
|
|
|
|
|
|
|
|
accumulatedValuesByDate[dateString]
|
|
|
|
|
|
|
|
?.investmentValueWithCurrencyEffect ?? new Big(0)
|
|
|
|
|
|
|
|
).add(investmentValueWithCurrencyEffect),
|
|
|
|
totalCurrentValue: (
|
|
|
|
totalCurrentValue: (
|
|
|
|
accumulatedValuesByDate[dateString]?.totalCurrentValue ?? new Big(0)
|
|
|
|
accumulatedValuesByDate[dateString]?.totalCurrentValue ?? new Big(0)
|
|
|
|
).add(currentValue),
|
|
|
|
).add(currentValue),
|
|
|
@ -351,11 +367,11 @@ export class PortfolioCalculator {
|
|
|
|
totalInvestmentValue: (
|
|
|
|
totalInvestmentValue: (
|
|
|
|
accumulatedValuesByDate[dateString]?.totalInvestmentValue ??
|
|
|
|
accumulatedValuesByDate[dateString]?.totalInvestmentValue ??
|
|
|
|
new Big(0)
|
|
|
|
new Big(0)
|
|
|
|
).add(investmentValue),
|
|
|
|
).add(investmentValueAccumulated),
|
|
|
|
totalInvestmentValueWithCurrencyEffect: (
|
|
|
|
totalInvestmentValueWithCurrencyEffect: (
|
|
|
|
accumulatedValuesByDate[dateString]
|
|
|
|
accumulatedValuesByDate[dateString]
|
|
|
|
?.totalInvestmentValueWithCurrencyEffect ?? new Big(0)
|
|
|
|
?.totalInvestmentValueWithCurrencyEffect ?? new Big(0)
|
|
|
|
).add(investmentValueWithCurrencyEffect),
|
|
|
|
).add(investmentValueAccumulatedWithCurrencyEffect),
|
|
|
|
totalNetPerformanceValue: (
|
|
|
|
totalNetPerformanceValue: (
|
|
|
|
accumulatedValuesByDate[dateString]?.totalNetPerformanceValue ??
|
|
|
|
accumulatedValuesByDate[dateString]?.totalNetPerformanceValue ??
|
|
|
|
new Big(0)
|
|
|
|
new Big(0)
|
|
|
@ -378,6 +394,7 @@ export class PortfolioCalculator {
|
|
|
|
|
|
|
|
|
|
|
|
return Object.entries(accumulatedValuesByDate).map(([date, values]) => {
|
|
|
|
return Object.entries(accumulatedValuesByDate).map(([date, values]) => {
|
|
|
|
const {
|
|
|
|
const {
|
|
|
|
|
|
|
|
investmentValueWithCurrencyEffect,
|
|
|
|
totalCurrentValue,
|
|
|
|
totalCurrentValue,
|
|
|
|
totalCurrentValueWithCurrencyEffect,
|
|
|
|
totalCurrentValueWithCurrencyEffect,
|
|
|
|
totalInvestmentValue,
|
|
|
|
totalInvestmentValue,
|
|
|
@ -407,6 +424,8 @@ export class PortfolioCalculator {
|
|
|
|
date,
|
|
|
|
date,
|
|
|
|
netPerformanceInPercentage,
|
|
|
|
netPerformanceInPercentage,
|
|
|
|
netPerformanceInPercentageWithCurrencyEffect,
|
|
|
|
netPerformanceInPercentageWithCurrencyEffect,
|
|
|
|
|
|
|
|
investmentValueWithCurrencyEffect:
|
|
|
|
|
|
|
|
investmentValueWithCurrencyEffect.toNumber(),
|
|
|
|
netPerformance: totalNetPerformanceValue.toNumber(),
|
|
|
|
netPerformance: totalNetPerformanceValue.toNumber(),
|
|
|
|
netPerformanceWithCurrencyEffect:
|
|
|
|
netPerformanceWithCurrencyEffect:
|
|
|
|
totalNetPerformanceValueWithCurrencyEffect.toNumber(),
|
|
|
|
totalNetPerformanceValueWithCurrencyEffect.toNumber(),
|
|
|
@ -671,95 +690,27 @@ export class PortfolioCalculator {
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public getInvestmentsByGroup(
|
|
|
|
public getInvestmentsByGroup({
|
|
|
|
groupBy: GroupBy
|
|
|
|
data,
|
|
|
|
): { date: string; investment: Big }[] {
|
|
|
|
groupBy
|
|
|
|
if (this.orders.length === 0) {
|
|
|
|
}: {
|
|
|
|
return [];
|
|
|
|
data: HistoricalDataItem[];
|
|
|
|
}
|
|
|
|
groupBy: GroupBy;
|
|
|
|
|
|
|
|
}): InvestmentItem[] {
|
|
|
|
const investments: { date: string; investment: Big }[] = [];
|
|
|
|
const groupedData: { [dateGroup: string]: Big } = {};
|
|
|
|
let currentDate: Date;
|
|
|
|
|
|
|
|
let investmentByGroup = new Big(0);
|
|
|
|
for (const { date, investmentValueWithCurrencyEffect } of data) {
|
|
|
|
|
|
|
|
const dateGroup =
|
|
|
|
for (const [index, order] of this.orders.entries()) {
|
|
|
|
groupBy === 'month' ? date.substring(0, 7) : date.substring(0, 4);
|
|
|
|
if (
|
|
|
|
groupedData[dateGroup] = (groupedData[dateGroup] ?? new Big(0)).plus(
|
|
|
|
isSameYear(parseDate(order.date), currentDate) &&
|
|
|
|
investmentValueWithCurrencyEffect
|
|
|
|
(groupBy === 'year' || isSameMonth(parseDate(order.date), currentDate))
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
// Same group: Add up investments
|
|
|
|
|
|
|
|
investmentByGroup = investmentByGroup.plus(
|
|
|
|
|
|
|
|
order.quantity.mul(order.unitPrice).mul(this.getFactor(order.type))
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// New group: Store previous group and reset
|
|
|
|
|
|
|
|
if (currentDate) {
|
|
|
|
|
|
|
|
investments.push({
|
|
|
|
|
|
|
|
date: format(
|
|
|
|
|
|
|
|
set(currentDate, {
|
|
|
|
|
|
|
|
date: 1,
|
|
|
|
|
|
|
|
month: groupBy === 'year' ? 0 : currentDate.getMonth()
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
DATE_FORMAT
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
investment: investmentByGroup
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
currentDate = parseDate(order.date);
|
|
|
|
|
|
|
|
investmentByGroup = order.quantity
|
|
|
|
|
|
|
|
.mul(order.unitPrice)
|
|
|
|
|
|
|
|
.mul(this.getFactor(order.type));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (index === this.orders.length - 1) {
|
|
|
|
|
|
|
|
// Store current group (latest order)
|
|
|
|
|
|
|
|
investments.push({
|
|
|
|
|
|
|
|
date: format(
|
|
|
|
|
|
|
|
set(currentDate, {
|
|
|
|
|
|
|
|
date: 1,
|
|
|
|
|
|
|
|
month: groupBy === 'year' ? 0 : currentDate.getMonth()
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
DATE_FORMAT
|
|
|
|
|
|
|
|
),
|
|
|
|
|
|
|
|
investment: investmentByGroup
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Fill in the missing dates with investment = 0
|
|
|
|
|
|
|
|
const startDate = parseDate(first(this.orders).date);
|
|
|
|
|
|
|
|
const endDate = parseDate(last(this.orders).date);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const allDates: string[] = [];
|
|
|
|
|
|
|
|
currentDate = startDate;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (currentDate <= endDate) {
|
|
|
|
|
|
|
|
allDates.push(
|
|
|
|
|
|
|
|
format(
|
|
|
|
|
|
|
|
set(currentDate, {
|
|
|
|
|
|
|
|
date: 1,
|
|
|
|
|
|
|
|
month: groupBy === 'year' ? 0 : currentDate.getMonth()
|
|
|
|
|
|
|
|
}),
|
|
|
|
|
|
|
|
DATE_FORMAT
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
);
|
|
|
|
);
|
|
|
|
currentDate.setMonth(currentDate.getMonth() + 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (const date of allDates) {
|
|
|
|
return Object.keys(groupedData).map((dateGroup) => ({
|
|
|
|
const existingInvestment = investments.find((investment) => {
|
|
|
|
date: groupBy === 'month' ? `${dateGroup}-01` : `${dateGroup}-01-01`,
|
|
|
|
return investment.date === date;
|
|
|
|
investment: groupedData[dateGroup].toNumber()
|
|
|
|
});
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
if (!existingInvestment) {
|
|
|
|
|
|
|
|
investments.push({ date, investment: new Big(0) });
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return sortBy(investments, ({ date }) => {
|
|
|
|
|
|
|
|
return date;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private calculateOverallPerformance(positions: TimelinePosition[]) {
|
|
|
|
private calculateOverallPerformance(positions: TimelinePosition[]) {
|
|
|
@ -886,17 +837,6 @@ export class PortfolioCalculator {
|
|
|
|
return factor;
|
|
|
|
return factor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private addToDate(date: Date, accuracy: Accuracy): Date {
|
|
|
|
|
|
|
|
switch (accuracy) {
|
|
|
|
|
|
|
|
case 'day':
|
|
|
|
|
|
|
|
return addDays(date, 1);
|
|
|
|
|
|
|
|
case 'month':
|
|
|
|
|
|
|
|
return addMonths(date, 1);
|
|
|
|
|
|
|
|
case 'year':
|
|
|
|
|
|
|
|
return addYears(date, 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private getSymbolMetrics({
|
|
|
|
private getSymbolMetrics({
|
|
|
|
end,
|
|
|
|
end,
|
|
|
|
exchangeRates,
|
|
|
|
exchangeRates,
|
|
|
@ -933,7 +873,10 @@ export class PortfolioCalculator {
|
|
|
|
let initialValueWithCurrencyEffect: Big;
|
|
|
|
let initialValueWithCurrencyEffect: Big;
|
|
|
|
let investmentAtStartDate: Big;
|
|
|
|
let investmentAtStartDate: Big;
|
|
|
|
let investmentAtStartDateWithCurrencyEffect: Big;
|
|
|
|
let investmentAtStartDateWithCurrencyEffect: Big;
|
|
|
|
const investmentValues: { [date: string]: Big } = {};
|
|
|
|
const investmentValuesAccumulated: { [date: string]: Big } = {};
|
|
|
|
|
|
|
|
const investmentValuesAccumulatedWithCurrencyEffect: {
|
|
|
|
|
|
|
|
[date: string]: Big;
|
|
|
|
|
|
|
|
} = {};
|
|
|
|
const investmentValuesWithCurrencyEffect: { [date: string]: Big } = {};
|
|
|
|
const investmentValuesWithCurrencyEffect: { [date: string]: Big } = {};
|
|
|
|
let lastAveragePrice = new Big(0);
|
|
|
|
let lastAveragePrice = new Big(0);
|
|
|
|
let lastAveragePriceWithCurrencyEffect = new Big(0);
|
|
|
|
let lastAveragePriceWithCurrencyEffect = new Big(0);
|
|
|
@ -975,7 +918,8 @@ export class PortfolioCalculator {
|
|
|
|
hasErrors: false,
|
|
|
|
hasErrors: false,
|
|
|
|
initialValue: new Big(0),
|
|
|
|
initialValue: new Big(0),
|
|
|
|
initialValueWithCurrencyEffect: new Big(0),
|
|
|
|
initialValueWithCurrencyEffect: new Big(0),
|
|
|
|
investmentValues: {},
|
|
|
|
investmentValuesAccumulated: {},
|
|
|
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect: {},
|
|
|
|
investmentValuesWithCurrencyEffect: {},
|
|
|
|
investmentValuesWithCurrencyEffect: {},
|
|
|
|
netPerformance: new Big(0),
|
|
|
|
netPerformance: new Big(0),
|
|
|
|
netPerformancePercentage: new Big(0),
|
|
|
|
netPerformancePercentage: new Big(0),
|
|
|
@ -1014,7 +958,8 @@ export class PortfolioCalculator {
|
|
|
|
hasErrors: true,
|
|
|
|
hasErrors: true,
|
|
|
|
initialValue: new Big(0),
|
|
|
|
initialValue: new Big(0),
|
|
|
|
initialValueWithCurrencyEffect: new Big(0),
|
|
|
|
initialValueWithCurrencyEffect: new Big(0),
|
|
|
|
investmentValues: {},
|
|
|
|
investmentValuesAccumulated: {},
|
|
|
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect: {},
|
|
|
|
investmentValuesWithCurrencyEffect: {},
|
|
|
|
investmentValuesWithCurrencyEffect: {},
|
|
|
|
netPerformance: new Big(0),
|
|
|
|
netPerformance: new Big(0),
|
|
|
|
netPerformancePercentage: new Big(0),
|
|
|
|
netPerformancePercentage: new Big(0),
|
|
|
@ -1407,11 +1352,15 @@ export class PortfolioCalculator {
|
|
|
|
feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect)
|
|
|
|
feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect)
|
|
|
|
);
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
investmentValues[order.date] = totalInvestment;
|
|
|
|
investmentValuesAccumulated[order.date] = totalInvestment;
|
|
|
|
|
|
|
|
|
|
|
|
investmentValuesWithCurrencyEffect[order.date] =
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect[order.date] =
|
|
|
|
totalInvestmentWithCurrencyEffect;
|
|
|
|
totalInvestmentWithCurrencyEffect;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
investmentValuesWithCurrencyEffect[order.date] = (
|
|
|
|
|
|
|
|
investmentValuesWithCurrencyEffect[order.date] ?? new Big(0)
|
|
|
|
|
|
|
|
).add(transactionInvestmentWithCurrencyEffect);
|
|
|
|
|
|
|
|
|
|
|
|
timeWeightedInvestmentValues[order.date] =
|
|
|
|
timeWeightedInvestmentValues[order.date] =
|
|
|
|
totalInvestmentDays > 0
|
|
|
|
totalInvestmentDays > 0
|
|
|
|
? sumOfTimeWeightedInvestments.div(totalInvestmentDays)
|
|
|
|
? sumOfTimeWeightedInvestments.div(totalInvestmentDays)
|
|
|
@ -1569,7 +1518,8 @@ export class PortfolioCalculator {
|
|
|
|
grossPerformancePercentageWithCurrencyEffect,
|
|
|
|
grossPerformancePercentageWithCurrencyEffect,
|
|
|
|
initialValue,
|
|
|
|
initialValue,
|
|
|
|
initialValueWithCurrencyEffect,
|
|
|
|
initialValueWithCurrencyEffect,
|
|
|
|
investmentValues,
|
|
|
|
investmentValuesAccumulated,
|
|
|
|
|
|
|
|
investmentValuesAccumulatedWithCurrencyEffect,
|
|
|
|
investmentValuesWithCurrencyEffect,
|
|
|
|
investmentValuesWithCurrencyEffect,
|
|
|
|
netPerformancePercentage,
|
|
|
|
netPerformancePercentage,
|
|
|
|
netPerformancePercentageWithCurrencyEffect,
|
|
|
|
netPerformancePercentageWithCurrencyEffect,
|
|
|
@ -1591,15 +1541,4 @@ export class PortfolioCalculator {
|
|
|
|
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect
|
|
|
|
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect
|
|
|
|
};
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private isNextItemActive(
|
|
|
|
|
|
|
|
timelineSpecification: TimelineSpecification[],
|
|
|
|
|
|
|
|
currentDate: Date,
|
|
|
|
|
|
|
|
i: number
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
i + 1 < timelineSpecification.length &&
|
|
|
|
|
|
|
|
!isBefore(currentDate, parseDate(timelineSpecification[i + 1].start))
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|