Browse Source

Merge branch 'main' into feature/upgrade-ionicons-to-version-7.4.0

pull/3356/head
Thomas Kaul 1 year ago
committed by GitHub
parent
commit
170cefe0da
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 8
      apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts
  3. 20
      apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
  4. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts
  5. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts
  6. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts
  7. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts
  8. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts
  9. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts
  10. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts
  11. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts
  12. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts
  13. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts
  14. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
  15. 1
      apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
  16. 23
      apps/api/src/app/portfolio/portfolio.service.ts
  17. 2
      apps/api/src/app/redis-cache/redis-cache.service.ts
  18. 4
      apps/api/src/events/portfolio-changed.listener.ts

2
CHANGELOG.md

@ -16,11 +16,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed ### Changed
- Skipped the caching in the portfolio calculator if there are active filters (experimental)
- Upgraded `ionicons` from version `7.3.0` to `7.4.0` - Upgraded `ionicons` from version `7.3.0` to `7.4.0`
### Fixed ### Fixed
- Fixed an issue in the calculation of the portfolio summary caused by future liabilities - Fixed an issue in the calculation of the portfolio summary caused by future liabilities
- Fixed a division by zero error in the dividend yield calculation (experimental)
## 2.77.1 - 2024-04-27 ## 2.77.1 - 2024-04-27

8
apps/api/src/app/portfolio/calculator/portfolio-calculator.factory.ts

