From 73cd2f9cb7192564f8ff2bbd60b1f2737f614090 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 10 Oct 2024 20:27:33 +0200
Subject: [PATCH 01/34] Bugfix/fix exception in portfolio details endpoint
(#3896)
* Fix exception caused by markets and marketsAdvanced
* Update changelog
---
CHANGELOG.md | 4 ++++
apps/api/src/app/endpoints/public/public.controller.ts | 2 +-
apps/api/src/app/portfolio/portfolio.controller.ts | 4 ++--
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 752fc2397..58dd3fdbc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Moved the tags from the info to the user service
- Switched the `prefer-const` rule from `warn` to `error` in the `eslint` configuration
+### Fixed
+
+- Fixed an exception in the portfolio details endpoint caused by a calculation of the allocations by market
+
## 2.113.0 - 2024-10-06
### Added
diff --git a/apps/api/src/app/endpoints/public/public.controller.ts b/apps/api/src/app/endpoints/public/public.controller.ts
index 9399f97bf..7488e4201 100644
--- a/apps/api/src/app/endpoints/public/public.controller.ts
+++ b/apps/api/src/app/endpoints/public/public.controller.ts
@@ -76,7 +76,7 @@ export class PublicController {
})
]);
- Object.values(markets).forEach((market) => {
+ Object.values(markets ?? {}).forEach((market) => {
delete market.valueInBaseCurrency;
});
diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts
index ff0c31060..326dda151 100644
--- a/apps/api/src/app/portfolio/portfolio.controller.ts
+++ b/apps/api/src/app/portfolio/portfolio.controller.ts
@@ -172,10 +172,10 @@ export class PortfolioController {
}) ||
isRestrictedView(this.request.user)
) {
- Object.values(markets).forEach((market) => {
+ Object.values(markets ?? {}).forEach((market) => {
delete market.valueInBaseCurrency;
});
- Object.values(marketsAdvanced).forEach((market) => {
+ Object.values(marketsAdvanced ?? {}).forEach((market) => {
delete market.valueInBaseCurrency;
});
From 7252a54ae059889d5fbb3adb4d744fff9fa6c859 Mon Sep 17 00:00:00 2001
From: Uday R <82779467+uday-rana@users.noreply.github.com>
Date: Thu, 10 Oct 2024 15:06:17 -0400
Subject: [PATCH 02/34] Feature/Set up tooltip in treemap chart component
(#3897)
* Set up tooltip in treemap chart component
* Update changelog
---
CHANGELOG.md | 1 +
.../home-holdings/home-holdings.html | 3 ++
.../treemap-chart/treemap-chart.component.ts | 48 ++++++++++++++++---
3 files changed, 46 insertions(+), 6 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58dd3fdbc..0d6ba5d26 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
+- Added a tooltip to the chart of the holdings tab on the home page (experimental)
- Extended the _Public API_ with the health check endpoint (experimental)
### Changed
diff --git a/apps/client/src/app/components/home-holdings/home-holdings.html b/apps/client/src/app/components/home-holdings/home-holdings.html
index 01afe31a2..f1c4e7e88 100644
--- a/apps/client/src/app/components/home-holdings/home-holdings.html
+++ b/apps/client/src/app/components/home-holdings/home-holdings.html
@@ -38,8 +38,11 @@
}
diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
index 8915707fa..b278180ea 100644
--- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
+++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
@@ -2,11 +2,13 @@ import {
getAnnualizedPerformancePercent,
getIntervalFromDateRange
} from '@ghostfolio/common/calculation-helper';
+import { getTooltipOptions } from '@ghostfolio/common/chart-helper';
+import { getLocale } from '@ghostfolio/common/helper';
import {
AssetProfileIdentifier,
PortfolioPosition
} from '@ghostfolio/common/interfaces';
-import { DateRange } from '@ghostfolio/common/types';
+import { ColorScheme, DateRange } from '@ghostfolio/common/types';
import { CommonModule } from '@angular/common';
import {
@@ -25,7 +27,7 @@ import { DataSource } from '@prisma/client';
import { Big } from 'big.js';
import { ChartConfiguration } from 'chart.js';
import { LinearScale } from 'chart.js';
-import { Chart } from 'chart.js';
+import { Chart, Tooltip } from 'chart.js';
import { TreemapController, TreemapElement } from 'chartjs-chart-treemap';
import { differenceInDays, max } from 'date-fns';
import { orderBy } from 'lodash';
@@ -44,9 +46,12 @@ const { gray, green, red } = require('open-color');
export class GfTreemapChartComponent
implements AfterViewInit, OnChanges, OnDestroy
{
+ @Input() baseCurrency: string;
+ @Input() colorScheme: ColorScheme;
@Input() cursor: string;
@Input() dateRange: DateRange;
@Input() holdings: PortfolioPosition[];
+ @Input() locale = getLocale();
@Output() treemapChartClicked = new EventEmitter();
@@ -58,7 +63,7 @@ export class GfTreemapChartComponent
public isLoading = true;
public constructor() {
- Chart.register(LinearScale, TreemapController, TreemapElement);
+ Chart.register(LinearScale, Tooltip, TreemapController, TreemapElement);
}
public ngAfterViewInit() {
@@ -168,6 +173,9 @@ export class GfTreemapChartComponent
if (this.chartCanvas) {
if (this.chart) {
this.chart.data = data;
+ this.chart.options.plugins.tooltip = (
+ this.getTooltipPluginConfiguration()
+ );
this.chart.update();
} else {
this.chart = new Chart(this.chartCanvas.nativeElement, {
@@ -199,9 +207,7 @@ export class GfTreemapChartComponent
}
},
plugins: {
- tooltip: {
- enabled: false
- }
+ tooltip: this.getTooltipPluginConfiguration()
}
},
type: 'treemap'
@@ -211,4 +217,34 @@ export class GfTreemapChartComponent
this.isLoading = false;
}
+
+ private getTooltipPluginConfiguration() {
+ return {
+ ...getTooltipOptions({
+ colorScheme: this.colorScheme,
+ currency: this.baseCurrency,
+ locale: this.locale
+ }),
+ callbacks: {
+ label: (context) => {
+ if (context.raw._data.valueInBaseCurrency !== null) {
+ const value = context.raw._data.valueInBaseCurrency;
+ return `${value.toLocaleString(this.locale, {
+ maximumFractionDigits: 2,
+ minimumFractionDigits: 2
+ })} ${this.baseCurrency}`;
+ } else {
+ const percentage =
+ context.raw._data.allocationInPercentage * 100;
+ return `${percentage.toFixed(2)}%`;
+ }
+ },
+ title: () => {
+ return '';
+ }
+ },
+ xAlign: 'center',
+ yAlign: 'center'
+ };
+ }
}
From f5c0d803a06ac36886657491fbf0fd9afb480425 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 10 Oct 2024 21:09:58 +0200
Subject: [PATCH 03/34] Release 2.114.0 (#3905)
---
CHANGELOG.md | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0d6ba5d26..e66630572 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## Unreleased
+## 2.114.0 - 2024-10-10
### Added
diff --git a/package.json b/package.json
index 894b0d192..e283d6a23 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ghostfolio",
- "version": "2.113.0",
+ "version": "2.114.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio",
From 5f4cbe3af72a1cd3422be09f3ee07a0161085bfc Mon Sep 17 00:00:00 2001
From: Madhab Chandra Sahoo
<30400985+madhab-chandra-sahoo@users.noreply.github.com>
Date: Fri, 11 Oct 2024 23:29:08 +0530
Subject: [PATCH 04/34] Bugfix/considered language of user settings on login
with Security Token (#3828)
* Consider language of user settings on login with Security Token
* Update changelog
---
CHANGELOG.md | 6 ++++++
.../src/app/components/header/header.component.ts | 13 ++++++++++++-
2 files changed, 18 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e66630572..d334d6b08 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Unreleased
+
+### Fixed
+
+- Considered the language of the user settings on login with _Security Token_
+
## 2.114.0 - 2024-10-10
### Added
diff --git a/apps/client/src/app/components/header/header.component.ts b/apps/client/src/app/components/header/header.component.ts
index be90fbc8e..33069aa23 100644
--- a/apps/client/src/app/components/header/header.component.ts
+++ b/apps/client/src/app/components/header/header.component.ts
@@ -261,7 +261,18 @@ export class HeaderComponent implements OnChanges {
this.settingsStorageService.getSetting(KEY_STAY_SIGNED_IN) === 'true'
);
- this.router.navigate(['/']);
+ this.userService
+ .get()
+ .pipe(takeUntil(this.unsubscribeSubject))
+ .subscribe((user) => {
+ const userLanguage = user?.settings?.language;
+
+ if (userLanguage && document.documentElement.lang !== userLanguage) {
+ window.location.href = `../${userLanguage}`;
+ } else {
+ this.router.navigate(['/']);
+ }
+ });
}
public ngOnDestroy() {
From d158d0c326567600dbddfed0c90b1d18de33a28c Mon Sep 17 00:00:00 2001
From: Uday R <82779467+uday-rana@users.noreply.github.com>
Date: Fri, 11 Oct 2024 14:13:40 -0400
Subject: [PATCH 05/34] Feature/Extend tooltip in treemap chart component by
name (#3907)
* Extend tooltip in treemap chart component by name
* Update changelog
---
CHANGELOG.md | 4 ++++
.../treemap-chart/treemap-chart.component.ts | 18 +++++++++++++-----
2 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d334d6b08..388fd9772 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Added
+
+- Added the name to the tooltip of the chart of the holdings tab on the home page (experimental)
+
### Fixed
- Considered the language of the user settings on login with _Security Token_
diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
index b278180ea..0e694f6dc 100644
--- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
+++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
@@ -227,16 +227,24 @@ export class GfTreemapChartComponent
}),
callbacks: {
label: (context) => {
+ const name = context.raw._data.name;
+ const symbol = context.raw._data.symbol;
+
if (context.raw._data.valueInBaseCurrency !== null) {
const value = context.raw._data.valueInBaseCurrency;
- return `${value.toLocaleString(this.locale, {
- maximumFractionDigits: 2,
- minimumFractionDigits: 2
- })} ${this.baseCurrency}`;
+
+ return [
+ `${name ?? symbol}`,
+ `${value.toLocaleString(this.locale, {
+ maximumFractionDigits: 2,
+ minimumFractionDigits: 2
+ })} ${this.baseCurrency}`
+ ];
} else {
const percentage =
context.raw._data.allocationInPercentage * 100;
- return `${percentage.toFixed(2)}%`;
+
+ return [`${name ?? symbol}`, `${percentage.toFixed(2)}%`];
}
},
title: () => {
From 32452a5d22f7e02425958a3c14e7f20e6ac88432 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 11 Oct 2024 20:42:48 +0200
Subject: [PATCH 06/34] Refactoring
---
.../portfolio-calculator-test-utils.ts | 6 +++
...io-calculator-dynamic-buy-and-sell.spec.ts | 51 ++++++++++---------
2 files changed, 32 insertions(+), 25 deletions(-)
diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts
index d458be708..217ec499b 100644
--- a/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts
+++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts
@@ -1,3 +1,5 @@
+import { readFileSync } from 'fs';
+
export const activityDummyData = {
accountId: undefined,
accountUserId: undefined,
@@ -29,3 +31,7 @@ export const symbolProfileDummyData = {
export const userDummyData = {
id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
};
+
+export function loadActivityExportFile(filePath: string) {
+ return JSON.parse(readFileSync(filePath, 'utf8')).activities;
+}
diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-dynamic-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-dynamic-buy-and-sell.spec.ts
index 529583fc0..1589cecaa 100644
--- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-dynamic-buy-and-sell.spec.ts
+++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-dynamic-buy-and-sell.spec.ts
@@ -1,5 +1,11 @@
+import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
-import { userDummyData } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
+import {
+ activityDummyData,
+ loadActivityExportFile,
+ symbolProfileDummyData,
+ userDummyData
+} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
import {
PerformanceCalculationType,
PortfolioCalculatorFactory
@@ -15,7 +21,6 @@ import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/po
import { parseDate } from '@ghostfolio/common/helper';
import { Big } from 'big.js';
-import { existsSync, readFileSync } from 'fs';
import { last } from 'lodash';
import { join } from 'path';
@@ -50,6 +55,8 @@ jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
});
describe('PortfolioCalculator', () => {
+ let activityDtos: CreateOrderDto[];
+
let configurationService: ConfigurationService;
let currentRateService: CurrentRateService;
let exchangeRateDataService: ExchangeRateDataService;
@@ -57,6 +64,15 @@ describe('PortfolioCalculator', () => {
let portfolioSnapshotService: PortfolioSnapshotService;
let redisCacheService: RedisCacheService;
+ beforeAll(() => {
+ activityDtos = loadActivityExportFile(
+ join(
+ __dirname,
+ '../../../../../../../test/import/ok-novn-buy-and-sell.json'
+ )
+ );
+ });
+
beforeEach(() => {
configurationService = new ConfigurationService();
@@ -82,40 +98,25 @@ describe('PortfolioCalculator', () => {
);
});
- //read from activities json
- let activities: any[];
-
- beforeAll(() => {
- const jsonFilePath = join(
- __dirname,
- '../../../../../../../test/import/ok-novn-buy-and-sell.json'
- );
-
- if (!existsSync(jsonFilePath))
- throw new Error('JSON file not found at: ' + jsonFilePath);
-
- const jsonData = readFileSync(jsonFilePath, 'utf8');
- activities = JSON.parse(jsonData).activities;
- });
-
describe('get current positions', () => {
it.only('with NOVN.SW buy and sell', async () => {
jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
- //map activity with json
- const mappedactivities: Activity[] = activities.map((activity) => ({
+ const activities: Activity[] = activityDtos.map((activity) => ({
+ ...activityDummyData,
...activity,
date: new Date(activity.date),
SymbolProfile: {
- currency: activity.currency || 'CHF',
- dataSource: activity.dataSource || 'YAHOO',
- name: activity.name || 'Default Name', // provide a default name if missing
- symbol: activity.symbol || 'UNKNOWN' // provide a default symbol if missing
+ ...symbolProfileDummyData,
+ currency: activity.currency,
+ dataSource: activity.dataSource,
+ name: 'Novartis AG',
+ symbol: activity.symbol
}
}));
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
- activities: mappedactivities,
+ activities,
calculationType: PerformanceCalculationType.TWR,
currency: 'CHF',
userId: userDummyData.id
From 77662336ce3d333d725574fb7f4a1f93bc6a100b Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 11 Oct 2024 20:43:28 +0200
Subject: [PATCH 07/34] Update changelog
---
CHANGELOG.md | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e66630572..b065ac696 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Unreleased
+
+### Changed
+
+- Improved the portfolio unit tests to work with exported activity files
+
## 2.114.0 - 2024-10-10
### Added
From 825c55fa4ff89077a6d2e450a5210226ad5db54c Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 11 Oct 2024 20:44:33 +0200
Subject: [PATCH 08/34] Refactoring
---
...io-calculator-dynamic-buy-and-sell.spec.ts | 253 ---------
...folio-calculator-novn-buy-and-sell.spec.ts | 512 +++++++++---------
2 files changed, 253 insertions(+), 512 deletions(-)
delete mode 100644 apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-dynamic-buy-and-sell.spec.ts
diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-dynamic-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-dynamic-buy-and-sell.spec.ts
deleted file mode 100644
index 1589cecaa..000000000
--- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-dynamic-buy-and-sell.spec.ts
+++ /dev/null
@@ -1,253 +0,0 @@
-import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
-import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
-import {
- activityDummyData,
- loadActivityExportFile,
- symbolProfileDummyData,
- userDummyData
-} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
-import {
- PerformanceCalculationType,
- PortfolioCalculatorFactory
-} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
-import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
-import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
-import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
-import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock';
-import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
-import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
-import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
-import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
-import { parseDate } from '@ghostfolio/common/helper';
-
-import { Big } from 'big.js';
-import { last } from 'lodash';
-import { join } from 'path';
-
-jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- CurrentRateService: jest.fn().mockImplementation(() => {
- return CurrentRateServiceMock;
- })
- };
-});
-
-jest.mock(
- '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service',
- () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- PortfolioSnapshotService: jest.fn().mockImplementation(() => {
- return PortfolioSnapshotServiceMock;
- })
- };
- }
-);
-
-jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- RedisCacheService: jest.fn().mockImplementation(() => {
- return RedisCacheServiceMock;
- })
- };
-});
-
-describe('PortfolioCalculator', () => {
- let activityDtos: CreateOrderDto[];
-
- let configurationService: ConfigurationService;
- let currentRateService: CurrentRateService;
- let exchangeRateDataService: ExchangeRateDataService;
- let portfolioCalculatorFactory: PortfolioCalculatorFactory;
- let portfolioSnapshotService: PortfolioSnapshotService;
- let redisCacheService: RedisCacheService;
-
- beforeAll(() => {
- activityDtos = loadActivityExportFile(
- join(
- __dirname,
- '../../../../../../../test/import/ok-novn-buy-and-sell.json'
- )
- );
- });
-
- beforeEach(() => {
- configurationService = new ConfigurationService();
-
- currentRateService = new CurrentRateService(null, null, null, null);
-
- exchangeRateDataService = new ExchangeRateDataService(
- null,
- null,
- null,
- null
- );
-
- portfolioSnapshotService = new PortfolioSnapshotService(null);
-
- redisCacheService = new RedisCacheService(null, null);
-
- portfolioCalculatorFactory = new PortfolioCalculatorFactory(
- configurationService,
- currentRateService,
- exchangeRateDataService,
- portfolioSnapshotService,
- redisCacheService
- );
- });
-
- describe('get current positions', () => {
- it.only('with NOVN.SW buy and sell', async () => {
- jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
-
- const activities: Activity[] = activityDtos.map((activity) => ({
- ...activityDummyData,
- ...activity,
- date: new Date(activity.date),
- SymbolProfile: {
- ...symbolProfileDummyData,
- currency: activity.currency,
- dataSource: activity.dataSource,
- name: 'Novartis AG',
- symbol: activity.symbol
- }
- }));
-
- const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
- activities,
- calculationType: PerformanceCalculationType.TWR,
- currency: 'CHF',
- userId: userDummyData.id
- });
-
- const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
-
- const investments = portfolioCalculator.getInvestments();
-
- const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({
- data: portfolioSnapshot.historicalData,
- groupBy: 'month'
- });
-
- expect(portfolioSnapshot.historicalData[0]).toEqual({
- date: '2022-03-06',
- investmentValueWithCurrencyEffect: 0,
- netPerformance: 0,
- netPerformanceInPercentage: 0,
- netPerformanceInPercentageWithCurrencyEffect: 0,
- netPerformanceWithCurrencyEffect: 0,
- netWorth: 0,
- totalAccountBalance: 0,
- totalInvestment: 0,
- totalInvestmentValueWithCurrencyEffect: 0,
- value: 0,
- valueWithCurrencyEffect: 0
- });
-
- expect(portfolioSnapshot.historicalData[1]).toEqual({
- date: '2022-03-07',
- investmentValueWithCurrencyEffect: 151.6,
- netPerformance: 0,
- netPerformanceInPercentage: 0,
- netPerformanceInPercentageWithCurrencyEffect: 0,
- netPerformanceWithCurrencyEffect: 0,
- netWorth: 151.6,
- totalAccountBalance: 0,
- totalInvestment: 151.6,
- totalInvestmentValueWithCurrencyEffect: 151.6,
- value: 151.6,
- valueWithCurrencyEffect: 151.6
- });
-
- expect(
- portfolioSnapshot.historicalData[
- portfolioSnapshot.historicalData.length - 1
- ]
- ).toEqual({
- date: '2022-04-11',
- investmentValueWithCurrencyEffect: 0,
- netPerformance: 19.86,
- netPerformanceInPercentage: 0.13100263852242744,
- netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744,
- netPerformanceWithCurrencyEffect: 19.86,
- netWorth: 0,
- totalAccountBalance: 0,
- totalInvestment: 0,
- totalInvestmentValueWithCurrencyEffect: 0,
- value: 0,
- valueWithCurrencyEffect: 0
- });
-
- expect(portfolioSnapshot).toMatchObject({
- currentValueInBaseCurrency: new Big('0'),
- errors: [],
- hasErrors: false,
- positions: [
- {
- averagePrice: new Big('0'),
- currency: 'CHF',
- dataSource: 'YAHOO',
- dividend: new Big('0'),
- dividendInBaseCurrency: new Big('0'),
- fee: new Big('0'),
- feeInBaseCurrency: new Big('0'),
- firstBuyDate: '2022-03-07',
- grossPerformance: new Big('19.86'),
- grossPerformancePercentage: new Big('0.13100263852242744063'),
- grossPerformancePercentageWithCurrencyEffect: new Big(
- '0.13100263852242744063'
- ),
- grossPerformanceWithCurrencyEffect: new Big('19.86'),
- investment: new Big('0'),
- investmentWithCurrencyEffect: new Big('0'),
- netPerformance: new Big('19.86'),
- netPerformancePercentage: new Big('0.13100263852242744063'),
- netPerformancePercentageWithCurrencyEffectMap: {
- max: new Big('0.13100263852242744063')
- },
- netPerformanceWithCurrencyEffectMap: {
- max: new Big('19.86')
- },
- marketPrice: 87.8,
- marketPriceInBaseCurrency: 87.8,
- quantity: new Big('0'),
- symbol: 'NOVN.SW',
- tags: [],
- timeWeightedInvestment: new Big('151.6'),
- timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'),
- transactionCount: 2,
- valueInBaseCurrency: new Big('0')
- }
- ],
- totalFeesWithCurrencyEffect: new Big('0'),
- totalInterestWithCurrencyEffect: new Big('0'),
- totalInvestment: new Big('0'),
- totalInvestmentWithCurrencyEffect: new Big('0'),
- totalLiabilitiesWithCurrencyEffect: new Big('0'),
- totalValuablesWithCurrencyEffect: new Big('0')
- });
-
- expect(last(portfolioSnapshot.historicalData)).toMatchObject(
- expect.objectContaining({
- netPerformance: 19.86,
- netPerformanceInPercentage: 0.13100263852242744063,
- netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063,
- netPerformanceWithCurrencyEffect: 19.86,
- totalInvestmentValueWithCurrencyEffect: 0
- })
- );
-
- expect(investments).toEqual([
- { date: '2022-03-07', investment: new Big('151.6') },
- { date: '2022-04-08', investment: new Big('0') }
- ]);
-
- expect(investmentsByMonth).toEqual([
- { date: '2022-03-01', investment: 151.6 },
- { date: '2022-04-01', investment: -151.6 }
- ]);
- });
- });
-});
diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
index db5aaf6bc..1589cecaa 100644
--- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
+++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
@@ -1,259 +1,253 @@
-import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
-import {
- activityDummyData,
- symbolProfileDummyData,
- userDummyData
-} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
-import {
- PerformanceCalculationType,
- PortfolioCalculatorFactory
-} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
-import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
-import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
-import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
-import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock';
-import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
-import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
-import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
-import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
-import { parseDate } from '@ghostfolio/common/helper';
-
-import { Big } from 'big.js';
-import { last } from 'lodash';
-
-jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- CurrentRateService: jest.fn().mockImplementation(() => {
- return CurrentRateServiceMock;
- })
- };
-});
-
-jest.mock(
- '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service',
- () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- PortfolioSnapshotService: jest.fn().mockImplementation(() => {
- return PortfolioSnapshotServiceMock;
- })
- };
- }
-);
-
-jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- RedisCacheService: jest.fn().mockImplementation(() => {
- return RedisCacheServiceMock;
- })
- };
-});
-
-describe('PortfolioCalculator', () => {
- let configurationService: ConfigurationService;
- let currentRateService: CurrentRateService;
- let exchangeRateDataService: ExchangeRateDataService;
- let portfolioCalculatorFactory: PortfolioCalculatorFactory;
- let portfolioSnapshotService: PortfolioSnapshotService;
- let redisCacheService: RedisCacheService;
-
- beforeEach(() => {
- configurationService = new ConfigurationService();
-
- currentRateService = new CurrentRateService(null, null, null, null);
-
- exchangeRateDataService = new ExchangeRateDataService(
- null,
- null,
- null,
- null
- );
-
- portfolioSnapshotService = new PortfolioSnapshotService(null);
-
- redisCacheService = new RedisCacheService(null, null);
-
- portfolioCalculatorFactory = new PortfolioCalculatorFactory(
- configurationService,
- currentRateService,
- exchangeRateDataService,
- portfolioSnapshotService,
- redisCacheService
- );
- });
-
- describe('get current positions', () => {
- it.only('with NOVN.SW buy and sell', async () => {
- jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
-
- const activities: Activity[] = [
- {
- ...activityDummyData,
- date: new Date('2022-03-07'),
- fee: 0,
- quantity: 2,
- SymbolProfile: {
- ...symbolProfileDummyData,
- currency: 'CHF',
- dataSource: 'YAHOO',
- name: 'Novartis AG',
- symbol: 'NOVN.SW'
- },
- type: 'BUY',
- unitPrice: 75.8
- },
- {
- ...activityDummyData,
- date: new Date('2022-04-08'),
- fee: 0,
- quantity: 2,
- SymbolProfile: {
- ...symbolProfileDummyData,
- currency: 'CHF',
- dataSource: 'YAHOO',
- name: 'Novartis AG',
- symbol: 'NOVN.SW'
- },
- type: 'SELL',
- unitPrice: 85.73
- }
- ];
-
- const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
- activities,
- calculationType: PerformanceCalculationType.TWR,
- currency: 'CHF',
- userId: userDummyData.id
- });
-
- const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
-
- const investments = portfolioCalculator.getInvestments();
-
- const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({
- data: portfolioSnapshot.historicalData,
- groupBy: 'month'
- });
-
- expect(portfolioSnapshot.historicalData[0]).toEqual({
- date: '2022-03-06',
- investmentValueWithCurrencyEffect: 0,
- netPerformance: 0,
- netPerformanceInPercentage: 0,
- netPerformanceInPercentageWithCurrencyEffect: 0,
- netPerformanceWithCurrencyEffect: 0,
- netWorth: 0,
- totalAccountBalance: 0,
- totalInvestment: 0,
- totalInvestmentValueWithCurrencyEffect: 0,
- value: 0,
- valueWithCurrencyEffect: 0
- });
-
- expect(portfolioSnapshot.historicalData[1]).toEqual({
- date: '2022-03-07',
- investmentValueWithCurrencyEffect: 151.6,
- netPerformance: 0,
- netPerformanceInPercentage: 0,
- netPerformanceInPercentageWithCurrencyEffect: 0,
- netPerformanceWithCurrencyEffect: 0,
- netWorth: 151.6,
- totalAccountBalance: 0,
- totalInvestment: 151.6,
- totalInvestmentValueWithCurrencyEffect: 151.6,
- value: 151.6,
- valueWithCurrencyEffect: 151.6
- });
-
- expect(
- portfolioSnapshot.historicalData[
- portfolioSnapshot.historicalData.length - 1
- ]
- ).toEqual({
- date: '2022-04-11',
- investmentValueWithCurrencyEffect: 0,
- netPerformance: 19.86,
- netPerformanceInPercentage: 0.13100263852242744,
- netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744,
- netPerformanceWithCurrencyEffect: 19.86,
- netWorth: 0,
- totalAccountBalance: 0,
- totalInvestment: 0,
- totalInvestmentValueWithCurrencyEffect: 0,
- value: 0,
- valueWithCurrencyEffect: 0
- });
-
- expect(portfolioSnapshot).toMatchObject({
- currentValueInBaseCurrency: new Big('0'),
- errors: [],
- hasErrors: false,
- positions: [
- {
- averagePrice: new Big('0'),
- currency: 'CHF',
- dataSource: 'YAHOO',
- dividend: new Big('0'),
- dividendInBaseCurrency: new Big('0'),
- fee: new Big('0'),
- feeInBaseCurrency: new Big('0'),
- firstBuyDate: '2022-03-07',
- grossPerformance: new Big('19.86'),
- grossPerformancePercentage: new Big('0.13100263852242744063'),
- grossPerformancePercentageWithCurrencyEffect: new Big(
- '0.13100263852242744063'
- ),
- grossPerformanceWithCurrencyEffect: new Big('19.86'),
- investment: new Big('0'),
- investmentWithCurrencyEffect: new Big('0'),
- netPerformance: new Big('19.86'),
- netPerformancePercentage: new Big('0.13100263852242744063'),
- netPerformancePercentageWithCurrencyEffectMap: {
- max: new Big('0.13100263852242744063')
- },
- netPerformanceWithCurrencyEffectMap: {
- max: new Big('19.86')
- },
- marketPrice: 87.8,
- marketPriceInBaseCurrency: 87.8,
- quantity: new Big('0'),
- symbol: 'NOVN.SW',
- tags: [],
- timeWeightedInvestment: new Big('151.6'),
- timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'),
- transactionCount: 2,
- valueInBaseCurrency: new Big('0')
- }
- ],
- totalFeesWithCurrencyEffect: new Big('0'),
- totalInterestWithCurrencyEffect: new Big('0'),
- totalInvestment: new Big('0'),
- totalInvestmentWithCurrencyEffect: new Big('0'),
- totalLiabilitiesWithCurrencyEffect: new Big('0'),
- totalValuablesWithCurrencyEffect: new Big('0')
- });
-
- expect(last(portfolioSnapshot.historicalData)).toMatchObject(
- expect.objectContaining({
- netPerformance: 19.86,
- netPerformanceInPercentage: 0.13100263852242744063,
- netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063,
- netPerformanceWithCurrencyEffect: 19.86,
- totalInvestmentValueWithCurrencyEffect: 0
- })
- );
-
- expect(investments).toEqual([
- { date: '2022-03-07', investment: new Big('151.6') },
- { date: '2022-04-08', investment: new Big('0') }
- ]);
-
- expect(investmentsByMonth).toEqual([
- { date: '2022-03-01', investment: 151.6 },
- { date: '2022-04-01', investment: -151.6 }
- ]);
- });
- });
-});
+import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
+import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
+import {
+ activityDummyData,
+ loadActivityExportFile,
+ symbolProfileDummyData,
+ userDummyData
+} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
+import {
+ PerformanceCalculationType,
+ PortfolioCalculatorFactory
+} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
+import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
+import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
+import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
+import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock';
+import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
+import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
+import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
+import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
+import { parseDate } from '@ghostfolio/common/helper';
+
+import { Big } from 'big.js';
+import { last } from 'lodash';
+import { join } from 'path';
+
+jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
+ return {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ CurrentRateService: jest.fn().mockImplementation(() => {
+ return CurrentRateServiceMock;
+ })
+ };
+});
+
+jest.mock(
+ '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service',
+ () => {
+ return {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ PortfolioSnapshotService: jest.fn().mockImplementation(() => {
+ return PortfolioSnapshotServiceMock;
+ })
+ };
+ }
+);
+
+jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
+ return {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ RedisCacheService: jest.fn().mockImplementation(() => {
+ return RedisCacheServiceMock;
+ })
+ };
+});
+
+describe('PortfolioCalculator', () => {
+ let activityDtos: CreateOrderDto[];
+
+ let configurationService: ConfigurationService;
+ let currentRateService: CurrentRateService;
+ let exchangeRateDataService: ExchangeRateDataService;
+ let portfolioCalculatorFactory: PortfolioCalculatorFactory;
+ let portfolioSnapshotService: PortfolioSnapshotService;
+ let redisCacheService: RedisCacheService;
+
+ beforeAll(() => {
+ activityDtos = loadActivityExportFile(
+ join(
+ __dirname,
+ '../../../../../../../test/import/ok-novn-buy-and-sell.json'
+ )
+ );
+ });
+
+ beforeEach(() => {
+ configurationService = new ConfigurationService();
+
+ currentRateService = new CurrentRateService(null, null, null, null);
+
+ exchangeRateDataService = new ExchangeRateDataService(
+ null,
+ null,
+ null,
+ null
+ );
+
+ portfolioSnapshotService = new PortfolioSnapshotService(null);
+
+ redisCacheService = new RedisCacheService(null, null);
+
+ portfolioCalculatorFactory = new PortfolioCalculatorFactory(
+ configurationService,
+ currentRateService,
+ exchangeRateDataService,
+ portfolioSnapshotService,
+ redisCacheService
+ );
+ });
+
+ describe('get current positions', () => {
+ it.only('with NOVN.SW buy and sell', async () => {
+ jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
+
+ const activities: Activity[] = activityDtos.map((activity) => ({
+ ...activityDummyData,
+ ...activity,
+ date: new Date(activity.date),
+ SymbolProfile: {
+ ...symbolProfileDummyData,
+ currency: activity.currency,
+ dataSource: activity.dataSource,
+ name: 'Novartis AG',
+ symbol: activity.symbol
+ }
+ }));
+
+ const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
+ activities,
+ calculationType: PerformanceCalculationType.TWR,
+ currency: 'CHF',
+ userId: userDummyData.id
+ });
+
+ const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
+
+ const investments = portfolioCalculator.getInvestments();
+
+ const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({
+ data: portfolioSnapshot.historicalData,
+ groupBy: 'month'
+ });
+
+ expect(portfolioSnapshot.historicalData[0]).toEqual({
+ date: '2022-03-06',
+ investmentValueWithCurrencyEffect: 0,
+ netPerformance: 0,
+ netPerformanceInPercentage: 0,
+ netPerformanceInPercentageWithCurrencyEffect: 0,
+ netPerformanceWithCurrencyEffect: 0,
+ netWorth: 0,
+ totalAccountBalance: 0,
+ totalInvestment: 0,
+ totalInvestmentValueWithCurrencyEffect: 0,
+ value: 0,
+ valueWithCurrencyEffect: 0
+ });
+
+ expect(portfolioSnapshot.historicalData[1]).toEqual({
+ date: '2022-03-07',
+ investmentValueWithCurrencyEffect: 151.6,
+ netPerformance: 0,
+ netPerformanceInPercentage: 0,
+ netPerformanceInPercentageWithCurrencyEffect: 0,
+ netPerformanceWithCurrencyEffect: 0,
+ netWorth: 151.6,
+ totalAccountBalance: 0,
+ totalInvestment: 151.6,
+ totalInvestmentValueWithCurrencyEffect: 151.6,
+ value: 151.6,
+ valueWithCurrencyEffect: 151.6
+ });
+
+ expect(
+ portfolioSnapshot.historicalData[
+ portfolioSnapshot.historicalData.length - 1
+ ]
+ ).toEqual({
+ date: '2022-04-11',
+ investmentValueWithCurrencyEffect: 0,
+ netPerformance: 19.86,
+ netPerformanceInPercentage: 0.13100263852242744,
+ netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744,
+ netPerformanceWithCurrencyEffect: 19.86,
+ netWorth: 0,
+ totalAccountBalance: 0,
+ totalInvestment: 0,
+ totalInvestmentValueWithCurrencyEffect: 0,
+ value: 0,
+ valueWithCurrencyEffect: 0
+ });
+
+ expect(portfolioSnapshot).toMatchObject({
+ currentValueInBaseCurrency: new Big('0'),
+ errors: [],
+ hasErrors: false,
+ positions: [
+ {
+ averagePrice: new Big('0'),
+ currency: 'CHF',
+ dataSource: 'YAHOO',
+ dividend: new Big('0'),
+ dividendInBaseCurrency: new Big('0'),
+ fee: new Big('0'),
+ feeInBaseCurrency: new Big('0'),
+ firstBuyDate: '2022-03-07',
+ grossPerformance: new Big('19.86'),
+ grossPerformancePercentage: new Big('0.13100263852242744063'),
+ grossPerformancePercentageWithCurrencyEffect: new Big(
+ '0.13100263852242744063'
+ ),
+ grossPerformanceWithCurrencyEffect: new Big('19.86'),
+ investment: new Big('0'),
+ investmentWithCurrencyEffect: new Big('0'),
+ netPerformance: new Big('19.86'),
+ netPerformancePercentage: new Big('0.13100263852242744063'),
+ netPerformancePercentageWithCurrencyEffectMap: {
+ max: new Big('0.13100263852242744063')
+ },
+ netPerformanceWithCurrencyEffectMap: {
+ max: new Big('19.86')
+ },
+ marketPrice: 87.8,
+ marketPriceInBaseCurrency: 87.8,
+ quantity: new Big('0'),
+ symbol: 'NOVN.SW',
+ tags: [],
+ timeWeightedInvestment: new Big('151.6'),
+ timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'),
+ transactionCount: 2,
+ valueInBaseCurrency: new Big('0')
+ }
+ ],
+ totalFeesWithCurrencyEffect: new Big('0'),
+ totalInterestWithCurrencyEffect: new Big('0'),
+ totalInvestment: new Big('0'),
+ totalInvestmentWithCurrencyEffect: new Big('0'),
+ totalLiabilitiesWithCurrencyEffect: new Big('0'),
+ totalValuablesWithCurrencyEffect: new Big('0')
+ });
+
+ expect(last(portfolioSnapshot.historicalData)).toMatchObject(
+ expect.objectContaining({
+ netPerformance: 19.86,
+ netPerformanceInPercentage: 0.13100263852242744063,
+ netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063,
+ netPerformanceWithCurrencyEffect: 19.86,
+ totalInvestmentValueWithCurrencyEffect: 0
+ })
+ );
+
+ expect(investments).toEqual([
+ { date: '2022-03-07', investment: new Big('151.6') },
+ { date: '2022-04-08', investment: new Big('0') }
+ ]);
+
+ expect(investmentsByMonth).toEqual([
+ { date: '2022-03-01', investment: 151.6 },
+ { date: '2022-04-01', investment: -151.6 }
+ ]);
+ });
+ });
+});
From 70cc7e4aee4ad7a56de57fc4744bfbee78931d20 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 11 Oct 2024 20:53:09 +0200
Subject: [PATCH 09/34] Refactoring
---
.../twr/portfolio-calculator-novn-buy-and-sell.spec.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
index 1589cecaa..66cdb9e8e 100644
--- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
+++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
@@ -105,7 +105,7 @@ describe('PortfolioCalculator', () => {
const activities: Activity[] = activityDtos.map((activity) => ({
...activityDummyData,
...activity,
- date: new Date(activity.date),
+ date: parseDate(activity.date),
SymbolProfile: {
...symbolProfileDummyData,
currency: activity.currency,
From f0fdbc6cb8a232ea86f61b3537c0eefe2e767a9f Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Fri, 11 Oct 2024 21:01:01 +0200
Subject: [PATCH 10/34] Update date
---
test/import/ok-novn-buy-and-sell.json | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/test/import/ok-novn-buy-and-sell.json b/test/import/ok-novn-buy-and-sell.json
index b8a62279d..b7ab6aee1 100644
--- a/test/import/ok-novn-buy-and-sell.json
+++ b/test/import/ok-novn-buy-and-sell.json
@@ -11,7 +11,7 @@
"unitPrice": 85.73,
"currency": "CHF",
"dataSource": "YAHOO",
- "date": "2022-04-07T22:00:00.000Z",
+ "date": "2022-04-08T00:00:00.000Z",
"symbol": "NOVN.SW"
},
{
@@ -21,7 +21,7 @@
"unitPrice": 75.8,
"currency": "CHF",
"dataSource": "YAHOO",
- "date": "2022-03-06T23:00:00.000Z",
+ "date": "2022-03-07T00:00:00.000Z",
"symbol": "NOVN.SW"
}
]
From 7a11bb93d5badddc69651b5d6fe8f5b20421c58c Mon Sep 17 00:00:00 2001
From: Dhaneshwari Tendle
<110600266+dhaneshwaritendle@users.noreply.github.com>
Date: Sat, 12 Oct 2024 00:41:39 +0530
Subject: [PATCH 11/34] Feature/Set up unit test that loads activity from
exported json file (#3901)
* Set up unit test that loads activity from exported json file
* Update changelog
---
CHANGELOG.md | 4 +
.../portfolio-calculator-test-utils.ts | 6 +
...folio-calculator-novn-buy-and-sell.spec.ts | 512 +++++++++---------
test/import/ok-novn-buy-and-sell.json | 4 +-
4 files changed, 265 insertions(+), 261 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 388fd9772..d83247b12 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added the name to the tooltip of the chart of the holdings tab on the home page (experimental)
+### Changed
+
+- Improved the portfolio unit tests to work with exported activity files
+
### Fixed
- Considered the language of the user settings on login with _Security Token_
diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts
index d458be708..217ec499b 100644
--- a/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts
+++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator-test-utils.ts
@@ -1,3 +1,5 @@
+import { readFileSync } from 'fs';
+
export const activityDummyData = {
accountId: undefined,
accountUserId: undefined,
@@ -29,3 +31,7 @@ export const symbolProfileDummyData = {
export const userDummyData = {
id: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
};
+
+export function loadActivityExportFile(filePath: string) {
+ return JSON.parse(readFileSync(filePath, 'utf8')).activities;
+}
diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
index db5aaf6bc..66cdb9e8e 100644
--- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
+++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell.spec.ts
@@ -1,259 +1,253 @@
-import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
-import {
- activityDummyData,
- symbolProfileDummyData,
- userDummyData
-} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
-import {
- PerformanceCalculationType,
- PortfolioCalculatorFactory
-} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
-import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
-import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
-import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
-import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock';
-import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
-import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
-import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
-import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
-import { parseDate } from '@ghostfolio/common/helper';
-
-import { Big } from 'big.js';
-import { last } from 'lodash';
-
-jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- CurrentRateService: jest.fn().mockImplementation(() => {
- return CurrentRateServiceMock;
- })
- };
-});
-
-jest.mock(
- '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service',
- () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- PortfolioSnapshotService: jest.fn().mockImplementation(() => {
- return PortfolioSnapshotServiceMock;
- })
- };
- }
-);
-
-jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
- return {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- RedisCacheService: jest.fn().mockImplementation(() => {
- return RedisCacheServiceMock;
- })
- };
-});
-
-describe('PortfolioCalculator', () => {
- let configurationService: ConfigurationService;
- let currentRateService: CurrentRateService;
- let exchangeRateDataService: ExchangeRateDataService;
- let portfolioCalculatorFactory: PortfolioCalculatorFactory;
- let portfolioSnapshotService: PortfolioSnapshotService;
- let redisCacheService: RedisCacheService;
-
- beforeEach(() => {
- configurationService = new ConfigurationService();
-
- currentRateService = new CurrentRateService(null, null, null, null);
-
- exchangeRateDataService = new ExchangeRateDataService(
- null,
- null,
- null,
- null
- );
-
- portfolioSnapshotService = new PortfolioSnapshotService(null);
-
- redisCacheService = new RedisCacheService(null, null);
-
- portfolioCalculatorFactory = new PortfolioCalculatorFactory(
- configurationService,
- currentRateService,
- exchangeRateDataService,
- portfolioSnapshotService,
- redisCacheService
- );
- });
-
- describe('get current positions', () => {
- it.only('with NOVN.SW buy and sell', async () => {
- jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
-
- const activities: Activity[] = [
- {
- ...activityDummyData,
- date: new Date('2022-03-07'),
- fee: 0,
- quantity: 2,
- SymbolProfile: {
- ...symbolProfileDummyData,
- currency: 'CHF',
- dataSource: 'YAHOO',
- name: 'Novartis AG',
- symbol: 'NOVN.SW'
- },
- type: 'BUY',
- unitPrice: 75.8
- },
- {
- ...activityDummyData,
- date: new Date('2022-04-08'),
- fee: 0,
- quantity: 2,
- SymbolProfile: {
- ...symbolProfileDummyData,
- currency: 'CHF',
- dataSource: 'YAHOO',
- name: 'Novartis AG',
- symbol: 'NOVN.SW'
- },
- type: 'SELL',
- unitPrice: 85.73
- }
- ];
-
- const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
- activities,
- calculationType: PerformanceCalculationType.TWR,
- currency: 'CHF',
- userId: userDummyData.id
- });
-
- const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
-
- const investments = portfolioCalculator.getInvestments();
-
- const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({
- data: portfolioSnapshot.historicalData,
- groupBy: 'month'
- });
-
- expect(portfolioSnapshot.historicalData[0]).toEqual({
- date: '2022-03-06',
- investmentValueWithCurrencyEffect: 0,
- netPerformance: 0,
- netPerformanceInPercentage: 0,
- netPerformanceInPercentageWithCurrencyEffect: 0,
- netPerformanceWithCurrencyEffect: 0,
- netWorth: 0,
- totalAccountBalance: 0,
- totalInvestment: 0,
- totalInvestmentValueWithCurrencyEffect: 0,
- value: 0,
- valueWithCurrencyEffect: 0
- });
-
- expect(portfolioSnapshot.historicalData[1]).toEqual({
- date: '2022-03-07',
- investmentValueWithCurrencyEffect: 151.6,
- netPerformance: 0,
- netPerformanceInPercentage: 0,
- netPerformanceInPercentageWithCurrencyEffect: 0,
- netPerformanceWithCurrencyEffect: 0,
- netWorth: 151.6,
- totalAccountBalance: 0,
- totalInvestment: 151.6,
- totalInvestmentValueWithCurrencyEffect: 151.6,
- value: 151.6,
- valueWithCurrencyEffect: 151.6
- });
-
- expect(
- portfolioSnapshot.historicalData[
- portfolioSnapshot.historicalData.length - 1
- ]
- ).toEqual({
- date: '2022-04-11',
- investmentValueWithCurrencyEffect: 0,
- netPerformance: 19.86,
- netPerformanceInPercentage: 0.13100263852242744,
- netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744,
- netPerformanceWithCurrencyEffect: 19.86,
- netWorth: 0,
- totalAccountBalance: 0,
- totalInvestment: 0,
- totalInvestmentValueWithCurrencyEffect: 0,
- value: 0,
- valueWithCurrencyEffect: 0
- });
-
- expect(portfolioSnapshot).toMatchObject({
- currentValueInBaseCurrency: new Big('0'),
- errors: [],
- hasErrors: false,
- positions: [
- {
- averagePrice: new Big('0'),
- currency: 'CHF',
- dataSource: 'YAHOO',
- dividend: new Big('0'),
- dividendInBaseCurrency: new Big('0'),
- fee: new Big('0'),
- feeInBaseCurrency: new Big('0'),
- firstBuyDate: '2022-03-07',
- grossPerformance: new Big('19.86'),
- grossPerformancePercentage: new Big('0.13100263852242744063'),
- grossPerformancePercentageWithCurrencyEffect: new Big(
- '0.13100263852242744063'
- ),
- grossPerformanceWithCurrencyEffect: new Big('19.86'),
- investment: new Big('0'),
- investmentWithCurrencyEffect: new Big('0'),
- netPerformance: new Big('19.86'),
- netPerformancePercentage: new Big('0.13100263852242744063'),
- netPerformancePercentageWithCurrencyEffectMap: {
- max: new Big('0.13100263852242744063')
- },
- netPerformanceWithCurrencyEffectMap: {
- max: new Big('19.86')
- },
- marketPrice: 87.8,
- marketPriceInBaseCurrency: 87.8,
- quantity: new Big('0'),
- symbol: 'NOVN.SW',
- tags: [],
- timeWeightedInvestment: new Big('151.6'),
- timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'),
- transactionCount: 2,
- valueInBaseCurrency: new Big('0')
- }
- ],
- totalFeesWithCurrencyEffect: new Big('0'),
- totalInterestWithCurrencyEffect: new Big('0'),
- totalInvestment: new Big('0'),
- totalInvestmentWithCurrencyEffect: new Big('0'),
- totalLiabilitiesWithCurrencyEffect: new Big('0'),
- totalValuablesWithCurrencyEffect: new Big('0')
- });
-
- expect(last(portfolioSnapshot.historicalData)).toMatchObject(
- expect.objectContaining({
- netPerformance: 19.86,
- netPerformanceInPercentage: 0.13100263852242744063,
- netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063,
- netPerformanceWithCurrencyEffect: 19.86,
- totalInvestmentValueWithCurrencyEffect: 0
- })
- );
-
- expect(investments).toEqual([
- { date: '2022-03-07', investment: new Big('151.6') },
- { date: '2022-04-08', investment: new Big('0') }
- ]);
-
- expect(investmentsByMonth).toEqual([
- { date: '2022-03-01', investment: 151.6 },
- { date: '2022-04-01', investment: -151.6 }
- ]);
- });
- });
-});
+import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
+import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
+import {
+ activityDummyData,
+ loadActivityExportFile,
+ symbolProfileDummyData,
+ userDummyData
+} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
+import {
+ PerformanceCalculationType,
+ PortfolioCalculatorFactory
+} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory';
+import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service';
+import { CurrentRateServiceMock } from '@ghostfolio/api/app/portfolio/current-rate.service.mock';
+import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service';
+import { RedisCacheServiceMock } from '@ghostfolio/api/app/redis-cache/redis-cache.service.mock';
+import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
+import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
+import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
+import { PortfolioSnapshotServiceMock } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service.mock';
+import { parseDate } from '@ghostfolio/common/helper';
+
+import { Big } from 'big.js';
+import { last } from 'lodash';
+import { join } from 'path';
+
+jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
+ return {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ CurrentRateService: jest.fn().mockImplementation(() => {
+ return CurrentRateServiceMock;
+ })
+ };
+});
+
+jest.mock(
+ '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service',
+ () => {
+ return {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ PortfolioSnapshotService: jest.fn().mockImplementation(() => {
+ return PortfolioSnapshotServiceMock;
+ })
+ };
+ }
+);
+
+jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
+ return {
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ RedisCacheService: jest.fn().mockImplementation(() => {
+ return RedisCacheServiceMock;
+ })
+ };
+});
+
+describe('PortfolioCalculator', () => {
+ let activityDtos: CreateOrderDto[];
+
+ let configurationService: ConfigurationService;
+ let currentRateService: CurrentRateService;
+ let exchangeRateDataService: ExchangeRateDataService;
+ let portfolioCalculatorFactory: PortfolioCalculatorFactory;
+ let portfolioSnapshotService: PortfolioSnapshotService;
+ let redisCacheService: RedisCacheService;
+
+ beforeAll(() => {
+ activityDtos = loadActivityExportFile(
+ join(
+ __dirname,
+ '../../../../../../../test/import/ok-novn-buy-and-sell.json'
+ )
+ );
+ });
+
+ beforeEach(() => {
+ configurationService = new ConfigurationService();
+
+ currentRateService = new CurrentRateService(null, null, null, null);
+
+ exchangeRateDataService = new ExchangeRateDataService(
+ null,
+ null,
+ null,
+ null
+ );
+
+ portfolioSnapshotService = new PortfolioSnapshotService(null);
+
+ redisCacheService = new RedisCacheService(null, null);
+
+ portfolioCalculatorFactory = new PortfolioCalculatorFactory(
+ configurationService,
+ currentRateService,
+ exchangeRateDataService,
+ portfolioSnapshotService,
+ redisCacheService
+ );
+ });
+
+ describe('get current positions', () => {
+ it.only('with NOVN.SW buy and sell', async () => {
+ jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
+
+ const activities: Activity[] = activityDtos.map((activity) => ({
+ ...activityDummyData,
+ ...activity,
+ date: parseDate(activity.date),
+ SymbolProfile: {
+ ...symbolProfileDummyData,
+ currency: activity.currency,
+ dataSource: activity.dataSource,
+ name: 'Novartis AG',
+ symbol: activity.symbol
+ }
+ }));
+
+ const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
+ activities,
+ calculationType: PerformanceCalculationType.TWR,
+ currency: 'CHF',
+ userId: userDummyData.id
+ });
+
+ const portfolioSnapshot = await portfolioCalculator.computeSnapshot();
+
+ const investments = portfolioCalculator.getInvestments();
+
+ const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({
+ data: portfolioSnapshot.historicalData,
+ groupBy: 'month'
+ });
+
+ expect(portfolioSnapshot.historicalData[0]).toEqual({
+ date: '2022-03-06',
+ investmentValueWithCurrencyEffect: 0,
+ netPerformance: 0,
+ netPerformanceInPercentage: 0,
+ netPerformanceInPercentageWithCurrencyEffect: 0,
+ netPerformanceWithCurrencyEffect: 0,
+ netWorth: 0,
+ totalAccountBalance: 0,
+ totalInvestment: 0,
+ totalInvestmentValueWithCurrencyEffect: 0,
+ value: 0,
+ valueWithCurrencyEffect: 0
+ });
+
+ expect(portfolioSnapshot.historicalData[1]).toEqual({
+ date: '2022-03-07',
+ investmentValueWithCurrencyEffect: 151.6,
+ netPerformance: 0,
+ netPerformanceInPercentage: 0,
+ netPerformanceInPercentageWithCurrencyEffect: 0,
+ netPerformanceWithCurrencyEffect: 0,
+ netWorth: 151.6,
+ totalAccountBalance: 0,
+ totalInvestment: 151.6,
+ totalInvestmentValueWithCurrencyEffect: 151.6,
+ value: 151.6,
+ valueWithCurrencyEffect: 151.6
+ });
+
+ expect(
+ portfolioSnapshot.historicalData[
+ portfolioSnapshot.historicalData.length - 1
+ ]
+ ).toEqual({
+ date: '2022-04-11',
+ investmentValueWithCurrencyEffect: 0,
+ netPerformance: 19.86,
+ netPerformanceInPercentage: 0.13100263852242744,
+ netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744,
+ netPerformanceWithCurrencyEffect: 19.86,
+ netWorth: 0,
+ totalAccountBalance: 0,
+ totalInvestment: 0,
+ totalInvestmentValueWithCurrencyEffect: 0,
+ value: 0,
+ valueWithCurrencyEffect: 0
+ });
+
+ expect(portfolioSnapshot).toMatchObject({
+ currentValueInBaseCurrency: new Big('0'),
+ errors: [],
+ hasErrors: false,
+ positions: [
+ {
+ averagePrice: new Big('0'),
+ currency: 'CHF',
+ dataSource: 'YAHOO',
+ dividend: new Big('0'),
+ dividendInBaseCurrency: new Big('0'),
+ fee: new Big('0'),
+ feeInBaseCurrency: new Big('0'),
+ firstBuyDate: '2022-03-07',
+ grossPerformance: new Big('19.86'),
+ grossPerformancePercentage: new Big('0.13100263852242744063'),
+ grossPerformancePercentageWithCurrencyEffect: new Big(
+ '0.13100263852242744063'
+ ),
+ grossPerformanceWithCurrencyEffect: new Big('19.86'),
+ investment: new Big('0'),
+ investmentWithCurrencyEffect: new Big('0'),
+ netPerformance: new Big('19.86'),
+ netPerformancePercentage: new Big('0.13100263852242744063'),
+ netPerformancePercentageWithCurrencyEffectMap: {
+ max: new Big('0.13100263852242744063')
+ },
+ netPerformanceWithCurrencyEffectMap: {
+ max: new Big('19.86')
+ },
+ marketPrice: 87.8,
+ marketPriceInBaseCurrency: 87.8,
+ quantity: new Big('0'),
+ symbol: 'NOVN.SW',
+ tags: [],
+ timeWeightedInvestment: new Big('151.6'),
+ timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'),
+ transactionCount: 2,
+ valueInBaseCurrency: new Big('0')
+ }
+ ],
+ totalFeesWithCurrencyEffect: new Big('0'),
+ totalInterestWithCurrencyEffect: new Big('0'),
+ totalInvestment: new Big('0'),
+ totalInvestmentWithCurrencyEffect: new Big('0'),
+ totalLiabilitiesWithCurrencyEffect: new Big('0'),
+ totalValuablesWithCurrencyEffect: new Big('0')
+ });
+
+ expect(last(portfolioSnapshot.historicalData)).toMatchObject(
+ expect.objectContaining({
+ netPerformance: 19.86,
+ netPerformanceInPercentage: 0.13100263852242744063,
+ netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063,
+ netPerformanceWithCurrencyEffect: 19.86,
+ totalInvestmentValueWithCurrencyEffect: 0
+ })
+ );
+
+ expect(investments).toEqual([
+ { date: '2022-03-07', investment: new Big('151.6') },
+ { date: '2022-04-08', investment: new Big('0') }
+ ]);
+
+ expect(investmentsByMonth).toEqual([
+ { date: '2022-03-01', investment: 151.6 },
+ { date: '2022-04-01', investment: -151.6 }
+ ]);
+ });
+ });
+});
diff --git a/test/import/ok-novn-buy-and-sell.json b/test/import/ok-novn-buy-and-sell.json
index b8a62279d..b7ab6aee1 100644
--- a/test/import/ok-novn-buy-and-sell.json
+++ b/test/import/ok-novn-buy-and-sell.json
@@ -11,7 +11,7 @@
"unitPrice": 85.73,
"currency": "CHF",
"dataSource": "YAHOO",
- "date": "2022-04-07T22:00:00.000Z",
+ "date": "2022-04-08T00:00:00.000Z",
"symbol": "NOVN.SW"
},
{
@@ -21,7 +21,7 @@
"unitPrice": 75.8,
"currency": "CHF",
"dataSource": "YAHOO",
- "date": "2022-03-06T23:00:00.000Z",
+ "date": "2022-03-07T00:00:00.000Z",
"symbol": "NOVN.SW"
}
]
From c44da0bce3934aa3448b96b0442d013337506267 Mon Sep 17 00:00:00 2001
From: ceroma <678940+ceroma@users.noreply.github.com>
Date: Sat, 12 Oct 2024 04:04:58 -0300
Subject: [PATCH 12/34] Feature/expose portfolio snapshot computation timeout
as environment variable (#3894)
* Expose portfolio snapshot computation timeout as environment variable
* Update changelog
---
CHANGELOG.md | 1 +
.../configuration/configuration.service.ts | 4 ++++
.../portfolio-snapshot.module.ts | 14 ++++++++++++--
libs/common/src/lib/config.ts | 1 +
4 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d83247b12..84b641513 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
+- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
- Improved the portfolio unit tests to work with exported activity files
### Fixed
diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts
index cca393a2a..dafd4803c 100644
--- a/apps/api/src/services/configuration/configuration.service.ts
+++ b/apps/api/src/services/configuration/configuration.service.ts
@@ -4,6 +4,7 @@ import {
DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE,
DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA,
DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT,
+ DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT,
DEFAULT_ROOT_URL
} from '@ghostfolio/common/config';
@@ -59,6 +60,9 @@ export class ConfigurationService {
PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT: num({
default: DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT
}),
+ PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT: num({
+ default: DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT
+ }),
REDIS_DB: num({ default: 0 }),
REDIS_HOST: str({ default: 'localhost' }),
REDIS_PASSWORD: str({ default: '' }),
diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
index 620feda53..058d971d8 100644
--- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
+++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
@@ -8,7 +8,10 @@ import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-
import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module';
import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module';
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
-import { PORTFOLIO_SNAPSHOT_QUEUE } from '@ghostfolio/common/config';
+import {
+ DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT,
+ PORTFOLIO_SNAPSHOT_QUEUE
+} from '@ghostfolio/common/config';
import { BullModule } from '@nestjs/bull';
import { Module } from '@nestjs/common';
@@ -20,7 +23,14 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor';
imports: [
AccountBalanceModule,
BullModule.registerQueue({
- name: PORTFOLIO_SNAPSHOT_QUEUE
+ name: PORTFOLIO_SNAPSHOT_QUEUE,
+ settings: {
+ lockDuration: parseInt(
+ process.env.PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT ??
+ DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT.toString(),
+ 10
+ )
+ }
}),
ConfigurationModule,
DataProviderModule,
diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts
index 19ec965fa..4a5079d28 100644
--- a/libs/common/src/lib/config.ts
+++ b/libs/common/src/lib/config.ts
@@ -51,6 +51,7 @@ export const DEFAULT_PAGE_SIZE = 50;
export const DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE = 1;
export const DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA = 1;
export const DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT = 1;
+export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT = 30000;
export const DEFAULT_ROOT_URL = 'https://localhost:4200';
// USX is handled separately
From 3289bd5cc936ae7e43c3fd53bb6d7e456e20e614 Mon Sep 17 00:00:00 2001
From: Tushar Agarwal <151814842+tushar-agarwal7@users.noreply.github.com>
Date: Sat, 12 Oct 2024 23:02:34 +0530
Subject: [PATCH 13/34] Feature/Simplify labels in treemap chart (#3912)
* Simplify labels in treemap chart
* Update changelog
---
CHANGELOG.md | 1 +
libs/ui/src/lib/treemap-chart/treemap-chart.component.ts | 3 +--
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 84b641513..8f6af2f7e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
+- Improved the labels of the chart of the holdings tab on the home page (experimental)
- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
- Improved the portfolio unit tests to work with exported activity files
diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
index 0e694f6dc..0b3f17676 100644
--- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
+++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
@@ -151,13 +151,12 @@ export class GfTreemapChartComponent
align: 'left',
color: ['white'],
display: true,
- font: [{ size: 14 }, { size: 11 }, { lineHeight: 2, size: 14 }],
+ font: [{ size: 16 }, { lineHeight: 1.5, size: 14 }],
formatter(ctx) {
const netPerformancePercentWithCurrencyEffect =
ctx.raw._data.netPerformancePercentWithCurrencyEffect;
return [
- ctx.raw._data.name,
ctx.raw._data.symbol,
`${netPerformancePercentWithCurrencyEffect > 0 ? '+' : ''}${(ctx.raw._data.netPerformancePercentWithCurrencyEffect * 100).toFixed(2)}%`
];
From aee5e833a52b6685f12d10e9be622fe52eda3660 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Sat, 12 Oct 2024 19:35:43 +0200
Subject: [PATCH 14/34] Feature/harmonize processor concurrency environment
variables (#3913)
* Harmonize processor concurrency environment variables
* Update changelog
---
CHANGELOG.md | 7 +++++++
.../configuration/configuration.service.ts | 18 +++++++++---------
.../interfaces/environment.interface.ts | 4 ++++
.../data-gathering/data-gathering.processor.ts | 12 ++++++------
.../portfolio-snapshot.processor.ts | 4 ++--
libs/common/src/lib/config.ts | 6 +++---
6 files changed, 31 insertions(+), 20 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f6af2f7e..72c166601 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,12 +15,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved the labels of the chart of the holdings tab on the home page (experimental)
- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
+- Harmonized the processor concurrency environment variables
- Improved the portfolio unit tests to work with exported activity files
### Fixed
- Considered the language of the user settings on login with _Security Token_
+### Todo
+
+- Rename the environment variable from `PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE` to `PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY`
+- Rename the environment variable from `PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA` to `PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY`
+- Rename the environment variable from `PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT` to `PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY`
+
## 2.114.0 - 2024-10-10
### Added
diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts
index dafd4803c..10810deb5 100644
--- a/apps/api/src/services/configuration/configuration.service.ts
+++ b/apps/api/src/services/configuration/configuration.service.ts
@@ -1,9 +1,9 @@
import { Environment } from '@ghostfolio/api/services/interfaces/environment.interface';
import {
CACHE_TTL_NO_CACHE,
- DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE,
- DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA,
- DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT,
+ DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY,
+ DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY,
+ DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY,
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT,
DEFAULT_ROOT_URL
} from '@ghostfolio/common/config';
@@ -51,14 +51,14 @@ export class ConfigurationService {
MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }),
MAX_CHART_ITEMS: num({ default: 365 }),
PORT: port({ default: 3333 }),
- PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE: num({
- default: DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE
+ PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY: num({
+ default: DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY
}),
- PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA: num({
- default: DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA
+ PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY: num({
+ default: DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY
}),
- PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT: num({
- default: DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT
+ PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY: num({
+ default: DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY
}),
PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT: num({
default: DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT
diff --git a/apps/api/src/services/interfaces/environment.interface.ts b/apps/api/src/services/interfaces/environment.interface.ts
index d07937787..8d6dd34de 100644
--- a/apps/api/src/services/interfaces/environment.interface.ts
+++ b/apps/api/src/services/interfaces/environment.interface.ts
@@ -30,6 +30,10 @@ export interface Environment extends CleanedEnvAccessors {
MAX_ACTIVITIES_TO_IMPORT: number;
MAX_CHART_ITEMS: number;
PORT: number;
+ PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY: number;
+ PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY: number;
+ PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY: number;
+ PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT: number;
REDIS_DB: number;
REDIS_HOST: string;
REDIS_PASSWORD: string;
diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts
index 2745aa288..5d0d1e131 100644
--- a/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts
+++ b/apps/api/src/services/queues/data-gathering/data-gathering.processor.ts
@@ -3,8 +3,8 @@ import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfac
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
import {
DATA_GATHERING_QUEUE,
- DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE,
- DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA,
+ DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY,
+ DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY,
GATHER_ASSET_PROFILE_PROCESS,
GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME
} from '@ghostfolio/common/config';
@@ -38,8 +38,8 @@ export class DataGatheringProcessor {
@Process({
concurrency: parseInt(
- process.env.PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE ??
- DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE.toString(),
+ process.env.PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY ??
+ DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY.toString(),
10
),
name: GATHER_ASSET_PROFILE_PROCESS
@@ -69,8 +69,8 @@ export class DataGatheringProcessor {
@Process({
concurrency: parseInt(
- process.env.PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA ??
- DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA.toString(),
+ process.env.PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY ??
+ DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY.toString(),
10
),
name: GATHER_HISTORICAL_MARKET_DATA_PROCESS_JOB_NAME
diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
index 7c89e9c23..c66ef2a4c 100644
--- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
+++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
@@ -9,7 +9,7 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import {
CACHE_TTL_INFINITE,
- DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT,
+ DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY,
PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME,
PORTFOLIO_SNAPSHOT_QUEUE
} from '@ghostfolio/common/config';
@@ -35,7 +35,7 @@ export class PortfolioSnapshotProcessor {
@Process({
concurrency: parseInt(
process.env.PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT ??
- DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT.toString(),
+ DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY.toString(),
10
),
name: PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME
diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts
index 4a5079d28..87b348b26 100644
--- a/libs/common/src/lib/config.ts
+++ b/libs/common/src/lib/config.ts
@@ -48,9 +48,9 @@ export const DEFAULT_CURRENCY = 'USD';
export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy';
export const DEFAULT_LANGUAGE_CODE = 'en';
export const DEFAULT_PAGE_SIZE = 50;
-export const DEFAULT_PROCESSOR_CONCURRENCY_GATHER_ASSET_PROFILE = 1;
-export const DEFAULT_PROCESSOR_CONCURRENCY_GATHER_HISTORICAL_MARKET_DATA = 1;
-export const DEFAULT_PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT = 1;
+export const DEFAULT_PROCESSOR_GATHER_ASSET_PROFILE_CONCURRENCY = 1;
+export const DEFAULT_PROCESSOR_GATHER_HISTORICAL_MARKET_DATA_CONCURRENCY = 1;
+export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY = 1;
export const DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT = 30000;
export const DEFAULT_ROOT_URL = 'https://localhost:4200';
From f8da265f5f4d8d34a3e11232a31b6c5d2ccad44a Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Sat, 12 Oct 2024 21:04:09 +0200
Subject: [PATCH 15/34] Feature/restructure XRayRulesSettings (#3898)
* Restructure XRayRulesSettings
* Update changelog
---
CHANGELOG.md | 1 +
apps/api/src/app/portfolio/rules.service.ts | 7 +--
apps/api/src/app/user/user.service.ts | 46 ++++++++++++++-----
apps/api/src/models/rule.ts | 10 +++-
.../current-investment.ts | 15 +++++-
.../account-cluster-risk/single-account.ts | 6 ++-
.../base-currency-current-investment.ts | 6 ++-
.../current-investment.ts | 15 +++++-
.../emergency-fund/emergency-fund-setup.ts | 6 ++-
.../fees/fee-ratio-initial-investment.ts | 15 +++++-
.../interfaces/interfaces.ts | 2 +
.../rule-settings-dialog.component.ts | 8 ++--
.../rule-settings-dialog.html | 14 ++++--
.../app/components/rule/rule.component.html | 2 +-
.../src/app/components/rule/rule.component.ts | 15 +++---
.../app/components/rules/rules.component.html | 1 +
.../app/components/rules/rules.component.ts | 4 +-
.../portfolio/fire/fire-page.component.ts | 5 ++
.../app/pages/portfolio/fire/fire-page.html | 5 ++
.../portfolio-report-rule.interface.ts | 13 ++++--
.../lib/types/x-ray-rules-settings.type.ts | 6 +--
21 files changed, 149 insertions(+), 53 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 72c166601..6e1b35474 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Improved the labels of the chart of the holdings tab on the home page (experimental)
+- Refactored the rule thresholds in the _X-ray_ section (experimental)
- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
- Harmonized the processor concurrency environment variables
- Improved the portfolio unit tests to work with exported activity files
diff --git a/apps/api/src/app/portfolio/rules.service.ts b/apps/api/src/app/portfolio/rules.service.ts
index fd9d794b2..5f0aa64d5 100644
--- a/apps/api/src/app/portfolio/rules.service.ts
+++ b/apps/api/src/app/portfolio/rules.service.ts
@@ -24,13 +24,10 @@ export class RulesService {
return {
evaluation,
value,
+ configuration: rule.getConfiguration(),
isActive: true,
key: rule.getKey(),
- name: rule.getName(),
- settings: {
- thresholdMax: settings['thresholdMax'],
- thresholdMin: settings['thresholdMin']
- }
+ name: rule.getName()
};
} else {
return {
diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts
index 0f76b9540..e8a437be6 100644
--- a/apps/api/src/app/user/user.service.ts
+++ b/apps/api/src/app/user/user.service.ts
@@ -2,6 +2,12 @@ import { OrderService } from '@ghostfolio/api/app/order/order.service';
import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service';
import { environment } from '@ghostfolio/api/environments/environment';
import { PortfolioChangedEvent } from '@ghostfolio/api/events/portfolio-changed.event';
+import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment';
+import { AccountClusterRiskSingleAccount } from '@ghostfolio/api/models/rules/account-cluster-risk/single-account';
+import { CurrencyClusterRiskBaseCurrencyCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/base-currency-current-investment';
+import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/currency-cluster-risk/current-investment';
+import { EmergencyFundSetup } from '@ghostfolio/api/models/rules/emergency-fund/emergency-fund-setup';
+import { FeeRatioInitialInvestment } from '@ghostfolio/api/models/rules/fees/fee-ratio-initial-investment';
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
@@ -200,17 +206,35 @@ export class UserService {
(user.Settings.settings as UserSettings).viewMode = 'DEFAULT';
}
- // Set default values for X-ray rules
- if (!(user.Settings.settings as UserSettings).xRayRules) {
- (user.Settings.settings as UserSettings).xRayRules = {
- AccountClusterRiskCurrentInvestment: { isActive: true },
- AccountClusterRiskSingleAccount: { isActive: true },
- CurrencyClusterRiskBaseCurrencyCurrentInvestment: { isActive: true },
- CurrencyClusterRiskCurrentInvestment: { isActive: true },
- EmergencyFundSetup: { isActive: true },
- FeeRatioInitialInvestment: { isActive: true }
- };
- }
+ (user.Settings.settings as UserSettings).xRayRules = {
+ AccountClusterRiskCurrentInvestment:
+ new AccountClusterRiskCurrentInvestment(undefined, {}).getSettings(
+ user.Settings.settings
+ ),
+ AccountClusterRiskSingleAccount: new AccountClusterRiskSingleAccount(
+ undefined,
+ {}
+ ).getSettings(user.Settings.settings),
+ CurrencyClusterRiskBaseCurrencyCurrentInvestment:
+ new CurrencyClusterRiskBaseCurrencyCurrentInvestment(
+ undefined,
+ undefined
+ ).getSettings(user.Settings.settings),
+ CurrencyClusterRiskCurrentInvestment:
+ new CurrencyClusterRiskCurrentInvestment(
+ undefined,
+ undefined
+ ).getSettings(user.Settings.settings),
+ EmergencyFundSetup: new EmergencyFundSetup(
+ undefined,
+ undefined
+ ).getSettings(user.Settings.settings),
+ FeeRatioInitialInvestment: new FeeRatioInitialInvestment(
+ undefined,
+ undefined,
+ undefined
+ ).getSettings(user.Settings.settings)
+ };
let currentPermissions = getPermissions(user.role);
diff --git a/apps/api/src/models/rule.ts b/apps/api/src/models/rule.ts
index a1e0d9bee..187527fbb 100644
--- a/apps/api/src/models/rule.ts
+++ b/apps/api/src/models/rule.ts
@@ -1,7 +1,11 @@
import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
import { groupBy } from '@ghostfolio/common/helper';
-import { PortfolioPosition, UserSettings } from '@ghostfolio/common/interfaces';
+import {
+ PortfolioPosition,
+ PortfolioReportRule,
+ UserSettings
+} from '@ghostfolio/common/interfaces';
import { Big } from 'big.js';
@@ -65,5 +69,9 @@ export abstract class Rule implements RuleInterface {
public abstract evaluate(aRuleSettings: T): EvaluationResult;
+ public abstract getConfiguration(): Partial<
+ PortfolioReportRule['configuration']
+ >;
+
public abstract getSettings(aUserSettings: UserSettings): T;
}
diff --git a/apps/api/src/models/rules/account-cluster-risk/current-investment.ts b/apps/api/src/models/rules/account-cluster-risk/current-investment.ts
index 13680270e..95a8022ed 100644
--- a/apps/api/src/models/rules/account-cluster-risk/current-investment.ts
+++ b/apps/api/src/models/rules/account-cluster-risk/current-investment.ts
@@ -76,11 +76,22 @@ export class AccountClusterRiskCurrentInvestment extends Rule {
};
}
+ public getConfiguration() {
+ return {
+ threshold: {
+ max: 1,
+ min: 0,
+ step: 0.01
+ },
+ thresholdMax: true
+ };
+ }
+
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return {
baseCurrency,
- isActive: xRayRules[this.getKey()].isActive,
- thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.5
+ isActive: xRayRules?.[this.getKey()].isActive ?? true,
+ thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.5
};
}
}
diff --git a/apps/api/src/models/rules/account-cluster-risk/single-account.ts b/apps/api/src/models/rules/account-cluster-risk/single-account.ts
index feaaf4e38..ef549e579 100644
--- a/apps/api/src/models/rules/account-cluster-risk/single-account.ts
+++ b/apps/api/src/models/rules/account-cluster-risk/single-account.ts
@@ -34,9 +34,13 @@ export class AccountClusterRiskSingleAccount extends Rule {
};
}
+ public getConfiguration() {
+ return undefined;
+ }
+
public getSettings({ xRayRules }: UserSettings): RuleSettings {
return {
- isActive: xRayRules[this.getKey()].isActive
+ isActive: xRayRules?.[this.getKey()].isActive ?? true
};
}
}
diff --git a/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts b/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts
index 39ee8b88d..573795799 100644
--- a/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts
+++ b/apps/api/src/models/rules/currency-cluster-risk/base-currency-current-investment.ts
@@ -61,10 +61,14 @@ export class CurrencyClusterRiskBaseCurrencyCurrentInvestment extends Rule {
};
}
+ public getConfiguration() {
+ return {
+ threshold: {
+ max: 1,
+ min: 0,
+ step: 0.01
+ },
+ thresholdMax: true
+ };
+ }
+
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return {
baseCurrency,
- isActive: xRayRules[this.getKey()].isActive,
- thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.5
+ isActive: xRayRules?.[this.getKey()].isActive ?? true,
+ thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.5
};
}
}
diff --git a/apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts b/apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts
index 819b8bd7b..d13f2ffc5 100644
--- a/apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts
+++ b/apps/api/src/models/rules/emergency-fund/emergency-fund-setup.ts
@@ -32,10 +32,14 @@ export class EmergencyFundSetup extends Rule {
};
}
+ public getConfiguration() {
+ return undefined;
+ }
+
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return {
baseCurrency,
- isActive: xRayRules[this.getKey()].isActive
+ isActive: xRayRules?.[this.getKey()].isActive ?? true
};
}
}
diff --git a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts b/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
index 9b1961ed6..a3ea8d059 100644
--- a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
+++ b/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
@@ -43,11 +43,22 @@ export class FeeRatioInitialInvestment extends Rule {
};
}
+ public getConfiguration() {
+ return {
+ threshold: {
+ max: 0.1,
+ min: 0,
+ step: 0.005
+ },
+ thresholdMax: true
+ };
+ }
+
public getSettings({ baseCurrency, xRayRules }: UserSettings): Settings {
return {
baseCurrency,
- isActive: xRayRules[this.getKey()].isActive,
- thresholdMax: xRayRules[this.getKey()]?.thresholdMax ?? 0.01
+ isActive: xRayRules?.[this.getKey()].isActive ?? true,
+ thresholdMax: xRayRules?.[this.getKey()]?.thresholdMax ?? 0.01
};
}
}
diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts
index a409ab503..7eee7e52d 100644
--- a/apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts
+++ b/apps/client/src/app/components/rule/rule-settings-dialog/interfaces/interfaces.ts
@@ -1,5 +1,7 @@
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
+import { XRayRulesSettings } from '@ghostfolio/common/types';
export interface IRuleSettingsDialogParams {
rule: PortfolioReportRule;
+ settings: XRayRulesSettings['AccountClusterRiskCurrentInvestment'];
}
diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts
index 265d3c941..0dd23ab16 100644
--- a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts
+++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts
@@ -1,4 +1,4 @@
-import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
+import { XRayRulesSettings } from '@ghostfolio/common/types';
import { CommonModule } from '@angular/common';
import { Component, Inject } from '@angular/core';
@@ -29,12 +29,10 @@ import { IRuleSettingsDialogParams } from './interfaces/interfaces';
templateUrl: './rule-settings-dialog.html'
})
export class GfRuleSettingsDialogComponent {
- public settings: PortfolioReportRule['settings'];
+ public settings: XRayRulesSettings['AccountClusterRiskCurrentInvestment'];
public constructor(
@Inject(MAT_DIALOG_DATA) public data: IRuleSettingsDialogParams,
public dialogRef: MatDialogRef
- ) {
- this.settings = this.data.rule.settings;
- }
+ ) {}
}
diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
index ef86549f6..0c2477b63 100644
--- a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
+++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
@@ -4,34 +4,38 @@
Threshold Min
Threshold Max
Close
-
+
Save
diff --git a/apps/client/src/app/components/rule/rule.component.html b/apps/client/src/app/components/rule/rule.component.html
index 5491933c0..7cea512e3 100644
--- a/apps/client/src/app/components/rule/rule.component.html
+++ b/apps/client/src/app/components/rule/rule.component.html
@@ -62,7 +62,7 @@
- @if (rule?.isActive && !isEmpty(rule.settings)) {
+ @if (rule?.isActive && rule?.configuration) {
Customize ...
diff --git a/apps/client/src/app/components/rule/rule.component.ts b/apps/client/src/app/components/rule/rule.component.ts
index 6e6c368f0..f51ce805f 100644
--- a/apps/client/src/app/components/rule/rule.component.ts
+++ b/apps/client/src/app/components/rule/rule.component.ts
@@ -1,5 +1,7 @@
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
+import { RuleSettings } from '@ghostfolio/api/models/interfaces/rule-settings.interface';
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
+import { XRayRulesSettings } from '@ghostfolio/common/types';
import {
ChangeDetectionStrategy,
@@ -10,7 +12,6 @@ import {
Output
} from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
-import { isEmpty } from 'lodash';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject, takeUntil } from 'rxjs';
@@ -27,11 +28,10 @@ export class RuleComponent implements OnInit {
@Input() hasPermissionToUpdateUserSettings: boolean;
@Input() isLoading: boolean;
@Input() rule: PortfolioReportRule;
+ @Input() settings: XRayRulesSettings['AccountClusterRiskCurrentInvestment'];
@Output() ruleUpdated = new EventEmitter();
- public isEmpty = isEmpty;
-
private deviceType: string;
private unsubscribeSubject = new Subject();
@@ -46,16 +46,17 @@ export class RuleComponent implements OnInit {
public onCustomizeRule(rule: PortfolioReportRule) {
const dialogRef = this.dialog.open(GfRuleSettingsDialogComponent, {
- data: {
- rule
- },
+ data: {
+ rule,
+ settings: this.settings
+ } as IRuleSettingsDialogParams,
width: this.deviceType === 'mobile' ? '100vw' : '50rem'
});
dialogRef
.afterClosed()
.pipe(takeUntil(this.unsubscribeSubject))
- .subscribe((settings: PortfolioReportRule['settings']) => {
+ .subscribe((settings: RuleSettings) => {
if (settings) {
this.ruleUpdated.emit({
xRayRules: {
diff --git a/apps/client/src/app/components/rules/rules.component.html b/apps/client/src/app/components/rules/rules.component.html
index 31e61bfc2..28343673d 100644
--- a/apps/client/src/app/components/rules/rules.component.html
+++ b/apps/client/src/app/components/rules/rules.component.html
@@ -12,6 +12,7 @@
hasPermissionToUpdateUserSettings
"
[rule]="rule"
+ [settings]="settings?.[rule.key]"
(ruleUpdated)="onRuleUpdated($event)"
/>
}
diff --git a/apps/client/src/app/components/rules/rules.component.ts b/apps/client/src/app/components/rules/rules.component.ts
index b8493e7be..fb2ef1cdb 100644
--- a/apps/client/src/app/components/rules/rules.component.ts
+++ b/apps/client/src/app/components/rules/rules.component.ts
@@ -1,5 +1,6 @@
import { UpdateUserSettingDto } from '@ghostfolio/api/app/user/update-user-setting.dto';
import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
+import { XRayRulesSettings } from '@ghostfolio/common/types';
import {
ChangeDetectionStrategy,
@@ -19,11 +20,10 @@ export class RulesComponent {
@Input() hasPermissionToUpdateUserSettings: boolean;
@Input() isLoading: boolean;
@Input() rules: PortfolioReportRule[];
+ @Input() settings: XRayRulesSettings;
@Output() rulesUpdated = new EventEmitter();
- public constructor() {}
-
public onRuleUpdated(event: UpdateUserSettingDto) {
this.rulesUpdated.emit(event);
}
diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
index 10a2eb604..54f65b531 100644
--- a/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
+++ b/apps/client/src/app/pages/portfolio/fire/fire-page.component.ts
@@ -138,6 +138,11 @@ export class FirePageComponent implements OnDestroy, OnInit {
.putUserSetting(event)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
+ this.userService
+ .get(true)
+ .pipe(takeUntil(this.unsubscribeSubject))
+ .subscribe();
+
this.initializePortfolioReport();
});
}
diff --git a/apps/client/src/app/pages/portfolio/fire/fire-page.html b/apps/client/src/app/pages/portfolio/fire/fire-page.html
index b0fade836..c4a521a8c 100644
--- a/apps/client/src/app/pages/portfolio/fire/fire-page.html
+++ b/apps/client/src/app/pages/portfolio/fire/fire-page.html
@@ -132,6 +132,7 @@
"
[isLoading]="isLoadingPortfolioReport"
[rules]="emergencyFundRules"
+ [settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)"
/>
@@ -150,6 +151,7 @@
"
[isLoading]="isLoadingPortfolioReport"
[rules]="currencyClusterRiskRules"
+ [settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)"
/>
@@ -168,6 +170,7 @@
"
[isLoading]="isLoadingPortfolioReport"
[rules]="accountClusterRiskRules"
+ [settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)"
/>
@@ -186,6 +189,7 @@
"
[isLoading]="isLoadingPortfolioReport"
[rules]="feeRules"
+ [settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)"
/>
@@ -200,6 +204,7 @@
"
[isLoading]="isLoadingPortfolioReport"
[rules]="inactiveRules"
+ [settings]="user?.settings?.xRayRules"
(rulesUpdated)="onRulesUpdated($event)"
/>
diff --git a/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts b/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
index 29cbb4a8f..f69c097fc 100644
--- a/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
+++ b/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
@@ -1,11 +1,16 @@
export interface PortfolioReportRule {
+ configuration?: {
+ threshold?: {
+ max: number;
+ min: number;
+ step: number;
+ };
+ thresholdMax?: boolean;
+ thresholdMin?: boolean;
+ };
evaluation?: string;
isActive: boolean;
key: string;
name: string;
- settings?: {
- thresholdMax?: number;
- thresholdMin?: number;
- };
value?: boolean;
}
diff --git a/libs/common/src/lib/types/x-ray-rules-settings.type.ts b/libs/common/src/lib/types/x-ray-rules-settings.type.ts
index a55487f0b..fddd708cc 100644
--- a/libs/common/src/lib/types/x-ray-rules-settings.type.ts
+++ b/libs/common/src/lib/types/x-ray-rules-settings.type.ts
@@ -1,5 +1,3 @@
-import { PortfolioReportRule } from '@ghostfolio/common/interfaces';
-
export type XRayRulesSettings = {
AccountClusterRiskCurrentInvestment?: RuleSettings;
AccountClusterRiskSingleAccount?: RuleSettings;
@@ -9,6 +7,8 @@ export type XRayRulesSettings = {
FeeRatioInitialInvestment?: RuleSettings;
};
-interface RuleSettings extends Pick {
+interface RuleSettings {
isActive: boolean;
+ thresholdMax?: number;
+ thresholdMin?: number;
}
From 67a147bd96e794be30273237e74ec3c47283c322 Mon Sep 17 00:00:00 2001
From: Madhab Chandra Sahoo
<30400985+madhab-chandra-sahoo@users.noreply.github.com>
Date: Sun, 13 Oct 2024 19:43:26 +0530
Subject: [PATCH 16/34] Feature/Improve background color assignment in treemap
chart component (#3918)
* Improve background color assignment in treemap chart component
* Update changelog
---
CHANGELOG.md | 1 +
.../lib/treemap-chart/treemap-chart.component.ts | 13 +++++++++++--
2 files changed, 12 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6e1b35474..77c0743bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
+- Improved the backgrounds of the chart of the holdings tab on the home page (experimental)
- Improved the labels of the chart of the holdings tab on the home page (experimental)
- Refactored the rule thresholds in the _X-ray_ section (experimental)
- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
index 0b3f17676..7099b01fd 100644
--- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
+++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
@@ -91,7 +91,7 @@ export class GfTreemapChartComponent
datasets: [
{
backgroundColor(ctx) {
- const annualizedNetPerformancePercentWithCurrencyEffect =
+ let annualizedNetPerformancePercentWithCurrencyEffect =
getAnnualizedPerformancePercent({
daysInMarket: differenceInDays(
endDate,
@@ -105,6 +105,12 @@ export class GfTreemapChartComponent
)
}).toNumber();
+ // Round to 2 decimal places
+ annualizedNetPerformancePercentWithCurrencyEffect =
+ Math.round(
+ annualizedNetPerformancePercentWithCurrencyEffect * 100
+ ) / 100;
+
if (
annualizedNetPerformancePercentWithCurrencyEffect >
0.03 * GfTreemapChartComponent.HEAT_MULTIPLIER
@@ -123,8 +129,11 @@ export class GfTreemapChartComponent
} else if (annualizedNetPerformancePercentWithCurrencyEffect > 0) {
return green[3];
} else if (
- annualizedNetPerformancePercentWithCurrencyEffect === 0
+ Math.abs(annualizedNetPerformancePercentWithCurrencyEffect) === 0
) {
+ annualizedNetPerformancePercentWithCurrencyEffect = Math.abs(
+ annualizedNetPerformancePercentWithCurrencyEffect
+ );
return gray[3];
} else if (
annualizedNetPerformancePercentWithCurrencyEffect >
From a14c10bad2ea65c65d950e6633fa9302b10aa679 Mon Sep 17 00:00:00 2001
From: dw-0
Date: Mon, 14 Oct 2024 10:49:18 +0200
Subject: [PATCH 17/34] Feature/Enable unused compiler options in tsconfig
(#3895)
* Enable noUnusedLocals noUnusedParameters in compiler options of tsconfig
* Update changelog
---
CHANGELOG.md | 2 ++
apps/api/src/app/account/create-account.dto.ts | 2 +-
apps/api/src/app/account/update-account.dto.ts | 2 +-
apps/api/src/app/auth/auth.controller.ts | 11 ++++-------
apps/api/src/app/auth/google.strategy.ts | 8 ++++----
apps/api/src/app/auth/web-auth.service.ts | 11 +++++------
.../transform-data-source-in-response.interceptor.ts | 2 +-
.../yahoo-finance/yahoo-finance.service.spec.ts | 4 ----
.../yahoo-finance/yahoo-finance.service.ts | 2 --
.../google-sheets/google-sheets.service.ts | 2 +-
.../benchmark-comparator.component.ts | 7 ++++---
.../investment-chart/investment-chart.component.ts | 7 ++++---
libs/common/src/lib/chart-helper.ts | 2 +-
libs/ui/src/lib/line-chart/line-chart.component.ts | 7 ++++---
tsconfig.base.json | 4 ++--
15 files changed, 34 insertions(+), 39 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 77c0743bc..021aaa9fb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
- Harmonized the processor concurrency environment variables
- Improved the portfolio unit tests to work with exported activity files
+- Enabled the `noUnusedLocals` compiler option in the `tsconfig`
+- Enabled the `noUnusedParameters` compiler option in the `tsconfig`
### Fixed
diff --git a/apps/api/src/app/account/create-account.dto.ts b/apps/api/src/app/account/create-account.dto.ts
index f3c88316f..b331d4ec7 100644
--- a/apps/api/src/app/account/create-account.dto.ts
+++ b/apps/api/src/app/account/create-account.dto.ts
@@ -36,6 +36,6 @@ export class CreateAccountDto {
name: string;
@IsString()
- @ValidateIf((object, value) => value !== null)
+ @ValidateIf((_object, value) => value !== null)
platformId: string | null;
}
diff --git a/apps/api/src/app/account/update-account.dto.ts b/apps/api/src/app/account/update-account.dto.ts
index 6b87af71b..3a721d873 100644
--- a/apps/api/src/app/account/update-account.dto.ts
+++ b/apps/api/src/app/account/update-account.dto.ts
@@ -35,6 +35,6 @@ export class UpdateAccountDto {
name: string;
@IsString()
- @ValidateIf((object, value) => value !== null)
+ @ValidateIf((_object, value) => value !== null)
platformId: string | null;
}
diff --git a/apps/api/src/app/auth/auth.controller.ts b/apps/api/src/app/auth/auth.controller.ts
index c81c7e224..5019bef21 100644
--- a/apps/api/src/app/auth/auth.controller.ts
+++ b/apps/api/src/app/auth/auth.controller.ts
@@ -14,12 +14,12 @@ import {
Req,
Res,
UseGuards,
- VERSION_NEUTRAL,
- Version
+ Version,
+ VERSION_NEUTRAL
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { Request, Response } from 'express';
-import { StatusCodes, getReasonPhrase } from 'http-status-codes';
+import { getReasonPhrase, StatusCodes } from 'http-status-codes';
import { AuthService } from './auth.service';
import {
@@ -130,10 +130,7 @@ export class AuthController {
public async verifyAttestation(
@Body() body: { deviceName: string; credential: AttestationCredentialJSON }
) {
- return this.webAuthService.verifyAttestation(
- body.deviceName,
- body.credential
- );
+ return this.webAuthService.verifyAttestation(body.credential);
}
@Post('webauthn/generate-assertion-options')
diff --git a/apps/api/src/app/auth/google.strategy.ts b/apps/api/src/app/auth/google.strategy.ts
index ea6772680..02f82a7a8 100644
--- a/apps/api/src/app/auth/google.strategy.ts
+++ b/apps/api/src/app/auth/google.strategy.ts
@@ -11,7 +11,7 @@ import { AuthService } from './auth.service';
export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
public constructor(
private readonly authService: AuthService,
- private readonly configurationService: ConfigurationService
+ configurationService: ConfigurationService
) {
super({
callbackURL: `${configurationService.get(
@@ -25,9 +25,9 @@ export class GoogleStrategy extends PassportStrategy(Strategy, 'google') {
}
public async validate(
- request: any,
- token: string,
- refreshToken: string,
+ _request: any,
+ _token: string,
+ _refreshToken: string,
profile: Profile,
done: Function
) {
diff --git a/apps/api/src/app/auth/web-auth.service.ts b/apps/api/src/app/auth/web-auth.service.ts
index 961bbe9a7..2f8dd1018 100644
--- a/apps/api/src/app/auth/web-auth.service.ts
+++ b/apps/api/src/app/auth/web-auth.service.ts
@@ -13,16 +13,16 @@ import {
import { REQUEST } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import {
+ generateAuthenticationOptions,
GenerateAuthenticationOptionsOpts,
+ generateRegistrationOptions,
GenerateRegistrationOptionsOpts,
VerifiedAuthenticationResponse,
VerifiedRegistrationResponse,
- VerifyAuthenticationResponseOpts,
- VerifyRegistrationResponseOpts,
- generateAuthenticationOptions,
- generateRegistrationOptions,
verifyAuthenticationResponse,
- verifyRegistrationResponse
+ VerifyAuthenticationResponseOpts,
+ verifyRegistrationResponse,
+ VerifyRegistrationResponseOpts
} from '@simplewebauthn/server';
import {
@@ -80,7 +80,6 @@ export class WebAuthService {
}
public async verifyAttestation(
- deviceName: string,
credential: AttestationCredentialJSON
): Promise {
const user = this.request.user;
diff --git a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts
index aff42f002..f5034927c 100644
--- a/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts
+++ b/apps/api/src/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor.ts
@@ -21,7 +21,7 @@ export class TransformDataSourceInResponseInterceptor
) {}
public intercept(
- context: ExecutionContext,
+ _context: ExecutionContext,
next: CallHandler
): Observable {
return next.handle().pipe(
diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts
index 951a623d0..8a8ab1f08 100644
--- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts
+++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.spec.ts
@@ -1,4 +1,3 @@
-import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service';
import { YahooFinanceDataEnhancerService } from './yahoo-finance.service';
@@ -26,16 +25,13 @@ jest.mock(
);
describe('YahooFinanceDataEnhancerService', () => {
- let configurationService: ConfigurationService;
let cryptocurrencyService: CryptocurrencyService;
let yahooFinanceDataEnhancerService: YahooFinanceDataEnhancerService;
beforeAll(async () => {
- configurationService = new ConfigurationService();
cryptocurrencyService = new CryptocurrencyService();
yahooFinanceDataEnhancerService = new YahooFinanceDataEnhancerService(
- configurationService,
cryptocurrencyService
);
});
diff --git a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts
index 1b1335b7e..6090b4f98 100644
--- a/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts
+++ b/apps/api/src/services/data-provider/data-enhancer/yahoo-finance/yahoo-finance.service.ts
@@ -1,4 +1,3 @@
-import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { CryptocurrencyService } from '@ghostfolio/api/services/cryptocurrency/cryptocurrency.service';
import { DataEnhancerInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-enhancer.interface';
import {
@@ -24,7 +23,6 @@ import type { Price } from 'yahoo-finance2/dist/esm/src/modules/quoteSummary-ifa
@Injectable()
export class YahooFinanceDataEnhancerService implements DataEnhancerInterface {
public constructor(
- private readonly configurationService: ConfigurationService,
private readonly cryptocurrencyService: CryptocurrencyService
) {}
diff --git a/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts b/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts
index 966069f22..9f2344233 100644
--- a/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts
+++ b/apps/api/src/services/data-provider/google-sheets/google-sheets.service.ts
@@ -76,7 +76,7 @@ export class GoogleSheetsService implements DataProviderInterface {
} = {};
rows
- .filter((row, index) => {
+ .filter((_row, index) => {
return index >= 1;
})
.forEach((row) => {
diff --git a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
index a59515969..dc80b4058 100644
--- a/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
+++ b/apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
@@ -29,12 +29,13 @@ import { SymbolProfile } from '@prisma/client';
import {
Chart,
ChartData,
+ LinearScale,
LineController,
LineElement,
- LinearScale,
PointElement,
TimeScale,
- Tooltip
+ Tooltip,
+ TooltipPosition
} from 'chart.js';
import 'chartjs-adapter-date-fns';
import annotationPlugin from 'chartjs-plugin-annotation';
@@ -74,7 +75,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
Tooltip
);
- Tooltip.positioners['top'] = (elements, position) =>
+ Tooltip.positioners['top'] = (_elements, position: TooltipPosition) =>
getTooltipPositionerMapTop(this.chart, position);
}
diff --git a/apps/client/src/app/components/investment-chart/investment-chart.component.ts b/apps/client/src/app/components/investment-chart/investment-chart.component.ts
index 15a4a6f9a..e84032060 100644
--- a/apps/client/src/app/components/investment-chart/investment-chart.component.ts
+++ b/apps/client/src/app/components/investment-chart/investment-chart.component.ts
@@ -29,12 +29,13 @@ import {
BarElement,
Chart,
ChartData,
+ LinearScale,
LineController,
LineElement,
- LinearScale,
PointElement,
TimeScale,
- Tooltip
+ Tooltip,
+ TooltipPosition
} from 'chart.js';
import 'chartjs-adapter-date-fns';
import annotationPlugin from 'chartjs-plugin-annotation';
@@ -79,7 +80,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
Tooltip
);
- Tooltip.positioners['top'] = (elements, position) =>
+ Tooltip.positioners['top'] = (_elements, position: TooltipPosition) =>
getTooltipPositionerMapTop(this.chart, position);
}
diff --git a/libs/common/src/lib/chart-helper.ts b/libs/common/src/lib/chart-helper.ts
index 5b65d4a87..4181ebbbf 100644
--- a/libs/common/src/lib/chart-helper.ts
+++ b/libs/common/src/lib/chart-helper.ts
@@ -103,7 +103,7 @@ export function getVerticalHoverLinePlugin(
colorScheme?: ColorScheme
) {
return {
- afterDatasetsDraw: (chart, x, options) => {
+ afterDatasetsDraw: (chart, _, options) => {
const active = chart.getActiveElements();
if (!active || active.length === 0) {
diff --git a/libs/ui/src/lib/line-chart/line-chart.component.ts b/libs/ui/src/lib/line-chart/line-chart.component.ts
index 4098e1d5b..e48ead9d9 100644
--- a/libs/ui/src/lib/line-chart/line-chart.component.ts
+++ b/libs/ui/src/lib/line-chart/line-chart.component.ts
@@ -27,12 +27,13 @@ import {
import {
Chart,
Filler,
+ LinearScale,
LineController,
LineElement,
- LinearScale,
PointElement,
TimeScale,
- Tooltip
+ Tooltip,
+ TooltipPosition
} from 'chart.js';
import 'chartjs-adapter-date-fns';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@@ -85,7 +86,7 @@ export class GfLineChartComponent
Tooltip
);
- Tooltip.positioners['top'] = (elements, position) =>
+ Tooltip.positioners['top'] = (_elements, position: TooltipPosition) =>
getTooltipPositionerMapTop(this.chart, position);
}
diff --git a/tsconfig.base.json b/tsconfig.base.json
index e977a9596..34ed5d559 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -31,8 +31,8 @@
"noImplicitThis": false,
"noImplicitOverride": false,
"noPropertyAccessFromIndexSignature": false,
- "noUnusedLocals": false,
- "noUnusedParameters": false,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
"allowUnreachableCode": true
},
"exclude": ["node_modules", "tmp"]
From 662bfb647e2a5873c53b67a3eaebe1cca0347ecf Mon Sep 17 00:00:00 2001
From: vitalymatyushik
Date: Mon, 14 Oct 2024 21:38:57 +0200
Subject: [PATCH 18/34] Feature/add sliders to customize x-ray rules (#3922)
* Add sliders to customize X-ray rules
* Update changelog
---
CHANGELOG.md | 1 +
.../rule-settings-dialog.component.ts | 6 +--
.../rule-settings-dialog.html | 50 ++++++++++++-------
3 files changed, 35 insertions(+), 22 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 021aaa9fb..47ebfb7dc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved the backgrounds of the chart of the holdings tab on the home page (experimental)
- Improved the labels of the chart of the holdings tab on the home page (experimental)
+- Improved the usability to customize the rule thresholds in the _X-ray_ section by introducing sliders (experimental)
- Refactored the rule thresholds in the _X-ray_ section (experimental)
- Exposed the timeout of the portfolio snapshot computation as an environment variable (`PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT`)
- Harmonized the processor concurrency environment variables
diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts
index 0dd23ab16..7aa228776 100644
--- a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts
+++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.component.ts
@@ -9,8 +9,7 @@ import {
MatDialogModule,
MatDialogRef
} from '@angular/material/dialog';
-import { MatFormFieldModule } from '@angular/material/form-field';
-import { MatInputModule } from '@angular/material/input';
+import { MatSliderModule } from '@angular/material/slider';
import { IRuleSettingsDialogParams } from './interfaces/interfaces';
@@ -20,8 +19,7 @@ import { IRuleSettingsDialogParams } from './interfaces/interfaces';
FormsModule,
MatButtonModule,
MatDialogModule,
- MatFormFieldModule,
- MatInputModule
+ MatSliderModule
],
selector: 'gf-rule-settings-dialog',
standalone: true,
diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
index 0c2477b63..3ae5234e9 100644
--- a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
+++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
@@ -1,32 +1,46 @@
{{ data.rule.name }}
-
- Threshold Min
-
+ Threshold Min ({{
+ data.settings.thresholdMin?.toFixed(2)
+ }})
+
+ {{ data.rule.configuration.threshold.min.toFixed(2) }}
+
-
-
+
+
+ {{ data.rule.configuration.threshold.max.toFixed(2) }}
+
+
- Threshold Max
-
+ Threshold Max ({{
+ data.settings.thresholdMax?.toFixed(2)
+ }})
+
+ {{ data.rule.configuration.threshold.min.toFixed(2) }}
+
-
+ [max]="data.rule.configuration.threshold.max"
+ [min]="data.rule.configuration.threshold.min"
+ [step]="data.rule.configuration.threshold.step"
+ >
+
+
+ {{ data.rule.configuration.threshold.max.toFixed(2) }}
+
From 6be8565442a187728171622992d9f615b4038dd0 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Mon, 14 Oct 2024 21:41:50 +0200
Subject: [PATCH 19/34] Release 2.115.0 (#3925)
---
CHANGELOG.md | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 47ebfb7dc..a2b1a5888 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## Unreleased
+## 2.115.0 - 2024-10-14
### Added
diff --git a/package.json b/package.json
index e283d6a23..9dc6666ab 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ghostfolio",
- "version": "2.114.0",
+ "version": "2.115.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio",
From ab10b9da54cbcd23221dd2adaa9f0b1c4e6d5405 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Tue, 15 Oct 2024 20:01:19 +0200
Subject: [PATCH 20/34] Feature/improve language localization for de 20241014
(#3927)
* Update translations
* Update changelog
---
CHANGELOG.md | 6 +++
apps/client/src/locales/messages.ca.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.de.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.es.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.fr.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.it.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.nl.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.pl.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.pt.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.tr.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.xlf | 50 ++++++++++++-------------
apps/client/src/locales/messages.zh.xlf | 50 ++++++++++++-------------
12 files changed, 281 insertions(+), 275 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a2b1a5888..ee0bc11e1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Unreleased
+
+### Changed
+
+- Improved the language localization for German (`de`)
+
## 2.115.0 - 2024-10-14
### Added
diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf
index 06f8a5647..24dc124a7 100644
--- a/apps/client/src/locales/messages.ca.xlf
+++ b/apps/client/src/locales/messages.ca.xlf
@@ -1471,7 +1471,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -2303,7 +2303,7 @@
Portfolio
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2319,7 +2319,7 @@
Punt de Referència
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2579,7 +2579,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -2635,7 +2635,7 @@
Gestionar Activitats
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -2767,7 +2767,7 @@
Total Amount
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -2775,7 +2775,7 @@
Savings Rate
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -3163,7 +3163,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -3175,7 +3175,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -3187,7 +3187,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -3199,7 +3199,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -3211,7 +3211,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -5199,7 +5199,7 @@
Currency Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -5207,7 +5207,7 @@
Account Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5995,7 +5995,7 @@
Find holding...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6003,7 +6003,7 @@
Week to date
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6011,7 +6011,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6019,7 +6019,7 @@
Month to date
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6027,7 +6027,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6035,7 +6035,7 @@
Year to date
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6043,7 +6043,7 @@
year
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6051,7 +6051,7 @@
years
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6991,7 +6991,7 @@
Inactive
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7063,7 +7063,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7071,7 +7071,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf
index 62302249d..00eb0e87a 100644
--- a/apps/client/src/locales/messages.de.xlf
+++ b/apps/client/src/locales/messages.de.xlf
@@ -554,7 +554,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -1058,7 +1058,7 @@
Aktivitäten verwalten
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -1414,7 +1414,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -1426,7 +1426,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -1438,7 +1438,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -1450,7 +1450,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -1462,7 +1462,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -2374,7 +2374,7 @@
Portfolio
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2898,7 +2898,7 @@
Benchmark
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2962,7 +2962,7 @@
Gesamtbetrag
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -2978,7 +2978,7 @@
Sparrate
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -3730,7 +3730,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -5843,7 +5843,7 @@
Währungsklumpenrisiken
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -5851,7 +5851,7 @@
Kontoklumpenrisiken
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5943,7 +5943,7 @@
Finde Position...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6311,7 +6311,7 @@
Seit Wochenbeginn
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6319,7 +6319,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6327,7 +6327,7 @@
Seit Monatsbeginn
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6335,7 +6335,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6343,7 +6343,7 @@
Seit Jahresbeginn
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6387,7 +6387,7 @@
Jahr
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6395,7 +6395,7 @@
Jahre
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6991,7 +6991,7 @@
Inaktiv
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7063,7 +7063,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7071,7 +7071,7 @@
Schliessen
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf
index 1e897f596..9d788c1b4 100644
--- a/apps/client/src/locales/messages.es.xlf
+++ b/apps/client/src/locales/messages.es.xlf
@@ -555,7 +555,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -1059,7 +1059,7 @@
Gestión de las operaciones
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -1415,7 +1415,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -1427,7 +1427,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -1439,7 +1439,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -1451,7 +1451,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -1463,7 +1463,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -2375,7 +2375,7 @@
Cartera
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2891,7 +2891,7 @@
Benchmark
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2963,7 +2963,7 @@
Importe total
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -2979,7 +2979,7 @@
Tasa de ahorro
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -3731,7 +3731,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -5844,7 +5844,7 @@
Currency Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -5852,7 +5852,7 @@
Account Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5944,7 +5944,7 @@
Find holding...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6312,7 +6312,7 @@
Week to date
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6320,7 +6320,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6328,7 +6328,7 @@
Month to date
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6336,7 +6336,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6344,7 +6344,7 @@
Year to date
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6388,7 +6388,7 @@
año
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6396,7 +6396,7 @@
años
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6992,7 +6992,7 @@
Inactive
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7064,7 +7064,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7072,7 +7072,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf
index aa366fcc4..88afcb818 100644
--- a/apps/client/src/locales/messages.fr.xlf
+++ b/apps/client/src/locales/messages.fr.xlf
@@ -614,7 +614,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -1142,7 +1142,7 @@
Portefeuille
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -1158,7 +1158,7 @@
Référence
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -1378,7 +1378,7 @@
Gérer les Activités
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -1426,7 +1426,7 @@
Montant Total
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -1434,7 +1434,7 @@
Taux d’Épargne
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -1726,7 +1726,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -1738,7 +1738,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -1750,7 +1750,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -1762,7 +1762,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -1774,7 +1774,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -3730,7 +3730,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -5843,7 +5843,7 @@
Risques de change
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -5851,7 +5851,7 @@
Risques liés aux regroupements de comptes
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5943,7 +5943,7 @@
Chercher un actif...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6311,7 +6311,7 @@
Week to date
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6319,7 +6319,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6327,7 +6327,7 @@
Month to date
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6335,7 +6335,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6343,7 +6343,7 @@
Year to date
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6387,7 +6387,7 @@
année
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6395,7 +6395,7 @@
années
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6991,7 +6991,7 @@
Inactif
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7063,7 +7063,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7071,7 +7071,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf
index a9d6df210..08c7e8b26 100644
--- a/apps/client/src/locales/messages.it.xlf
+++ b/apps/client/src/locales/messages.it.xlf
@@ -555,7 +555,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -1059,7 +1059,7 @@
Gestione delle attività
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -1415,7 +1415,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -1427,7 +1427,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -1439,7 +1439,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -1451,7 +1451,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -1463,7 +1463,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -2375,7 +2375,7 @@
Portafoglio
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2891,7 +2891,7 @@
Benchmark
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2963,7 +2963,7 @@
Importo totale
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -2979,7 +2979,7 @@
Tasso di risparmio
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -3731,7 +3731,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -5844,7 +5844,7 @@
Currency Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -5852,7 +5852,7 @@
Account Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5944,7 +5944,7 @@
Trova possedimenti...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6312,7 +6312,7 @@
Da inizio settimana
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6320,7 +6320,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6328,7 +6328,7 @@
Da inizio mese
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6336,7 +6336,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6344,7 +6344,7 @@
Da inizio anno
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6388,7 +6388,7 @@
anno
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6396,7 +6396,7 @@
anni
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6992,7 +6992,7 @@
Inattivo
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7064,7 +7064,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7072,7 +7072,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf
index 441455ef8..0d5d9ced0 100644
--- a/apps/client/src/locales/messages.nl.xlf
+++ b/apps/client/src/locales/messages.nl.xlf
@@ -554,7 +554,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -1058,7 +1058,7 @@
Activiteiten beheren
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -1414,7 +1414,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -1426,7 +1426,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -1438,7 +1438,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -1450,7 +1450,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -1462,7 +1462,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -2374,7 +2374,7 @@
Portefeuille
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2890,7 +2890,7 @@
Benchmark
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2962,7 +2962,7 @@
Totaalbedrag
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -2978,7 +2978,7 @@
Spaarrente
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -3730,7 +3730,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -5843,7 +5843,7 @@
Currency Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -5851,7 +5851,7 @@
Account Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5943,7 +5943,7 @@
Find holding...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6311,7 +6311,7 @@
Week to date
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6319,7 +6319,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6327,7 +6327,7 @@
Month to date
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6335,7 +6335,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6343,7 +6343,7 @@
Year to date
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6387,7 +6387,7 @@
year
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6395,7 +6395,7 @@
years
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6991,7 +6991,7 @@
Inactive
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7063,7 +7063,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7071,7 +7071,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf
index e68b07f45..04e410baf 100644
--- a/apps/client/src/locales/messages.pl.xlf
+++ b/apps/client/src/locales/messages.pl.xlf
@@ -1363,7 +1363,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -2131,7 +2131,7 @@
Portfel
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2147,7 +2147,7 @@
Poziom Odniesienia (Benchmark)
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2283,7 +2283,7 @@
Zarządzaj Aktywnościami
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -2415,7 +2415,7 @@
Całkowita Kwota
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -2423,7 +2423,7 @@
Stopa Oszczędności
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -2551,7 +2551,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -2915,7 +2915,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -2927,7 +2927,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -2939,7 +2939,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -2951,7 +2951,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -2963,7 +2963,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -4727,7 +4727,7 @@
Currency Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -4735,7 +4735,7 @@
Account Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5511,7 +5511,7 @@
Znajdź portfel akcji...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6311,7 +6311,7 @@
Week to date
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6319,7 +6319,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6327,7 +6327,7 @@
Month to date
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6335,7 +6335,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6343,7 +6343,7 @@
Year to date
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6387,7 +6387,7 @@
year
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6395,7 +6395,7 @@
years
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6991,7 +6991,7 @@
Nieaktywny
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7063,7 +7063,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7071,7 +7071,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf
index 8bb514d06..97b7805e3 100644
--- a/apps/client/src/locales/messages.pt.xlf
+++ b/apps/client/src/locales/messages.pt.xlf
@@ -614,7 +614,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -1006,7 +1006,7 @@
Portefólio
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -1022,7 +1022,7 @@
Referência
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -1242,7 +1242,7 @@
Gerir Atividades
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -1298,7 +1298,7 @@
Valor Total
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -1306,7 +1306,7 @@
Taxa de Poupança
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -1706,7 +1706,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -1718,7 +1718,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -1730,7 +1730,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -1742,7 +1742,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -1754,7 +1754,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -3730,7 +3730,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -5843,7 +5843,7 @@
Currency Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -5851,7 +5851,7 @@
Account Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5943,7 +5943,7 @@
Find holding...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6311,7 +6311,7 @@
Week to date
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6319,7 +6319,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6327,7 +6327,7 @@
Month to date
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6335,7 +6335,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6343,7 +6343,7 @@
Year to date
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6387,7 +6387,7 @@
year
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6395,7 +6395,7 @@
years
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6991,7 +6991,7 @@
Inactive
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7063,7 +7063,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7071,7 +7071,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf
index e5292e342..204282131 100644
--- a/apps/client/src/locales/messages.tr.xlf
+++ b/apps/client/src/locales/messages.tr.xlf
@@ -1327,7 +1327,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -1995,7 +1995,7 @@
Portföy
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2011,7 +2011,7 @@
Karşılaştırma Ölçütü
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2135,7 +2135,7 @@
İşlemleri Yönet
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -2267,7 +2267,7 @@
Toplam Tutar
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -2275,7 +2275,7 @@
Tasarruf Oranı
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -2591,7 +2591,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -2759,7 +2759,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -2771,7 +2771,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -2783,7 +2783,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -2795,7 +2795,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -2807,7 +2807,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -5843,7 +5843,7 @@
Kur Kümelenme Riskleri (Currency Cluster Risks)
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -5851,7 +5851,7 @@
Hesap Kümelenme Riski (Account Cluster Risks)
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5943,7 +5943,7 @@
Sahip olunan varlıkları bul...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6311,7 +6311,7 @@
Week to date
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6319,7 +6319,7 @@
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6327,7 +6327,7 @@
Month to date
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6335,7 +6335,7 @@
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6343,7 +6343,7 @@
Year to date
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6387,7 +6387,7 @@
year
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6395,7 +6395,7 @@
years
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6991,7 +6991,7 @@
Inactive
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7063,7 +7063,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7071,7 +7071,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf
index 849b1053e..23cfaf65c 100644
--- a/apps/client/src/locales/messages.xlf
+++ b/apps/client/src/locales/messages.xlf
@@ -1312,7 +1312,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -2013,7 +2013,7 @@
Portfolio
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2028,7 +2028,7 @@
Benchmark
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2151,7 +2151,7 @@
Manage Activities
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -2268,14 +2268,14 @@
Total Amount
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
Savings Rate
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -2392,7 +2392,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -2723,7 +2723,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -2734,7 +2734,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -2745,7 +2745,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -2756,7 +2756,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -2767,7 +2767,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -4337,14 +4337,14 @@
Currency Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
Account Cluster Risks
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5071,7 +5071,7 @@
Find holding...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -5734,35 +5734,35 @@
Year to date
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
Week to date
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
Month to date
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
MTD
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
WTD
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -5801,14 +5801,14 @@
year
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
years
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6331,7 +6331,7 @@
Inactive
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -6359,7 +6359,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -6408,7 +6408,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf
index 22aa783d6..97c8c71ab 100644
--- a/apps/client/src/locales/messages.zh.xlf
+++ b/apps/client/src/locales/messages.zh.xlf
@@ -1372,7 +1372,7 @@
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 35
+ 53
apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html
@@ -2148,7 +2148,7 @@
文件夹
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 116
+ 117
apps/client/src/app/pages/portfolio/portfolio-page-routing.module.ts
@@ -2164,7 +2164,7 @@
基准
apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts
- 128
+ 129
@@ -2300,7 +2300,7 @@
管理活动
apps/client/src/app/components/home-holdings/home-holdings.html
- 62
+ 65
@@ -2432,7 +2432,7 @@
总金额
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 141
+ 142
@@ -2440,7 +2440,7 @@
储蓄率
apps/client/src/app/components/investment-chart/investment-chart.component.ts
- 213
+ 214
@@ -2568,7 +2568,7 @@
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 176
+ 179
@@ -2932,7 +2932,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 217
+ 210
@@ -2944,7 +2944,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -2956,7 +2956,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -2968,7 +2968,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -2980,7 +2980,7 @@
libs/ui/src/lib/assistant/assistant.component.ts
- 256
+ 249
@@ -4744,7 +4744,7 @@
货币集群风险
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 140
+ 141
@@ -4752,7 +4752,7 @@
账户集群风险
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 158
+ 160
@@ -5560,7 +5560,7 @@
查找持有...
libs/ui/src/lib/assistant/assistant.component.ts
- 140
+ 139
@@ -6312,7 +6312,7 @@
今年迄今为止
libs/ui/src/lib/assistant/assistant.component.ts
- 227
+ 220
@@ -6320,7 +6320,7 @@
本周至今
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6328,7 +6328,7 @@
本月至今
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6336,7 +6336,7 @@
最大输运量
libs/ui/src/lib/assistant/assistant.component.ts
- 223
+ 216
@@ -6344,7 +6344,7 @@
世界贸易组织
libs/ui/src/lib/assistant/assistant.component.ts
- 219
+ 212
@@ -6388,7 +6388,7 @@
年
libs/ui/src/lib/assistant/assistant.component.ts
- 231
+ 224
@@ -6396,7 +6396,7 @@
年
libs/ui/src/lib/assistant/assistant.component.ts
- 253
+ 246
@@ -6992,7 +6992,7 @@
Inactive
apps/client/src/app/pages/portfolio/fire/fire-page.html
- 194
+ 198
@@ -7064,7 +7064,7 @@
Threshold Max
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 22
+ 29
@@ -7072,7 +7072,7 @@
Close
apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
- 33
+ 47
From 7f97168aa7e94fa39b8efb178c9db11bc19f07c0 Mon Sep 17 00:00:00 2001
From: vitalymatyushik
Date: Tue, 15 Oct 2024 20:10:35 +0200
Subject: [PATCH 21/34] Feature/disable text hover effect in tree map chart
(#3929)
* Disable text hover effect in tree map chart
* Update changelog
---
CHANGELOG.md | 1 +
.../treemap-chart/treemap-chart.component.ts | 18 +++++++++---------
2 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ee0bc11e1..2331f1a8e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
+- Disabled the text hover effect in the chart of the holdings tab on the home page (experimental)
- Improved the language localization for German (`de`)
## 2.115.0 - 2024-10-14
diff --git a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
index 7099b01fd..7f74a81e1 100644
--- a/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
+++ b/libs/ui/src/lib/treemap-chart/treemap-chart.component.ts
@@ -87,7 +87,7 @@ export class GfTreemapChartComponent
const { endDate, startDate } = getIntervalFromDateRange(this.dateRange);
- const data: ChartConfiguration['data'] = {
+ const data: ChartConfiguration['data'] = {
datasets: [
{
backgroundColor(ctx) {
@@ -170,25 +170,25 @@ export class GfTreemapChartComponent
`${netPerformancePercentWithCurrencyEffect > 0 ? '+' : ''}${(ctx.raw._data.netPerformancePercentWithCurrencyEffect * 100).toFixed(2)}%`
];
},
+ hoverColor: 'white',
position: 'top'
},
spacing: 1,
tree: this.holdings
}
]
- };
+ } as any;
if (this.chartCanvas) {
if (this.chart) {
this.chart.data = data;
- this.chart.options.plugins.tooltip = (
- this.getTooltipPluginConfiguration()
- );
+ this.chart.options.plugins.tooltip =
+ this.getTooltipPluginConfiguration() as unknown;
this.chart.update();
} else {
this.chart = new Chart(this.chartCanvas.nativeElement, {
data,
- options: {
+ options: {
animation: false,
onClick: (event, activeElements) => {
try {
@@ -217,7 +217,7 @@ export class GfTreemapChartComponent
plugins: {
tooltip: this.getTooltipPluginConfiguration()
}
- },
+ } as unknown,
type: 'treemap'
});
}
@@ -239,7 +239,7 @@ export class GfTreemapChartComponent
const symbol = context.raw._data.symbol;
if (context.raw._data.valueInBaseCurrency !== null) {
- const value = context.raw._data.valueInBaseCurrency;
+ const value = context.raw._data.valueInBaseCurrency as number;
return [
`${name ?? symbol}`,
@@ -250,7 +250,7 @@ export class GfTreemapChartComponent
];
} else {
const percentage =
- context.raw._data.allocationInPercentage * 100;
+ (context.raw._data.allocationInPercentage as number) * 100;
return [`${name ?? symbol}`, `${percentage.toFixed(2)}%`];
}
From 144e5da753be089905d23d33babb01d20e734c20 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Tue, 15 Oct 2024 20:49:04 +0200
Subject: [PATCH 22/34] Feature/add units to x ray rule settings (#3926)
* Introduce unit
* Update changelog
---
CHANGELOG.md | 1 +
.../current-investment.ts | 3 +-
.../current-investment.ts | 3 +-
.../fees/fee-ratio-initial-investment.ts | 3 +-
.../rule-settings-dialog.html | 50 +++++++++++++++----
.../portfolio-report-rule.interface.ts | 1 +
6 files changed, 48 insertions(+), 13 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2331f1a8e..c9ea9ad93 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Disabled the text hover effect in the chart of the holdings tab on the home page (experimental)
+- Improved the usability to customize the rule thresholds in the _X-ray_ section by introducing units (experimental)
- Improved the language localization for German (`de`)
## 2.115.0 - 2024-10-14
diff --git a/apps/api/src/models/rules/account-cluster-risk/current-investment.ts b/apps/api/src/models/rules/account-cluster-risk/current-investment.ts
index 95a8022ed..564af935d 100644
--- a/apps/api/src/models/rules/account-cluster-risk/current-investment.ts
+++ b/apps/api/src/models/rules/account-cluster-risk/current-investment.ts
@@ -81,7 +81,8 @@ export class AccountClusterRiskCurrentInvestment extends Rule {
threshold: {
max: 1,
min: 0,
- step: 0.01
+ step: 0.01,
+ unit: '%'
},
thresholdMax: true
};
diff --git a/apps/api/src/models/rules/currency-cluster-risk/current-investment.ts b/apps/api/src/models/rules/currency-cluster-risk/current-investment.ts
index a928412ae..024d5b614 100644
--- a/apps/api/src/models/rules/currency-cluster-risk/current-investment.ts
+++ b/apps/api/src/models/rules/currency-cluster-risk/current-investment.ts
@@ -66,7 +66,8 @@ export class CurrencyClusterRiskCurrentInvestment extends Rule {
threshold: {
max: 1,
min: 0,
- step: 0.01
+ step: 0.01,
+ unit: '%'
},
thresholdMax: true
};
diff --git a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts b/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
index a3ea8d059..fa9d7e7bc 100644
--- a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
+++ b/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts
@@ -48,7 +48,8 @@ export class FeeRatioInitialInvestment extends Rule {
threshold: {
max: 0.1,
min: 0,
- step: 0.005
+ step: 0.0025,
+ unit: '%'
},
thresholdMax: true
};
diff --git a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
index 3ae5234e9..8806dae6a 100644
--- a/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
+++ b/apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html
@@ -6,11 +6,20 @@
[ngClass]="{ 'd-none': !data.rule.configuration.thresholdMin }"
>
- Threshold Min ({{
- data.settings.thresholdMin?.toFixed(2)
- }})
+ Threshold Min :
+ @if (data.rule.configuration.threshold.unit === '%') {
+ {{ data.settings.thresholdMin | percent: '1.2-2' }}
+ } @else {
+ {{ data.settings.thresholdMin }}
+ }
- {{ data.rule.configuration.threshold.min.toFixed(2) }}
+ @if (data.rule.configuration.threshold.unit === '%') {
+ {{
+ data.rule.configuration.threshold.min | percent: '1.2-2'
+ }}
+ } @else {
+ {{ data.rule.configuration.threshold.min }}
+ }
- {{ data.rule.configuration.threshold.max.toFixed(2) }}
+ @if (data.rule.configuration.threshold.unit === '%') {
+ {{
+ data.rule.configuration.threshold.max | percent: '1.2-2'
+ }}
+ } @else {
+ {{ data.rule.configuration.threshold.max }}
+ }
- Threshold Max ({{
- data.settings.thresholdMax?.toFixed(2)
- }})
+ Threshold Max :
+ @if (data.rule.configuration.threshold.unit === '%') {
+ {{ data.settings.thresholdMax | percent: '1.2-2' }}
+ } @else {
+ {{ data.settings.thresholdMax }}
+ }
- {{ data.rule.configuration.threshold.min.toFixed(2) }}
+ @if (data.rule.configuration.threshold.unit === '%') {
+ {{
+ data.rule.configuration.threshold.min | percent: '1.2-2'
+ }}
+ } @else {
+ {{ data.rule.configuration.threshold.min }}
+ }
- {{ data.rule.configuration.threshold.max.toFixed(2) }}
+ @if (data.rule.configuration.threshold.unit === '%') {
+ {{
+ data.rule.configuration.threshold.max | percent: '1.2-2'
+ }}
+ } @else {
+ {{ data.rule.configuration.threshold.max }}
+ }
diff --git a/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts b/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
index f69c097fc..0296606b8 100644
--- a/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
+++ b/libs/common/src/lib/interfaces/portfolio-report-rule.interface.ts
@@ -4,6 +4,7 @@ export interface PortfolioReportRule {
max: number;
min: number;
step: number;
+ unit?: string;
};
thresholdMax?: boolean;
thresholdMin?: boolean;
From 0403117e8cbf4e6665344ec5d591a7dee4403d0c Mon Sep 17 00:00:00 2001
From: JN Brisset
Date: Tue, 15 Oct 2024 12:50:33 -0600
Subject: [PATCH 23/34] Feature/Set permission on entrypoint.sh in Dockerfile
(#3903)
* Set permission on entrypoint.sh in Dockerfile
* Update changelog
---
CHANGELOG.md | 4 ++++
Dockerfile | 1 +
2 files changed, 5 insertions(+)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9ea9ad93..23fcb46de 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
+### Added
+
+- Set the permissions (`chmod 0700`) on `entrypoint.sh` in the `Dockerfile`
+
### Changed
- Disabled the text hover effect in the chart of the holdings tab on the home page (experimental)
diff --git a/Dockerfile b/Dockerfile
index e6c38f273..0e5c0d275 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -61,6 +61,7 @@ RUN apt-get update && apt-get install -y --no-install-suggests \
COPY --chown=node:node --from=builder /ghostfolio/dist/apps /ghostfolio/apps
COPY --chown=node:node ./docker/entrypoint.sh /ghostfolio/entrypoint.sh
+RUN chmod 0700 /ghostfolio/entrypoint.sh
WORKDIR /ghostfolio/apps/api
EXPOSE ${PORT:-3333}
USER node
From 6696a4447a78591c44101fcedbc5275a82da5c7d Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Wed, 16 Oct 2024 20:44:45 +0200
Subject: [PATCH 24/34] Feature/Refactor test ok-novn-buy-and-sell-partially to
load json file (#3935)
* Refactor test to load json file
---
...ulator-novn-buy-and-sell-partially.spec.ts | 56 +++++++++----------
.../ok-novn-buy-and-sell-partially.json | 8 +--
2 files changed, 29 insertions(+), 35 deletions(-)
diff --git a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
index 30eb79754..f9f99ee45 100644
--- a/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
+++ b/apps/api/src/app/portfolio/calculator/twr/portfolio-calculator-novn-buy-and-sell-partially.spec.ts
@@ -1,6 +1,8 @@
+import { CreateOrderDto } from '@ghostfolio/api/app/order/create-order.dto';
import { Activity } from '@ghostfolio/api/app/order/interfaces/activities.interface';
import {
activityDummyData,
+ loadActivityExportFile,
symbolProfileDummyData,
userDummyData
} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils';
@@ -20,6 +22,7 @@ import { parseDate } from '@ghostfolio/common/helper';
import { Big } from 'big.js';
import { last } from 'lodash';
+import { join } from 'path';
jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => {
return {
@@ -52,6 +55,8 @@ jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => {
});
describe('PortfolioCalculator', () => {
+ let activityDtos: CreateOrderDto[];
+
let configurationService: ConfigurationService;
let currentRateService: CurrentRateService;
let exchangeRateDataService: ExchangeRateDataService;
@@ -59,6 +64,15 @@ describe('PortfolioCalculator', () => {
let portfolioSnapshotService: PortfolioSnapshotService;
let redisCacheService: RedisCacheService;
+ beforeAll(() => {
+ activityDtos = loadActivityExportFile(
+ join(
+ __dirname,
+ '../../../../../../../test/import/ok-novn-buy-and-sell-partially.json'
+ )
+ );
+ });
+
beforeEach(() => {
configurationService = new ConfigurationService();
@@ -88,38 +102,18 @@ describe('PortfolioCalculator', () => {
it.only('with NOVN.SW buy and sell partially', async () => {
jest.useFakeTimers().setSystemTime(parseDate('2022-04-11').getTime());
- const activities: Activity[] = [
- {
- ...activityDummyData,
- date: new Date('2022-03-07'),
- fee: 1.3,
- quantity: 2,
- SymbolProfile: {
- ...symbolProfileDummyData,
- currency: 'CHF',
- dataSource: 'YAHOO',
- name: 'Novartis AG',
- symbol: 'NOVN.SW'
- },
- type: 'BUY',
- unitPrice: 75.8
- },
- {
- ...activityDummyData,
- date: new Date('2022-04-08'),
- fee: 2.95,
- quantity: 1,
- SymbolProfile: {
- ...symbolProfileDummyData,
- currency: 'CHF',
- dataSource: 'YAHOO',
- name: 'Novartis AG',
- symbol: 'NOVN.SW'
- },
- type: 'SELL',
- unitPrice: 85.73
+ const activities: Activity[] = activityDtos.map((activity) => ({
+ ...activityDummyData,
+ ...activity,
+ date: parseDate(activity.date),
+ SymbolProfile: {
+ ...symbolProfileDummyData,
+ currency: activity.currency,
+ dataSource: activity.dataSource,
+ name: 'Novartis AG',
+ symbol: activity.symbol
}
- ];
+ }));
const portfolioCalculator = portfolioCalculatorFactory.createCalculator({
activities,
diff --git a/test/import/ok-novn-buy-and-sell-partially.json b/test/import/ok-novn-buy-and-sell-partially.json
index c184b4ba4..06cbc75ea 100644
--- a/test/import/ok-novn-buy-and-sell-partially.json
+++ b/test/import/ok-novn-buy-and-sell-partially.json
@@ -5,23 +5,23 @@
},
"activities": [
{
- "fee": 0,
+ "fee": 1.3,
"quantity": 1,
"type": "SELL",
"unitPrice": 85.73,
"currency": "CHF",
"dataSource": "YAHOO",
- "date": "2022-04-07T22:00:00.000Z",
+ "date": "2022-04-08T00:00:00.000Z",
"symbol": "NOVN.SW"
},
{
- "fee": 0,
+ "fee": 2.95,
"quantity": 2,
"type": "BUY",
"unitPrice": 75.8,
"currency": "CHF",
"dataSource": "YAHOO",
- "date": "2022-03-06T23:00:00.000Z",
+ "date": "2022-03-07T00:00:00.000Z",
"symbol": "NOVN.SW"
}
]
From ce6f175f9aede56a3f3aa6aece47c91e3b3205f0 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Wed, 16 Oct 2024 20:48:27 +0200
Subject: [PATCH 25/34] Bugfix/fix usage of processor portfolio snapshot
computation concurrency env variable (#3936)
* Fix usage of PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY
* Update changelog
---
CHANGELOG.md | 4 ++++
apps/api/src/app/admin/queue/queue.service.ts | 4 ++--
.../src/app/portfolio/calculator/portfolio-calculator.ts | 8 ++++----
.../portfolio-snapshot/portfolio-snapshot.module.ts | 4 ++--
.../portfolio-snapshot/portfolio-snapshot.processor.ts | 6 +++---
.../portfolio-snapshot/portfolio-snapshot.service.ts | 4 ++--
libs/common/src/lib/config.ts | 8 +++++---
7 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 23fcb46de..b67cd0f3e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,6 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Improved the usability to customize the rule thresholds in the _X-ray_ section by introducing units (experimental)
- Improved the language localization for German (`de`)
+### Fixed
+
+- Fixed the usage of the environment variable `PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY`
+
## 2.115.0 - 2024-10-14
### Added
diff --git a/apps/api/src/app/admin/queue/queue.service.ts b/apps/api/src/app/admin/queue/queue.service.ts
index 7e4f0adb7..b0058e81f 100644
--- a/apps/api/src/app/admin/queue/queue.service.ts
+++ b/apps/api/src/app/admin/queue/queue.service.ts
@@ -1,6 +1,6 @@
import {
DATA_GATHERING_QUEUE,
- PORTFOLIO_SNAPSHOT_QUEUE,
+ PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE,
QUEUE_JOB_STATUS_LIST
} from '@ghostfolio/common/config';
import { AdminJobs } from '@ghostfolio/common/interfaces';
@@ -14,7 +14,7 @@ export class QueueService {
public constructor(
@InjectQueue(DATA_GATHERING_QUEUE)
private readonly dataGatheringQueue: Queue,
- @InjectQueue(PORTFOLIO_SNAPSHOT_QUEUE)
+ @InjectQueue(PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE)
private readonly portfolioSnapshotQueue: Queue
) {}
diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
index 3d39b80b5..dec0e6387 100644
--- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
+++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts
@@ -15,8 +15,8 @@ import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'
import {
PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME,
PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS,
- PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_HIGH,
- PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_LOW
+ PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_HIGH,
+ PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW
} from '@ghostfolio/common/config';
import {
DATE_FORMAT,
@@ -1080,7 +1080,7 @@ export abstract class PortfolioCalculator {
opts: {
...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS,
jobId,
- priority: PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_LOW
+ priority: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW
}
});
}
@@ -1096,7 +1096,7 @@ export abstract class PortfolioCalculator {
opts: {
...PORTFOLIO_SNAPSHOT_PROCESS_JOB_OPTIONS,
jobId,
- priority: PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_HIGH
+ priority: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_HIGH
}
});
diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
index 058d971d8..958636334 100644
--- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
+++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.module.ts
@@ -10,7 +10,7 @@ import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-da
import { PortfolioSnapshotService } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service';
import {
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT,
- PORTFOLIO_SNAPSHOT_QUEUE
+ PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE
} from '@ghostfolio/common/config';
import { BullModule } from '@nestjs/bull';
@@ -23,7 +23,7 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor';
imports: [
AccountBalanceModule,
BullModule.registerQueue({
- name: PORTFOLIO_SNAPSHOT_QUEUE,
+ name: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE,
settings: {
lockDuration: parseInt(
process.env.PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_TIMEOUT ??
diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
index c66ef2a4c..c586a51b3 100644
--- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
+++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.processor.ts
@@ -11,7 +11,7 @@ import {
CACHE_TTL_INFINITE,
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY,
PORTFOLIO_SNAPSHOT_PROCESS_JOB_NAME,
- PORTFOLIO_SNAPSHOT_QUEUE
+ PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE
} from '@ghostfolio/common/config';
import { Process, Processor } from '@nestjs/bull';
@@ -22,7 +22,7 @@ import { addMilliseconds } from 'date-fns';
import { IPortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue-job.interface';
@Injectable()
-@Processor(PORTFOLIO_SNAPSHOT_QUEUE)
+@Processor(PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE)
export class PortfolioSnapshotProcessor {
public constructor(
private readonly accountBalanceService: AccountBalanceService,
@@ -34,7 +34,7 @@ export class PortfolioSnapshotProcessor {
@Process({
concurrency: parseInt(
- process.env.PROCESSOR_CONCURRENCY_PORTFOLIO_SNAPSHOT ??
+ process.env.PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY ??
DEFAULT_PROCESSOR_PORTFOLIO_SNAPSHOT_COMPUTATION_CONCURRENCY.toString(),
10
),
diff --git a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.ts b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.ts
index 27ebdee53..9dba9275e 100644
--- a/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.ts
+++ b/apps/api/src/services/queues/portfolio-snapshot/portfolio-snapshot.service.ts
@@ -1,4 +1,4 @@
-import { PORTFOLIO_SNAPSHOT_QUEUE } from '@ghostfolio/common/config';
+import { PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE } from '@ghostfolio/common/config';
import { InjectQueue } from '@nestjs/bull';
import { Injectable } from '@nestjs/common';
@@ -9,7 +9,7 @@ import { IPortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queu
@Injectable()
export class PortfolioSnapshotService {
public constructor(
- @InjectQueue(PORTFOLIO_SNAPSHOT_QUEUE)
+ @InjectQueue(PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE)
private readonly portfolioSnapshotQueue: Queue
) {}
diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts
index 87b348b26..4580ef4df 100644
--- a/libs/common/src/lib/config.ts
+++ b/libs/common/src/lib/config.ts
@@ -40,9 +40,11 @@ export const DATA_GATHERING_QUEUE_PRIORITY_MEDIUM = Math.round(
DATA_GATHERING_QUEUE_PRIORITY_LOW / 2
);
-export const PORTFOLIO_SNAPSHOT_QUEUE = 'PORTFOLIO_SNAPSHOT_QUEUE';
-export const PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_HIGH = 1;
-export const PORTFOLIO_SNAPSHOT_QUEUE_PRIORITY_LOW = Number.MAX_SAFE_INTEGER;
+export const PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE =
+ 'PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE';
+export const PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_HIGH = 1;
+export const PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE_PRIORITY_LOW =
+ Number.MAX_SAFE_INTEGER;
export const DEFAULT_CURRENCY = 'USD';
export const DEFAULT_DATE_FORMAT_MONTH_YEAR = 'MMM yyyy';
From 04b056e4e5c71dc4695ce92cb31d9db534d8320f Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Wed, 16 Oct 2024 20:51:18 +0200
Subject: [PATCH 26/34] Feature/switch to adjusted market prices in get
historical of eod historical data service (#3934)
* Switch to adjusted market prices in getHistorical()
* Update changelog
---
CHANGELOG.md | 1 +
.../eod-historical-data/eod-historical-data.service.ts | 6 +++---
2 files changed, 4 insertions(+), 3 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b67cd0f3e..afb2151e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Disabled the text hover effect in the chart of the holdings tab on the home page (experimental)
- Improved the usability to customize the rule thresholds in the _X-ray_ section by introducing units (experimental)
+- Switched to adjusted market prices (splits and dividends) in the get historical functionality of the _EOD Historical Data_ service
- Improved the language localization for German (`de`)
### Fixed
diff --git a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts
index 3a840340e..78325d447 100644
--- a/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts
+++ b/apps/api/src/services/data-provider/eod-historical-data/eod-historical-data.service.ts
@@ -163,10 +163,10 @@ export class EodHistoricalDataService implements DataProviderInterface {
).json();
return response.reduce(
- (result, { close, date }) => {
- if (isNumber(close)) {
+ (result, { adjusted_close, date }) => {
+ if (isNumber(adjusted_close)) {
result[this.convertFromEodSymbol(symbol)][date] = {
- marketPrice: close
+ marketPrice: adjusted_close
};
} else {
Logger.error(
From d5fb32fb52ed1374de892559c2ef92c7bfcf10d1 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Wed, 16 Oct 2024 21:19:38 +0200
Subject: [PATCH 27/34] Feature/extend self hosting faq by benchmarks (#3937)
* Extend FAQ by benchmarks
* Update changelog
---
CHANGELOG.md | 1 +
.../faq/self-hosting/self-hosting-page.html | 38 ++++++++++++++-----
2 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index afb2151e5..e15dbf994 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
+- Extended the content of the _Self-Hosting_ section by the benchmarks concept on the Frequently Asked Questions (FAQ) page
- Set the permissions (`chmod 0700`) on `entrypoint.sh` in the `Dockerfile`
### Changed
diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html
index 96da35ca9..ac8eddc48 100644
--- a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html
+++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html
@@ -51,8 +51,8 @@
manually enter it.
- Go to the Admin Control panel
- Go to the Market Data section
+ Open the Admin Control panel
+ Navigate to the Market Data section
Click on the + button
Switch to Add Currency
Insert e.g. EUR
for Euro
@@ -78,8 +78,8 @@
do the following:
- Go to the Admin Control panel
- Go to the Market Data section
+ Open the Admin Control panel
+ Navigate to the Market Data section
Select Filter by Currencies
Find the entry USDEUR
@@ -105,8 +105,8 @@
- Go to the Admin Control panel
- Go to the Settings section
+ Open the Admin Control panel
+ Navigate to the Settings section
Click on the Add Platform button
@@ -117,8 +117,8 @@
- Go to the Admin Control panel
- Go to the Settings section
+ Open the Admin Control panel
+ Navigate to the Settings section
Click on the Add Tag button
@@ -133,6 +133,24 @@
providers are considered experimental.
+
+
+ How do I set up a benchmark?
+
+
+
+ To compare your performance with benchmarks like
+ Bitcoin , Gold , or the S&P 500 , follow these
+ steps.
+
+
+ Open the Admin Control panel
+ Navigate to the Market Data section
+ Choose an asset profile
+ In the dialog, check the Benchmark box
+
+
+
How do I add a custom asset?
@@ -143,8 +161,8 @@
provider, you can create a custom asset as follows.
- Go to the Admin Control panel
- Go to the Market Data section
+ Open the Admin Control panel
+ Navigate to the Market Data section
Create an asset profile
Select Add Manually and enter a unique symbol
Edit your asset profile
From 7f304247929d65f9665a6f35e618b577c6ff4468 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 17 Oct 2024 14:13:02 +0200
Subject: [PATCH 28/34] Feature/improve empty state in benchmarks of markets
overview (#3939)
* Improve empty state
* Update changelog
---
CHANGELOG.md | 1 +
.../home-market/home-market.component.ts | 3 ---
.../app/components/home-market/home-market.html | 10 ----------
.../components/home-market/home-market.module.ts | 4 +---
.../ui/src/lib/benchmark/benchmark.component.html | 15 +++++++++++++++
libs/ui/src/lib/benchmark/benchmark.component.ts | 5 +++++
6 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e15dbf994..852e4576e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
+- Improved the empty state in the benchmarks of the markets overview
- Disabled the text hover effect in the chart of the holdings tab on the home page (experimental)
- Improved the usability to customize the rule thresholds in the _X-ray_ section by introducing units (experimental)
- Switched to adjusted market prices (splits and dividends) in the get historical functionality of the _EOD Historical Data_ service
diff --git a/apps/client/src/app/components/home-market/home-market.component.ts b/apps/client/src/app/components/home-market/home-market.component.ts
index 3a42a9ebc..3480eaeb7 100644
--- a/apps/client/src/app/components/home-market/home-market.component.ts
+++ b/apps/client/src/app/components/home-market/home-market.component.ts
@@ -29,7 +29,6 @@ export class HomeMarketComponent implements OnDestroy, OnInit {
public hasPermissionToAccessFearAndGreedIndex: boolean;
public historicalDataItems: HistoricalDataItem[];
public info: InfoItem;
- public isLoading = true;
public readonly numberOfDays = 365;
public user: User;
@@ -43,7 +42,6 @@ export class HomeMarketComponent implements OnDestroy, OnInit {
) {
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
this.info = this.dataService.fetchInfo();
- this.isLoading = true;
this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject))
@@ -89,7 +87,6 @@ export class HomeMarketComponent implements OnDestroy, OnInit {
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ benchmarks }) => {
this.benchmarks = benchmarks;
- this.isLoading = false;
this.changeDetectorRef.markForCheck();
});
diff --git a/apps/client/src/app/components/home-market/home-market.html b/apps/client/src/app/components/home-market/home-market.html
index c362fdd18..2fcdb5716 100644
--- a/apps/client/src/app/components/home-market/home-market.html
+++ b/apps/client/src/app/components/home-market/home-market.html
@@ -36,16 +36,6 @@
[locale]="user?.settings?.locale || undefined"
[user]="user"
/>
- @if (isLoading) {
-
- }
diff --git a/apps/client/src/app/components/home-market/home-market.module.ts b/apps/client/src/app/components/home-market/home-market.module.ts
index bc35b4bef..b8e6582a5 100644
--- a/apps/client/src/app/components/home-market/home-market.module.ts
+++ b/apps/client/src/app/components/home-market/home-market.module.ts
@@ -4,7 +4,6 @@ import { GfLineChartComponent } from '@ghostfolio/ui/line-chart';
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
-import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { HomeMarketComponent } from './home-market.component';
@@ -15,8 +14,7 @@ import { HomeMarketComponent } from './home-market.component';
CommonModule,
GfBenchmarkComponent,
GfFearAndGreedIndexModule,
- GfLineChartComponent,
- NgxSkeletonLoaderModule
+ GfLineChartComponent
],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
diff --git a/libs/ui/src/lib/benchmark/benchmark.component.html b/libs/ui/src/lib/benchmark/benchmark.component.html
index ec92554de..8867e1c9e 100644
--- a/libs/ui/src/lib/benchmark/benchmark.component.html
+++ b/libs/ui/src/lib/benchmark/benchmark.component.html
@@ -122,3 +122,18 @@
"
>
+
+@if (isLoading) {
+
+} @else if (benchmarks?.length === 0) {
+
+ No data available
+
+}
diff --git a/libs/ui/src/lib/benchmark/benchmark.component.ts b/libs/ui/src/lib/benchmark/benchmark.component.ts
index 764d65c2c..22bc9a128 100644
--- a/libs/ui/src/lib/benchmark/benchmark.component.ts
+++ b/libs/ui/src/lib/benchmark/benchmark.component.ts
@@ -49,6 +49,7 @@ export class GfBenchmarkComponent implements OnChanges, OnDestroy {
@Input() user: User;
public displayedColumns = ['name', 'date', 'change', 'marketCondition'];
+ public isLoading = true;
public resolveMarketCondition = resolveMarketCondition;
public translate = translate;
@@ -76,6 +77,10 @@ export class GfBenchmarkComponent implements OnChanges, OnDestroy {
}
public ngOnChanges() {
+ if (this.benchmarks) {
+ this.isLoading = false;
+ }
+
if (this.user?.settings?.isExperimentalFeatures) {
this.displayedColumns = [
'name',
From 6e490e5710b443fbc331adbd6142da8a2cd4bf88 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 17 Oct 2024 14:15:52 +0200
Subject: [PATCH 29/34] Feature/extend self hosting faq by benchmarks for
markets (#3940)
* Extend FAQ by benchmarks for Markets
* Update changelog
---
CHANGELOG.md | 3 ++-
.../faq/self-hosting/self-hosting-page.html | 24 ++++++++++++++++---
2 files changed, 23 insertions(+), 4 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 852e4576e..4d9ece4ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
-- Extended the content of the _Self-Hosting_ section by the benchmarks concept on the Frequently Asked Questions (FAQ) page
+- Extended the content of the _Self-Hosting_ section by the benchmarks concept for _Compare with..._ on the Frequently Asked Questions (FAQ) page
+- Extended the content of the _Self-Hosting_ section by the benchmarks concept for _Markets_ on the Frequently Asked Questions (FAQ) page
- Set the permissions (`chmod 0700`) on `entrypoint.sh` in the `Dockerfile`
### Changed
diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html
index ac8eddc48..7538678c3 100644
--- a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html
+++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html
@@ -139,9 +139,9 @@
- To compare your performance with benchmarks like
- Bitcoin , Gold , or the S&P 500 , follow these
- steps.
+ To compare your performance with benchmarks (see
+ Compare with... ) like Bitcoin , Gold , or the
+ S&P 500 , follow these steps.
Open the Admin Control panel
@@ -170,6 +170,24 @@
+
+
+ How do I set up Markets ?
+
+
+ The Markets list is derived from your Benchmarks .
+
+ Open the Admin Control panel
+ Navigate to the Market Data section
+ Choose an asset profile
+ In the dialog, check the Benchmark box
+
+
+ Please note: Data is cached, meaning changes may take a few minutes
+ to appear.
+
+
+
Which devices are supported?
From cfd5b6bbf2376aa97181f051fff3b92ac46702f2 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 17 Oct 2024 17:46:03 +0200
Subject: [PATCH 30/34] Release 2.116.0 (#3942)
---
CHANGELOG.md | 2 +-
package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4d9ece4ee..c369e5905 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## Unreleased
+## 2.116.0 - 2024-10-17
### Added
diff --git a/package.json b/package.json
index 9dc6666ab..3e405ef31 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ghostfolio",
- "version": "2.115.0",
+ "version": "2.116.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"repository": "https://github.com/ghostfolio/ghostfolio",
From ba52e385a16c1525d6a50824570002e36a8ae84d Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 17 Oct 2024 20:42:24 +0200
Subject: [PATCH 31/34] Feature/extend personal finance tools 20241017 (#3944)
* Add Leafs
* Add FIREkit
---
libs/common/src/lib/personal-finance-tools.ts | 20 +++++++++++++++++++
libs/ui/src/lib/i18n.ts | 1 +
2 files changed, 21 insertions(+)
diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts
index b5aeed19d..7378fbcd4 100644
--- a/libs/common/src/lib/personal-finance-tools.ts
+++ b/libs/common/src/lib/personal-finance-tools.ts
@@ -250,6 +250,17 @@ export const personalFinanceTools: Product[] = [
pricingPerYear: '€69.99',
slogan: 'Personal finances, simplified'
},
+ {
+ founded: 2021,
+ hasFreePlan: true,
+ hasSelfHostingAbility: false,
+ key: 'firekit',
+ languages: ['English', 'українська мова'],
+ name: 'FIREkit',
+ origin: 'Ukraine',
+ pricingPerYear: '$40',
+ slogan: 'A simple solution to track your wealth online'
+ },
{
hasFreePlan: true,
hasSelfHostingAbility: false,
@@ -337,6 +348,15 @@ export const personalFinanceTools: Product[] = [
pricingPerYear: '$150',
slogan: 'The Time Machine for your Net Worth'
},
+ {
+ founded: 2021,
+ hasFreePlan: false,
+ key: 'leafs',
+ languages: ['Deutsch', 'English'],
+ name: 'Leafs',
+ origin: 'Switzerland',
+ slogan: 'Sustainability insights for wealth managers'
+ },
{
founded: 2018,
hasFreePlan: false,
diff --git a/libs/ui/src/lib/i18n.ts b/libs/ui/src/lib/i18n.ts
index a98cbd704..46a8cd0fa 100644
--- a/libs/ui/src/lib/i18n.ts
+++ b/libs/ui/src/lib/i18n.ts
@@ -88,6 +88,7 @@ const locales = {
'South Africa': $localize`South Africa`,
Switzerland: $localize`Switzerland`,
Thailand: $localize`Thailand`,
+ Ukraine: $localize`Ukraine`,
'United States': $localize`United States`,
// Fear and Greed Index
From a9d26b319d633d9755659b4cc6f49513811be642 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Thu, 17 Oct 2024 20:42:59 +0200
Subject: [PATCH 32/34] Feature/Format database schema (#3943)
* Format
---
prisma/schema.prisma | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 0ae1df65a..9fa550762 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -193,9 +193,9 @@ model SymbolProfileOverrides {
holdings Json? @default("[]")
name String?
sectors Json? @default("[]")
- url String?
symbolProfileId String @id
updatedAt DateTime @updatedAt
+ url String?
SymbolProfile SymbolProfile @relation(fields: [symbolProfileId], onDelete: Cascade, references: [id])
}
@@ -239,7 +239,7 @@ model User {
Order Order[]
Settings Settings?
Subscription Subscription[]
- Tag Tag[]
+ Tag Tag[]
@@index([accessToken])
@@index([createdAt])
From d59dfc3d5bc2ae085226af12c960b96c7af143c7 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Sat, 19 Oct 2024 10:04:10 +0200
Subject: [PATCH 33/34] Feature/Archive discontinued personal finance tools
(#3945)
* Archive discontinued personal finance tools
---
libs/common/src/lib/personal-finance-tools.ts | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts
index 7378fbcd4..1ec5fbbc2 100644
--- a/libs/common/src/lib/personal-finance-tools.ts
+++ b/libs/common/src/lib/personal-finance-tools.ts
@@ -115,6 +115,7 @@ export const personalFinanceTools: Product[] = [
},
{
founded: 2022,
+ isArchived: true,
key: 'capmon',
name: 'CapMon.org',
origin: 'Germany',
@@ -303,6 +304,7 @@ export const personalFinanceTools: Product[] = [
{
hasFreePlan: true,
hasSelfHostingAbility: false,
+ isArchived: true,
key: 'intuit-mint',
name: 'Intuit Mint',
note: 'Intuit Mint was discontinued in 2023',
@@ -413,6 +415,7 @@ export const personalFinanceTools: Product[] = [
{
founded: 1991,
hasSelfHostingAbility: true,
+ isArchived: true,
key: 'microsoft-money',
name: 'Microsoft Money',
note: 'Microsoft Money was discontinued in 2010',
@@ -520,6 +523,7 @@ export const personalFinanceTools: Product[] = [
},
{
hasFreePlan: true,
+ isArchived: true,
key: 'portfoloo',
name: 'Portfoloo',
note: 'Portfoloo was discontinued',
@@ -558,6 +562,7 @@ export const personalFinanceTools: Product[] = [
{
founded: 2019,
hasSelfHostingAbility: false,
+ isArchived: true,
key: 'sarmaaya.pk',
name: 'Sarmaaya.pk Portfolio Tracking',
note: 'Sarmaaya.pk Portfolio Tracking was discontinued in 2024',
@@ -594,6 +599,7 @@ export const personalFinanceTools: Product[] = [
},
{
hasFreePlan: true,
+ isArchived: true,
key: 'sharesmaster',
name: 'SharesMaster',
note: 'SharesMaster was discontinued',
@@ -634,6 +640,7 @@ export const personalFinanceTools: Product[] = [
},
{
founded: 2008,
+ isArchived: true,
key: 'stockmarketeye',
name: 'StockMarketEye',
origin: 'France',
@@ -746,6 +753,7 @@ export const personalFinanceTools: Product[] = [
founded: 2021,
hasFreePlan: true,
hasSelfHostingAbility: false,
+ isArchived: true,
key: 'yeekatee',
languages: ['Deutsch', 'English', 'Español', 'Français', 'Italiano'],
name: 'yeekatee',
From 6bb7c0d19602806856f73f30a7b6d9b34d5f9326 Mon Sep 17 00:00:00 2001
From: Thomas Kaul <4159106+dtslvr@users.noreply.github.com>
Date: Sat, 19 Oct 2024 10:04:27 +0200
Subject: [PATCH 34/34] Bugfix/fix style selector in carousel component (#3948)
* Fix style selector
* Update changelog
---
CHANGELOG.md | 6 ++++++
libs/ui/src/lib/carousel/carousel.component.scss | 2 +-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c369e5905..e08f74559 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## Unreleased
+
+### Fixed
+
+- Fixed an issue in the carousel component for the testimonial section on the landing page
+
## 2.116.0 - 2024-10-17
### Added
diff --git a/libs/ui/src/lib/carousel/carousel.component.scss b/libs/ui/src/lib/carousel/carousel.component.scss
index 546c92194..05ab9ff93 100644
--- a/libs/ui/src/lib/carousel/carousel.component.scss
+++ b/libs/ui/src/lib/carousel/carousel.component.scss
@@ -3,7 +3,7 @@
position: relative;
::ng-deep {
- [gf-carousel-item] {
+ [gfCarouselItem] {
flex-shrink: 0;
width: 100%;
}