Browse Source

Clean up

pull/3393/head
Thomas Kaul 1 year ago
parent
commit
50d8dc3851
  1. 2
      apps/api/src/app/portfolio/calculator/mwr/portfolio-calculator.ts
  2. 15
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  3. 155
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator.ts
  4. 3
      apps/api/src/services/configuration/configuration.service.ts
  5. 2
      libs/common/src/lib/interfaces/symbol-metrics.interface.ts

2
apps/api/src/app/portfolio/calculator/mwr/portfolio-calculator.ts

@ -16,7 +16,6 @@ export class MWRPortfolioCalculator extends PortfolioCalculator {
dataSource, dataSource,
end, end,
exchangeRates, exchangeRates,
isChartMode = false,
marketSymbolMap, marketSymbolMap,
start, start,
step = 1, step = 1,
@ -24,7 +23,6 @@ export class MWRPortfolioCalculator extends PortfolioCalculator {
}: { }: {
end: Date; end: Date;
exchangeRates: { [dateString: string]: number }; exchangeRates: { [dateString: string]: number };
isChartMode?: boolean;
marketSymbolMap: { marketSymbolMap: {
[date: string]: { [symbol: string]: Big }; [date: string]: { [symbol: string]: Big };
}; };

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

@ -320,11 +320,9 @@ export abstract class PortfolioCalculator {
investmentValuesWithCurrencyEffect, investmentValuesWithCurrencyEffect,
netPerformance, netPerformance,
netPerformancePercentage, netPerformancePercentage,
netPerformancePercentageWithCurrencyEffect,
netPerformancePercentageWithCurrencyEffectMap, netPerformancePercentageWithCurrencyEffectMap,
netPerformanceValues, netPerformanceValues,
netPerformanceValuesWithCurrencyEffect, netPerformanceValuesWithCurrencyEffect,
netPerformanceWithCurrencyEffect,
netPerformanceWithCurrencyEffectMap, netPerformanceWithCurrencyEffectMap,
timeWeightedInvestment, timeWeightedInvestment,
timeWeightedInvestmentValues, timeWeightedInvestmentValues,
@ -344,7 +342,6 @@ export abstract class PortfolioCalculator {
end: this.endDate, end: this.endDate,
exchangeRates: exchangeRates:
exchangeRatesByCurrency[`${item.currency}${this.currency}`], exchangeRatesByCurrency[`${item.currency}${this.currency}`],
isChartMode: true,
start: this.startDate, start: this.startDate,
symbol: item.symbol symbol: item.symbol
}); });
@ -673,11 +670,10 @@ export abstract class PortfolioCalculator {
const { historicalData } = this.snapshot; const { historicalData } = this.snapshot;
const newChartData: HistoricalDataItem[] = []; const chart: HistoricalDataItem[] = [];
let netPerformanceAtStartDate: number; let netPerformanceAtStartDate: number;
let netPerformanceWithCurrencyEffectAtStartDate: number; let netPerformanceWithCurrencyEffectAtStartDate: number;
let netPerformanceInPercentageWithCurrencyEffectAtStartDate: number;
let totalInvestmentValuesWithCurrencyEffect: number[] = []; let totalInvestmentValuesWithCurrencyEffect: number[] = [];
for (let historicalDataItem of historicalData) { for (let historicalDataItem of historicalData) {
@ -689,9 +685,6 @@ export abstract class PortfolioCalculator {
netPerformanceWithCurrencyEffectAtStartDate = netPerformanceWithCurrencyEffectAtStartDate =
historicalDataItem.netPerformanceWithCurrencyEffect; historicalDataItem.netPerformanceWithCurrencyEffect;
netPerformanceInPercentageWithCurrencyEffectAtStartDate =
historicalDataItem.netPerformanceInPercentageWithCurrencyEffect;
} }
const netPerformanceSinceStartDate = const netPerformanceSinceStartDate =
@ -713,7 +706,7 @@ export abstract class PortfolioCalculator {
totalInvestmentValuesWithCurrencyEffect.length totalInvestmentValuesWithCurrencyEffect.length
: 0; : 0;
newChartData.push({ chart.push({
...historicalDataItem, ...historicalDataItem,
netPerformance: netPerformance:
historicalDataItem.netPerformance - netPerformanceAtStartDate, historicalDataItem.netPerformance - netPerformanceAtStartDate,
@ -733,7 +726,7 @@ export abstract class PortfolioCalculator {
} }
} }
return { chart: newChartData }; return { chart };
} }
public getStartDate() { public getStartDate() {
@ -768,7 +761,6 @@ export abstract class PortfolioCalculator {
dataSource, dataSource,
end, end,
exchangeRates, exchangeRates,
isChartMode,
marketSymbolMap, marketSymbolMap,
start, start,
symbol symbol
@ -776,7 +768,6 @@ export abstract class PortfolioCalculator {
chartDateMap: { [date: string]: boolean }; chartDateMap: { [date: string]: boolean };
end: Date; end: Date;
exchangeRates: { [dateString: string]: number }; exchangeRates: { [dateString: string]: number };
isChartMode?: boolean;
marketSymbolMap: { marketSymbolMap: {
[date: string]: { [symbol: string]: Big }; [date: string]: { [symbol: string]: Big };
}; };

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

@ -31,7 +31,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
let grossPerformanceWithCurrencyEffect = new Big(0); let grossPerformanceWithCurrencyEffect = new Big(0);
let hasErrors = false; let hasErrors = false;
let netPerformance = new Big(0); let netPerformance = new Big(0);
let netPerformanceWithCurrencyEffect = new Big(0);
let totalFeesWithCurrencyEffect = new Big(0); let totalFeesWithCurrencyEffect = new Big(0);
let totalInterestWithCurrencyEffect = new Big(0); let totalInterestWithCurrencyEffect = new Big(0);
let totalInvestment = new Big(0); let totalInvestment = new Big(0);
@ -76,11 +75,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
); );
netPerformance = netPerformance.plus(currentPosition.netPerformance); netPerformance = netPerformance.plus(currentPosition.netPerformance);
netPerformanceWithCurrencyEffect =
netPerformanceWithCurrencyEffect.plus(
currentPosition.netPerformancePercentageWithCurrencyEffectMap['max']
);
} else if (!currentPosition.quantity.eq(0)) { } else if (!currentPosition.quantity.eq(0)) {
hasErrors = true; hasErrors = true;
} }
@ -123,7 +117,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
dataSource, dataSource,
end, end,
exchangeRates, exchangeRates,
isChartMode = false,
marketSymbolMap, marketSymbolMap,
start, start,
symbol symbol
@ -131,7 +124,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
chartDateMap?: { [date: string]: boolean }; chartDateMap?: { [date: string]: boolean };
end: Date; end: Date;
exchangeRates: { [dateString: string]: number }; exchangeRates: { [dateString: string]: number };
isChartMode?: boolean;
marketSymbolMap: { marketSymbolMap: {
[date: string]: { [symbol: string]: Big }; [date: string]: { [symbol: string]: Big };
}; };
@ -211,11 +203,9 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
investmentValuesWithCurrencyEffect: {}, investmentValuesWithCurrencyEffect: {},
netPerformance: new Big(0), netPerformance: new Big(0),
netPerformancePercentage: new Big(0), netPerformancePercentage: new Big(0),
netPerformancePercentageWithCurrencyEffect: new Big(0),
netPerformancePercentageWithCurrencyEffectMap: {}, netPerformancePercentageWithCurrencyEffectMap: {},
netPerformanceValues: {}, netPerformanceValues: {},
netPerformanceValuesWithCurrencyEffect: {}, netPerformanceValuesWithCurrencyEffect: {},
netPerformanceWithCurrencyEffect: new Big(0),
netPerformanceWithCurrencyEffectMap: {}, netPerformanceWithCurrencyEffectMap: {},
timeWeightedInvestment: new Big(0), timeWeightedInvestment: new Big(0),
timeWeightedInvestmentValues: {}, timeWeightedInvestmentValues: {},
@ -263,12 +253,10 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
investmentValuesWithCurrencyEffect: {}, investmentValuesWithCurrencyEffect: {},
netPerformance: new Big(0), netPerformance: new Big(0),
netPerformancePercentage: new Big(0), netPerformancePercentage: new Big(0),
netPerformancePercentageWithCurrencyEffect: new Big(0),
netPerformancePercentageWithCurrencyEffectMap: {}, netPerformancePercentageWithCurrencyEffectMap: {},
netPerformanceWithCurrencyEffectMap: {}, netPerformanceWithCurrencyEffectMap: {},
netPerformanceValues: {}, netPerformanceValues: {},
netPerformanceValuesWithCurrencyEffect: {}, netPerformanceValuesWithCurrencyEffect: {},
netPerformanceWithCurrencyEffect: new Big(0),
timeWeightedInvestment: new Big(0), timeWeightedInvestment: new Big(0),
timeWeightedInvestmentValues: {}, timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {}, timeWeightedInvestmentValuesWithCurrencyEffect: {},
@ -319,46 +307,43 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
let day = start; let day = start;
let lastUnitPrice: Big; let lastUnitPrice: Big;
if (isChartMode) { const ordersByDate: { [date: string]: PortfolioOrderItem[] } = {};
const ordersByDate: { [date: string]: PortfolioOrderItem[] } = {};
for (const order of orders) { for (const order of orders) {
ordersByDate[order.date] = ordersByDate[order.date] ?? []; ordersByDate[order.date] = ordersByDate[order.date] ?? [];
ordersByDate[order.date].push(order); ordersByDate[order.date].push(order);
} }
while (isBefore(day, end)) { while (isBefore(day, end)) {
const dateString = format(day, DATE_FORMAT); const dateString = format(day, DATE_FORMAT);
if (ordersByDate[dateString]?.length > 0) { if (ordersByDate[dateString]?.length > 0) {
for (let order of ordersByDate[dateString]) { for (let order of ordersByDate[dateString]) {
order.unitPriceFromMarketData = order.unitPriceFromMarketData =
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice; marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice;
}
} else if (chartDateMap[dateString]) {
orders.push({
date: dateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
quantity: new Big(0),
SymbolProfile: {
dataSource,
symbol
},
type: 'BUY',
unitPrice: marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice,
unitPriceFromMarketData:
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice
});
} }
} else if (chartDateMap[dateString]) {
orders.push({
date: dateString,
fee: new Big(0),
feeInBaseCurrency: new Big(0),
quantity: new Big(0),
SymbolProfile: {
dataSource,
symbol
},
type: 'BUY',
unitPrice: marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice,
unitPriceFromMarketData:
marketSymbolMap[dateString]?.[symbol] ?? lastUnitPrice
});
}
const lastOrder = last(orders); const lastOrder = last(orders);
lastUnitPrice = lastUnitPrice = lastOrder.unitPriceFromMarketData ?? lastOrder.unitPrice;
lastOrder.unitPriceFromMarketData ?? lastOrder.unitPrice;
day = addDays(day, 1); day = addDays(day, 1);
}
} }
// Sort orders so that the start and end placeholder order are at the correct // Sort orders so that the start and end placeholder order are at the correct
@ -681,44 +666,42 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
); );
} }
if (isChartMode) { currentValues[order.date] = valueOfInvestment;
currentValues[order.date] = valueOfInvestment;
currentValuesWithCurrencyEffect[order.date] = currentValuesWithCurrencyEffect[order.date] =
valueOfInvestmentWithCurrencyEffect; valueOfInvestmentWithCurrencyEffect;
netPerformanceValues[order.date] = grossPerformance netPerformanceValues[order.date] = grossPerformance
.minus(grossPerformanceAtStartDate) .minus(grossPerformanceAtStartDate)
.minus(fees.minus(feesAtStartDate)); .minus(fees.minus(feesAtStartDate));
netPerformanceValuesWithCurrencyEffect[order.date] = netPerformanceValuesWithCurrencyEffect[order.date] =
grossPerformanceWithCurrencyEffect grossPerformanceWithCurrencyEffect
.minus(grossPerformanceAtStartDateWithCurrencyEffect) .minus(grossPerformanceAtStartDateWithCurrencyEffect)
.minus( .minus(
feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect) feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect)
); );
investmentValuesAccumulated[order.date] = totalInvestment; investmentValuesAccumulated[order.date] = totalInvestment;
investmentValuesAccumulatedWithCurrencyEffect[order.date] = investmentValuesAccumulatedWithCurrencyEffect[order.date] =
totalInvestmentWithCurrencyEffect; totalInvestmentWithCurrencyEffect;
investmentValuesWithCurrencyEffect[order.date] = ( investmentValuesWithCurrencyEffect[order.date] = (
investmentValuesWithCurrencyEffect[order.date] ?? new Big(0) investmentValuesWithCurrencyEffect[order.date] ?? new Big(0)
).add(transactionInvestmentWithCurrencyEffect); ).add(transactionInvestmentWithCurrencyEffect);
timeWeightedInvestmentValues[order.date] = timeWeightedInvestmentValues[order.date] =
totalInvestmentDays > 0 totalInvestmentDays > 0
? sumOfTimeWeightedInvestments.div(totalInvestmentDays) ? sumOfTimeWeightedInvestments.div(totalInvestmentDays)
: new Big(0); : new Big(0);
timeWeightedInvestmentValuesWithCurrencyEffect[order.date] = timeWeightedInvestmentValuesWithCurrencyEffect[order.date] =
totalInvestmentDays > 0 totalInvestmentDays > 0
? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div( ? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div(
totalInvestmentDays totalInvestmentDays
) )
: new Big(0); : new Big(0);
}
} }
if (PortfolioCalculator.ENABLE_LOGGING) { if (PortfolioCalculator.ENABLE_LOGGING) {
@ -760,11 +743,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
.minus(grossPerformanceAtStartDate) .minus(grossPerformanceAtStartDate)
.minus(fees.minus(feesAtStartDate)); .minus(fees.minus(feesAtStartDate));
const totalNetPerformanceWithCurrencyEffect =
grossPerformanceWithCurrencyEffect
.minus(grossPerformanceAtStartDateWithCurrencyEffect)
.minus(feesWithCurrencyEffect.minus(feesAtStartDateWithCurrencyEffect));
const timeWeightedAverageInvestmentBetweenStartAndEndDate = const timeWeightedAverageInvestmentBetweenStartAndEndDate =
totalInvestmentDays > 0 totalInvestmentDays > 0
? sumOfTimeWeightedInvestments.div(totalInvestmentDays) ? sumOfTimeWeightedInvestments.div(totalInvestmentDays)
@ -810,15 +788,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
) )
: new Big(0); : new Big(0);
const netPerformancePercentageWithCurrencyEffect =
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect.gt(
0
)
? totalNetPerformanceWithCurrencyEffect.div(
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect
)
: new Big(0);
const netPerformancePercentageWithCurrencyEffectMap: { const netPerformancePercentageWithCurrencyEffectMap: {
[key: DateRange]: Big; [key: DateRange]: Big;
} = {}; } = {};
@ -946,9 +915,9 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
Net performance: ${totalNetPerformance.toFixed( Net performance: ${totalNetPerformance.toFixed(
2 2
)} / ${netPerformancePercentage.mul(100).toFixed(2)}% )} / ${netPerformancePercentage.mul(100).toFixed(2)}%
Net performance with currency effect: ${totalNetPerformanceWithCurrencyEffect.toFixed( Net performance with currency effect: ${netPerformancePercentageWithCurrencyEffectMap[
2 'max'
)} / ${netPerformancePercentageWithCurrencyEffect.mul(100).toFixed(2)}%` ].toFixed(2)}%`
); );
} }
@ -964,7 +933,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
investmentValuesAccumulatedWithCurrencyEffect, investmentValuesAccumulatedWithCurrencyEffect,
investmentValuesWithCurrencyEffect, investmentValuesWithCurrencyEffect,
netPerformancePercentage, netPerformancePercentage,
netPerformancePercentageWithCurrencyEffect,
netPerformancePercentageWithCurrencyEffectMap, netPerformancePercentageWithCurrencyEffectMap,
netPerformanceValues, netPerformanceValues,
netPerformanceValuesWithCurrencyEffect, netPerformanceValuesWithCurrencyEffect,
@ -987,7 +955,6 @@ export class TWRPortfolioCalculator extends PortfolioCalculator {
totalGrossPerformanceWithCurrencyEffect, totalGrossPerformanceWithCurrencyEffect,
hasErrors: totalUnits.gt(0) && (!initialValue || !unitPriceAtEndDate), hasErrors: totalUnits.gt(0) && (!initialValue || !unitPriceAtEndDate),
netPerformance: totalNetPerformance, netPerformance: totalNetPerformance,
netPerformanceWithCurrencyEffect: totalNetPerformanceWithCurrencyEffect,
timeWeightedInvestment: timeWeightedInvestment:
timeWeightedAverageInvestmentBetweenStartAndEndDate, timeWeightedAverageInvestmentBetweenStartAndEndDate,
timeWeightedInvestmentWithCurrencyEffect: timeWeightedInvestmentWithCurrencyEffect:

3
apps/api/src/services/configuration/configuration.service.ts

@ -4,6 +4,7 @@ import { DEFAULT_ROOT_URL } from '@ghostfolio/common/config';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { DataSource } from '@prisma/client'; import { DataSource } from '@prisma/client';
import { bool, cleanEnv, host, json, num, port, str, url } from 'envalid'; import { bool, cleanEnv, host, json, num, port, str, url } from 'envalid';
import ms from 'ms';
@Injectable() @Injectable()
export class ConfigurationService { export class ConfigurationService {
@ -20,7 +21,7 @@ export class ConfigurationService {
API_KEY_FINANCIAL_MODELING_PREP: str({ default: '' }), API_KEY_FINANCIAL_MODELING_PREP: str({ default: '' }),
API_KEY_OPEN_FIGI: str({ default: '' }), API_KEY_OPEN_FIGI: str({ default: '' }),
API_KEY_RAPID_API: str({ default: '' }), API_KEY_RAPID_API: str({ default: '' }),
CACHE_QUOTES_TTL: num({ default: 60 }), CACHE_QUOTES_TTL: num({ default: ms('1 minute') / 1000 }),
CACHE_TTL: num({ default: 1 }), CACHE_TTL: num({ default: 1 }),
DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }), DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }),
DATA_SOURCE_IMPORT: str({ default: DataSource.YAHOO }), DATA_SOURCE_IMPORT: str({ default: DataSource.YAHOO }),

2
libs/common/src/lib/interfaces/symbol-metrics.interface.ts

@ -28,13 +28,11 @@ export interface SymbolMetrics {
}; };
netPerformance: Big; netPerformance: Big;
netPerformancePercentage: Big; netPerformancePercentage: Big;
netPerformancePercentageWithCurrencyEffect: Big;
netPerformancePercentageWithCurrencyEffectMap: { [key: DateRange]: Big }; netPerformancePercentageWithCurrencyEffectMap: { [key: DateRange]: Big };
netPerformanceValues: { netPerformanceValues: {
[date: string]: Big; [date: string]: Big;
}; };
netPerformanceValuesWithCurrencyEffect: { [date: string]: Big }; netPerformanceValuesWithCurrencyEffect: { [date: string]: Big };
netPerformanceWithCurrencyEffect: Big;
netPerformanceWithCurrencyEffectMap: { [key: DateRange]: Big }; netPerformanceWithCurrencyEffectMap: { [key: DateRange]: Big };
timeWeightedInvestment: Big; timeWeightedInvestment: Big;
timeWeightedInvestmentValues: { timeWeightedInvestmentValues: {

Loading…
Cancel
Save