Browse Source

Task/rename time weighted investment to average investment (#7918)

Rename time weighted investment to average investment
pull/7919/head
Thomas Kaul 1 week ago
committed by GitHub
parent
commit
74d564a2b2
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 111
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  2. 8
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts
  3. 8
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts
  4. 4
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts
  5. 4
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts
  6. 4
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts
  7. 8
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts
  8. 4
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts
  9. 8
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts
  10. 4
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts
  11. 8
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
  12. 4
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts
  13. 4
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts
  14. 98
      apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts
  15. 16
      apps/api/src/app/portfolio/interfaces/holding-performance.interface.ts
  16. 4
      apps/api/src/app/portfolio/portfolio.service.spec.ts
  17. 14
      apps/api/src/app/portfolio/portfolio.service.ts
  18. 43
      libs/common/src/lib/models/portfolio-snapshot-holding.ts

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

@ -355,6 +355,8 @@ export abstract class PortfolioCalculator {
const accumulatedValuesByDate: { const accumulatedValuesByDate: {
[date: string]: { [date: string]: {
investmentValueWithCurrencyEffect: Big; investmentValueWithCurrencyEffect: Big;
totalAverageInvestmentValue: Big;
totalAverageInvestmentValueWithCurrencyEffect: Big;
totalCashValueWithCurrencyEffect: Big; totalCashValueWithCurrencyEffect: Big;
totalCurrentValue: Big; totalCurrentValue: Big;
totalCurrentValueWithCurrencyEffect: Big; totalCurrentValueWithCurrencyEffect: Big;
@ -363,13 +365,13 @@ export abstract class PortfolioCalculator {
totalNetPerformanceValue: Big; totalNetPerformanceValue: Big;
totalNetPerformanceValueWithCurrencyEffect: Big; totalNetPerformanceValueWithCurrencyEffect: Big;
totalNetWorthValueWithCurrencyEffect: Big; totalNetWorthValueWithCurrencyEffect: Big;
totalTimeWeightedInvestmentValue: Big;
totalTimeWeightedInvestmentValueWithCurrencyEffect: Big;
}; };
} = {}; } = {};
const valuesByAssetProfileIdentifier: { const valuesByAssetProfileIdentifier: {
[assetProfileIdentifier: string]: { [assetProfileIdentifier: string]: {
averageInvestmentValues: { [date: string]: Big };
averageInvestmentValuesWithCurrencyEffect: { [date: string]: Big };
currentValues: { [date: string]: Big }; currentValues: { [date: string]: Big };
currentValuesWithCurrencyEffect: { [date: string]: Big }; currentValuesWithCurrencyEffect: { [date: string]: Big };
investmentValuesAccumulated: { [date: string]: Big }; investmentValuesAccumulated: { [date: string]: Big };
@ -378,8 +380,6 @@ export abstract class PortfolioCalculator {
netPerformanceValues: { [date: string]: Big }; netPerformanceValues: { [date: string]: Big };
netPerformanceValuesWithCurrencyEffect: { [date: string]: Big }; netPerformanceValuesWithCurrencyEffect: { [date: string]: Big };
netWorthValuesWithCurrencyEffect: { [date: string]: Big }; netWorthValuesWithCurrencyEffect: { [date: string]: Big };
timeWeightedInvestmentValues: { [date: string]: Big };
timeWeightedInvestmentValuesWithCurrencyEffect: { [date: string]: Big };
}; };
} = {}; } = {};
@ -403,6 +403,10 @@ export abstract class PortfolioCalculator {
item.symbol === this.currency; item.symbol === this.currency;
const { const {
averageInvestment,
averageInvestmentValues,
averageInvestmentValuesWithCurrencyEffect,
averageInvestmentWithCurrencyEffect,
currentValues, currentValues,
currentValuesWithCurrencyEffect, currentValuesWithCurrencyEffect,
grossPerformance, grossPerformance,
@ -419,10 +423,6 @@ export abstract class PortfolioCalculator {
netPerformanceValues, netPerformanceValues,
netPerformanceValuesWithCurrencyEffect, netPerformanceValuesWithCurrencyEffect,
netPerformanceWithCurrencyEffectMap, netPerformanceWithCurrencyEffectMap,
timeWeightedInvestment,
timeWeightedInvestmentValues,
timeWeightedInvestmentValuesWithCurrencyEffect,
timeWeightedInvestmentWithCurrencyEffect,
totalDividend, totalDividend,
totalDividendInBaseCurrency, totalDividendInBaseCurrency,
totalInterestInBaseCurrency, totalInterestInBaseCurrency,
@ -450,6 +450,8 @@ export abstract class PortfolioCalculator {
valuesByAssetProfileIdentifier[assetProfileIdentifier] = valuesByAssetProfileIdentifier[assetProfileIdentifier] =
isCashInBaseCurrency isCashInBaseCurrency
? { ? {
averageInvestmentValues: {},
averageInvestmentValuesWithCurrencyEffect: {},
currentValues: {}, currentValues: {},
currentValuesWithCurrencyEffect: {}, currentValuesWithCurrencyEffect: {},
investmentValuesAccumulated: {}, investmentValuesAccumulated: {},
@ -457,11 +459,11 @@ export abstract class PortfolioCalculator {
investmentValuesWithCurrencyEffect: {}, investmentValuesWithCurrencyEffect: {},
netPerformanceValues: {}, netPerformanceValues: {},
netPerformanceValuesWithCurrencyEffect: {}, netPerformanceValuesWithCurrencyEffect: {},
netWorthValuesWithCurrencyEffect: currentValuesWithCurrencyEffect, netWorthValuesWithCurrencyEffect: currentValuesWithCurrencyEffect
timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {}
} }
: { : {
averageInvestmentValues,
averageInvestmentValuesWithCurrencyEffect,
currentValues, currentValues,
currentValuesWithCurrencyEffect, currentValuesWithCurrencyEffect,
investmentValuesAccumulated, investmentValuesAccumulated,
@ -469,14 +471,12 @@ export abstract class PortfolioCalculator {
investmentValuesWithCurrencyEffect, investmentValuesWithCurrencyEffect,
netPerformanceValues, netPerformanceValues,
netPerformanceValuesWithCurrencyEffect, netPerformanceValuesWithCurrencyEffect,
timeWeightedInvestmentValues,
timeWeightedInvestmentValuesWithCurrencyEffect,
netWorthValuesWithCurrencyEffect: currentValuesWithCurrencyEffect netWorthValuesWithCurrencyEffect: currentValuesWithCurrencyEffect
}; };
positions.push({ positions.push({
timeWeightedInvestment, averageInvestment,
timeWeightedInvestmentWithCurrencyEffect, averageInvestmentWithCurrencyEffect,
activitiesCount: item.activitiesCount, activitiesCount: item.activitiesCount,
averagePrice: item.averagePrice, averagePrice: item.averagePrice,
currency: item.currency, currency: item.currency,
@ -586,12 +586,12 @@ export abstract class PortfolioCalculator {
assetProfileValues.netWorthValuesWithCurrencyEffect?.[dateString] ?? assetProfileValues.netWorthValuesWithCurrencyEffect?.[dateString] ??
new Big(0); new Big(0);
const timeWeightedInvestmentValue = const averageInvestmentValue =
assetProfileValues.timeWeightedInvestmentValues?.[dateString] ?? assetProfileValues.averageInvestmentValues?.[dateString] ??
new Big(0); new Big(0);
const timeWeightedInvestmentValueWithCurrencyEffect = const averageInvestmentValueWithCurrencyEffect =
assetProfileValues.timeWeightedInvestmentValuesWithCurrencyEffect?.[ assetProfileValues.averageInvestmentValuesWithCurrencyEffect?.[
dateString dateString
] ?? new Big(0); ] ?? new Big(0);
@ -600,6 +600,14 @@ export abstract class PortfolioCalculator {
accumulatedValuesByDate[dateString] accumulatedValuesByDate[dateString]
?.investmentValueWithCurrencyEffect ?? new Big(0) ?.investmentValueWithCurrencyEffect ?? new Big(0)
).add(investmentValueWithCurrencyEffect), ).add(investmentValueWithCurrencyEffect),
totalAverageInvestmentValue: (
accumulatedValuesByDate[dateString]?.totalAverageInvestmentValue ??
new Big(0)
).add(averageInvestmentValue),
totalAverageInvestmentValueWithCurrencyEffect: (
accumulatedValuesByDate[dateString]
?.totalAverageInvestmentValueWithCurrencyEffect ?? new Big(0)
).add(averageInvestmentValueWithCurrencyEffect),
totalCashValueWithCurrencyEffect: ( totalCashValueWithCurrencyEffect: (
accumulatedValuesByDate[dateString] accumulatedValuesByDate[dateString]
?.totalCashValueWithCurrencyEffect ?? new Big(0) ?.totalCashValueWithCurrencyEffect ?? new Big(0)
@ -634,15 +642,7 @@ export abstract class PortfolioCalculator {
totalNetWorthValueWithCurrencyEffect: ( totalNetWorthValueWithCurrencyEffect: (
accumulatedValuesByDate[dateString] accumulatedValuesByDate[dateString]
?.totalNetWorthValueWithCurrencyEffect ?? new Big(0) ?.totalNetWorthValueWithCurrencyEffect ?? new Big(0)
).add(netWorthValueWithCurrencyEffect), ).add(netWorthValueWithCurrencyEffect)
totalTimeWeightedInvestmentValue: (
accumulatedValuesByDate[dateString]
?.totalTimeWeightedInvestmentValue ?? new Big(0)
).add(timeWeightedInvestmentValue),
totalTimeWeightedInvestmentValueWithCurrencyEffect: (
accumulatedValuesByDate[dateString]
?.totalTimeWeightedInvestmentValueWithCurrencyEffect ?? new Big(0)
).add(timeWeightedInvestmentValueWithCurrencyEffect)
}; };
} }
} }
@ -652,6 +652,8 @@ export abstract class PortfolioCalculator {
).map(([date, values]) => { ).map(([date, values]) => {
const { const {
investmentValueWithCurrencyEffect, investmentValueWithCurrencyEffect,
totalAverageInvestmentValue,
totalAverageInvestmentValueWithCurrencyEffect,
totalCashValueWithCurrencyEffect, totalCashValueWithCurrencyEffect,
totalCurrentValue, totalCurrentValue,
totalCurrentValueWithCurrencyEffect, totalCurrentValueWithCurrencyEffect,
@ -659,22 +661,18 @@ export abstract class PortfolioCalculator {
totalInvestmentValueWithCurrencyEffect, totalInvestmentValueWithCurrencyEffect,
totalNetPerformanceValue, totalNetPerformanceValue,
totalNetPerformanceValueWithCurrencyEffect, totalNetPerformanceValueWithCurrencyEffect,
totalNetWorthValueWithCurrencyEffect, totalNetWorthValueWithCurrencyEffect
totalTimeWeightedInvestmentValue,
totalTimeWeightedInvestmentValueWithCurrencyEffect
} = values; } = values;
const netPerformanceInPercentage = totalTimeWeightedInvestmentValue.eq(0) const netPerformanceInPercentage = totalAverageInvestmentValue.eq(0)
? 0 ? 0
: totalNetPerformanceValue : totalNetPerformanceValue.div(totalAverageInvestmentValue).toNumber();
.div(totalTimeWeightedInvestmentValue)
.toNumber();
const netPerformanceInPercentageWithCurrencyEffect = const netPerformanceInPercentageWithCurrencyEffect =
totalTimeWeightedInvestmentValueWithCurrencyEffect.eq(0) totalAverageInvestmentValueWithCurrencyEffect.eq(0)
? 0 ? 0
: totalNetPerformanceValueWithCurrencyEffect : totalNetPerformanceValueWithCurrencyEffect
.div(totalTimeWeightedInvestmentValueWithCurrencyEffect) .div(totalAverageInvestmentValueWithCurrencyEffect)
.toNumber(); .toNumber();
return { return {
@ -868,6 +866,10 @@ export abstract class PortfolioCalculator {
protected getEmptyHoldingPerformance(): HoldingPerformance { protected getEmptyHoldingPerformance(): HoldingPerformance {
return { return {
averageInvestment: new Big(0),
averageInvestmentValues: {},
averageInvestmentValuesWithCurrencyEffect: {},
averageInvestmentWithCurrencyEffect: new Big(0),
currentValues: {}, currentValues: {},
currentValuesWithCurrencyEffect: {}, currentValuesWithCurrencyEffect: {},
grossPerformance: new Big(0), grossPerformance: new Big(0),
@ -884,10 +886,6 @@ export abstract class PortfolioCalculator {
netPerformanceValues: {}, netPerformanceValues: {},
netPerformanceValuesWithCurrencyEffect: {}, netPerformanceValuesWithCurrencyEffect: {},
netPerformanceWithCurrencyEffectMap: {}, netPerformanceWithCurrencyEffectMap: {},
timeWeightedInvestment: new Big(0),
timeWeightedInvestmentValues: {},
timeWeightedInvestmentValuesWithCurrencyEffect: {},
timeWeightedInvestmentWithCurrencyEffect: new Big(0),
totalDividend: new Big(0), totalDividend: new Big(0),
totalDividendInBaseCurrency: new Big(0), totalDividendInBaseCurrency: new Big(0),
totalInterestInBaseCurrency: new Big(0), totalInterestInBaseCurrency: new Big(0),
@ -1346,12 +1344,12 @@ export abstract class PortfolioCalculator {
const chart: HistoricalDataItem[] = []; const chart: HistoricalDataItem[] = [];
const averageInvestmentValues: number[] = [];
const averageInvestmentValuesWithCurrencyEffect: number[] = [];
let grossPerformanceAtStartDate: number; let grossPerformanceAtStartDate: number;
let grossPerformanceWithCurrencyEffectAtStartDate: number; let grossPerformanceWithCurrencyEffectAtStartDate: number;
let netPerformanceAtStartDate: number; let netPerformanceAtStartDate: number;
let netPerformanceWithCurrencyEffectAtStartDate: number; let netPerformanceWithCurrencyEffectAtStartDate: number;
const timeWeightedInvestmentValues: number[] = [];
const timeWeightedInvestmentValuesWithCurrencyEffect: number[] = [];
for (const historicalDataItem of historicalData) { for (const historicalDataItem of historicalData) {
const date = resetHours(parseDate(historicalDataItem.date)); const date = resetHours(parseDate(historicalDataItem.date));
@ -1382,28 +1380,27 @@ export abstract class PortfolioCalculator {
// investment of each day. Thus the range starts with the value of its // investment of each day. Thus the range starts with the value of its
// first day, and subsequent buy and sell activities stay included. // first day, and subsequent buy and sell activities stay included.
if (historicalDataItem.totalInvestment > 0) { if (historicalDataItem.totalInvestment > 0) {
timeWeightedInvestmentValues.push( averageInvestmentValues.push(
historicalDataItem.totalInvestment + grossPerformanceAtStartDate historicalDataItem.totalInvestment + grossPerformanceAtStartDate
); );
} }
if (historicalDataItem.totalInvestmentValueWithCurrencyEffect > 0) { if (historicalDataItem.totalInvestmentValueWithCurrencyEffect > 0) {
timeWeightedInvestmentValuesWithCurrencyEffect.push( averageInvestmentValuesWithCurrencyEffect.push(
historicalDataItem.totalInvestmentValueWithCurrencyEffect + historicalDataItem.totalInvestmentValueWithCurrencyEffect +
grossPerformanceWithCurrencyEffectAtStartDate grossPerformanceWithCurrencyEffectAtStartDate
); );
} }
const timeWeightedInvestmentValue = const averageInvestmentValue =
timeWeightedInvestmentValues.length > 0 averageInvestmentValues.length > 0
? sum(timeWeightedInvestmentValues) / ? sum(averageInvestmentValues) / averageInvestmentValues.length
timeWeightedInvestmentValues.length
: 0; : 0;
const timeWeightedInvestmentValueWithCurrencyEffect = const averageInvestmentValueWithCurrencyEffect =
timeWeightedInvestmentValuesWithCurrencyEffect.length > 0 averageInvestmentValuesWithCurrencyEffect.length > 0
? sum(timeWeightedInvestmentValuesWithCurrencyEffect) / ? sum(averageInvestmentValuesWithCurrencyEffect) /
timeWeightedInvestmentValuesWithCurrencyEffect.length averageInvestmentValuesWithCurrencyEffect.length
: 0; : 0;
chart.push({ chart.push({
@ -1412,13 +1409,13 @@ export abstract class PortfolioCalculator {
netPerformanceWithCurrencyEffect: netPerformanceWithCurrencyEffect:
netPerformanceWithCurrencyEffectSinceStartDate, netPerformanceWithCurrencyEffectSinceStartDate,
netPerformanceInPercentage: netPerformanceInPercentage:
timeWeightedInvestmentValue > 0 averageInvestmentValue > 0
? netPerformanceSinceStartDate / timeWeightedInvestmentValue ? netPerformanceSinceStartDate / averageInvestmentValue
: 0, : 0,
netPerformanceInPercentageWithCurrencyEffect: netPerformanceInPercentageWithCurrencyEffect:
timeWeightedInvestmentValueWithCurrencyEffect > 0 averageInvestmentValueWithCurrencyEffect > 0
? netPerformanceWithCurrencyEffectSinceStartDate / ? netPerformanceWithCurrencyEffectSinceStartDate /
timeWeightedInvestmentValueWithCurrencyEffect averageInvestmentValueWithCurrencyEffect
: 0 : 0
}); });
} }

8
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts

@ -148,6 +148,10 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 2, activitiesCount: 2,
averageInvestment: new Big('474.93846153846153846154'),
averageInvestmentWithCurrencyEffect: new Big(
'474.93846153846153846154'
),
averagePrice: new Big('139.75'), averagePrice: new Big('139.75'),
currency: 'CHF', currency: 'CHF',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -177,10 +181,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('4'), quantity: new Big('4'),
symbol: 'BALN.SW', symbol: 'BALN.SW',
tags: [], tags: [],
timeWeightedInvestment: new Big('474.93846153846153846154'),
timeWeightedInvestmentWithCurrencyEffect: new Big(
'474.93846153846153846154'
),
valueInBaseCurrency: new Big('595.6') valueInBaseCurrency: new Big('595.6')
} }
], ],

8
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts

@ -164,6 +164,10 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 3, activitiesCount: 3,
averageInvestment: new Big('285.80000000000000396627'),
averageInvestmentWithCurrencyEffect: new Big(
'285.80000000000000396627'
),
averagePrice: new Big('0'), averagePrice: new Big('0'),
currency: 'CHF', currency: 'CHF',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -191,10 +195,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('0'), quantity: new Big('0'),
symbol: 'BALN.SW', symbol: 'BALN.SW',
tags: [], tags: [],
timeWeightedInvestment: new Big('285.80000000000000396627'),
timeWeightedInvestmentWithCurrencyEffect: new Big(
'285.80000000000000396627'
),
valueInBaseCurrency: new Big('0') valueInBaseCurrency: new Big('0')
} }
], ],

4
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts

@ -155,6 +155,8 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 2, activitiesCount: 2,
averageInvestment: new Big('285.8'),
averageInvestmentWithCurrencyEffect: new Big('285.8'),
averagePrice: new Big('0'), averagePrice: new Big('0'),
currency: 'CHF', currency: 'CHF',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -184,8 +186,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('0'), quantity: new Big('0'),
symbol: 'BALN.SW', symbol: 'BALN.SW',
tags: [], tags: [],
timeWeightedInvestment: new Big('285.8'),
timeWeightedInvestmentWithCurrencyEffect: new Big('285.8'),
valueInBaseCurrency: new Big('0') valueInBaseCurrency: new Big('0')
} }
], ],

4
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts

@ -138,6 +138,8 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 1, activitiesCount: 1,
averageInvestment: new Big('273.2'),
averageInvestmentWithCurrencyEffect: new Big('273.2'),
averagePrice: new Big('136.6'), averagePrice: new Big('136.6'),
currency: 'CHF', currency: 'CHF',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -173,8 +175,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('2'), quantity: new Big('2'),
symbol: 'BALN.SW', symbol: 'BALN.SW',
tags: [], tags: [],
timeWeightedInvestment: new Big('273.2'),
timeWeightedInvestmentWithCurrencyEffect: new Big('273.2'),
valueInBaseCurrency: new Big('297.8') valueInBaseCurrency: new Big('297.8')
} }
], ],

4
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts

@ -199,6 +199,8 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 1, activitiesCount: 1,
averageInvestment: new Big('44558.42'),
averageInvestmentWithCurrencyEffect: new Big('44558.42'),
averagePrice: new Big('44558.42'), averagePrice: new Big('44558.42'),
currency: 'USD', currency: 'USD',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -228,8 +230,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('1'), quantity: new Big('1'),
symbol: 'BTCUSD', symbol: 'BTCUSD',
tags: [], tags: [],
timeWeightedInvestment: new Big('44558.42'),
timeWeightedInvestmentWithCurrencyEffect: new Big('44558.42'),
valueInBaseCurrency: new Big('43099.7') valueInBaseCurrency: new Big('43099.7')
} }
], ],

8
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts

@ -167,6 +167,10 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 2, activitiesCount: 2,
averageInvestment: new Big('623.73992504096715328467'),
averageInvestmentWithCurrencyEffect: new Big(
'636.79469348020066587024'
),
averagePrice: new Big('320.43'), averagePrice: new Big('320.43'),
currency: 'USD', currency: 'USD',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -202,10 +206,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('1'), quantity: new Big('1'),
symbol: 'BTCUSD', symbol: 'BTCUSD',
tags: [], tags: [],
timeWeightedInvestment: new Big('623.73992504096715328467'),
timeWeightedInvestmentWithCurrencyEffect: new Big(
'636.79469348020066587024'
),
valueInBaseCurrency: new Big('13298.425356') valueInBaseCurrency: new Big('13298.425356')
} }
], ],

4
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts

@ -199,6 +199,8 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 1, activitiesCount: 1,
averageInvestment: new Big('44558.42'),
averageInvestmentWithCurrencyEffect: new Big('44558.42'),
averagePrice: new Big('44558.42'), averagePrice: new Big('44558.42'),
currency: 'USD', currency: 'USD',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -228,8 +230,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('1'), quantity: new Big('1'),
symbol: 'BTCUSD', symbol: 'BTCUSD',
tags: [], tags: [],
timeWeightedInvestment: new Big('44558.42'),
timeWeightedInvestmentWithCurrencyEffect: new Big('44558.42'),
valueInBaseCurrency: new Big('43099.7') valueInBaseCurrency: new Big('43099.7')
} }
], ],