@ -32,6 +32,7 @@ export class PortfolioCalculatorFactory {
calculationType, calculationType,
currency, currency,
dateRange = 'max', dateRange = 'max',
hasFilters,
isExperimentalFeatures = false, isExperimentalFeatures = false,
userId userId
}: { }: {
@ -40,9 +41,12 @@ export class PortfolioCalculatorFactory {
calculationType: PerformanceCalculationType; calculationType: PerformanceCalculationType;
currency: string; currency: string;
dateRange?: DateRange; dateRange?: DateRange;
hasFilters: boolean;
isExperimentalFeatures?: boolean; isExperimentalFeatures?: boolean;
userId: string; userId: string;
}): PortfolioCalculator { }): PortfolioCalculator {
const useCache = !hasFilters && isExperimentalFeatures;
switch (calculationType) { switch (calculationType) {
case PerformanceCalculationType.MWR: case PerformanceCalculationType.MWR:
return new MWRPortfolioCalculator({ return new MWRPortfolioCalculator({
@ -50,7 +54,7 @@ export class PortfolioCalculatorFactory {
activities, activities,
currency, currency,
dateRange, dateRange,
isExperimentalFeatures, useCache,
userId, userId,
configurationService: this.configurationService, configurationService: this.configurationService,
currentRateService: this.currentRateService, currentRateService: this.currentRateService,
@ -64,7 +68,7 @@ export class PortfolioCalculatorFactory {
currency, currency,
currentRateService: this.currentRateService, currentRateService: this.currentRateService,
dateRange, dateRange,
isExperimentalFeatures, useCache,
userId, userId,
configurationService: this.configurationService, configurationService: this.configurationService,
exchangeRateDataService: this.exchangeRateDataService, exchangeRateDataService: this.exchangeRateDataService,

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

@ -56,14 +56,15 @@ export abstract class PortfolioCalculator {
private currency: string; private currency: string;
private currentRateService: CurrentRateService; private currentRateService: CurrentRateService;
private dataProviderInfos: DataProviderInfo[]; private dataProviderInfos: DataProviderInfo[];
private dateRange: DateRange;
private endDate: Date; private endDate: Date;
private exchangeRateDataService: ExchangeRateDataService; private exchangeRateDataService: ExchangeRateDataService;
private isExperimentalFeatures: boolean;
private redisCacheService: RedisCacheService; private redisCacheService: RedisCacheService;
private snapshot: PortfolioSnapshot; private snapshot: PortfolioSnapshot;
private snapshotPromise: Promise<void>; private snapshotPromise: Promise<void>;
private startDate: Date; private startDate: Date;
private transactionPoints: TransactionPoint[]; private transactionPoints: TransactionPoint[];
private useCache: boolean;
private userId: string; private userId: string;
public constructor({ public constructor({
@ -74,8 +75,8 @@ export abstract class PortfolioCalculator {
currentRateService, currentRateService,
dateRange, dateRange,
exchangeRateDataService, exchangeRateDataService,
isExperimentalFeatures,
redisCacheService, redisCacheService,
useCache,
userId userId
}: { }: {
accountBalanceItems: HistoricalDataItem[]; accountBalanceItems: HistoricalDataItem[];
@ -85,16 +86,16 @@ export abstract class PortfolioCalculator {
currentRateService: CurrentRateService; currentRateService: CurrentRateService;
dateRange: DateRange; dateRange: DateRange;
exchangeRateDataService: ExchangeRateDataService; exchangeRateDataService: ExchangeRateDataService;
isExperimentalFeatures: boolean;
redisCacheService: RedisCacheService; redisCacheService: RedisCacheService;
useCache: boolean;
userId: string; userId: string;
}) { }) {
this.accountBalanceItems = accountBalanceItems; this.accountBalanceItems = accountBalanceItems;
this.configurationService = configurationService; this.configurationService = configurationService;
this.currency = currency; this.currency = currency;
this.currentRateService = currentRateService; this.currentRateService = currentRateService;
this.dateRange = dateRange;
this.exchangeRateDataService = exchangeRateDataService; this.exchangeRateDataService = exchangeRateDataService;
this.isExperimentalFeatures = isExperimentalFeatures;
this.activities = activities this.activities = activities
.map( .map(
@ -129,6 +130,7 @@ export abstract class PortfolioCalculator {
}); });
this.redisCacheService = redisCacheService; this.redisCacheService = redisCacheService;
this.useCache = useCache;
this.userId = userId; this.userId = userId;
const { endDate, startDate } = getInterval(dateRange); const { endDate, startDate } = getInterval(dateRange);
@ -1047,11 +1049,13 @@ export abstract class PortfolioCalculator {
} }
private async initialize() { private async initialize() {
if (this.isExperimentalFeatures) { if (this.useCache) {
const startTimeTotal = performance.now(); const startTimeTotal = performance.now();
const cachedSnapshot = await this.redisCacheService.get( const cachedSnapshot = await this.redisCacheService.get(
this.redisCacheService.getPortfolioSnapshotKey(this.userId) this.redisCacheService.getPortfolioSnapshotKey({
userId: this.userId
})
); );
if (cachedSnapshot) { if (cachedSnapshot) {
@ -1074,7 +1078,9 @@ export abstract class PortfolioCalculator {
); );
this.redisCacheService.set( this.redisCacheService.set(
this.redisCacheService.getPortfolioSnapshotKey(this.userId), this.redisCacheService.getPortfolioSnapshotKey({
userId: this.userId
}),
JSON.stringify(this.snapshot), JSON.stringify(this.snapshot),
this.configurationService.get('CACHE_QUOTES_TTL') this.configurationService.get('CACHE_QUOTES_TTL')
); );

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

@ -123,6 +123,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', currency: 'CHF',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy-and-sell.spec.ts

@ -108,6 +108,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', currency: 'CHF',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-baln-buy.spec.ts

@ -93,6 +93,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', currency: 'CHF',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

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

@ -121,6 +121,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', currency: 'CHF',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-fee.spec.ts

@ -93,6 +93,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'USD', currency: 'USD',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-googl-buy.spec.ts

@ -106,6 +106,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', currency: 'CHF',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-item.spec.ts

@ -93,6 +93,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'USD', currency: 'USD',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-liability.spec.ts

@ -93,6 +93,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'USD', currency: 'USD',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-msft-buy-with-dividend.spec.ts

@ -121,6 +121,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'USD', currency: 'USD',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-no-orders.spec.ts

@ -71,6 +71,7 @@ describe('PortfolioCalculator', () => {
activities: [], activities: [],
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', currency: 'CHF',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

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

@ -108,6 +108,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', currency: 'CHF',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

1
apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts

@ -108,6 +108,7 @@ describe('PortfolioCalculator', () => {
activities, activities,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: 'CHF', currency: 'CHF',
hasFilters: false,
userId: userDummyData.id userId: userDummyData.id
}); });

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

@ -277,9 +277,11 @@ export class PortfolioService {
const portfolioCalculator = this.calculatorFactory.createCalculator({ const portfolioCalculator = this.calculatorFactory.createCalculator({
activities, activities,
dateRange,
userId, userId,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: this.request.user.Settings.settings.baseCurrency, currency: this.request.user.Settings.settings.baseCurrency,
hasFilters: filters?.length > 0,
isExperimentalFeatures: isExperimentalFeatures:
this.request.user.Settings.settings.isExperimentalFeatures this.request.user.Settings.settings.isExperimentalFeatures
}); });
@ -358,6 +360,7 @@ export class PortfolioService {
userId, userId,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: userCurrency, currency: userCurrency,
hasFilters: filters?.length > 0,
isExperimentalFeatures: isExperimentalFeatures:
this.request.user?.Settings.settings.isExperimentalFeatures this.request.user?.Settings.settings.isExperimentalFeatures
}); });
@ -660,6 +663,7 @@ export class PortfolioService {
}), }),
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: userCurrency, currency: userCurrency,
hasFilters: true,
isExperimentalFeatures: isExperimentalFeatures:
this.request.user.Settings.settings.isExperimentalFeatures this.request.user.Settings.settings.isExperimentalFeatures
}); });
@ -700,17 +704,19 @@ export class PortfolioService {
const dividendYieldPercent = this.getAnnualizedPerformancePercent({ const dividendYieldPercent = this.getAnnualizedPerformancePercent({
daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)), daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)),
netPerformancePercent: dividendInBaseCurrency.div( netPerformancePercent: timeWeightedInvestment.eq(0)
timeWeightedInvestment ? new Big(0)
) : dividendInBaseCurrency.div(timeWeightedInvestment)
}); });
const dividendYieldPercentWithCurrencyEffect = const dividendYieldPercentWithCurrencyEffect =
this.getAnnualizedPerformancePercent({ this.getAnnualizedPerformancePercent({
daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)), daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)),
netPerformancePercent: dividendInBaseCurrency.div( netPerformancePercent: timeWeightedInvestmentWithCurrencyEffect.eq(0)
timeWeightedInvestmentWithCurrencyEffect ? new Big(0)
) : dividendInBaseCurrency.div(
timeWeightedInvestmentWithCurrencyEffect
)
}); });
const historicalData = await this.dataProviderService.getHistorical( const historicalData = await this.dataProviderService.getHistorical(
@ -931,6 +937,7 @@ export class PortfolioService {
userId, userId,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: this.request.user.Settings.settings.baseCurrency, currency: this.request.user.Settings.settings.baseCurrency,
hasFilters: filters?.length > 0,
isExperimentalFeatures: isExperimentalFeatures:
this.request.user.Settings.settings.isExperimentalFeatures this.request.user.Settings.settings.isExperimentalFeatures
}); });
@ -1085,7 +1092,7 @@ export class PortfolioService {
) )
); );
const { endDate, startDate } = getInterval(dateRange); const { endDate } = getInterval(dateRange);
const { activities } = await this.orderService.getOrders({ const { activities } = await this.orderService.getOrders({
endDate, endDate,
@ -1123,6 +1130,7 @@ export class PortfolioService {
userId, userId,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: userCurrency, currency: userCurrency,
hasFilters: filters?.length > 0,
isExperimentalFeatures: isExperimentalFeatures:
this.request.user.Settings.settings.isExperimentalFeatures this.request.user.Settings.settings.isExperimentalFeatures
}); });
@ -1220,6 +1228,7 @@ export class PortfolioService {
userId, userId,
calculationType: PerformanceCalculationType.TWR, calculationType: PerformanceCalculationType.TWR,
currency: this.request.user.Settings.settings.baseCurrency, currency: this.request.user.Settings.settings.baseCurrency,
hasFilters: false,
isExperimentalFeatures: isExperimentalFeatures:
this.request.user.Settings.settings.isExperimentalFeatures this.request.user.Settings.settings.isExperimentalFeatures
}); });

2
apps/api/src/app/redis-cache/redis-cache.service.ts

@ -24,7 +24,7 @@ export class RedisCacheService {
return this.cache.get(key); return this.cache.get(key);
} }
public getPortfolioSnapshotKey(userId: string) { public getPortfolioSnapshotKey({ userId }: { userId: string }) {
return `portfolio-snapshot-${userId}`; return `portfolio-snapshot-${userId}`;
} }

4
apps/api/src/events/portfolio-changed.listener.ts

@ -17,7 +17,9 @@ export class PortfolioChangedListener {
); );
this.redisCacheService.remove( this.redisCacheService.remove(
this.redisCacheService.getPortfolioSnapshotKey(event.getUserId()) this.redisCacheService.getPortfolioSnapshotKey({
userId: event.getUserId()
})
); );
} }
} }

Loading…
Cancel
Save