8
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts

@ -252,6 +252,10 @@ describe('PortfolioCalculator', () => {
*/ */
expect(position).toMatchObject<PortfolioSnapshotHolding>({ expect(position).toMatchObject<PortfolioSnapshotHolding>({
activitiesCount: 2, activitiesCount: 2,
averageInvestment: new Big('912.47956403269754768392'),
averageInvestmentWithCurrencyEffect: new Big(
'852.45231607629427792916'
),
averagePrice: new Big(1), averagePrice: new Big(1),
currency: 'USD', currency: 'USD',
dataSource: DataSource.YAHOO, dataSource: DataSource.YAHOO,
@ -292,10 +296,6 @@ describe('PortfolioCalculator', () => {
}, },
quantity: new Big(2000), quantity: new Big(2000),
symbol: 'USD', symbol: 'USD',
timeWeightedInvestment: new Big('912.47956403269754768392'),
timeWeightedInvestmentWithCurrencyEffect: new Big(
'852.45231607629427792916'
),
valueInBaseCurrency: new Big(1820) valueInBaseCurrency: new Big(1820)
}); });

4
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts

@ -144,6 +144,8 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 1, activitiesCount: 1,
averageInvestment: new Big('89.12').mul(0.8854),
averageInvestmentWithCurrencyEffect: new Big('82.329056'),
averagePrice: new Big('89.12'), averagePrice: new Big('89.12'),
currency: 'USD', currency: 'USD',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -173,8 +175,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('1'), quantity: new Big('1'),
symbol: 'GOOGL', symbol: 'GOOGL',
tags: [], tags: [],
timeWeightedInvestment: new Big('89.12').mul(0.8854),
timeWeightedInvestmentWithCurrencyEffect: new Big('82.329056'),
valueInBaseCurrency: new Big('103.10483') valueInBaseCurrency: new Big('103.10483')
} }
], ],

8
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts

@ -144,6 +144,10 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 2, activitiesCount: 2,
averageInvestment: new Big('145.10285714285714285714'),
averageInvestmentWithCurrencyEffect: new Big(
'145.10285714285714285714'
),
averagePrice: new Big('75.80'), averagePrice: new Big('75.80'),
currency: 'CHF', currency: 'CHF',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -173,10 +177,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('1'), quantity: new Big('1'),
symbol: 'NOVN.SW', symbol: 'NOVN.SW',
tags: [], tags: [],
timeWeightedInvestment: new Big('145.10285714285714285714'),
timeWeightedInvestmentWithCurrencyEffect: new Big(
'145.10285714285714285714'
),
valueInBaseCurrency: new Big('87.8') valueInBaseCurrency: new Big('87.8')
} }
], ],

4
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts

@ -197,6 +197,8 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 2, activitiesCount: 2,
averageInvestment: new Big('151.6'),
averageInvestmentWithCurrencyEffect: new Big('151.6'),
averagePrice: new Big('0'), averagePrice: new Big('0'),
currency: 'CHF', currency: 'CHF',
dataSource: 'YAHOO', dataSource: 'YAHOO',
@ -226,8 +228,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('0'), quantity: new Big('0'),
symbol: 'NOVN.SW', symbol: 'NOVN.SW',
tags: [], tags: [],
timeWeightedInvestment: new Big('151.6'),
timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'),
valueInBaseCurrency: new Big('0') valueInBaseCurrency: new Big('0')
} }
], ],

4
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts

@ -121,6 +121,8 @@ describe('PortfolioCalculator', () => {
positions: [ positions: [
{ {
activitiesCount: 1, activitiesCount: 1,
averageInvestment: new Big('500000'),
averageInvestmentWithCurrencyEffect: new Big('500000'),
averagePrice: new Big('500000'), averagePrice: new Big('500000'),
currency: 'USD', currency: 'USD',
dataSource: 'MANUAL', dataSource: 'MANUAL',
@ -148,8 +150,6 @@ describe('PortfolioCalculator', () => {
quantity: new Big('1'), quantity: new Big('1'),
symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde', symbol: 'dac95060-d4f2-4653-a253-2c45e6fb5cde',
tags: [], tags: [],
timeWeightedInvestment: new Big('500000'),
timeWeightedInvestmentWithCurrencyEffect: new Big('500000'),
valueInBaseCurrency: new Big('500000') valueInBaseCurrency: new Big('500000')
} }
], ],

98
apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts

@ -31,12 +31,12 @@ export class RoaiPortfolioCalculator 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 totalAverageInvestment = new Big(0);
let totalAverageInvestmentWithCurrencyEffect = new Big(0);
let totalFeesWithCurrencyEffect = new Big(0); let totalFeesWithCurrencyEffect = new Big(0);
const totalInterestWithCurrencyEffect = new Big(0); const totalInterestWithCurrencyEffect = new Big(0);
let totalInvestment = new Big(0); let totalInvestment = new Big(0);
let totalInvestmentWithCurrencyEffect = new Big(0); let totalInvestmentWithCurrencyEffect = new Big(0);
let totalTimeWeightedInvestment = new Big(0);
let totalTimeWeightedInvestmentWithCurrencyEffect = new Big(0);
for (const currentPosition of positions) { for (const currentPosition of positions) {
if (currentPosition.valueInBaseCurrency) { if (currentPosition.valueInBaseCurrency) {
@ -83,14 +83,14 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
hasErrors = true; hasErrors = true;
} }
if (currentPosition.timeWeightedInvestment) { if (currentPosition.averageInvestment) {
totalTimeWeightedInvestment = totalTimeWeightedInvestment.plus( totalAverageInvestment = totalAverageInvestment.plus(
currentPosition.timeWeightedInvestment currentPosition.averageInvestment
); );
totalTimeWeightedInvestmentWithCurrencyEffect = totalAverageInvestmentWithCurrencyEffect =
totalTimeWeightedInvestmentWithCurrencyEffect.plus( totalAverageInvestmentWithCurrencyEffect.plus(
currentPosition.timeWeightedInvestmentWithCurrencyEffect currentPosition.averageInvestmentWithCurrencyEffect
); );
} else if (!currentPosition.quantity.eq(0)) { } else if (!currentPosition.quantity.eq(0)) {
this.logger.warn( this.logger.warn(
@ -137,14 +137,14 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
}; };
start: Date; start: Date;
} & AssetProfileIdentifier): HoldingPerformance { } & AssetProfileIdentifier): HoldingPerformance {
let investmentAtStartDate: Big; const averageInvestmentValues: { [date: string]: Big } = {};
let investmentAtStartDateWithCurrencyEffect: Big;
const timeWeightedInvestmentValues: { [date: string]: Big } = {};
const timeWeightedInvestmentValuesWithCurrencyEffect: { const averageInvestmentValuesWithCurrencyEffect: {
[date: string]: Big; [date: string]: Big;
} = {}; } = {};
let investmentAtStartDate: Big;
let investmentAtStartDateWithCurrencyEffect: Big;
let valueAtStartDate: Big; let valueAtStartDate: Big;
let valueAtStartDateWithCurrencyEffect: Big; let valueAtStartDateWithCurrencyEffect: Big;
@ -248,9 +248,9 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
return itemType === 'end'; return itemType === 'end';
}); });
let sumOfWeightedInvestments = new Big(0);
let sumOfWeightedInvestmentsWithCurrencyEffect = new Big(0);
let totalInvestmentDays = 0; let totalInvestmentDays = 0;
let sumOfTimeWeightedInvestments = new Big(0);
let sumOfTimeWeightedInvestmentsWithCurrencyEffect = new Big(0);
for (let i = 0; i < items.length; i += 1) { for (let i = 0; i < items.length; i += 1) {
const item = items[i]; const item = items[i];
@ -269,7 +269,7 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
if (i > indexOfStartActivity) { if (i > indexOfStartActivity) {
// Only consider periods with an investment for the calculation of // Only consider periods with an investment for the calculation of
// the time weighted investment // the average investment
if ( if (
item.valueBeforeTransaction.gt(0) && item.valueBeforeTransaction.gt(0) &&
['BUY', 'SELL'].includes(item.type) ['BUY', 'SELL'].includes(item.type)
@ -289,18 +289,18 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
} }
// Sum up the total investment days since the start date to calculate // Sum up the total investment days since the start date to calculate
// the time weighted investment // the average investment
totalInvestmentDays += daysSinceLastActivity; totalInvestmentDays += daysSinceLastActivity;
sumOfTimeWeightedInvestments = sumOfTimeWeightedInvestments.add( sumOfWeightedInvestments = sumOfWeightedInvestments.add(
valueAtStartDate valueAtStartDate
.minus(investmentAtStartDate) .minus(investmentAtStartDate)
.plus(item.investmentBeforeTransaction) .plus(item.investmentBeforeTransaction)
.mul(daysSinceLastActivity) .mul(daysSinceLastActivity)
); );
sumOfTimeWeightedInvestmentsWithCurrencyEffect = sumOfWeightedInvestmentsWithCurrencyEffect =
sumOfTimeWeightedInvestmentsWithCurrencyEffect.add( sumOfWeightedInvestmentsWithCurrencyEffect.add(
valueAtStartDateWithCurrencyEffect valueAtStartDateWithCurrencyEffect
.minus(investmentAtStartDateWithCurrencyEffect) .minus(investmentAtStartDateWithCurrencyEffect)
.plus(item.investmentBeforeTransactionWithCurrencyEffect) .plus(item.investmentBeforeTransactionWithCurrencyEffect)
@ -309,17 +309,17 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
} }
// If duration is effectively zero (first day), use the actual investment as the base. // If duration is effectively zero (first day), use the actual investment as the base.
// Otherwise, use the calculated time-weighted average. // Otherwise, use the calculated average investment.
timeWeightedInvestmentValues[item.date] = averageInvestmentValues[item.date] =
totalInvestmentDays > Number.EPSILON totalInvestmentDays > Number.EPSILON
? sumOfTimeWeightedInvestments.div(totalInvestmentDays) ? sumOfWeightedInvestments.div(totalInvestmentDays)
: item.investment.gt(0) : item.investment.gt(0)
? item.investment ? item.investment
: new Big(0); : new Big(0);
timeWeightedInvestmentValuesWithCurrencyEffect[item.date] = averageInvestmentValuesWithCurrencyEffect[item.date] =
totalInvestmentDays > Number.EPSILON totalInvestmentDays > Number.EPSILON
? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div( ? sumOfWeightedInvestmentsWithCurrencyEffect.div(
totalInvestmentDays totalInvestmentDays
) )
: item.investmentWithCurrencyEffect.gt(0) : item.investmentWithCurrencyEffect.gt(0)
@ -363,31 +363,25 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
.minus(grossPerformanceAtStartDate) .minus(grossPerformanceAtStartDate)
.minus(fees.minus(feesAtStartDate)); .minus(fees.minus(feesAtStartDate));
const timeWeightedAverageInvestmentBetweenStartAndEndDate = const averageInvestmentBetweenStartAndEndDate =
totalInvestmentDays > 0 totalInvestmentDays > 0
? sumOfTimeWeightedInvestments.div(totalInvestmentDays) ? sumOfWeightedInvestments.div(totalInvestmentDays)
: new Big(0); : new Big(0);
const timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect = const averageInvestmentBetweenStartAndEndDateWithCurrencyEffect =
totalInvestmentDays > 0 totalInvestmentDays > 0
? sumOfTimeWeightedInvestmentsWithCurrencyEffect.div( ? sumOfWeightedInvestmentsWithCurrencyEffect.div(totalInvestmentDays)
totalInvestmentDays
)
: new Big(0); : new Big(0);
const grossPerformancePercentage = const grossPerformancePercentage =
timeWeightedAverageInvestmentBetweenStartAndEndDate.gt(0) averageInvestmentBetweenStartAndEndDate.gt(0)
? totalGrossPerformance.div( ? totalGrossPerformance.div(averageInvestmentBetweenStartAndEndDate)
timeWeightedAverageInvestmentBetweenStartAndEndDate
)
: new Big(0); : new Big(0);
const grossPerformancePercentageWithCurrencyEffect = const grossPerformancePercentageWithCurrencyEffect =
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect.gt( averageInvestmentBetweenStartAndEndDateWithCurrencyEffect.gt(0)
0
)
? totalGrossPerformanceWithCurrencyEffect.div( ? totalGrossPerformanceWithCurrencyEffect.div(
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect averageInvestmentBetweenStartAndEndDateWithCurrencyEffect
) )
: new Big(0); : new Big(0);
@ -401,12 +395,11 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
.div(totalQuantity) .div(totalQuantity)
: new Big(0); : new Big(0);
const netPerformancePercentage = const netPerformancePercentage = averageInvestmentBetweenStartAndEndDate.gt(
timeWeightedAverageInvestmentBetweenStartAndEndDate.gt(0) 0
? totalNetPerformance.div( )
timeWeightedAverageInvestmentBetweenStartAndEndDate ? totalNetPerformance.div(averageInvestmentBetweenStartAndEndDate)
) : new Big(0);
: new Big(0);
const netPerformancePercentageWithCurrencyEffectMap: { const netPerformancePercentageWithCurrencyEffectMap: {
[key: DateRange]: Big; [key: DateRange]: Big;
@ -512,10 +505,10 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
Total investment with currency effect: ${totalInvestmentWithCurrencyEffect.toFixed( Total investment with currency effect: ${totalInvestmentWithCurrencyEffect.toFixed(
2 2
)} )}
Time weighted investment: ${timeWeightedAverageInvestmentBetweenStartAndEndDate.toFixed( Average investment: ${averageInvestmentBetweenStartAndEndDate.toFixed(
2 2
)} )}
Time weighted investment with currency effect: ${timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect.toFixed( Average investment with currency effect: ${averageInvestmentBetweenStartAndEndDateWithCurrencyEffect.toFixed(
2 2
)} )}
Total dividend: ${totalDividend.toFixed(2)} Total dividend: ${totalDividend.toFixed(2)}
@ -541,6 +534,8 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
} }
return { return {
averageInvestmentValues,
averageInvestmentValuesWithCurrencyEffect,
currentValues, currentValues,
currentValuesWithCurrencyEffect, currentValuesWithCurrencyEffect,
grossPerformancePercentage, grossPerformancePercentage,
@ -553,23 +548,20 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator {
netPerformanceValues, netPerformanceValues,
netPerformanceValuesWithCurrencyEffect, netPerformanceValuesWithCurrencyEffect,
netPerformanceWithCurrencyEffectMap, netPerformanceWithCurrencyEffectMap,
timeWeightedInvestmentValues,
timeWeightedInvestmentValuesWithCurrencyEffect,
totalDividend, totalDividend,
totalDividendInBaseCurrency, totalDividendInBaseCurrency,
totalInterestInBaseCurrency, totalInterestInBaseCurrency,
totalInvestment, totalInvestment,
totalInvestmentWithCurrencyEffect, totalInvestmentWithCurrencyEffect,
totalLiabilitiesInBaseCurrency, totalLiabilitiesInBaseCurrency,
averageInvestment: averageInvestmentBetweenStartAndEndDate,
averageInvestmentWithCurrencyEffect:
averageInvestmentBetweenStartAndEndDateWithCurrencyEffect,
grossPerformance: totalGrossPerformance, grossPerformance: totalGrossPerformance,
grossPerformanceWithCurrencyEffect: grossPerformanceWithCurrencyEffect:
totalGrossPerformanceWithCurrencyEffect, totalGrossPerformanceWithCurrencyEffect,
hasErrors: totalQuantity.gt(0) && (!initialValue || !unitPriceAtEndDate), hasErrors: totalQuantity.gt(0) && (!initialValue || !unitPriceAtEndDate),
netPerformance: totalNetPerformance, netPerformance: totalNetPerformance
timeWeightedInvestment:
timeWeightedAverageInvestmentBetweenStartAndEndDate,
timeWeightedInvestmentWithCurrencyEffect:
timeWeightedAverageInvestmentBetweenStartAndEndDateWithCurrencyEffect
}; };
} }

16
apps/api/src/app/portfolio/interfaces/holding-performance.interface.ts

@ -3,6 +3,14 @@ import { DateRange } from '@ghostfolio/common/types';
import { Big } from 'big.js'; import { Big } from 'big.js';
export interface HoldingPerformance { export interface HoldingPerformance {
averageInvestment: Big;
averageInvestmentValues: {
[date: string]: Big;
};
averageInvestmentValuesWithCurrencyEffect: {
[date: string]: Big;
};
averageInvestmentWithCurrencyEffect: Big;
currentValues: { currentValues: {
[date: string]: Big; [date: string]: Big;
}; };
@ -31,14 +39,6 @@ export interface HoldingPerformance {
}; };
netPerformanceValuesWithCurrencyEffect: { [date: string]: Big }; netPerformanceValuesWithCurrencyEffect: { [date: string]: Big };
netPerformanceWithCurrencyEffectMap: { [key: DateRange]: Big }; netPerformanceWithCurrencyEffectMap: { [key: DateRange]: Big };
timeWeightedInvestment: Big;
timeWeightedInvestmentValues: {
[date: string]: Big;
};
timeWeightedInvestmentValuesWithCurrencyEffect: {
[date: string]: Big;
};
timeWeightedInvestmentWithCurrencyEffect: Big;
totalDividend: Big; totalDividend: Big;
totalDividendInBaseCurrency: Big; totalDividendInBaseCurrency: Big;
totalInterestInBaseCurrency: Big; totalInterestInBaseCurrency: Big;

4
apps/api/src/app/portfolio/portfolio.service.spec.ts

@ -406,6 +406,8 @@ describe('PortfolioService', () => {
const usdPosition = { const usdPosition = {
activitiesCount: 1, activitiesCount: 1,
averageInvestment: new Big(0),
averageInvestmentWithCurrencyEffect: new Big(0),
averagePrice: new Big(1), averagePrice: new Big(1),
currency: 'USD', currency: 'USD',
dataSource: DataSource.YAHOO, dataSource: DataSource.YAHOO,
@ -429,8 +431,6 @@ describe('PortfolioService', () => {
quantity: new Big(quantity), quantity: new Big(quantity),
symbol: 'USD', symbol: 'USD',
tags: [], tags: [],
timeWeightedInvestment: new Big(0),
timeWeightedInvestmentWithCurrencyEffect: new Big(0),
valueInBaseCurrency: new Big(1820) valueInBaseCurrency: new Big(1820)
}; };

14
apps/api/src/app/portfolio/portfolio.service.ts

@ -984,6 +984,8 @@ export class PortfolioService {
const { const {
activitiesCount, activitiesCount,
averageInvestment,
averageInvestmentWithCurrencyEffect,
averagePrice, averagePrice,
currency, currency,
dateOfFirstActivity, dateOfFirstActivity,
@ -1000,9 +1002,7 @@ export class PortfolioService {
netPerformancePercentageWithCurrencyEffectMap, netPerformancePercentageWithCurrencyEffectMap,
netPerformanceWithCurrencyEffectMap, netPerformanceWithCurrencyEffectMap,
quantity, quantity,
tags, tags
timeWeightedInvestment,
timeWeightedInvestmentWithCurrencyEffect
} = holding; } = holding;
const activitiesOfHolding = activities.filter((activity) => { const activitiesOfHolding = activities.filter((activity) => {
@ -1017,9 +1017,9 @@ export class PortfolioService {
new Date(), new Date(),
parseDate(dateOfFirstActivity) parseDate(dateOfFirstActivity)
), ),
netPerformancePercentage: timeWeightedInvestment.eq(0) netPerformancePercentage: averageInvestment.eq(0)
? new Big(0) ? new Big(0)
: dividendInBaseCurrency.div(timeWeightedInvestment) : dividendInBaseCurrency.div(averageInvestment)
}); });
const dividendYieldPercentWithCurrencyEffect = const dividendYieldPercentWithCurrencyEffect =
@ -1028,9 +1028,9 @@ export class PortfolioService {
new Date(), new Date(),
parseDate(dateOfFirstActivity) parseDate(dateOfFirstActivity)
), ),
netPerformancePercentage: timeWeightedInvestmentWithCurrencyEffect.eq(0) netPerformancePercentage: averageInvestmentWithCurrencyEffect.eq(0)
? new Big(0) ? new Big(0)
: dividendInBaseCurrency.div(timeWeightedInvestmentWithCurrencyEffect) : dividendInBaseCurrency.div(averageInvestmentWithCurrencyEffect)
}); });
const historicalData = await this.dataProviderService.getHistorical( const historicalData = await this.dataProviderService.getHistorical(

43
libs/common/src/lib/models/portfolio-snapshot-holding.ts

@ -6,11 +6,44 @@ import { DateRange } from '@ghostfolio/common/types';
import { DataSource, Tag } from '@prisma/client'; import { DataSource, Tag } from '@prisma/client';
import { Big } from 'big.js'; import { Big } from 'big.js';
import { Transform, Type } from 'class-transformer'; import { Expose, Transform, Type } from 'class-transformer';
/**
* @deprecated Backward compatibility to read the portfolio snapshots which
* have been cached with the former name of the property
*
* TODO: Remove the fallback with the next release, together with the
* `@Expose()` decorators of `averageInvestment` and
* `averageInvestmentWithCurrencyEffect`
*/
function transformToBigWithFallback(formerKey: string) {
return ({ obj, value }: { obj: Record<string, string>; value: string }) => {
const valueOrFallback = value ?? obj[formerKey];
return valueOrFallback === undefined
? undefined
: transformToBig({ value: valueOrFallback });
};
}
export class PortfolioSnapshotHolding { export class PortfolioSnapshotHolding {
activitiesCount: number; activitiesCount: number;
@Expose()
@Transform(transformToBigWithFallback('timeWeightedInvestment'), {
toClassOnly: true
})
@Type(() => Big)
averageInvestment: Big;
@Expose()
@Transform(
transformToBigWithFallback('timeWeightedInvestmentWithCurrencyEffect'),
{ toClassOnly: true }
)
@Type(() => Big)
averageInvestmentWithCurrencyEffect: Big;
@Transform(transformToBig, { toClassOnly: true }) @Transform(transformToBig, { toClassOnly: true })
@Type(() => Big) @Type(() => Big)
averagePrice: Big; averagePrice: Big;
@ -83,14 +116,6 @@ export class PortfolioSnapshotHolding {
symbol: string; symbol: string;
tags?: Tag[]; tags?: Tag[];
@Transform(transformToBig, { toClassOnly: true })
@Type(() => Big)
timeWeightedInvestment: Big;
@Transform(transformToBig, { toClassOnly: true })
@Type(() => Big)
timeWeightedInvestmentWithCurrencyEffect: Big;
@Transform(transformToBig, { toClassOnly: true }) @Transform(transformToBig, { toClassOnly: true })
@Type(() => Big) @Type(() => Big)
valueInBaseCurrency: Big; valueInBaseCurrency: Big;

Loading…
Cancel
Save