diff --git a/.github/workflows/build-code.yml b/.github/workflows/build-code.yml index 7a8f72ac4..bd5d1efdc 100644 --- a/.github/workflows/build-code.yml +++ b/.github/workflows/build-code.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: node_version: - - 22 + - 22.22.1 steps: - name: Checkout code uses: actions/checkout@v4 diff --git a/.vscode/extensions.json b/.vscode/extensions.json index fde9874a2..68abade5f 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,8 +1,8 @@ { "recommendations": [ "angular.ng-template", + "esbenp.prettier-vscode", "firsttris.vscode-jest-runner", - "nrwl.angular-console", - "prettier.prettier-vscode" + "nrwl.angular-console" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 36091af85..9bf4d12b5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,4 @@ { - "editor.defaultFormatter": "prettier.prettier-vscode", + "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave": true } diff --git a/CHANGELOG.md b/CHANGELOG.md index dd6f29fe2..09fa18ca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,318 @@ 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.250.0 - 2026-03-17 + +### Added + +- Added support for specific calendar year date ranges (`2025`, `2024`, `2023`, etc.) on the portfolio activities page + +### Changed + +- Consolidated the sign-out logic within the user service to unify cookie, state and token clearance +- Improved the language localization for Polish (`pl`) +- Upgraded `@ionic/angular` from version `8.7.3` to `8.8.1` +- Upgraded `replace-in-file` from version `8.3.0` to `8.4.0` +- Upgraded `svgmap` from version `2.14.0` to `2.19.2` +- Pinned the _Node.js_ version in the _Build code_ _GitHub Action_ to ensure environment consistency for tests + +### Fixed + +- Fixed an issue with the detection of the thousand separator for the `de-CH` locale +- Fixed an issue in the _Storybook_ stories of the symbol autocomplete component caused by a circular dependency + +## 2.249.0 - 2026-03-10 + +### Added + +- Integrated _Bull Dashboard_ for a detailed jobs queue view in the admin control panel (experimental) +- Added a debounce to the `PortfolioChangedListener` and `AssetProfileChangedListener` to minimize redundant _Redis_ and database operations + +### Changed + +- Improved the _Storybook_ stories of the value component +- Improved the language localization for Dutch (`nl`) +- Improved the language localization for German (`de`) +- Upgraded `class-validator` from version `0.14.3` to `0.15.1` + +### Fixed + +- Fixed false _Redis_ health check failures by using unique keys and increasing the timeout to 5s + +## 2.248.0 - 2026-03-07 + +### Added + +- Added support for column sorting to the data providers management of the admin control panel + +### Changed + +- Included asset profile data in the endpoint `GET api/v1/portfolio/holdings` +- Included asset profile data in the holdings of the public page +- Reused the value component in the platform management of the admin control panel +- Reused the value component in the tag management of the admin control panel +- Deprecated the `api/v1/order` endpoints in favor of the `api/v1/activities` endpoints +- Upgraded `jsonpath` from version `1.1.1` to `1.2.1` + +### Fixed + +- Fixed an issue in the _FIRE_ calculator to correctly calculate the projected total amount + +## 2.247.0 - 2026-03-04 + +### Changed + +- Upgraded `yahoo-finance2` from version `3.13.0` to `3.13.2` + +## 2.246.0 - 2026-03-03 + +### Changed + +- Removed the deprecated `committedFunds` from the summary of the portfolio details endpoint +- Upgraded `Nx` from version `22.4.5` to `22.5.3` + +### Fixed + +- Fixed an issue where the apply and reset filter buttons remained disabled in the assistant + +## 2.245.0 - 2026-03-01 + +### Changed + +- Excluded the scraper configuration from the import and export functionality +- Excluded the symbol mapping from the import and export functionality +- Improved the language localization for Dutch (`nl`) +- Improved the language localization for Italian (`it`) +- Improved the language localization for Spanish (`es`) + +### Fixed + +- Resolved the data source transformation in the errors of the performance endpoint +- Resolved the data source transformation in the export functionality + +## 2.244.0 - 2026-02-28 + +### Changed + +- Improved the usability of the asset profile details dialog in the admin control panel for currencies +- Removed the deprecated static portfolio analysis rule: _Fees_ (Fee Ratio) +- Refactored queries in the data provider service to use Prisma’s safe query methods + +### Fixed + +- Fixed an exception by adding a fallback for missing market price values on the _X-ray_ page + +## 2.243.0 - 2026-02-23 + +### Changed + +- Improved the language localization for Chinese (`zh`) +- Upgraded `nestjs` from version `11.1.8` to `11.1.14` + +### Fixed + +- Fixed an issue when creating activities of type `FEE`, `INTEREST` or `LIABILITY` + +## 2.242.0 - 2026-02-22 + +### Changed + +- Changed the account field to optional in the create or update activity dialog + +### Fixed + +- Fixed a validation issue for valuables used in the create and import activity logic +- Fixed the page size for presets in the historical market data table of the admin control panel + +## 2.241.0 - 2026-02-21 + +### Changed + +- Improved the usability of the portfolio summary tab on the home page in the _Presenter View_ +- Refreshed the cryptocurrencies list +- Improved the language localization for German (`de`) +- Improved the language localization for Spanish (`es`) + +### Fixed + +- Fixed an issue with `balanceInBaseCurrency` of the accounts in the value redaction interceptor for the impersonation mode +- Fixed an issue with `comment` of the accounts in the value redaction interceptor for the impersonation mode +- Fixed an issue with `dividendInBaseCurrency` of the accounts in the value redaction interceptor for the impersonation mode +- Fixed an issue with `interestInBaseCurrency` of the accounts in the value redaction interceptor for the impersonation mode +- Fixed an issue with `value` of the accounts in the value redaction interceptor for the impersonation mode + +## 2.240.0 - 2026-02-18 + +### Added + +- Added a _No Activities_ preset to the historical market data table of the admin control panel +- Added support for custom cryptocurrencies defined in the database +- Added support for the cryptocurrency _Sky_ + +### Changed + +- Harmonized the validation for the create activity endpoint with the existing import activity logic +- Upgraded `marked` from version `17.0.1` to `17.0.2` +- Upgraded `ngx-markdown` from version `21.0.1` to `21.1.0` + +## 2.239.0 - 2026-02-15 + +### Added + +- Added a new static portfolio analysis rule based on the total investment volume: _Fees_ (Fee Ratio) +- Extended the content of the _Self-Hosting_ section on the Frequently Asked Questions (FAQ) page with information on derived currencies + +### Changed + +- Deprecated the existing static portfolio analysis rule: _Fees_ (Fee Ratio) +- Ignored nested ETFs when fetching top holdings for ETF and mutual fund assets from _Yahoo Finance_ +- Improved the scraper configuration with more detailed error messages +- Improved the language localization for German (`de`) +- Upgraded `@simplewebauthn/browser` and `@simplewebauthn/server` from version `13.1.0` to `13.2.2` +- Upgraded `cheerio` from version `1.0.0` to `1.2.0` + +### Fixed + +- Fixed the investment value by including currency effects in the portfolio summary tab on the home page +- Added the missing `valueInBaseCurrency` to the response of the import activities endpoint + +## 2.238.0 - 2026-02-12 + +### Changed + +- Upgraded `ngx-skeleton-loader` from version `11.3.0` to `12.0.0` +- Upgraded `twitter-api-v2` from version `1.27.0` to `1.29.0` + +### Fixed + +- Fixed a performance calculation issue by resetting tracking variables when a holding is fully closed +- Fixed an issue in the annualized performance calculation +- Fixed an issue with the exchange rate calculation by expanding the date range to cover the full day (start to end of day) + +## 2.237.0 - 2026-02-08 + +### Changed + +- Removed the deprecated `transactionCount` in the portfolio calculator and service +- Refreshed the cryptocurrencies list +- Upgraded `Nx` from version `22.4.1` to `22.4.5` + +### Fixed + +- Fixed the accounts of the assistant for the impersonation mode +- Fixed the tags of the assistant for the impersonation mode + +## 2.236.0 - 2026-02-05 + +### Changed + +- Removed the deprecated `transactionCount` in the endpoint `GET api/v1/admin` +- Upgraded `stripe` from version `20.1.0` to `20.3.0` + +### Fixed + +- Fixed an exception when fetching the top holdings for ETF and mutual fund assets from _Yahoo Finance_ + +## 2.235.0 - 2026-02-03 + +### Added + +- Added the ability to fetch top holdings for ETF and mutual fund assets from _Yahoo Finance_ +- Added support for the impersonation mode in the endpoint `GET api/v1/account/:id/balances` +- Added an action menu to the user detail dialog in the users section of the admin control panel + +### Changed + +- Optimized the value redaction interceptor for the impersonation mode by introducing `fast-redact` +- Refactored `showTransactions` in favor of `showActivitiesCount` in the accounts table component +- Refactored `transactionCount` in favor of `activitiesCount` in the accounts table component +- Deprecated `transactionCount` in favor of `activitiesCount` in the endpoint `GET api/v1/admin` +- Removed the deprecated `firstBuyDate` in the portfolio calculator +- Upgraded `yahoo-finance2` from version `3.11.2` to `3.13.0` + +## 2.234.0 - 2026-01-30 + +### Changed + +- Improved the usability of the create asset profile dialog in the market data section of the admin control panel +- Improved the language localization for Chinese (`zh`) +- Improved the language localization for German (`de`) +- Improved the language localization for Spanish (`es`) +- Upgraded `angular` from version `21.0.6` to `21.1.1` +- Upgraded `lodash` from version `4.17.21` to `4.17.23` +- Upgraded `Nx` from version `22.3.3` to `22.4.1` +- Upgraded `prettier` from version `3.8.0` to `3.8.1` + +## 2.233.0 - 2026-01-23 + +### Changed + +- Deprecated `firstBuyDate` in favor of `dateOfFirstActivity` in the portfolio calculator +- Deprecated `transactionCount` in favor of `activitiesCount` in the portfolio calculator and service +- Removed the deprecated `firstBuyDate` from the endpoint `GET api/v1/portfolio/holding/:dataSource/:symbol` +- Refreshed the cryptocurrencies list +- Upgraded `prettier` from version `3.7.4` to `3.8.0` + +## 2.232.0 - 2026-01-19 + +### Added + +- Extended the analysis page to include the total amount, change and performance with currency effects (experimental) + +### Changed + +- Deprecated `firstBuyDate` in favor of `dateOfFirstActivity` in the endpoint `GET api/v1/portfolio/holding/:dataSource/:symbol` +- Improved the language localization for German (`de`) +- Upgraded `countries-list` from version `3.2.0` to `3.2.2` + +## 2.231.0 - 2026-01-17 + +### Changed + +- Removed the deprecated platforms from the info service +- Removed the deprecated activities from the endpoint `GET api/v1/portfolio/holding/:dataSource/:symbol` + +### Fixed + +- Fixed a numeric parsing error related to cash positions on the _X-ray_ page +- Fixed the total fee calculation in the holding detail dialog related to activities in a custom currency +- Fixed the total fee calculation in the summary related to activities in a custom currency + +## 2.230.0 - 2026-01-14 + +### Added + +- Set up the language localization for Korean (`ko`) + +### Changed + +- Restored the support for specific calendar year date ranges (`2024`, `2023`, `2022`, etc.) in the holdings table (experimental) + +### Fixed + +- Fixed the total fee calculation in the holding detail dialog related to activities in a custom currency +- Fixed the total fee calculation in the summary related to activities in a custom currency + +## 2.229.0 - 2026-01-11 + +### Changed + +- Set the active sort column in the accounts table component +- Deprecated `activities` in the endpoint `GET api/v1/portfolio/holding/:dataSource/:symbol` +- Moved the admin service to `@ghostfolio/ui/services` +- Moved the data service to `@ghostfolio/ui/services` +- Refactored the dividend import +- Refreshed the cryptocurrencies list + +### Fixed + +- Fixed the net worth calculation to prevent the double counting of cash positions +- Fixed the filtering by asset class in the endpoint `GET api/v1/portfolio/holdings` +- Fixed the case-insensitive sorting in the accounts table component +- Fixed the case-insensitive sorting in the benchmark component +- Fixed the case-insensitive sorting in the holdings table component + +## 2.228.0 - 2026-01-03 ### Added @@ -17,6 +328,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Integrated the endpoint to get all platforms (`GET api/v1/platforms`) into the create or update account dialog - Extracted the scraper configuration to a dedicated tab in the asset profile details dialog of the admin control panel - Improved the language localization for German (`de`) +- Upgraded `@date-fns/utc` from version `2.1.0` to `2.1.1` + +### Fixed + +- Improved the table headers’ alignment of the accounts table on mobile ## 2.227.0 - 2026-01-02 diff --git a/README.md b/README.md index 35276b232..44212b607 100644 --- a/README.md +++ b/README.md @@ -85,31 +85,32 @@ We provide official container images hosted on [Docker Hub](https://hub.docker.c ### Supported Environment Variables -| Name | Type | Default Value | Description | -| ------------------------ | --------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| `ACCESS_TOKEN_SALT` | `string` | | A random string used as salt for access tokens | -| `API_KEY_COINGECKO_DEMO` | `string` (optional) |   | The _CoinGecko_ Demo API key | -| `API_KEY_COINGECKO_PRO` | `string` (optional) | | The _CoinGecko_ Pro API key | -| `DATABASE_URL` | `string` | | The database connection URL, e.g. `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer` | -| `HOST` | `string` (optional) | `0.0.0.0` | The host where the Ghostfolio application will run on | -| `JWT_SECRET_KEY` | `string` | | A random string used for _JSON Web Tokens_ (JWT) | -| `LOG_LEVELS` | `string[]` (optional) | | The logging levels for the Ghostfolio application, e.g. `["debug","error","log","warn"]` | -| `PORT` | `number` (optional) | `3333` | The port where the Ghostfolio application will run on | -| `POSTGRES_DB` | `string` | | The name of the _PostgreSQL_ database | -| `POSTGRES_PASSWORD` | `string` | | The password of the _PostgreSQL_ database | -| `POSTGRES_USER` | `string` | | The user of the _PostgreSQL_ database | -| `REDIS_DB` | `number` (optional) | `0` | The database index of _Redis_ | -| `REDIS_HOST` | `string` | | The host where _Redis_ is running | -| `REDIS_PASSWORD` | `string` | | The password of _Redis_ | -| `REDIS_PORT` | `number` | | The port where _Redis_ is running | -| `REQUEST_TIMEOUT` | `number` (optional) | `2000` | The timeout of network requests to data providers in milliseconds | -| `ROOT_URL` | `string` (optional) | `http://0.0.0.0:3333` | The root URL of the Ghostfolio application, used for generating callback URLs and external links. | +| Name | Type | Default Value | Description | +| --------------------------- | --------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| `ACCESS_TOKEN_SALT` | `string` | | A random string used as salt for access tokens | +| `API_KEY_COINGECKO_DEMO` | `string` (optional) |   | The _CoinGecko_ Demo API key | +| `API_KEY_COINGECKO_PRO` | `string` (optional) | | The _CoinGecko_ Pro API key | +| `DATABASE_URL` | `string` | | The database connection URL, e.g. `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}?sslmode=prefer` | +| `ENABLE_FEATURE_AUTH_TOKEN` | `boolean` (optional) | `true` | Enables authentication via security token | +| `HOST` | `string` (optional) | `0.0.0.0` | The host where the Ghostfolio application will run on | +| `JWT_SECRET_KEY` | `string` | | A random string used for _JSON Web Tokens_ (JWT) | +| `LOG_LEVELS` | `string[]` (optional) | | The logging levels for the Ghostfolio application, e.g. `["debug","error","log","warn"]` | +| `PORT` | `number` (optional) | `3333` | The port where the Ghostfolio application will run on | +| `POSTGRES_DB` | `string` | | The name of the _PostgreSQL_ database | +| `POSTGRES_PASSWORD` | `string` | | The password of the _PostgreSQL_ database | +| `POSTGRES_USER` | `string` | | The user of the _PostgreSQL_ database | +| `REDIS_DB` | `number` (optional) | `0` | The database index of _Redis_ | +| `REDIS_HOST` | `string` | | The host where _Redis_ is running | +| `REDIS_PASSWORD` | `string` | | The password of _Redis_ | +| `REDIS_PORT` | `number` | | The port where _Redis_ is running | +| `REQUEST_TIMEOUT` | `number` (optional) | `2000` | The timeout of network requests to data providers in milliseconds | +| `ROOT_URL` | `string` (optional) | `http://0.0.0.0:3333` | The root URL of the Ghostfolio application, used for generating callback URLs and external links. | #### OpenID Connect OIDC (Experimental) | Name | Type | Default Value | Description | | -------------------------- | --------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------- | -| `ENABLE_FEATURE_AUTH_OIDC` | `boolean` (optional) | `false` | Enables _OpenID Connect_ authentication | +| `ENABLE_FEATURE_AUTH_OIDC` | `boolean` (optional) | `false` | Enables authentication via _OpenID Connect_ | | `OIDC_AUTHORIZATION_URL` | `string` (optional) | | Manual override for the OIDC authorization endpoint (falls back to the discovery from the issuer) | | `OIDC_CALLBACK_URL` | `string` (optional) | `${ROOT_URL}/api/auth/oidc/callback` | The OIDC callback URL | | `OIDC_CLIENT_ID` | `string` | | The OIDC client ID | @@ -312,17 +313,16 @@ Ghostfolio is **100% free** and **open source**. We encourage and support an act Not sure what to work on? We have [some ideas](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22%20no%3Aassignee), even for [newcomers](https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22%20no%3Aassignee). Please join the Ghostfolio [Slack](https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg) channel or post to [@ghostfolio\_](https://x.com/ghostfolio_) on _X_. We would love to hear from you. -If you like to support this project, become a [**Sponsor**](https://github.com/sponsors/ghostfolio), get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio). - ## Sponsors +If you like to support this project, get [**Ghostfolio Premium**](https://ghostfol.io/en/pricing), become a [**Sponsor**](https://github.com/sponsors/ghostfolio) or [**Buy me a coffee**](https://www.buymeacoffee.com/ghostfolio). + +
+
-

- Browser testing via
- - LambdaTest Logo - -

+ + TestMu AI Logo +
## Analytics diff --git a/apps/api/src/app/account/account.controller.ts b/apps/api/src/app/account/account.controller.ts index 542b199fd..052720176 100644 --- a/apps/api/src/app/account/account.controller.ts +++ b/apps/api/src/app/account/account.controller.ts @@ -132,12 +132,16 @@ export class AccountController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) public async getAccountBalancesById( + @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Param('id') id: string ): Promise { + const impersonationUserId = + await this.impersonationService.validateImpersonationId(impersonationId); + return this.accountBalanceService.getAccountBalances({ filters: [{ id, type: 'ACCOUNT' }], userCurrency: this.request.user.settings.settings.baseCurrency, - userId: this.request.user.id + userId: impersonationUserId || this.request.user.id }); } diff --git a/apps/api/src/app/account/account.service.ts b/apps/api/src/app/account/account.service.ts index 398a89bb9..e1b01a6ed 100644 --- a/apps/api/src/app/account/account.service.ts +++ b/apps/api/src/app/account/account.service.ts @@ -150,15 +150,15 @@ export class AccountService { }); return accounts.map((account) => { - let transactionCount = 0; + let activitiesCount = 0; for (const { isDraft } of account.activities) { if (!isDraft) { - transactionCount += 1; + activitiesCount += 1; } } - const result = { ...account, transactionCount }; + const result = { ...account, activitiesCount }; delete result.activities; diff --git a/apps/api/src/app/order/order.controller.ts b/apps/api/src/app/activities/activities.controller.ts similarity index 78% rename from apps/api/src/app/order/order.controller.ts rename to apps/api/src/app/activities/activities.controller.ts index 73c295f1b..141fd4c82 100644 --- a/apps/api/src/app/order/order.controller.ts +++ b/apps/api/src/app/activities/activities.controller.ts @@ -4,6 +4,7 @@ import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/ import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { ApiService } from '@ghostfolio/api/services/api/api.service'; +import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { getIntervalFromDateRange } from '@ghostfolio/common/calculation-helper'; @@ -36,27 +37,32 @@ import { } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; -import { Order as OrderModel, Prisma } from '@prisma/client'; +import { Order, Prisma } from '@prisma/client'; import { parseISO } from 'date-fns'; import { StatusCodes, getReasonPhrase } from 'http-status-codes'; -import { OrderService } from './order.service'; +import { ActivitiesService } from './activities.service'; -@Controller('order') -export class OrderController { +@Controller([ + 'activities', + /** @deprecated */ + 'order' +]) +export class ActivitiesController { public constructor( + private readonly activitiesService: ActivitiesService, private readonly apiService: ApiService, + private readonly dataProviderService: DataProviderService, private readonly dataGatheringService: DataGatheringService, private readonly impersonationService: ImpersonationService, - private readonly orderService: OrderService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @Delete() - @HasPermission(permissions.deleteOrder) + @HasPermission(permissions.deleteActivity) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) - public async deleteOrders( + public async deleteActivities( @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, @Query('dataSource') filterByDataSource?: string, @@ -71,29 +77,29 @@ export class OrderController { filterByTags }); - return this.orderService.deleteOrders({ + return this.activitiesService.deleteActivities({ filters, userId: this.request.user.id }); } @Delete(':id') - @HasPermission(permissions.deleteOrder) + @HasPermission(permissions.deleteActivity) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - public async deleteOrder(@Param('id') id: string): Promise { - const order = await this.orderService.order({ + public async deleteActivity(@Param('id') id: string): Promise { + const activity = await this.activitiesService.order({ id, userId: this.request.user.id }); - if (!order) { + if (!activity) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN ); } - return this.orderService.deleteOrder({ + return this.activitiesService.deleteActivity({ id }); } @@ -103,7 +109,7 @@ export class OrderController { @UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) - public async getAllOrders( + public async getAllActivities( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Query('accounts') filterByAccounts?: string, @Query('assetClasses') filterByAssetClasses?: string, @@ -120,7 +126,7 @@ export class OrderController { let startDate: Date; if (dateRange) { - ({ endDate, startDate } = getIntervalFromDateRange(dateRange)); + ({ endDate, startDate } = getIntervalFromDateRange({ dateRange })); } const filters = this.apiService.buildFiltersFromQueryParams({ @@ -135,7 +141,7 @@ export class OrderController { await this.impersonationService.validateImpersonationId(impersonationId); const userCurrency = this.request.user.settings.settings.baseCurrency; - const { activities, count } = await this.orderService.getOrders({ + const { activities, count } = await this.activitiesService.getActivities({ endDate, filters, sortColumn, @@ -156,7 +162,7 @@ export class OrderController { @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(RedactValuesInResponseInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) - public async getOrderById( + public async getActivityById( @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string, @Param('id') id: string ): Promise { @@ -164,7 +170,7 @@ export class OrderController { await this.impersonationService.validateImpersonationId(impersonationId); const userCurrency = this.request.user.settings.settings.baseCurrency; - const { activities } = await this.orderService.getOrders({ + const { activities } = await this.activitiesService.getActivities({ userCurrency, includeDrafts: true, userId: impersonationUserId || this.request.user.id, @@ -185,11 +191,34 @@ export class OrderController { return activity; } - @HasPermission(permissions.createOrder) + @HasPermission(permissions.createActivity) @Post() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) - public async createOrder(@Body() data: CreateOrderDto): Promise { + public async createActivity(@Body() data: CreateOrderDto): Promise { + try { + await this.dataProviderService.validateActivities({ + activitiesDto: [ + { + currency: data.currency, + dataSource: data.dataSource, + symbol: data.symbol, + type: data.type + } + ], + maxActivitiesToImport: 1, + user: this.request.user + }); + } catch (error) { + throw new HttpException( + { + error: getReasonPhrase(StatusCodes.BAD_REQUEST), + message: [error.message] + }, + StatusCodes.BAD_REQUEST + ); + } + const currency = data.currency; const customCurrency = data.customCurrency; const dataSource = data.dataSource; @@ -202,7 +231,7 @@ export class OrderController { delete data.dataSource; - const order = await this.orderService.createOrder({ + const activity = await this.activitiesService.createActivity({ ...data, date: parseISO(data.date), SymbolProfile: { @@ -227,14 +256,14 @@ export class OrderController { userId: this.request.user.id }); - if (dataSource && !order.isDraft) { + if (dataSource && !activity.isDraft) { // Gather symbol data in the background, if data source is set // (not MANUAL) and not draft this.dataGatheringService.gatherSymbols({ dataGatheringItems: [ { dataSource, - date: order.date, + date: activity.date, symbol: data.symbol } ], @@ -242,19 +271,22 @@ export class OrderController { }); } - return order; + return activity; } - @HasPermission(permissions.updateOrder) + @HasPermission(permissions.updateActivity) @Put(':id') @UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseInterceptors(TransformDataSourceInRequestInterceptor) - public async update(@Param('id') id: string, @Body() data: UpdateOrderDto) { - const originalOrder = await this.orderService.order({ + public async updateActivity( + @Param('id') id: string, + @Body() data: UpdateOrderDto + ) { + const originalActivity = await this.activitiesService.order({ id }); - if (!originalOrder || originalOrder.userId !== this.request.user.id) { + if (!originalActivity || originalActivity.userId !== this.request.user.id) { throw new HttpException( getReasonPhrase(StatusCodes.FORBIDDEN), StatusCodes.FORBIDDEN @@ -277,7 +309,7 @@ export class OrderController { delete data.dataSource; - return this.orderService.updateOrder({ + return this.activitiesService.updateActivity({ data: { ...data, date, diff --git a/apps/api/src/app/order/order.module.ts b/apps/api/src/app/activities/activities.module.ts similarity index 86% rename from apps/api/src/app/order/order.module.ts rename to apps/api/src/app/activities/activities.module.ts index 9bc837aa6..7476ad66a 100644 --- a/apps/api/src/app/order/order.module.ts +++ b/apps/api/src/app/activities/activities.module.ts @@ -15,12 +15,12 @@ import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/sym import { Module } from '@nestjs/common'; -import { OrderController } from './order.controller'; -import { OrderService } from './order.service'; +import { ActivitiesController } from './activities.controller'; +import { ActivitiesService } from './activities.service'; @Module({ - controllers: [OrderController], - exports: [OrderService], + controllers: [ActivitiesController], + exports: [ActivitiesService], imports: [ ApiModule, CacheModule, @@ -35,6 +35,6 @@ import { OrderService } from './order.service'; TransformDataSourceInRequestModule, TransformDataSourceInResponseModule ], - providers: [AccountBalanceService, AccountService, OrderService] + providers: [AccountBalanceService, AccountService, ActivitiesService] }) -export class OrderModule {} +export class ActivitiesModule {} diff --git a/apps/api/src/app/order/order.service.ts b/apps/api/src/app/activities/activities.service.ts similarity index 89% rename from apps/api/src/app/order/order.service.ts rename to apps/api/src/app/activities/activities.service.ts index 57fe5d3b6..89b9468f8 100644 --- a/apps/api/src/app/order/order.service.ts +++ b/apps/api/src/app/activities/activities.service.ts @@ -44,7 +44,7 @@ import { groupBy, uniqBy } from 'lodash'; import { randomUUID } from 'node:crypto'; @Injectable() -export class OrderService { +export class ActivitiesService { public constructor( private readonly accountBalanceService: AccountBalanceService, private readonly accountService: AccountService, @@ -62,7 +62,7 @@ export class OrderService { tags, userId }: { tags: Tag[]; userId: string } & AssetProfileIdentifier) { - const orders = await this.prismaService.order.findMany({ + const activities = await this.prismaService.order.findMany({ where: { userId, SymbolProfile: { @@ -73,7 +73,7 @@ export class OrderService { }); await Promise.all( - orders.map(({ id }) => + activities.map(({ id }) => this.prismaService.order.update({ data: { tags: { @@ -96,7 +96,7 @@ export class OrderService { ); } - public async createOrder( + public async createActivity( data: Prisma.OrderCreateInput & { accountId?: string; assetClass?: AssetClass; @@ -201,7 +201,7 @@ export class OrderService { ? false : isAfter(data.date as Date, endOfToday()); - const order = await this.prismaService.order.create({ + const activity = await this.prismaService.order.create({ data: { ...orderData, account, @@ -235,56 +235,56 @@ export class OrderService { this.eventEmitter.emit( AssetProfileChangedEvent.getName(), new AssetProfileChangedEvent({ - currency: order.SymbolProfile.currency, - dataSource: order.SymbolProfile.dataSource, - symbol: order.SymbolProfile.symbol + currency: activity.SymbolProfile.currency, + dataSource: activity.SymbolProfile.dataSource, + symbol: activity.SymbolProfile.symbol }) ); this.eventEmitter.emit( PortfolioChangedEvent.getName(), new PortfolioChangedEvent({ - userId: order.userId + userId: activity.userId }) ); - return order; + return activity; } - public async deleteOrder( + public async deleteActivity( where: Prisma.OrderWhereUniqueInput ): Promise { - const order = await this.prismaService.order.delete({ + const activity = await this.prismaService.order.delete({ where }); const [symbolProfile] = await this.symbolProfileService.getSymbolProfilesByIds([ - order.symbolProfileId + activity.symbolProfileId ]); if (symbolProfile.activitiesCount === 0) { - await this.symbolProfileService.deleteById(order.symbolProfileId); + await this.symbolProfileService.deleteById(activity.symbolProfileId); } this.eventEmitter.emit( PortfolioChangedEvent.getName(), new PortfolioChangedEvent({ - userId: order.userId + userId: activity.userId }) ); - return order; + return activity; } - public async deleteOrders({ + public async deleteActivities({ filters, userId }: { filters?: Filter[]; userId: string; }): Promise { - const { activities } = await this.getOrders({ + const { activities } = await this.getActivities({ filters, userId, includeDrafts: true, @@ -324,24 +324,44 @@ export class OrderService { } /** - * Generates synthetic orders for cash holdings based on account balance history. + * Generates synthetic activities for cash holdings based on account balance history. * Treat currencies as assets with a fixed unit price of 1.0 (in their own currency) to allow * performance tracking based on exchange rate fluctuations. * * @param cashDetails - The cash balance details. + * @param filters - Optional filters to apply. * @param userCurrency - The base currency of the user. * @param userId - The ID of the user. * @returns A response containing the list of synthetic cash activities. */ - public async getCashOrders({ + public async getCashActivities({ cashDetails, + filters = [], userCurrency, userId }: { cashDetails: CashDetails; + filters?: Filter[]; userCurrency: string; userId: string; }): Promise { + const filtersByAssetClass = filters.filter(({ type }) => { + return type === 'ASSET_CLASS'; + }); + + if ( + filtersByAssetClass.length > 0 && + !filtersByAssetClass.find(({ id }) => { + return id === AssetClass.LIQUIDITY; + }) + ) { + // If asset class filters are present and none of them is liquidity, return an empty response + return { + activities: [], + count: 0 + }; + } + const activities: Activity[] = []; for (const account of cashDetails.accounts) { @@ -428,7 +448,10 @@ export class OrderService { }; } - public async getLatestOrder({ dataSource, symbol }: AssetProfileIdentifier) { + public async getLatestActivity({ + dataSource, + symbol + }: AssetProfileIdentifier) { return this.prismaService.order.findFirst({ orderBy: { date: 'desc' @@ -439,7 +462,7 @@ export class OrderService { }); } - public async getOrders({ + public async getActivities({ endDate, filters, includeDrafts = false, @@ -722,47 +745,51 @@ export class OrderService { } /** - * Retrieves all orders required for the portfolio calculator, including both standard asset orders - * and synthetic orders representing cash activities. - * - * @param filters - Optional filters to apply to the orders. - * @param userCurrency - The base currency of the user. - * @param userId - The ID of the user. - * @returns An object containing the combined list of activities and the total count. + * Retrieves all activities required for the portfolio calculator, including both standard asset activities + * and optional synthetic activities representing cash activities. */ @LogPerformance - public async getOrdersForPortfolioCalculator({ + public async getActivitiesForPortfolioCalculator({ filters, userCurrency, - userId + userId, + withCash = false }: { + /** Optional filters to apply to the activities. */ filters?: Filter[]; + /** The base currency of the user. */ userCurrency: string; + /** The ID of the user. */ userId: string; + /** Whether to include cash activities in the result. */ + withCash?: boolean; }) { - const nonCashOrders = await this.getOrders({ + const activities = await this.getActivities({ filters, userCurrency, userId, withExcludedAccountsAndActivities: false // TODO }); - const cashDetails = await this.accountService.getCashDetails({ - filters, - userId, - currency: userCurrency - }); + if (withCash) { + const cashDetails = await this.accountService.getCashDetails({ + filters, + userId, + currency: userCurrency + }); - const cashOrders = await this.getCashOrders({ - cashDetails, - userCurrency, - userId - }); + const cashActivities = await this.getCashActivities({ + cashDetails, + filters, + userCurrency, + userId + }); - return { - activities: [...nonCashOrders.activities, ...cashOrders.activities], - count: nonCashOrders.count + cashOrders.count - }; + activities.activities.push(...cashActivities.activities); + activities.count += cashActivities.count; + } + + return activities; } public async getStatisticsByCurrency( @@ -793,7 +820,7 @@ export class OrderService { }); } - public async updateOrder({ + public async updateActivity({ data, where }: { @@ -858,7 +885,7 @@ export class OrderService { data: { tags: { set: [] } } }); - const order = await this.prismaService.order.update({ + const activity = await this.prismaService.order.update({ where, data: { ...data, @@ -872,11 +899,11 @@ export class OrderService { this.eventEmitter.emit( PortfolioChangedEvent.getName(), new PortfolioChangedEvent({ - userId: order.userId + userId: activity.userId }) ); - return order; + return activity; } private async orders(params: { diff --git a/apps/api/src/app/admin/admin.controller.ts b/apps/api/src/app/admin/admin.controller.ts index 24467c732..69b619625 100644 --- a/apps/api/src/app/admin/admin.controller.ts +++ b/apps/api/src/app/admin/admin.controller.ts @@ -172,7 +172,7 @@ export class AdminController { let date: Date; if (dateRange) { - const { startDate } = getIntervalFromDateRange(dateRange); + const { startDate } = getIntervalFromDateRange({ dateRange }); date = startDate; } @@ -247,14 +247,17 @@ export class AdminController { @Param('symbol') symbol: string ): Promise<{ price: number }> { try { - const price = await this.manualService.test(data.scraperConfiguration); + const price = await this.manualService.test({ + symbol, + scraperConfiguration: data.scraperConfiguration + }); if (price) { return { price }; } throw new Error( - `Could not parse the current market price for ${symbol} (${dataSource})` + `Could not parse the market price for ${symbol} (${dataSource})` ); } catch (error) { Logger.error(error, 'AdminController'); diff --git a/apps/api/src/app/admin/admin.module.ts b/apps/api/src/app/admin/admin.module.ts index 598b68f17..960a36629 100644 --- a/apps/api/src/app/admin/admin.module.ts +++ b/apps/api/src/app/admin/admin.module.ts @@ -1,4 +1,4 @@ -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { BenchmarkModule } from '@ghostfolio/api/services/benchmark/benchmark.module'; @@ -20,6 +20,7 @@ import { QueueModule } from './queue/queue.module'; @Module({ imports: [ + ActivitiesModule, ApiModule, BenchmarkModule, ConfigurationModule, @@ -28,7 +29,6 @@ import { QueueModule } from './queue/queue.module'; DemoModule, ExchangeRateDataModule, MarketDataModule, - OrderModule, PrismaModule, PropertyModule, QueueModule, diff --git a/apps/api/src/app/admin/admin.service.ts b/apps/api/src/app/admin/admin.service.ts index 705085a48..d2bf6e411 100644 --- a/apps/api/src/app/admin/admin.service.ts +++ b/apps/api/src/app/admin/admin.service.ts @@ -1,4 +1,4 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { environment } from '@ghostfolio/api/environments/environment'; import { BenchmarkService } from '@ghostfolio/api/services/benchmark/benchmark.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; @@ -55,12 +55,12 @@ import { groupBy } from 'lodash'; @Injectable() export class AdminService { public constructor( + private readonly activitiesService: ActivitiesService, private readonly benchmarkService: BenchmarkService, private readonly configurationService: ConfigurationService, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly marketDataService: MarketDataService, - private readonly orderService: OrderService, private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly symbolProfileService: SymbolProfileService @@ -138,11 +138,11 @@ export class AdminService { public async get(): Promise { const dataSources = Object.values(DataSource); - const [enabledDataSources, settings, transactionCount, userCount] = + const [activitiesCount, enabledDataSources, settings, userCount] = await Promise.all([ + this.prismaService.order.count(), this.dataProviderService.getDataSources(), this.propertyService.get(), - this.prismaService.order.count(), this.countUsersWithAnalytics() ]); @@ -182,9 +182,9 @@ export class AdminService { ).filter(Boolean); return { + activitiesCount, dataProviders, settings, - transactionCount, userCount, version: environment.version }; @@ -225,6 +225,10 @@ export class AdminService { presetId === 'ETF_WITHOUT_SECTORS' ) { filters = [{ id: 'ETF', type: 'ASSET_SUB_CLASS' }]; + } else if (presetId === 'NO_ACTIVITIES') { + where.activities = { + none: {} + }; } const searchQuery = filters.find(({ type }) => { @@ -466,10 +470,12 @@ export class AdminService { let currency: EnhancedSymbolProfile['currency'] = '-'; let dateOfFirstActivity: EnhancedSymbolProfile['dateOfFirstActivity']; - if (isCurrency(getCurrencyFromSymbol(symbol))) { + const isCurrencyAssetProfile = isCurrency(getCurrencyFromSymbol(symbol)); + + if (isCurrencyAssetProfile) { currency = getCurrencyFromSymbol(symbol); ({ activitiesCount, dateOfFirstActivity } = - await this.orderService.getStatisticsByCurrency(currency)); + await this.activitiesService.getStatisticsByCurrency(currency)); } const [[assetProfile], marketData] = await Promise.all([ @@ -504,6 +510,8 @@ export class AdminService { dataSource, dateOfFirstActivity, symbol, + assetClass: isCurrencyAssetProfile ? AssetClass.LIQUIDITY : undefined, + assetSubClass: isCurrencyAssetProfile ? AssetSubClass.CASH : undefined, isActive: true } }; @@ -790,7 +798,7 @@ export class AdminService { if (isCurrency(getCurrencyFromSymbol(symbol))) { currency = getCurrencyFromSymbol(symbol); ({ activitiesCount, dateOfFirstActivity } = - await this.orderService.getStatisticsByCurrency(currency)); + await this.activitiesService.getStatisticsByCurrency(currency)); } const lastMarketPrice = lastMarketPriceMap.get( diff --git a/apps/api/src/app/app.module.ts b/apps/api/src/app/app.module.ts index 89f52e1ea..8ebe05928 100644 --- a/apps/api/src/app/app.module.ts +++ b/apps/api/src/app/app.module.ts @@ -1,4 +1,5 @@ import { EventsModule } from '@ghostfolio/api/events/events.module'; +import { BullBoardAuthMiddleware } from '@ghostfolio/api/middlewares/bull-board-auth.middleware'; import { HtmlTemplateMiddleware } from '@ghostfolio/api/middlewares/html-template.middleware'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { CronModule } from '@ghostfolio/api/services/cron/cron.module'; @@ -10,10 +11,13 @@ import { PropertyModule } from '@ghostfolio/api/services/property/property.modul import { DataGatheringModule } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.module'; import { PortfolioSnapshotQueueModule } from '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.module'; import { + BULL_BOARD_ROUTE, DEFAULT_LANGUAGE_CODE, SUPPORTED_LANGUAGE_CODES } from '@ghostfolio/common/config'; +import { ExpressAdapter } from '@bull-board/express'; +import { BullBoardModule } from '@bull-board/nestjs'; import { BullModule } from '@nestjs/bull'; import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; @@ -25,6 +29,7 @@ import { join } from 'node:path'; import { AccessModule } from './access/access.module'; import { AccountModule } from './account/account.module'; +import { ActivitiesModule } from './activities/activities.module'; import { AdminModule } from './admin/admin.module'; import { AppController } from './app.controller'; import { AssetModule } from './asset/asset.module'; @@ -48,7 +53,6 @@ import { HealthModule } from './health/health.module'; import { ImportModule } from './import/import.module'; import { InfoModule } from './info/info.module'; import { LogoModule } from './logo/logo.module'; -import { OrderModule } from './order/order.module'; import { PlatformModule } from './platform/platform.module'; import { PortfolioModule } from './portfolio/portfolio.module'; import { RedisCacheModule } from './redis-cache/redis-cache.module'; @@ -62,6 +66,7 @@ import { UserModule } from './user/user.module'; AdminModule, AccessModule, AccountModule, + ActivitiesModule, AiModule, ApiKeysModule, AssetModule, @@ -69,6 +74,29 @@ import { UserModule } from './user/user.module'; AuthDeviceModule, AuthModule, BenchmarksModule, + ...(process.env.ENABLE_FEATURE_BULL_BOARD === 'true' + ? [ + BullBoardModule.forRoot({ + adapter: ExpressAdapter, + boardOptions: { + uiConfig: { + boardLogo: { + height: 0, + path: '', + width: 0 + }, + boardTitle: 'Job Queues', + favIcon: { + alternative: '/assets/favicon-32x32.png', + default: '/assets/favicon-32x32.png' + } + } + }, + middleware: BullBoardAuthMiddleware, + route: BULL_BOARD_ROUTE + }) + ] + : []), BullModule.forRoot({ redis: { db: parseInt(process.env.REDIS_DB ?? '0', 10), @@ -94,7 +122,6 @@ import { UserModule } from './user/user.module'; InfoModule, LogoModule, MarketDataModule, - OrderModule, PlatformModule, PlatformsModule, PortfolioModule, @@ -105,7 +132,12 @@ import { UserModule } from './user/user.module'; RedisCacheModule, ScheduleModule.forRoot(), ServeStaticModule.forRoot({ - exclude: ['/.well-known/*wildcard', '/api/*wildcard', '/sitemap.xml'], + exclude: [ + `${BULL_BOARD_ROUTE}/*wildcard`, + '/.well-known/*wildcard', + '/api/*wildcard', + '/sitemap.xml' + ], rootPath: join(__dirname, '..', 'client'), serveStaticOptions: { setHeaders: (res) => { diff --git a/apps/api/src/app/endpoints/ai/ai.module.ts b/apps/api/src/app/endpoints/ai/ai.module.ts index 8a441fde7..eab4ecf8b 100644 --- a/apps/api/src/app/endpoints/ai/ai.module.ts +++ b/apps/api/src/app/endpoints/ai/ai.module.ts @@ -1,6 +1,6 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; @@ -29,6 +29,7 @@ import { AiService } from './ai.service'; @Module({ controllers: [AiController], imports: [ + ActivitiesModule, ApiModule, BenchmarkModule, ConfigurationModule, @@ -37,7 +38,6 @@ import { AiService } from './ai.service'; I18nModule, ImpersonationModule, MarketDataModule, - OrderModule, PortfolioSnapshotQueueModule, PrismaModule, PropertyModule, diff --git a/apps/api/src/app/endpoints/assets/assets.controller.ts b/apps/api/src/app/endpoints/assets/assets.controller.ts index a314b3f19..397686d8c 100644 --- a/apps/api/src/app/endpoints/assets/assets.controller.ts +++ b/apps/api/src/app/endpoints/assets/assets.controller.ts @@ -4,6 +4,7 @@ import { interpolate } from '@ghostfolio/common/helper'; import { Controller, Get, + OnModuleInit, Param, Res, Version, @@ -14,12 +15,14 @@ import { readFileSync } from 'node:fs'; import { join } from 'node:path'; @Controller('assets') -export class AssetsController { +export class AssetsController implements OnModuleInit { private webManifest = ''; public constructor( public readonly configurationService: ConfigurationService - ) { + ) {} + + public onModuleInit() { try { this.webManifest = readFileSync( join(__dirname, 'assets', 'site.webmanifest'), diff --git a/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts index 629d90928..970925777 100644 --- a/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.controller.ts @@ -126,10 +126,10 @@ export class BenchmarksController { @Query('tags') filterByTags?: string, @Query('withExcludedAccounts') withExcludedAccountsParam = 'false' ): Promise { - const { endDate, startDate } = getIntervalFromDateRange( + const { endDate, startDate } = getIntervalFromDateRange({ dateRange, - new Date(startDateString) - ); + startDate: new Date(startDateString) + }); const filters = this.apiService.buildFiltersFromQueryParams({ filterByAccounts, diff --git a/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts b/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts index 8bdf79035..2bcd6177d 100644 --- a/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts +++ b/apps/api/src/app/endpoints/benchmarks/benchmarks.module.ts @@ -1,6 +1,6 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; @@ -32,6 +32,7 @@ import { BenchmarksService } from './benchmarks.service'; @Module({ controllers: [BenchmarksController], imports: [ + ActivitiesModule, ApiModule, ConfigurationModule, DataProviderModule, @@ -39,7 +40,6 @@ import { BenchmarksService } from './benchmarks.service'; I18nModule, ImpersonationModule, MarketDataModule, - OrderModule, PortfolioSnapshotQueueModule, PrismaModule, PropertyModule, diff --git a/apps/api/src/app/endpoints/market-data/market-data.controller.ts b/apps/api/src/app/endpoints/market-data/market-data.controller.ts index 987d34918..0dae82d2c 100644 --- a/apps/api/src/app/endpoints/market-data/market-data.controller.ts +++ b/apps/api/src/app/endpoints/market-data/market-data.controller.ts @@ -2,6 +2,8 @@ import { AdminService } from '@ghostfolio/api/app/admin/admin.service'; import { SymbolService } from '@ghostfolio/api/app/symbol/symbol.service'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; +import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.interceptor'; +import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.interceptor'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; import { @@ -28,7 +30,8 @@ import { Param, Post, Query, - UseGuards + UseGuards, + UseInterceptors } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; @@ -86,6 +89,8 @@ export class MarketDataController { @Get(':dataSource/:symbol') @UseGuards(AuthGuard('jwt')) + @UseInterceptors(TransformDataSourceInRequestInterceptor) + @UseInterceptors(TransformDataSourceInResponseInterceptor) public async getMarketDataBySymbol( @Param('dataSource') dataSource: DataSource, @Param('symbol') symbol: string diff --git a/apps/api/src/app/endpoints/market-data/market-data.module.ts b/apps/api/src/app/endpoints/market-data/market-data.module.ts index a8b355de3..d5d64673d 100644 --- a/apps/api/src/app/endpoints/market-data/market-data.module.ts +++ b/apps/api/src/app/endpoints/market-data/market-data.module.ts @@ -1,5 +1,7 @@ import { AdminModule } from '@ghostfolio/api/app/admin/admin.module'; import { SymbolModule } from '@ghostfolio/api/app/symbol/symbol.module'; +import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; +import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; import { MarketDataModule as MarketDataServiceModule } from '@ghostfolio/api/services/market-data/market-data.module'; import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; @@ -13,7 +15,9 @@ import { MarketDataController } from './market-data.controller'; AdminModule, MarketDataServiceModule, SymbolModule, - SymbolProfileModule + SymbolProfileModule, + TransformDataSourceInRequestModule, + TransformDataSourceInResponseModule ] }) export class MarketDataModule {} diff --git a/apps/api/src/app/endpoints/platforms/platforms.controller.ts b/apps/api/src/app/endpoints/platforms/platforms.controller.ts index 46303a3f8..92ba77297 100644 --- a/apps/api/src/app/endpoints/platforms/platforms.controller.ts +++ b/apps/api/src/app/endpoints/platforms/platforms.controller.ts @@ -15,7 +15,9 @@ export class PlatformsController { @HasPermission(permissions.readPlatforms) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) public async getPlatforms(): Promise { - const platforms = await this.platformService.getPlatforms(); + const platforms = await this.platformService.getPlatforms({ + orderBy: { name: 'asc' } + }); return { platforms }; } diff --git a/apps/api/src/app/endpoints/public/public.controller.ts b/apps/api/src/app/endpoints/public/public.controller.ts index b4ecd37ba..b97640cab 100644 --- a/apps/api/src/app/endpoints/public/public.controller.ts +++ b/apps/api/src/app/endpoints/public/public.controller.ts @@ -1,5 +1,5 @@ import { AccessService } from '@ghostfolio/api/app/access/access.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; import { UserService } from '@ghostfolio/api/app/user/user.service'; import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor'; @@ -28,9 +28,9 @@ import { StatusCodes, getReasonPhrase } from 'http-status-codes'; export class PublicController { public constructor( private readonly accessService: AccessService, + private readonly activitiesService: ActivitiesService, private readonly configurationService: ConfigurationService, private readonly exchangeRateDataService: ExchangeRateDataService, - private readonly orderService: OrderService, private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser, private readonly userService: UserService @@ -81,7 +81,7 @@ export class PublicController { }) ]); - const { activities } = await this.orderService.getOrders({ + const { activities } = await this.activitiesService.getActivities({ sortColumn: 'date', sortDirection: 'desc', take: 10, @@ -167,6 +167,7 @@ export class PublicController { allocationInPercentage: portfolioPosition.valueInBaseCurrency / totalValue, assetClass: hasDetails ? portfolioPosition.assetClass : undefined, + assetProfile: hasDetails ? portfolioPosition.assetProfile : undefined, countries: hasDetails ? portfolioPosition.countries : [], currency: hasDetails ? portfolioPosition.currency : undefined, dataSource: portfolioPosition.dataSource, diff --git a/apps/api/src/app/endpoints/public/public.module.ts b/apps/api/src/app/endpoints/public/public.module.ts index 19e281dde..e8395228f 100644 --- a/apps/api/src/app/endpoints/public/public.module.ts +++ b/apps/api/src/app/endpoints/public/public.module.ts @@ -1,7 +1,7 @@ import { AccessModule } from '@ghostfolio/api/app/access/access.module'; import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; @@ -27,13 +27,13 @@ import { PublicController } from './public.controller'; controllers: [PublicController], imports: [ AccessModule, + ActivitiesModule, BenchmarkModule, DataProviderModule, ExchangeRateDataModule, I18nModule, ImpersonationModule, MarketDataModule, - OrderModule, PortfolioSnapshotQueueModule, PrismaModule, RedisCacheModule, diff --git a/apps/api/src/app/export/export.module.ts b/apps/api/src/app/export/export.module.ts index 4f40cc417..6158fe043 100644 --- a/apps/api/src/app/export/export.module.ts +++ b/apps/api/src/app/export/export.module.ts @@ -1,5 +1,5 @@ import { AccountModule } from '@ghostfolio/api/app/account/account.module'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { MarketDataModule } from '@ghostfolio/api/services/market-data/market-data.module'; @@ -14,9 +14,9 @@ import { ExportService } from './export.service'; controllers: [ExportController], imports: [ AccountModule, + ActivitiesModule, ApiModule, MarketDataModule, - OrderModule, TagModule, TransformDataSourceInRequestModule ], diff --git a/apps/api/src/app/export/export.service.ts b/apps/api/src/app/export/export.service.ts index d07b199be..4f2fb3309 100644 --- a/apps/api/src/app/export/export.service.ts +++ b/apps/api/src/app/export/export.service.ts @@ -1,5 +1,5 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { environment } from '@ghostfolio/api/environments/environment'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { TagService } from '@ghostfolio/api/services/tag/tag.service'; @@ -17,8 +17,8 @@ import { groupBy, uniqBy } from 'lodash'; export class ExportService { public constructor( private readonly accountService: AccountService, + private readonly activitiesService: ActivitiesService, private readonly marketDataService: MarketDataService, - private readonly orderService: OrderService, private readonly tagService: TagService ) {} @@ -38,7 +38,7 @@ export class ExportService { }); const platformsMap: { [platformId: string]: Platform } = {}; - let { activities } = await this.orderService.getOrders({ + let { activities } = await this.activitiesService.getActivities({ filters, userId, includeDrafts: true, @@ -182,10 +182,8 @@ export class ExportService { isActive, isin, name, - scraperConfiguration, sectors, symbol, - symbolMapping, url }) => { return { @@ -204,11 +202,8 @@ export class ExportService { isin, marketData: marketDataByAssetProfile[id], name, - scraperConfiguration: - scraperConfiguration as unknown as Prisma.JsonArray, sectors: sectors as unknown as Prisma.JsonArray, symbol, - symbolMapping, url }; } diff --git a/apps/api/src/app/import/import.controller.ts b/apps/api/src/app/import/import.controller.ts index 2681444df..d5724bef2 100644 --- a/apps/api/src/app/import/import.controller.ts +++ b/apps/api/src/app/import/import.controller.ts @@ -38,7 +38,7 @@ export class ImportController { @Post() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) - @HasPermission(permissions.createOrder) + @HasPermission(permissions.createActivity) @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInResponseInterceptor) public async import( @@ -103,6 +103,7 @@ export class ImportController { const activities = await this.importService.getDividends({ dataSource, symbol, + userCurrency: this.request.user.settings.settings.baseCurrency, userId: this.request.user.id }); diff --git a/apps/api/src/app/import/import.module.ts b/apps/api/src/app/import/import.module.ts index 88990af2e..ca9b5667b 100644 --- a/apps/api/src/app/import/import.module.ts +++ b/apps/api/src/app/import/import.module.ts @@ -1,11 +1,12 @@ import { AccountModule } from '@ghostfolio/api/app/account/account.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { CacheModule } from '@ghostfolio/api/app/cache/cache.module'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; import { PlatformModule } from '@ghostfolio/api/app/platform/platform.module'; import { PortfolioModule } from '@ghostfolio/api/app/portfolio/portfolio.module'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { TransformDataSourceInRequestModule } from '@ghostfolio/api/interceptors/transform-data-source-in-request/transform-data-source-in-request.module'; import { TransformDataSourceInResponseModule } from '@ghostfolio/api/interceptors/transform-data-source-in-response/transform-data-source-in-response.module'; +import { ApiModule } from '@ghostfolio/api/services/api/api.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; import { ExchangeRateDataModule } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.module'; @@ -24,13 +25,14 @@ import { ImportService } from './import.service'; controllers: [ImportController], imports: [ AccountModule, + ActivitiesModule, + ApiModule, CacheModule, ConfigurationModule, DataGatheringModule, DataProviderModule, ExchangeRateDataModule, MarketDataModule, - OrderModule, PlatformModule, PortfolioModule, PrismaModule, diff --git a/apps/api/src/app/import/import.service.ts b/apps/api/src/app/import/import.service.ts index 2deef1c44..b82f763a0 100644 --- a/apps/api/src/app/import/import.service.ts +++ b/apps/api/src/app/import/import.service.ts @@ -1,9 +1,10 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { PortfolioService } from '@ghostfolio/api/app/portfolio/portfolio.service'; -import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { ApiService } from '@ghostfolio/api/services/api/api.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; +import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile/symbol-profile.service'; @@ -25,13 +26,13 @@ import { } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { - AccountWithPlatform, + AccountWithValue, OrderWithAccount, UserWithSettings } from '@ghostfolio/common/types'; import { Injectable } from '@nestjs/common'; -import { DataSource, Prisma, SymbolProfile } from '@prisma/client'; +import { DataSource, Prisma } from '@prisma/client'; import { Big } from 'big.js'; import { endOfToday, isAfter, isSameSecond, parseISO } from 'date-fns'; import { omit, uniqBy } from 'lodash'; @@ -43,11 +44,12 @@ import { ImportDataDto } from './import-data.dto'; export class ImportService { public constructor( private readonly accountService: AccountService, - private readonly configurationService: ConfigurationService, + private readonly activitiesService: ActivitiesService, + private readonly apiService: ApiService, private readonly dataGatheringService: DataGatheringService, private readonly dataProviderService: DataProviderService, + private readonly exchangeRateDataService: ExchangeRateDataService, private readonly marketDataService: MarketDataService, - private readonly orderService: OrderService, private readonly platformService: PlatformService, private readonly portfolioService: PortfolioService, private readonly symbolProfileService: SymbolProfileService, @@ -57,8 +59,12 @@ export class ImportService { public async getDividends({ dataSource, symbol, + userCurrency, userId - }: AssetProfileIdentifier & { userId: string }): Promise { + }: AssetProfileIdentifier & { + userCurrency: string; + userId: string; + }): Promise { try { const holding = await this.portfolioService.getHolding({ dataSource, @@ -71,36 +77,45 @@ export class ImportService { return []; } - const { activities, firstBuyDate, historicalData } = holding; + const filters = this.apiService.buildFiltersFromQueryParams({ + filterByDataSource: dataSource, + filterBySymbol: symbol + }); - const [[assetProfile], dividends] = await Promise.all([ - this.symbolProfileService.getSymbolProfiles([ - { - dataSource, - symbol - } - ]), - await this.dataProviderService.getDividends({ - dataSource, - symbol, - from: parseDate(firstBuyDate), - granularity: 'day', - to: new Date() - }) - ]); + const { dateOfFirstActivity, historicalData } = holding; - const accounts = activities - .filter(({ account }) => { - return !!account; - }) - .map(({ account }) => { - return account; - }); + const [{ accounts }, { activities }, [assetProfile], dividends] = + await Promise.all([ + this.portfolioService.getAccountsWithAggregations({ + filters, + userId, + withExcludedAccounts: true + }), + this.activitiesService.getActivities({ + filters, + userCurrency, + userId, + startDate: parseDate(dateOfFirstActivity) + }), + this.symbolProfileService.getSymbolProfiles([ + { + dataSource, + symbol + } + ]), + await this.dataProviderService.getDividends({ + dataSource, + symbol, + from: parseDate(dateOfFirstActivity), + granularity: 'day', + to: new Date() + }) + ]); const account = this.isUniqueAccount(accounts) ? accounts[0] : undefined; return await Promise.all( - Object.entries(dividends).map(async ([dateString, { marketPrice }]) => { + Object.entries(dividends).map(([dateString, { marketPrice }]) => { const quantity = historicalData.find((historicalDataItem) => { return historicalDataItem.date === dateString; @@ -378,7 +393,7 @@ export class ImportService { } } - const assetProfiles = await this.validateActivities({ + const assetProfiles = await this.dataProviderService.validateActivities({ activitiesDto, assetProfilesWithMarketDataDto, maxActivitiesToImport, @@ -533,7 +548,7 @@ export class ImportService { continue; } - order = await this.orderService.createOrder({ + order = await this.activitiesService.createActivity({ comment, currency, date, @@ -575,10 +590,18 @@ export class ImportService { const value = new Big(quantity).mul(unitPrice).toNumber(); + const valueInBaseCurrency = this.exchangeRateDataService.toCurrencyAtDate( + value, + currency ?? assetProfile.currency, + userCurrency, + date + ); + activities.push({ ...order, error, value, + valueInBaseCurrency: await valueInBaseCurrency, // @ts-ignore SymbolProfile: assetProfile }); @@ -622,7 +645,7 @@ export class ImportService { userId: string; }): Promise[]> { const { activities: existingActivities } = - await this.orderService.getOrders({ + await this.activitiesService.getActivities({ userCurrency, userId, includeDrafts: true, @@ -695,141 +718,13 @@ export class ImportService { ); } - private isUniqueAccount(accounts: AccountWithPlatform[]) { + private isUniqueAccount(accounts: AccountWithValue[]) { const uniqueAccountIds = new Set(); - for (const account of accounts) { - uniqueAccountIds.add(account.id); + for (const { id } of accounts) { + uniqueAccountIds.add(id); } return uniqueAccountIds.size === 1; } - - private async validateActivities({ - activitiesDto, - assetProfilesWithMarketDataDto, - maxActivitiesToImport, - user - }: { - activitiesDto: Partial[]; - assetProfilesWithMarketDataDto: ImportDataDto['assetProfiles']; - maxActivitiesToImport: number; - user: UserWithSettings; - }) { - if (activitiesDto?.length > maxActivitiesToImport) { - throw new Error(`Too many activities (${maxActivitiesToImport} at most)`); - } - - const assetProfiles: { - [assetProfileIdentifier: string]: Partial; - } = {}; - const dataSources = await this.dataProviderService.getDataSources(); - - for (const [ - index, - { currency, dataSource, symbol, type } - ] of activitiesDto.entries()) { - if (!dataSources.includes(dataSource)) { - throw new Error( - `activities.${index}.dataSource ("${dataSource}") is not valid` - ); - } - - if ( - this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && - user.subscription.type === 'Basic' - ) { - const dataProvider = this.dataProviderService.getDataProvider( - DataSource[dataSource] - ); - - if (dataProvider.getDataProviderInfo().isPremium) { - throw new Error( - `activities.${index}.dataSource ("${dataSource}") is not valid` - ); - } - } - - if (!assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })]) { - if (['FEE', 'INTEREST', 'LIABILITY'].includes(type)) { - // Skip asset profile validation for FEE, INTEREST, and LIABILITY - // as these activity types don't require asset profiles - const assetProfileInImport = assetProfilesWithMarketDataDto?.find( - (profile) => { - return ( - profile.dataSource === dataSource && profile.symbol === symbol - ); - } - ); - - assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })] = { - currency, - dataSource, - symbol, - name: assetProfileInImport?.name - }; - - continue; - } - - let assetProfile: Partial = { currency }; - - try { - assetProfile = ( - await this.dataProviderService.getAssetProfiles([ - { dataSource, symbol } - ]) - )?.[symbol]; - } catch {} - - if (!assetProfile?.name) { - const assetProfileInImport = assetProfilesWithMarketDataDto?.find( - (profile) => { - return ( - profile.dataSource === dataSource && profile.symbol === symbol - ); - } - ); - - if (assetProfileInImport) { - // Merge all fields of custom asset profiles into the validation object - Object.assign(assetProfile, { - assetClass: assetProfileInImport.assetClass, - assetSubClass: assetProfileInImport.assetSubClass, - comment: assetProfileInImport.comment, - countries: assetProfileInImport.countries, - currency: assetProfileInImport.currency, - cusip: assetProfileInImport.cusip, - dataSource: assetProfileInImport.dataSource, - figi: assetProfileInImport.figi, - figiComposite: assetProfileInImport.figiComposite, - figiShareClass: assetProfileInImport.figiShareClass, - holdings: assetProfileInImport.holdings, - isActive: assetProfileInImport.isActive, - isin: assetProfileInImport.isin, - name: assetProfileInImport.name, - scraperConfiguration: assetProfileInImport.scraperConfiguration, - sectors: assetProfileInImport.sectors, - symbol: assetProfileInImport.symbol, - symbolMapping: assetProfileInImport.symbolMapping, - url: assetProfileInImport.url - }); - } - } - - if (!['FEE', 'INTEREST', 'LIABILITY'].includes(type)) { - if (!assetProfile?.name) { - throw new Error( - `activities.${index}.symbol ("${symbol}") is not valid for the specified data source ("${dataSource}")` - ); - } - } - - assetProfiles[getAssetProfileIdentifier({ dataSource, symbol })] = - assetProfile; - } - } - - return assetProfiles; - } } diff --git a/apps/api/src/app/info/info.service.ts b/apps/api/src/app/info/info.service.ts index c5152c1a2..9b4a4d597 100644 --- a/apps/api/src/app/info/info.service.ts +++ b/apps/api/src/app/info/info.service.ts @@ -1,4 +1,3 @@ -import { PlatformService } from '@ghostfolio/api/app/platform/platform.service'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscription.service'; import { UserService } from '@ghostfolio/api/app/user/user.service'; @@ -38,7 +37,6 @@ export class InfoService { private readonly configurationService: ConfigurationService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly jwtService: JwtService, - private readonly platformService: PlatformService, private readonly propertyService: PropertyService, private readonly redisCacheService: RedisCacheService, private readonly subscriptionService: SubscriptionService, @@ -103,16 +101,12 @@ export class InfoService { benchmarks, demoAuthToken, isUserSignupEnabled, - platforms, statistics, subscriptionOffer ] = await Promise.all([ this.benchmarkService.getBenchmarkAssetProfiles(), this.getDemoAuthToken(), this.propertyService.isUserSignupEnabled(), - this.platformService.getPlatforms({ - orderBy: { name: 'asc' } - }), this.getStatistics(), this.subscriptionService.getSubscriptionOffer({ key: 'default' }) ]); @@ -127,7 +121,6 @@ export class InfoService { demoAuthToken, globalPermissions, isReadOnlyMode, - platforms, statistics, subscriptionOffer, baseCurrency: DEFAULT_CURRENCY, diff --git a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts index d2b3c0625..d57b85d8c 100644 --- a/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/portfolio-calculator.ts @@ -39,6 +39,7 @@ import { GroupBy } from '@ghostfolio/common/types'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; import { Logger } from '@nestjs/common'; +import { AssetSubClass } from '@prisma/client'; import { Big } from 'big.js'; import { plainToClass } from 'class-transformer'; import { @@ -52,6 +53,7 @@ import { isBefore, isWithinInterval, min, + startOfDay, startOfYear, subDays } from 'date-fns'; @@ -119,6 +121,7 @@ export abstract class PortfolioCalculator { ({ date, feeInAssetProfileCurrency, + feeInBaseCurrency, quantity, SymbolProfile, tags = [], @@ -141,6 +144,7 @@ export abstract class PortfolioCalculator { type, date: format(date, DATE_FORMAT), fee: new Big(feeInAssetProfileCurrency), + feeInBaseCurrency: new Big(feeInBaseCurrency), quantity: new Big(quantity), unitPrice: new Big(unitPriceInAssetProfileCurrency) }; @@ -154,13 +158,13 @@ export abstract class PortfolioCalculator { this.redisCacheService = redisCacheService; this.userId = userId; - const { endDate, startDate } = getIntervalFromDateRange( - 'max', - subDays(dateOfFirstActivity, 1) - ); + const { endDate, startDate } = getIntervalFromDateRange({ + dateRange: 'max', + startDate: subDays(dateOfFirstActivity, 1) + }); - this.endDate = endDate; - this.startDate = startDate; + this.endDate = endOfDay(endDate); + this.startDate = startOfDay(startDate); this.computeTransactionPoints(); @@ -233,7 +237,7 @@ export abstract class PortfolioCalculator { const exchangeRatesByCurrency = await this.exchangeRateDataService.getExchangeRatesByCurrency({ currencies: Array.from(new Set(Object.values(currencies))), - endDate: endOfDay(this.endDate), + endDate: this.endDate, startDate: this.startDate, targetCurrency: this.currency }); @@ -335,12 +339,6 @@ export abstract class PortfolioCalculator { } = {}; for (const item of lastTransactionPoint.items) { - const feeInBaseCurrency = item.fee.mul( - exchangeRatesByCurrency[`${item.currency}${this.currency}`]?.[ - lastTransactionPoint.date - ] ?? 1 - ); - const marketPriceInBaseCurrency = ( marketSymbolMap[endDateString]?.[item.symbol] ?? item.averagePrice ).mul( @@ -389,29 +387,36 @@ export abstract class PortfolioCalculator { hasAnySymbolMetricsErrors = hasAnySymbolMetricsErrors || hasErrors; - valuesBySymbol[item.symbol] = { - currentValues, - currentValuesWithCurrencyEffect, - investmentValuesAccumulated, - investmentValuesAccumulatedWithCurrencyEffect, - investmentValuesWithCurrencyEffect, - netPerformanceValues, - netPerformanceValuesWithCurrencyEffect, - timeWeightedInvestmentValues, - timeWeightedInvestmentValuesWithCurrencyEffect - }; + const includeInTotalAssetValue = + item.assetSubClass !== AssetSubClass.CASH; + + if (includeInTotalAssetValue) { + valuesBySymbol[item.symbol] = { + currentValues, + currentValuesWithCurrencyEffect, + investmentValuesAccumulated, + investmentValuesAccumulatedWithCurrencyEffect, + investmentValuesWithCurrencyEffect, + netPerformanceValues, + netPerformanceValuesWithCurrencyEffect, + timeWeightedInvestmentValues, + timeWeightedInvestmentValuesWithCurrencyEffect + }; + } positions.push({ - feeInBaseCurrency, + includeInTotalAssetValue, timeWeightedInvestment, timeWeightedInvestmentWithCurrencyEffect, - dividend: totalDividend, - dividendInBaseCurrency: totalDividendInBaseCurrency, + activitiesCount: item.activitiesCount, averagePrice: item.averagePrice, currency: item.currency, dataSource: item.dataSource, + dateOfFirstActivity: item.dateOfFirstActivity, + dividend: totalDividend, + dividendInBaseCurrency: totalDividendInBaseCurrency, fee: item.fee, - firstBuyDate: item.firstBuyDate, + feeInBaseCurrency: item.feeInBaseCurrency, grossPerformance: !hasErrors ? (grossPerformance ?? null) : null, grossPerformancePercentage: !hasErrors ? (grossPerformancePercentage ?? null) @@ -426,9 +431,8 @@ export abstract class PortfolioCalculator { investment: totalInvestment, investmentWithCurrencyEffect: totalInvestmentWithCurrencyEffect, marketPrice: - marketSymbolMap[endDateString]?.[item.symbol]?.toNumber() ?? null, - marketPriceInBaseCurrency: - marketPriceInBaseCurrency?.toNumber() ?? null, + marketSymbolMap[endDateString]?.[item.symbol]?.toNumber() ?? 1, + marketPriceInBaseCurrency: marketPriceInBaseCurrency?.toNumber() ?? 1, netPerformance: !hasErrors ? (netPerformance ?? null) : null, netPerformancePercentage: !hasErrors ? (netPerformancePercentage ?? null) @@ -442,7 +446,6 @@ export abstract class PortfolioCalculator { quantity: item.quantity, symbol: item.symbol, tags: item.tags, - transactionCount: item.transactionCount, valueInBaseCurrency: new Big(marketPriceInBaseCurrency).mul( item.quantity ) @@ -882,7 +885,7 @@ export abstract class PortfolioCalculator { // Make sure some key dates are present for (const dateRange of ['1d', '1y', '5y', 'max', 'mtd', 'wtd', 'ytd']) { const { endDate: dateRangeEnd, startDate: dateRangeStart } = - getIntervalFromDateRange(dateRange); + getIntervalFromDateRange({ dateRange }); if ( !isBefore(dateRangeStart, startDate) && @@ -931,6 +934,7 @@ export abstract class PortfolioCalculator { for (const { date, fee, + feeInBaseCurrency, quantity, SymbolProfile, tags, @@ -990,16 +994,18 @@ export abstract class PortfolioCalculator { investment, skipErrors, symbol, + activitiesCount: oldAccumulatedSymbol.activitiesCount + 1, averagePrice: newQuantity.eq(0) ? new Big(0) : investment.div(newQuantity).abs(), + dateOfFirstActivity: oldAccumulatedSymbol.dateOfFirstActivity, dividend: new Big(0), fee: oldAccumulatedSymbol.fee.plus(fee), - firstBuyDate: oldAccumulatedSymbol.firstBuyDate, + feeInBaseCurrency: + oldAccumulatedSymbol.feeInBaseCurrency.plus(feeInBaseCurrency), includeInHoldings: oldAccumulatedSymbol.includeInHoldings, quantity: newQuantity, - tags: oldAccumulatedSymbol.tags.concat(tags), - transactionCount: oldAccumulatedSymbol.transactionCount + 1 + tags: oldAccumulatedSymbol.tags.concat(tags) }; } else { currentTransactionPointItem = { @@ -1007,16 +1013,17 @@ export abstract class PortfolioCalculator { currency, dataSource, fee, + feeInBaseCurrency, skipErrors, symbol, tags, + activitiesCount: 1, averagePrice: unitPrice, + dateOfFirstActivity: date, dividend: new Big(0), - firstBuyDate: date, includeInHoldings: INVESTMENT_ACTIVITY_TYPES.includes(type), investment: unitPrice.mul(quantity).mul(factor), - quantity: quantity.mul(factor), - transactionCount: 1 + quantity: quantity.mul(factor) }; } diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts index f0e2f6488..9a93d0419 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-buy.spec.ts @@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-22'), feeInAssetProfileCurrency: 1.55, + feeInBaseCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -102,6 +103,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-30'), feeInAssetProfileCurrency: 1.65, + feeInBaseCurrency: 1.65, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -131,20 +133,26 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('595.6'), errors: [], hasErrors: false, positions: [ { + activitiesCount: 2, averagePrice: new Big('139.75'), currency: 'CHF', dataSource: 'YAHOO', + dateOfFirstActivity: '2021-11-22', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('3.2'), feeInBaseCurrency: new Big('3.2'), - firstBuyDate: '2021-11-22', grossPerformance: new Big('36.6'), grossPerformancePercentage: new Big('0.07706261539956593567'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -170,7 +178,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '474.93846153846153846154' ), - transactionCount: 2, valueInBaseCurrency: new Big('595.6') } ], @@ -187,6 +194,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.07032490039195362, netPerformanceInPercentageWithCurrencyEffect: 0.07032490039195362, netPerformanceWithCurrencyEffect: 33.4, + totalInvestment: 559, totalInvestmentValueWithCurrencyEffect: 559 }) ); @@ -200,6 +208,10 @@ describe('PortfolioCalculator', () => { { date: '2021-11-01', investment: 559 }, { date: '2021-12-01', investment: 0 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2021-01-01', investment: 559 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts index 10b1fabd3..c876d0db1 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell-in-two-activities.spec.ts @@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-22'), feeInAssetProfileCurrency: 1.55, + feeInBaseCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -102,6 +103,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-30'), feeInAssetProfileCurrency: 1.65, + feeInBaseCurrency: 1.65, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -117,6 +119,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-30'), feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -146,20 +149,26 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('0'), errors: [], hasErrors: false, positions: [ { + activitiesCount: 3, averagePrice: new Big('0'), currency: 'CHF', dataSource: 'YAHOO', + dateOfFirstActivity: '2021-11-22', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('3.2'), feeInBaseCurrency: new Big('3.2'), - firstBuyDate: '2021-11-22', grossPerformance: new Big('-12.6'), grossPerformancePercentage: new Big('-0.04408677396780965649'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -183,7 +192,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '285.80000000000000396627' ), - transactionCount: 3, valueInBaseCurrency: new Big('0') } ], @@ -200,6 +208,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: -0.05528341497550734703, netPerformanceInPercentageWithCurrencyEffect: -0.05528341497550734703, netPerformanceWithCurrencyEffect: -15.8, + totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0 }) ); @@ -213,6 +222,10 @@ describe('PortfolioCalculator', () => { { date: '2021-11-01', investment: 0 }, { date: '2021-12-01', investment: 0 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2021-01-01', investment: 0 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts index 32cd9f7d4..ae921d6d9 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy-and-sell.spec.ts @@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-22'), feeInAssetProfileCurrency: 1.55, + feeInBaseCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -102,6 +103,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-30'), feeInAssetProfileCurrency: 1.65, + feeInBaseCurrency: 1.65, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -131,20 +133,26 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('0'), errors: [], hasErrors: false, positions: [ { + activitiesCount: 2, averagePrice: new Big('0'), currency: 'CHF', dataSource: 'YAHOO', + dateOfFirstActivity: '2021-11-22', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('3.2'), feeInBaseCurrency: new Big('3.2'), - firstBuyDate: '2021-11-22', grossPerformance: new Big('-12.6'), grossPerformancePercentage: new Big('-0.0440867739678096571'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -168,7 +176,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('285.8'), timeWeightedInvestmentWithCurrencyEffect: new Big('285.8'), - transactionCount: 2, valueInBaseCurrency: new Big('0') } ], @@ -185,6 +192,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: -0.05528341497550734703, netPerformanceInPercentageWithCurrencyEffect: -0.05528341497550734703, netPerformanceWithCurrencyEffect: -15.8, + totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0 }) ); @@ -198,6 +206,10 @@ describe('PortfolioCalculator', () => { { date: '2021-11-01', investment: 0 }, { date: '2021-12-01', investment: 0 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2021-01-01', investment: 0 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts index bfa4d06f3..6207f1417 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-baln-buy.spec.ts @@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-30'), feeInAssetProfileCurrency: 1.55, + feeInBaseCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -122,20 +123,26 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('297.8'), errors: [], hasErrors: false, positions: [ { + activitiesCount: 1, averagePrice: new Big('136.6'), currency: 'CHF', dataSource: 'YAHOO', + dateOfFirstActivity: '2021-11-30', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('1.55'), feeInBaseCurrency: new Big('1.55'), - firstBuyDate: '2021-11-30', grossPerformance: new Big('24.6'), grossPerformancePercentage: new Big('0.09004392386530014641'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -165,7 +172,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('273.2'), timeWeightedInvestmentWithCurrencyEffect: new Big('273.2'), - transactionCount: 1, valueInBaseCurrency: new Big('297.8') } ], @@ -186,6 +192,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.08437042459736457, netPerformanceInPercentageWithCurrencyEffect: 0.08437042459736457, netPerformanceWithCurrencyEffect: 23.05, + totalInvestment: 273.2, totalInvestmentValueWithCurrencyEffect: 273.2 }) ); @@ -198,6 +205,10 @@ describe('PortfolioCalculator', () => { { date: '2021-11-01', investment: 273.2 }, { date: '2021-12-01', investment: 0 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2021-01-01', investment: 273.2 } + ]); }); it.only('with BALN.SW buy (with unit price lower than closing price)', async () => { @@ -208,6 +219,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-30'), feeInAssetProfileCurrency: 1.55, + feeInBaseCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -247,6 +259,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-30'), feeInAssetProfileCurrency: 1.55, + feeInBaseCurrency: 1.55, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts index 84ea6c251..774c1d2f6 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur-in-base-currency-eur.spec.ts @@ -110,6 +110,7 @@ describe('PortfolioCalculator', () => { ...activity, date: parseDate(activity.date), feeInAssetProfileCurrency: 4.46, + feeInBaseCurrency: 3.94, SymbolProfile: { ...symbolProfileDummyData, currency: 'USD', diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts index 32b3f05c2..055356325 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btceur.spec.ts @@ -98,6 +98,7 @@ describe('PortfolioCalculator', () => { ...activity, date: parseDate(activity.date), feeInAssetProfileCurrency: 4.46, + feeInBaseCurrency: 4.46, SymbolProfile: { ...symbolProfileDummyData, currency: 'USD', @@ -131,6 +132,11 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2021-12-11', investmentValueWithCurrencyEffect: 0, @@ -189,14 +195,15 @@ describe('PortfolioCalculator', () => { hasErrors: false, positions: [ { + activitiesCount: 1, averagePrice: new Big('44558.42'), currency: 'USD', dataSource: 'YAHOO', + dateOfFirstActivity: '2021-12-12', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('4.46'), feeInBaseCurrency: new Big('4.46'), - firstBuyDate: '2021-12-12', grossPerformance: new Big('-1458.72'), grossPerformancePercentage: new Big('-0.03273724696701543726'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -220,7 +227,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('44558.42'), timeWeightedInvestmentWithCurrencyEffect: new Big('44558.42'), - transactionCount: 1, valueInBaseCurrency: new Big('43099.7') } ], @@ -244,6 +250,11 @@ describe('PortfolioCalculator', () => { { date: '2021-12-01', investment: 44558.42 }, { date: '2022-01-01', investment: 0 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2021-01-01', investment: 44558.42 }, + { date: '2022-01-01', investment: 0 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts index 0c111fab2..11765fc49 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-buy-and-sell-partially.spec.ts @@ -100,6 +100,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2015-01-01'), feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, quantity: 2, SymbolProfile: { ...symbolProfileDummyData, @@ -115,6 +116,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2017-12-31'), feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -144,6 +146,11 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('13298.425356'), errors: [], @@ -151,14 +158,15 @@ describe('PortfolioCalculator', () => { hasErrors: false, positions: [ { + activitiesCount: 2, averagePrice: new Big('320.43'), currency: 'USD', dataSource: 'YAHOO', + dateOfFirstActivity: '2015-01-01', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('0'), feeInBaseCurrency: new Big('0'), - firstBuyDate: '2015-01-01', grossPerformance: new Big('27172.74').mul(0.97373), grossPerformancePercentage: new Big('0.4241983590271396608571'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -186,7 +194,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '636.79389574611155533947' ), - transactionCount: 2, valueInBaseCurrency: new Big('13298.425356') } ], @@ -203,6 +210,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 42.41983590271396609433, netPerformanceInPercentageWithCurrencyEffect: 41.64017412624815597854, netPerformanceWithCurrencyEffect: 26516.208701400000064086, + totalInvestment: 318.542667299999967957, totalInvestmentValueWithCurrencyEffect: 318.542667299999967957 }) ); @@ -251,6 +259,13 @@ describe('PortfolioCalculator', () => { { date: '2017-12-01', investment: -318.54266729999995 }, { date: '2018-01-01', investment: 0 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2015-01-01', investment: 637.0853345999999 }, + { date: '2016-01-01', investment: 0 }, + { date: '2017-01-01', investment: -318.54266729999995 }, + { date: '2018-01-01', investment: 0 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts index 618dc805c..6a45f79c6 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd-short.spec.ts @@ -98,6 +98,7 @@ describe('PortfolioCalculator', () => { ...activity, date: parseDate(activity.date), feeInAssetProfileCurrency: activity.fee, + feeInBaseCurrency: activity.fee, SymbolProfile: { ...symbolProfileDummyData, currency: 'USD', diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts index 716ec7a59..64882061f 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-btcusd.spec.ts @@ -98,6 +98,7 @@ describe('PortfolioCalculator', () => { ...activity, date: parseDate(activity.date), feeInAssetProfileCurrency: 4.46, + feeInBaseCurrency: 4.46, SymbolProfile: { ...symbolProfileDummyData, currency: 'USD', @@ -131,6 +132,11 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2021-12-11', investmentValueWithCurrencyEffect: 0, @@ -189,14 +195,15 @@ describe('PortfolioCalculator', () => { hasErrors: false, positions: [ { + activitiesCount: 1, averagePrice: new Big('44558.42'), currency: 'USD', dataSource: 'YAHOO', + dateOfFirstActivity: '2021-12-12', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('4.46'), feeInBaseCurrency: new Big('4.46'), - firstBuyDate: '2021-12-12', grossPerformance: new Big('-1458.72'), grossPerformancePercentage: new Big('-0.03273724696701543726'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -220,7 +227,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('44558.42'), timeWeightedInvestmentWithCurrencyEffect: new Big('44558.42'), - transactionCount: 1, valueInBaseCurrency: new Big('43099.7') } ], @@ -244,6 +250,11 @@ describe('PortfolioCalculator', () => { { date: '2021-12-01', investment: 44558.42 }, { date: '2022-01-01', investment: 0 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2021-01-01', investment: 44558.42 }, + { date: '2022-01-01', investment: 0 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts index db6e08151..217a67c49 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-cash.spec.ts @@ -1,6 +1,6 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { userDummyData } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; @@ -14,10 +14,11 @@ import { ExchangeRateDataServiceMock } from '@ghostfolio/api/services/exchange-r 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 { HistoricalDataItem } from '@ghostfolio/common/interfaces'; +import { TimelinePosition } from '@ghostfolio/common/models'; import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; import { DataSource } from '@prisma/client'; +import { Big } from 'big.js'; import { randomUUID } from 'node:crypto'; jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { @@ -61,11 +62,11 @@ jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { describe('PortfolioCalculator', () => { let accountBalanceService: AccountBalanceService; let accountService: AccountService; + let activitiesService: ActivitiesService; let configurationService: ConfigurationService; let currentRateService: CurrentRateService; let dataProviderService: DataProviderService; let exchangeRateDataService: ExchangeRateDataService; - let orderService: OrderService; let portfolioCalculatorFactory: PortfolioCalculatorFactory; let portfolioSnapshotService: PortfolioSnapshotService; let redisCacheService: RedisCacheService; @@ -105,13 +106,13 @@ describe('PortfolioCalculator', () => { ); currentRateService = new CurrentRateService( - dataProviderService, null, + dataProviderService, null, null ); - orderService = new OrderService( + activitiesService = new ActivitiesService( accountBalanceService, accountService, null, @@ -182,17 +183,17 @@ describe('PortfolioCalculator', () => { .spyOn(dataProviderService, 'getDataSourceForExchangeRates') .mockReturnValue(DataSource.YAHOO); - jest.spyOn(orderService, 'getOrders').mockResolvedValue({ + jest.spyOn(activitiesService, 'getActivities').mockResolvedValue({ activities: [], count: 0 }); - const { activities } = await orderService.getOrdersForPortfolioCalculator( - { + const { activities } = + await activitiesService.getActivitiesForPortfolioCalculator({ userCurrency: 'CHF', - userId: userDummyData.id - } - ); + userId: userDummyData.id, + withCash: true + }); jest.spyOn(currentRateService, 'getValues').mockResolvedValue({ dataProviderInfos: [], @@ -200,90 +201,88 @@ describe('PortfolioCalculator', () => { values: [] }); + const accountBalanceItems = + await accountBalanceService.getAccountBalanceItems({ + userCurrency: 'CHF', + userId: userDummyData.id + }); + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ + accountBalanceItems, activities, calculationType: PerformanceCalculationType.ROAI, currency: 'CHF', userId: userDummyData.id }); - const { historicalData } = await portfolioCalculator.computeSnapshot(); - - const historicalData20231231 = historicalData.find(({ date }) => { - return date === '2023-12-31'; - }); - const historicalData20240101 = historicalData.find(({ date }) => { - return date === '2024-01-01'; - }); - const historicalData20241231 = historicalData.find(({ date }) => { - return date === '2024-12-31'; - }); + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); - /** - * Investment value with currency effect: 1000 USD * 0.85 = 850 CHF - * Total investment: 1000 USD * 0.91 = 910 CHF - * Value (current): 1000 USD * 0.91 = 910 CHF - * Value with currency effect: 1000 USD * 0.85 = 850 CHF - */ - expect(historicalData20231231).toMatchObject({ - date: '2023-12-31', - investmentValueWithCurrencyEffect: 850, - netPerformance: 0, - netPerformanceInPercentage: 0, - netPerformanceInPercentageWithCurrencyEffect: 0, - netPerformanceWithCurrencyEffect: 0, - netWorth: 850, - totalAccountBalance: 0, - totalInvestment: 910, - totalInvestmentValueWithCurrencyEffect: 850, - value: 910, - valueWithCurrencyEffect: 850 + const position = portfolioSnapshot.positions.find(({ symbol }) => { + return symbol === 'USD'; }); /** - * Net performance with currency effect: (1000 * 0.86) - (1000 * 0.85) = 10 CHF - * Total investment: 1000 USD * 0.91 = 910 CHF - * Total investment value with currency effect: 1000 USD * 0.85 = 850 CHF - * Value (current): 1000 USD * 0.91 = 910 CHF - * Value with currency effect: 1000 USD * 0.86 = 860 CHF + * Investment: 2000 USD * 0.91 = 1820 CHF + * Investment value with currency effect: (1000 USD * 0.85) + (1000 USD * 0.90) = 1750 CHF + * Net performance: (1000 USD * 1.0) - (1000 USD * 1.0) = 0 CHF + * Total account balance: 2000 USD * 0.85 = 1700 CHF (using the exchange rate on 2024-12-31) + * Value in base currency: 2000 USD * 0.91 = 1820 CHF */ - expect(historicalData20240101).toMatchObject({ - date: '2024-01-01', - investmentValueWithCurrencyEffect: 0, - netPerformance: 0, - netPerformanceInPercentage: 0, - netPerformanceInPercentageWithCurrencyEffect: 0.011764705882352941, - netPerformanceWithCurrencyEffect: 10, - netWorth: 860, - totalAccountBalance: 0, - totalInvestment: 910, - totalInvestmentValueWithCurrencyEffect: 850, - value: 910, - valueWithCurrencyEffect: 860 + expect(position).toMatchObject({ + activitiesCount: 2, + averagePrice: new Big(1), + currency: 'USD', + dataSource: DataSource.YAHOO, + dateOfFirstActivity: '2023-12-31', + dividend: new Big(0), + dividendInBaseCurrency: new Big(0), + fee: new Big(0), + feeInBaseCurrency: new Big(0), + grossPerformance: new Big(0), + grossPerformancePercentage: new Big(0), + grossPerformancePercentageWithCurrencyEffect: new Big( + '0.08211603004634809014' + ), + grossPerformanceWithCurrencyEffect: new Big(70), + includeInTotalAssetValue: false, + investment: new Big(1820), + investmentWithCurrencyEffect: new Big(1750), + marketPrice: 1, + marketPriceInBaseCurrency: 0.91, + netPerformance: new Big(0), + netPerformancePercentage: new Big(0), + netPerformancePercentageWithCurrencyEffectMap: { + '1d': new Big('0.01111111111111111111'), + '1y': new Big('0.06937181021989792704'), + '5y': new Big('0.0818817546090273363'), + max: new Big('0.0818817546090273363'), + mtd: new Big('0.01111111111111111111'), + wtd: new Big('-0.05517241379310344828'), + ytd: new Big('0.01111111111111111111') + }, + netPerformanceWithCurrencyEffectMap: { + '1d': new Big(20), + '1y': new Big(60), + '5y': new Big(70), + max: new Big(70), + mtd: new Big(20), + wtd: new Big(-80), + ytd: new Big(20) + }, + quantity: new Big(2000), + symbol: 'USD', + timeWeightedInvestment: new Big('912.47956403269754768392'), + timeWeightedInvestmentWithCurrencyEffect: new Big( + '852.45231607629427792916' + ), + valueInBaseCurrency: new Big(1820) }); - /** - * Investment value with currency effect: 1000 USD * 0.90 = 900 CHF - * Net performance: (1000 USD * 1.0) - (1000 USD * 1.0) = 0 CHF - * Net performance with currency effect: (1000 USD * 0.9) - (1000 USD * 0.85) = 50 CHF - * Total investment: 2000 USD * 0.91 = 1820 CHF - * Total investment value with currency effect: (1000 USD * 0.85) + (1000 USD * 0.90) = 1750 CHF - * Value (current): 2000 USD * 0.91 = 1820 CHF - * Value with currency effect: 2000 USD * 0.9 = 1800 CHF - */ - expect(historicalData20241231).toMatchObject({ - date: '2024-12-31', - investmentValueWithCurrencyEffect: 900, - netPerformance: 0, - netPerformanceInPercentage: 0, - netPerformanceInPercentageWithCurrencyEffect: 0.058823529411764705, - netPerformanceWithCurrencyEffect: 50, - netWorth: 1800, - totalAccountBalance: 0, - totalInvestment: 1820, - totalInvestmentValueWithCurrencyEffect: 1750, - value: 1820, - valueWithCurrencyEffect: 1800 + expect(portfolioSnapshot).toMatchObject({ + hasErrors: false, + totalFeesWithCurrencyEffect: new Big(0), + totalInterestWithCurrencyEffect: new Big(0), + totalLiabilitiesWithCurrencyEffect: new Big(0) }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts index aae77c876..a3fbc0758 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-fee.spec.ts @@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-09-01'), feeInAssetProfileCurrency: 49, + feeInBaseCurrency: 49, quantity: 0, SymbolProfile: { ...symbolProfileDummyData, @@ -127,6 +128,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0, netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, + totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts index 495728e22..122a9aaed 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-googl-buy.spec.ts @@ -99,6 +99,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2023-01-03'), feeInAssetProfileCurrency: 1, + feeInBaseCurrency: 0.9238, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -128,20 +129,26 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('103.10483'), errors: [], hasErrors: false, positions: [ { + activitiesCount: 1, averagePrice: new Big('89.12'), currency: 'USD', dataSource: 'YAHOO', + dateOfFirstActivity: '2023-01-03', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('1'), feeInBaseCurrency: new Big('0.9238'), - firstBuyDate: '2023-01-03', grossPerformance: new Big('27.33').mul(0.8854), grossPerformancePercentage: new Big('0.3066651705565529623'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -165,7 +172,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('89.12').mul(0.8854), timeWeightedInvestmentWithCurrencyEffect: new Big('82.329056'), - transactionCount: 1, valueInBaseCurrency: new Big('103.10483') } ], @@ -182,6 +188,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.29544434470377019749, netPerformanceInPercentageWithCurrencyEffect: 0.24112962014285697628, netPerformanceWithCurrencyEffect: 19.851974, + totalInvestment: new Big('89.12').mul(0.8854).toNumber(), totalInvestmentValueWithCurrencyEffect: 82.329056 }) ); @@ -217,6 +224,10 @@ describe('PortfolioCalculator', () => { investment: 0 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2023-01-01', investment: 82.329056 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-jnug-buy-and-sell-and-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-jnug-buy-and-sell-and-buy-and-sell.spec.ts new file mode 100644 index 000000000..d5b22e864 --- /dev/null +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-jnug-buy-and-sell-and-buy-and-sell.spec.ts @@ -0,0 +1,190 @@ +import { + activityDummyData, + loadExportFile, + symbolProfileDummyData, + userDummyData +} from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator-test-utils'; +import { 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 { Activity, ExportResponse } from '@ghostfolio/common/interfaces'; +import { PerformanceCalculationType } from '@ghostfolio/common/types/performance-calculation-type.type'; + +import { Big } from 'big.js'; +import { join } from 'node:path'; + +jest.mock('@ghostfolio/api/app/portfolio/current-rate.service', () => { + return { + CurrentRateService: jest.fn().mockImplementation(() => { + return CurrentRateServiceMock; + }) + }; +}); + +jest.mock( + '@ghostfolio/api/services/queues/portfolio-snapshot/portfolio-snapshot.service', + () => { + return { + PortfolioSnapshotService: jest.fn().mockImplementation(() => { + return PortfolioSnapshotServiceMock; + }) + }; + } +); + +jest.mock('@ghostfolio/api/app/redis-cache/redis-cache.service', () => { + return { + RedisCacheService: jest.fn().mockImplementation(() => { + return RedisCacheServiceMock; + }) + }; +}); + +describe('PortfolioCalculator', () => { + let exportResponse: ExportResponse; + + let configurationService: ConfigurationService; + let currentRateService: CurrentRateService; + let exchangeRateDataService: ExchangeRateDataService; + let portfolioCalculatorFactory: PortfolioCalculatorFactory; + let portfolioSnapshotService: PortfolioSnapshotService; + let redisCacheService: RedisCacheService; + + beforeAll(() => { + exportResponse = loadExportFile( + join( + __dirname, + '../../../../../../../test/import/ok/jnug-buy-and-sell-and-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 JNUG buy and sell', async () => { + jest.useFakeTimers().setSystemTime(parseDate('2025-12-28').getTime()); + + const activities: Activity[] = exportResponse.activities.map( + (activity) => ({ + ...activityDummyData, + ...activity, + date: parseDate(activity.date), + feeInAssetProfileCurrency: activity.fee, + feeInBaseCurrency: activity.fee, + SymbolProfile: { + ...symbolProfileDummyData, + currency: activity.currency, + dataSource: activity.dataSource, + name: 'Direxion Daily Junior Gold Miners Index Bull 2X Shares', + symbol: activity.symbol + }, + unitPriceInAssetProfileCurrency: activity.unitPrice + }) + ); + + const portfolioCalculator = portfolioCalculatorFactory.createCalculator({ + activities, + calculationType: PerformanceCalculationType.ROAI, + currency: exportResponse.user.settings.currency, + userId: userDummyData.id + }); + + const portfolioSnapshot = await portfolioCalculator.computeSnapshot(); + + const investments = portfolioCalculator.getInvestments(); + + const investmentsByMonth = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'month' + }); + + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + + expect(portfolioSnapshot).toMatchObject({ + currentValueInBaseCurrency: new Big('0'), + errors: [], + hasErrors: false, + positions: [ + { + activitiesCount: 4, + averagePrice: new Big('0'), + currency: 'USD', + dataSource: 'YAHOO', + dateOfFirstActivity: '2025-12-11', + dividend: new Big('0'), + dividendInBaseCurrency: new Big('0'), + fee: new Big('4'), + feeInBaseCurrency: new Big('4'), + grossPerformance: new Big('43.95'), // (1890.00 - 1885.05) + (2080.10 - 2041.10) + grossPerformanceWithCurrencyEffect: new Big('43.95'), // (1890.00 - 1885.05) + (2080.10 - 2041.10) + investment: new Big('0'), + investmentWithCurrencyEffect: new Big('0'), + netPerformance: new Big('39.95'), // (1890.00 - 1885.05) + (2080.10 - 2041.10) - 4 + netPerformanceWithCurrencyEffectMap: { + max: new Big('39.95') // (1890.00 - 1885.05) + (2080.10 - 2041.10) - 4 + }, + marketPrice: 237.8000030517578, + marketPriceInBaseCurrency: 237.8000030517578, + quantity: new Big('0'), + symbol: 'JNUG', + tags: [], + valueInBaseCurrency: new Big('0') + } + ], + totalFeesWithCurrencyEffect: new Big('4'), + totalInterestWithCurrencyEffect: new Big('0'), + totalInvestment: new Big('0'), + totalInvestmentWithCurrencyEffect: new Big('0'), + totalLiabilitiesWithCurrencyEffect: new Big('0') + }); + + expect(investments).toEqual([ + { date: '2025-12-11', investment: new Big('1885.05') }, + { date: '2025-12-18', investment: new Big('2041.1') }, + { date: '2025-12-28', investment: new Big('0') } + ]); + + expect(investmentsByMonth).toEqual([ + { date: '2025-12-01', investment: 0 } + ]); + + expect(investmentsByYear).toEqual([ + { date: '2025-01-01', investment: 0 } + ]); + }); + }); +}); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts index 1fd88dacc..acbf6a66b 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-liability.spec.ts @@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2023-01-01'), // Date in future feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-and-sell.spec.ts index 4c8ccdcf5..baa6ae1ed 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-and-sell.spec.ts @@ -80,6 +80,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2024-03-08'), feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, quantity: 0.3333333333333333, SymbolProfile: { ...symbolProfileDummyData, @@ -94,8 +95,9 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2024-03-13'), - quantity: 0.6666666666666666, feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, + quantity: 0.6666666666666666, SymbolProfile: { ...symbolProfileDummyData, currency: 'USD', @@ -109,8 +111,9 @@ describe('PortfolioCalculator', () => { { ...activityDummyData, date: new Date('2024-03-14'), - quantity: 1, feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, + quantity: 1, SymbolProfile: { ...symbolProfileDummyData, currency: 'USD', diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts index 0331e163e..e7eff6682 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-msft-buy-with-dividend.spec.ts @@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-09-16'), feeInAssetProfileCurrency: 19, + feeInBaseCurrency: 19, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -102,6 +103,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2021-11-16'), feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -129,13 +131,14 @@ describe('PortfolioCalculator', () => { hasErrors: false, positions: [ { + activitiesCount: 2, averagePrice: new Big('298.58'), currency: 'USD', dataSource: 'YAHOO', + dateOfFirstActivity: '2021-09-16', dividend: new Big('0.62'), dividendInBaseCurrency: new Big('0.62'), fee: new Big('19'), - firstBuyDate: '2021-09-16', grossPerformance: new Big('33.25'), grossPerformancePercentage: new Big('0.11136043941322258691'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -159,8 +162,7 @@ describe('PortfolioCalculator', () => { }, quantity: new Big('1'), symbol: 'MSFT', - tags: [], - transactionCount: 2 + tags: [] } ], totalFeesWithCurrencyEffect: new Big('19'), @@ -172,6 +174,7 @@ describe('PortfolioCalculator', () => { expect(portfolioSnapshot.historicalData.at(-1)).toMatchObject( expect.objectContaining({ + totalInvestment: 298.58, totalInvestmentValueWithCurrencyEffect: 298.58 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts index fdd9e4718..6c47af7ca 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-no-orders.spec.ts @@ -93,6 +93,11 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big(0), hasErrors: false, @@ -108,6 +113,8 @@ describe('PortfolioCalculator', () => { expect(investments).toEqual([]); expect(investmentsByMonth).toEqual([]); + + expect(investmentsByYear).toEqual([]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts index 650944421..3034e3a1f 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell-partially.spec.ts @@ -101,6 +101,7 @@ describe('PortfolioCalculator', () => { ...activity, date: parseDate(activity.date), feeInAssetProfileCurrency: activity.fee, + feeInBaseCurrency: activity.fee, SymbolProfile: { ...symbolProfileDummyData, currency: activity.currency, @@ -128,20 +129,26 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot).toMatchObject({ currentValueInBaseCurrency: new Big('87.8'), errors: [], hasErrors: false, positions: [ { + activitiesCount: 2, averagePrice: new Big('75.80'), currency: 'CHF', dataSource: 'YAHOO', + dateOfFirstActivity: '2022-03-07', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('4.25'), feeInBaseCurrency: new Big('4.25'), - firstBuyDate: '2022-03-07', grossPerformance: new Big('21.93'), grossPerformancePercentage: new Big('0.15113417083448194384'), grossPerformancePercentageWithCurrencyEffect: new Big( @@ -167,7 +174,6 @@ describe('PortfolioCalculator', () => { timeWeightedInvestmentWithCurrencyEffect: new Big( '145.10285714285714285714' ), - transactionCount: 2, valueInBaseCurrency: new Big('87.8') } ], @@ -184,6 +190,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.12184460284330327256, netPerformanceInPercentageWithCurrencyEffect: 0.12184460284330327256, netPerformanceWithCurrencyEffect: 17.68, + totalInvestment: 75.8, totalInvestmentValueWithCurrencyEffect: 75.8 }) ); @@ -197,6 +204,10 @@ describe('PortfolioCalculator', () => { { date: '2022-03-01', investment: 151.6 }, { date: '2022-04-01', investment: -75.8 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2022-01-01', investment: 75.8 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts index 2e408dc3c..c79fdef58 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-novn-buy-and-sell.spec.ts @@ -101,6 +101,7 @@ describe('PortfolioCalculator', () => { ...activity, date: parseDate(activity.date), feeInAssetProfileCurrency: activity.fee, + feeInBaseCurrency: activity.fee, SymbolProfile: { ...symbolProfileDummyData, currency: activity.currency, @@ -128,6 +129,11 @@ describe('PortfolioCalculator', () => { groupBy: 'month' }); + const investmentsByYear = portfolioCalculator.getInvestmentsByGroup({ + data: portfolioSnapshot.historicalData, + groupBy: 'year' + }); + expect(portfolioSnapshot.historicalData[0]).toEqual({ date: '2022-03-06', investmentValueWithCurrencyEffect: 0, @@ -187,14 +193,15 @@ describe('PortfolioCalculator', () => { hasErrors: false, positions: [ { + activitiesCount: 2, averagePrice: new Big('0'), currency: 'CHF', dataSource: 'YAHOO', + dateOfFirstActivity: '2022-03-07', 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( @@ -218,7 +225,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('151.6'), timeWeightedInvestmentWithCurrencyEffect: new Big('151.6'), - transactionCount: 2, valueInBaseCurrency: new Big('0') } ], @@ -235,6 +241,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0.13100263852242744063, netPerformanceInPercentageWithCurrencyEffect: 0.13100263852242744063, netPerformanceWithCurrencyEffect: 19.86, + totalInvestment: 0, totalInvestmentValueWithCurrencyEffect: 0 }) ); @@ -248,6 +255,10 @@ describe('PortfolioCalculator', () => { { date: '2022-03-01', investment: 151.6 }, { date: '2022-04-01', investment: -151.6 } ]); + + expect(investmentsByYear).toEqual([ + { date: '2022-01-01', investment: 0 } + ]); }); }); }); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts index 3c7c3be4b..e518a5994 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator-valuable.spec.ts @@ -87,6 +87,7 @@ describe('PortfolioCalculator', () => { ...activityDummyData, date: new Date('2022-01-01'), feeInAssetProfileCurrency: 0, + feeInBaseCurrency: 0, quantity: 1, SymbolProfile: { ...symbolProfileDummyData, @@ -115,21 +116,22 @@ describe('PortfolioCalculator', () => { hasErrors: false, positions: [ { + activitiesCount: 1, averagePrice: new Big('500000'), currency: 'USD', dataSource: 'MANUAL', + dateOfFirstActivity: '2022-01-01', dividend: new Big('0'), dividendInBaseCurrency: new Big('0'), fee: new Big('0'), feeInBaseCurrency: new Big('0'), - firstBuyDate: '2022-01-01', grossPerformance: new Big('0'), grossPerformancePercentage: new Big('0'), grossPerformancePercentageWithCurrencyEffect: new Big('0'), grossPerformanceWithCurrencyEffect: new Big('0'), investment: new Big('500000'), investmentWithCurrencyEffect: new Big('500000'), - marketPrice: null, + marketPrice: 1, marketPriceInBaseCurrency: 500000, netPerformance: new Big('0'), netPerformancePercentage: new Big('0'), @@ -144,7 +146,6 @@ describe('PortfolioCalculator', () => { tags: [], timeWeightedInvestment: new Big('500000'), timeWeightedInvestmentWithCurrencyEffect: new Big('500000'), - transactionCount: 1, valueInBaseCurrency: new Big('500000') } ], @@ -161,6 +162,7 @@ describe('PortfolioCalculator', () => { netPerformanceInPercentage: 0, netPerformanceInPercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, + totalInvestment: 500000, totalInvestmentValueWithCurrencyEffect: 500000 }) ); diff --git a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts index 070d7543b..2841e9975 100644 --- a/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts +++ b/apps/api/src/app/portfolio/calculator/roai/portfolio-calculator.ts @@ -13,7 +13,14 @@ import { PerformanceCalculationType } from '@ghostfolio/common/types/performance import { Logger } from '@nestjs/common'; import { Big } from 'big.js'; -import { addMilliseconds, differenceInDays, format, isBefore } from 'date-fns'; +import { + addMilliseconds, + differenceInDays, + eachYearOfInterval, + format, + isBefore, + isThisYear +} from 'date-fns'; import { cloneDeep, sortBy } from 'lodash'; export class RoaiPortfolioCalculator extends PortfolioCalculator { @@ -34,7 +41,11 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { let totalTimeWeightedInvestment = new Big(0); let totalTimeWeightedInvestmentWithCurrencyEffect = new Big(0); - for (const currentPosition of positions) { + for (const currentPosition of positions.filter( + ({ includeInTotalAssetValue }) => { + return includeInTotalAssetValue; + } + )) { if (currentPosition.feeInBaseCurrency) { totalFeesWithCurrencyEffect = totalFeesWithCurrencyEffect.plus( currentPosition.feeInBaseCurrency @@ -615,6 +626,13 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { totalQuantityFromBuyTransactions ); + if (totalUnits.eq(0)) { + // Reset tracking variables when position is fully closed + totalInvestmentFromBuyTransactions = new Big(0); + totalInvestmentFromBuyTransactionsWithCurrencyEffect = new Big(0); + totalQuantityFromBuyTransactions = new Big(0); + } + if (PortfolioCalculator.ENABLE_LOGGING) { console.log( 'grossPerformanceFromSells', @@ -833,17 +851,16 @@ export class RoaiPortfolioCalculator extends PortfolioCalculator { 'max', 'mtd', 'wtd', - 'ytd' - // TODO: - // ...eachYearOfInterval({ end, start }) - // .filter((date) => { - // return !isThisYear(date); - // }) - // .map((date) => { - // return format(date, 'yyyy'); - // }) + 'ytd', + ...eachYearOfInterval({ end, start }) + .filter((date) => { + return !isThisYear(date); + }) + .map((date) => { + return format(date, 'yyyy'); + }) ] as DateRange[]) { - const dateInterval = getIntervalFromDateRange(dateRange); + const dateInterval = getIntervalFromDateRange({ dateRange }); const endDate = dateInterval.endDate; let startDate = dateInterval.startDate; diff --git a/apps/api/src/app/portfolio/current-rate.service.mock.ts b/apps/api/src/app/portfolio/current-rate.service.mock.ts index 4b4b8f00e..8e027f971 100644 --- a/apps/api/src/app/portfolio/current-rate.service.mock.ts +++ b/apps/api/src/app/portfolio/current-rate.service.mock.ts @@ -64,6 +64,17 @@ function mockGetValue(symbol: string, date: Date) { return { marketPrice: 0 }; + case 'JNUG': + if (isSameDay(parseDate('2025-12-10'), date)) { + return { marketPrice: 204.5599975585938 }; + } else if (isSameDay(parseDate('2025-12-17'), date)) { + return { marketPrice: 203.9700012207031 }; + } else if (isSameDay(parseDate('2025-12-28'), date)) { + return { marketPrice: 237.8000030517578 }; + } + + return { marketPrice: 0 }; + case 'MSFT': if (isSameDay(parseDate('2021-09-16'), date)) { return { marketPrice: 89.12 }; diff --git a/apps/api/src/app/portfolio/current-rate.service.spec.ts b/apps/api/src/app/portfolio/current-rate.service.spec.ts index d8b7482e7..5f2358679 100644 --- a/apps/api/src/app/portfolio/current-rate.service.spec.ts +++ b/apps/api/src/app/portfolio/current-rate.service.spec.ts @@ -114,9 +114,9 @@ describe('CurrentRateService', () => { marketDataService = new MarketDataService(null); currentRateService = new CurrentRateService( + null, dataProviderService, marketDataService, - null, null ); }); diff --git a/apps/api/src/app/portfolio/current-rate.service.ts b/apps/api/src/app/portfolio/current-rate.service.ts index 5d39a54bb..b454b01cd 100644 --- a/apps/api/src/app/portfolio/current-rate.service.ts +++ b/apps/api/src/app/portfolio/current-rate.service.ts @@ -1,4 +1,4 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { LogPerformance } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.interceptor'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; @@ -24,9 +24,9 @@ export class CurrentRateService { private static readonly MARKET_DATA_PAGE_SIZE = 50000; public constructor( + private readonly activitiesService: ActivitiesService, private readonly dataProviderService: DataProviderService, private readonly marketDataService: MarketDataService, - private readonly orderService: OrderService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @@ -129,10 +129,11 @@ export class CurrentRateService { if (!value) { // Fallback to unit price of latest activity - const latestActivity = await this.orderService.getLatestOrder({ - dataSource, - symbol - }); + const latestActivity = + await this.activitiesService.getLatestActivity({ + dataSource, + symbol + }); value = { dataSource, diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-order-item.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-order-item.interface.ts index 06e471d67..42759b521 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-order-item.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-order-item.interface.ts @@ -3,7 +3,6 @@ import { Big } from 'big.js'; import { PortfolioOrder } from './portfolio-order.interface'; export interface PortfolioOrderItem extends PortfolioOrder { - feeInBaseCurrency?: Big; feeInBaseCurrencyWithCurrencyEffect?: Big; itemType?: 'end' | 'start'; unitPriceFromMarketData?: Big; diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts index fcc8322fc..2dbd68f12 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-order.interface.ts @@ -3,6 +3,7 @@ import { Activity } from '@ghostfolio/common/interfaces'; export interface PortfolioOrder extends Pick { date: string; fee: Big; + feeInBaseCurrency: Big; quantity: Big; SymbolProfile: Pick< Activity['SymbolProfile'], diff --git a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts index 14e2e1f37..7f3f54ff5 100644 --- a/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/transaction-point-symbol.interface.ts @@ -2,18 +2,19 @@ import { AssetSubClass, DataSource, Tag } from '@prisma/client'; import { Big } from 'big.js'; export interface TransactionPointSymbol { + activitiesCount: number; assetSubClass: AssetSubClass; averagePrice: Big; currency: string; dataSource: DataSource; + dateOfFirstActivity: string; dividend: Big; fee: Big; - firstBuyDate: string; + feeInBaseCurrency: Big; includeInHoldings: boolean; investment: Big; quantity: Big; skipErrors: boolean; symbol: string; tags?: Tag[]; - transactionCount: number; } diff --git a/apps/api/src/app/portfolio/portfolio.controller.ts b/apps/api/src/app/portfolio/portfolio.controller.ts index 03796dad6..9c41aecb9 100644 --- a/apps/api/src/app/portfolio/portfolio.controller.ts +++ b/apps/api/src/app/portfolio/portfolio.controller.ts @@ -1,4 +1,4 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; import { @@ -63,10 +63,10 @@ import { UpdateHoldingTagsDto } from './update-holding-tags.dto'; @Controller('portfolio') export class PortfolioController { public constructor( + private readonly activitiesService: ActivitiesService, private readonly apiService: ApiService, private readonly configurationService: ConfigurationService, private readonly impersonationService: ImpersonationService, - private readonly orderService: OrderService, private readonly portfolioService: PortfolioService, @Inject(REQUEST) private readonly request: RequestWithUser ) {} @@ -187,7 +187,6 @@ export class PortfolioController { portfolioSummary = nullifyValuesInObject(summary, [ 'cash', - 'committedFunds', 'currentNetWorth', 'currentValueInBaseCurrency', 'dividendInBaseCurrency', @@ -195,15 +194,18 @@ export class PortfolioController { 'excludedAccountsAndActivities', 'fees', 'filteredValueInBaseCurrency', + 'fireWealth', 'grossPerformance', 'grossPerformanceWithCurrencyEffect', 'interestInBaseCurrency', 'items', 'liabilities', + 'liabilitiesInBaseCurrency', 'netPerformance', 'netPerformanceWithCurrencyEffect', 'totalBuy', 'totalInvestment', + 'totalInvestmentValueWithCurrencyEffect', 'totalSell', 'totalValueInBaseCurrency' ]); @@ -318,9 +320,9 @@ export class PortfolioController { await this.impersonationService.validateImpersonationId(impersonationId); const userCurrency = this.request.user.settings.settings.baseCurrency; - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); - const { activities } = await this.orderService.getOrders({ + const { activities } = await this.activitiesService.getActivities({ endDate, filters, startDate, @@ -329,7 +331,7 @@ export class PortfolioController { types: ['DIVIDEND'] }); - let dividends = await this.portfolioService.getDividends({ + let dividends = this.portfolioService.getDividends({ activities, groupBy }); @@ -637,7 +639,7 @@ export class PortfolioController { return report; } - @HasPermission(permissions.updateOrder) + @HasPermission(permissions.updateActivity) @Put('holding/:dataSource/:symbol/tags') @UseInterceptors(TransformDataSourceInRequestInterceptor) @UseGuards(AuthGuard('jwt'), HasPermissionGuard) diff --git a/apps/api/src/app/portfolio/portfolio.module.ts b/apps/api/src/app/portfolio/portfolio.module.ts index 6dd5811a3..65a9b71aa 100644 --- a/apps/api/src/app/portfolio/portfolio.module.ts +++ b/apps/api/src/app/portfolio/portfolio.module.ts @@ -1,7 +1,7 @@ import { AccessModule } from '@ghostfolio/api/app/access/access.module'; import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { UserModule } from '@ghostfolio/api/app/user/user.module'; import { PerformanceLoggingModule } from '@ghostfolio/api/interceptors/performance-logging/performance-logging.module'; @@ -34,6 +34,7 @@ import { RulesService } from './rules.service'; exports: [PortfolioService], imports: [ AccessModule, + ActivitiesModule, ApiModule, BenchmarkModule, ConfigurationModule, @@ -43,7 +44,6 @@ import { RulesService } from './rules.service'; I18nModule, ImpersonationModule, MarketDataModule, - OrderModule, PerformanceLoggingModule, PortfolioSnapshotQueueModule, PrismaModule, diff --git a/apps/api/src/app/portfolio/portfolio.service.ts b/apps/api/src/app/portfolio/portfolio.service.ts index 5613af9e7..60b413cf9 100644 --- a/apps/api/src/app/portfolio/portfolio.service.ts +++ b/apps/api/src/app/portfolio/portfolio.service.ts @@ -1,7 +1,7 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; import { AccountService } from '@ghostfolio/api/app/account/account.service'; import { CashDetails } from '@ghostfolio/api/app/account/interfaces/cash-details.interface'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { UserService } from '@ghostfolio/api/app/user/user.service'; import { getFactor } from '@ghostfolio/api/helper/portfolio.helper'; import { AccountClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rules/account-cluster-risk/current-investment'; @@ -13,7 +13,7 @@ import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rul import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/developed-markets'; import { EconomicMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/emerging-markets'; 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 { FeeRatioTotalInvestmentVolume } from '@ghostfolio/api/models/rules/fees/fee-ratio-total-investment-volume'; import { BuyingPower } from '@ghostfolio/api/models/rules/liquidity/buying-power'; import { RegionalMarketClusterRiskAsiaPacific } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/asia-pacific'; import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/emerging-markets'; @@ -105,13 +105,13 @@ export class PortfolioService { public constructor( private readonly accountBalanceService: AccountBalanceService, private readonly accountService: AccountService, + private readonly activitiesService: ActivitiesService, private readonly benchmarkService: BenchmarkService, private readonly calculatorFactory: PortfolioCalculatorFactory, private readonly dataProviderService: DataProviderService, private readonly exchangeRateDataService: ExchangeRateDataService, private readonly i18nService: I18nService, private readonly impersonationService: ImpersonationService, - private readonly orderService: OrderService, @Inject(REQUEST) private readonly request: RequestWithUser, private readonly rulesService: RulesService, private readonly symbolProfileService: SymbolProfileService, @@ -179,9 +179,9 @@ export class PortfolioService { return Promise.all( accounts.map(async (account) => { + let activitiesCount = 0; let dividendInBaseCurrency = 0; let interestInBaseCurrency = 0; - let transactionCount = 0; for (const { currency, @@ -214,7 +214,7 @@ export class PortfolioService { } if (!isDraft) { - transactionCount += 1; + activitiesCount += 1; } } @@ -223,9 +223,9 @@ export class PortfolioService { const result = { ...account, + activitiesCount, dividendInBaseCurrency, interestInBaseCurrency, - transactionCount, valueInBaseCurrency, allocationInPercentage: 0, balanceInBaseCurrency: this.exchangeRateDataService.toCurrency( @@ -262,6 +262,8 @@ export class PortfolioService { withExcludedAccounts }); + let activitiesCount = 0; + const searchQuery = filters.find(({ type }) => { return type === 'SEARCH_QUERY'; })?.id; @@ -281,9 +283,10 @@ export class PortfolioService { let totalDividendInBaseCurrency = new Big(0); let totalInterestInBaseCurrency = new Big(0); let totalValueInBaseCurrency = new Big(0); - let transactionCount = 0; for (const account of accounts) { + activitiesCount += account.activitiesCount; + totalBalanceInBaseCurrency = totalBalanceInBaseCurrency.plus( account.balanceInBaseCurrency ); @@ -296,7 +299,6 @@ export class PortfolioService { totalValueInBaseCurrency = totalValueInBaseCurrency.plus( account.valueInBaseCurrency ); - transactionCount += account.transactionCount; } for (const account of accounts) { @@ -310,7 +312,7 @@ export class PortfolioService { return { accounts, - transactionCount, + activitiesCount, totalBalanceInBaseCurrency: totalBalanceInBaseCurrency.toNumber(), totalDividendInBaseCurrency: totalDividendInBaseCurrency.toNumber(), totalInterestInBaseCurrency: totalInterestInBaseCurrency.toNumber(), @@ -318,13 +320,13 @@ export class PortfolioService { }; } - public async getDividends({ + public getDividends({ activities, groupBy }: { activities: Activity[]; groupBy?: GroupBy; - }): Promise { + }): InvestmentItem[] { let dividends = activities.map(({ currency, date, value }) => { return { date: format(date, DATE_FORMAT), @@ -401,10 +403,10 @@ export class PortfolioService { const user = await this.userService.user({ id: userId }); const userCurrency = this.getUserCurrency(user); - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + await this.activitiesService.getActivitiesForPortfolioCalculator({ filters, userCurrency, userId @@ -488,7 +490,7 @@ export class PortfolioService { ); const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + await this.activitiesService.getActivitiesForPortfolioCalculator({ filters, userCurrency, userId @@ -567,9 +569,10 @@ export class PortfolioService { } for (const { + activitiesCount, currency, + dateOfFirstActivity, dividend, - firstBuyDate, grossPerformance, grossPerformanceWithCurrencyEffect, grossPerformancePercentage, @@ -583,7 +586,6 @@ export class PortfolioService { quantity, symbol, tags, - transactionCount, valueInBaseCurrency } of positions) { if (isFilteredByClosedHoldings === true) { @@ -610,21 +612,43 @@ export class PortfolioService { } holdings[symbol] = { + activitiesCount, currency, markets, marketsAdvanced, marketPrice, symbol, tags, - transactionCount, allocationInPercentage: filteredValueInBaseCurrency.eq(0) ? 0 : valueInBaseCurrency.div(filteredValueInBaseCurrency).toNumber(), assetClass: assetProfile.assetClass, + assetProfile: { + assetClass: assetProfile.assetClass, + assetSubClass: assetProfile.assetSubClass, + countries: assetProfile.countries, + currency: assetProfile.currency, + dataSource: assetProfile.dataSource, + holdings: assetProfile.holdings.map( + ({ allocationInPercentage, name }) => { + return { + allocationInPercentage, + name, + valueInBaseCurrency: valueInBaseCurrency + .mul(allocationInPercentage) + .toNumber() + }; + } + ), + name: assetProfile.name, + sectors: assetProfile.sectors, + symbol: assetProfile.symbol, + url: assetProfile.url + }, assetSubClass: assetProfile.assetSubClass, countries: assetProfile.countries, dataSource: assetProfile.dataSource, - dateOfFirstActivity: parseDate(firstBuyDate), + dateOfFirstActivity: parseDate(dateOfFirstActivity), dividend: dividend?.toNumber() ?? 0, grossPerformance: grossPerformance?.toNumber() ?? 0, grossPerformancePercent: grossPerformancePercentage?.toNumber() ?? 0, @@ -756,7 +780,7 @@ export class PortfolioService { const userCurrency = this.getUserCurrency(user); const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + await this.activitiesService.getActivitiesForPortfolioCalculator({ userCurrency, userId }); @@ -789,11 +813,12 @@ export class PortfolioService { } const { + activitiesCount, averagePrice, currency, + dateOfFirstActivity, dividendInBaseCurrency, - fee, - firstBuyDate, + feeInBaseCurrency, grossPerformance, grossPerformancePercentage, grossPerformancePercentageWithCurrencyEffect, @@ -807,8 +832,7 @@ export class PortfolioService { quantity, tags, timeWeightedInvestment, - timeWeightedInvestmentWithCurrencyEffect, - transactionCount + timeWeightedInvestmentWithCurrencyEffect } = holding; const activitiesOfHolding = activities.filter(({ SymbolProfile }) => { @@ -819,7 +843,10 @@ export class PortfolioService { }); const dividendYieldPercent = getAnnualizedPerformancePercent({ - daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)), + daysInMarket: differenceInDays( + new Date(), + parseDate(dateOfFirstActivity) + ), netPerformancePercentage: timeWeightedInvestment.eq(0) ? new Big(0) : dividendInBaseCurrency.div(timeWeightedInvestment) @@ -827,7 +854,10 @@ export class PortfolioService { const dividendYieldPercentWithCurrencyEffect = getAnnualizedPerformancePercent({ - daysInMarket: differenceInDays(new Date(), parseDate(firstBuyDate)), + daysInMarket: differenceInDays( + new Date(), + parseDate(dateOfFirstActivity) + ), netPerformancePercentage: timeWeightedInvestmentWithCurrencyEffect.eq(0) ? new Big(0) : dividendInBaseCurrency.div(timeWeightedInvestmentWithCurrencyEffect) @@ -836,7 +866,7 @@ export class PortfolioService { const historicalData = await this.dataProviderService.getHistorical( [{ dataSource, symbol }], 'day', - parseISO(firstBuyDate), + parseISO(dateOfFirstActivity), new Date() ); @@ -901,7 +931,7 @@ export class PortfolioService { // Add historical entry for buy date, if no historical data available historicalDataArray.push({ averagePrice: activitiesOfHolding[0].unitPriceInAssetProfileCurrency, - date: firstBuyDate, + date: dateOfFirstActivity, marketPrice: activitiesOfHolding[0].unitPriceInAssetProfileCurrency, quantity: activitiesOfHolding[0].quantity }); @@ -914,25 +944,20 @@ export class PortfolioService { ); return { - firstBuyDate, + activitiesCount, + dateOfFirstActivity, marketPrice, marketPriceMax, marketPriceMin, SymbolProfile, tags, - activities: activitiesOfHolding, - activitiesCount: transactionCount, averagePrice: averagePrice.toNumber(), dataProviderInfo: portfolioCalculator.getDataProviderInfos()?.[0], dividendInBaseCurrency: dividendInBaseCurrency.toNumber(), dividendYieldPercent: dividendYieldPercent.toNumber(), dividendYieldPercentWithCurrencyEffect: dividendYieldPercentWithCurrencyEffect.toNumber(), - feeInBaseCurrency: this.exchangeRateDataService.toCurrency( - fee.toNumber(), - SymbolProfile.currency, - userCurrency - ), + feeInBaseCurrency: feeInBaseCurrency.toNumber(), grossPerformance: grossPerformance?.toNumber(), grossPerformancePercent: grossPerformancePercentage?.toNumber(), grossPerformancePercentWithCurrencyEffect: @@ -985,7 +1010,7 @@ export class PortfolioService { userId, userCurrency }), - this.orderService.getOrdersForPortfolioCalculator({ + this.activitiesService.getActivitiesForPortfolioCalculator({ filters, userCurrency, userId @@ -1004,7 +1029,8 @@ export class PortfolioService { netPerformancePercentage: 0, netPerformancePercentageWithCurrencyEffect: 0, netPerformanceWithCurrencyEffect: 0, - totalInvestment: 0 + totalInvestment: 0, + totalInvestmentValueWithCurrencyEffect: 0 } }; } @@ -1021,7 +1047,7 @@ export class PortfolioService { const { errors, hasErrors, historicalData } = await portfolioCalculator.getSnapshot(); - const { endDate, startDate } = getIntervalFromDateRange(dateRange); + const { endDate, startDate } = getIntervalFromDateRange({ dateRange }); const { chart } = await portfolioCalculator.getPerformance({ end: endDate, @@ -1035,6 +1061,7 @@ export class PortfolioService { netPerformanceWithCurrencyEffect, netWorth, totalInvestment, + totalInvestmentValueWithCurrencyEffect, valueWithCurrencyEffect } = chart?.at(-1) ?? { netPerformance: 0, @@ -1055,6 +1082,7 @@ export class PortfolioService { netPerformance, netPerformanceWithCurrencyEffect, totalInvestment, + totalInvestmentValueWithCurrencyEffect, currentNetWorth: netWorth, currentValueInBaseCurrency: valueWithCurrencyEffect, netPerformancePercentage: netPerformanceInPercentage, @@ -1303,11 +1331,11 @@ export class PortfolioService { }), rules: await this.rulesService.evaluate( [ - new FeeRatioInitialInvestment( + new FeeRatioTotalInvestmentVolume( this.exchangeRateDataService, this.i18nService, userSettings.language, - summary.committedFunds, + summary.totalBuy + summary.totalSell, summary.fees ) ], @@ -1343,7 +1371,12 @@ export class PortfolioService { }) { userId = await this.getUserId(impersonationId, userId); - await this.orderService.assignTags({ dataSource, symbol, tags, userId }); + await this.activitiesService.assignTags({ + dataSource, + symbol, + tags, + userId + }); } private getAggregatedMarkets(holdings: Record): { @@ -1662,9 +1695,21 @@ export class PortfolioService { }): PortfolioPosition { return { currency, + activitiesCount: 0, allocationInPercentage: 0, assetClass: AssetClass.LIQUIDITY, assetSubClass: AssetSubClass.CASH, + assetProfile: { + currency, + assetClass: AssetClass.LIQUIDITY, + assetSubClass: AssetSubClass.CASH, + countries: [], + dataSource: undefined, + holdings: [], + name: currency, + sectors: [], + symbol: currency + }, countries: [], dataSource: undefined, dateOfFirstActivity: undefined, @@ -1685,7 +1730,6 @@ export class PortfolioService { sectors: [], symbol: currency, tags: [], - transactionCount: 0, valueInBaseCurrency: balance }; } @@ -1835,7 +1879,7 @@ export class PortfolioService { userId = await this.getUserId(impersonationId, userId); const user = await this.userService.user({ id: userId }); - const { activities } = await this.orderService.getOrders({ + const { activities } = await this.activitiesService.getActivities({ userCurrency, userId, withExcludedAccountsAndActivities: true @@ -1857,8 +1901,11 @@ export class PortfolioService { } } - const { currentValueInBaseCurrency, totalInvestment } = - await portfolioCalculator.getSnapshot(); + const { + currentValueInBaseCurrency, + totalInvestment, + totalInvestmentWithCurrencyEffect + } = await portfolioCalculator.getSnapshot(); const { performance } = await this.getPerformance({ impersonationId, @@ -1872,18 +1919,17 @@ export class PortfolioService { netPerformanceWithCurrencyEffect } = performance; - const dividendInBaseCurrency = - await portfolioCalculator.getDividendInBaseCurrency(); - const totalEmergencyFund = this.getTotalEmergencyFund({ emergencyFundHoldingsValueInBaseCurrency, userSettings: user.settings?.settings as UserSettings }); - const fees = await portfolioCalculator.getFeesInBaseCurrency(); + const dateOfFirstActivity = portfolioCalculator.getStartDate(); - const firstOrderDate = portfolioCalculator.getStartDate(); + const dividendInBaseCurrency = + await portfolioCalculator.getDividendInBaseCurrency(); + const fees = await portfolioCalculator.getFeesInBaseCurrency(); const interest = await portfolioCalculator.getInterestInBaseCurrency(); const liabilities = @@ -1906,8 +1952,6 @@ export class PortfolioService { .plus(emergencyFundHoldingsValueInBaseCurrency) .toNumber(); - const committedFunds = new Big(totalBuy).minus(totalSell); - const totalOfExcludedActivities = this.getSumOfActivityType({ userCurrency, activities: excludedActivities, @@ -1941,7 +1985,7 @@ export class PortfolioService { .minus(liabilities) .toNumber(); - const daysInMarket = differenceInDays(new Date(), firstOrderDate); + const daysInMarket = differenceInDays(new Date(), dateOfFirstActivity); const annualizedPerformancePercent = getAnnualizedPerformancePercent({ daysInMarket, @@ -1960,6 +2004,7 @@ export class PortfolioService { annualizedPerformancePercent, annualizedPerformancePercentWithCurrencyEffect, cash, + dateOfFirstActivity, excludedAccountsAndActivities, netPerformance, netPerformancePercentage, @@ -1970,9 +2015,7 @@ export class PortfolioService { activityCount: activities.filter(({ type }) => { return ['BUY', 'SELL'].includes(type); }).length, - committedFunds: committedFunds.toNumber(), currentValueInBaseCurrency: currentValueInBaseCurrency.toNumber(), - dateOfFirstActivity: firstOrderDate, dividendInBaseCurrency: dividendInBaseCurrency.toNumber(), emergencyFund: { assets: emergencyFundHoldingsValueInBaseCurrency, @@ -2002,6 +2045,8 @@ export class PortfolioService { interestInBaseCurrency: interest.toNumber(), liabilitiesInBaseCurrency: liabilities.toNumber(), totalInvestment: totalInvestment.toNumber(), + totalInvestmentValueWithCurrencyEffect: + totalInvestmentWithCurrencyEffect.toNumber(), totalValueInBaseCurrency: netWorth }; } diff --git a/apps/api/src/app/redis-cache/redis-cache.service.ts b/apps/api/src/app/redis-cache/redis-cache.service.ts index 1ea0a6137..619d23fc5 100644 --- a/apps/api/src/app/redis-cache/redis-cache.service.ts +++ b/apps/api/src/app/redis-cache/redis-cache.service.ts @@ -6,7 +6,7 @@ import { CACHE_MANAGER, Cache } from '@nestjs/cache-manager'; import { Inject, Injectable, Logger } from '@nestjs/common'; import Keyv from 'keyv'; import ms from 'ms'; -import { createHash } from 'node:crypto'; +import { createHash, randomUUID } from 'node:crypto'; @Injectable() export class RedisCacheService { @@ -75,13 +75,16 @@ export class RedisCacheService { } public async isHealthy() { - const testKey = '__health_check__'; + const HEALTH_CHECK_TIMEOUT = ms('5 seconds'); + + const testKey = `__health_check__${randomUUID().replace(/-/g, '')}`; const testValue = Date.now().toString(); try { await Promise.race([ (async () => { - await this.set(testKey, testValue, ms('1 second')); + await this.set(testKey, testValue, HEALTH_CHECK_TIMEOUT); + const result = await this.get(testKey); if (result !== testValue) { @@ -91,7 +94,7 @@ export class RedisCacheService { new Promise((_, reject) => setTimeout( () => reject(new Error('Redis health check failed: timeout')), - ms('2 seconds') + HEALTH_CHECK_TIMEOUT ) ) ]); diff --git a/apps/api/src/app/subscription/subscription.service.ts b/apps/api/src/app/subscription/subscription.service.ts index b38b07bb4..689ee3e6a 100644 --- a/apps/api/src/app/subscription/subscription.service.ts +++ b/apps/api/src/app/subscription/subscription.service.ts @@ -35,7 +35,7 @@ export class SubscriptionService { this.stripe = new Stripe( this.configurationService.get('STRIPE_SECRET_KEY'), { - apiVersion: '2025-12-15.clover' + apiVersion: '2026-01-28.clover' } ); } @@ -100,7 +100,6 @@ export class SubscriptionService { ); return { - sessionId: session.id, sessionUrl: session.url }; } diff --git a/apps/api/src/app/user/user.controller.ts b/apps/api/src/app/user/user.controller.ts index 397ae016b..6346ce43a 100644 --- a/apps/api/src/app/user/user.controller.ts +++ b/apps/api/src/app/user/user.controller.ts @@ -1,8 +1,11 @@ import { HasPermission } from '@ghostfolio/api/decorators/has-permission.decorator'; import { HasPermissionGuard } from '@ghostfolio/api/guards/has-permission.guard'; +import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.interceptor'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; +import { ImpersonationService } from '@ghostfolio/api/services/impersonation/impersonation.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PropertyService } from '@ghostfolio/api/services/property/property.service'; +import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; import { DeleteOwnUserDto, UpdateOwnAccessTokenDto, @@ -28,7 +31,8 @@ import { Param, Post, Put, - UseGuards + UseGuards, + UseInterceptors } from '@nestjs/common'; import { REQUEST } from '@nestjs/core'; import { JwtService } from '@nestjs/jwt'; @@ -43,6 +47,7 @@ import { UserService } from './user.service'; export class UserController { public constructor( private readonly configurationService: ConfigurationService, + private readonly impersonationService: ImpersonationService, private readonly jwtService: JwtService, private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, @@ -107,13 +112,19 @@ export class UserController { @Get() @UseGuards(AuthGuard('jwt'), HasPermissionGuard) + @UseInterceptors(RedactValuesInResponseInterceptor) public async getUser( - @Headers('accept-language') acceptLanguage: string + @Headers('accept-language') acceptLanguage: string, + @Headers(HEADER_KEY_IMPERSONATION.toLowerCase()) impersonationId: string ): Promise { - return this.userService.getUser( - this.request.user, - acceptLanguage?.split(',')?.[0] - ); + const impersonationUserId = + await this.impersonationService.validateImpersonationId(impersonationId); + + return this.userService.getUser({ + impersonationUserId, + locale: acceptLanguage?.split(',')?.[0], + user: this.request.user + }); } @Post() diff --git a/apps/api/src/app/user/user.module.ts b/apps/api/src/app/user/user.module.ts index 8a21b0a55..3f4e898fc 100644 --- a/apps/api/src/app/user/user.module.ts +++ b/apps/api/src/app/user/user.module.ts @@ -1,7 +1,9 @@ -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { SubscriptionModule } from '@ghostfolio/api/app/subscription/subscription.module'; +import { RedactValuesInResponseModule } from '@ghostfolio/api/interceptors/redact-values-in-response/redact-values-in-response.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { I18nModule } from '@ghostfolio/api/services/i18n/i18n.module'; +import { ImpersonationModule } from '@ghostfolio/api/services/impersonation/impersonation.module'; import { PrismaModule } from '@ghostfolio/api/services/prisma/prisma.module'; import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; import { TagModule } from '@ghostfolio/api/services/tag/tag.module'; @@ -16,15 +18,17 @@ import { UserService } from './user.service'; controllers: [UserController], exports: [UserService], imports: [ + ActivitiesModule, ConfigurationModule, I18nModule, + ImpersonationModule, JwtModule.register({ secret: process.env.JWT_SECRET_KEY, signOptions: { expiresIn: '30 days' } }), - OrderModule, PrismaModule, PropertyModule, + RedactValuesInResponseModule, SubscriptionModule, TagModule ], diff --git a/apps/api/src/app/user/user.service.ts b/apps/api/src/app/user/user.service.ts index 1a04a675c..ff6eea19f 100644 --- a/apps/api/src/app/user/user.service.ts +++ b/apps/api/src/app/user/user.service.ts @@ -1,4 +1,4 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.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'; @@ -12,7 +12,7 @@ import { CurrencyClusterRiskCurrentInvestment } from '@ghostfolio/api/models/rul import { EconomicMarketClusterRiskDevelopedMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/developed-markets'; import { EconomicMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/economic-market-cluster-risk/emerging-markets'; 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 { FeeRatioTotalInvestmentVolume } from '@ghostfolio/api/models/rules/fees/fee-ratio-total-investment-volume'; import { BuyingPower } from '@ghostfolio/api/models/rules/liquidity/buying-power'; import { RegionalMarketClusterRiskAsiaPacific } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/asia-pacific'; import { RegionalMarketClusterRiskEmergingMarkets } from '@ghostfolio/api/models/rules/regional-market-cluster-risk/emerging-markets'; @@ -30,7 +30,7 @@ import { PROPERTY_IS_READ_ONLY_MODE, PROPERTY_SYSTEM_MESSAGE, TAG_ID_EXCLUDE_FROM_ANALYSIS, - locale + locale as defaultLocale } from '@ghostfolio/common/config'; import { User as IUser, @@ -49,16 +49,16 @@ import { Injectable } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; import { Prisma, Role, User } from '@prisma/client'; import { differenceInDays, subDays } from 'date-fns'; -import { sortBy, without } from 'lodash'; +import { without } from 'lodash'; import { createHmac } from 'node:crypto'; @Injectable() export class UserService { public constructor( + private readonly activitiesService: ActivitiesService, private readonly configurationService: ConfigurationService, private readonly eventEmitter: EventEmitter2, private readonly i18nService: I18nService, - private readonly orderService: OrderService, private readonly prismaService: PrismaService, private readonly propertyService: PropertyService, private readonly subscriptionService: SubscriptionService, @@ -96,18 +96,18 @@ export class UserService { return { accessToken, hashedAccessToken }; } - public async getUser( - { - accounts, - id, - permissions, - provider, - settings, - subscription, - thirdPartyId - }: UserWithSettings, - aLocale = locale - ): Promise { + public async getUser({ + impersonationUserId, + locale = defaultLocale, + user + }: { + impersonationUserId: string; + locale?: string; + user: UserWithSettings; + }): Promise { + const { id, permissions, provider, settings, subscription, thirdPartyId } = + user; + const userData = await Promise.all([ this.prismaService.access.findMany({ include: { @@ -116,22 +116,31 @@ export class UserService { orderBy: { alias: 'asc' }, where: { granteeUserId: id } }), + this.prismaService.account.findMany({ + orderBy: { + name: 'asc' + }, + where: { + userId: impersonationUserId || user.id + } + }), this.prismaService.order.count({ - where: { userId: id } + where: { userId: impersonationUserId || user.id } }), this.prismaService.order.findFirst({ orderBy: { date: 'asc' }, - where: { userId: id } + where: { userId: impersonationUserId || user.id } }), - this.tagService.getTagsForUser(id) + this.tagService.getTagsForUser(impersonationUserId || user.id) ]); const access = userData[0]; - const activitiesCount = userData[1]; - const firstActivity = userData[2]; - let tags = userData[3].filter((tag) => { + const accounts = userData[1]; + const activitiesCount = userData[2]; + const firstActivity = userData[3]; + let tags = userData[4].filter((tag) => { return tag.id !== TAG_ID_EXCLUDE_FROM_ANALYSIS; }); @@ -154,7 +163,6 @@ export class UserService { } return { - accounts, activitiesCount, id, permissions, @@ -170,10 +178,13 @@ export class UserService { permissions: accessItem.permissions }; }), + accounts: accounts.sort((a, b) => { + return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); + }), dateOfFirstActivity: firstActivity?.date ?? new Date(), settings: { ...(settings.settings as UserSettings), - locale: (settings.settings as UserSettings)?.locale ?? aLocale + locale: (settings.settings as UserSettings)?.locale ?? locale } }; } @@ -368,7 +379,7 @@ export class UserService { undefined, undefined ).getSettings(user.settings.settings), - FeeRatioInitialInvestment: new FeeRatioInitialInvestment( + FeeRatioTotalInvestmentVolume: new FeeRatioTotalInvestmentVolume( undefined, undefined, undefined, @@ -522,13 +533,20 @@ export class UserService { } } - if (!environment.production && hasRole(user, Role.ADMIN)) { - currentPermissions.push(permissions.impersonateAllUsers); + if (hasRole(user, Role.ADMIN)) { + if (this.configurationService.get('ENABLE_FEATURE_BULL_BOARD')) { + currentPermissions.push(permissions.accessAdminControlBullBoard); + } + + if (!environment.production) { + currentPermissions.push(permissions.impersonateAllUsers); + } } - user.accounts = sortBy(user.accounts, ({ name }) => { - return name.toLowerCase(); + user.accounts = user.accounts.sort((a, b) => { + return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); }); + user.permissions = currentPermissions.sort(); return user; @@ -634,7 +652,7 @@ export class UserService { } catch {} try { - await this.orderService.deleteOrders({ + await this.activitiesService.deleteActivities({ userId: where.id }); } catch {} diff --git a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json index 80c07fc64..d00ded6ef 100644 --- a/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json +++ b/apps/api/src/assets/cryptocurrencies/cryptocurrencies.json @@ -4,6 +4,7 @@ "4": "4", "7": "Lucky7", "8": "8", + "21": "2131KOBUSHIDE", "32": "Project 32", "42": "Semantic Layer", "47": "President Trump", @@ -20,8 +21,10 @@ "1337": "EliteCoin", "1717": "1717 Masonic Commemorative Token", "2015": "2015 coin", + "2016": "2016 coin", "2024": "2024", "2025": "2025 TOKEN", + "2026": "2026", "2049": "TOKEN 2049", "2192": "LERNITAS", "4444": "4444 Meme", @@ -55,6 +58,7 @@ "10SET": "Tenset", "1ART": "ArtWallet", "1CAT": "Bitcoin Cats", + "1COIN": "1 coin can change your life", "1CR": "1Credit", "1EARTH": "EarthFund", "1ECO": "1eco", @@ -83,6 +87,7 @@ "1UP": "Uptrennd", "1WO": "1World", "2022M": "2022MOON", + "2026MEMECLUB": "2026", "20EX": "20ex", "21BTC": "21.co Wrapped BTC", "21X": "21X", @@ -113,6 +118,7 @@ "3DES": "3DES", "3DVANCE": "3D Vance", "3FT": "ThreeFold Token", + "3KDS": "3KDS", "3KM": "3 Kingdoms Multiverse", "3P": "Web3Camp", "3RDEYE": "3rd Eye", @@ -146,11 +152,13 @@ "7E": "7ELEVEN", "88MPH": "88mph", "8BIT": "8BIT Coin", + "8BITCOIN": "8-Bit COIN", "8BT": "8 Circuit Studios", "8LNDS": "8Lends", "8PAY": "8Pay", "8X8": "8X8 Protocol", "99BTC": "99 Bitcoins", + "9BIT": "The9bit", "9DOGS": "NINE DOGS", "9GAG": "9GAG", "9MM": "Shigure UI", @@ -175,13 +183,17 @@ "AAC": "Double-A Chain", "AAG": "AAG Ventures", "AAI": "AutoAir AI", + "AALON": "American Airlines Group (Ondo Tokenized)", + "AAPLON": "Apple (Ondo Tokenized)", "AAPLX": "Apple xStock", "AAPX": "AMPnet", + "AARBWBTC": "Aave Arbitrum WBTC", "AARDY": "Baby Aardvark", "AARK": "Aark", "AART": "ALL.ART", "AAST": "AASToken", "AAT": "Agricultural Trade Chain", + "AAVAWBTC": "Aave aWBTC", "AAVE": "Aave", "AAVEE": "AAVE.e (Avalanche Bride)", "AAVEGOTCHIFOMO": "Aavegotchi FOMO", @@ -295,7 +307,8 @@ "ADEL": "Akropolis Delphi", "ADF": "Art de Finance", "ADH": "Adhive", - "ADI": "Aditus", + "ADI": "ADI", + "ADITUS": "Aditus", "ADIX": "Adix Token", "ADK": "Aidos Kuneen", "ADL": "Adel", @@ -408,10 +421,12 @@ "AGS": "Aegis", "AGT": "Alaya Governance Token", "AGURI": "Aguri-Chan", + "AGUSTO": "Agusto", "AGV": "Astra Guild Ventures", "AGVC": "AgaveCoin", "AGVE": "Agave", "AGX": "Agricoin", + "AHARWBTC": "Aave Harmony WBTC", "AHOO": "Ahoolee", "AHT": "AhaToken", "AI": "Sleepless", @@ -429,6 +444,7 @@ "AIAI": "All In AI", "AIAKITA": "AiAkita", "AIAT": "AI Analysis Token", + "AIAV": "AI AVatar", "AIB": "AdvancedInternetBlock", "AIBABYDOGE": "AIBabyDoge", "AIBB": "AiBB", @@ -502,6 +518,7 @@ "AIPAD": "AIPAD", "AIPE": "AI Prediction Ecosystem", "AIPEPE": "AI PEPE KING", + "AIPF": "AI Powered Finance", "AIPG": "AI Power Grid", "AIPIN": "AI PIN", "AIPO": "Aipocalypto", @@ -546,7 +563,7 @@ "AIVV1": "AIVille Governance Token", "AIWALLET": "AiWallet Token", "AIWS": "AIWS", - "AIX": "ALIENX", + "AIX": "Ai Xovia", "AIX9": "AthenaX9", "AIXBT": "aixbt by Virtuals", "AIXCB": "aixCB by Virtuals", @@ -619,6 +636,7 @@ "ALIEN": "AlienCoin", "ALIENPEP": "Alien Pepe", "ALIENS": "Aliens", + "ALIENX": "ALIENX", "ALIF": " ALIF COIN", "ALINK": "Aave LINK v1", "ALIS": "ALISmedia", @@ -626,6 +644,7 @@ "ALITA": "Alita Network", "ALITATOKEN": "Alita Token", "ALIX": "AlinX", + "ALK": "Alkemi Network DAO Token", "ALKI": "Alkimi", "ALKIMI": "ALKIMI", "ALLBI": "ALL BEST ICO", @@ -639,10 +658,12 @@ "ALMANAK": "Almanak", "ALMC": "Awkward Look Monkey Club", "ALME": "Alita", + "ALMEELA": "Almeela", "ALMOND": "Almond", "ALN": "Aluna", "ALNV1": "Aluna v1", "ALOHA": "Aloha", + "ALOKA": "ALOKA", "ALON": "Alon", "ALOR": "The Algorix", "ALOT": "Dexalot", @@ -689,7 +710,9 @@ "AMADEUS": "AMADEUS", "AMAL": "AMAL", "AMAPT": "Amnis Finance", + "AMARA": "AMARA", "AMATEN": "Amaten", + "AMATO": "AMATO", "AMAZINGTEAM": "AmazingTeamDAO", "AMB": "AirDAO", "AMBER": "AmberCoin", @@ -698,6 +721,7 @@ "AMBRX": "Amber xStock", "AMBT": "AMBT Token", "AMC": "AI Meta Coin", + "AMCON": "AMC Entertainment (Ondo Tokenized)", "AMDC": "Allmedi Coin", "AMDG": "AMDG", "AMDX": "AMD xStock", @@ -825,6 +849,7 @@ "AOK": "AOK", "AOL": "AOL (America Online)", "AOP": "Ark Of Panda", + "AOPTWBTC": "Aave Optimism WBTC", "AOS": "AOS", "AOT": "Age of Tanks", "AP": "America Party", @@ -861,6 +886,7 @@ "APOL": "Apollo FTW", "APOLL": "Apollon Limassol", "APOLLO": "Apollo Crypto", + "APOLWBTC": "Aave Polygon WBTC", "APP": "Moon App", "APPA": "Dappad", "APPC": "AppCoins", @@ -914,7 +940,9 @@ "ARAW": "Araw", "ARB": "Arbitrum", "ARBI": "Arbipad", + "ARBINU": "ArbInu", "ARBIT": "Arbit Coin", + "ARBITROVE": "Arbitrove Governance Token", "ARBP": "ARB Protocol", "ARBS": "Arbswap", "ARBT": "ARBITRAGE", @@ -1041,6 +1069,7 @@ "ASBNB": "Astherus Staked BNB", "ASC": "All InX SMART CHAIN", "ASCEND": "Ascend", + "ASCN": "AlphaScan", "ASD": "AscendEX Token", "ASDEX": "AstraDEX", "ASEED": "aUSD SEED (Acala)", @@ -1082,6 +1111,7 @@ "ASTA": "ASTA", "ASTER": "Aster", "ASTERINU": "Aster INU", + "ASTHERUSUSDF": "Astherus USDF", "ASTO": "Altered State Token", "ASTON": "Aston", "ASTONV": "Aston Villa Fan Token", @@ -1133,6 +1163,7 @@ "ATLA": "Atleta Network", "ATLAS": "Star Atlas", "ATLASD": "Atlas DEX", + "ATLASOFUSA": "Atlas", "ATLX": "Atlantis Loans Polygon", "ATM": "Atletico de Madrid Fan Token", "ATMA": "ATMA", @@ -1151,6 +1182,7 @@ "ATON": "Further Network", "ATOPLUS": "ATO+", "ATOR": "ATOR Protocol", + "ATOS": "Atoshi", "ATOZ": "Race Kingdom", "ATP": "Atlas Protocol", "ATPAY": "AtPay", @@ -1173,6 +1205,7 @@ "AUCO": "Advanced United Continent", "AUCTION": "Bounce", "AUDC": "Aussie Digital", + "AUDD": "Australian Digital Dollar", "AUDF": "Forte AUD", "AUDIO": "Audius", "AUDM": "Macropod Stablecoin", @@ -1260,6 +1293,7 @@ "AWARE": "ChainAware.ai", "AWARETOKEN": "AWARE", "AWAX": "AWAX", + "AWBTC": "Aave interest bearing WBTC", "AWC": "Atomic Wallet Coin", "AWE": "AWE Network", "AWK": "Awkward Monkey Base", @@ -1302,6 +1336,7 @@ "AXT": "AIX", "AXYS": "Axys", "AYA": "Aryacoin", + "AYFI": "Aave YFI", "AYNI": "Ayni Gold", "AZ": "Azbit", "AZA": "Kaliza", @@ -1312,8 +1347,10 @@ "AZIT": "Azit", "AZNX": "AstraZeneca xStock", "AZR": "Azure", + "AZTEC": "AZTEC", "AZU": "Azultec", "AZUKI": "Azuki", + "AZUKI2": "AZUKI 2.0", "AZUKIDAO": "AzukiDAO", "AZUM": "Azuma Coin", "AZUR": "Azuro Protocol", @@ -1340,6 +1377,7 @@ "BABI": "Babylons", "BABL": "Babylon Finance", "BABY": "Babylon", + "BABY4": "Baby 4", "BABYANDY": "Baby Andy", "BABYASTER": "Baby Aster", "BABYB": "Baby Bali", @@ -1354,6 +1392,7 @@ "BABYBOME": "Book of Baby Memes", "BABYBOMEOW": "Baby of BOMEOW", "BABYBONK": "Baby Bonk", + "BABYBOOM": "BabyBoomToken", "BABYBOSS": "Baby Boss", "BABYBROC": "Baby Broccoli", "BABYBROCCOL": "Baby Broccoli", @@ -1535,6 +1574,7 @@ "BAOM": "Battle of Memes", "BAOS": "BaoBaoSol", "BAOV1": "BaoToken v1", + "BAP3X": "bAP3X", "BAR": "FC Barcelona Fan Token", "BARA": "Capybara", "BARAKATUH": "Barakatuh", @@ -1599,6 +1639,7 @@ "BB": "BounceBit", "BB1": "Bitbond", "BBADGER": "Badger Sett Badger", + "BBAION": "BigBear.ai Holdings (Ondo Tokenized)", "BBANK": "BlockBank", "BBB": "BitBullBot", "BBBTC": "Big Back Bitcoin", @@ -1632,7 +1673,7 @@ "BBS": "BBSCoin", "BBSNEK": "BabySNEK", "BBSOL": "Bybit Staked SOL", - "BBT": "BabyBoomToken", + "BBT": "BurgerBlastToken", "BBTC": "Binance Wrapped BTC", "BBTF": "Block Buster Tech Inc", "BBUSD": "BounceBit USD", @@ -1678,6 +1719,7 @@ "BCOINM": "Bomb Crypto (MATIC)", "BCOINSOL": "Bomb Crypto (SOL)", "BCOINTON": "Bomb Crypto (TON)", + "BCONG": "BabyCong", "BCOQ": "BLACK COQINU", "BCP": "BlockChainPeople", "BCPAY": "Bitcashpay", @@ -1728,13 +1770,15 @@ "BEAMMW": "Beam", "BEAN": "Bean", "BEANS": "SUNBEANS (BEANS)", - "BEAR": "Bear Inu", + "BEAR": "3X Short Bitcoin Token", "BEARIN": "Bear in Bathrobe", + "BEARINU": "Bear Inu", "BEAST": "MrBeast", "BEAT": "Beat Token", "BEATAI": "eBeat AI", "BEATLES": "JohnLennonC0IN", "BEATS": "Sol Beats", + "BEATSWAP": "BeatSwap", "BEATTOKEN": "BEAT Token", "BEAVER": "beaver", "BEB1M": "BeB", @@ -1816,7 +1860,7 @@ "BES": "battle esports coin", "BESA": "Besa Gaming", "BESHARE": "Beshare Token", - "BEST": "Bitpanda Ecosystem Token", + "BEST": "Best Wallet Token", "BESTC": "BestChain", "BETA": "Beta Finance", "BETACOIN": "BetaCoin", @@ -1851,6 +1895,7 @@ "BFLOKI": "BurnFloki", "BFLY": "Butterfly Protocol", "BFM": "BenefitMine", + "BFR": "Buffer Token", "BFT": "BF Token", "BFTB": "Brazil Fan Token", "BFTC": "BITS FACTOR", @@ -1975,7 +2020,8 @@ "BIPC": "BipCoin", "BIPX": "Bispex", "BIR": "Birake", - "BIRB": "Birb", + "BIRB": "Moonbirds", + "BIRBV1": "Birb", "BIRD": "BIRD", "BIRDCHAIN": "Birdchain", "BIRDD": "BIRD DOG", @@ -2016,6 +2062,7 @@ "BITCOINCONFI": "Bitcoin Confidential", "BITCOINOTE": "BitcoiNote", "BITCOINP": "Bitcoin Private", + "BITCOINSCRYPT": "Bitcoin Scrypt", "BITCOINV": "BitcoinV", "BITCONNECT": "BitConnect Coin", "BITCORE": "BitCore", @@ -2038,6 +2085,7 @@ "BITOK": "BitOKX", "BITONE": "BITONE", "BITORB": "BitOrbit", + "BITPANDA": "Bitpanda Ecosystem Token", "BITRA": "Bitratoken", "BITRADIO": "Bitradio", "BITREWARDS": "BitRewards", @@ -2098,6 +2146,7 @@ "BLACKSALE": "Black Sale", "BLACKST": "Black Stallion", "BLACKSWAN": "BlackSwan AI", + "BLACKWHALE": "The Black Whale", "BLADE": "BladeGames", "BLADEW": "BladeWarrior", "BLAKEBTC": "BlakeBitcoin", @@ -2143,9 +2192,11 @@ "BLOB": "B.O.B the Blob", "BLOBERC20": "Blob", "BLOC": "Blockcloud", - "BLOCK": "Blockasset", + "BLOCK": "Block", + "BLOCKASSET": "Blockasset", "BLOCKB": "Block Browser", "BLOCKBID": "Blockbid", + "BLOCKCHAINTRADED": "Blockchain Traded Fund", "BLOCKF": "Block Farm Club", "BLOCKG": "BlockGames", "BLOCKIFY": "Blockify.Games", @@ -2218,6 +2269,7 @@ "BM": "BitMoon", "BMAGA": "Baby Maga", "BMARS": "Binamars", + "BMAX": "BMAX", "BMB": "Beamable Network Token", "BMBO": "Bamboo Coin", "BMC": "Blackmoon Crypto", @@ -2295,6 +2347,7 @@ "BNPL": "BNPL Pay", "BNR": "BiNeuro", "BNRTX": "BnrtxCoin", + "BNRY": "Binary Coin", "BNS": "BNS token", "BNSAI": "bonsAI Network", "BNSD": "BNSD Finance", @@ -2479,9 +2532,10 @@ "BOSSCOQ": "THE COQFATHER", "BOST": "BoostCoin", "BOSU": "Bosu Inu", - "BOT": "Bot Planet", + "BOT": "HyperBot", "BOTC": "BotChain", "BOTIFY": "BOTIFY", + "BOTPLANET": "Bot Planet", "BOTS": "ArkDAO", "BOTTO": "Botto", "BOTX": "BOTXCOIN", @@ -2495,6 +2549,7 @@ "BOWSC": "BowsCoin", "BOWSER": "Bowser", "BOX": "DeBoxToken", + "BOXABL": "BOXABL", "BOXCAT": "BOXCAT", "BOXETH": "Cat-in-a-Box Ether", "BOXT": "BOX Token", @@ -2516,6 +2571,7 @@ "BPD": "Beautiful Princess Disorder", "BPDAI": "Binance-Peg Dai (Binance Bridge)", "BPDOGE": "Binance-Peg DogeZilla (Binance Bridge)", + "BPEPE": "BABY PEPE", "BPEPEF": "Baby Pepe Floki", "BPET": "BPET", "BPINKY": "BPINKY", @@ -2579,6 +2635,7 @@ "BRETTGOLD": "Brett Gold", "BRETTONETH": "Brett ETH", "BRETTSUI": "Brett (brettsui.com)", + "BREV": "Brevis Token", "BREW": "CafeSwap Token", "BREWERY": "Brewery Consortium Coin", "BREWLABS": "Brewlabs", @@ -2737,6 +2794,7 @@ "BTCAS": "BitcoinAsia", "BTCAT": "Bitcoin Cat", "BTCB": "Bitcoin BEP2", + "BTCBAM": "BitCoin Bam", "BTCBASE": "Bitcoin on Base", "BTCBR": "Bitcoin BR", "BTCBRV1": "Bitcoin BR v1", @@ -2752,6 +2810,7 @@ "BTCHD": "Bitcoin HD", "BTCINU": "Bitcoin Inu", "BTCIX": "BITCOLOJIX", + "BTCJ": "Bitcoin (JustCrypto)", "BTCK": "Bitcoin Turbo Koin", "BTCL": "BTC Lite", "BTCM": "BTCMoon", @@ -2767,10 +2826,10 @@ "BTCR": "BitCurrency", "BTCRED": "Bitcoin Red", "BTCRY": "BitCrystal", - "BTCS": "Bitcoin Scrypt", + "BTCS": "BTCs", "BTCSR": "BTC Strategic Reserve", "BTCST": "BTC Standard Hashrate Token", - "BTCT": "Bitcoin Token", + "BTCTOKEN": "Bitcoin Token", "BTCUS": "Bitcoinus", "BTCV": "Bitcoin Vault", "BTCVB": "BitcoinVB", @@ -2782,9 +2841,10 @@ "BTELEGRAM": "BetterTelegram Token", "BTEV1": "Betero v1", "BTEX": "BTEX", - "BTF": "Blockchain Traded Fund", + "BTF": "Bitfinity Network", "BTFA": "Banana Task Force Ape", "BTG": "Bitcoin Gold", + "BTGON": "B2Gold (Ondo Tokenized)", "BTH": "Bithereum", "BTK": "Bostoken", "BTL": "Bitlocus", @@ -2927,13 +2987,16 @@ "BURRRD": "BURRRD", "BURT": "BURT", "BUSD": "Binance USD", + "BUSD0": "Bond USD0", "BUSDC": "BUSD", "BUSY": "Busy DAO", "BUT": "Bucket Token", "BUTT": "Buttercat", + "BUTTC": "Buttcoin", "BUTTCOIN": "The Next Bitcoin", "BUTTHOLE": "Butthole Coin", "BUTTPLUG": "fartcoin killer", + "BUTWHY": "ButWhy", "BUX": "BUX", "BUXCOIN": "Buxcoin", "BUY": "Burency", @@ -2965,6 +3028,7 @@ "BXA": "Blockchain Exchange Alliance", "BXBT": "BoxBet", "BXC": "BonusCloud", + "BXE": "Banxchange", "BXF": "BlackFort Token", "BXH": "BXH", "BXK": "Bitbook Gambling", @@ -3030,7 +3094,7 @@ "CAG": "Change", "CAGA": "Crypto Asset Governance Alliance", "CAH": "Moon Tropica", - "CAI": "Chasm", + "CAI": "CharacterX", "CAID": "ClearAid", "CAILA": "Caila", "CAIR": "Crypto-AI-Robo.com", @@ -3126,7 +3190,8 @@ "CASPER": "Casper DeFi", "CASPERTOKEN": "Casper Token", "CASPUR": "Caspur Zoomies", - "CAST": "Castello Coin", + "CAST": "CAST ORACLES", + "CASTELLOCOIN": "Castello Coin", "CASTLE": "bitCastle", "CAT": "Simon's Cat", "CATA": "CATAMOTO", @@ -3143,6 +3208,7 @@ "CATCO": "CatCoin", "CATCOIN": "CatCoin", "CATCOINETH": "Catcoin", + "CATCOINIO": "Catcoin", "CATCOINOFSOL": "Cat Coin", "CATCOINV2": "CatCoin Cash", "CATDOG": "Cat-Dog", @@ -3187,6 +3253,7 @@ "CATW": "Cat wif Hands", "CATWARRIOR": "Cat warrior", "CATWIF": "CatWifHat", + "CATWIFM": "catwifmask", "CATX": "CAT.trade Protocol", "CATZ": "CatzCoin", "CAU": "Canxium", @@ -3236,6 +3303,7 @@ "CBX": "CropBytes", "CBXRP": "Coinbase Wrapped XRP", "CBY": "Carbify", + "CBYTE": "CBYTE", "CC": "Canton Coin", "CC10": "Cryptocurrency Top 10 Tokens Index", "CCA": "CCA", @@ -3310,6 +3378,7 @@ "CENTRA": "Centra", "CENTS": "Centience", "CENX": "Centcex", + "CEO": "CEO", "CEODOGE": "CEO DOGE", "CERBER": "CERBEROGE", "CERE": "Cere Network", @@ -3384,12 +3453,14 @@ "CHARGED": "GoCharge Tech", "CHARIZARD": "Charizard Inu", "CHARL": "Charlie", + "CHARLI": "Charlie Trump Dog", "CHARLIE": "Charlie Kirk", "CHARM": "Charm Coin", "CHARS": "CHARS", "CHART": "BetOnChart", "CHARTA": "CHARTAI", "CHARTIQ": "ChartIQ", + "CHAS": "Chasm", "CHASH": "CleverHash", "CHAT": "Solchat", "CHATAI": "ChatAI Token", @@ -3496,6 +3567,7 @@ "CHR": "Chroma", "CHRETT": "Chinese BRETT", "CHRISPUMP": "Christmas Pump", + "CHRONOEFFE": "Chronoeffector", "CHRP": "Chirpley", "CHS": "Chainsquare", "CHSB": "SwissBorg", @@ -3519,6 +3591,7 @@ "CIC": "Crazy Internet Coin", "CICHAIN": "CIChain", "CIF": "Crypto Improvement Fund", + "CIFRON": "Cipher Mining (Ondo Tokenized)", "CIG": "cig", "CIM": "COINCOME", "CIN": "CinderCoin", @@ -3545,6 +3618,7 @@ "CIX100": "Cryptoindex", "CJ": "CryptoJacks", "CJC": "CryptoJournal", + "CJL": "Cjournal", "CJR": "Conjure", "CJT": "ConnectJob Token", "CKB": "Nervos Network", @@ -3564,6 +3638,8 @@ "CLASH": "GeorgePlaysClashRoyale", "CLASHUB": "Clashub", "CLASS": "Class Coin", + "CLAWD": "clawd.atg.eth", + "CLAWNCH": "CLAWNCH", "CLAY": "Clayton", "CLAYN": "Clay Nation", "CLB": "Cloudbric", @@ -3588,7 +3664,8 @@ "CLIN": "Clinicoin", "CLINK": "cLINK", "CLINT": "Clinton", - "CLIPPY": "CLIPPY", + "CLIPPY": "Clippy", + "CLIPPYETH": "CLIPPY", "CLIPS": "Clips", "CLIQ": "DefiCliq", "CLIST": "Chainlist", @@ -3650,6 +3727,7 @@ "CMPT": "Spatial Computing", "CMPV2": "Caduceus Protocol", "CMQ": "Communique", + "CMR": "U.S Critical Mineral Reserve", "CMS": "COMSA", "CMSN": "The Commission", "CMT": "CyberMiles", @@ -3695,7 +3773,8 @@ "COC": "Coin of the champions", "COCAINE": "THE GOOD STUFF", "COCK": "Shibacock", - "COCO": "COCO COIN", + "COCO": "coco", + "COCOCOIN": "COCO COIN", "COCONUT": "Coconut", "COCOR": "Cocoro", "COCORO": "Cocoro", @@ -3726,8 +3805,10 @@ "COI": "Coinnec", "COINAI": "Coinbase AI Agent", "COINB": "Coinbidex", + "COINBANK": "CoinBank", "COINBT": "CoinBot", "COINBUCK": "Coinbuck", + "COINCOLLECT": "CoinCollect", "COINDEALTOKEN": "CoinDeal Token", "COINDEFI": "Coin", "COINDEPO": "CoinDepo Token", @@ -3737,6 +3818,7 @@ "COINLION": "CoinLion", "COINM": "CoinMarketPrime", "COINONAT": "Coinonat", + "COINRADR": "CoinRadr", "COINSCOPE": "Coinscope", "COINSL": "CoinsLoot", "COINVEST": "Coinvest", @@ -3750,11 +3832,12 @@ "COLA": "Cola", "COLISEUM": "Coliseum", "COLL": "Collateral Pay", + "COLLAB": "Collab.Land", "COLLAR": "PolyPup Finance", "COLLAT": "Collaterize", "COLLE": "Collective Care", "COLLEA": "Colle AI", - "COLLECT": "CoinCollect", + "COLLECT": "Collect on Fanable", "COLLG": "Collateral Pay Governance", "COLON": "Colon", "COLR": "colR Coin", @@ -3813,6 +3896,7 @@ "COPIUM": "Copium", "COPPER": "COPPER", "COPS": "Cops Finance", + "COPXON": "Global X Copper Miners ETF (Ondo Tokenized)", "COPYCAT": "Copycat Finance", "COQ": "Coq Inu", "COR": "Coreto", @@ -3890,6 +3974,7 @@ "CPLO": "Cpollo", "CPM": "Crypto Pump Meme", "CPN": "CompuCoin", + "CPNGON": "Coupang (Ondo Tokenized)", "CPO": "Cryptopolis", "CPOO": "Cockapoo", "CPOOL": "Clearpool", @@ -3922,6 +4007,7 @@ "CRAPPY": "CrappyBird", "CRASH": "Solana Crash", "CRASHBOYS": "CRASHBOYS", + "CRAT": "CratD2C", "CRAVE": "CraveCoin", "CRAYRABBIT": "CrazyRabbit", "CRAZ": "CRAZY FLOKI", @@ -3970,6 +4056,7 @@ "CREPECOIN": "Crepe Coin", "CRES": "Cresio", "CRESV1": "Cresio v1", + "CRETA": "Creta World", "CREV": "CryptoRevolution", "CREVA": "Creva Coin", "CREW": "CREW INU", @@ -4356,6 +4443,7 @@ "DANJ": "Danjuan Cat", "DANK": "DarkKush", "DANKDOGE": "Dank Doge", + "DANKDOGEAI": "DankDogeAI", "DANNY": "Degen Danny", "DAO": "DAO Maker", "DAO1": "DAO1", @@ -4552,6 +4640,7 @@ "DEFIL": "DeFIL", "DEFILAB": "Defi", "DEFISCALE": "DeFiScale", + "DEFISSI": "DEFI.ssi", "DEFIT": "Digital Fitness", "DEFLA": "Defla", "DEFLCT": "Deflect", @@ -4778,8 +4867,10 @@ "DINGER": "Dinger Token", "DINGO": "Dingocoin", "DINNER": "Trump Dinner", - "DINO": "DinoLFG", + "DINO": "DINO", + "DINOLFG": "DinoLFG", "DINOS": "Dinosaur Inu", + "DINOSOL": "DINOSOL", "DINOSWAP": "DinoSwap", "DINT": "DinarTether", "DINU": "Dogey-Inu", @@ -4840,6 +4931,7 @@ "DLXV": "Delta-X", "DLY": "Daily Finance", "DLYCOP": "Daily COP", + "DM": "Dumb Money", "DMA": "Dragoma", "DMAGA": "Dark MAGA", "DMAIL": "DMAIL Network", @@ -4863,6 +4955,7 @@ "DMTR": "Dimitra", "DMX": "Dymmax", "DMZ": "DeMon Token", + "DN": "DeepNode", "DN8": "Pldgr", "DNA": "Metaverse", "DNAPEPE": "DNA PEPE", @@ -4872,6 +4965,7 @@ "DNFLX": "Netflix Tokenized Stock Defichain", "DNFT": "DareNFT", "DNN": "DNN Token", + "DNNON": "Denison Mines (Ondo Tokenized)", "DNO": "Denaro", "DNODE": "DecentraNode", "DNOTES": "Dnotes", @@ -4947,6 +5041,7 @@ "DOGEIN": "Doge In Glasses", "DOGEINU": "Doge Inu", "DOGEIUS": "DOGEIUS", + "DOGEJ": "Dogecoin (JustCrypto)", "DOGEKING": "DogeKing", "DOGELEGION": "DOGE LEGION", "DOGEM": "Doge Matrix", @@ -4974,6 +5069,7 @@ "DOGEZILLA": "DogeZilla", "DOGEZILLAV1": "DogeZilla v1", "DOGG": "Doggo", + "DOGGO": "DOGGO", "DOGGS": "Doggensnout", "DOGGY": "Doggy", "DOGGYCOIN": "DOGGY", @@ -5035,7 +5131,8 @@ "DONKEY": "donkey", "DONNIEFIN": "Donnie Finance", "DONS": "The Dons", - "DONT": "Donald Trump (dont.cash)", + "DONT": "DisclaimerCoin", + "DONTCASH": "DONT", "DONU": "Donu", "DONUT": "Donut", "DONUTS": "The Simpsons", @@ -5390,6 +5487,7 @@ "ECET": "Evercraft Ecotechnologies", "ECG": "EcoSmart", "ECH": "EthereCash", + "ECHELON": "Echelon Token", "ECHO": "Echo", "ECHOBOT": "ECHO BOT", "ECHOD": "EchoDEX", @@ -5487,6 +5585,7 @@ "EGGC": "EggCoin", "EGGMAN": "Eggman Inu", "EGGP": "Eggplant Finance", + "EGGT": "Egg N Partners", "EGGY": "EGGY", "EGI": "eGame", "EGL": "The Eagle Of Truth", @@ -5507,6 +5606,7 @@ "EHASH": "EHash", "EHIVE": "eHive", "EHRT": "Eight Hours Token", + "EICOIN": "EICOIN", "EIFI": "EIFI FINANCE", "EIGEN": "EigenLayer", "EIGENP": "Eigenpie", @@ -5591,6 +5691,7 @@ "ELONTRUMP": "ELON TRUMP", "ELP": "Ellerium", "ELS": "Ethlas", + "ELSA": "Elsa", "ELT": "Element Black", "ELTC2": "eLTC", "ELTCOIN": "ELTCOIN", @@ -5661,6 +5762,7 @@ "ENEDEX": "Enedex", "ENERGYLEDGER": "Energy Ledger", "ENERGYX": "Safe Energy", + "ENEXSPACE": "ENEX", "ENF": "enfineo", "ENG": "Enigma", "ENGT": "Engagement Token", @@ -5683,6 +5785,7 @@ "ENTER": "EnterCoin", "ENTR": "EnterDAO", "ENTRC": "ENTER COIN", + "ENTROPY": "Entropy", "ENTRP": "Hut34 Project", "ENTRY": "ENTRY", "ENTS": "Ents", @@ -5692,7 +5795,7 @@ "ENVIENTA": "Envienta", "ENVION": "Envion", "ENVOY": "Envoy A.I", - "ENX": "ENEX", + "ENX": "Enigma", "EOC": "EveryonesCoin", "EON": "Exscudo", "EONC": "Dimension", @@ -5711,6 +5814,7 @@ "EPETS": "Etherpets", "EPIC": "Epic Chain", "EPICCASH": "Epic Cash", + "EPICV1": "Ethernity Chain", "EPIK": "EPIK Token", "EPIKO": "Epiko", "EPIX": "Byepix", @@ -5743,6 +5847,7 @@ "ERA7": "Era Token", "ERASWAP": "Era Swap Token", "ERB": "ERBCoin", + "ERBB": "Exchange Request for Bitbon", "ERC": "EuropeCoin", "ERC20": "ERC20", "ERC20V1": "ERC20 v1", @@ -5781,7 +5886,7 @@ "ESGC": "ESG Chain", "ESH": "Switch", "ESHIB": "Euro Shiba Inu", - "ESIM": "EvoSimGame", + "ESIM": "DEPINSIM Token", "ESM": "EL SALVADOR MEME", "ESN": "Ethersocial", "ESNC": "Galaxy Arena Metaverse", @@ -5832,6 +5937,7 @@ "ETHEREM": "Etherempires", "ETHEREUMMEME": "Solana Ethereum Meme", "ETHEREUMP": "ETHEREUMPLUS", + "ETHEREUMSCRYPT": "EthereumScrypt", "ETHERINC": "EtherInc", "ETHERKING": "Ether Kingdoms Token", "ETHERNITY": "Ethernity Chain", @@ -5842,6 +5948,7 @@ "ETHFI": "Ether.fi", "ETHI": "Ethical Finance", "ETHIX": "EthicHub", + "ETHJ": "Ethereum (JustCrypto)", "ETHM": "Ethereum Meta", "ETHO": "The Etho Protocol", "ETHOS": "Ethos Project", @@ -5853,7 +5960,7 @@ "ETHPR": "Ethereum Premium", "ETHPY": "Etherpay", "ETHR": "Ethereal", - "ETHS": "EthereumScrypt", + "ETHS": "Ethscriptions", "ETHSHIB": "Eth Shiba", "ETHV": "Ethverse", "ETHW": "Ethereum PoW", @@ -5914,6 +6021,7 @@ "EURU": "Upper Euro", "EURX": "eToro Euro", "EUSD": "Egoras Dollar", + "EUSX": "eUSX", "EUT": "EarnUp Token", "EUTBL": "Spiko EU T-Bills Money Market Fund", "EV": "EVAI", @@ -5952,6 +6060,7 @@ "EVOC": "EVOCPLUS", "EVOL": "EVOL NETWORK", "EVOS": "EVOS", + "EVOSIM": "EvoSimGame", "EVOVERSES": "EvoVerses", "EVR": "Everus", "EVRICE": "Evrice", @@ -6026,6 +6135,7 @@ "F2C": "Ftribe Fighters", "F2K": "Farm2Kitchen", "F3": "Friend3", + "F5": "F5-promoT5", "F7": "Five7", "F9": "Falcon Nine", "FAB": "FABRK Token", @@ -6066,6 +6176,7 @@ "FAN": "Fanadise", "FAN360": "Fan360", "FANC": "fanC", + "FANCYTHATTOKEN": "Fancy That", "FAND": "Fandomdao", "FANG": "FANG Token", "FANS": "Fantasy Cash", @@ -6140,6 +6251,7 @@ "FCTC": "FaucetCoin", "FCTR": "FactorDAO", "FDC": "Fidance", + "FDGC": "FINTECH DIGITAL GOLD COIN", "FDLS": "FIDELIS", "FDM": "Fandom", "FDO": "Firdaos", @@ -6211,6 +6323,7 @@ "FIC": "Filecash", "FID": "Fidira", "FIDA": "Bonfida", + "FIDD": "Fidelity Digital Dollar", "FIDLE": "Fidlecoin", "FIDO": "FIDO", "FIDU": "Fidu", @@ -6221,7 +6334,7 @@ "FIFTY": "FIFTYONEFIFTY", "FIG": "FlowCom", "FIGH": "FIGHT FIGHT FIGHT", - "FIGHT": "Fight to MAGA", + "FIGHT2MAGA": "Fight to MAGA", "FIGHTMAGA": "FIGHT MAGA", "FIGHTPEPE": "FIGHT PEPE", "FIGHTRUMP": "FIGHT TRUMP", @@ -6287,6 +6400,7 @@ "FK": "FK Coin", "FKBIDEN": "Fkbiden", "FKGARY": "Fuck Gary Gensler", + "FKH": "Flying Ketamine Horse", "FKPEPE": "Fuck Pepe", "FKR": "Flicker", "FKRPRO": "FlickerPro", @@ -6412,7 +6526,7 @@ "FNB": "FNB protocol", "FNC": "Fancy Games", "FNCT": "Financie Token", - "FNCY": "Fancy That", + "FNCY": "FNCY", "FND": "Rare FND", "FNDZ": "FNDZ Token", "FNF": "FunFi", @@ -6440,7 +6554,10 @@ "FOFARIO": "Fofar", "FOFO": "FOFO", "FOFOTOKEN": "FOFO Token", + "FOG": "FOGnet", "FOGE": "Fat Doge", + "FOGO": "Fogo", + "FOGV1": "FOGnet v1", "FOIN": "Foin", "FOL": "Folder Protocol", "FOLD": "Manifold Finance", @@ -6466,6 +6583,7 @@ "FORA": "UFORIKA", "FORCE": "TriForce Tokens", "FORCEC": "Force Coin", + "FORDON": "Ford Motor (Ondo Tokenized)", "FORE": "FORE Protocol", "FOREFRONT": "Forefront", "FOREST": "Forest", @@ -6595,6 +6713,7 @@ "FRR": "Frontrow", "FRSP": "Forkspot", "FRST": "FirstCoin", + "FRT": "FORT Token", "FRTC": "FART COIN", "FRTN": "EbisusBay Fortune", "FRTS": "Fruits", @@ -6709,6 +6828,7 @@ "FWB": "Friends With Benefits Pro", "FWBV1": "Friends With Benefits Pro v1", "FWC": "Qatar 2022", + "FWCL": "Legends", "FWH": "FigureWifHat", "FWOG": "Fwog", "FWT": "Freeway Token", @@ -6824,6 +6944,7 @@ "GASP": "GASP", "GASPCOIN": "gAsp", "GASS": "Gasspas", + "GAST": "Gas Town", "GASTRO": "GastroCoin", "GAT": "Gather", "GATA": "Gata", @@ -7042,6 +7163,7 @@ "GIGASWAP": "GigaSwap", "GIGGLE": "Giggle Fund", "GIGGLEACADEMY": "Giggle Academy", + "GIGL": "GIGGLE PANDA", "GIGS": "Climate101", "GIGX": "GigXCoin", "GIKO": "Giko Cat", @@ -7131,6 +7253,7 @@ "GMDP": "GMD Protocol", "GME": "GameStop", "GMEE": "GAMEE", + "GMEON": "GameStop (Ondo Tokenized)", "GMEPEPE": "GAMESTOP PEPE", "GMETHERFRENS": "GM", "GMETRUMP": "GME TRUMP", @@ -7209,6 +7332,7 @@ "GOFINDXR": "Gofind XR", "GOFX": "GooseFX", "GOG": "Guild of Guardians", + "GOGE": "GOLD DOGE", "GOGLZ": "GOGGLES", "GOGLZV1": "GOGGLES v1", "GOGO": "GOGO Finance", @@ -7319,10 +7443,12 @@ "GPU": "Node AI", "GPUCOIN": "GPU Coin", "GPUINU": "GPU Inu", + "GPUNET": "GPUnet", "GPX": "GPEX", "GQ": "Galactic Quadrant", "GR": "GROM", "GRAB": "GRABWAY", + "GRABON": "Grab Holdings (Ondo Tokenized)", "GRACY": "Gracy", "GRAI": "Gravita Protocol", "GRAIL": "Camelot Token", @@ -7331,6 +7457,7 @@ "GRAND": "Grand Theft Ape", "GRANDCOIN": "GrandCoin", "GRANDMA": "Grandma", + "GRANT": "GrantiX Token", "GRAPE": "GrapeCoin", "GRAPHGRAIAI": "GraphGrail AI", "GRASS": "Grass", @@ -7455,6 +7582,7 @@ "GTAN": "Giant Token", "GTAVI": "GTAVI", "GTBOT": "Gaming-T-Bot", + "GTBTC": "Gate Wrapped BTC", "GTC": "Gitcoin", "GTCC": "GTC COIN", "GTCOIN": "Game Tree", @@ -7517,6 +7645,7 @@ "GVT": "Genesis Vision", "GW": "Gyrowin", "GWD": "GreenWorld", + "GWEI": "ETHGas", "GWGW": "GoWrap", "GWT": "Galaxy War", "GX": "GameX", @@ -7558,6 +7687,7 @@ "HACHIKO": "Hachiko Inu Token", "HACHIONB": "Hachi On Base", "HACK": "HACK", + "HADES": "Hades", "HAEDAL": "Haedal Protocol", "HAGGIS": "New Born Haggis Pygmy Hippo", "HAHA": "Hasaki", @@ -7572,6 +7702,7 @@ "HALF": "0.5X Long Bitcoin Token", "HALFP": "Half Pizza", "HALFSHIT": "0.5X Long Shitcoin Index Token", + "HALIS": "Halis", "HALLO": "Halloween Coin", "HALLOWEEN": "HALLOWEEN", "HALO": "Halo Coin", @@ -7772,6 +7903,7 @@ "HIENS3": "hiENS3", "HIENS4": "hiENS4", "HIFI": "Hifi Finance", + "HIFIDENZA": "hiFIDENZA", "HIFLUF": "hiFLUF", "HIFRIENDS": "hiFRIENDS", "HIGAZERS": "hiGAZERS", @@ -7811,6 +7943,7 @@ "HITBTC": "HitBTC Token", "HITOP": "Hitop", "HIUNDEAD": "hiUNDEAD", + "HIVALHALLA": "hiVALHALLA", "HIVE": "Hive", "HIVP": "HiveSwap", "HIX": "HELIX Orange", @@ -7829,13 +7962,13 @@ "HLG": "Holograph", "HLINK": "Chainlink (Harmony One Bridge)", "HLM": "Helium", - "HLN": "Holonus", + "HLN": "Ēnosys", "HLO": "Halo", "HLOV1": "Halo v1", "HLP": "Purpose Coin", "HLPR": "HELPER COIN", "HLPT": "HLP Token", - "HLS": "Halis", + "HLS": "Helios", "HLT": "HyperLoot", "HLTC": "Huobi LTC", "HLX": "Helex", @@ -7894,6 +8027,7 @@ "HOLDON4": "HoldOn4DearLife", "HOLDS": "Holdstation", "HOLO": "Holoworld", + "HOLON": "Holonus", "HOLY": "Holy Trinity", "HOM": "Homeety", "HOME": "Home", @@ -7916,6 +8050,7 @@ "HONOR": "HonorLand", "HONX": "Honeywell xStock", "HOODOG": "Hoodog", + "HOODON": "Robinhood Markets (Ondo Tokenized)", "HOODRAT": "Hoodrat Coin", "HOODX": "Robinhood xStock", "HOOF": "Metaderby Hoof", @@ -7984,6 +8119,7 @@ "HSN": "Hyper Speed Network", "HSOL": "Helius Staked SOL", "HSP": "Horse Power", + "HSR": "Hshare", "HSS": "Hashshare", "HST": "Decision Token", "HSUI": "Suicune", @@ -8005,6 +8141,7 @@ "HTN": "Hoosat Network", "HTO": "Heavenland HTO", "HTR": "Hathor", + "HTS": "Home3", "HTT": "Hello Art", "HTX": "HTX", "HTZ": "Hertz Network", @@ -8111,6 +8248,7 @@ "IAI": "inheritance Art", "IAM": "IAME Identity", "IAOMIN": "Yao Ming", + "IAUON": "iShares Gold Trust (Ondo Tokenized)", "IB": "Iron Bank", "IBANK": "iBankCoin", "IBAT": "Battle Infinity", @@ -8179,6 +8317,7 @@ "IDLE": "IDLE", "IDM": "IDM", "IDNA": "Idena", + "IDNG": "IDNGold", "IDO": "Idexo", "IDOL": "MEET48 Token", "IDOLINU": "IDOLINU", @@ -8268,7 +8407,8 @@ "IMS": "Independent Money System", "IMST": "Imsmart", "IMT": "Immortal Token", - "IMU": "imusify", + "IMU": "Immunefi", + "IMUSIFY": "imusify", "IMVR": "ImmVRse", "IMX": "Immutable X", "IN": "INFINIT", @@ -8342,12 +8482,14 @@ "INSPI": "InspireAI", "INSR": "Insurabler", "INSTAMINE": "Instamine Nuggets", + "INSTANTSPONSOR": "Instant Sponsor Token", "INSTAR": "Insights Network", "INSUR": "InsurAce", "INSURANCE": "insurance", "INSURC": "InsurChain Coin", "INSUREDFIN": "Insured Finance", "INT": "Internet Node token", + "INTCON": "Intel (Ondo Tokenized)", "INTCX": "Intel xStock", "INTD": "INTDESTCOIN", "INTE": "InteractWith", @@ -8427,9 +8569,11 @@ "IQN": "IQeon", "IQQ": "Iqoniq", "IQT": "IQ Protocol", + "IR": "Infrared Governance Token", "IRA": "Diligence", "IRC": "IRIS", "IRENA": "Irena Coin Apps", + "IRENON": "IREN (Ondo Tokenized)", "IRIS": "IRIS Network", "IRISTOKEN": "Iris Ecosystem", "IRL": "IrishCoin", @@ -8503,6 +8647,7 @@ "IVZ": "InvisibleCoin", "IW": "iWallet", "IWFT": "İstanbul Wild Cats", + "IWMON": "iShares Russell 2000 ETF (Ondo Tokenized)", "IWT": "IwToken", "IX": "X-Block", "IXC": "IXcoin", @@ -8527,6 +8672,7 @@ "J9BC": "J9CASINO", "JACK": "Jack Token", "JACKPOT": "Solana Jackpot", + "JACKSON": "Jackson", "JACS": "JACS", "JACY": "JACY", "JADE": "Jade Protocol", @@ -8558,6 +8704,7 @@ "JAWN": "Long Jawn Silvers", "JAWS": "AutoShark", "JAY": "Jaypeggers", + "JBC": "Japan Brand Coin", "JBO": "JBOX", "JBOT": "JACKBOT", "JBS": "JumBucks Coin", @@ -8596,6 +8743,7 @@ "JERRYINUCOM": "Jerry Inu", "JES": "Jesus", "JESSE": "jesse", + "JESSECOIN": "jesse", "JEST": "Jester", "JESUS": "Jesus Coin", "JET": "Jet Protocol", @@ -8603,6 +8751,7 @@ "JETCOIN": "Jetcoin", "JETFUEL": "Jetfuel Finance", "JETTON": "JetTon Game", + "JETUSD": "JETUSD", "JEUR": "Jarvis Synthetic Euro", "JEW": "Shekel", "JEWEL": "DeFi Kingdoms", @@ -8614,6 +8763,7 @@ "JFIVE": "Jonny Five", "JFOX": "JuniperFox AI", "JFP": "JUSTICE FOR PEANUT", + "JGGL": "JGGL Token", "JGLP": "Jones GLP", "JGN": "Juggernaut", "JHH": "Jen-Hsun Huang", @@ -8624,6 +8774,7 @@ "JIM": "Jim", "JIN": "JinPeng", "JIND": "JINDO INU", + "JINDO": "JINDOGE", "JINDOGE": "Jindoge", "JIO": "JIO Token", "JITOSOL": "Jito Staked SOL", @@ -8650,6 +8801,7 @@ "JNX": "Janex", "JNY": "JNY", "JOB": "Jobchain", + "JOBCOIN": "buy instead of getting a job", "JOBIESS": "JobIess", "JOBS": "JobsCoin", "JOBSEEK": "JobSeek AI", @@ -8665,7 +8817,8 @@ "JOHNNY": "Johnny The Bull", "JOINCOIN": "JoinCoin", "JOINT": "Joint Ventures", - "JOJO": "JOJO", + "JOJO": "JOJOWORLD", + "JOJOSCLUB": "JOJO", "JOJOTOKEN": "JOJO", "JOK": "JokInTheBox", "JOKER": "JOKER", @@ -8749,6 +8902,7 @@ "JWBTC": "Wrapped Bitcoin (TON Bridge)", "JWIF": "Jerrywifhat", "JWL": "Jewels", + "JWT": "JW Token", "JYAI": "Jerry The Turtle By Matt Furie", "JYC": "Joe-Yo Coin", "K": "Sidekick", @@ -8757,7 +8911,13 @@ "KAAI": "KanzzAI", "KAAS": "KAASY.AI", "KAB": "KABOSU", - "KABOSU": "Kabosu Family", + "KABOSU": "X Meme Dog", + "KABOSUCOIN": "Kabosu", + "KABOSUCOM": "Kabosu", + "KABOSUFAMILY": "Kabosu Family", + "KABOSUTOKEN": "Kabosu", + "KABOSUTOKENETH": "KABOSU", + "KABUTO": "Kabuto", "KABY": "Kaby Arena", "KAC": "KACO Finance", "KACY": "markkacy", @@ -8865,6 +9025,7 @@ "KDC": "Klondike Coin", "KDG": "Kingdom Game 4.0", "KDIA": "KDIA COIN", + "KDK": "Kodiak Token", "KDOE": "Kudoe", "KDOGE": "KingDoge", "KDT": "Kenyan Digital Token", @@ -8926,6 +9087,7 @@ "KGC": "Krypton Galaxy Coin", "KGEN": "KGeN", "KGO": "Kiwigo", + "KGST": "KGST", "KGT": "Kaby Gaming Token", "KHAI": "khai", "KHEOWZOO": "khaokheowzoo", @@ -9055,6 +9217,7 @@ "KNDC": "KanadeCoin", "KNDM": "Kingdom", "KNDX": "Kondux", + "KNEKTED": "Knekted", "KNFT": "KStarNFT", "KNG": "BetKings", "KNGN": "KingN Coin", @@ -9067,13 +9230,14 @@ "KNOW": "KNOW", "KNOX": "KnoxDAO", "KNS": "Kenshi", - "KNT": "Knekted", + "KNT": "KayakNet", "KNTO": "Kento", "KNTQ": "Kinetiq Governance Token", "KNU": "Keanu", "KNUT": "Knut From Zoo", "KNUXX": "Knuxx Bully of ETH", "KNW": "Knowledge", + "KO": "Kyuzo's Friends", "KOAI": "KOI", "KOALA": "KOALA", "KOBAN": "KOBAN", @@ -9089,6 +9253,7 @@ "KOII": "Koii", "KOIN": "Koinos", "KOINB": "KoinBülteni Token", + "KOINDEX": "KOIN", "KOINETWORK": "Koi Network", "KOIP": "KoiPond", "KOJI": "Koji", @@ -9548,16 +9713,18 @@ "LIQUIDIUM": "LIQUIDIUM•TOKEN", "LIR": "Let it Ride", "LIS": "Realis Network", - "LISA": "Lisa Simpson", + "LISA": "LISA Token", "LISAS": "Lisa Simpson", + "LISASIMPSONCLUB": "Lisa Simpson", "LIST": "KList Protocol", "LISTA": "Lista DAO", "LISTEN": "Listen", "LISUSD": "lisUSD", - "LIT": "Litentry", + "LIT": "Lighter", "LITE": "Lite USD", "LITEBTC": "LiteBitcoin", "LITENETT": "Litenett", + "LITENTRY": "Litentry", "LITH": "Lithium Finance", "LITHIUM": "Lithium", "LITHO": "Lithosphere", @@ -9566,7 +9733,7 @@ "LITTLEGUY": "just a little guy", "LITTLEMANYU": "Little Manyu", "LIV": "LiviaCoin", - "LIVE": "TRONbetLive", + "LIVE": "SecondLive", "LIVENCOIN": "LivenPay", "LIVESEY": "Dr. Livesey", "LIVESTARS": "Live Stars", @@ -9689,7 +9856,7 @@ "LORY": "Yield Parrot", "LOS": "Lord Of SOL", "LOST": "Lost Worlds", - "LOT": "Lukki Operating Token", + "LOT": "League of Traders", "LOTES": "Loteo", "LOTEU": "Loteo", "LOTT": "Beauty bakery lott", @@ -9732,12 +9899,13 @@ "LQT": "Lifty", "LQTY": "Liquity", "LRC": "Loopring", + "LRCV1": "Loopring v1", "LRDS": "BLOCKLORDS", "LRG": "Largo Coin", "LRN": "Loopring [NEO]", "LRT": "LandRocker", "LSC": "LS Coin", - "LSD": "Pontem Liquidswap", + "LSD": "LSD", "LSDOGE": "LSDoge", "LSETH": "Liquid Staked ETH", "LSHARE": "LSHARE", @@ -9764,6 +9932,7 @@ "LTCC": "Listerclassic Coin", "LTCD": "LitecoinDark", "LTCH": "Litecoin Cash", + "LTCJ": "Litecoin (JustCrypto)", "LTCP": "LitecoinPro", "LTCR": "LiteCreed", "LTCU": "LiteCoin Ultra", @@ -9815,6 +9984,7 @@ "LUFFYV1": "Luffy v1", "LUIGI": "Luigi Inu", "LUIS": "Tongue Cat", + "LUKKI": "Lukki Operating Token", "LULU": "LULU", "LUM": "Luminous", "LUMA": "LUMA Token", @@ -9901,6 +10071,7 @@ "M0": "M by M^0", "M1": "SupplyShock", "M2O": "M2O Token", + "M3H": "MehVerseCoin", "M3M3": "M3M3", "M87": "MESSIER", "MA": "Mind-AI", @@ -9919,6 +10090,8 @@ "MADOG": "MarvelDoge", "MADP": "Mad Penguin", "MADPEPE": "Mad Pepe", + "MADU": "Nicolas Maduro", + "MADURO": "MADURO", "MAECENAS": "Maecenas", "MAEP": "Maester Protocol", "MAF": "MetaMAFIA", @@ -9950,6 +10123,7 @@ "MAGICK": "Cosmic Universe Magick", "MAGICV": "Magicverse", "MAGIK": "Magik Finance", + "MAGMA": "MAGMA", "MAGN": "Magnate Finance", "MAGNE": "Magnetix", "MAGNET": "Yield Magnet", @@ -10007,8 +10181,7 @@ "MANUSAI": "Manus AI Agent", "MANYU": "Manyu", "MANYUDOG": "MANYU", - "MAO": "MAO", - "MAOMEME": "Mao", + "MAO": "Mao", "MAOW": "MAOW", "MAP": "MAP Protocol", "MAPC": "MapCoin", @@ -10018,6 +10191,7 @@ "MAPS": "MAPS", "MAPU": "MatchAwards Platform Utility Token", "MAR3": "Mar3 AI", + "MARAON": "MARA Holdings (Ondo Tokenized)", "MARCO": "MELEGA", "MARCUS": "Marcus Cesar Inu", "MARE": "Mare Finance", @@ -10044,6 +10218,7 @@ "MARSMI": "MarsMi", "MARSO": "Marso.Tech", "MARSRISE": "MarsRise", + "MARSTOKEN": "Mars Token", "MARSUPILAMI": "MARSUPILAMI INU", "MARSW": "Marswap", "MART": "ArtMeta", @@ -10071,7 +10246,7 @@ "MASTERMIX": "Master MIX Token", "MASTERTRADER": "MasterTraderCoin", "MASYA": "MASYA", - "MAT": "My Master Wa", + "MAT": "Matchain", "MATA": "Ninneko", "MATAR": "MATAR AI", "MATCH": "Matching Game", @@ -10179,6 +10354,7 @@ "MCIV": "Mars Civ Project", "MCL": "McLaren F1", "MCLB": "Millennium Club Coin", + "MCM": "Mochimo", "MCN": "mCoin", "MCO": "Crypto.com", "MCO2": "Moss Carbon Credit", @@ -10198,6 +10374,7 @@ "MCU": "MediChain", "MCUSD": "Moola Celo USD", "MCV": "MCV Token", + "MCX": "MachiX Token", "MD": "MetaDeck", "MDA": "Moeda", "MDAI": "MindAI", @@ -10248,6 +10425,7 @@ "MEF": "MEFLEX", "MEFA": "Metaverse Face", "MEFAI": "META FINANCIAL AI", + "MEFI": "Meo Finance", "MEGA": "MegaFlash", "MEGABOT": "Megabot", "MEGAD": "Mega Dice Casino", @@ -10286,6 +10464,7 @@ "MEMEAI": "Meme Ai", "MEMEBRC": "MEME", "MEMECOIN": "just memecoin", + "MEMECOINDAOAI": "MemeCoinDAO", "MEMECUP": "Meme Cup", "MEMEETF": "Meme ETF", "MEMEFI": "MemeFi", @@ -10297,7 +10476,7 @@ "MEMEMUSK": "MEME MUSK", "MEMENTO": "MEMENTO•MORI (Runes)", "MEMERUNE": "MEME•ECONOMICS", - "MEMES": "MemeCoinDAO", + "MEMES": "memes will continue", "MEMESAI": "Memes AI", "MEMESQUAD": "Meme Squad", "MEMET": "MEMETOON", @@ -10366,6 +10545,7 @@ "METANIAV1": "METANIAGAMES", "METANO": "Metano", "METAPK": "Metapocket", + "METAPLACE": "Metaplace", "METAQ": "MetaQ", "METAS": "Metaseer", "METAT": "MetaTrace", @@ -10464,6 +10644,7 @@ "MICRO": "Micro GPT", "MICRODOGE": "MicroDoge", "MICROMINES": "Micromines", + "MICROVISION": "MicroVisionChain", "MIDAI": "Midway AI", "MIDAS": "Midas", "MIDASDOLLAR": "Midas Dollar Share", @@ -10484,7 +10665,7 @@ "MIININGNFT": "MiningNFT", "MIKE": "Mike", "MIKS": "MIKS COIN", - "MIL": "Milllionaire Coin", + "MIL": "Mil", "MILA": "MILADY MEME TOKEN", "MILC": "Micro Licensing Coin", "MILE": "milestoneBased", @@ -10497,6 +10678,7 @@ "MILLI": "Million", "MILLIM": "Millimeter", "MILLIMV1": "Millimeter v1", + "MILLLIONAIRECOIN": "Milllionaire Coin", "MILLY": "milly", "MILO": "Milo Inu", "MILOCEO": "Milo CEO", @@ -10510,6 +10692,7 @@ "MIMO": "MIMO Parallel Governance Token", "MIN": "MINDOL", "MINA": "Mina Protocol", + "MINAR": "Miner Arena", "MINC": "MinCoin", "MIND": "Morpheus Labs", "MINDBODY": "Mind Body Soul", @@ -10766,6 +10949,7 @@ "MOLK": "Mobilink Token", "MOLLARS": "MollarsToken", "MOLLY": "Molly", + "MOLT": "Moltbook", "MOM": "Mother of Memes", "MOMA": "Mochi Market", "MOMIJI": "MAGA Momiji", @@ -10781,6 +10965,7 @@ "MONAV": "Monavale", "MONB": "MonbaseCoin", "MONDO": "mondo", + "MONEROAI": "Monero AI", "MONEROCHAN": "Monerochan", "MONET": "Claude Monet Memeory Coin", "MONETA": "Moneta", @@ -10889,6 +11074,7 @@ "MOTIONCOIN": "Motion", "MOTO": "Motocoin", "MOUND": "Mound Token", + "MOUNTA": "Mountain Protocol", "MOUTAI": "Moutai", "MOV": "MovieCoin", "MOVD": "MOVE Network", @@ -10911,7 +11097,7 @@ "MPAA": "MPAA", "MPAD": "MultiPad", "MPAY": "Menapay", - "MPC": "Metaplace", + "MPC": "Partisia Blockchain", "MPD": "Metapad", "MPG": "Max Property Group", "MPH": "Morpher", @@ -10970,6 +11156,7 @@ "MSCT": "MUSE ENT NFT", "MSD": "MSD", "MSFT": "Microsoft 6900", + "MSFTON": "Microsoft (Ondo Tokenized)", "MSFTX": "Microsoft xStock", "MSG": "MsgSender", "MSGO": "MetaSetGO", @@ -10993,6 +11180,7 @@ "MSTRX": "MicroStrategy xStock", "MSU": "MetaSoccer", "MSUSHI": "Sushi (Multichain)", + "MSVP": "MetaSoilVerseProtocol", "MSWAP": "MoneySwap", "MT": "Mint Token", "MTA": "Meta", @@ -11010,6 +11198,7 @@ "MTHB": "MTHAIBAHT", "MTHD": "Method Finance", "MTHN": "MTH Network", + "MTHT": "MetaHint", "MTIK": "MatikaToken", "MTIX": "Matrix Token", "MTK": "Moya Token", @@ -11072,6 +11261,7 @@ "MUNITY": "Metahorse Unity", "MUNK": "Dramatic Chipmunk", "MUNSUN": "MUNSUN", + "MUON": "Micron Technology (Ondo Tokenized)", "MURA": "Murasaki", "MURATIAI": "MuratiAI", "MUSCAT": "MusCat", @@ -11119,9 +11309,11 @@ "MWD": "MEW WOOF DAO", "MWETH": "Moonwell Flagship ETH (Morpho Vault)", "MWH": "Melania Wif Hat", + "MWT": "Mountain Wolf Token", "MWXT": "MWX Token", "MX": "MX Token", - "MXC": "Machine Xchange Coin", + "MXC": "MXC Token", + "MXCV1": "Machine Xchange Coin v1", "MXD": "Denarius", "MXGP": "MXGP Fan Token", "MXM": "Maximine", @@ -11144,10 +11336,12 @@ "MYL": "MyLottoCoin", "MYLINX": "Linx", "MYLO": "MYLOCAT", + "MYMASTERWAR": "My Master Wa", "MYNE": "ITSMYNE", "MYO": "Mycro", "MYOBU": "Myōbu", "MYRA": "Mytheria", + "MYRC": "MYRC", "MYRE": "Myre", "MYRIA": "Myria", "MYRO": "Myro", @@ -11175,6 +11369,7 @@ "N3": "Network3", "N3DR": "NeorderDAO ", "N3ON": "N3on", + "N4T": "Nobel For Trump", "N64": "N64", "N7": "Number7", "N8V": "NativeCoin", @@ -11389,6 +11584,7 @@ "NEWSTOKENS": "NewsTokens", "NEWT": "Newton Protocol", "NEWTON": "Newtonium", + "NEWYORKCOIN": "NewYorkCoin", "NEX": "Nash Exchange", "NEXA": "Nexa", "NEXAI": "NexAI", @@ -11416,6 +11612,7 @@ "NFCR": "NFCore", "NFD": "Feisty Doge NFT", "NFE": "Edu3Labs", + "NFLXON": "Netflix (Ondo Tokenized)", "NFLXX": "Netflix xStock", "NFM": "NFMart", "NFN": "Nafen", @@ -11453,6 +11650,7 @@ "NGL": "Entangle", "NGM": "e-Money", "NGMI": "NGMI Coin", + "NGNT": "Naira Token", "NGTG": "NUGGET TRAP", "NHCT": "Nano Healthcare Token", "NHI": "Non Human Intelligence", @@ -11464,6 +11662,7 @@ "NIC": "NewInvestCoin", "NICE": "Nice", "NICEC": "NiceCoin", + "NIETZSCHEAN": "Nietzschean Penguin", "NIF": "Unifty", "NIFT": "Niftify", "NIFTSY": "Envelop", @@ -11495,6 +11694,7 @@ "NINU": "Nvidia Inu", "NIOB": "Niob Finance", "NIOCTIB": "nioctiB", + "NIOON": "NIO (Ondo Tokenized)", "NIOX": "Autonio", "NIOXV1": "Autonio v1", "NIOXV2": "Autonio v2", @@ -11550,6 +11750,7 @@ "NOBS": "No BS Crypto", "NOC": "Nono Coin", "NOCHILL": "AVAX HAS NO CHILL", + "NOCK": "Nockchain", "NODE": "NodeOps", "NODELYAI": "NodelyAI", "NODESYNAPSE": "NodeSynapse", @@ -11595,7 +11796,9 @@ "NOTDOG": "NOTDOG", "NOTE": "Republic Note", "NOTECANTO": "Note", - "NOTHING": "NOTHING", + "NOTHING": "Youll own nothing & be happy", + "NOTHINGCASH": "NOTHING", + "NOTIFAI": "NotifAi News", "NOTINU": "NOTCOIN INU", "NOTIONAL": "Notional Finance", "NOV": "Novara Calcio Fan Token", @@ -11611,6 +11814,7 @@ "NPER": "NPER", "NPICK": "NPICK BLOCK", "NPLC": "Plus Coin", + "NPLCV1": "PlusCoin v1", "NPM": "Neptune Mutual", "NPRO": "NPRO", "NPT": "Neopin", @@ -11624,6 +11828,7 @@ "NRCH": "EnreachDAO", "NRFB": "NuriFootBall", "NRG": "Energi", + "NRGE": "New Resources Generation Energy", "NRGY": "NRGY Defi", "NRK": "Nordek", "NRM": "Neuromachine", @@ -11703,6 +11908,7 @@ "NVA": "Neeva Defi", "NVB": "NovaBank", "NVC": "NovaCoin", + "NVDAON": "NVIDIA (Ondo Tokenized)", "NVDAX": "NVIDIA xStock", "NVDX": "Nodvix", "NVG": "NightVerse Game", @@ -11722,6 +11928,7 @@ "NWIF": "neirowifhat", "NWP": "NWPSolution", "NWS": "Nodewaves", + "NXA": "NEXA Agent", "NXC": "Nexium", "NXD": "Nexus Dubai", "NXDT": "NXD Next", @@ -11743,7 +11950,7 @@ "NYANDOGE": "NyanDOGE International", "NYANTE": "Nyantereum International", "NYBBLE": "Nybble", - "NYC": "NewYorkCoin", + "NYC": "NYC", "NYCREC": "NYCREC", "NYE": "NewYork Exchange", "NYEX": "Nyerium", @@ -11766,7 +11973,8 @@ "OAS": "Oasis City", "OASC": "Oasis City", "OASI": "Oasis Metaverse", - "OASIS": "Oasis", + "OASIS": "OASIS", + "OASISPLATFORM": "Oasis", "OAT": "OAT Network", "OATH": "OATH Protocol", "OAX": "Oax", @@ -11798,6 +12006,7 @@ "OCE": "OceanEX Token", "OCEAN": "Ocean Protocol", "OCEANT": "Poseidon Foundation", + "OCEANV1": "Ocean Protocol v1", "OCH": "Orchai", "OCICAT": "OciCat", "OCL": "Oceanlab", @@ -11945,7 +12154,7 @@ "OMNIXIO": "OMNIX", "OMNOM": "Doge Eat Doge", "OMNOMN": "Omega Network", - "OMT": "Mars Token", + "OMT": "Oracle Meta Technologies", "OMV1": "OM Token (v1)", "OMX": "Project Shivom", "OMZ": "Open Meta City", @@ -11955,6 +12164,7 @@ "ONCH": "OnchainPoints.xyz", "ONDO": "Ondo", "ONDOAI": "Ondo DeFAI", + "ONDSON": "Ondas Holdings (Ondo Tokenized)", "ONE": "Harmony", "ONEROOT": "OneRoot Network", "ONES": "OneSwap DAO", @@ -11983,12 +12193,14 @@ "ONUS": "ONUS", "ONX": "OnX.finance", "OOB": "Oobit", + "OOBV1": "Oobit", "OOE": "OpenOcean", "OOFP": "OOFP", "OOGI": "OOGI", "OOKI": "Ooki", "OOKS": "Onooks", "OOM": "OomerBot", + "OOOO": "oooo", "OOPS": "OOPS", "OORC": "Orbit Bridge Klaytn Orbit Chain", "OORT": "OORT", @@ -12010,6 +12222,7 @@ "OPENCUSTODY": "Open Custody Protocol", "OPENDAO": "OpenDAO", "OPENGO": "OPEN Governance Token", + "OPENON": "Opendoor Technologies (Ondo Tokenized)", "OPENP": "Open Platform", "OPENRI": "Open Rights Exchange", "OPENSOURCE": "Open Source Network", @@ -12174,7 +12387,8 @@ "OWB": "OWB", "OWC": "Oduwa", "OWD": "Owlstand", - "OWL": "OWL Token", + "OWL": "Owlto", + "OWLTOKEN": "OWL Token", "OWN": "OTHERWORLD", "OWNDATA": "OWNDATA", "OWNLY": "Ownly", @@ -12198,6 +12412,7 @@ "OZG": "Ozagold", "OZK": "OrdiZK", "OZMPC": "Ozempic", + "OZNI": "Ni Token", "OZO": "Ozone Chain", "OZONE": "Ozone metaverse", "OZONEC": "Ozonechain", @@ -12207,6 +12422,7 @@ "P202": "Project 202", "P2P": "Sentinel", "P2PS": "P2P Solutions Foundation", + "P2PV1": "Sentinel", "P33L": "THE P33L", "P3D": "3DPass", "P404": "Potion 404", @@ -12222,6 +12438,7 @@ "PACOCA": "Pacoca", "PACP": "PAC Protocol", "PACT": "impactMarket", + "PACTTOKEN": "PACT community token", "PACTV1": "impactMarket v1", "PAD": "NearPad", "PAF": "Pacific", @@ -12265,6 +12482,7 @@ "PANGEA": "PANGEA", "PANIC": "PanicSwap", "PANO": "PanoVerse", + "PANTHER": "Panther Protocol", "PANTOS": "Pantos", "PAO": "South Pao", "PAPA": "Papa Bear", @@ -12377,10 +12595,12 @@ "PCN": "PeepCoin", "PCNT": "Playcent", "PCO": "Pecunio", + "PCOCK": "PulseChain Peacock", "PCOIN": "Pioneer Coin", "PCR": "Paycer Protocol", "PCS": "Pabyosi Coin", "PCSP": "GenomicDao G-Stroke", + "PCT": "PET CASH TOKEN", "PCW": "Power Crypto World", "PCX": "ChainX", "PD": "PUDEL", @@ -12391,6 +12611,7 @@ "PDD": "PDDOLLAR", "PDEX": "Polkadex", "PDF": "Port of DeFi Network", + "PDI": "Phuture DeFi Index", "PDJT": "President Donald J. Trump", "PDOG": "Polkadog", "PDOGE": "PolkaDoge", @@ -12453,6 +12674,7 @@ "PENDY": "Pendy", "PENG": "Peng", "PENGCOIN": "PENG", + "PENGO": "Petro Penguins", "PENGU": "Pudgy Penguins", "PENGUAI": "PENGU AI", "PENGUI": "Penguiana", @@ -12513,6 +12735,7 @@ "PEPEMO": "PepeMo", "PEPEMOON": "PEPEMOON", "PEPEMUSK": "pepemusk", + "PEPENODE": "PEPENODE", "PEPEOFSOL": "Pepe of Solana", "PEPEPI": "PEPEPi", "PEPER": "Baby Pepe", @@ -12548,6 +12771,7 @@ "PERC": "Perion", "PERCY": "Percy Verence", "PERI": "PERI Finance", + "PERKSCOIN": "PerksCoin ", "PERL": "PERL.eco", "PERMIAN": "Permian", "PERP": "Perpetual Protocol", @@ -12575,7 +12799,10 @@ "PEUSD": "peg-eUSD", "PEW": "pepe in a memes world", "PEX": "Pexcoin", + "PF": "Purple Frog", + "PFEON": "Pfizer (Ondo Tokenized)", "PFEX": "Pfizer xStock", + "PFF": "PumpFunFloki", "PFI": "PrimeFinance", "PFID": "Pofid Dao", "PFL": "Professional Fighters League Fan Token", @@ -12671,6 +12898,7 @@ "PIKAM": "Pikamoon", "PIKE": "Pike Token", "PIKO": "Pinnako", + "PIKZ": "PIKZ", "PILLAR": "PillarFi", "PILOT": "Unipilot", "PIM": "PIM", @@ -12765,7 +12993,7 @@ "PLAYCOIN": "PlayCoin", "PLAYFUN": "PLAYFUN", "PLAYKEY": "Playkey", - "PLAYSOL": "Play Solana", + "PLAYSOLANA": "Play Solana", "PLAYTOKEN": "Play Token", "PLB": "Paladeum", "PLBT": "Polybius", @@ -12808,12 +13036,14 @@ "PLSX": "PulseX", "PLT": "Poollotto.finance", "PLTC": "PlatonCoin", + "PLTRON": "Palantir Technologies (Ondo Tokenized)", "PLTRX": "Palantir xStock", "PLTX": "PlutusX", "PLTXYZ": "Add.xyz", "PLU": "Pluton", "PLUG": "PL^Gnet", "PLUGCN": "Plug Chain", + "PLUGON": "Plug Power (Ondo Tokenized)", "PLUME": "Plume", "PLUP": "PoolUp", "PLURA": "PluraCoin", @@ -12838,7 +13068,7 @@ "PMOON": "Pookimoon", "PMPY": "Prometheum Prodigy", "PMR": "Pomerium Utility Token", - "PMT": "POWER MARKET", + "PMT": "Public Masterpiece Token", "PMTN": "Peer Mountain", "PMX": "Phillip Morris xStock", "PNB": "Pink BNB", @@ -12908,7 +13138,7 @@ "POLLEN": "Beraborrow", "POLLUK": "Jasse Polluk", "POLLUX": "Pollux Coin", - "POLLY": "Polynetica", + "POLLY": "Polly Penguin", "POLNX": "eToro Polish Zloty", "POLO": "NftyPlay", "POLS": "Polkastarter", @@ -12917,6 +13147,7 @@ "POLY": "Polymath Network", "POLYCUB": "PolyCub", "POLYDOGE": "PolyDoge", + "POLYN": "Polynetica", "POLYPAD": "PolyPad", "POLYX": "Polymesh", "POM": "Proof Of Memes", @@ -12929,6 +13160,7 @@ "PONKE": "Ponke", "PONKEBNB": "Ponke BNB", "PONKEI": "Chinese Ponkei the Original", + "PONTEM": "Pontem Liquidswap", "PONYO": "Ponyo Impact", "PONZI": "Ponzi", "PONZIO": "Ponzio The Cat", @@ -13001,7 +13233,9 @@ "POUW": "Pouwifhat", "POW": "PowBlocks", "POWELL": "Jerome Powell", - "POWER": "Powerloom Token", + "POWER": "Power", + "POWERLOOM": "Powerloom Token", + "POWERMARKET": "POWER MARKET", "POWR": "Power Ledger", "POWSCHE": "Powsche", "POX": "Monkey Pox", @@ -13042,6 +13276,7 @@ "PREAI": "Predict Crypto", "PREC": "Precipitate.AI", "PRED": "Predictcoin", + "PREDIC": "PredicTools", "PREM": "Premium", "PREME": "PREME Token", "PREMIA": "Premia", @@ -13050,6 +13285,7 @@ "PRESI": "Turbo Trump", "PRESID": "President Ron DeSantis", "PRESIDEN": "President Elon", + "PRESSX": "PressX", "PRFT": "Proof Suite Token", "PRG": "Paragon", "PRI": "PRIVATEUM INITIATIVE", @@ -13149,6 +13385,7 @@ "PSWAP": "Polkaswap", "PSY": "PsyOptions", "PSYOP": "PSYOP", + "PSYOPANIME": "PsyopAnime", "PT": "Phemex", "PTA": "PentaCoin", "PTAS": "La Peseta", @@ -13247,8 +13484,9 @@ "PUX": "pukkamex", "PVC": "PVC Meta", "PVFYBO": "JRVGCUPVSC", - "PVP": "PvP", + "PVP": "Pvpfun", "PVPCHAIN": "PVPChain", + "PVPGAME": "PvP", "PVT": "Punkvism Token", "PVU": "Plant vs Undead Token", "PWAR": "PolkaWar", @@ -13261,14 +13499,16 @@ "PWR": "MaxxChain", "PWRC": "PWR Coin", "PWT": "PANDAINU", - "PX": "PXcoin", + "PX": "Not Pixel", "PXB": "PixelBit", "PXC": "PhoenixCoin", + "PXCOIN": "PXcoin", "PXG": "PlayGame", "PXI": "Prime-X1", "PXL": "PIXEL", "PXP": "PointPay", "PXT": "Pixer Eternity", + "PYBOBO": "Capybobo", "PYC": "PayCoin", "PYE": "CreamPYE", "PYI": "PYRIN", @@ -13278,6 +13518,7 @@ "PYME": "PymeDAO", "PYN": "Paynetic", "PYP": "PayPro", + "PYPLON": "PayPal (Ondo Tokenized)", "PYQ": "PolyQuity", "PYR": "Vulcan Forged", "PYRAM": "Pyram Token", @@ -13314,6 +13555,7 @@ "QBX": "qiibee foundation", "QBZ": "QUEENBEE", "QC": "Qcash", + "QCAD": "QCAD", "QCH": "QChi", "QCN": "Quazar Coin", "QCO": "Qravity", @@ -13346,6 +13588,7 @@ "QNX": "QueenDex Coin", "QOBI": "Qobit", "QOM": "Shiba Predator", + "QONE": "QONE", "QOOB": "QOOBER", "QORA": "QoraCoin", "QORPO": "QORPO WORLD", @@ -13385,6 +13628,7 @@ "QUA": "Quantum Tech", "QUAC": "QUACK", "QUACK": "Rich Quack", + "QUADRANS": "QuadransToken", "QUAI": "Quai Network", "QUAIN": "QUAIN", "QUAM": "Quam Network", @@ -13446,7 +13690,7 @@ "RADAR": "DappRadar", "RADI": "RadicalCoin", "RADIO": "RadioShack", - "RADR": "CoinRadr", + "RADR": "RADR", "RADX": "Radx AI", "RAFF": "Ton Raffles", "RAFFLES": "Degen Raffles", @@ -13461,6 +13705,7 @@ "RAIF": "RAI Finance", "RAIIN": "Raiin", "RAIL": "Railgun", + "RAILS": "Rails Token", "RAIN": "Rain", "RAINBOW": "Rainbow Token", "RAINC": "RainCheck", @@ -13470,6 +13715,7 @@ "RAIREFLEX": "Rai Reflex Index", "RAISE": "Raise Token", "RAIT": "Rabbitgame", + "RAITOKEN": "RAI", "RAIZER": "RAIZER", "RAK": "Rake Finance", "RAKE": "Rake Coin", @@ -13497,16 +13743,18 @@ "RATOTHERAT": "Rato The Rat", "RATS": "Rats", "RATWIF": "RatWifHat", - "RAVE": "Ravendex", + "RAVE": "RaveDAO", "RAVELOUS": "Ravelous", "RAVEN": "Raven Protocol", "RAVENCOINC": "Ravencoin Classic", + "RAVENDEX": "Ravendex", "RAWDOG": "RawDog", "RAWG": "RAWG", "RAY": "Raydium", "RAYS": "Rays Network", "RAZE": "Raze Network", "RAZOR": "Razor Network", + "RAZORCOIN": "RazorCoin", "RB": "REBorn", "RBBT": "RabbitCoin", "RBC": "Rubic", @@ -13588,6 +13836,7 @@ "REALYN": "Real", "REAP": "ReapChain", "REAPER": "Grim Finance", + "REAT": "REAT", "REAU": "Vira-lata Finance", "REBD": "REBORN", "REBL": "REBL", @@ -13810,7 +14059,8 @@ "RIVUS": "RivusDAO", "RIYA": "Etheriya", "RIZ": "Rivalz Network", - "RIZE": "Rizespor Token", + "RIZE": "RIZE", + "RIZESPOR": "Rizespor Token", "RIZO": "HahaYes", "RIZOLOL": "Rizo", "RIZZ": "Rizz", @@ -13852,10 +14102,12 @@ "RNDR": "Render Token", "RNDX": "Round X", "RNEAR": "Near (Rainbow Bridge)", + "RNGR": "Ranger", "RNS": "RenosCoin", "RNT": "REAL NIGGER TATE", "RNTB": "BitRent", "RNX": "ROONEX", + "ROA": "ROA CORE", "ROAD": "ROAD", "ROAM": "Roam Token", "ROAR": "Alpha DEX", @@ -13889,6 +14141,7 @@ "ROK": "Rockchain", "ROKM": "Rocket Ma", "ROKO": "Roko", + "ROLL": "Roll", "ROLLSROYCE": "RollsRoyce", "ROLS": "RollerSwap", "ROM": "ROMCOIN", @@ -13993,6 +14246,7 @@ "RTM": "Raptoreum", "RTR": "Restore The Republic", "RTT": "Restore Truth Token", + "RTX": "RateX", "RU": "RIFI United", "RUBB": "Rubber Ducky Cult", "RUBCASH": "RUBCASH", @@ -14080,7 +14334,7 @@ "RYT": "Real Yield Token", "RYU": "The Blue Dragon", "RYZ": "Anryze", - "RZR": "RazorCoin", + "RZR": "Rezor", "RZTO": "RZTO Token", "RZUSD": "RZUSD", "RedFlokiCEO": "Red Floki CEO", @@ -14142,6 +14396,7 @@ "SAKAI": "Sakai Vault", "SAKATA": "Sakata Inu", "SAKE": "SakeToken", + "SAKURACOIN": "Sakuracoin", "SAL": "Salvium", "SALD": "Salad", "SALE": "DxSale Network", @@ -14283,7 +14538,7 @@ "SCOIN": "ShinCoin", "SCONE": "Sportcash One", "SCOOBY": "Scooby coin", - "SCOR": "Scorista", + "SCOR": "Scor", "SCORE": "Scorecoin", "SCOT": "Scotcoin", "SCOTT": "Scottish", @@ -14345,6 +14600,7 @@ "SEAM": "Seamless Protocol", "SEAMLESS": "SeamlessSwap", "SEAN": "Starfish Finance", + "SEAS": "Seasons", "SEAT": "Seamans Token", "SEATLABNFT": "SeatlabNFT", "SEBA": "Seba", @@ -14377,6 +14633,7 @@ "SELFIEC": "Selfie Cat", "SELFT": "SelfToken", "SELLC": "Sell Token", + "SELO": "SELO+", "SEM": "Semux", "SEN": "Sentaro", "SENA": "Ethena Staked ENA", @@ -14393,7 +14650,7 @@ "SENSOR": "Sensor Protocol", "SENSOV1": "SENSO v1", "SENSUS": "Sensus", - "SENT": "Sentinel", + "SENT": "Sentient", "SENTAI": "SentAI", "SENTI": "Sentinel Bot Ai", "SENTIS": "Sentism AI Token", @@ -14419,6 +14676,7 @@ "SETH": "sETH", "SETH2": "sETH2", "SETHER": "Sether", + "SETHH": "Staked ETH Harbour", "SETS": "Sensitrust", "SEUR": "Synth sEUR", "SEW": "simpson in a memes world", @@ -14461,6 +14719,7 @@ "SGB": "Songbird", "SGDX": "eToro Singapore Dollar", "SGE": "Society of Galactic Exploration", + "SGI": "SmartGolfToken", "SGLY": "Singularity", "SGN": "Signals Network", "SGO": "SafuuGO", @@ -14482,7 +14741,6 @@ "SHANG": "Shanghai Inu", "SHAR": "Shark Cat", "SHARBI": "SHARBI", - "SHARD": "ShardCoin", "SHARDS": "WorldShards", "SHARE": "Seigniorage Shares", "SHARECHAIN": "ShareChain", @@ -14530,6 +14788,7 @@ "SHIBACASH": "ShibaCash", "SHIBADOG": "Shiba San", "SHIBAI": "AiShiba", + "SHIBAINU": "SHIBA INU", "SHIBAKEN": "Shibaken Finance", "SHIBAMOM": "Shiba Mom", "SHIBANCE": "Shibance Token", @@ -14580,6 +14839,7 @@ "SHIRO": "Shiro Neko", "SHIROSOL": "Shiro Neko (shirosol.online)", "SHIRYOINU": "Shiryo-Inu", + "SHISA": "SHISA", "SHISHA": "Shisha Coin", "SHIT": "I will poop it NFT", "SHITC": "Shitcoin", @@ -14599,6 +14859,7 @@ "SHOKI": "Shoki", "SHON": "ShonToken", "SHONG": "Shong Inu", + "SHOOK": "SHOOK", "SHOOT": "Mars Battle", "SHOOTER": "Top Down Survival Shooter", "SHOP": "Shoppi Coin", @@ -14628,9 +14889,11 @@ "SHUFFLE": "SHUFFLE!", "SHVR": "Shivers", "SHX": "Stronghold Token", + "SHXV1": "Stronghold Token v1", "SHY": "Shytoshi Kusama", "SHYTCOIN": "ShytCoin", "SI": "Siren", + "SI14": "Si14", "SIACLASSIC": "SiaClassic", "SIB": "SibCoin", "SIBA": "SibaInu", @@ -14646,6 +14909,7 @@ "SIFT": "Smart Investment Fund Token", "SIFU": "SIFU", "SIG": "Signal", + "SIGHT": "Empire of Sight", "SIGM": "Sigma", "SIGMA": "SIGMA", "SIGN": "Sign", @@ -14654,6 +14918,7 @@ "SIGNMETA": "Sign Token", "SIGT": "Signatum", "SIGU": "Singular", + "SIH": "Salient Investment Holding", "SIKA": "SikaSwap", "SIL": "SIL Finance Token V2", "SILENTIS": "Silentis", @@ -14691,6 +14956,7 @@ "SINE": "Sinelock", "SING": "SingularFarm", "SINGLE": "Single Finance", + "SINGULARRY": "SINGULARRY", "SINK": "Let that sink in", "SINS": "SafeInsure", "SINSO": "SINSO", @@ -14747,7 +15013,7 @@ "SKO": "Sugar Kingdom Odyssey", "SKOP": "Skulls of Pepe Token", "SKPEPE": "Sheikh Pepe", - "SKR": "Sakuracoin", + "SKR": "Seeker", "SKRB": "Sakura Bloom", "SKRIMP": "Skrimples", "SKRP": "Skraps", @@ -14804,6 +15070,7 @@ "SLOKI": "Super Floki", "SLOP": "Slop", "SLORK": "SLORK", + "SLOT": "Alphaslot", "SLOTH": "Sloth", "SLOTHA": "Slothana", "SLP": "Smooth Love Potion", @@ -14817,6 +15084,7 @@ "SLUGDENG": "SLUG DENG", "SLUMBO": "SLUMBO", "SLVLUSD": "Staked Level USD", + "SLVON": "iShares Silver Trust (Ondo Tokenized)", "SLVX": "eToro Silver", "SLX": "SLIMEX", "SMA": "Soma Network", @@ -14831,6 +15099,7 @@ "SMARTLOX": "SmartLOX", "SMARTM": "SmartMesh", "SMARTMEME": "SmartMEME", + "SMARTMFG": "Smart MFG", "SMARTNFT": "SmartNFT", "SMARTO": "smARTOFGIVING", "SMARTSHARE": "Smartshare", @@ -14840,6 +15109,7 @@ "SMBR": "Sombra", "SMBSWAP": "SimbCoin Swap", "SMC": "SmartCoin", + "SMCION": "Super Micro Computer (Ondo Tokenized)", "SMCW": "Space Misfits", "SMD": "SMD Coin", "SMETA": "StarkMeta", @@ -14899,6 +15169,7 @@ "SNAP": "SnapEx", "SNAPCAT": "Snapcat", "SNAPKERO": "SNAP", + "SNAPON": "Snap (Ondo Tokenized)", "SNB": "SynchroBitcoin", "SNC": "SunContract", "SNCT": "SnakeCity", @@ -14942,7 +15213,7 @@ "SNPT": "SNPIT TOKEN", "SNRG": "Synergy", "SNRK": "Snark Launch", - "SNS": "Synesis One", + "SNS": "Solana Name Service", "SNST": "Smooth Network Solutions Token", "SNSY": "Sensay", "SNT": "Status Network Token", @@ -14975,11 +15246,13 @@ "SOETH": "Wrapped Ethereum (Sollet)", "SOFAC": "SofaCat", "SOFI": "RAI Finance", + "SOFION": "SoFi Technologies (Ondo Tokenized)", "SOFTCO": "SOFT COQ INU", "SOFTT": "Wrapped FTT (Sollet)", "SOGNI": "Sogni AI", "SOGUR": "Sogur Currency", "SOH": "Stohn Coin", + "SOHMV1": "Staked Olympus v1", "SOHOT": "SOHOTRN", "SOIL": "Soil", "SOILCOIN": "SoilCoin", @@ -15031,6 +15304,7 @@ "SOLIDSEX": "SOLIDsex: Tokenized veSOLID", "SOLINK": "Wrapped Chainlink (Sollet)", "SOLITO": "SOLITO", + "SOLKABOSU": "Kabosu", "SOLKIT": "Solana Kit", "SOLLY": "Solly", "SOLM": "SolMix", @@ -15040,6 +15314,7 @@ "SOLNAV": "SOLNAV AI", "SOLNIC": "Solnic", "SOLO": "Sologenic", + "SOLOM": "Solomon", "SOLOR": "Solordi", "SOLP": "SolPets", "SOLPAD": "Solpad Finance", @@ -15122,7 +15397,7 @@ "SP8DE": "Sp8de", "SPA": "Sperax", "SPAC": "SPACE DOGE", - "SPACE": "MicroVisionChain", + "SPACE": "Spacecoin", "SPACECOIN": "SpaceCoin", "SPACED": "SPACE DRAGON", "SPACEHAMSTER": "Space Hamster", @@ -15207,6 +15482,7 @@ "SPO": "Spores Network", "SPOK": "Spock", "SPOL": "Starterpool", + "SPON": "Spheron Network", "SPONG": "Spongebob", "SPONGE": "Sponge", "SPONGEBOB": "Spongebob Squarepants", @@ -15215,6 +15491,7 @@ "SPOOL": "Spool DAO Token", "SPORE": "Spore", "SPORT": "SportsCoin", + "SPORTFUN": "Sport.fun", "SPORTS": "ZenSports", "SPORTSFIX": "SportsFix", "SPORTSP": "SportsPie", @@ -15243,6 +15520,7 @@ "SPX6969": "SPX 6969", "SPXC": "SpaceXCoin", "SPY": "Smarty Pay", + "SPYON": "SPDR S&P 500 ETF (Ondo Tokenized)", "SPYRO": "SPYRO", "SPYX": "SP500 xStock", "SQ3": "Squad3", @@ -15251,6 +15529,7 @@ "SQG": "Squid Token", "SQGROW": "SquidGrow", "SQL": "Squall Coin", + "SQQQON": "ProShares UltraPro Short QQQ (Ondo Tokenized)", "SQR": "Magic Square", "SQRL": "Squirrel Swap", "SQT": "SubQuery Network", @@ -15268,6 +15547,8 @@ "SQUIDGROWV1": "SquidGrow v1", "SQUIDV1": "Squid Game v1", "SQUIDW": "Squidward Coin", + "SQUIG": "Squiggle DAO Token", + "SQUIGDAO": "SquiggleDAO ERC20", "SQUIRT": "SQUIRTLE", "SQUOGE": "DogeSquatch", "SR30": "SatsRush", @@ -15332,21 +15613,24 @@ "STACS": "STACS Token", "STAFIRETH": "StaFi Staked ETH", "STAGE": "Stage", + "STAI": "StereoAI", "STAK": "Jigstack", "STAKE": "xDai Chain", "STAKEDETH": "StakeHound Staked Ether", + "STAKERDAOWXTZ": "Wrapped Tezos", "STALIN": "StalinCoin", "STAMP": "SafePost", "STAN": "Stank Memes", "STANDARD": "Stakeborg DAO", "STAPT": "Ditto Staked Aptos", - "STAR": "StarHeroes", + "STAR": "Starpower Network Token", "STAR10": "Ronaldinho Coin", "STARAMBA": "Staramba", "STARBASE": "Starbase", "STARC": "StarChain", "STARDOGE": "StarDOGE", "STARGATEAI": "Stargate AI Agent", + "STARHEROES": "StarHeroes", "STARL": "StarLink", "STARLAUNCH": "StarLaunch", "STARLY": "Starly", @@ -15422,6 +15706,7 @@ "STIMA": "STIMA", "STING": "Sting", "STINJ": "Stride Staked INJ", + "STIPS": "Stips", "STITCH": "Stitch", "STIX": "STIX", "STJUNO": "Stride Staked JUNO", @@ -15597,8 +15882,10 @@ "SUPERBONK": "SUPER BONK", "SUPERC": "SuperCoin", "SUPERCAT": "SUPERCAT", + "SUPERCYCLE": "Crypto SuperCycle", "SUPERDAPP": "SuperDapp", "SUPERF": "SUPER FLOKI", + "SUPERFL": "Superfluid", "SUPERGROK": "SuperGrok", "SUPEROETHB": "Super OETH", "SUPERT": "Super Trump", @@ -15732,6 +16019,7 @@ "SYNCO": "Synco", "SYND": "Syndicate", "SYNDOG": "Synthesizer Dog", + "SYNESIS": "Synesis One", "SYNK": "Synk", "SYNLEV": "SynLev", "SYNO": "Synonym Finance", @@ -15832,6 +16120,7 @@ "TATSU": "Taτsu", "TAU": "Lamden Tau", "TAUC": "Taurus Coin", + "TAUD": "TrueAUD", "TAUM": "Orbitau Taureum", "TAUR": "Marnotaur", "TAVA": "ALTAVA", @@ -15855,6 +16144,7 @@ "TBILL": "OpenEden T-Bills", "TBILLV1": "OpenEden T-Bills v1", "TBIS": "TBIS token", + "TBK": "TBK Token", "TBL": "Tombola", "TBLLX": "TBLL xStock", "TBR": "Tuebor", @@ -15902,7 +16192,8 @@ "TDROP": "ThetaDrop", "TDS": "TokenDesk", "TDX": "Tidex Token", - "TEA": "TeaDAO", + "TEA": "TeaFi Token", + "TEADAO": "TeaDAO", "TEAM": "TeamUP", "TEARS": "Liberals Tears", "TEC": "TeCoin", @@ -15933,7 +16224,7 @@ "TEMM": "TEM MARKET", "TEMP": "Tempus", "TEMPLE": "TempleDAO", - "TEN": "Tokenomy", + "TEN": "TEN", "TEND": "Tendies", "TENDIE": "TendieSwap", "TENET": "TENET", @@ -15947,8 +16238,8 @@ "TEQ": "Teq Network", "TER": "TerraNovaCoin", "TERA": "TERA", + "TERA2": "Terareum", "TERADYNE": "Teradyne", - "TERAR": "Terareum", "TERAV1": "Terareum v1", "TERAWATT": "Terawatt", "TERM": "Terminal of Simpson", @@ -15975,6 +16266,7 @@ "TETSUO": "Tetsuo Coin", "TETU": "TETU", "TEVA": "Tevaera", + "TEVI": "TEVI Coin", "TEW": "Trump in a memes world", "TEX": "Terrax", "TF47": "Trump Force 47", @@ -15988,7 +16280,7 @@ "TFT": "The Famous Token", "TFUEL": "Theta Fuel", "TGAME": "TrueGame", - "TGC": "TigerCoin", + "TGC": "TG.Casino", "TGCC": "TheGCCcoin", "TGPT": "Trading GPT", "TGRAM": "TG20 TGram", @@ -16026,7 +16318,9 @@ "THEOS": "Theos", "THEP": "The Protocol", "THEPLAY": "PLAY", + "THEREALCHAIN": "REAL", "THERESAMAY": "Theresa May Coin", + "THEROS": "THEROS", "THES": "The Standard Protocol (USDS)", "THESTANDARD": "Standard Token", "THETA": "Theta Network", @@ -16051,6 +16345,7 @@ "THOR": "THORSwap", "THOREUM": "Thoreum V3", "THP": "TurboHigh Performance", + "THQ": "Theoriq Token", "THR": "Thorecoin", "THREE": "Three Protocol Token ", "THRT": "ThriveToken", @@ -16078,6 +16373,7 @@ "TIG": "Tigereum", "TIGER": "TIGER", "TIGERC": "TigerCash", + "TIGERCOIN": "TigerCoin", "TIGERCV1": "TigerCash v1", "TIGERMOON": "TigerMoon", "TIGERSHARK": "Tiger Shark", @@ -16109,9 +16405,10 @@ "TIPS": "FedoraCoin", "TIPSX": "WisdomTree TIPS Digital Fund", "TIPSY": "TipsyCoin", - "TIT": "TittieCoin", + "TIT": "TITANIUM", "TITA": "Titan Hunters", "TITAN": "SATOSHI•RUNE•TITAN (Runes)", + "TITANCOIN": "Titan Coin", "TITANO": "Titano", "TITANSWAP": "TitanSwap", "TITANX": "TitanX", @@ -16120,6 +16417,7 @@ "TITI": "TiTi Protocol", "TITN": "Titan", "TITS": "We Love Tits", + "TITTIECOIN": "TittieCoin", "TITTY": "TamaKitty", "TIUSD": "TiUSD", "TIX": "Blocktix", @@ -16134,6 +16432,7 @@ "TKMK": "TOKAMAK", "TKMN": "Tokemon", "TKN": "Token Name Service", + "TKNT": "TKN Token", "TKO": "Tokocrypto", "TKP": "TOKPIE", "TKR": "CryptoInsight", @@ -16147,6 +16446,7 @@ "TLN": "Trustlines Network", "TLOS": "Telos", "TLP": "TulipCoin", + "TLTON": "iShares 20+ Year Treasury Bond ETF (Ondo Tokenized)", "TLW": "TILWIKI", "TMAGA": "THE MAGA MOVEMENT", "TMAI": "Token Metrics AI", @@ -16154,6 +16454,7 @@ "TME": "Timereum", "TMED": "MDsquare", "TMFT": "Turkish Motorcycle Federation", + "TMG": "T-mac DAO", "TMN": "TranslateMe", "TMNG": "TMN Global", "TMNT": "TMNT", @@ -16193,6 +16494,7 @@ "TOKC": "Tokyo Coin", "TOKE": "Tokemak", "TOKEN": "TokenFi", + "TOKENOMY": "Tokenomy", "TOKENPLACE": "Tokenplace", "TOKENSTARS": "TokenStars", "TOKERO": "TOKERO LevelUP Token", @@ -16299,6 +16601,7 @@ "TPV": "TravGoPV", "TPY": "Thrupenny", "TQ": "TonQuestion", + "TQQQON": "ProShares UltraPro QQQ (Ondo Tokenized)", "TQQQX": "TQQQ xStock", "TQRT": "TokoQrt", "TR3": "Tr3zor", @@ -16312,6 +16615,7 @@ "TRADE": "Polytrade", "TRADEBOT": "TradeBot", "TRADECHAIN": "Trade Chain", + "TRADETIDE": "Trade Tide Token", "TRADEX": "TradeX AI", "TRADOOR": "Tradoor", "TRAI": "Trackgood AI", @@ -16357,10 +16661,11 @@ "TRGI": "The Real Golden Inu", "TRHUB": "Tradehub", "TRI": "Triangles Coin", - "TRIA": "Triaconta", + "TRIA": "TRIA", "TRIAS": "Trias", "TRIBE": "Tribe", "TRIBETOKEN": "TribeToken", + "TRIBEX": "Tribe Token", "TRIBL": "Tribal Token", "TRICK": "TrickyCoin", "TRICKLE": "Trickle", @@ -16391,6 +16696,7 @@ "TROLLMODE": "TROLL MODE", "TROLLRUN": "TROLL", "TROLLS": "trolls in a memes world", + "TRONBETLIVE": "TRONbetLive", "TRONDOG": "TronDog", "TRONI": "Tron Inu", "TRONP": "Donald Tronp", @@ -16398,7 +16704,7 @@ "TROP": "Interop", "TROPPY": "TROPPY", "TROSS": "Trossard", - "TROVE": "Arbitrove Governance Token", + "TROVE": "TROVE", "TROY": "Troy", "TRP": "Tronipay", "TRR": "Terran Coin", @@ -16499,8 +16805,10 @@ "TSHARE": "Tomb Shares", "TSHP": "12Ships", "TSL": "Energo", + "TSLAON": "Tesla (Ondo Tokenized)", "TSLAX": "Tesla xStock", "TSLT": "Tamkin", + "TSMON": "Taiwan Semiconductor Manufacturing (Ondo Tokenized)", "TSN": "Tsunami Exchange Token", "TSO": "Thesirion", "TSOTCHKE": "tsotchke", @@ -16520,7 +16828,7 @@ "TTF": "TurboTrix Finance", "TTK": "The Three Kingdoms", "TTM": "Tradetomato", - "TTN": "Titan Coin", + "TTN": "TTN", "TTNT": "TITA Project", "TTT": "TRUMPETTOKEN", "TTTU": "T-Project", @@ -16537,7 +16845,8 @@ "TUKI": "Tuki", "TUKIV1": "Tuki v1", "TULIP": "Tulip Protocol", - "TUNA": "TUNACOIN", + "TUNA": "DefiTuna", + "TUNACOIN": "TUNACOIN", "TUNE": "Bitune", "TUNETRADEX": "TuneTrade", "TUP": "Tenup", @@ -16614,7 +16923,7 @@ "TZKI": "Tsuzuki Inu", "TZPEPE": "Tezos Pepe", "TZU": "Sun Tzu", - "U": "Union", + "U": "United Stables", "U2U": "U2U Network", "U8D": "Universal Dollar", "UA1": "UA1", @@ -16641,6 +16950,7 @@ "UBXT": "UpBots", "UC": "YouLive Coin", "UCA": "UCA Coin", + "UCANFIX": "Ucan fix life in1day", "UCAP": "Unicap.finance", "UCASH": "U.CASH", "UCCOIN": "UC Coin", @@ -16762,6 +17072,7 @@ "UNIL": "UniLayer", "UNIM": "Unicorn Milk", "UNIO": "Unio Coin", + "UNION": "Union", "UNIPOWER": "UniPower", "UNIPT": "Universal Protocol Token", "UNIQ": "Uniqredit", @@ -16838,7 +17149,9 @@ "US": "Talus Token", "USA": "Based USA", "USACOIN": "American Coin", - "USAT": "USAT", + "USAGIBNB": "U", + "USAT": "Tether America USD", + "USATINC": "USAT", "USBT": "Universal Blockchain", "USC": "Ultimate Secure Cash", "USCC": "USC", @@ -16877,16 +17190,20 @@ "USDGLOBI": "Globiance USD Stablecoin", "USDGV1": "USDG v1", "USDGV2": "USDG", - "USDH": "USDH Hubble Stablecoin", + "USDH": "USDH", + "USDHHUBBLE": "USDH Hubble Stablecoin", "USDHL": "Hyper USD", "USDI": "Interest Protocol USDi", "USDJ": "USDJ", "USDK": "USDK", + "USDKG": "USDKG", "USDL": "Lift Dollar", - "USDM": "Mountain Protocol", + "USDM": "USDM", "USDMA": "USD mars", - "USDN": "Neutral AI", + "USDN": "Ultimate Synthetic Delta Neutral", + "USDNEUTRAL": "Neutral AI", "USDO": "USD Open Dollar", + "USDON": "U.S. Dollar Tokenized Currency (Ondo)", "USDP": "Pax Dollar", "USDPLUS": "Overnight.fi USD+", "USDQ": "Quantoz USDQ", @@ -16924,6 +17241,7 @@ "USN": "USN", "USNBT": "NuBits", "USNOTA": "NOTA", + "USOR": "U.S Oil", "USP": "USP Token", "USPEPE": "American pepe", "USPLUS": "Fluent Finance", @@ -16941,11 +17259,13 @@ "USUALX": "USUALx", "USUD": "USUD", "USV": "Universal Store of Value", - "USX": "USX Quantum", + "USX": "USX", + "USXQ": "USX Quantum", "USYC": "Hashnote USYC", "UT": "Ulord", "UTBAI": "UTB.ai", "UTC": "UltraCoin", + "UTED": "United", "UTG": "UltronGlow", "UTH": "Uther", "UTHR": "Utherverse Xaeon", @@ -16968,8 +17288,9 @@ "UUU": "U Network", "UVT": "UvToken", "UW3S": "Utility Web3Shot", - "UWU": "UwU Lend", + "UWU": "Unlimited Wealth Utility", "UWUCOIN": "uwu", + "UWULEND": "UwU Lend", "UX": "Umee", "UXLINK": "UXLINK", "UXLINKV1": "UXLINK v1", @@ -16998,6 +17319,7 @@ "VALU": "Value", "VALUE": "Value Liquidity", "VALYR": "Valyr", + "VAM": "Vitalum", "VAMPIRE": "Vampire Inu", "VAN": "Vanspor Token", "VANA": "Vana", @@ -17094,6 +17416,7 @@ "VEO": "Amoveo", "VER": "VersalNFT", "VERA": "Vera", + "VEREM": "Verified Emeralds", "VERI": "Veritaseum", "VERIC": "VeriCoin", "VERIFY": "Verify", @@ -17154,6 +17477,7 @@ "VIDZ": "PureVidz", "VIEW": "Viewly", "VIG": "TheVig", + "VIGI": "Vigi", "VIK": "VIKTAMA", "VIKITA": "VIKITA", "VIKKY": "VikkyToken", @@ -17206,10 +17530,12 @@ "VIZ": "VIZ Token", "VIZION": "ViZion Protocol", "VIZSLASWAP": "VizslaSwap", + "VK": "VK Token", "VKNF": "VKENAF", "VLC": "Volcano Uni", "VLDY": "Validity", "VLK": "Vulkania", + "VLR": "Velora", "VLS": "Veles", "VLT": "Veltor", "VLTC": "Venus LTC", @@ -17263,6 +17589,7 @@ "VON": "Vameon", "VONE": "Vone", "VONSPEED": "Andrea Von Speed", + "VOOI": "VOOI", "VOOT": "VootCoin", "VOOZ": "Vooz Coin", "VOPO": "VOPO", @@ -17290,6 +17617,7 @@ "VRC": "Virtual Coin", "VRFY": "VERIFY", "VRGW": "Virtual Reality Game World", + "VRGX": "VROOMGO", "VRH": "Versailles Heroes", "VRL": "Virtual X", "VRM": "Verium", @@ -17323,6 +17651,7 @@ "VSYS": "V Systems", "VT": "Virtual Tourist", "VTC": "Vertcoin", + "VTCN": "Versatize Coin", "VTG": "Victory Gem", "VTHO": "VeChainThor", "VTIX": "Vanguard xStock", @@ -17355,6 +17684,7 @@ "VVS": "VVS Finance", "VVV": "Venice Token", "VX": "Visa xStock", + "VXC": "VINX COIN", "VXL": "Voxel X Network", "VXR": "Vox Royale", "VXRP": "Venus XRP", @@ -17367,6 +17697,7 @@ "VYPER": "VYPER.WIN", "VYVO": "Vyvo AI", "VZ": "Vault Zero", + "VZON": "Verizon (Ondo Tokenized)", "VZT": "Vezt", "W": "Wormhole", "W1": "W1", @@ -17424,7 +17755,8 @@ "WANNA": "Wanna Bot", "WANUSDT": "wanUSDT", "WAP": "Wet Ass Pussy", - "WAR": "WeStarter", + "WAR": "WAR", + "WARD": "Warden", "WARP": "WarpCoin", "WARPED": "Warped Games", "WARPIE": "Warpie", @@ -17443,6 +17775,7 @@ "WATCH": "Yieldwatch", "WATER": "Waterfall", "WATERCOIN": "WATER", + "WATLAS": "Wrapped Star Atlas (Portal Bridge)", "WATT": "WATTTON", "WAVAX": "Wrapped AVAX", "WAVES": "Waves", @@ -17492,6 +17825,7 @@ "WCFGV1": "Wrapped Centrifuge", "WCFX": "Wrapped Conflux", "WCG": "World Crypto Gold", + "WCHZ": "Wrapped Chiliz", "WCKB": "Wrapped Nervos Network", "WCOIN": "WCoin", "WCORE": "Wrapped Core", @@ -17524,6 +17858,7 @@ "WEBSIM": "The Css God by Virtuals", "WEBSS": "Websser", "WEC": "Whole Earth Coin", + "WECAN": "Wecan Group", "WECO": "WECOIN", "WED": "Wednesday Inu", "WEEBS": "Weebs", @@ -17561,8 +17896,10 @@ "WEPC": "World Earn & Play Community", "WEPE": "Wall Street Pepe", "WERK": "Werk Family", + "WESHOWTOKEN": "WeShow Token", "WEST": "Waves Enterprise", - "WET": "WeShow Token", + "WESTARTER": "WeStarter", + "WET": "HumidiFi Token", "WETH": "WETH", "WETHV1": "WETH v1", "WETHW": "Wrapped EthereumPoW", @@ -17581,6 +17918,7 @@ "WFIL": "Wrapped Filecoin", "WFLAMA": "WIFLAMA", "WFLOW": "Wrapped Flow", + "WFLR": "Wrapped Flare", "WFO": "WoofOracle", "WFRAGSOL": "Wrapped fragSOL", "WFT": "Windfall Token", @@ -17605,6 +17943,7 @@ "WHATSONPIC": "WhatsOnPic", "WHBAR": "Wrapped HBAR", "WHC": "Whales Club", + "WHCHZ": "Chiliz (Portal Bridge)", "WHEAT": "Wheat Token", "WHEE": "WHEE (Ordinals)", "WHEEL": "Wheelers", @@ -17617,6 +17956,8 @@ "WHISKEY": "WHISKEY", "WHITE": "WhiteRock", "WHITEHEART": "Whiteheart", + "WHITEPEPE": "The White Pepe", + "WHITEWHALE": "The White Whale", "WHL": "WhaleCoin", "WHO": "Truwho", "WHOLE": "Whole Network", @@ -17733,6 +18074,7 @@ "WMNT": "Wrapped Mantle", "WMOXY": "Moxy", "WMT": "World Mobile Token v1", + "WMTON": "Walmart (Ondo Tokenized)", "WMTX": "World Mobile Token", "WMW": "WoopMoney", "WMX": "Wombex Finance", @@ -17827,6 +18169,7 @@ "WPP": "Green Energy Token", "WPR": "WePower", "WQT": "Work Quest", + "WR": "White Rat", "WRC": "Worldcore", "WREACT": "Wrapped REACT", "WRK": "BlockWRK", @@ -17889,6 +18232,7 @@ "WUF": "WUFFI", "WUK": "WUKONG", "WUKONG": "Sun Wukong", + "WULFON": "Terawulf (Ondo Tokenized)", "WULFY": "Wulfy", "WUM": "Unicorn Meat", "WUSD": "Worldwide USD", @@ -17914,7 +18258,6 @@ "WXPL": "Wrapped XPL", "WXRP": "Wrapped XRP", "WXT": "WXT", - "WXTZ": "Wrapped Tezos", "WYAC": "Woman Yelling At Cat", "WYN": "Wynn", "WYNN": "Anita Max Wynn", @@ -17957,6 +18300,7 @@ "XAS": "Asch", "XAT": "ShareAt", "XAUC": "XauCoin", + "XAUH": "Herculis Gold Coin", "XAUM": "Matrixdock Gold", "XAUR": "Xaurum", "XAUT": "Tether Gold", @@ -18005,6 +18349,7 @@ "XCHF": "CryptoFranc", "XCHNG": "Chainge Finance", "XCI": "Cannabis Industry Coin", + "XCL": "Xcellar", "XCLR": "ClearCoin", "XCM": "CoinMetro", "XCN": "Onyxcoin", @@ -18043,7 +18388,8 @@ "XEC": "eCash", "XED": "Exeedme", "XEDO": "XedoAI", - "XEL": "Xel", + "XEL": "XELIS", + "XELCOIN": "Xel", "XELS": "XELS Coin", "XEM": "NEM", "XEN": "XEN Crypto", @@ -18053,6 +18399,7 @@ "XENO": "Xeno", "XENOVERSE": "Xenoverse", "XEP": "Electra Protocol", + "XERA": "XERA", "XERS": "X Project", "XES": "Proxeus", "XET": "Xfinite Entertainment Token", @@ -18171,6 +18518,7 @@ "XP": "Xphere", "XPA": "XPA", "XPARTY": "X Party", + "XPASS": "XPASS Token", "XPAT": "Bitnation Pangea", "XPAY": "Wallet Pay", "XPB": "Pebble Coin", @@ -18232,6 +18580,7 @@ "XRPCV1": "XRP Classic v1", "XRPEPE": "XRPEPE", "XRPH": "XRP Healthcare", + "XRPHEDGE": "1X Short XRP Token", "XRS": "Xrius", "XRT": "Robonomics Network", "XRUN": "XRun", @@ -18361,13 +18710,15 @@ "YEAI": "YE AI Agent", "YEARN": "YearnTogether", "YEC": "Ycash", - "YEE": "Yeeco", + "YEE": "Yee Token", + "YEECO": "Yeeco", "YEED": "Yggdrash", "YEEHAW": "YEEHAW", "YEET": "Yeet", "YEETI": "YEETI 液体", "YEFI": "YeFi", "YEL": "Yel.Finance", + "YELLOWWHALE": "The Yellow Whale", "YELP": "Yelpro", "YEON": "Yeon", "YEPE": "Yellow Pepe", @@ -18497,6 +18848,7 @@ "ZAIF": "Zaif Token", "ZAIFIN": "Zero Collateral Dai", "ZAM": "Zamio", + "ZAMA": "Zama", "ZAMZAM": "ZAMZAM", "ZANO": "Zano", "ZAO": "zkTAO", @@ -18542,8 +18894,7 @@ "ZEBU": "ZEBU", "ZEC": "ZCash", "ZECD": "ZCashDarkCoin", - "ZED": "ZED Token", - "ZEDCOIN": "ZedCoin", + "ZED": "ZedCoins", "ZEDD": "ZedDex", "ZEDTOKEN": "Zed Token", "ZEDX": "ZEDX Сoin", @@ -18569,6 +18920,7 @@ "ZENPROTOCOL": "Zen Protocol", "ZENQ": "Zenqira", "ZENT": "Zentry", + "ZENV1": "Horizen v1", "ZEON": "Zeon Network", "ZEP": "Zeppelin Dao", "ZEPH": "Zephyr Protocol", @@ -18586,12 +18938,14 @@ "ZET2": "Zeta2Coin", "ZETA": "ZetaChain", "ZETH": "Zethan", + "ZETO": "ZeTo", "ZETRIX": "Zetrix", "ZEUM": "Colizeum", "ZEUS": "Zeus Network", "ZEUSPEPES": "Zeus", "ZEX": "Zeta", "ZEXI": "ZEXICON", + "ZEXX": "ZEXXCOIN", "ZEXY": "ZEXY", "ZF": "zkSwap Finance ", "ZFI": "Zyfi", @@ -18638,6 +18992,7 @@ "ZKEVM": "zkEVMChain (BSC)", "ZKEX": "zkExchange", "ZKF": "ZKFair", + "ZKFG": "ZKFG", "ZKGPT": "ZKGPT", "ZKGROK": "ZKGROK", "ZKGUN": "zkGUN", @@ -18649,7 +19004,7 @@ "ZKLAB": "zkSync Labs", "ZKLK": "ZkLock", "ZKML": "zKML", - "ZKP": "Panther Protocol", + "ZKP": "zkPass", "ZKPAD": "zkLaunchpad", "ZKPEPE": "ZKPEPEs", "ZKS": "ZKSpace", @@ -18693,6 +19048,7 @@ "ZOOM": "ZoomCoin", "ZOOMER": "Zoomer Coin", "ZOON": "CryptoZoon", + "ZOOSTORY": "ZOO", "ZOOT": "Zoo Token", "ZOOTOPIA": "Zootopia", "ZORA": "Zora", @@ -18720,8 +19076,9 @@ "ZSD": "Zephyr Protocol Stable Dollar", "ZSE": "ZSEcoin", "ZSH": "Ziesha", + "ZSWAP": "ZygoSwap", "ZT": "ZBG Token", - "ZTC": "ZeTo", + "ZTC": "Zenchain", "ZTG": "Zeitgeist", "ZTK": "Zefi", "ZTX": "ZTX", @@ -18769,5 +19126,14 @@ "vXDEFI": "vXDEFI", "wsOHM": "Wrapped Staked Olympus", "修仙": "修仙", - "币安人生": "币安人生" + "分红狗头": "分红狗头", + "哭哭马": "哭哭马", + "安": "安", + "币安人生": "币安人生", + "恶俗企鹅": "恶俗企鹅", + "我踏马来了": "我踏马来了", + "狗屎": "狗屎", + "老子": "老子", + "雪球": "雪球", + "黑马": "黑马" } diff --git a/apps/api/src/assets/cryptocurrencies/custom.json b/apps/api/src/assets/cryptocurrencies/custom.json index 814aeec34..a26fc33df 100644 --- a/apps/api/src/assets/cryptocurrencies/custom.json +++ b/apps/api/src/assets/cryptocurrencies/custom.json @@ -4,6 +4,7 @@ "LUNA1": "Terra", "LUNA2": "Terra", "SGB1": "Songbird", + "SKY33038": "Sky", "SMURFCAT": "Real Smurf Cat", "TON11419": "Toncoin", "UNI1": "Uniswap", diff --git a/apps/api/src/events/asset-profile-changed.event.ts b/apps/api/src/events/asset-profile-changed.event.ts index 46a8c5db4..c08fe59f1 100644 --- a/apps/api/src/events/asset-profile-changed.event.ts +++ b/apps/api/src/events/asset-profile-changed.event.ts @@ -8,4 +8,16 @@ export class AssetProfileChangedEvent { public static getName(): string { return 'assetProfile.changed'; } + + public getCurrency() { + return this.data.currency; + } + + public getDataSource() { + return this.data.dataSource; + } + + public getSymbol() { + return this.data.symbol; + } } diff --git a/apps/api/src/events/asset-profile-changed.listener.ts b/apps/api/src/events/asset-profile-changed.listener.ts index ad80ee4a5..cc70edad6 100644 --- a/apps/api/src/events/asset-profile-changed.listener.ts +++ b/apps/api/src/events/asset-profile-changed.listener.ts @@ -1,29 +1,74 @@ -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service'; import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathering/data-gathering.service'; import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; +import { getAssetProfileIdentifier } from '@ghostfolio/common/helper'; import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; +import { DataSource } from '@prisma/client'; +import ms from 'ms'; import { AssetProfileChangedEvent } from './asset-profile-changed.event'; @Injectable() export class AssetProfileChangedListener { + private static readonly DEBOUNCE_DELAY = ms('5 seconds'); + + private debounceTimers = new Map(); + public constructor( + private readonly activitiesService: ActivitiesService, private readonly configurationService: ConfigurationService, private readonly dataGatheringService: DataGatheringService, private readonly dataProviderService: DataProviderService, - private readonly exchangeRateDataService: ExchangeRateDataService, - private readonly orderService: OrderService + private readonly exchangeRateDataService: ExchangeRateDataService ) {} @OnEvent(AssetProfileChangedEvent.getName()) - public async handleAssetProfileChanged(event: AssetProfileChangedEvent) { + public handleAssetProfileChanged(event: AssetProfileChangedEvent) { + const currency = event.getCurrency(); + const dataSource = event.getDataSource(); + const symbol = event.getSymbol(); + + const key = getAssetProfileIdentifier({ + dataSource, + symbol + }); + + const existingTimer = this.debounceTimers.get(key); + + if (existingTimer) { + clearTimeout(existingTimer); + } + + this.debounceTimers.set( + key, + setTimeout(() => { + this.debounceTimers.delete(key); + + void this.processAssetProfileChanged({ + currency, + dataSource, + symbol + }); + }, AssetProfileChangedListener.DEBOUNCE_DELAY) + ); + } + + private async processAssetProfileChanged({ + currency, + dataSource, + symbol + }: { + currency: string; + dataSource: DataSource; + symbol: string; + }) { Logger.log( - `Asset profile of ${event.data.symbol} (${event.data.dataSource}) has changed`, + `Asset profile of ${symbol} (${dataSource}) has changed`, 'AssetProfileChangedListener' ); @@ -31,16 +76,16 @@ export class AssetProfileChangedListener { this.configurationService.get( 'ENABLE_FEATURE_GATHER_NEW_EXCHANGE_RATES' ) === false || - event.data.currency === DEFAULT_CURRENCY + currency === DEFAULT_CURRENCY ) { return; } const existingCurrencies = this.exchangeRateDataService.getCurrencies(); - if (!existingCurrencies.includes(event.data.currency)) { + if (!existingCurrencies.includes(currency)) { Logger.log( - `New currency ${event.data.currency} has been detected`, + `New currency ${currency} has been detected`, 'AssetProfileChangedListener' ); @@ -48,13 +93,13 @@ export class AssetProfileChangedListener { } const { dateOfFirstActivity } = - await this.orderService.getStatisticsByCurrency(event.data.currency); + await this.activitiesService.getStatisticsByCurrency(currency); if (dateOfFirstActivity) { await this.dataGatheringService.gatherSymbol({ dataSource: this.dataProviderService.getDataSourceForExchangeRates(), date: dateOfFirstActivity, - symbol: `${DEFAULT_CURRENCY}${event.data.currency}` + symbol: `${DEFAULT_CURRENCY}${currency}` }); } } diff --git a/apps/api/src/events/events.module.ts b/apps/api/src/events/events.module.ts index ece67ebe0..772766945 100644 --- a/apps/api/src/events/events.module.ts +++ b/apps/api/src/events/events.module.ts @@ -1,4 +1,4 @@ -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; import { ConfigurationModule } from '@ghostfolio/api/services/configuration/configuration.module'; import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module'; @@ -12,11 +12,11 @@ import { PortfolioChangedListener } from './portfolio-changed.listener'; @Module({ imports: [ + ActivitiesModule, ConfigurationModule, DataGatheringModule, DataProviderModule, ExchangeRateDataModule, - OrderModule, RedisCacheModule ], providers: [AssetProfileChangedListener, PortfolioChangedListener] diff --git a/apps/api/src/events/portfolio-changed.listener.ts b/apps/api/src/events/portfolio-changed.listener.ts index d12b9558d..f8e2a9229 100644 --- a/apps/api/src/events/portfolio-changed.listener.ts +++ b/apps/api/src/events/portfolio-changed.listener.ts @@ -2,22 +2,44 @@ import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.s import { Injectable, Logger } from '@nestjs/common'; import { OnEvent } from '@nestjs/event-emitter'; +import ms from 'ms'; import { PortfolioChangedEvent } from './portfolio-changed.event'; @Injectable() export class PortfolioChangedListener { + private static readonly DEBOUNCE_DELAY = ms('5 seconds'); + + private debounceTimers = new Map(); + public constructor(private readonly redisCacheService: RedisCacheService) {} @OnEvent(PortfolioChangedEvent.getName()) handlePortfolioChangedEvent(event: PortfolioChangedEvent) { + const userId = event.getUserId(); + + const existingTimer = this.debounceTimers.get(userId); + + if (existingTimer) { + clearTimeout(existingTimer); + } + + this.debounceTimers.set( + userId, + setTimeout(() => { + this.debounceTimers.delete(userId); + + void this.processPortfolioChanged({ userId }); + }, PortfolioChangedListener.DEBOUNCE_DELAY) + ); + } + + private async processPortfolioChanged({ userId }: { userId: string }) { Logger.log( - `Portfolio of user '${event.getUserId()}' has changed`, + `Portfolio of user '${userId}' has changed`, 'PortfolioChangedListener' ); - this.redisCacheService.removePortfolioSnapshotsByUserId({ - userId: event.getUserId() - }); + await this.redisCacheService.removePortfolioSnapshotsByUserId({ userId }); } } diff --git a/apps/api/src/helper/object.helper.spec.ts b/apps/api/src/helper/object.helper.spec.ts index e1ec81b8f..ba8760c70 100644 --- a/apps/api/src/helper/object.helper.spec.ts +++ b/apps/api/src/helper/object.helper.spec.ts @@ -1,4 +1,6 @@ -import { query, redactAttributes } from './object.helper'; +import { DEFAULT_REDACTED_PATHS } from '@ghostfolio/common/config'; + +import { query, redactPaths } from './object.helper'; describe('query', () => { it('should get market price from stock API response', () => { @@ -22,46 +24,38 @@ describe('query', () => { describe('redactAttributes', () => { it('should redact provided attributes', () => { - expect(redactAttributes({ object: {}, options: [] })).toStrictEqual({}); + expect(redactPaths({ object: {}, paths: [] })).toStrictEqual({}); - expect( - redactAttributes({ object: { value: 1000 }, options: [] }) - ).toStrictEqual({ value: 1000 }); + expect(redactPaths({ object: { value: 1000 }, paths: [] })).toStrictEqual({ + value: 1000 + }); expect( - redactAttributes({ + redactPaths({ object: { value: 1000 }, - options: [{ attribute: 'value', valueMap: { '*': null } }] + paths: ['value'] }) ).toStrictEqual({ value: null }); expect( - redactAttributes({ + redactPaths({ object: { value: 'abc' }, - options: [{ attribute: 'value', valueMap: { abc: 'xyz' } }] + paths: ['value'], + valueMap: { abc: 'xyz' } }) ).toStrictEqual({ value: 'xyz' }); expect( - redactAttributes({ + redactPaths({ object: { data: [{ value: 'a' }, { value: 'b' }] }, - options: [{ attribute: 'value', valueMap: { a: 1, b: 2 } }] + paths: ['data[*].value'], + valueMap: { a: 1, b: 2 } }) ).toStrictEqual({ data: [{ value: 1 }, { value: 2 }] }); - expect( - redactAttributes({ - object: { value1: 'a', value2: 'b' }, - options: [ - { attribute: 'value1', valueMap: { a: 'x' } }, - { attribute: 'value2', valueMap: { '*': 'y' } } - ] - }) - ).toStrictEqual({ value1: 'x', value2: 'y' }); - console.time('redactAttributes execution time'); expect( - redactAttributes({ + redactPaths({ object: { accounts: { '2e937c05-657c-4de9-8fb3-0813a2245f26': { @@ -117,6 +111,7 @@ describe('redactAttributes', () => { hasError: false, holdings: { 'AAPL.US': { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -136,7 +131,6 @@ describe('redactAttributes', () => { marketPrice: 220.79, symbol: 'AAPL.US', tags: [], - transactionCount: 1, allocationInPercentage: 0.044900865255793135, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -169,6 +163,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.0694356974830054 }, 'ALV.DE': { + activitiesCount: 2, currency: 'EUR', markets: { UNKNOWN: 0, @@ -188,7 +183,6 @@ describe('redactAttributes', () => { marketPrice: 296.5, symbol: 'ALV.DE', tags: [], - transactionCount: 2, allocationInPercentage: 0.026912563036519527, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -216,6 +210,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.04161818652826481 }, AMZN: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -235,7 +230,6 @@ describe('redactAttributes', () => { marketPrice: 187.99, symbol: 'AMZN', tags: [], - transactionCount: 1, allocationInPercentage: 0.07646101417126275, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -268,6 +262,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.11824101426541227 }, bitcoin: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 36985.0332704, @@ -293,7 +288,6 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 1, allocationInPercentage: 0.15042891393226654, assetClass: 'LIQUIDITY', assetSubClass: 'CRYPTOCURRENCY', @@ -319,6 +313,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.232626620912395 }, BONDORA_GO_AND_GROW: { + activitiesCount: 5, currency: 'EUR', markets: { UNKNOWN: 2231.644722160232, @@ -344,7 +339,6 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 5, allocationInPercentage: 0.009076749759365777, assetClass: 'FIXED_INCOME', assetSubClass: 'BOND', @@ -370,6 +364,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.014036487867880205 }, FRANKLY95P: { + activitiesCount: 6, currency: 'CHF', markets: { UNKNOWN: 0, @@ -395,7 +390,6 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 6, allocationInPercentage: 0.09095764645669335, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -494,6 +488,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.14065892911313693 }, MSFT: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -513,7 +508,6 @@ describe('redactAttributes', () => { marketPrice: 428.02, symbol: 'MSFT', tags: [], - transactionCount: 1, allocationInPercentage: 0.05222646409742627, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -546,6 +540,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.08076416659271518 }, TSLA: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -565,7 +560,6 @@ describe('redactAttributes', () => { marketPrice: 260.46, symbol: 'TSLA', tags: [], - transactionCount: 1, allocationInPercentage: 0.1589050142378352, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -598,6 +592,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.2457342510950259 }, VTI: { + activitiesCount: 5, currency: 'USD', markets: { UNKNOWN: 0, @@ -617,7 +612,6 @@ describe('redactAttributes', () => { marketPrice: 282.05, symbol: 'VTI', tags: [], - transactionCount: 5, allocationInPercentage: 0.057358979326040366, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -770,6 +764,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.08870120238725339 }, 'VWRL.SW': { + activitiesCount: 5, currency: 'CHF', markets: { UNKNOWN: 0, @@ -789,7 +784,6 @@ describe('redactAttributes', () => { marketPrice: 117.62, symbol: 'VWRL.SW', tags: [], - transactionCount: 5, allocationInPercentage: 0.09386983901959013, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -1178,6 +1172,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.145162408515095 }, 'XDWD.DE': { + activitiesCount: 1, currency: 'EUR', markets: { UNKNOWN: 0, @@ -1197,7 +1192,6 @@ describe('redactAttributes', () => { marketPrice: 105.72, symbol: 'XDWD.DE', tags: [], - transactionCount: 1, allocationInPercentage: 0.03598477442100562, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -1456,6 +1450,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.055647656152211074 }, USD: { + activitiesCount: 0, currency: 'USD', allocationInPercentage: 0.20291717628620132, assetClass: 'LIQUIDITY', @@ -1478,7 +1473,6 @@ describe('redactAttributes', () => { sectors: [], symbol: 'USD', tags: [], - transactionCount: 0, valueInBaseCurrency: 49890, valueInPercentage: 0.3137956381563603 } @@ -1546,7 +1540,6 @@ describe('redactAttributes', () => { netPerformanceWithCurrencyEffect: null, totalBuy: null, totalSell: null, - committedFunds: null, currentValueInBaseCurrency: null, dividendInBaseCurrency: null, emergencyFund: null, @@ -1560,38 +1553,12 @@ describe('redactAttributes', () => { items: null, liabilities: null, totalInvestment: null, + totalInvestmentValueWithCurrencyEffect: null, totalValueInBaseCurrency: null, currentNetWorth: null } }, - options: [ - 'balance', - 'balanceInBaseCurrency', - 'comment', - 'convertedBalance', - 'dividendInBaseCurrency', - 'fee', - 'feeInBaseCurrency', - 'grossPerformance', - 'grossPerformanceWithCurrencyEffect', - 'investment', - 'netPerformance', - 'netPerformanceWithCurrencyEffect', - 'quantity', - 'symbolMapping', - 'totalBalanceInBaseCurrency', - 'totalValueInBaseCurrency', - 'unitPrice', - 'value', - 'valueInBaseCurrency' - ].map((attribute) => { - return { - attribute, - valueMap: { - '*': null - } - }; - }) + paths: DEFAULT_REDACTED_PATHS }) ).toStrictEqual({ accounts: { @@ -1648,6 +1615,7 @@ describe('redactAttributes', () => { hasError: false, holdings: { 'AAPL.US': { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -1667,7 +1635,6 @@ describe('redactAttributes', () => { marketPrice: 220.79, symbol: 'AAPL.US', tags: [], - transactionCount: 1, allocationInPercentage: 0.044900865255793135, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -1681,7 +1648,7 @@ describe('redactAttributes', () => { ], dataSource: 'EOD_HISTORICAL_DATA', dateOfFirstActivity: '2021-11-30T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.3183066634822068, grossPerformancePercentWithCurrencyEffect: 0.3183066634822068, @@ -1700,6 +1667,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.0694356974830054 }, 'ALV.DE': { + activitiesCount: 2, currency: 'EUR', markets: { UNKNOWN: 0, @@ -1719,7 +1687,6 @@ describe('redactAttributes', () => { marketPrice: 296.5, symbol: 'ALV.DE', tags: [], - transactionCount: 2, allocationInPercentage: 0.026912563036519527, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -1728,7 +1695,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2021-04-22T22:00:00.000Z', - dividend: 192, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.3719230057375532, grossPerformancePercentWithCurrencyEffect: 0.2650716044872953, @@ -1747,6 +1714,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.04161818652826481 }, AMZN: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -1766,7 +1734,6 @@ describe('redactAttributes', () => { marketPrice: 187.99, symbol: 'AMZN', tags: [], - transactionCount: 1, allocationInPercentage: 0.07646101417126275, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -1780,7 +1747,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2018-09-30T22:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.8594552890963852, grossPerformancePercentWithCurrencyEffect: 0.8594552890963852, @@ -1799,6 +1766,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.11824101426541227 }, bitcoin: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 36985.0332704, @@ -1824,14 +1792,13 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 1, allocationInPercentage: 0.15042891393226654, assetClass: 'LIQUIDITY', assetSubClass: 'CRYPTOCURRENCY', countries: [], dataSource: 'COINGECKO', dateOfFirstActivity: '2017-08-15T22:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 17.4925166352, grossPerformancePercentWithCurrencyEffect: 17.4925166352, @@ -1850,6 +1817,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.232626620912395 }, BONDORA_GO_AND_GROW: { + activitiesCount: 5, currency: 'EUR', markets: { UNKNOWN: 2231.644722160232, @@ -1875,14 +1843,13 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 5, allocationInPercentage: 0.009076749759365777, assetClass: 'FIXED_INCOME', assetSubClass: 'BOND', countries: [], dataSource: 'MANUAL', dateOfFirstActivity: '2021-01-31T23:00:00.000Z', - dividend: 11.45, + dividend: null, grossPerformance: null, grossPerformancePercent: 0, grossPerformancePercentWithCurrencyEffect: -0.06153834320225245, @@ -1901,6 +1868,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.014036487867880205 }, FRANKLY95P: { + activitiesCount: 6, currency: 'CHF', markets: { UNKNOWN: 0, @@ -1926,7 +1894,6 @@ describe('redactAttributes', () => { userId: null } ], - transactionCount: 6, allocationInPercentage: 0.09095764645669335, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -1986,7 +1953,7 @@ describe('redactAttributes', () => { ], dataSource: 'MANUAL', dateOfFirstActivity: '2021-03-31T22:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.27579517683678895, grossPerformancePercentWithCurrencyEffect: 0.458553421589667, @@ -2005,6 +1972,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.14065892911313693 }, MSFT: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -2024,7 +1992,6 @@ describe('redactAttributes', () => { marketPrice: 428.02, symbol: 'MSFT', tags: [], - transactionCount: 1, allocationInPercentage: 0.05222646409742627, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -2038,7 +2005,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2023-01-02T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.7865431171216295, grossPerformancePercentWithCurrencyEffect: 0.7865431171216295, @@ -2057,6 +2024,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.08076416659271518 }, TSLA: { + activitiesCount: 1, currency: 'USD', markets: { UNKNOWN: 0, @@ -2076,7 +2044,6 @@ describe('redactAttributes', () => { marketPrice: 260.46, symbol: 'TSLA', tags: [], - transactionCount: 1, allocationInPercentage: 0.1589050142378352, assetClass: 'EQUITY', assetSubClass: 'STOCK', @@ -2090,7 +2057,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2017-01-02T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 17.184314638161936, grossPerformancePercentWithCurrencyEffect: 17.184314638161936, @@ -2109,6 +2076,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.2457342510950259 }, VTI: { + activitiesCount: 5, currency: 'USD', markets: { UNKNOWN: 0, @@ -2128,7 +2096,6 @@ describe('redactAttributes', () => { marketPrice: 282.05, symbol: 'VTI', tags: [], - transactionCount: 5, allocationInPercentage: 0.057358979326040366, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -2172,7 +2139,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2019-02-28T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.8832083851170418, grossPerformancePercentWithCurrencyEffect: 0.8832083851170418, @@ -2281,6 +2248,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.08870120238725339 }, 'VWRL.SW': { + activitiesCount: 5, currency: 'CHF', markets: { UNKNOWN: 0, @@ -2300,7 +2268,6 @@ describe('redactAttributes', () => { marketPrice: 117.62, symbol: 'VWRL.SW', tags: [], - transactionCount: 5, allocationInPercentage: 0.09386983901959013, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -2567,7 +2534,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2018-02-28T23:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.3683200415015591, grossPerformancePercentWithCurrencyEffect: 0.5806366182968891, @@ -2681,6 +2648,7 @@ describe('redactAttributes', () => { valueInPercentage: 0.145162408515095 }, 'XDWD.DE': { + activitiesCount: 1, currency: 'EUR', markets: { UNKNOWN: 0, @@ -2700,7 +2668,6 @@ describe('redactAttributes', () => { marketPrice: 105.72, symbol: 'XDWD.DE', tags: [], - transactionCount: 1, allocationInPercentage: 0.03598477442100562, assetClass: 'EQUITY', assetSubClass: 'ETF', @@ -2846,7 +2813,7 @@ describe('redactAttributes', () => { ], dataSource: 'YAHOO', dateOfFirstActivity: '2021-08-18T22:00:00.000Z', - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0.3474381850624522, grossPerformancePercentWithCurrencyEffect: 0.28744846894552306, @@ -2959,12 +2926,13 @@ describe('redactAttributes', () => { valueInPercentage: 0.055647656152211074 }, USD: { + activitiesCount: 0, currency: 'USD', allocationInPercentage: 0.20291717628620132, assetClass: 'LIQUIDITY', assetSubClass: 'CASH', countries: [], - dividend: 0, + dividend: null, grossPerformance: null, grossPerformancePercent: 0, grossPerformancePercentWithCurrencyEffect: 0, @@ -2981,7 +2949,6 @@ describe('redactAttributes', () => { sectors: [], symbol: 'USD', tags: [], - transactionCount: 0, valueInBaseCurrency: null, valueInPercentage: 0.3137956381563603 } @@ -3049,7 +3016,6 @@ describe('redactAttributes', () => { netPerformanceWithCurrencyEffect: null, totalBuy: null, totalSell: null, - committedFunds: null, currentValueInBaseCurrency: null, dividendInBaseCurrency: null, emergencyFund: null, @@ -3063,6 +3029,7 @@ describe('redactAttributes', () => { items: null, liabilities: null, totalInvestment: null, + totalInvestmentValueWithCurrencyEffect: null, totalValueInBaseCurrency: null, currentNetWorth: null } diff --git a/apps/api/src/helper/object.helper.ts b/apps/api/src/helper/object.helper.ts index 6bb6579d2..350d5fe04 100644 --- a/apps/api/src/helper/object.helper.ts +++ b/apps/api/src/helper/object.helper.ts @@ -1,6 +1,6 @@ -import { Big } from 'big.js'; +import fastRedact from 'fast-redact'; import jsonpath from 'jsonpath'; -import { cloneDeep, isArray, isObject } from 'lodash'; +import { cloneDeep, isObject } from 'lodash'; export function hasNotDefinedValuesInObject(aObject: Object): boolean { for (const key in aObject) { @@ -42,60 +42,29 @@ export function query({ return jsonpath.query(object, pathExpression); } -export function redactAttributes({ - isFirstRun = true, +export function redactPaths({ object, - options + paths, + valueMap }: { - isFirstRun?: boolean; object: any; - options: { attribute: string; valueMap: { [key: string]: any } }[]; + paths: fastRedact.RedactOptions['paths']; + valueMap?: { [key: string]: any }; }): any { - if (!object || !options?.length) { - return object; - } - - // Create deep clone - const redactedObject = isFirstRun - ? JSON.parse(JSON.stringify(object)) - : object; - - for (const option of options) { - if (redactedObject.hasOwnProperty(option.attribute)) { - if (option.valueMap['*'] || option.valueMap['*'] === null) { - redactedObject[option.attribute] = option.valueMap['*']; - } else if (option.valueMap[redactedObject[option.attribute]]) { - redactedObject[option.attribute] = - option.valueMap[redactedObject[option.attribute]]; - } - } else { - // If the attribute is not present on the current object, - // check if it exists on any nested objects - for (const property in redactedObject) { - if (isArray(redactedObject[property])) { - redactedObject[property] = redactedObject[property].map( - (currentObject) => { - return redactAttributes({ - options, - isFirstRun: false, - object: currentObject - }); - } - ); - } else if ( - isObject(redactedObject[property]) && - !(redactedObject[property] instanceof Big) - ) { - // Recursively call the function on the nested object - redactedObject[property] = redactAttributes({ - options, - isFirstRun: false, - object: redactedObject[property] - }); + const redact = fastRedact({ + paths, + censor: (value) => { + if (valueMap) { + if (valueMap[value]) { + return valueMap[value]; + } else { + return value; } + } else { + return null; } } - } + }); - return redactedObject; + return JSON.parse(redact(object)); } diff --git a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts index 5ecf7c48d..60b994cac 100644 --- a/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts +++ b/apps/api/src/interceptors/redact-values-in-response/redact-values-in-response.interceptor.ts @@ -1,5 +1,8 @@ -import { redactAttributes } from '@ghostfolio/api/helper/object.helper'; -import { HEADER_KEY_IMPERSONATION } from '@ghostfolio/common/config'; +import { redactPaths } from '@ghostfolio/api/helper/object.helper'; +import { + DEFAULT_REDACTED_PATHS, + HEADER_KEY_IMPERSONATION +} from '@ghostfolio/common/config'; import { hasReadRestrictedAccessPermission, isRestrictedView @@ -39,40 +42,9 @@ export class RedactValuesInResponseInterceptor implements NestInterceptor< }) || isRestrictedView(user) ) { - data = redactAttributes({ + data = redactPaths({ object: data, - options: [ - 'balance', - 'balanceInBaseCurrency', - 'comment', - 'convertedBalance', - 'dividendInBaseCurrency', - 'fee', - 'feeInBaseCurrency', - 'grossPerformance', - 'grossPerformanceWithCurrencyEffect', - 'interestInBaseCurrency', - 'investment', - 'netPerformance', - 'netPerformanceWithCurrencyEffect', - 'quantity', - 'symbolMapping', - 'totalBalanceInBaseCurrency', - 'totalDividendInBaseCurrency', - 'totalInterestInBaseCurrency', - 'totalValueInBaseCurrency', - 'unitPrice', - 'unitPriceInAssetProfileCurrency', - 'value', - 'valueInBaseCurrency' - ].map((attribute) => { - return { - attribute, - valueMap: { - '*': null - } - }; - }) + paths: DEFAULT_REDACTED_PATHS }); } 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 9af256671..57643f76c 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 @@ -1,4 +1,4 @@ -import { redactAttributes } from '@ghostfolio/api/helper/object.helper'; +import { redactPaths } from '@ghostfolio/api/helper/object.helper'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { encodeDataSource } from '@ghostfolio/common/helper'; @@ -58,13 +58,21 @@ export class TransformDataSourceInResponseInterceptor< } } - data = redactAttributes({ + data = redactPaths({ + valueMap, object: data, - options: [ - { - valueMap, - attribute: 'dataSource' - } + paths: [ + 'activities[*].dataSource', + 'activities[*].SymbolProfile.dataSource', + 'benchmarks[*].dataSource', + 'errors[*].dataSource', + 'fearAndGreedIndex.CRYPTOCURRENCIES.dataSource', + 'fearAndGreedIndex.STOCKS.dataSource', + 'holdings[*].assetProfile.dataSource', + 'holdings[*].dataSource', + 'items[*].dataSource', + 'SymbolProfile.dataSource', + 'watchlist[*].dataSource' ] }); } diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index a8de3dc5e..f08a09a83 100644 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,4 +1,5 @@ import { + BULL_BOARD_ROUTE, DEFAULT_HOST, DEFAULT_PORT, STORYBOOK_PATH, @@ -14,6 +15,7 @@ import { import { ConfigService } from '@nestjs/config'; import { NestFactory } from '@nestjs/core'; import type { NestExpressApplication } from '@nestjs/platform-express'; +import cookieParser from 'cookie-parser'; import { NextFunction, Request, Response } from 'express'; import helmet from 'helmet'; @@ -46,6 +48,7 @@ async function bootstrap() { }); app.setGlobalPrefix('api', { exclude: [ + `${BULL_BOARD_ROUTE.substring(1)}{/*wildcard}`, 'sitemap.xml', ...SUPPORTED_LANGUAGE_CODES.map((languageCode) => { // Exclude language-specific routes with an optional wildcard @@ -53,6 +56,7 @@ async function bootstrap() { }) ] }); + app.useGlobalPipes( new ValidationPipe({ forbidNonWhitelisted: true, @@ -64,6 +68,8 @@ async function bootstrap() { // Support 10mb csv/json files for importing activities app.useBodyParser('json', { limit: '10mb' }); + app.use(cookieParser()); + if (configService.get('ENABLE_FEATURE_SUBSCRIPTION') === 'true') { app.use((req: Request, res: Response, next: NextFunction) => { if (req.path.startsWith(STORYBOOK_PATH)) { diff --git a/apps/api/src/middlewares/bull-board-auth.middleware.ts b/apps/api/src/middlewares/bull-board-auth.middleware.ts new file mode 100644 index 000000000..432deb974 --- /dev/null +++ b/apps/api/src/middlewares/bull-board-auth.middleware.ts @@ -0,0 +1,28 @@ +import { BULL_BOARD_COOKIE_NAME } from '@ghostfolio/common/config'; +import { hasPermission, permissions } from '@ghostfolio/common/permissions'; + +import { ForbiddenException, Injectable, NestMiddleware } from '@nestjs/common'; +import { NextFunction, Request, Response } from 'express'; +import passport from 'passport'; + +@Injectable() +export class BullBoardAuthMiddleware implements NestMiddleware { + public use(req: Request, res: Response, next: NextFunction) { + const token = req.cookies?.[BULL_BOARD_COOKIE_NAME]; + + if (token) { + req.headers.authorization = `Bearer ${token}`; + } + + passport.authenticate('jwt', { session: false }, (error, user) => { + if ( + error || + !hasPermission(user?.permissions, permissions.accessAdminControl) + ) { + next(new ForbiddenException()); + } else { + next(); + } + })(req, res, next); + } +} diff --git a/apps/api/src/models/rule.ts b/apps/api/src/models/rule.ts index 9c27e0018..622375b5b 100644 --- a/apps/api/src/models/rule.ts +++ b/apps/api/src/models/rule.ts @@ -57,7 +57,7 @@ export abstract class Rule implements RuleInterface { previousValue + this.exchangeRateDataService.toCurrency( new Big(currentValue.quantity) - .mul(currentValue.marketPrice) + .mul(currentValue.marketPrice ?? 0) .toNumber(), currentValue.currency, baseCurrency diff --git a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts b/apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts similarity index 78% rename from apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts rename to apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts index cb85a73ba..07bf5fa2c 100644 --- a/apps/api/src/models/rules/fees/fee-ratio-initial-investment.ts +++ b/apps/api/src/models/rules/fees/fee-ratio-total-investment-volume.ts @@ -3,35 +3,36 @@ import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate- import { I18nService } from '@ghostfolio/api/services/i18n/i18n.service'; import { RuleSettings, UserSettings } from '@ghostfolio/common/interfaces'; -export class FeeRatioInitialInvestment extends Rule { +export class FeeRatioTotalInvestmentVolume extends Rule { private fees: number; - private totalInvestment: number; + private totalInvestmentVolumeInBaseCurrency: number; public constructor( protected exchangeRateDataService: ExchangeRateDataService, private i18nService: I18nService, languageCode: string, - totalInvestment: number, + totalInvestmentVolumeInBaseCurrency: number, fees: number ) { super(exchangeRateDataService, { languageCode, - key: FeeRatioInitialInvestment.name + key: FeeRatioTotalInvestmentVolume.name }); this.fees = fees; - this.totalInvestment = totalInvestment; + this.totalInvestmentVolumeInBaseCurrency = + totalInvestmentVolumeInBaseCurrency; } public evaluate(ruleSettings: Settings) { - const feeRatio = this.totalInvestment - ? this.fees / this.totalInvestment + const feeRatio = this.totalInvestmentVolumeInBaseCurrency + ? this.fees / this.totalInvestmentVolumeInBaseCurrency : 0; if (feeRatio > ruleSettings.thresholdMax) { return { evaluation: this.i18nService.getTranslation({ - id: 'rule.feeRatioInitialInvestment.false', + id: 'rule.feeRatioTotalInvestmentVolume.false', languageCode: this.getLanguageCode(), placeholders: { feeRatio: (ruleSettings.thresholdMax * 100).toFixed(2), @@ -44,7 +45,7 @@ export class FeeRatioInitialInvestment extends Rule { return { evaluation: this.i18nService.getTranslation({ - id: 'rule.feeRatioInitialInvestment.true', + id: 'rule.feeRatioTotalInvestmentVolume.true', languageCode: this.getLanguageCode(), placeholders: { feeRatio: (feeRatio * 100).toPrecision(3), @@ -76,7 +77,7 @@ export class FeeRatioInitialInvestment extends Rule { public getName() { return this.i18nService.getTranslation({ - id: 'rule.feeRatioInitialInvestment', + id: 'rule.feeRatioTotalInvestmentVolume', languageCode: this.getLanguageCode() }); } diff --git a/apps/api/src/services/configuration/configuration.service.ts b/apps/api/src/services/configuration/configuration.service.ts index 5f9d1055d..ad8e84a99 100644 --- a/apps/api/src/services/configuration/configuration.service.ts +++ b/apps/api/src/services/configuration/configuration.service.ts @@ -30,6 +30,7 @@ export class ConfigurationService { API_KEY_FINANCIAL_MODELING_PREP: str({ default: '' }), API_KEY_OPEN_FIGI: str({ default: '' }), API_KEY_RAPID_API: str({ default: '' }), + BULL_BOARD_IS_READ_ONLY: bool({ default: true }), CACHE_QUOTES_TTL: num({ default: ms('1 minute') }), CACHE_TTL: num({ default: CACHE_TTL_NO_CACHE }), DATA_SOURCE_EXCHANGE_RATES: str({ default: DataSource.YAHOO }), @@ -43,6 +44,7 @@ export class ConfigurationService { ENABLE_FEATURE_AUTH_GOOGLE: bool({ default: false }), ENABLE_FEATURE_AUTH_OIDC: bool({ default: false }), ENABLE_FEATURE_AUTH_TOKEN: bool({ default: true }), + ENABLE_FEATURE_BULL_BOARD: bool({ default: false }), ENABLE_FEATURE_FEAR_AND_GREED_INDEX: bool({ default: false }), ENABLE_FEATURE_GATHER_NEW_EXCHANGE_RATES: bool({ default: true }), ENABLE_FEATURE_READ_ONLY_MODE: bool({ default: false }), diff --git a/apps/api/src/services/cryptocurrency/cryptocurrency.module.ts b/apps/api/src/services/cryptocurrency/cryptocurrency.module.ts index 8820205eb..e882f4da5 100644 --- a/apps/api/src/services/cryptocurrency/cryptocurrency.module.ts +++ b/apps/api/src/services/cryptocurrency/cryptocurrency.module.ts @@ -1,9 +1,12 @@ +import { PropertyModule } from '@ghostfolio/api/services/property/property.module'; + import { Module } from '@nestjs/common'; import { CryptocurrencyService } from './cryptocurrency.service'; @Module({ - providers: [CryptocurrencyService], - exports: [CryptocurrencyService] + exports: [CryptocurrencyService], + imports: [PropertyModule], + providers: [CryptocurrencyService] }) export class CryptocurrencyModule {} diff --git a/apps/api/src/services/cryptocurrency/cryptocurrency.service.ts b/apps/api/src/services/cryptocurrency/cryptocurrency.service.ts index b814fc186..933029ea2 100644 --- a/apps/api/src/services/cryptocurrency/cryptocurrency.service.ts +++ b/apps/api/src/services/cryptocurrency/cryptocurrency.service.ts @@ -1,31 +1,39 @@ -import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; +import { PropertyService } from '@ghostfolio/api/services/property/property.service'; +import { + DEFAULT_CURRENCY, + PROPERTY_CUSTOM_CRYPTOCURRENCIES +} from '@ghostfolio/common/config'; -import { Injectable } from '@nestjs/common'; +import { Injectable, OnModuleInit } from '@nestjs/common'; const cryptocurrencies = require('../../assets/cryptocurrencies/cryptocurrencies.json'); const customCryptocurrencies = require('../../assets/cryptocurrencies/custom.json'); @Injectable() -export class CryptocurrencyService { +export class CryptocurrencyService implements OnModuleInit { private combinedCryptocurrencies: string[]; + public constructor(private readonly propertyService: PropertyService) {} + + public async onModuleInit() { + const customCryptocurrenciesFromDatabase = + await this.propertyService.getByKey>( + PROPERTY_CUSTOM_CRYPTOCURRENCIES + ); + + this.combinedCryptocurrencies = [ + ...Object.keys(cryptocurrencies), + ...Object.keys(customCryptocurrencies), + ...Object.keys(customCryptocurrenciesFromDatabase ?? {}) + ]; + } + public isCryptocurrency(aSymbol = '') { const cryptocurrencySymbol = aSymbol.substring(0, aSymbol.length - 3); return ( aSymbol.endsWith(DEFAULT_CURRENCY) && - this.getCryptocurrencies().includes(cryptocurrencySymbol) + this.combinedCryptocurrencies.includes(cryptocurrencySymbol) ); } - - private getCryptocurrencies() { - if (!this.combinedCryptocurrencies) { - this.combinedCryptocurrencies = [ - ...Object.keys(cryptocurrencies), - ...Object.keys(customCryptocurrencies) - ]; - } - - return this.combinedCryptocurrencies; - } } 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 c37a9fe3e..9335d86d0 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 @@ -29,7 +29,7 @@ describe('YahooFinanceDataEnhancerService', () => { let yahooFinanceDataEnhancerService: YahooFinanceDataEnhancerService; beforeAll(async () => { - cryptocurrencyService = new CryptocurrencyService(); + cryptocurrencyService = new CryptocurrencyService(null); yahooFinanceDataEnhancerService = new YahooFinanceDataEnhancerService( 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 65bcd6c06..72136dc04 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 @@ -135,10 +135,10 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { shortName, symbol }: { - longName: Price['longName']; - quoteType: Price['quoteType']; - shortName: Price['shortName']; - symbol: Price['symbol']; + longName?: Price['longName']; + quoteType?: Price['quoteType']; + shortName?: Price['shortName']; + symbol?: Price['symbol']; }) { let name = longName; @@ -206,17 +206,28 @@ export class YahooFinanceDataEnhancerService implements DataEnhancerInterface { ); if (['ETF', 'MUTUALFUND'].includes(assetSubClass)) { - response.sectors = []; - - for (const sectorWeighting of assetProfile.topHoldings - ?.sectorWeightings ?? []) { - for (const [sector, weight] of Object.entries(sectorWeighting)) { - response.sectors.push({ + response.holdings = + assetProfile.topHoldings?.holdings + ?.filter(({ holdingName }) => { + return !holdingName?.includes('ETF'); + }) + ?.map(({ holdingName, holdingPercent }) => { + return { + name: this.formatName({ longName: holdingName }), + weight: holdingPercent + }; + }) ?? []; + + response.sectors = ( + assetProfile.topHoldings?.sectorWeightings ?? [] + ).flatMap((sectorWeighting) => { + return Object.entries(sectorWeighting).map(([sector, weight]) => { + return { name: this.parseSector(sector), weight: weight as number - }); - } - } + }; + }); + }); } else if ( assetSubClass === 'STOCK' && assetProfile.summaryProfile?.country diff --git a/apps/api/src/services/data-provider/data-provider.service.ts b/apps/api/src/services/data-provider/data-provider.service.ts index 5a088c0e4..a6b12cce2 100644 --- a/apps/api/src/services/data-provider/data-provider.service.ts +++ b/apps/api/src/services/data-provider/data-provider.service.ts @@ -1,3 +1,4 @@ +import { ImportDataDto } from '@ghostfolio/api/app/import/import-data.dto'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { DataProviderInterface } from '@ghostfolio/api/services/data-provider/interfaces/data-provider.interface'; @@ -10,8 +11,10 @@ import { PROPERTY_API_KEY_GHOSTFOLIO, PROPERTY_DATA_SOURCE_MAPPING } from '@ghostfolio/common/config'; +import { CreateOrderDto } from '@ghostfolio/common/dtos'; import { DATE_FORMAT, + getAssetProfileIdentifier, getCurrencyFromSymbol, getStartOfUtcDate, isCurrency, @@ -27,7 +30,7 @@ import { import type { Granularity, UserWithSettings } from '@ghostfolio/common/types'; import { Inject, Injectable, Logger, OnModuleInit } from '@nestjs/common'; -import { DataSource, MarketData, SymbolProfile } from '@prisma/client'; +import { DataSource, MarketData, Prisma, SymbolProfile } from '@prisma/client'; import { Big } from 'big.js'; import { eachDayOfInterval, format, isValid } from 'date-fns'; import { groupBy, isEmpty, isNumber, uniqWith } from 'lodash'; @@ -185,6 +188,125 @@ export class DataProviderService implements OnModuleInit { return dataSources.sort(); } + public async validateActivities({ + activitiesDto, + assetProfilesWithMarketDataDto, + maxActivitiesToImport, + user + }: { + activitiesDto: Pick< + Partial, + 'currency' | 'dataSource' | 'symbol' | 'type' + >[]; + assetProfilesWithMarketDataDto?: ImportDataDto['assetProfiles']; + maxActivitiesToImport: number; + user: UserWithSettings; + }) { + if (activitiesDto?.length > maxActivitiesToImport) { + throw new Error(`Too many activities (${maxActivitiesToImport} at most)`); + } + + const assetProfiles: { + [assetProfileIdentifier: string]: Partial; + } = {}; + + const dataSources = await this.getDataSources(); + + for (const [ + index, + { currency, dataSource, symbol, type } + ] of activitiesDto.entries()) { + const activityPath = + maxActivitiesToImport === 1 ? 'activity' : `activities.${index}`; + + if (!dataSources.includes(dataSource)) { + throw new Error( + `${activityPath}.dataSource ("${dataSource}") is not valid` + ); + } + + if ( + this.configurationService.get('ENABLE_FEATURE_SUBSCRIPTION') && + user.subscription.type === 'Basic' + ) { + const dataProvider = this.getDataProvider(DataSource[dataSource]); + + if (dataProvider.getDataProviderInfo().isPremium) { + throw new Error( + `${activityPath}.dataSource ("${dataSource}") is not valid` + ); + } + } + + const assetProfileIdentifier = getAssetProfileIdentifier({ + dataSource, + symbol + }); + + if (!assetProfiles[assetProfileIdentifier]) { + if ( + (dataSource === DataSource.MANUAL && type === 'BUY') || + ['FEE', 'INTEREST', 'LIABILITY'].includes(type) + ) { + const assetProfileInImport = assetProfilesWithMarketDataDto?.find( + (assetProfile) => { + return ( + assetProfile.dataSource === dataSource && + assetProfile.symbol === symbol + ); + } + ); + + assetProfiles[assetProfileIdentifier] = { + currency, + dataSource, + symbol, + name: assetProfileInImport?.name ?? symbol + }; + + continue; + } + + let assetProfile: Partial = { currency }; + + try { + assetProfile = ( + await this.getAssetProfiles([ + { + dataSource, + symbol + } + ]) + )?.[symbol]; + } catch {} + + if (!assetProfile?.name) { + const assetProfileInImport = assetProfilesWithMarketDataDto?.find( + (profile) => { + return ( + profile.dataSource === dataSource && profile.symbol === symbol + ); + } + ); + + if (assetProfileInImport) { + Object.assign(assetProfile, assetProfileInImport); + } + } + + if (!assetProfile?.name) { + throw new Error( + `activities.${index}.symbol ("${symbol}") is not valid for the specified data source ("${dataSource}")` + ); + } + + assetProfiles[assetProfileIdentifier] = assetProfile; + } + } + + return assetProfiles; + } + public async getDividends({ dataSource, from, @@ -225,36 +347,35 @@ export class DataProviderService implements OnModuleInit { const granularityQuery = aGranularity === 'month' - ? `AND (date_part('day', date) = 1 OR date >= TIMESTAMP 'yesterday')` - : ''; + ? Prisma.sql`AND (date_part('day', date) = 1 OR date >= TIMESTAMP 'yesterday')` + : Prisma.empty; const rangeQuery = from && to - ? `AND date >= '${format(from, DATE_FORMAT)}' AND date <= '${format( + ? Prisma.sql`AND date >= ${format(from, DATE_FORMAT)}::timestamp AND date <= ${format( to, DATE_FORMAT - )}'` - : ''; + )}::timestamp` + : Prisma.empty; const dataSources = aItems.map(({ dataSource }) => { return dataSource; }); + const symbols = aItems.map(({ symbol }) => { return symbol; }); try { - const queryRaw = ` - SELECT * - FROM "MarketData" - WHERE "dataSource" IN ('${dataSources.join(`','`)}') - AND "symbol" IN ('${symbols.join( - `','` - )}') ${granularityQuery} ${rangeQuery} - ORDER BY date;`; - - const marketDataByGranularity: MarketData[] = - await this.prismaService.$queryRawUnsafe(queryRaw); + const marketDataByGranularity: MarketData[] = await this.prismaService + .$queryRaw` + SELECT * + FROM "MarketData" + WHERE "dataSource"::text IN (${Prisma.join(dataSources)}) + AND "symbol" IN (${Prisma.join(symbols)}) + ${granularityQuery} + ${rangeQuery} + ORDER BY date;`; response = marketDataByGranularity.reduce((r, marketData) => { const { date, marketPrice, symbol } = marketData; diff --git a/apps/api/src/services/data-provider/manual/manual.service.ts b/apps/api/src/services/data-provider/manual/manual.service.ts index 7392f0914..51e65e631 100644 --- a/apps/api/src/services/data-provider/manual/manual.service.ts +++ b/apps/api/src/services/data-provider/manual/manual.service.ts @@ -105,7 +105,10 @@ export class ManualService implements DataProviderInterface { return {}; } - const value = await this.scrape(symbolProfile.scraperConfiguration); + const value = await this.scrape({ + symbol, + scraperConfiguration: symbolProfile.scraperConfiguration + }); return { [symbol]: { @@ -170,7 +173,10 @@ export class ManualService implements DataProviderInterface { symbolProfilesWithScraperConfigurationAndInstantMode.map( async ({ scraperConfiguration, symbol }) => { try { - const marketPrice = await this.scrape(scraperConfiguration); + const marketPrice = await this.scrape({ + scraperConfiguration, + symbol + }); return { marketPrice, symbol }; } catch (error) { Logger.error( @@ -267,13 +273,23 @@ export class ManualService implements DataProviderInterface { }; } - public async test(scraperConfiguration: ScraperConfiguration) { - return this.scrape(scraperConfiguration); + public async test({ + scraperConfiguration, + symbol + }: { + scraperConfiguration: ScraperConfiguration; + symbol: string; + }) { + return this.scrape({ scraperConfiguration, symbol }); } - private async scrape( - scraperConfiguration: ScraperConfiguration - ): Promise { + private async scrape({ + scraperConfiguration, + symbol + }: { + scraperConfiguration: ScraperConfiguration; + symbol: string; + }): Promise { let locale = scraperConfiguration.locale; const response = await fetch(scraperConfiguration.url, { @@ -283,6 +299,12 @@ export class ManualService implements DataProviderInterface { ) }); + if (!response.ok) { + throw new Error( + `Failed to scrape the market price for ${symbol} (${this.getName()}): ${response.status} ${response.statusText} at ${scraperConfiguration.url}` + ); + } + let value: string; if (response.headers.get('content-type')?.includes('application/json')) { diff --git a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.mock.ts b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.mock.ts index 857c1b5a5..742be36b4 100644 --- a/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.mock.ts +++ b/apps/api/src/services/exchange-rate-data/exchange-rate-data.service.mock.ts @@ -1,5 +1,7 @@ -export const ExchangeRateDataServiceMock = { - getExchangeRatesByCurrency: ({ targetCurrency }): Promise => { +import { ExchangeRateDataService } from './exchange-rate-data.service'; + +export const ExchangeRateDataServiceMock: Partial = { + getExchangeRatesByCurrency: ({ targetCurrency }) => { if (targetCurrency === 'CHF') { return Promise.resolve({ CHFCHF: { diff --git a/apps/api/src/services/i18n/i18n.service.ts b/apps/api/src/services/i18n/i18n.service.ts index cf340d7c6..1cdb811a9 100644 --- a/apps/api/src/services/i18n/i18n.service.ts +++ b/apps/api/src/services/i18n/i18n.service.ts @@ -1,16 +1,16 @@ import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import * as cheerio from 'cheerio'; import { readFileSync, readdirSync } from 'node:fs'; import { join } from 'node:path'; @Injectable() -export class I18nService { +export class I18nService implements OnModuleInit { private localesPath = join(__dirname, 'assets', 'locales'); private translations: { [locale: string]: cheerio.CheerioAPI } = {}; - public constructor() { + public onModuleInit() { this.loadFiles(); } diff --git a/apps/api/src/services/interfaces/environment.interface.ts b/apps/api/src/services/interfaces/environment.interface.ts index 57c58898e..9664ae144 100644 --- a/apps/api/src/services/interfaces/environment.interface.ts +++ b/apps/api/src/services/interfaces/environment.interface.ts @@ -10,6 +10,7 @@ export interface Environment extends CleanedEnvAccessors { API_KEY_FINANCIAL_MODELING_PREP: string; API_KEY_OPEN_FIGI: string; API_KEY_RAPID_API: string; + BULL_BOARD_IS_READ_ONLY: boolean; CACHE_QUOTES_TTL: number; CACHE_TTL: number; DATA_SOURCE_EXCHANGE_RATES: string; @@ -19,6 +20,7 @@ export interface Environment extends CleanedEnvAccessors { ENABLE_FEATURE_AUTH_GOOGLE: boolean; ENABLE_FEATURE_AUTH_OIDC: boolean; ENABLE_FEATURE_AUTH_TOKEN: boolean; + ENABLE_FEATURE_BULL_BOARD: boolean; ENABLE_FEATURE_FEAR_AND_GREED_INDEX: boolean; ENABLE_FEATURE_GATHER_NEW_EXCHANGE_RATES: boolean; ENABLE_FEATURE_READ_ONLY_MODE: boolean; diff --git a/apps/api/src/services/queues/data-gathering/data-gathering.module.ts b/apps/api/src/services/queues/data-gathering/data-gathering.module.ts index b51823476..f251c8d0c 100644 --- a/apps/api/src/services/queues/data-gathering/data-gathering.module.ts +++ b/apps/api/src/services/queues/data-gathering/data-gathering.module.ts @@ -9,6 +9,8 @@ import { DataGatheringService } from '@ghostfolio/api/services/queues/data-gathe import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile/symbol-profile.module'; import { DATA_GATHERING_QUEUE } from '@ghostfolio/common/config'; +import { BullAdapter } from '@bull-board/api/bullAdapter'; +import { BullBoardModule } from '@bull-board/nestjs'; import { BullModule } from '@nestjs/bull'; import { Module } from '@nestjs/common'; import ms from 'ms'; @@ -17,6 +19,18 @@ import { DataGatheringProcessor } from './data-gathering.processor'; @Module({ imports: [ + ...(process.env.ENABLE_FEATURE_BULL_BOARD === 'true' + ? [ + BullBoardModule.forFeature({ + adapter: BullAdapter, + name: DATA_GATHERING_QUEUE, + options: { + displayName: 'Data Gathering', + readOnlyMode: process.env.BULL_BOARD_IS_READ_ONLY !== 'false' + } + }) + ] + : []), BullModule.registerQueue({ limiter: { duration: ms('4 seconds'), 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 958636334..1260f1cf0 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 @@ -1,5 +1,5 @@ import { AccountBalanceModule } from '@ghostfolio/api/app/account-balance/account-balance.module'; -import { OrderModule } from '@ghostfolio/api/app/order/order.module'; +import { ActivitiesModule } from '@ghostfolio/api/app/activities/activities.module'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { CurrentRateService } from '@ghostfolio/api/app/portfolio/current-rate.service'; import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module'; @@ -13,6 +13,8 @@ import { PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE } from '@ghostfolio/common/config'; +import { BullAdapter } from '@bull-board/api/bullAdapter'; +import { BullBoardModule } from '@bull-board/nestjs'; import { BullModule } from '@nestjs/bull'; import { Module } from '@nestjs/common'; @@ -22,6 +24,19 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor'; exports: [BullModule, PortfolioSnapshotService], imports: [ AccountBalanceModule, + ActivitiesModule, + ...(process.env.ENABLE_FEATURE_BULL_BOARD === 'true' + ? [ + BullBoardModule.forFeature({ + adapter: BullAdapter, + name: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE, + options: { + displayName: 'Portfolio Snapshot Computation', + readOnlyMode: process.env.BULL_BOARD_IS_READ_ONLY !== 'false' + } + }) + ] + : []), BullModule.registerQueue({ name: PORTFOLIO_SNAPSHOT_COMPUTATION_QUEUE, settings: { @@ -36,7 +51,6 @@ import { PortfolioSnapshotProcessor } from './portfolio-snapshot.processor'; DataProviderModule, ExchangeRateDataModule, MarketDataModule, - OrderModule, RedisCacheModule ], providers: [ 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 75a3a8631..f3aa6e77e 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 @@ -1,5 +1,5 @@ import { AccountBalanceService } from '@ghostfolio/api/app/account-balance/account-balance.service'; -import { OrderService } from '@ghostfolio/api/app/order/order.service'; +import { ActivitiesService } from '@ghostfolio/api/app/activities/activities.service'; import { PortfolioCalculatorFactory } from '@ghostfolio/api/app/portfolio/calculator/portfolio-calculator.factory'; import { PortfolioSnapshotValue } from '@ghostfolio/api/app/portfolio/interfaces/snapshot-value.interface'; import { RedisCacheService } from '@ghostfolio/api/app/redis-cache/redis-cache.service'; @@ -23,9 +23,9 @@ import { PortfolioSnapshotQueueJob } from './interfaces/portfolio-snapshot-queue export class PortfolioSnapshotProcessor { public constructor( private readonly accountBalanceService: AccountBalanceService, + private readonly activitiesService: ActivitiesService, private readonly calculatorFactory: PortfolioCalculatorFactory, private readonly configurationService: ConfigurationService, - private readonly orderService: OrderService, private readonly redisCacheService: RedisCacheService ) {} @@ -47,10 +47,11 @@ export class PortfolioSnapshotProcessor { ); const { activities } = - await this.orderService.getOrdersForPortfolioCalculator({ + await this.activitiesService.getActivitiesForPortfolioCalculator({ filters: job.data.filters, userCurrency: job.data.userCurrency, - userId: job.data.userId + userId: job.data.userId, + withCash: true }); const accountBalanceItems = diff --git a/apps/api/src/services/tag/tag.service.ts b/apps/api/src/services/tag/tag.service.ts index eb2d7bfef..f4cbd4cb1 100644 --- a/apps/api/src/services/tag/tag.service.ts +++ b/apps/api/src/services/tag/tag.service.ts @@ -75,12 +75,16 @@ export class TagService { } }); - return tags.map(({ _count, id, name, userId }) => ({ - id, - name, - userId, - isUsed: _count.activities > 0 - })); + return tags + .map(({ _count, id, name, userId }) => ({ + id, + name, + userId, + isUsed: _count.activities > 0 + })) + .sort((a, b) => { + return a.name.toLowerCase().localeCompare(b.name.toLowerCase()); + }); } public async getTagsWithActivityCount() { diff --git a/apps/api/src/services/twitter-bot/twitter-bot.service.ts b/apps/api/src/services/twitter-bot/twitter-bot.service.ts index ee951820d..b424f7198 100644 --- a/apps/api/src/services/twitter-bot/twitter-bot.service.ts +++ b/apps/api/src/services/twitter-bot/twitter-bot.service.ts @@ -10,19 +10,21 @@ import { resolveMarketCondition } from '@ghostfolio/common/helper'; -import { Injectable, Logger } from '@nestjs/common'; +import { Injectable, Logger, OnModuleInit } from '@nestjs/common'; import { isWeekend } from 'date-fns'; import { TwitterApi, TwitterApiReadWrite } from 'twitter-api-v2'; @Injectable() -export class TwitterBotService { +export class TwitterBotService implements OnModuleInit { private twitterClient: TwitterApiReadWrite; public constructor( private readonly benchmarkService: BenchmarkService, private readonly configurationService: ConfigurationService, private readonly symbolService: SymbolService - ) { + ) {} + + public onModuleInit() { this.twitterClient = new TwitterApi({ accessSecret: this.configurationService.get( 'TWITTER_ACCESS_TOKEN_SECRET' diff --git a/apps/client/project.json b/apps/client/project.json index 09968d23f..38887ca8a 100644 --- a/apps/client/project.json +++ b/apps/client/project.json @@ -26,6 +26,10 @@ "baseHref": "/it/", "translation": "apps/client/src/locales/messages.it.xlf" }, + "ko": { + "baseHref": "/ko/", + "translation": "apps/client/src/locales/messages.ko.xlf" + }, "nl": { "baseHref": "/nl/", "translation": "apps/client/src/locales/messages.nl.xlf" @@ -110,6 +114,10 @@ "baseHref": "/it/", "localize": ["it"] }, + "development-ko": { + "baseHref": "/ko/", + "localize": ["ko"] + }, "development-nl": { "baseHref": "/nl/", "localize": ["nl"] @@ -213,6 +221,9 @@ "sslKey": "apps/client/localhost.pem" }, "configurations": { + "development-ca": { + "buildTarget": "client:build:development-ca" + }, "development-de": { "buildTarget": "client:build:development-de" }, @@ -228,6 +239,9 @@ "development-it": { "buildTarget": "client:build:development-it" }, + "development-ko": { + "buildTarget": "client:build:development-ko" + }, "development-nl": { "buildTarget": "client:build:development-nl" }, @@ -264,6 +278,7 @@ "messages.es.xlf", "messages.fr.xlf", "messages.it.xlf", + "messages.ko.xlf", "messages.nl.xlf", "messages.pl.xlf", "messages.pt.xlf", diff --git a/apps/client/proxy.conf.json b/apps/client/proxy.conf.json index a31371d9f..825965b92 100644 --- a/apps/client/proxy.conf.json +++ b/apps/client/proxy.conf.json @@ -1,4 +1,8 @@ { + "/admin/queues": { + "target": "http://0.0.0.0:3333", + "secure": false + }, "/api": { "target": "http://0.0.0.0:3333", "secure": false diff --git a/apps/client/src/app/app.component.ts b/apps/client/src/app/app.component.ts index 12a7b0de9..96d248f57 100644 --- a/apps/client/src/app/app.component.ts +++ b/apps/client/src/app/app.component.ts @@ -4,17 +4,19 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes, publicRoutes } from '@ghostfolio/common/routes/routes'; import { ColorScheme } from '@ghostfolio/common/types'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + DestroyRef, DOCUMENT, HostBinding, Inject, - OnDestroy, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatDialog } from '@angular/material/dialog'; import { Title } from '@angular/platform-browser'; import { @@ -29,16 +31,13 @@ import { DataSource } from '@prisma/client'; import { addIcons } from 'ionicons'; import { openOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { filter, takeUntil } from 'rxjs/operators'; +import { filter } from 'rxjs/operators'; import { GfFooterComponent } from './components/footer/footer.component'; import { GfHeaderComponent } from './components/header/header.component'; import { GfHoldingDetailDialogComponent } from './components/holding-detail-dialog/holding-detail-dialog.component'; import { HoldingDetailDialogParams } from './components/holding-detail-dialog/interfaces/interfaces'; -import { DataService } from './services/data.service'; import { ImpersonationStorageService } from './services/impersonation-storage.service'; -import { TokenStorageService } from './services/token-storage.service'; import { UserService } from './services/user/user.service'; @Component({ @@ -48,7 +47,7 @@ import { UserService } from './services/user/user.service'; styleUrls: ['./app.component.scss'], templateUrl: './app.component.html' }) -export class GfAppComponent implements OnDestroy, OnInit { +export class GfAppComponent implements OnInit { @HostBinding('class.has-info-message') get getHasMessage() { return this.hasInfoMessage; } @@ -69,11 +68,10 @@ export class GfAppComponent implements OnDestroy, OnInit { public showFooter = false; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, @Inject(DOCUMENT) private document: Document, @@ -82,14 +80,13 @@ export class GfAppComponent implements OnDestroy, OnInit { private route: ActivatedRoute, private router: Router, private title: Title, - private tokenStorageService: TokenStorageService, private userService: UserService ) { this.initializeTheme(); this.user = undefined; this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if ( params['dataSource'] && @@ -112,7 +109,7 @@ export class GfAppComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); @@ -201,7 +198,7 @@ export class GfAppComponent implements OnDestroy, OnInit { }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { this.user = state.user; @@ -236,21 +233,15 @@ export class GfAppComponent implements OnDestroy, OnInit { } public onCreateAccount() { - this.tokenStorageService.signOut(); + this.userService.signOut(); } public onSignOut() { - this.tokenStorageService.signOut(); - this.userService.remove(); + this.userService.signOut(); document.location.href = `/${document.documentElement.lang}`; } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private initializeTheme(userPreferredColorScheme?: ColorScheme) { const isDarkTheme = userPreferredColorScheme ? userPreferredColorScheme === 'DARK' @@ -274,7 +265,7 @@ export class GfAppComponent implements OnDestroy, OnInit { }) { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -296,15 +287,21 @@ export class GfAppComponent implements OnDestroy, OnInit { ), hasPermissionToCreateActivity: !this.hasImpersonationId && - hasPermission(this.user?.permissions, permissions.createOrder) && + hasPermission( + this.user?.permissions, + permissions.createActivity + ) && !this.user?.settings?.isRestrictedView, hasPermissionToReportDataGlitch: hasPermission( this.user?.permissions, permissions.reportDataGlitch ), - hasPermissionToUpdateOrder: + hasPermissionToUpdateActivity: !this.hasImpersonationId && - hasPermission(this.user?.permissions, permissions.updateOrder) && + hasPermission( + this.user?.permissions, + permissions.updateActivity + ) && !this.user?.settings?.isRestrictedView, locale: this.user?.settings?.locale }, @@ -314,7 +311,7 @@ export class GfAppComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.router.navigate([], { queryParams: { diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts index d8f08ecc2..7a3040391 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.component.ts @@ -1,5 +1,4 @@ import { GfInvestmentChartComponent } from '@ghostfolio/client/components/investment-chart/investment-chart.component'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { NUMERICAL_PRECISION_THRESHOLD_6_FIGURES } from '@ghostfolio/common/config'; import { CreateAccountBalanceDto } from '@ghostfolio/common/dtos'; @@ -19,6 +18,7 @@ import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { GfDialogFooterComponent } from '@ghostfolio/ui/dialog-footer'; import { GfDialogHeaderComponent } from '@ghostfolio/ui/dialog-header'; import { GfHoldingsTableComponent } from '@ghostfolio/ui/holdings-table'; +import { DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { CommonModule } from '@angular/common'; @@ -26,11 +26,12 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + DestroyRef, Inject, - OnDestroy, OnInit } from '@angular/core'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog'; @@ -49,8 +50,7 @@ import { } from 'ionicons/icons'; import { isNumber } from 'lodash'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { forkJoin, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { forkJoin } from 'rxjs'; import { AccountDetailDialogParams } from './interfaces/interfaces'; @@ -77,9 +77,10 @@ import { AccountDetailDialogParams } from './interfaces/interfaces'; styleUrls: ['./account-detail-dialog.component.scss'], templateUrl: 'account-detail-dialog.html' }) -export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { +export class GfAccountDetailDialogComponent implements OnInit { public accountBalances: AccountBalancesResponse['balances']; public activities: OrderWithAccount[]; + public activitiesCount: number; public balance: number; public balancePrecision = 2; public currency: string; @@ -100,22 +101,20 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { public sortColumn = 'date'; public sortDirection: SortDirection = 'desc'; public totalItems: number; - public transactionCount: number; public user: User; public valueInBaseCurrency: number; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: AccountDetailDialogParams, private dataService: DataService, + private destroyRef: DestroyRef, public dialogRef: MatDialogRef, private router: Router, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -154,7 +153,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { public onAddAccountBalance(accountBalance: CreateAccountBalanceDto) { this.dataService .postAccountBalance(accountBalance) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.initialize(); }); @@ -163,7 +162,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { public onDeleteAccountBalance(aId: string) { this.dataService .deleteAccountBalance(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.initialize(); }); @@ -176,7 +175,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { this.dataService .fetchExport({ activityIds }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { downloadAsFile({ content: data, @@ -212,19 +211,20 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { private fetchAccount() { this.dataService .fetchAccount(this.data.accountId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( ({ + activitiesCount, balance, currency, dividendInBaseCurrency, interestInBaseCurrency, name, platform, - transactionCount, value, valueInBaseCurrency }) => { + this.activitiesCount = activitiesCount; this.balance = balance; if ( @@ -270,7 +270,6 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { this.name = name; this.platformName = platform?.name ?? '-'; - this.transactionCount = transactionCount; this.valueInBaseCurrency = valueInBaseCurrency; this.changeDetectorRef.markForCheck(); @@ -287,7 +286,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { sortColumn: this.sortColumn, sortDirection: this.sortDirection }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ activities, count }) => { this.dataSource = new MatTableDataSource(activities); this.totalItems = count; @@ -304,7 +303,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { forkJoin({ accountBalances: this.dataService .fetchAccountBalances(this.data.accountId) - .pipe(takeUntil(this.unsubscribeSubject)), + .pipe(takeUntilDestroyed(this.destroyRef)), portfolioPerformance: this.dataService .fetchPortfolioPerformance({ filters: [ @@ -317,7 +316,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { withExcludedAccounts: true, withItems: true }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) }).subscribe({ error: () => { this.isLoadingChart = false; @@ -360,7 +359,7 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { } ] }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { this.holdings = holdings; @@ -374,9 +373,4 @@ export class GfAccountDetailDialogComponent implements OnDestroy, OnInit { this.fetchChart(); this.fetchPortfolioHoldings(); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html index 07ea17038..e41d3415c 100644 --- a/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html +++ b/apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html @@ -82,7 +82,7 @@ >
- Activities
@@ -102,8 +102,6 @@
Holdings
(); public defaultDateTimeFormat: string; public filterForm: FormGroup; + public displayedColumns = [ 'index', 'type', @@ -93,21 +98,24 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { 'status', 'actions' ]; + + public hasPermissionToAccessBullBoard = false; public isLoading = false; public statusFilterOptions = QUEUE_JOB_STATUS_LIST; - public user: User; - private unsubscribeSubject = new Subject(); + private user: User; public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private formBuilder: FormBuilder, private notificationService: NotificationService, + private tokenStorageService: TokenStorageService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -115,6 +123,11 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { this.defaultDateTimeFormat = getDateWithTimeFormatString( this.user.settings.locale ); + + this.hasPermissionToAccessBullBoard = hasPermission( + this.user.permissions, + permissions.accessAdminControlBullBoard + ); } }); @@ -126,6 +139,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { chevronUpCircleOutline, ellipsisHorizontal, ellipsisVertical, + openOutline, pauseOutline, playOutline, removeCircleOutline, @@ -139,7 +153,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { }); this.filterForm.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { const currentFilter = this.filterForm.get('status').value; this.fetchJobs(currentFilter ? [currentFilter] : undefined); @@ -151,7 +165,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { public onDeleteJob(aId: string) { this.adminService .deleteJob(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.fetchJobs(); }); @@ -162,7 +176,7 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { this.adminService .deleteJobs({ status: currentFilter ? [currentFilter] : undefined }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.fetchJobs(currentFilter ? [currentFilter] : undefined); }); @@ -171,12 +185,24 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { public onExecuteJob(aId: string) { this.adminService .executeJob(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.fetchJobs(); }); } + public onOpenBullBoard() { + const token = this.tokenStorageService.getToken(); + + document.cookie = [ + `${BULL_BOARD_COOKIE_NAME}=${encodeURIComponent(token)}`, + 'path=/', + 'SameSite=Strict' + ].join('; '); + + window.open(BULL_BOARD_ROUTE, '_blank'); + } + public onViewData(aData: AdminJobs['jobs'][0]['data']) { this.notificationService.alert({ title: JSON.stringify(aData, null, ' ') @@ -189,17 +215,12 @@ export class GfAdminJobsComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchJobs(aStatus?: JobStatus[]) { this.isLoading = true; this.adminService .fetchJobs({ status: aStatus }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ jobs }) => { this.dataSource = new MatTableDataSource(jobs); this.dataSource.sort = this.sort; diff --git a/apps/client/src/app/components/admin-jobs/admin-jobs.html b/apps/client/src/app/components/admin-jobs/admin-jobs.html index a82294001..cff80498c 100644 --- a/apps/client/src/app/components/admin-jobs/admin-jobs.html +++ b/apps/client/src/app/components/admin-jobs/admin-jobs.html @@ -1,6 +1,15 @@
+ @if (hasPermissionToAccessBullBoard) { +
+ +
+ } +
diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts index 4f1b60981..d3265946f 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.component.ts @@ -1,5 +1,3 @@ -import { AdminService } from '@ghostfolio/client/services/admin.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { DEFAULT_PAGE_SIZE, @@ -18,6 +16,7 @@ import { GfSymbolPipe } from '@ghostfolio/common/pipes'; import { GfActivitiesFilterComponent } from '@ghostfolio/ui/activities-filter'; import { translate } from '@ghostfolio/ui/i18n'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { AdminService, DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { SelectionModel } from '@angular/cdk/collections'; @@ -27,10 +26,11 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatDialog } from '@angular/material/dialog'; @@ -64,7 +64,7 @@ import { import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; import { Subject } from 'rxjs'; -import { distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators'; +import { distinctUntilChanged } from 'rxjs/operators'; import { AdminMarketDataService } from './admin-market-data.service'; import { GfAssetProfileDialogComponent } from './asset-profile-dialog/asset-profile-dialog.component'; @@ -96,9 +96,7 @@ import { CreateAssetProfileDialogParams } from './create-asset-profile-dialog/in styleUrls: ['./admin-market-data.scss'], templateUrl: './admin-market-data.html' }) -export class GfAdminMarketDataComponent - implements AfterViewInit, OnDestroy, OnInit -{ +export class GfAdminMarketDataComponent implements AfterViewInit, OnInit { @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -141,6 +139,11 @@ export class GfAdminMarketDataComponent id: 'ETF_WITHOUT_SECTORS', label: $localize`ETFs without Sectors`, type: 'PRESET_ID' as Filter['type'] + }, + { + id: 'NO_ACTIVITIES', + label: $localize`No Activities`, + type: 'PRESET_ID' as Filter['type'] } ]; public benchmarks: Partial[]; @@ -162,13 +165,12 @@ export class GfAdminMarketDataComponent public totalItems = 0; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( public adminMarketDataService: AdminMarketDataService, private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private route: ActivatedRoute, @@ -205,7 +207,7 @@ export class GfAdminMarketDataComponent this.displayedColumns.push('actions'); this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if ( params['assetProfileDialog'] && @@ -222,7 +224,7 @@ export class GfAdminMarketDataComponent }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -234,7 +236,7 @@ export class GfAdminMarketDataComponent }); this.filters$ - .pipe(distinctUntilChanged(), takeUntil(this.unsubscribeSubject)) + .pipe(distinctUntilChanged(), takeUntilDestroyed(this.destroyRef)) .subscribe((filters) => { this.activeFilters = filters; @@ -298,7 +300,7 @@ export class GfAdminMarketDataComponent public onGather7Days() { this.adminService .gather7Days() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { setTimeout(() => { window.location.reload(); @@ -309,7 +311,7 @@ export class GfAdminMarketDataComponent public onGatherMax() { this.adminService .gatherMax() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { setTimeout(() => { window.location.reload(); @@ -320,7 +322,7 @@ export class GfAdminMarketDataComponent public onGatherProfileData() { this.adminService .gatherProfileData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } @@ -330,14 +332,14 @@ export class GfAdminMarketDataComponent }: AssetProfileIdentifier) { this.adminService .gatherProfileDataBySymbol({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } public onGatherSymbol({ dataSource, symbol }: AssetProfileIdentifier) { this.adminService .gatherSymbol({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } @@ -354,11 +356,6 @@ export class GfAdminMarketDataComponent }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private loadData( { pageIndex, @@ -375,7 +372,7 @@ export class GfAdminMarketDataComponent this.pageSize = this.activeFilters.length === 1 && this.activeFilters[0].type === 'PRESET_ID' - ? undefined + ? Number.MAX_SAFE_INTEGER : DEFAULT_PAGE_SIZE; if (pageIndex === 0 && this.paginator) { @@ -395,7 +392,7 @@ export class GfAdminMarketDataComponent skip: pageIndex * this.pageSize, take: this.pageSize }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ count, marketData }) => { this.totalItems = count; @@ -426,7 +423,7 @@ export class GfAdminMarketDataComponent }) { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -448,7 +445,7 @@ export class GfAdminMarketDataComponent dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( (newAssetProfileIdentifier: AssetProfileIdentifier | undefined) => { if (newAssetProfileIdentifier) { @@ -464,7 +461,7 @@ export class GfAdminMarketDataComponent private openCreateAssetProfileDialog() { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -482,33 +479,28 @@ export class GfAdminMarketDataComponent dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ dataSource, symbol } = {}) => { - if (dataSource && symbol) { + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((result) => { + if (!result) { + this.router.navigate(['.'], { relativeTo: this.route }); + + return; + } + + const { addAssetProfile, dataSource, symbol } = result; + + if (addAssetProfile && dataSource && symbol) { this.adminService .addAssetProfile({ dataSource, symbol }) - .pipe( - switchMap(() => { - this.isLoading = true; - this.changeDetectorRef.markForCheck(); - - return this.adminService.fetchAdminMarketData({ - filters: this.activeFilters, - take: this.pageSize - }); - }), - takeUntil(this.unsubscribeSubject) - ) - .subscribe(({ marketData }) => { - this.dataSource = new MatTableDataSource(marketData); - this.dataSource.sort = this.sort; - this.isLoading = false; - - this.changeDetectorRef.markForCheck(); + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(() => { + this.loadData(); }); + } else { + this.loadData(); } - this.router.navigate(['.'], { relativeTo: this.route }); + this.onOpenAssetProfileDialog({ dataSource, symbol }); }); }); } diff --git a/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts b/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts index eaad32c0e..9528687a8 100644 --- a/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts +++ b/apps/client/src/app/components/admin-market-data/admin-market-data.service.ts @@ -1,4 +1,3 @@ -import { AdminService } from '@ghostfolio/client/services/admin.service'; import { ghostfolioScraperApiSymbolPrefix } from '@ghostfolio/common/config'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { @@ -11,6 +10,7 @@ import { AdminMarketDataItem } from '@ghostfolio/common/interfaces'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { AdminService } from '@ghostfolio/ui/services'; import { Injectable } from '@angular/core'; import { EMPTY, catchError, finalize, forkJoin } from 'rxjs'; diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts index 07e060764..c0af46e22 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts @@ -1,13 +1,15 @@ import { AdminMarketDataService } from '@ghostfolio/client/components/admin-market-data/admin-market-data.service'; -import { AdminService } from '@ghostfolio/client/services/admin.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { ASSET_CLASS_MAPPING, PROPERTY_IS_DATA_GATHERING_ENABLED } from '@ghostfolio/common/config'; import { UpdateAssetProfileDto } from '@ghostfolio/common/dtos'; -import { DATE_FORMAT } from '@ghostfolio/common/helper'; +import { + DATE_FORMAT, + getCurrencyFromSymbol, + isCurrency +} from '@ghostfolio/common/helper'; import { AdminMarketDataDetails, AssetClassSelectorOption, @@ -25,6 +27,7 @@ import { translate } from '@ghostfolio/ui/i18n'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { GfPortfolioProportionChartComponent } from '@ghostfolio/ui/portfolio-proportion-chart'; +import { AdminService, DataService } from '@ghostfolio/ui/services'; import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -34,12 +37,13 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, + DestroyRef, ElementRef, Inject, - OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { AbstractControl, FormBuilder, @@ -84,8 +88,8 @@ import { serverOutline } from 'ionicons/icons'; import ms from 'ms'; -import { EMPTY, Subject } from 'rxjs'; -import { catchError, takeUntil } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { catchError } from 'rxjs/operators'; import { AssetProfileDialogParams } from './interfaces/interfaces'; @@ -118,7 +122,7 @@ import { AssetProfileDialogParams } from './interfaces/interfaces'; styleUrls: ['./asset-profile-dialog.component.scss'], templateUrl: 'asset-profile-dialog.html' }) -export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { +export class GfAssetProfileDialogComponent implements OnInit { private static readonly HISTORICAL_DATA_TEMPLATE = `date;marketPrice\n${format( new Date(), DATE_FORMAT @@ -139,7 +143,6 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }); public assetSubClassOptions: AssetClassSelectorOption[] = []; - public assetProfile: AdminMarketDataDetails['assetProfile']; public assetProfileForm = this.formBuilder.group({ @@ -181,12 +184,14 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { ); public benchmarks: Partial[]; + public canEditAssetProfile = true; public countries: { [code: string]: { name: string; value: number }; }; public currencies: string[] = []; + public dateRangeOptions = [ { label: $localize`Current week` + ' (' + $localize`WTD` + ')', @@ -237,14 +242,13 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { public user: User; - private unsubscribeSubject = new Subject(); - public constructor( public adminMarketDataService: AdminMarketDataService, private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: AssetProfileDialogParams, private dataService: DataService, + private destroyRef: DestroyRef, public dialogRef: MatDialogRef, private formBuilder: FormBuilder, private notificationService: NotificationService, @@ -261,7 +265,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { } public get canSaveAssetProfileIdentifier() { - return !this.assetProfileForm.dirty; + return !this.assetProfileForm.dirty && this.canEditAssetProfile; } public ngOnInit() { @@ -278,7 +282,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { this.adminService .fetchAdminData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ settings }) => { this.isDataGatheringEnabled = settings[PROPERTY_IS_DATA_GATHERING_ENABLED] === false ? false : true; @@ -287,7 +291,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -296,7 +300,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { this.assetProfileForm .get('assetClass') - .valueChanges.pipe(takeUntil(this.unsubscribeSubject)) + .valueChanges.pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((assetClass) => { const assetSubClasses = ASSET_CLASS_MAPPING.get(assetClass) ?? []; @@ -319,12 +323,17 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { dataSource: this.data.dataSource, symbol: this.data.symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ assetProfile, marketData }) => { this.assetProfile = assetProfile; this.assetClassLabel = translate(this.assetProfile?.assetClass); this.assetSubClassLabel = translate(this.assetProfile?.assetSubClass); + + this.canEditAssetProfile = !isCurrency( + getCurrencyFromSymbol(this.data.symbol) + ); + this.countries = {}; this.isBenchmark = this.benchmarks.some(({ id }) => { @@ -391,6 +400,10 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { url: this.assetProfile?.url ?? '' }); + if (!this.canEditAssetProfile) { + this.assetProfileForm.disable(); + } + this.assetProfileForm.markAsPristine(); this.changeDetectorRef.markForCheck(); @@ -400,7 +413,9 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { public onCancelEditAssetProfileIdentifierMode() { this.isEditAssetProfileIdentifierMode = false; - this.assetProfileForm.enable(); + if (this.canEditAssetProfile) { + this.assetProfileForm.enable(); + } this.assetProfileIdentifierForm.reset(); } @@ -421,7 +436,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }: AssetProfileIdentifier) { this.adminService .gatherProfileDataBySymbol({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } @@ -434,7 +449,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { } & AssetProfileIdentifier) { this.adminService .gatherSymbol({ dataSource, range, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); } @@ -447,7 +462,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { public onSetBenchmark({ dataSource, symbol }: AssetProfileIdentifier) { this.dataService .postBenchmark({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.dataService.updateInfo(); @@ -649,7 +664,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(() => { const newAssetProfileIdentifier = { @@ -699,7 +714,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }); return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(({ price }) => { this.notificationService.alert({ @@ -730,7 +745,7 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { public onUnsetBenchmark({ dataSource, symbol }: AssetProfileIdentifier) { this.dataService .deleteBenchmark({ dataSource, symbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.dataService.updateInfo(); @@ -740,11 +755,6 @@ export class GfAssetProfileDialogComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - public onTriggerSubmitAssetProfileForm() { if (this.assetProfileForm.valid) { this.onSubmitAssetProfileForm(); diff --git a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html index a60e10edc..6b3141bfe 100644 --- a/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html +++ b/apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -300,6 +300,7 @@
Data Gathering diff --git a/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts b/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts index 32e1e3309..35887abb4 100644 --- a/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts +++ b/apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.component.ts @@ -1,19 +1,19 @@ -import { AdminService } from '@ghostfolio/client/services/admin.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { DEFAULT_CURRENCY, ghostfolioPrefix, PROPERTY_CURRENCIES } from '@ghostfolio/common/config'; +import { AdminService, DataService } from '@ghostfolio/ui/services'; import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { AbstractControl, FormBuilder, @@ -32,7 +32,7 @@ import { MatInputModule } from '@angular/material/input'; import { MatRadioModule } from '@angular/material/radio'; import { DataSource } from '@prisma/client'; import { isISO4217CurrencyCode } from 'class-validator'; -import { Subject, switchMap, takeUntil } from 'rxjs'; +import { switchMap } from 'rxjs'; import { CreateAssetProfileDialogMode } from './interfaces/interfaces'; @@ -53,19 +53,19 @@ import { CreateAssetProfileDialogMode } from './interfaces/interfaces'; styleUrls: ['./create-asset-profile-dialog.component.scss'], templateUrl: 'create-asset-profile-dialog.html' }) -export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { +export class GfCreateAssetProfileDialogComponent implements OnInit { public createAssetProfileForm: FormGroup; public ghostfolioPrefix = `${ghostfolioPrefix}_`; public mode: CreateAssetProfileDialogMode; private customCurrencies: string[]; private dataSourceForExchangeRates: DataSource; - private unsubscribeSubject = new Subject(); public constructor( public readonly adminService: AdminService, private readonly changeDetectorRef: ChangeDetectorRef, private readonly dataService: DataService, + private readonly destroyRef: DestroyRef, public readonly dialogRef: MatDialogRef, public readonly formBuilder: FormBuilder ) {} @@ -102,6 +102,7 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { public onSubmit() { if (this.mode === 'auto') { this.dialogRef.close({ + addAssetProfile: true, dataSource: this.createAssetProfileForm.get('searchSymbol').value.dataSource, symbol: this.createAssetProfileForm.get('searchSymbol').value.symbol @@ -125,13 +126,18 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { symbol: `${DEFAULT_CURRENCY}${currency}` }); }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(() => { - this.dialogRef.close(); + this.dialogRef.close({ + addAssetProfile: false, + dataSource: this.dataSourceForExchangeRates, + symbol: `${DEFAULT_CURRENCY}${currency}` + }); }); } else if (this.mode === 'manual') { this.dialogRef.close({ + addAssetProfile: true, dataSource: 'MANUAL', symbol: `${this.ghostfolioPrefix}${this.createAssetProfileForm.get('addSymbol').value}` }); @@ -149,11 +155,6 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { return false; } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private atLeastOneValid(control: AbstractControl): ValidationErrors { const addCurrencyControl = control.get('addCurrency'); const addSymbolControl = control.get('addSymbol'); @@ -184,7 +185,7 @@ export class GfCreateAssetProfileDialogComponent implements OnDestroy, OnInit { private initialize() { this.adminService .fetchAdminData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ dataProviders, settings }) => { this.customCurrencies = settings[PROPERTY_CURRENCIES] as string[]; diff --git a/apps/client/src/app/components/admin-overview/admin-overview.component.ts b/apps/client/src/app/components/admin-overview/admin-overview.component.ts index e4be7b062..5d4e5268e 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.component.ts +++ b/apps/client/src/app/components/admin-overview/admin-overview.component.ts @@ -1,6 +1,4 @@ -import { AdminService } from '@ghostfolio/client/services/admin.service'; import { CacheService } from '@ghostfolio/client/services/cache.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { PROPERTY_COUPONS, @@ -20,10 +18,17 @@ import { } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { AdminService, DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { CommonModule } from '@angular/common'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; @@ -51,8 +56,6 @@ import { trashOutline } from 'ionicons/icons'; import ms, { StringValue } from 'ms'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -73,7 +76,8 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./admin-overview.scss'], templateUrl: './admin-overview.html' }) -export class GfAdminOverviewComponent implements OnDestroy, OnInit { +export class GfAdminOverviewComponent implements OnInit { + public activitiesCount: number; public couponDuration: StringValue = '14 days'; public coupons: Coupon[]; public hasPermissionForSubscription: boolean; @@ -84,18 +88,16 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { public isDataGatheringEnabled: boolean; public permissions = permissions; public systemMessage: SystemMessage; - public transactionCount: number; public userCount: number; public user: User; public version: string; - private unsubscribeSubject = new Subject(); - public constructor( private adminService: AdminService, private cacheService: CacheService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private notificationService: NotificationService, private snackBar: MatSnackBar, private userService: UserService @@ -103,7 +105,7 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { this.info = this.dataService.fetchInfo(); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -220,7 +222,7 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { confirmFn: () => { this.cacheService .flush() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { setTimeout(() => { window.location.reload(); @@ -269,7 +271,7 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { public onSyncDemoUserAccount() { this.adminService .syncDemoUserAccount() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.snackBar.open( '✅ ' + $localize`Demo user account has been synced.`, @@ -281,21 +283,16 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchAdminData() { this.adminService .fetchAdminData() - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(({ settings, transactionCount, userCount, version }) => { + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe(({ activitiesCount, settings, userCount, version }) => { + this.activitiesCount = activitiesCount; this.coupons = (settings[PROPERTY_COUPONS] as Coupon[]) ?? []; this.isDataGatheringEnabled = settings[PROPERTY_IS_DATA_GATHERING_ENABLED] === false ? false : true; this.systemMessage = settings[PROPERTY_SYSTEM_MESSAGE] as SystemMessage; - this.transactionCount = transactionCount; this.userCount = userCount; this.version = version; @@ -321,7 +318,7 @@ export class GfAdminOverviewComponent implements OnDestroy, OnInit { .putAdminSetting(key, { value: value || value === false ? JSON.stringify(value) : undefined }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { setTimeout(() => { window.location.reload(); diff --git a/apps/client/src/app/components/admin-overview/admin-overview.html b/apps/client/src/app/components/admin-overview/admin-overview.html index c47387f37..f0a6ea1d5 100644 --- a/apps/client/src/app/components/admin-overview/admin-overview.html +++ b/apps/client/src/app/components/admin-overview/admin-overview.html @@ -20,11 +20,11 @@
- @if (transactionCount && userCount) { + @if (activitiesCount && userCount) {
- {{ transactionCount / userCount | number: '1.2-2' }} + {{ activitiesCount / userCount | number: '1.2-2' }} per User
} diff --git a/apps/client/src/app/components/admin-platform/admin-platform.component.html b/apps/client/src/app/components/admin-platform/admin-platform.component.html index 367827878..7370a19ae 100644 --- a/apps/client/src/app/components/admin-platform/admin-platform.component.html +++ b/apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -52,7 +52,11 @@ Accounts - {{ element.accountCount }} + diff --git a/apps/client/src/app/components/admin-platform/admin-platform.component.ts b/apps/client/src/app/components/admin-platform/admin-platform.component.ts index 832a70503..b8f2af789 100644 --- a/apps/client/src/app/components/admin-platform/admin-platform.component.ts +++ b/apps/client/src/app/components/admin-platform/admin-platform.component.ts @@ -1,19 +1,22 @@ -import { AdminService } from '@ghostfolio/client/services/admin.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; +import { getLocale } from '@ghostfolio/common/helper'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { AdminService, DataService } from '@ghostfolio/ui/services'; +import { GfValueComponent } from '@ghostfolio/ui/value'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, + Input, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; @@ -30,7 +33,6 @@ import { } from 'ionicons/icons'; import { get } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; import { GfCreateOrUpdatePlatformDialogComponent } from './create-or-update-platform-dialog/create-or-update-platform-dialog.component'; import { CreateOrUpdatePlatformDialogParams } from './create-or-update-platform-dialog/interfaces/interfaces'; @@ -39,6 +41,7 @@ import { CreateOrUpdatePlatformDialogParams } from './create-or-update-platform- changeDetection: ChangeDetectionStrategy.OnPush, imports: [ GfEntityLogoComponent, + GfValueComponent, IonIcon, MatButtonModule, MatMenuModule, @@ -50,7 +53,9 @@ import { CreateOrUpdatePlatformDialogParams } from './create-or-update-platform- styleUrls: ['./admin-platform.component.scss'], templateUrl: './admin-platform.component.html' }) -export class GfAdminPlatformComponent implements OnDestroy, OnInit { +export class GfAdminPlatformComponent implements OnInit { + @Input() locale = getLocale(); + @ViewChild(MatSort) sort: MatSort; public dataSource = new MatTableDataSource(); @@ -58,12 +63,11 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { public displayedColumns = ['name', 'url', 'accounts', 'actions']; public platforms: Platform[]; - private unsubscribeSubject = new Subject(); - public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private notificationService: NotificationService, @@ -72,7 +76,7 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { private userService: UserService ) { this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['createPlatformDialog']) { this.openCreatePlatformDialog(); @@ -114,20 +118,15 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private deletePlatform(aId: string) { this.adminService .deletePlatform(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchPlatforms(); @@ -138,7 +137,7 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { private fetchPlatforms() { this.adminService .fetchPlatforms() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((platforms) => { this.platforms = platforms; @@ -170,17 +169,17 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((platform: CreatePlatformDto | null) => { if (platform) { this.adminService .postPlatform(platform) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchPlatforms(); @@ -218,17 +217,17 @@ export class GfAdminPlatformComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((platform: UpdatePlatformDto | null) => { if (platform) { this.adminService .putPlatform(platform) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchPlatforms(); diff --git a/apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts b/apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts index dfcf300c1..0cfe026a4 100644 --- a/apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts +++ b/apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.component.ts @@ -2,12 +2,7 @@ import { CreatePlatformDto, UpdatePlatformDto } from '@ghostfolio/common/dtos'; import { validateObjectForForm } from '@ghostfolio/common/utils'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; -import { - ChangeDetectionStrategy, - Component, - Inject, - OnDestroy -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { FormBuilder, FormGroup, @@ -23,7 +18,6 @@ import { } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { Subject } from 'rxjs'; import { CreateOrUpdatePlatformDialogParams } from './interfaces/interfaces'; @@ -43,11 +37,9 @@ import { CreateOrUpdatePlatformDialogParams } from './interfaces/interfaces'; styleUrls: ['./create-or-update-platform-dialog.scss'], templateUrl: 'create-or-update-platform-dialog.html' }) -export class GfCreateOrUpdatePlatformDialogComponent implements OnDestroy { +export class GfCreateOrUpdatePlatformDialogComponent { public platformForm: FormGroup; - private unsubscribeSubject = new Subject(); - public constructor( @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdatePlatformDialogParams, public dialogRef: MatDialogRef, @@ -90,9 +82,4 @@ export class GfCreateOrUpdatePlatformDialogComponent implements OnDestroy { console.error(error); } } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.html b/apps/client/src/app/components/admin-settings/admin-settings.component.html index af64f034b..76af96c4e 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.html +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.html @@ -40,9 +40,21 @@ } - +
- diff --git a/apps/client/src/app/components/admin-tag/admin-tag.component.ts b/apps/client/src/app/components/admin-tag/admin-tag.component.ts index 305eb4628..506736156 100644 --- a/apps/client/src/app/components/admin-tag/admin-tag.component.ts +++ b/apps/client/src/app/components/admin-tag/admin-tag.component.ts @@ -1,17 +1,21 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { CreateTagDto, UpdateTagDto } from '@ghostfolio/common/dtos'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; +import { getLocale } from '@ghostfolio/common/helper'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { DataService } from '@ghostfolio/ui/services'; +import { GfValueComponent } from '@ghostfolio/ui/value'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, + Input, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; @@ -28,7 +32,6 @@ import { } from 'ionicons/icons'; import { get } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; import { GfCreateOrUpdateTagDialogComponent } from './create-or-update-tag-dialog/create-or-update-tag-dialog.component'; import { CreateOrUpdateTagDialogParams } from './create-or-update-tag-dialog/interfaces/interfaces'; @@ -36,6 +39,7 @@ import { CreateOrUpdateTagDialogParams } from './create-or-update-tag-dialog/int @Component({ changeDetection: ChangeDetectionStrategy.OnPush, imports: [ + GfValueComponent, IonIcon, MatButtonModule, MatMenuModule, @@ -47,7 +51,9 @@ import { CreateOrUpdateTagDialogParams } from './create-or-update-tag-dialog/int styleUrls: ['./admin-tag.component.scss'], templateUrl: './admin-tag.component.html' }) -export class GfAdminTagComponent implements OnDestroy, OnInit { +export class GfAdminTagComponent implements OnInit { + @Input() locale = getLocale(); + @ViewChild(MatSort) sort: MatSort; public dataSource = new MatTableDataSource(); @@ -55,11 +61,10 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { public displayedColumns = ['name', 'userId', 'activities', 'actions']; public tags: Tag[]; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private notificationService: NotificationService, @@ -68,7 +73,7 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { private userService: UserService ) { this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['createTagDialog']) { this.openCreateTagDialog(); @@ -110,20 +115,15 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private deleteTag(aId: string) { this.dataService .deleteTag(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchTags(); @@ -134,7 +134,7 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { private fetchTags() { this.dataService .fetchTags() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tags) => { this.tags = tags; @@ -165,17 +165,17 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tag: CreateTagDto | null) => { if (tag) { this.dataService .postTag(tag) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchTags(); @@ -204,17 +204,17 @@ export class GfAdminTagComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((tag: UpdateTagDto | null) => { if (tag) { this.dataService .putTag(tag) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe({ next: () => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchTags(); diff --git a/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts b/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts index 323609a48..e22c73478 100644 --- a/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts +++ b/apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.component.ts @@ -1,12 +1,7 @@ import { CreateTagDto, UpdateTagDto } from '@ghostfolio/common/dtos'; import { validateObjectForForm } from '@ghostfolio/common/utils'; -import { - ChangeDetectionStrategy, - Component, - Inject, - OnDestroy -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { FormBuilder, FormGroup, @@ -21,7 +16,6 @@ import { } from '@angular/material/dialog'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; -import { Subject } from 'rxjs'; import { CreateOrUpdateTagDialogParams } from './interfaces/interfaces'; @@ -40,11 +34,9 @@ import { CreateOrUpdateTagDialogParams } from './interfaces/interfaces'; styleUrls: ['./create-or-update-tag-dialog.scss'], templateUrl: 'create-or-update-tag-dialog.html' }) -export class GfCreateOrUpdateTagDialogComponent implements OnDestroy { +export class GfCreateOrUpdateTagDialogComponent { public tagForm: FormGroup; - private unsubscribeSubject = new Subject(); - public constructor( @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateTagDialogParams, public dialogRef: MatDialogRef, @@ -85,9 +77,4 @@ export class GfCreateOrUpdateTagDialogComponent implements OnDestroy { console.error(error); } } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/admin-users/admin-users.component.ts b/apps/client/src/app/components/admin-users/admin-users.component.ts index 1722b498f..874bbc1db 100644 --- a/apps/client/src/app/components/admin-users/admin-users.component.ts +++ b/apps/client/src/app/components/admin-users/admin-users.component.ts @@ -1,9 +1,6 @@ import { UserDetailDialogParams } from '@ghostfolio/client/components/user-detail-dialog/interfaces/interfaces'; import { GfUserDetailDialogComponent } from '@ghostfolio/client/components/user-detail-dialog/user-detail-dialog.component'; -import { AdminService } from '@ghostfolio/client/services/admin.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { DEFAULT_PAGE_SIZE } from '@ghostfolio/common/config'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; @@ -21,16 +18,18 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { AdminService, DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { CommonModule } from '@angular/common'; import { ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { MatMenuModule } from '@angular/material/menu'; @@ -57,8 +56,7 @@ import { } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { switchMap, tap } from 'rxjs/operators'; @Component({ imports: [ @@ -77,7 +75,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./admin-users.scss'], templateUrl: './admin-users.html' }) -export class GfAdminUsersComponent implements OnDestroy, OnInit { +export class GfAdminUsersComponent implements OnInit { @ViewChild(MatPaginator) paginator: MatPaginator; public dataSource = new MatTableDataSource(); @@ -95,19 +93,17 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { public totalItems = 0; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private impersonationStorageService: ImpersonationStorageService, private notificationService: NotificationService, private route: ActivatedRoute, private router: Router, - private tokenStorageService: TokenStorageService, private userService: UserService ) { this.deviceType = this.deviceService.getDeviceInfo().deviceType; @@ -140,8 +136,25 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { ]; } - this.route.paramMap - .pipe(takeUntil(this.unsubscribeSubject)) + this.userService.stateChanged + .pipe( + takeUntilDestroyed(this.destroyRef), + tap((state) => { + if (state?.user) { + this.user = state.user; + + this.defaultDateFormat = getDateFormatString( + this.user.settings.locale + ); + + this.hasPermissionToImpersonateAllUsers = hasPermission( + this.user.permissions, + permissions.impersonateAllUsers + ); + } + }), + switchMap(() => this.route.paramMap) + ) .subscribe((params) => { const userId = params.get('userId'); @@ -150,23 +163,6 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { } }); - this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe((state) => { - if (state?.user) { - this.user = state.user; - - this.defaultDateFormat = getDateFormatString( - this.user.settings.locale - ); - - this.hasPermissionToImpersonateAllUsers = hasPermission( - this.user.permissions, - permissions.impersonateAllUsers - ); - } - }); - addIcons({ contractOutline, ellipsisHorizontal, @@ -207,12 +203,15 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { confirmFn: () => { this.dataService .deleteUser(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { - this.fetchUsers(); + this.router.navigate(['..'], { relativeTo: this.route }); }); }, confirmType: ConfirmationDialogType.Warn, + discardFn: () => { + this.router.navigate(['..'], { relativeTo: this.route }); + }, title: $localize`Do you really want to delete this user?` }); } @@ -222,13 +221,12 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { confirmFn: () => { this.dataService .updateUserAccessToken(aUserId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ accessToken }) => { this.notificationService.alert({ discardFn: () => { if (aUserId === this.user.id) { - this.tokenStorageService.signOut(); - this.userService.remove(); + this.userService.signOut(); document.location.href = `/${document.documentElement.lang}`; } @@ -259,11 +257,6 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { ); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchUsers({ pageIndex }: { pageIndex: number } = { pageIndex: 0 }) { this.isLoading = true; @@ -276,7 +269,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { skip: pageIndex * this.pageSize, take: this.pageSize }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ count, users }) => { this.dataSource = new MatTableDataSource(users); this.totalItems = count; @@ -294,6 +287,7 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { >(GfUserDetailDialogComponent, { autoFocus: false, data: { + currentUserId: this.user?.id, deviceType: this.deviceType, hasPermissionForSubscription: this.hasPermissionForSubscription, locale: this.user?.settings?.locale, @@ -305,11 +299,15 @@ export class GfAdminUsersComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) - .subscribe(() => { - this.router.navigate( - internalRoutes.adminControl.subRoutes.users.routerLink - ); + .pipe(takeUntilDestroyed(this.destroyRef)) + .subscribe((data) => { + if (data?.action === 'delete' && data?.userId) { + this.onDeleteUser(data.userId); + } else { + this.router.navigate( + internalRoutes.adminControl.subRoutes.users.routerLink + ); + } }); } } 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 7f03ea57f..2ecefc311 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 @@ -1,6 +1,5 @@ import { getTooltipOptions, - getTooltipPositionerMapTop, getVerticalHoverLinePlugin } from '@ghostfolio/common/chart-helper'; import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config'; @@ -15,12 +14,14 @@ import { LineChartItem, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { ColorScheme } from '@ghostfolio/common/types'; +import { registerChartConfiguration } from '@ghostfolio/ui/chart'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, + type ElementRef, EventEmitter, Input, OnChanges, @@ -42,7 +43,7 @@ import { PointElement, TimeScale, Tooltip, - TooltipPosition + type TooltipOptions } from 'chart.js'; import 'chartjs-adapter-date-fns'; import annotationPlugin from 'chartjs-plugin-annotation'; @@ -78,7 +79,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { @Output() benchmarkChanged = new EventEmitter(); - @ViewChild('chartCanvas') chartCanvas; + @ViewChild('chartCanvas') chartCanvas: ElementRef; public chart: Chart<'line'>; public hasPermissionToAccessAdminControl: boolean; @@ -96,8 +97,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { Tooltip ); - Tooltip.positioners['top'] = (_elements, position: TooltipPosition) => - getTooltipPositionerMapTop(this.chart, position); + registerChartConfiguration(); addIcons({ arrowForwardOutline }); } @@ -157,8 +157,10 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { if (this.chartCanvas) { if (this.chart) { this.chart.data = data; + this.chart.options.plugins ??= {}; this.chart.options.plugins.tooltip = - this.getTooltipPluginConfiguration() as unknown; + this.getTooltipPluginConfiguration(); + this.chart.update(); } else { this.chart = new Chart(this.chartCanvas.nativeElement, { @@ -196,7 +198,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { verticalHoverLine: { color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` } - } as unknown, + }, responsive: true, scales: { x: { @@ -253,7 +255,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { } } - private getTooltipPluginConfiguration() { + private getTooltipPluginConfiguration(): Partial> { return { ...getTooltipOptions({ colorScheme: this.colorScheme, @@ -261,7 +263,7 @@ export class GfBenchmarkComparatorComponent implements OnChanges, OnDestroy { unit: '%' }), mode: 'index', - position: 'top' as unknown, + position: 'top', xAlign: 'center', yAlign: 'bottom' }; diff --git a/apps/client/src/app/components/data-provider-status/data-provider-status.component.ts b/apps/client/src/app/components/data-provider-status/data-provider-status.component.ts index 0f638961c..a77d65961 100644 --- a/apps/client/src/app/components/data-provider-status/data-provider-status.component.ts +++ b/apps/client/src/app/components/data-provider-status/data-provider-status.component.ts @@ -1,16 +1,17 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; +import { DataService } from '@ghostfolio/ui/services'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, + DestroyRef, Input, - OnDestroy, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import type { DataSource } from '@prisma/client'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { catchError, map, type Observable, of, Subject, takeUntil } from 'rxjs'; +import { catchError, map, type Observable, of } from 'rxjs'; import { DataProviderStatus } from './interfaces/interfaces'; @@ -20,14 +21,15 @@ import { DataProviderStatus } from './interfaces/interfaces'; selector: 'gf-data-provider-status', templateUrl: './data-provider-status.component.html' }) -export class GfDataProviderStatusComponent implements OnDestroy, OnInit { +export class GfDataProviderStatusComponent implements OnInit { @Input() dataSource: DataSource; public status$: Observable; - private unsubscribeSubject = new Subject(); - - public constructor(private dataService: DataService) {} + public constructor( + private dataService: DataService, + private destroyRef: DestroyRef + ) {} public ngOnInit() { this.status$ = this.dataService @@ -39,12 +41,7 @@ export class GfDataProviderStatusComponent implements OnDestroy, OnInit { catchError(() => { return of({ isHealthy: false }); }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/footer/footer.component.html b/apps/client/src/app/components/footer/footer.component.html index 155f27f68..45626620e 100644 --- a/apps/client/src/app/components/footer/footer.component.html +++ b/apps/client/src/app/components/footer/footer.component.html @@ -122,7 +122,9 @@ -->
  • - Chinese + Chinese (简体中文)
  • Deutsch @@ -139,6 +141,13 @@
  • Italiano
  • +
  • Nederlands
  • @@ -153,7 +162,9 @@ diff --git a/apps/client/src/app/components/header/header.component.ts b/apps/client/src/app/components/header/header.component.ts index b7bf4cb98..ab329251f 100644 --- a/apps/client/src/app/components/header/header.component.ts +++ b/apps/client/src/app/components/header/header.component.ts @@ -1,7 +1,6 @@ import { LoginWithAccessTokenDialogParams } from '@ghostfolio/client/components/login-with-access-token-dialog/interfaces/interfaces'; import { GfLoginWithAccessTokenDialogComponent } from '@ghostfolio/client/components/login-with-access-token-dialog/login-with-access-token-dialog.component'; import { LayoutService } from '@ghostfolio/client/core/layout.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { KEY_STAY_SIGNED_IN, @@ -18,12 +17,14 @@ import { GfAssistantComponent } from '@ghostfolio/ui/assistant/assistant.compone import { GfLogoComponent } from '@ghostfolio/ui/logo'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, + DestroyRef, EventEmitter, HostListener, Input, @@ -31,6 +32,7 @@ import { Output, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatBadgeModule } from '@angular/material/badge'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; @@ -48,8 +50,8 @@ import { radioButtonOffOutline, radioButtonOnOutline } from 'ionicons/icons'; -import { EMPTY, Subject } from 'rxjs'; -import { catchError, takeUntil } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { catchError } from 'rxjs/operators'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -131,10 +133,9 @@ export class GfHeaderComponent implements OnChanges { public routerLinkRegister = publicRoutes.register.routerLink; public routerLinkResources = publicRoutes.resources.routerLink; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, + private destroyRef: DestroyRef, private dialog: MatDialog, private impersonationStorageService: ImpersonationStorageService, private layoutService: LayoutService, @@ -146,7 +147,7 @@ export class GfHeaderComponent implements OnChanges { ) { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; this.impersonationId = impersonationId; @@ -224,11 +225,11 @@ export class GfHeaderComponent implements OnChanges { public onDateRangeChange(dateRange: DateRange) { this.dataService .putUserSetting({ dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); }); } @@ -252,11 +253,11 @@ export class GfHeaderComponent implements OnChanges { this.dataService .putUserSetting(userSetting) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); }); } @@ -301,7 +302,7 @@ export class GfHeaderComponent implements OnChanges { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data) => { if (data?.accessToken) { this.dataService @@ -314,7 +315,7 @@ export class GfHeaderComponent implements OnChanges { return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(({ authToken }) => { this.setToken(authToken); @@ -331,7 +332,7 @@ export class GfHeaderComponent implements OnChanges { this.userService .get() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { const userLanguage = user?.settings?.language; @@ -342,9 +343,4 @@ export class GfHeaderComponent implements OnChanges { } }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts index 6a7129fec..4d89cfbe1 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts @@ -1,4 +1,3 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { NUMERICAL_PRECISION_THRESHOLD_3_FIGURES, @@ -26,6 +25,7 @@ import { GfHistoricalMarketDataEditorComponent } from '@ghostfolio/ui/historical import { translate } from '@ghostfolio/ui/i18n'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; import { GfPortfolioProportionChartComponent } from '@ghostfolio/ui/portfolio-proportion-chart'; +import { DataService } from '@ghostfolio/ui/services'; import { GfTagsSelectorComponent } from '@ghostfolio/ui/tags-selector'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -116,11 +116,11 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { }; public dataProviderInfo: DataProviderInfo; public dataSource: MatTableDataSource; + public dateOfFirstActivity: string; public dividendInBaseCurrency: number; public dividendInBaseCurrencyPrecision = 2; public dividendYieldPercentWithCurrencyEffect: number; public feeInBaseCurrency: number; - public firstBuyDate: string; public hasPermissionToCreateOwnTag: boolean; public hasPermissionToReadMarketDataOfOwnAssetProfile: boolean; public historicalDataItems: LineChartItem[]; @@ -267,10 +267,10 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { activitiesCount, averagePrice, dataProviderInfo, + dateOfFirstActivity, dividendInBaseCurrency, dividendYieldPercentWithCurrencyEffect, feeInBaseCurrency, - firstBuyDate, historicalData, investmentInBaseCurrencyWithCurrencyEffect, marketPrice, @@ -298,6 +298,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { this.benchmarkDataItems = []; this.countries = {}; this.dataProviderInfo = dataProviderInfo; + this.dateOfFirstActivity = dateOfFirstActivity; this.dividendInBaseCurrency = dividendInBaseCurrency; if ( @@ -312,7 +313,6 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { dividendYieldPercentWithCurrencyEffect; this.feeInBaseCurrency = feeInBaseCurrency; - this.firstBuyDate = firstBuyDate; this.hasPermissionToReadMarketDataOfOwnAssetProfile = hasPermission( @@ -461,16 +461,16 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { } } - if (isToday(parseISO(this.firstBuyDate))) { + if (isToday(parseISO(this.dateOfFirstActivity))) { // Add average price this.historicalDataItems.push({ - date: this.firstBuyDate, + date: this.dateOfFirstActivity, value: this.averagePrice }); // Add benchmark 1 this.benchmarkDataItems.push({ - date: this.firstBuyDate, + date: this.dateOfFirstActivity, value: averagePrice }); @@ -501,7 +501,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { if ( this.benchmarkDataItems[0]?.value === undefined && - isSameMonth(parseISO(this.firstBuyDate), new Date()) + isSameMonth(parseISO(this.dateOfFirstActivity), new Date()) ) { this.benchmarkDataItems[0].value = this.averagePrice; } @@ -581,7 +581,7 @@ export class GfHoldingDetailDialogComponent implements OnDestroy, OnInit { }; this.dataService - .postOrder(activity) + .postActivity(activity) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe(() => { this.router.navigate( diff --git a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html index f52286160..15415e413 100644 --- a/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html +++ b/apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -215,7 +215,7 @@ [deviceType]="data.deviceType" [isDate]="true" [locale]="data.locale" - [value]="firstBuyDate" + [value]="dateOfFirstActivity" >First Activity @@ -377,13 +377,12 @@ @@ -400,7 +399,7 @@ diff --git a/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts index aab854384..527b13636 100644 --- a/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/holding-detail-dialog/interfaces/interfaces.ts @@ -11,7 +11,7 @@ export interface HoldingDetailDialogParams { hasPermissionToAccessAdminControl: boolean; hasPermissionToCreateActivity: boolean; hasPermissionToReportDataGlitch: boolean; - hasPermissionToUpdateOrder: boolean; + hasPermissionToUpdateActivity: boolean; locale: string; symbol: string; } diff --git a/apps/client/src/app/components/home-holdings/home-holdings.component.ts b/apps/client/src/app/components/home-holdings/home-holdings.component.ts index 33d9139ea..19a48ccd8 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.component.ts +++ b/apps/client/src/app/components/home-holdings/home-holdings.component.ts @@ -1,4 +1,3 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { @@ -11,6 +10,7 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { HoldingType, HoldingsViewMode } from '@ghostfolio/common/types'; import { GfHoldingsTableComponent } from '@ghostfolio/ui/holdings-table'; +import { DataService } from '@ghostfolio/ui/services'; import { GfToggleComponent } from '@ghostfolio/ui/toggle'; import { GfTreemapChartComponent } from '@ghostfolio/ui/treemap-chart'; @@ -19,9 +19,10 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms'; import { MatButtonModule } from '@angular/material/button'; import { MatButtonToggleModule } from '@angular/material/button-toggle'; @@ -30,8 +31,6 @@ import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { gridOutline, reorderFourOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -51,7 +50,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./home-holdings.scss'], templateUrl: './home-holdings.html' }) -export class GfHomeHoldingsComponent implements OnDestroy, OnInit { +export class GfHomeHoldingsComponent implements OnInit { public static DEFAULT_HOLDINGS_VIEW_MODE: HoldingsViewMode = 'TABLE'; public deviceType: string; @@ -71,11 +70,10 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { GfHomeHoldingsComponent.DEFAULT_HOLDINGS_VIEW_MODE ); - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private router: Router, @@ -89,13 +87,13 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -107,7 +105,7 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { this.hasPermissionToCreateActivity = hasPermission( this.user.permissions, - permissions.createOrder + permissions.createActivity ); this.initialize(); @@ -117,15 +115,15 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { }); this.viewModeFormControl.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((holdingsViewMode) => { this.dataService .putUserSetting({ holdingsViewMode }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -149,11 +147,6 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchHoldings() { const filters = this.userService.getFilters(); @@ -193,7 +186,7 @@ export class GfHomeHoldingsComponent implements OnDestroy, OnInit { this.holdings = undefined; this.fetchHoldings() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { this.holdings = holdings; 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 8b4e4c5d3..ec131cd39 100644 --- a/apps/client/src/app/components/home-holdings/home-holdings.html +++ b/apps/client/src/app/components/home-holdings/home-holdings.html @@ -46,8 +46,6 @@ }
    (); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { @@ -59,7 +57,7 @@ export class GfHomeMarketComponent implements OnDestroy, OnInit { this.info = this.dataService.fetchInfo(); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -82,7 +80,7 @@ export class GfHomeMarketComponent implements OnDestroy, OnInit { includeHistoricalData: this.numberOfDays, symbol: ghostfolioFearAndGreedIndexSymbol }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ historicalData, marketPrice }) => { this.fearAndGreedIndex = marketPrice; this.historicalDataItems = [ @@ -99,16 +97,11 @@ export class GfHomeMarketComponent implements OnDestroy, OnInit { this.dataService .fetchBenchmarks() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ benchmarks }) => { this.benchmarks = benchmarks; this.changeDetectorRef.markForCheck(); }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/home-overview/home-overview.component.ts b/apps/client/src/app/components/home-overview/home-overview.component.ts index 6c9694a19..58284d27d 100644 --- a/apps/client/src/app/components/home-overview/home-overview.component.ts +++ b/apps/client/src/app/components/home-overview/home-overview.component.ts @@ -1,6 +1,5 @@ import { GfPortfolioPerformanceComponent } from '@ghostfolio/client/components/portfolio-performance/portfolio-performance.component'; import { LayoutService } from '@ghostfolio/client/core/layout.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { NUMERICAL_PRECISION_THRESHOLD_6_FIGURES } from '@ghostfolio/common/config'; @@ -13,20 +12,20 @@ import { import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; +import { DataService } from '@ghostfolio/ui/services'; import { CommonModule } from '@angular/common'; import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { RouterModule } from '@angular/router'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -41,7 +40,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./home-overview.scss'], templateUrl: './home-overview.html' }) -export class GfHomeOverviewComponent implements OnDestroy, OnInit { +export class GfHomeOverviewComponent implements OnInit { public deviceType: string; public errors: AssetProfileIdentifier[]; public hasError: boolean; @@ -62,25 +61,24 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit { public unit: string; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private layoutService: LayoutService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; this.hasPermissionToCreateActivity = hasPermission( this.user.permissions, - permissions.createOrder + permissions.createActivity ); this.update(); @@ -99,7 +97,7 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; @@ -107,17 +105,12 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit { }); this.layoutService.shouldReloadContent$ - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.update(); }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private update() { this.historicalDataItems = null; this.isLoadingPerformance = true; @@ -126,7 +119,7 @@ export class GfHomeOverviewComponent implements OnDestroy, OnInit { .fetchPortfolioPerformance({ range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ chart, errors, performance }) => { this.errors = errors; this.performance = performance; diff --git a/apps/client/src/app/components/home-summary/home-summary.component.ts b/apps/client/src/app/components/home-summary/home-summary.component.ts index 845d1b448..719cfbd29 100644 --- a/apps/client/src/app/components/home-summary/home-summary.component.ts +++ b/apps/client/src/app/components/home-summary/home-summary.component.ts @@ -1,5 +1,4 @@ import { GfPortfolioSummaryComponent } from '@ghostfolio/client/components/portfolio-summary/portfolio-summary.component'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { @@ -8,19 +7,19 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatCardModule } from '@angular/material/card'; import { MatSnackBarRef, TextOnlySnackBar } from '@angular/material/snack-bar'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [GfPortfolioSummaryComponent, MatCardModule], @@ -29,7 +28,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./home-summary.scss'], templateUrl: './home-summary.html' }) -export class GfHomeSummaryComponent implements OnDestroy, OnInit { +export class GfHomeSummaryComponent implements OnInit { public deviceType: string; public hasImpersonationId: boolean; public hasPermissionForSubscription: boolean; @@ -40,11 +39,10 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { public summary: PortfolioSummary; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private userService: UserService @@ -57,7 +55,7 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { ); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -77,7 +75,7 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); @@ -86,11 +84,11 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { public onChangeEmergencyFund(emergencyFund: number) { this.dataService .putUserSetting({ emergencyFund }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -99,17 +97,12 @@ export class GfHomeSummaryComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private update() { this.isLoading = true; this.dataService .fetchPortfolioDetails() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ summary }) => { this.summary = summary; this.isLoading = false; diff --git a/apps/client/src/app/components/home-watchlist/home-watchlist.component.ts b/apps/client/src/app/components/home-watchlist/home-watchlist.component.ts index ab43e54dd..4adb4e54f 100644 --- a/apps/client/src/app/components/home-watchlist/home-watchlist.component.ts +++ b/apps/client/src/app/components/home-watchlist/home-watchlist.component.ts @@ -1,4 +1,3 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { @@ -9,6 +8,7 @@ import { import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectionStrategy, 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 5492ddd4c..53d4f5693 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 @@ -1,6 +1,5 @@ import { getTooltipOptions, - getTooltipPositionerMapTop, getVerticalHoverLinePlugin, transformTickToAbbreviation } from '@ghostfolio/common/chart-helper'; @@ -15,11 +14,13 @@ import { import { LineChartItem } from '@ghostfolio/common/interfaces'; import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface'; import { ColorScheme, GroupBy } from '@ghostfolio/common/types'; +import { registerChartConfiguration } from '@ghostfolio/ui/chart'; import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, + type ElementRef, Input, OnChanges, OnDestroy, @@ -34,12 +35,15 @@ import { LineController, LineElement, PointElement, + type ScriptableLineSegmentContext, TimeScale, Tooltip, - TooltipPosition + type TooltipOptions } from 'chart.js'; import 'chartjs-adapter-date-fns'; -import annotationPlugin from 'chartjs-plugin-annotation'; +import annotationPlugin, { + type AnnotationOptions +} from 'chartjs-plugin-annotation'; import { isAfter } from 'date-fns'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; @@ -62,7 +66,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { @Input() locale = getLocale(); @Input() savingsRate = 0; - @ViewChild('chartCanvas') chartCanvas; + @ViewChild('chartCanvas') chartCanvas: ElementRef; public chart: Chart<'bar' | 'line'>; private investments: InvestmentItem[]; @@ -81,8 +85,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { Tooltip ); - Tooltip.positioners['top'] = (_elements, position: TooltipPosition) => - getTooltipPositionerMapTop(this.chart, position); + registerChartConfiguration(); } public ngOnChanges() { @@ -121,12 +124,12 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { }), label: this.benchmarkDataLabel, segment: { - borderColor: (context: unknown) => + borderColor: (context) => this.isInFuture( context, `rgba(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b}, 0.67)` ), - borderDash: (context: unknown) => this.isInFuture(context, [2, 2]) + borderDash: (context) => this.isInFuture(context, [2, 2]) }, stepped: true }, @@ -143,12 +146,12 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { label: $localize`Total Amount`, pointRadius: 0, segment: { - borderColor: (context: unknown) => + borderColor: (context) => this.isInFuture( context, `rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.67)` ), - borderDash: (context: unknown) => this.isInFuture(context, [2, 2]) + borderDash: (context) => this.isInFuture(context, [2, 2]) } } ] @@ -157,17 +160,14 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { if (this.chartCanvas) { if (this.chart) { this.chart.data = chartData; + this.chart.options.plugins ??= {}; this.chart.options.plugins.tooltip = - this.getTooltipPluginConfiguration() as unknown; + this.getTooltipPluginConfiguration(); - if ( - this.savingsRate && - // @ts-ignore - this.chart.options.plugins.annotation.annotations.savingsRate - ) { - // @ts-ignore - this.chart.options.plugins.annotation.annotations.savingsRate.value = - this.savingsRate; + const annotations = this.chart.options.plugins.annotation + .annotations as Record>; + if (this.savingsRate && annotations.savingsRate) { + annotations.savingsRate.value = this.savingsRate; } this.chart.update(); @@ -201,7 +201,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { color: 'white', content: $localize`Savings Rate`, display: true, - font: { size: '10px', weight: 'normal' }, + font: { size: 10, weight: 'normal' }, padding: { x: 4, y: 2 @@ -229,7 +229,7 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { verticalHoverLine: { color: `rgba(${getTextColor(this.colorScheme)}, 0.1)` } - } as unknown, + }, responsive: true, scales: { x: { @@ -286,7 +286,9 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { } } - private getTooltipPluginConfiguration() { + private getTooltipPluginConfiguration(): Partial< + TooltipOptions<'bar' | 'line'> + > { return { ...getTooltipOptions({ colorScheme: this.colorScheme, @@ -296,13 +298,13 @@ export class GfInvestmentChartComponent implements OnChanges, OnDestroy { unit: this.isInPercent ? '%' : undefined }), mode: 'index', - position: 'top' as unknown, + position: 'top', xAlign: 'center', yAlign: 'bottom' }; } - private isInFuture(aContext: any, aValue: T) { + private isInFuture(aContext: ScriptableLineSegmentContext, aValue: T) { return isAfter(new Date(aContext?.p1?.parsed?.x), new Date()) ? aValue : undefined; diff --git a/apps/client/src/app/components/markets/markets.component.ts b/apps/client/src/app/components/markets/markets.component.ts index a7f83216f..4b83e897f 100644 --- a/apps/client/src/app/components/markets/markets.component.ts +++ b/apps/client/src/app/components/markets/markets.component.ts @@ -1,5 +1,4 @@ import { GfFearAndGreedIndexComponent } from '@ghostfolio/client/components/fear-and-greed-index/fear-and-greed-index.component'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { resetHours } from '@ghostfolio/common/helper'; import { @@ -12,6 +11,7 @@ import { import { FearAndGreedIndexMode } from '@ghostfolio/common/types'; import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; +import { DataService } from '@ghostfolio/ui/services'; import { GfToggleComponent } from '@ghostfolio/ui/toggle'; import { diff --git a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html index 46eb2845c..0e26a49a8 100644 --- a/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html +++ b/apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html @@ -65,7 +65,11 @@ [locale]="locale" [precision]="precision" [unit]="baseCurrency" - [value]="isLoading ? undefined : summary?.committedFunds" + [value]=" + isLoading + ? undefined + : summary?.totalInvestmentValueWithCurrencyEffect + " />
    @@ -180,18 +184,21 @@ [ngClass]="{ 'cursor-pointer': hasPermissionToUpdateUserSettings && + !user?.settings?.isRestrictedView && user?.subscription?.type !== 'Basic' }" (click)=" hasPermissionToUpdateUserSettings && + !user?.settings?.isRestrictedView && user?.subscription?.type !== 'Basic' && onEditEmergencyFund() " > @if ( hasPermissionToUpdateUserSettings && - user?.subscription?.type !== 'Basic' && - !isLoading + !isLoading && + !user?.settings?.isRestrictedView && + user?.subscription?.type !== 'Basic' ) { (); private deviceType: string; - private unsubscribeSubject = new Subject(); - public constructor( + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog ) { @@ -94,7 +94,7 @@ export class GfRuleComponent implements OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((settings: RuleSettings) => { if (settings) { this.ruleUpdated.emit({ @@ -115,9 +115,4 @@ export class GfRuleComponent implements OnInit { this.ruleUpdated.emit(settings); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts index 05c047dc6..5c87b2f63 100644 --- a/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts +++ b/apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts @@ -1,7 +1,7 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { CreateAccessDto, UpdateAccessDto } from '@ghostfolio/common/dtos'; import { validateObjectForForm } from '@ghostfolio/common/utils'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectionStrategy, diff --git a/apps/client/src/app/components/user-account-access/user-account-access.component.ts b/apps/client/src/app/components/user-account-access/user-account-access.component.ts index 11960b8aa..4f744a087 100644 --- a/apps/client/src/app/components/user-account-access/user-account-access.component.ts +++ b/apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -1,6 +1,4 @@ import { GfAccessTableComponent } from '@ghostfolio/client/components/access-table/access-table.component'; -import { DataService } from '@ghostfolio/client/services/data.service'; -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { CreateAccessDto } from '@ghostfolio/common/dtos'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; @@ -8,6 +6,7 @@ import { Access, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectionStrategy, @@ -76,7 +75,6 @@ export class GfUserAccountAccessComponent implements OnDestroy, OnInit { private notificationService: NotificationService, private route: ActivatedRoute, private router: Router, - private tokenStorageService: TokenStorageService, private userService: UserService ) { const { globalPermissions } = this.dataService.fetchInfo(); @@ -161,8 +159,7 @@ export class GfUserAccountAccessComponent implements OnDestroy, OnInit { .subscribe(({ accessToken }) => { this.notificationService.alert({ discardFn: () => { - this.tokenStorageService.signOut(); - this.userService.remove(); + this.userService.signOut(); document.location.href = `/${document.documentElement.lang}`; }, diff --git a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts index 8eec9c188..92fd0d590 100644 --- a/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts +++ b/apps/client/src/app/components/user-account-membership/user-account-membership.component.ts @@ -1,4 +1,3 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; import { getDateFormatString } from '@ghostfolio/common/helper'; @@ -8,6 +7,7 @@ import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { GfMembershipCardComponent } from '@ghostfolio/ui/membership-card'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; import { CommonModule } from '@angular/common'; import { diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts index fa0e10ab2..41e1e0faa 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.component.ts @@ -1,4 +1,3 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { KEY_STAY_SIGNED_IN, KEY_TOKEN, @@ -13,6 +12,7 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectionStrategy, @@ -93,6 +93,7 @@ export class GfUserAccountSettingsComponent implements OnDestroy, OnInit { 'es', 'fr', 'it', + 'ko', 'nl', 'pl', 'pt', @@ -301,8 +302,7 @@ export class GfUserAccountSettingsComponent implements OnDestroy, OnInit { takeUntil(this.unsubscribeSubject) ) .subscribe(() => { - this.tokenStorageService.signOut(); - this.userService.remove(); + this.userService.signOut(); document.location.href = `/${document.documentElement.lang}`; }); diff --git a/apps/client/src/app/components/user-account-settings/user-account-settings.html b/apps/client/src/app/components/user-account-settings/user-account-settings.html index 1c86a51f6..51df2a13b 100644 --- a/apps/client/src/app/components/user-account-settings/user-account-settings.html +++ b/apps/client/src/app/components/user-account-settings/user-account-settings.html @@ -87,7 +87,8 @@ > } Chinese (CommunityChinese / 简体中文 (Community) Italiano (Community) + @if (user?.settings?.isExperimentalFeatures) { + Korean / 한국어 (Community) + } Nederlands (Community) @if (user?.settings?.isExperimentalFeatures) { Українська (CommunityUkrainian / Українська (Community) } diff --git a/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts b/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts index b922e7a54..ed46e8a02 100644 --- a/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts +++ b/apps/client/src/app/components/user-detail-dialog/interfaces/interfaces.ts @@ -1,4 +1,5 @@ export interface UserDetailDialogParams { + currentUserId: string; deviceType: string; hasPermissionForSubscription: boolean; locale: string; diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts index 248fd48f3..6f7f4ead6 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.component.ts @@ -1,7 +1,5 @@ -import { AdminService } from '@ghostfolio/client/services/admin.service'; import { AdminUserResponse } from '@ghostfolio/common/interfaces'; -import { GfDialogFooterComponent } from '@ghostfolio/ui/dialog-footer'; -import { GfDialogHeaderComponent } from '@ghostfolio/ui/dialog-header'; +import { AdminService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { @@ -16,6 +14,10 @@ import { import { MatButtonModule } from '@angular/material/button'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog'; +import { MatMenuModule } from '@angular/material/menu'; +import { IonIcon } from '@ionic/angular/standalone'; +import { addIcons } from 'ionicons'; +import { ellipsisVertical } from 'ionicons/icons'; import { EMPTY, Subject } from 'rxjs'; import { catchError, takeUntil } from 'rxjs/operators'; @@ -25,11 +27,11 @@ import { UserDetailDialogParams } from './interfaces/interfaces'; changeDetection: ChangeDetectionStrategy.OnPush, host: { class: 'd-flex flex-column h-100' }, imports: [ - GfDialogFooterComponent, - GfDialogHeaderComponent, GfValueComponent, + IonIcon, MatButtonModule, - MatDialogModule + MatDialogModule, + MatMenuModule ], schemas: [CUSTOM_ELEMENTS_SCHEMA], selector: 'gf-user-detail-dialog', @@ -46,7 +48,11 @@ export class GfUserDetailDialogComponent implements OnDestroy, OnInit { private changeDetectorRef: ChangeDetectorRef, @Inject(MAT_DIALOG_DATA) public data: UserDetailDialogParams, public dialogRef: MatDialogRef - ) {} + ) { + addIcons({ + ellipsisVertical + }); + } public ngOnInit() { this.adminService @@ -66,6 +72,13 @@ export class GfUserDetailDialogComponent implements OnDestroy, OnInit { }); } + public deleteUser() { + this.dialogRef.close({ + action: 'delete', + userId: this.data.userId + }); + } + public onClose() { this.dialogRef.close(); } diff --git a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html index 60f6a2585..570dcf4d6 100644 --- a/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html +++ b/apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html @@ -1,9 +1,28 @@ - - +
    + + + + +
    @@ -103,7 +122,8 @@
    - +
    + +
    diff --git a/apps/client/src/app/core/auth.guard.ts b/apps/client/src/app/core/auth.guard.ts index c26419031..3292f0ff7 100644 --- a/apps/client/src/app/core/auth.guard.ts +++ b/apps/client/src/app/core/auth.guard.ts @@ -1,7 +1,7 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { SettingsStorageService } from '@ghostfolio/client/services/settings-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { internalRoutes, publicRoutes } from '@ghostfolio/common/routes/routes'; +import { DataService } from '@ghostfolio/ui/services'; import { Injectable } from '@angular/core'; import { @@ -68,7 +68,7 @@ export class AuthGuard { this.dataService .putUserSetting({ language: document.documentElement.lang }) .subscribe(() => { - this.userService.remove(); + this.userService.reset(); setTimeout(() => { window.location.reload(); diff --git a/apps/client/src/app/core/http-response.interceptor.ts b/apps/client/src/app/core/http-response.interceptor.ts index c2eef4175..315e9d64e 100644 --- a/apps/client/src/app/core/http-response.interceptor.ts +++ b/apps/client/src/app/core/http-response.interceptor.ts @@ -1,8 +1,8 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; -import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; +import { UserService } from '@ghostfolio/client/services/user/user.service'; import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; import { InfoItem } from '@ghostfolio/common/interfaces'; import { internalRoutes, publicRoutes } from '@ghostfolio/common/routes/routes'; +import { DataService } from '@ghostfolio/ui/services'; import { HTTP_INTERCEPTORS, @@ -32,8 +32,8 @@ export class HttpResponseInterceptor implements HttpInterceptor { public constructor( private dataService: DataService, private router: Router, - private tokenStorageService: TokenStorageService, private snackBar: MatSnackBar, + private userService: UserService, private webAuthnService: WebAuthnService ) { this.info = this.dataService.fetchInfo(); @@ -115,7 +115,7 @@ export class HttpResponseInterceptor implements HttpInterceptor { if (this.webAuthnService.isEnabled()) { this.router.navigate(internalRoutes.webauthn.routerLink); } else { - this.tokenStorageService.signOut(); + this.userService.signOut(); } } } diff --git a/apps/client/src/app/pages/about/about-page.component.ts b/apps/client/src/app/pages/about/about-page.component.ts index 4fe6a57e3..1e749d1cd 100644 --- a/apps/client/src/app/pages/about/about-page.component.ts +++ b/apps/client/src/app/pages/about/about-page.component.ts @@ -1,16 +1,17 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; @@ -24,8 +25,6 @@ import { sparklesOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page has-tabs' }, @@ -35,17 +34,16 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./about-page.scss'], templateUrl: './about-page.html' }) -export class AboutPageComponent implements OnDestroy, OnInit { +export class AboutPageComponent implements OnInit { public deviceType: string; public hasPermissionForSubscription: boolean; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { @@ -57,7 +55,7 @@ export class AboutPageComponent implements OnDestroy, OnInit { ); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { this.tabs = [ { @@ -118,9 +116,4 @@ export class AboutPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/about/changelog/changelog-page.component.ts b/apps/client/src/app/pages/about/changelog/changelog-page.component.ts index 69b397370..d7f583bd1 100644 --- a/apps/client/src/app/pages/about/changelog/changelog-page.component.ts +++ b/apps/client/src/app/pages/about/changelog/changelog-page.component.ts @@ -1,7 +1,6 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; @Component({ imports: [MarkdownModule, NgxSkeletonLoaderModule], @@ -9,17 +8,10 @@ import { Subject } from 'rxjs'; styleUrls: ['./changelog-page.scss'], templateUrl: './changelog-page.html' }) -export class GfChangelogPageComponent implements OnDestroy { +export class GfChangelogPageComponent { public isLoading = true; - private unsubscribeSubject = new Subject(); - public onLoad() { this.isLoading = false; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/about/license/license-page.component.ts b/apps/client/src/app/pages/about/license/license-page.component.ts index 0dc5b2f51..d530d0418 100644 --- a/apps/client/src/app/pages/about/license/license-page.component.ts +++ b/apps/client/src/app/pages/about/license/license-page.component.ts @@ -1,6 +1,5 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; -import { Subject } from 'rxjs'; @Component({ imports: [MarkdownModule], @@ -8,11 +7,4 @@ import { Subject } from 'rxjs'; styleUrls: ['./license-page.scss'], templateUrl: './license-page.html' }) -export class GfLicensePageComponent implements OnDestroy { - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} +export class GfLicensePageComponent {} diff --git a/apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts b/apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts index bdbbdf9a7..c2e500a52 100644 --- a/apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts +++ b/apps/client/src/app/pages/about/oss-friends/oss-friends-page.component.ts @@ -1,10 +1,9 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { arrowForwardOutline } from 'ionicons/icons'; -import { Subject } from 'rxjs'; const ossFriends = require('../../../../assets/oss-friends.json'); @@ -14,17 +13,10 @@ const ossFriends = require('../../../../assets/oss-friends.json'); styleUrls: ['./oss-friends-page.scss'], templateUrl: './oss-friends-page.html' }) -export class GfOpenSourceSoftwareFriendsPageComponent implements OnDestroy { +export class GfOpenSourceSoftwareFriendsPageComponent { public ossFriends = ossFriends.data; - private unsubscribeSubject = new Subject(); - public constructor() { addIcons({ arrowForwardOutline }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/about/overview/about-overview-page.component.ts b/apps/client/src/app/pages/about/overview/about-overview-page.component.ts index d315f2cbd..9c399762b 100644 --- a/apps/client/src/app/pages/about/overview/about-overview-page.component.ts +++ b/apps/client/src/app/pages/about/overview/about-overview-page.component.ts @@ -1,17 +1,18 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { DataService } from '@ghostfolio/ui/services'; import { CommonModule } from '@angular/common'; import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; @@ -23,8 +24,6 @@ import { logoX, mail } from 'ionicons/icons'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [CommonModule, IonIcon, MatButtonModule, RouterModule], @@ -33,7 +32,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./about-overview-page.scss'], templateUrl: './about-overview-page.html' }) -export class GfAboutOverviewPageComponent implements OnDestroy, OnInit { +export class GfAboutOverviewPageComponent implements OnInit { public hasPermissionForStatistics: boolean; public hasPermissionForSubscription: boolean; public isLoggedIn: boolean; @@ -43,11 +42,10 @@ export class GfAboutOverviewPageComponent implements OnDestroy, OnInit { public routerLinkOpenStartup = publicRoutes.openStartup.routerLink; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private userService: UserService ) { const { globalPermissions } = this.dataService.fetchInfo(); @@ -67,7 +65,7 @@ export class GfAboutOverviewPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -76,9 +74,4 @@ export class GfAboutOverviewPageComponent implements OnDestroy, OnInit { } }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/about/overview/about-overview-page.html b/apps/client/src/app/pages/about/overview/about-overview-page.html index 185becba7..cab1caa23 100644 --- a/apps/client/src/app/pages/about/overview/about-overview-page.html +++ b/apps/client/src/app/pages/about/overview/about-overview-page.html @@ -207,18 +207,20 @@

    Sponsors

    - Browser testing via -
    +
    Browser testing via
    LambdaTest Logo
    diff --git a/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts b/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts index 78881cd2c..50e4e3e2f 100644 --- a/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts +++ b/apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.component.ts @@ -1,6 +1,5 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; -import { Subject } from 'rxjs'; @Component({ imports: [MarkdownModule], @@ -8,11 +7,4 @@ import { Subject } from 'rxjs'; styleUrls: ['./privacy-policy-page.scss'], templateUrl: './privacy-policy-page.html' }) -export class GfPrivacyPolicyPageComponent implements OnDestroy { - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} +export class GfPrivacyPolicyPageComponent {} diff --git a/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.component.ts b/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.component.ts index dbf07ef19..7899f0187 100644 --- a/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.component.ts +++ b/apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.component.ts @@ -1,6 +1,5 @@ -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MarkdownModule } from 'ngx-markdown'; -import { Subject } from 'rxjs'; @Component({ imports: [MarkdownModule], @@ -8,11 +7,4 @@ import { Subject } from 'rxjs'; styleUrls: ['./terms-of-service-page.scss'], templateUrl: './terms-of-service-page.html' }) -export class GfTermsOfServicePageComponent implements OnDestroy { - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} +export class GfTermsOfServicePageComponent {} diff --git a/apps/client/src/app/pages/accounts/accounts-page.component.ts b/apps/client/src/app/pages/accounts/accounts-page.component.ts index 2b496e4fb..fdc78a8c4 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.component.ts +++ b/apps/client/src/app/pages/accounts/accounts-page.component.ts @@ -1,6 +1,5 @@ import { GfAccountDetailDialogComponent } from '@ghostfolio/client/components/account-detail-dialog/account-detail-dialog.component'; import { AccountDetailDialogParams } from '@ghostfolio/client/components/account-detail-dialog/interfaces/interfaces'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { @@ -12,8 +11,15 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { GfAccountsTableComponent } from '@ghostfolio/ui/accounts-table'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { DataService } from '@ghostfolio/ui/services'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatDialog } from '@angular/material/dialog'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; @@ -21,8 +27,8 @@ import { Account as AccountModel } from '@prisma/client'; import { addIcons } from 'ionicons'; import { addOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { EMPTY, Subject, Subscription } from 'rxjs'; -import { catchError, takeUntil } from 'rxjs/operators'; +import { EMPTY, Subscription } from 'rxjs'; +import { catchError } from 'rxjs/operators'; import { GfCreateOrUpdateAccountDialogComponent } from './create-or-update-account-dialog/create-or-update-account-dialog.component'; import { CreateOrUpdateAccountDialogParams } from './create-or-update-account-dialog/interfaces/interfaces'; @@ -36,8 +42,9 @@ import { GfTransferBalanceDialogComponent } from './transfer-balance/transfer-ba styleUrls: ['./accounts-page.scss'], templateUrl: './accounts-page.html' }) -export class GfAccountsPageComponent implements OnDestroy, OnInit { +export class GfAccountsPageComponent implements OnInit { public accounts: AccountModel[]; + public activitiesCount = 0; public deviceType: string; public hasImpersonationId: boolean; public hasPermissionToCreateAccount: boolean; @@ -45,14 +52,12 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { public routeQueryParams: Subscription; public totalBalanceInBaseCurrency = 0; public totalValueInBaseCurrency = 0; - public transactionCount = 0; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private impersonationStorageService: ImpersonationStorageService, @@ -62,7 +67,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { private userService: UserService ) { this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['accountId'] && params['accountDetailDialog']) { this.openAccountDetailDialog(params['accountId']); @@ -94,13 +99,13 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -124,18 +129,18 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { public fetchAccounts() { this.dataService .fetchAccounts() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( ({ accounts, + activitiesCount, totalBalanceInBaseCurrency, - totalValueInBaseCurrency, - transactionCount + totalValueInBaseCurrency }) => { this.accounts = accounts; + this.activitiesCount = activitiesCount; this.totalBalanceInBaseCurrency = totalBalanceInBaseCurrency; this.totalValueInBaseCurrency = totalValueInBaseCurrency; - this.transactionCount = transactionCount; if (this.accounts?.length <= 0) { this.router.navigate([], { queryParams: { createDialog: true } }); @@ -151,11 +156,11 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { this.dataService .deleteAccount(aId) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchAccounts(); @@ -204,18 +209,18 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((account: UpdateAccountDto | null) => { if (account) { this.reset(); this.dataService .putAccount(account) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchAccounts(); @@ -228,11 +233,6 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private openAccountDetailDialog(aAccountId: string) { const dialogRef = this.dialog.open< GfAccountDetailDialogComponent, @@ -245,7 +245,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { hasImpersonationId: this.hasImpersonationId, hasPermissionToCreateActivity: !this.hasImpersonationId && - hasPermission(this.user?.permissions, permissions.createOrder) && + hasPermission(this.user?.permissions, permissions.createActivity) && !this.user?.settings?.isRestrictedView }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', @@ -254,7 +254,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.fetchAccounts(); @@ -284,18 +284,18 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((account: CreateAccountDto | null) => { if (account) { this.reset(); this.dataService .postAccount(account) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.fetchAccounts(); @@ -321,7 +321,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((data: any) => { if (data) { this.reset(); @@ -343,7 +343,7 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { return EMPTY; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe(() => { this.fetchAccounts(); @@ -358,8 +358,8 @@ export class GfAccountsPageComponent implements OnDestroy, OnInit { private reset() { this.accounts = undefined; + this.activitiesCount = 0; this.totalBalanceInBaseCurrency = 0; this.totalValueInBaseCurrency = 0; - this.transactionCount = 0; } } diff --git a/apps/client/src/app/pages/accounts/accounts-page.html b/apps/client/src/app/pages/accounts/accounts-page.html index 6f29a4f7c..3d9d7ee5c 100644 --- a/apps/client/src/app/pages/accounts/accounts-page.html +++ b/apps/client/src/app/pages/accounts/accounts-page.html @@ -4,8 +4,8 @@

    Accounts

    ; public platforms: Platform[] = []; - private unsubscribeSubject = new Subject(); - public constructor( @Inject(MAT_DIALOG_DATA) public data: CreateOrUpdateAccountDialogParams, private dataService: DataService, @@ -170,11 +163,6 @@ export class GfCreateOrUpdateAccountDialogComponent implements OnDestroy { } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private autocompleteObjectValidator(): ValidatorFn { return (control: AbstractControl) => { if (control.value && typeof control.value === 'string') { diff --git a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts index 85d2e60bf..34a66b156 100644 --- a/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts +++ b/apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.component.ts @@ -1,12 +1,7 @@ import { TransferBalanceDto } from '@ghostfolio/common/dtos'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; -import { - ChangeDetectionStrategy, - Component, - Inject, - OnDestroy -} from '@angular/core'; +import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'; import { AbstractControl, FormBuilder, @@ -25,7 +20,6 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { Account } from '@prisma/client'; -import { Subject } from 'rxjs'; import { TransferBalanceDialogParams } from './interfaces/interfaces'; @@ -45,13 +39,11 @@ import { TransferBalanceDialogParams } from './interfaces/interfaces'; styleUrls: ['./transfer-balance-dialog.scss'], templateUrl: 'transfer-balance-dialog.html' }) -export class GfTransferBalanceDialogComponent implements OnDestroy { +export class GfTransferBalanceDialogComponent { public accounts: Account[] = []; public currency: string; public transferBalanceForm: FormGroup; - private unsubscribeSubject = new Subject(); - public constructor( @Inject(MAT_DIALOG_DATA) public data: TransferBalanceDialogParams, public dialogRef: MatDialogRef, @@ -93,11 +85,6 @@ export class GfTransferBalanceDialogComponent implements OnDestroy { this.dialogRef.close({ account }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private compareAccounts(control: AbstractControl): ValidationErrors { const accountFrom = control.get('fromAccount'); const accountTo = control.get('toAccount'); diff --git a/apps/client/src/app/pages/admin/admin-page.component.ts b/apps/client/src/app/pages/admin/admin-page.component.ts index b9243dcb9..284d3c41d 100644 --- a/apps/client/src/app/pages/admin/admin-page.component.ts +++ b/apps/client/src/app/pages/admin/admin-page.component.ts @@ -1,7 +1,7 @@ import { TabConfiguration } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; @@ -14,7 +14,6 @@ import { settingsOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page has-tabs' }, @@ -23,12 +22,10 @@ import { Subject } from 'rxjs'; styleUrls: ['./admin-page.scss'], templateUrl: './admin-page.html' }) -export class AdminPageComponent implements OnDestroy, OnInit { +export class AdminPageComponent implements OnInit { public deviceType: string; public tabs: TabConfiguration[] = []; - private unsubscribeSubject = new Subject(); - public constructor(private deviceService: DeviceDetectorService) { addIcons({ flashOutline, @@ -74,9 +71,4 @@ export class AdminPageComponent implements OnDestroy, OnInit { } ]; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/auth/auth-page.component.ts b/apps/client/src/app/pages/auth/auth-page.component.ts index 082401d6d..1b0b4a67c 100644 --- a/apps/client/src/app/pages/auth/auth-page.component.ts +++ b/apps/client/src/app/pages/auth/auth-page.component.ts @@ -4,20 +4,18 @@ import { } from '@ghostfolio/client/services/settings-storage.service'; import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ActivatedRoute, Router } from '@angular/router'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ selector: 'gf-auth-page', styleUrls: ['./auth-page.scss'], templateUrl: './auth-page.html' }) -export class GfAuthPageComponent implements OnDestroy, OnInit { - private unsubscribeSubject = new Subject(); - +export class GfAuthPageComponent implements OnInit { public constructor( + private destroyRef: DestroyRef, private route: ActivatedRoute, private router: Router, private settingsStorageService: SettingsStorageService, @@ -26,7 +24,7 @@ export class GfAuthPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.route.params - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { const jwt = params['jwt']; @@ -38,9 +36,4 @@ export class GfAuthPageComponent implements OnDestroy, OnInit { this.router.navigate(['/']); }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/blog/blog-page.component.ts b/apps/client/src/app/pages/blog/blog-page.component.ts index 9977e6df4..7f2c56d2d 100644 --- a/apps/client/src/app/pages/blog/blog-page.component.ts +++ b/apps/client/src/app/pages/blog/blog-page.component.ts @@ -1,13 +1,12 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { DataService } from '@ghostfolio/ui/services'; -import { Component, CUSTOM_ELEMENTS_SCHEMA, OnDestroy } from '@angular/core'; +import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { chevronForwardOutline } from 'ionicons/icons'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -17,11 +16,9 @@ import { Subject } from 'rxjs'; styleUrls: ['./blog-page.scss'], templateUrl: './blog-page.html' }) -export class GfBlogPageComponent implements OnDestroy { +export class GfBlogPageComponent { public hasPermissionForSubscription: boolean; - private unsubscribeSubject = new Subject(); - public constructor(private dataService: DataService) { const info = this.dataService.fetchInfo(); @@ -32,9 +29,4 @@ export class GfBlogPageComponent implements OnDestroy { addIcons({ chevronForwardOutline }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/demo/demo-page.component.ts b/apps/client/src/app/pages/demo/demo-page.component.ts index 9eba64788..235805dcc 100644 --- a/apps/client/src/app/pages/demo/demo-page.component.ts +++ b/apps/client/src/app/pages/demo/demo-page.component.ts @@ -1,11 +1,10 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { TokenStorageService } from '@ghostfolio/client/services/token-storage.service'; import { InfoItem } from '@ghostfolio/common/interfaces'; import { NotificationService } from '@ghostfolio/ui/notifications'; +import { DataService } from '@ghostfolio/ui/services'; -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { Router } from '@angular/router'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -13,11 +12,9 @@ import { Subject } from 'rxjs'; standalone: true, templateUrl: './demo-page.html' }) -export class GfDemoPageComponent implements OnDestroy { +export class GfDemoPageComponent { public info: InfoItem; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, private notificationService: NotificationService, @@ -40,9 +37,4 @@ export class GfDemoPageComponent implements OnDestroy { this.router.navigate(['/']); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/faq/faq-page.component.ts b/apps/client/src/app/pages/faq/faq-page.component.ts index cba9e19f1..83171254a 100644 --- a/apps/client/src/app/pages/faq/faq-page.component.ts +++ b/apps/client/src/app/pages/faq/faq-page.component.ts @@ -1,21 +1,15 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { TabConfiguration } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { DataService } from '@ghostfolio/ui/services'; -import { - CUSTOM_ELEMENTS_SCHEMA, - Component, - OnDestroy, - OnInit -} from '@angular/core'; +import { CUSTOM_ELEMENTS_SCHEMA, Component, OnInit } from '@angular/core'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { cloudyOutline, readerOutline, serverOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page has-tabs' }, @@ -25,13 +19,11 @@ import { Subject } from 'rxjs'; styleUrls: ['./faq-page.scss'], templateUrl: './faq-page.html' }) -export class GfFaqPageComponent implements OnDestroy, OnInit { +export class GfFaqPageComponent implements OnInit { public deviceType: string; public hasPermissionForSubscription: boolean; public tabs: TabConfiguration[] = []; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, private deviceService: DeviceDetectorService @@ -68,9 +60,4 @@ export class GfFaqPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts index ed1d74395..f2468c7d4 100644 --- a/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts +++ b/apps/client/src/app/pages/faq/self-hosting/self-hosting-page.component.ts @@ -1,10 +1,9 @@ import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; -import { CUSTOM_ELEMENTS_SCHEMA, Component, OnDestroy } from '@angular/core'; +import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -14,13 +13,6 @@ import { Subject } from 'rxjs'; styleUrls: ['./self-hosting-page.scss'], templateUrl: './self-hosting-page.html' }) -export class GfSelfHostingPageComponent implements OnDestroy { +export class GfSelfHostingPageComponent { public pricingUrl = `https://ghostfol.io/${document.documentElement.lang}/${publicRoutes.pricing.path}`; - - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } 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 42e810eb0..ef88df9aa 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 @@ -93,6 +93,10 @@ dialog +

    + For derived currencies (e.g. GBp), ensure that you + gather the data for the parent currency (e.g. GBP). +

    diff --git a/apps/client/src/app/pages/features/features-page.component.ts b/apps/client/src/app/pages/features/features-page.component.ts index dc2dfaf42..cef90f2e5 100644 --- a/apps/client/src/app/pages/features/features-page.component.ts +++ b/apps/client/src/app/pages/features/features-page.component.ts @@ -1,15 +1,15 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { InfoItem, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; -import { ChangeDetectorRef, Component, OnDestroy } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; -import { Subject, takeUntil } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -23,7 +23,7 @@ import { Subject, takeUntil } from 'rxjs'; styleUrls: ['./features-page.scss'], templateUrl: './features-page.html' }) -export class GfFeaturesPageComponent implements OnDestroy { +export class GfFeaturesPageComponent { public hasPermissionForSubscription: boolean; public hasPermissionToCreateUser: boolean; public info: InfoItem; @@ -31,11 +31,10 @@ export class GfFeaturesPageComponent implements OnDestroy { public routerLinkResources = publicRoutes.resources.routerLink; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private userService: UserService ) { this.info = this.dataService.fetchInfo(); @@ -43,7 +42,7 @@ export class GfFeaturesPageComponent implements OnDestroy { public ngOnInit() { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -62,9 +61,4 @@ export class GfFeaturesPageComponent implements OnDestroy { permissions.createUserAccount ); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/features/features-page.html b/apps/client/src/app/pages/features/features-page.html index d172347f7..efe96aec6 100644 --- a/apps/client/src/app/pages/features/features-page.html +++ b/apps/client/src/app/pages/features/features-page.html @@ -260,8 +260,9 @@

    Use Ghostfolio in multiple languages: English, - Chinese, Dutch, French, German, Italian, Polish, Portuguese, - Spanish and Turkish + Chinese, Dutch, French, German, Italian, + + Polish, Portuguese, Spanish and Turkish are currently supported.

    diff --git a/apps/client/src/app/pages/home/home-page.component.ts b/apps/client/src/app/pages/home/home-page.component.ts index fd860ced5..5130c8166 100644 --- a/apps/client/src/app/pages/home/home-page.component.ts +++ b/apps/client/src/app/pages/home/home-page.component.ts @@ -8,9 +8,10 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; @@ -23,8 +24,6 @@ import { readerOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page has-tabs' }, @@ -34,22 +33,21 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./home-page.scss'], templateUrl: './home-page.html' }) -export class GfHomePageComponent implements OnDestroy, OnInit { +export class GfHomePageComponent implements OnInit { public deviceType: string; public hasImpersonationId: boolean; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -110,14 +108,9 @@ export class GfHomePageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/i18n/i18n-page.component.ts b/apps/client/src/app/pages/i18n/i18n-page.component.ts index 19ecd222e..76d123914 100644 --- a/apps/client/src/app/pages/i18n/i18n-page.component.ts +++ b/apps/client/src/app/pages/i18n/i18n-page.component.ts @@ -1,5 +1,4 @@ import { Component } from '@angular/core'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -8,11 +7,4 @@ import { Subject } from 'rxjs'; styleUrls: ['./i18n-page.scss'], templateUrl: './i18n-page.html' }) -export class GfI18nPageComponent { - private unsubscribeSubject = new Subject(); - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } -} +export class GfI18nPageComponent {} diff --git a/apps/client/src/app/pages/i18n/i18n-page.html b/apps/client/src/app/pages/i18n/i18n-page.html index b4297d5ac..99ef3039e 100644 --- a/apps/client/src/app/pages/i18n/i18n-page.html +++ b/apps/client/src/app/pages/i18n/i18n-page.html @@ -149,14 +149,14 @@
  • An emergency fund has been set up
  • -
  • Fee Ratio
  • -
  • - The fees do exceed ${thresholdMax}% of your initial investment - (${feeRatio}%) -
  • -
  • - The fees do not exceed ${thresholdMax}% of your initial - investment (${feeRatio}%) +
  • Fee Ratio
  • +
  • + The fees do exceed ${thresholdMax}% of your total investment + volume (${feeRatio}%) +
  • +
  • + The fees do not exceed ${thresholdMax}% of your total + investment volume (${feeRatio}%)
  • Fees
  • diff --git a/apps/client/src/app/pages/landing/landing-page.component.ts b/apps/client/src/app/pages/landing/landing-page.component.ts index 55f07a798..9ee9cceb4 100644 --- a/apps/client/src/app/pages/landing/landing-page.component.ts +++ b/apps/client/src/app/pages/landing/landing-page.component.ts @@ -1,15 +1,15 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { Statistics } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { GfCarouselComponent } from '@ghostfolio/ui/carousel'; import { GfLogoComponent } from '@ghostfolio/ui/logo'; import { GfLogoCarouselComponent } from '@ghostfolio/ui/logo-carousel'; +import { DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { GfWorldMapChartComponent } from '@ghostfolio/ui/world-map-chart'; import { CommonModule } from '@angular/common'; -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; @@ -21,7 +21,6 @@ import { starOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -40,7 +39,7 @@ import { Subject } from 'rxjs'; styleUrls: ['./landing-page.scss'], templateUrl: './landing-page.html' }) -export class GfLandingPageComponent implements OnDestroy, OnInit { +export class GfLandingPageComponent implements OnInit { public countriesOfSubscribersMap: { [code: string]: { value: number }; } = {}; @@ -107,8 +106,6 @@ export class GfLandingPageComponent implements OnDestroy, OnInit { } ]; - private unsubscribeSubject = new Subject(); - public constructor( private dataService: DataService, private deviceService: DeviceDetectorService @@ -155,9 +152,4 @@ export class GfLandingPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/open/open-page.component.ts b/apps/client/src/app/pages/open/open-page.component.ts index 773025769..6284c41f4 100644 --- a/apps/client/src/app/pages/open/open-page.component.ts +++ b/apps/client/src/app/pages/open/open-page.component.ts @@ -1,6 +1,6 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { Statistics, User } from '@ghostfolio/common/interfaces'; +import { DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { diff --git a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts index 5b5273b65..4e5daf345 100644 --- a/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/activities-page.component.ts @@ -1,4 +1,3 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { IcsService } from '@ghostfolio/client/services/ics/ics.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; @@ -11,7 +10,9 @@ import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; +import { DateRange } from '@ghostfolio/common/types'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; +import { DataService } from '@ghostfolio/ui/services'; import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; @@ -129,8 +130,13 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { } public fetchActivities() { + const dateRange = this.user?.settings?.dateRange; + + const range = this.isCalendarYear(dateRange) ? dateRange : undefined; + this.dataService .fetchActivities({ + range, filters: this.userService.getFilters(), skip: this.pageIndex * this.pageSize, sortColumn: this.sortColumn, @@ -334,7 +340,7 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { .subscribe((activity: UpdateOrderDto) => { if (activity) { this.dataService - .putOrder(activity) + .putActivity(activity) .pipe(takeUntil(this.unsubscribeSubject)) .subscribe({ next: () => { @@ -352,6 +358,14 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { this.unsubscribeSubject.complete(); } + private isCalendarYear(dateRange: DateRange) { + if (!dateRange) { + return false; + } + + return /^\d{4}$/.test(dateRange); + } + private openCreateActivityDialog(aActivity?: Activity) { this.userService .get() @@ -385,7 +399,7 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { .pipe(takeUntil(this.unsubscribeSubject)) .subscribe((transaction: CreateOrderDto | null) => { if (transaction) { - this.dataService.postOrder(transaction).subscribe({ + this.dataService.postActivity(transaction).subscribe({ next: () => { this.userService .get(true) @@ -407,9 +421,9 @@ export class GfActivitiesPageComponent implements OnDestroy, OnInit { this.hasPermissionToCreateActivity = !this.hasImpersonationId && - hasPermission(this.user.permissions, permissions.createOrder); + hasPermission(this.user.permissions, permissions.createActivity); this.hasPermissionToDeleteActivity = !this.hasImpersonationId && - hasPermission(this.user.permissions, permissions.deleteOrder); + hasPermission(this.user.permissions, permissions.deleteActivity); } } diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts index b44e8ee6b..c7cd63191 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.component.ts @@ -10,6 +10,7 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { validateObjectForForm } from '@ghostfolio/common/utils'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; import { translate } from '@ghostfolio/ui/i18n'; +import { DataService } from '@ghostfolio/ui/services'; import { GfSymbolAutocompleteComponent } from '@ghostfolio/ui/symbol-autocomplete'; import { GfTagsSelectorComponent } from '@ghostfolio/ui/tags-selector'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -48,7 +49,6 @@ import { calendarClearOutline, refreshOutline } from 'ionicons/icons'; import { EMPTY, Subject } from 'rxjs'; import { catchError, delay, takeUntil } from 'rxjs/operators'; -import { DataService } from '../../../../services/data.service'; import { CreateOrUpdateActivityDialogParams } from './interfaces/interfaces'; import { ActivityType } from './types/activity-type.type'; @@ -188,8 +188,7 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { !this.data.activity?.accountId && this.mode === 'create' ? this.data.accounts[0].id - : this.data.activity?.accountId, - Validators.required + : this.data.activity?.accountId ], assetClass: [this.data.activity?.SymbolProfile?.assetClass], assetSubClass: [this.data.activity?.SymbolProfile?.assetSubClass], @@ -365,11 +364,6 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { (this.activityForm.get('dataSource').value === 'MANUAL' && type === 'BUY') ) { - this.activityForm - .get('accountId') - .removeValidators(Validators.required); - this.activityForm.get('accountId').updateValueAndValidity(); - const currency = this.data.accounts.find(({ id }) => { return id === this.activityForm.get('accountId').value; @@ -397,11 +391,6 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.activityForm.get('updateAccountBalance').disable(); this.activityForm.get('updateAccountBalance').setValue(false); } else if (['FEE', 'INTEREST', 'LIABILITY'].includes(type)) { - this.activityForm - .get('accountId') - .removeValidators(Validators.required); - this.activityForm.get('accountId').updateValueAndValidity(); - const currency = this.data.accounts.find(({ id }) => { return id === this.activityForm.get('accountId').value; @@ -447,8 +436,6 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { this.activityForm.get('updateAccountBalance').setValue(false); } } else { - this.activityForm.get('accountId').setValidators(Validators.required); - this.activityForm.get('accountId').updateValueAndValidity(); this.activityForm .get('dataSource') .setValidators(Validators.required); @@ -514,11 +501,12 @@ export class GfCreateOrUpdateActivityDialogComponent implements OnDestroy { comment: this.activityForm.get('comment').value || null, currency: this.activityForm.get('currency').value, customCurrency: this.activityForm.get('currencyOfUnitPrice').value, + dataSource: ['FEE', 'INTEREST', 'LIABILITY', 'VALUABLE'].includes( + this.activityForm.get('type').value + ) + ? 'MANUAL' + : this.activityForm.get('dataSource').value, date: this.activityForm.get('date').value, - dataSource: - this.activityForm.get('type').value === 'VALUABLE' - ? 'MANUAL' - : this.activityForm.get('dataSource').value, fee: this.activityForm.get('fee').value, quantity: this.activityForm.get('quantity').value, symbol: diff --git a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html index 42fbd0ebf..278ddcbbd 100644 --- a/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html +++ b/apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html @@ -84,12 +84,8 @@ > Account - @if ( - !activityForm.get('accountId').hasValidator(Validators.required) || - (!activityForm.get('accountId').value && mode === 'update') - ) { - - } + + @for (account of data.accounts; track account) {
    diff --git a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts index 582ab8e25..1a84e9f31 100644 --- a/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts +++ b/apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts @@ -1,5 +1,4 @@ import { GfFileDropDirective } from '@ghostfolio/client/directives/file-drop/file-drop.directive'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImportActivitiesService } from '@ghostfolio/client/services/import-activities.service'; import { CreateAccountWithBalancesDto, @@ -11,6 +10,7 @@ import { GfSymbolPipe } from '@ghostfolio/common/pipes'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table'; import { GfDialogFooterComponent } from '@ghostfolio/ui/dialog-footer'; import { GfDialogHeaderComponent } from '@ghostfolio/ui/dialog-header'; +import { DataService } from '@ghostfolio/ui/services'; import { StepperOrientation, diff --git a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts index b4de51701..5226c3c12 100644 --- a/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts +++ b/apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts @@ -1,6 +1,5 @@ import { GfAccountDetailDialogComponent } from '@ghostfolio/client/components/account-detail-dialog/account-detail-dialog.component'; import { AccountDetailDialogParams } from '@ghostfolio/client/components/account-detail-dialog/interfaces/interfaces'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { MAX_TOP_HOLDINGS, UNKNOWN_KEY } from '@ghostfolio/common/config'; @@ -17,12 +16,19 @@ import { Market, MarketAdvanced } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { GfPortfolioProportionChartComponent } from '@ghostfolio/ui/portfolio-proportion-chart'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; import { GfTopHoldingsComponent } from '@ghostfolio/ui/top-holdings'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { GfWorldMapChartComponent } from '@ghostfolio/ui/world-map-chart'; import { NgClass } from '@angular/common'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatCardModule } from '@angular/material/card'; import { MatDialog } from '@angular/material/dialog'; import { MatProgressBarModule } from '@angular/material/progress-bar'; @@ -36,8 +42,6 @@ import { } from '@prisma/client'; import { isNumber } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -54,7 +58,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./allocations-page.scss'], templateUrl: './allocations-page.html' }) -export class GfAllocationsPageComponent implements OnDestroy, OnInit { +export class GfAllocationsPageComponent implements OnInit { public accounts: { [id: string]: Pick & { id: string; @@ -119,11 +123,10 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { public user: User; public worldMapChartFormat: string; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private impersonationStorageService: ImpersonationStorageService, @@ -132,7 +135,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { private userService: UserService ) { this.route.queryParams - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((params) => { if (params['accountId'] && params['accountDetailDialog']) { this.openAccountDetailDialog(params['accountId']); @@ -145,13 +148,13 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -166,7 +169,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { this.initialize(); this.fetchPortfolioDetails() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((portfolioDetails) => { this.initialize(); @@ -202,11 +205,6 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { } } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private extractEtfProvider({ assetSubClass, name @@ -569,7 +567,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { hasImpersonationId: this.hasImpersonationId, hasPermissionToCreateActivity: !this.hasImpersonationId && - hasPermission(this.user?.permissions, permissions.createOrder) && + hasPermission(this.user?.permissions, permissions.createActivity) && !this.user?.settings?.isRestrictedView }, height: this.deviceType === 'mobile' ? '98vh' : '80vh', @@ -578,7 +576,7 @@ export class GfAllocationsPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.router.navigate(['.'], { relativeTo: this.route }); }); diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts index 63ed3569c..47845ea6f 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts @@ -1,8 +1,8 @@ import { GfBenchmarkComparatorComponent } from '@ghostfolio/client/components/benchmark-comparator/benchmark-comparator.component'; import { GfInvestmentChartComponent } from '@ghostfolio/client/components/investment-chart/investment-chart.component'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; +import { NUMERICAL_PRECISION_THRESHOLD_6_FIGURES } from '@ghostfolio/common/config'; import { HistoricalDataItem, InvestmentItem, @@ -16,6 +16,7 @@ import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import type { AiPromptMode, GroupBy } from '@ghostfolio/common/types'; import { translate } from '@ghostfolio/ui/i18n'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; import { GfToggleComponent } from '@ghostfolio/ui/toggle'; import { GfValueComponent } from '@ghostfolio/ui/value'; @@ -23,10 +24,11 @@ import { Clipboard } from '@angular/cdk/clipboard'; import { ChangeDetectorRef, Component, - OnDestroy, + DestroyRef, OnInit, ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatMenuModule, MatMenuTrigger } from '@angular/material/menu'; @@ -41,8 +43,6 @@ import { isNumber, sortBy } from 'lodash'; import ms from 'ms'; import { DeviceDetectorService } from 'ngx-device-detector'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ imports: [ @@ -63,7 +63,7 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./analysis-page.scss'], templateUrl: './analysis-page.html' }) -export class GfAnalysisPageComponent implements OnDestroy, OnInit { +export class GfAnalysisPageComponent implements OnInit { @ViewChild(MatMenuTrigger) actionsMenuButton!: MatMenuTrigger; public benchmark: Partial; @@ -94,18 +94,18 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { public performanceDataItems: HistoricalDataItem[]; public performanceDataItemsInPercentage: HistoricalDataItem[]; public portfolioEvolutionDataLabel = $localize`Investment`; + public precision = 2; public streaks: PortfolioInvestmentsResponse['streaks']; public top3: PortfolioPosition[]; public unitCurrentStreak: string; public unitLongestStreak: string; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private clipboard: Clipboard, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private snackBar: MatSnackBar, @@ -133,13 +133,13 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -161,11 +161,11 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { public onChangeBenchmark(symbolProfileId: string) { this.dataService .putUserSetting({ benchmark: symbolProfileId }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -191,7 +191,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { mode, filters: this.userService.getFilters() }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ prompt }) => { this.clipboard.copy(prompt); @@ -205,7 +205,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { snackBarRef .onAction() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { window.open('https://duck.ai', '_blank'); }); @@ -220,11 +220,6 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private fetchDividendsAndInvestments() { this.isLoadingDividendTimelineChart = true; this.isLoadingInvestmentTimelineChart = true; @@ -235,7 +230,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { groupBy: this.mode, range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ dividends }) => { this.dividendsByGroup = dividends; @@ -250,7 +245,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { groupBy: this.mode, range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ investments, streaks }) => { this.investmentsByGroup = investments; this.streaks = streaks; @@ -285,7 +280,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { filters: this.userService.getFilters(), range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ chart, firstOrderDate, performance }) => { this.firstOrderDate = firstOrderDate ?? new Date(); @@ -317,12 +312,21 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { : valueInPercentage }); } + this.performanceDataItemsInPercentage.push({ date, value: netPerformanceInPercentageWithCurrencyEffect }); } + if ( + this.deviceType === 'mobile' && + this.performance.currentValueInBaseCurrency >= + NUMERICAL_PRECISION_THRESHOLD_6_FIGURES + ) { + this.precision = 0; + } + this.isLoadingInvestmentChart = false; this.updateBenchmarkDataItems(); @@ -335,7 +339,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { filters: this.userService.getFilters(), range: this.user?.settings?.dateRange }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ holdings }) => { const holdingsSorted = sortBy( holdings.filter(({ netPerformancePercentWithCurrencyEffect }) => { @@ -386,7 +390,7 @@ export class GfAnalysisPageComponent implements OnDestroy, OnInit { range: this.user?.settings?.dateRange, startDate: this.firstOrderDate }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ marketData }) => { this.benchmarkDataItems = marketData.map(({ date, value }) => { return { diff --git a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html index 150caa7d8..517ad7101 100644 --- a/apps/client/src/app/pages/portfolio/analysis/analysis-page.html +++ b/apps/client/src/app/pages/portfolio/analysis/analysis-page.html @@ -74,6 +74,72 @@
  • } + + @if (user?.settings?.isExperimentalFeatures) { +
    +
    + + + Total amount + + +
    +
    + + + Change with currency effect + + +
    +
    + + + Performance with currency effect + + +
    +
    + } +
    (); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private impersonationStorageService: ImpersonationStorageService, private userService: UserService @@ -68,7 +71,7 @@ export class GfFirePageComponent implements OnDestroy, OnInit { this.dataService .fetchPortfolioDetails() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ summary }) => { this.fireWealth = { today: { @@ -92,19 +95,19 @@ export class GfFirePageComponent implements OnDestroy, OnInit { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.safeWithdrawalRateControl.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((value) => { this.onSafeWithdrawalRateChange(Number(value)); }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -132,11 +135,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { public onAnnualInterestRateChange(annualInterestRate: number) { this.dataService .putUserSetting({ annualInterestRate }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -163,11 +166,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { retirementDate: retirementDate.toISOString(), projectedTotalAmount: null }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -179,11 +182,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { public onSafeWithdrawalRateChange(safeWithdrawalRate: number) { this.dataService .putUserSetting({ safeWithdrawalRate }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -198,11 +201,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { public onSavingsRateChange(savingsRate: number) { this.dataService .putUserSetting({ savingsRate }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -217,11 +220,11 @@ export class GfFirePageComponent implements OnDestroy, OnInit { projectedTotalAmount, retirementDate: null }) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((user) => { this.user = user; @@ -230,11 +233,6 @@ export class GfFirePageComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private calculateWithdrawalRates() { if (this.fireWealth && this.user?.settings?.safeWithdrawalRate) { this.withdrawalRatePerYear = new Big( diff --git a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts index 387e3fd0f..eb4935127 100644 --- a/apps/client/src/app/pages/portfolio/portfolio-page.component.ts +++ b/apps/client/src/app/pages/portfolio/portfolio-page.component.ts @@ -2,7 +2,13 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { addIcons } from 'ionicons'; @@ -14,8 +20,6 @@ import { swapVerticalOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page has-tabs' }, @@ -24,20 +28,19 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./portfolio-page.scss'], templateUrl: './portfolio-page.html' }) -export class PortfolioPageComponent implements OnDestroy, OnInit { +export class PortfolioPageComponent implements OnInit { public deviceType: string; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.tabs = [ @@ -87,9 +90,4 @@ export class PortfolioPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts index 0bf869238..e97fd4876 100644 --- a/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts +++ b/apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.ts @@ -1,5 +1,4 @@ import { GfRulesComponent } from '@ghostfolio/client/components/rules/rules.component'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { ImpersonationStorageService } from '@ghostfolio/client/services/impersonation-storage.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { UpdateUserSettingDto } from '@ghostfolio/common/dtos'; @@ -10,9 +9,11 @@ import { import { User } from '@ghostfolio/common/interfaces/user.interface'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; import { NgClass } from '@angular/common'; -import { ChangeDetectorRef, Component } from '@angular/core'; +import { ChangeDetectorRef, Component, DestroyRef } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { @@ -21,7 +22,6 @@ import { warningOutline } from 'ionicons/icons'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { Subject, takeUntil } from 'rxjs'; @Component({ imports: [ @@ -48,11 +48,10 @@ export class GfXRayPageComponent { public statistics: PortfolioReportResponse['xRay']['statistics']; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private impersonationStorageService: ImpersonationStorageService, private userService: UserService ) { @@ -62,13 +61,13 @@ export class GfXRayPageComponent { public ngOnInit() { this.impersonationStorageService .onChangeHasImpersonation() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((impersonationId) => { this.hasImpersonationId = !!impersonationId; }); this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -91,28 +90,23 @@ export class GfXRayPageComponent { public onRulesUpdated(event: UpdateUserSettingDto) { this.dataService .putUserSetting(event) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.userService .get(true) - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(); this.initializePortfolioReport(); }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private initializePortfolioReport() { this.isLoading = true; this.dataService .fetchPortfolioReport() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ xRay: { categories, statistics } }) => { this.categories = categories; this.inactiveRules = this.mergeInactiveRules(categories); diff --git a/apps/client/src/app/pages/pricing/pricing-page.component.ts b/apps/client/src/app/pages/pricing/pricing-page.component.ts index aaf0c597b..831f0809c 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.component.ts +++ b/apps/client/src/app/pages/pricing/pricing-page.component.ts @@ -1,4 +1,3 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; @@ -6,6 +5,7 @@ import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { translate } from '@ghostfolio/ui/i18n'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { DataService } from '@ghostfolio/ui/services'; import { CommonModule } from '@angular/common'; import { @@ -82,6 +82,7 @@ export class GfPricingPageComponent implements OnDestroy, OnInit { 'frankly', 'Interactive Brokers', 'Mintos', + 'Monefit SmartSaver', 'Swissquote', 'VIAC', 'Zak' diff --git a/apps/client/src/app/pages/pricing/pricing-page.html b/apps/client/src/app/pages/pricing/pricing-page.html index 3cc0e460a..d755cd303 100644 --- a/apps/client/src/app/pages/pricing/pricing-page.html +++ b/apps/client/src/app/pages/pricing/pricing-page.html @@ -195,12 +195,9 @@

    • - Everything in -   - Basic, - plus: + Everything in Basic, plus:
    • diff --git a/apps/client/src/app/pages/public/public-page.component.ts b/apps/client/src/app/pages/public/public-page.component.ts index 55e2a122a..9ccbbf52e 100644 --- a/apps/client/src/app/pages/public/public-page.component.ts +++ b/apps/client/src/app/pages/public/public-page.component.ts @@ -1,4 +1,3 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { UNKNOWN_KEY } from '@ghostfolio/common/config'; import { prettifySymbol } from '@ghostfolio/common/helper'; import { @@ -11,6 +10,7 @@ import { Market } from '@ghostfolio/common/types'; import { GfActivitiesTableComponent } from '@ghostfolio/ui/activities-table/activities-table.component'; import { GfHoldingsTableComponent } from '@ghostfolio/ui/holdings-table/holdings-table.component'; import { GfPortfolioProportionChartComponent } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.component'; +import { DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { GfWorldMapChartComponent } from '@ghostfolio/ui/world-map-chart'; @@ -19,8 +19,10 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatTableDataSource } from '@angular/material/table'; @@ -29,8 +31,8 @@ import { AssetClass } from '@prisma/client'; import { StatusCodes } from 'http-status-codes'; import { isNumber } from 'lodash'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { EMPTY, Subject } from 'rxjs'; -import { catchError, takeUntil } from 'rxjs/operators'; +import { EMPTY } from 'rxjs'; +import { catchError } from 'rxjs/operators'; @Component({ host: { class: 'page' }, @@ -83,12 +85,12 @@ export class GfPublicPageComponent implements OnInit { public UNKNOWN_KEY = UNKNOWN_KEY; private accessId: string; - private unsubscribeSubject = new Subject(); public constructor( private activatedRoute: ActivatedRoute, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private router: Router ) { @@ -110,7 +112,7 @@ export class GfPublicPageComponent implements OnInit { this.dataService .fetchPublicPortfolio(this.accessId) .pipe( - takeUntil(this.unsubscribeSubject), + takeUntilDestroyed(this.destroyRef), catchError((error) => { if (error.status === StatusCodes.NOT_FOUND) { console.error(error); @@ -246,9 +248,4 @@ export class GfPublicPageComponent implements OnInit { }; } } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/public/public-page.html b/apps/client/src/app/pages/public/public-page.html index 079566e0d..c422f9006 100644 --- a/apps/client/src/app/pages/public/public-page.html +++ b/apps/client/src/app/pages/public/public-page.html @@ -78,7 +78,6 @@ [showLabels]="deviceType !== 'mobile'" /> (); - public constructor( private dataService: DataService, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private dialog: MatDialog, private router: Router, - private tokenStorageService: TokenStorageService + private tokenStorageService: TokenStorageService, + private userService: UserService ) { this.info = this.dataService.fetchInfo(); - this.tokenStorageService.signOut(); + this.userService.signOut(); } public ngOnInit() { @@ -93,7 +93,7 @@ export class GfRegisterPageComponent implements OnDestroy, OnInit { dialogRef .afterClosed() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((authToken) => { if (authToken) { this.tokenStorageService.saveToken(authToken, true); @@ -102,9 +102,4 @@ export class GfRegisterPageComponent implements OnDestroy, OnInit { } }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts b/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts index 36e1ce710..4cc0f52f8 100644 --- a/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts +++ b/apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.component.ts @@ -1,5 +1,5 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { DataService } from '@ghostfolio/ui/services'; import { ClipboardModule } from '@angular/cdk/clipboard'; import { TextFieldModule } from '@angular/cdk/text-field'; @@ -9,6 +9,7 @@ import { Component, CUSTOM_ELEMENTS_SCHEMA, Inject, + OnDestroy, ViewChild } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -52,7 +53,7 @@ import { UserAccountRegistrationDialogParams } from './interfaces/interfaces'; styleUrls: ['./user-account-registration-dialog.scss'], templateUrl: 'user-account-registration-dialog.html' }) -export class GfUserAccountRegistrationDialogComponent { +export class GfUserAccountRegistrationDialogComponent implements OnDestroy { @ViewChild(MatStepper) stepper!: MatStepper; public accessToken: string; @@ -95,4 +96,9 @@ export class GfUserAccountRegistrationDialogComponent { public onChangeDislaimerChecked() { this.isDisclaimerChecked = !this.isDisclaimerChecked; } + + public ngOnDestroy() { + this.unsubscribeSubject.next(); + this.unsubscribeSubject.complete(); + } } diff --git a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts index 96958dd70..112619239 100644 --- a/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts +++ b/apps/client/src/app/pages/resources/glossary/resources-glossary.component.ts @@ -1,7 +1,7 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { InfoItem } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; +import { DataService } from '@ghostfolio/ui/services'; import { Component, OnInit } from '@angular/core'; import { RouterModule } from '@angular/router'; diff --git a/apps/client/src/app/pages/resources/overview/resources-overview.component.html b/apps/client/src/app/pages/resources/overview/resources-overview.component.html index 3a6f18d40..86a334c79 100644 --- a/apps/client/src/app/pages/resources/overview/resources-overview.component.html +++ b/apps/client/src/app/pages/resources/overview/resources-overview.component.html @@ -7,7 +7,9 @@

      {{ item.title }}

      {{ item.description }}

      - Explore {{ item.title }} → + Explore {{ item.title }}
      }
    diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts b/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts index c4cfd184e..bb4ae3889 100644 --- a/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts +++ b/apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.component.ts @@ -1,13 +1,12 @@ import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; -import { Component, OnDestroy } from '@angular/core'; +import { Component } from '@angular/core'; import { MatCardModule } from '@angular/material/card'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { chevronForwardOutline } from 'ionicons/icons'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page' }, @@ -16,7 +15,7 @@ import { Subject } from 'rxjs'; styleUrls: ['./personal-finance-tools-page.scss'], templateUrl: './personal-finance-tools-page.html' }) -export class PersonalFinanceToolsPageComponent implements OnDestroy { +export class PersonalFinanceToolsPageComponent { public pathAlternativeTo = publicRoutes.resources.subRoutes.personalFinanceTools.subRoutes.product .path + '-'; @@ -28,14 +27,7 @@ export class PersonalFinanceToolsPageComponent implements OnDestroy { }); public routerLinkAbout = publicRoutes.about.routerLink; - private unsubscribeSubject = new Subject(); - public constructor() { addIcons({ chevronForwardOutline }); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts b/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts index 511cf672d..14f9554d5 100644 --- a/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts +++ b/apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts @@ -1,8 +1,8 @@ -import { DataService } from '@ghostfolio/client/services/data.service'; import { Product } from '@ghostfolio/common/interfaces'; import { personalFinanceTools } from '@ghostfolio/common/personal-finance-tools'; import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { translate } from '@ghostfolio/ui/i18n'; +import { DataService } from '@ghostfolio/ui/services'; import { Component, OnInit } from '@angular/core'; import { MatButtonModule } from '@angular/material/button'; @@ -43,15 +43,16 @@ export class GfProductPageComponent implements OnInit { isOpenSource: true, key: 'ghostfolio', languages: [ + 'Chinese (简体中文)', 'Deutsch', 'English', 'Español', 'Français', 'Italiano', + 'Korean (한국어)', 'Nederlands', 'Português', - 'Türkçe', - '简体中文' + 'Türkçe' ], name: 'Ghostfolio', origin: $localize`Switzerland`, diff --git a/apps/client/src/app/pages/resources/resources-page.component.ts b/apps/client/src/app/pages/resources/resources-page.component.ts index 9db996f57..c25ef00d6 100644 --- a/apps/client/src/app/pages/resources/resources-page.component.ts +++ b/apps/client/src/app/pages/resources/resources-page.component.ts @@ -13,7 +13,6 @@ import { readerOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; @Component({ host: { class: 'page has-tabs' }, @@ -47,8 +46,6 @@ export class ResourcesPageComponent implements OnInit { } ]; - private unsubscribeSubject = new Subject(); - public constructor(private deviceService: DeviceDetectorService) { addIcons({ bookOutline, libraryOutline, newspaperOutline, readerOutline }); } @@ -56,9 +53,4 @@ export class ResourcesPageComponent implements OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/user-account/user-account-page.component.ts b/apps/client/src/app/pages/user-account/user-account-page.component.ts index 7341660f2..24c150408 100644 --- a/apps/client/src/app/pages/user-account/user-account-page.component.ts +++ b/apps/client/src/app/pages/user-account/user-account-page.component.ts @@ -6,16 +6,16 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA, - OnDestroy, + DestroyRef, OnInit } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { diamondOutline, keyOutline, settingsOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject, takeUntil } from 'rxjs'; @Component({ host: { class: 'page has-tabs' }, @@ -25,20 +25,19 @@ import { Subject, takeUntil } from 'rxjs'; styleUrls: ['./user-account-page.scss'], templateUrl: './user-account-page.html' }) -export class GfUserAccountPageComponent implements OnDestroy, OnInit { +export class GfUserAccountPageComponent implements OnInit { public deviceType: string; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -73,9 +72,4 @@ export class GfUserAccountPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/webauthn/webauthn-page.component.ts b/apps/client/src/app/pages/webauthn/webauthn-page.component.ts index 74631eeca..8e7e58fd1 100644 --- a/apps/client/src/app/pages/webauthn/webauthn-page.component.ts +++ b/apps/client/src/app/pages/webauthn/webauthn-page.component.ts @@ -2,12 +2,16 @@ import { TokenStorageService } from '@ghostfolio/client/services/token-storage.s import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; import { GfLogoComponent } from '@ghostfolio/ui/logo'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { Router } from '@angular/router'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page' }, @@ -16,13 +20,12 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./webauthn-page.scss'], templateUrl: './webauthn-page.html' }) -export class GfWebauthnPageComponent implements OnDestroy, OnInit { +export class GfWebauthnPageComponent implements OnInit { public hasError = false; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private router: Router, private tokenStorageService: TokenStorageService, private webAuthnService: WebAuthnService @@ -35,7 +38,7 @@ export class GfWebauthnPageComponent implements OnDestroy, OnInit { public deregisterDevice() { this.webAuthnService .deregister() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.router.navigate(['/']); }); @@ -46,7 +49,7 @@ export class GfWebauthnPageComponent implements OnDestroy, OnInit { this.webAuthnService .login() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe( ({ authToken }) => { this.tokenStorageService.saveToken(authToken, false); @@ -59,9 +62,4 @@ export class GfWebauthnPageComponent implements OnDestroy, OnInit { } ); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/pages/zen/zen-page.component.ts b/apps/client/src/app/pages/zen/zen-page.component.ts index 280f33c25..633f15885 100644 --- a/apps/client/src/app/pages/zen/zen-page.component.ts +++ b/apps/client/src/app/pages/zen/zen-page.component.ts @@ -2,15 +2,19 @@ import { UserService } from '@ghostfolio/client/services/user/user.service'; import { TabConfiguration, User } from '@ghostfolio/common/interfaces'; import { internalRoutes } from '@ghostfolio/common/routes/routes'; -import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; +import { + ChangeDetectorRef, + Component, + DestroyRef, + OnInit +} from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatTabsModule } from '@angular/material/tabs'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { albumsOutline, analyticsOutline } from 'ionicons/icons'; import { DeviceDetectorService } from 'ngx-device-detector'; -import { Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; @Component({ host: { class: 'page has-tabs' }, @@ -19,20 +23,19 @@ import { takeUntil } from 'rxjs/operators'; styleUrls: ['./zen-page.scss'], templateUrl: './zen-page.html' }) -export class GfZenPageComponent implements OnDestroy, OnInit { +export class GfZenPageComponent implements OnInit { public deviceType: string; public tabs: TabConfiguration[] = []; public user: User; - private unsubscribeSubject = new Subject(); - public constructor( private changeDetectorRef: ChangeDetectorRef, + private destroyRef: DestroyRef, private deviceService: DeviceDetectorService, private userService: UserService ) { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.tabs = [ @@ -59,9 +62,4 @@ export class GfZenPageComponent implements OnDestroy, OnInit { public ngOnInit() { this.deviceType = this.deviceService.getDeviceInfo().deviceType; } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/apps/client/src/app/services/import-activities.service.ts b/apps/client/src/app/services/import-activities.service.ts index 94d8470f7..55b5c44d5 100644 --- a/apps/client/src/app/services/import-activities.service.ts +++ b/apps/client/src/app/services/import-activities.service.ts @@ -97,9 +97,7 @@ export class ImportActivitiesService { isin: null, marketData: [], name: symbol, - scraperConfiguration: null, sectors: [], - symbolMapping: {}, url: null }); } diff --git a/apps/client/src/app/services/token-storage.service.ts b/apps/client/src/app/services/token-storage.service.ts index 5b9a29a08..f54aab828 100644 --- a/apps/client/src/app/services/token-storage.service.ts +++ b/apps/client/src/app/services/token-storage.service.ts @@ -1,19 +1,11 @@ -import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; - import { Injectable } from '@angular/core'; import { KEY_TOKEN } from './settings-storage.service'; -import { UserService } from './user/user.service'; @Injectable({ providedIn: 'root' }) export class TokenStorageService { - public constructor( - private userService: UserService, - private webAuthnService: WebAuthnService - ) {} - public getToken(): string { return ( window.sessionStorage.getItem(KEY_TOKEN) || @@ -25,23 +17,7 @@ export class TokenStorageService { if (staySignedIn) { window.localStorage.setItem(KEY_TOKEN, token); } - window.sessionStorage.setItem(KEY_TOKEN, token); - } - - public signOut() { - const utmSource = window.localStorage.getItem('utm_source'); - if (this.webAuthnService.isEnabled()) { - this.webAuthnService.deregister().subscribe(); - } - - window.localStorage.clear(); - window.sessionStorage.clear(); - - this.userService.remove(); - - if (utmSource) { - window.localStorage.setItem('utm_source', utmSource); - } + window.sessionStorage.setItem(KEY_TOKEN, token); } } diff --git a/apps/client/src/app/services/user/user.service.ts b/apps/client/src/app/services/user/user.service.ts index bd9d7d04c..44b63e056 100644 --- a/apps/client/src/app/services/user/user.service.ts +++ b/apps/client/src/app/services/user/user.service.ts @@ -1,3 +1,4 @@ +import { WebAuthnService } from '@ghostfolio/client/services/web-authn.service'; import { Filter, User } from '@ghostfolio/common/interfaces'; import { hasPermission, permissions } from '@ghostfolio/common/permissions'; @@ -26,7 +27,8 @@ export class UserService extends ObservableStore { public constructor( private deviceService: DeviceDetectorService, private dialog: MatDialog, - private http: HttpClient + private http: HttpClient, + private webAuthnService: WebAuthnService ) { super({ trackStateHistory: true }); @@ -93,10 +95,40 @@ export class UserService extends ObservableStore { return this.getFilters().length > 0; } - public remove() { + public reset() { this.setState({ user: null }, UserStoreActions.RemoveUser); } + public signOut() { + const utmSource = window.localStorage.getItem('utm_source'); + + if (this.webAuthnService.isEnabled()) { + this.webAuthnService.deregister().subscribe(); + } + + window.localStorage.clear(); + window.sessionStorage.clear(); + + void this.clearAllCookies(); + + this.reset(); + + if (utmSource) { + window.localStorage.setItem('utm_source', utmSource); + } + } + + private async clearAllCookies() { + if (!('cookieStore' in window)) { + console.warn('Cookie Store API not available in this browser'); + return; + } + + const cookies = await cookieStore.getAll(); + + await Promise.all(cookies.map(({ name }) => cookieStore.delete(name))); + } + private fetchUser(): Observable { return this.http.get('/api/v1/user').pipe( map((user) => { diff --git a/apps/client/src/assets/images/sponsors/logo-lambdatest.png b/apps/client/src/assets/images/sponsors/logo-lambdatest.png deleted file mode 100644 index 9e05b1cde..000000000 Binary files a/apps/client/src/assets/images/sponsors/logo-lambdatest.png and /dev/null differ diff --git a/apps/client/src/assets/images/sponsors/logo-testmu-dark.svg b/apps/client/src/assets/images/sponsors/logo-testmu-dark.svg new file mode 100644 index 000000000..90fbbdd6d --- /dev/null +++ b/apps/client/src/assets/images/sponsors/logo-testmu-dark.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/client/src/assets/images/sponsors/logo-testmu-light.svg b/apps/client/src/assets/images/sponsors/logo-testmu-light.svg new file mode 100644 index 000000000..e925efd5e --- /dev/null +++ b/apps/client/src/assets/images/sponsors/logo-testmu-light.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/client/src/environments/environment.prod.ts b/apps/client/src/environments/environment.prod.ts index 6f1d6b92d..f3ded619e 100644 --- a/apps/client/src/environments/environment.prod.ts +++ b/apps/client/src/environments/environment.prod.ts @@ -1,5 +1,6 @@ -export const environment = { +import type { GfEnvironment } from '@ghostfolio/ui/environment'; + +export const environment: GfEnvironment = { lastPublish: '{BUILD_TIMESTAMP}', - production: true, - stripePublicKey: '' + production: true }; diff --git a/apps/client/src/environments/environment.ts b/apps/client/src/environments/environment.ts index 0a4d51d98..1b9efe2be 100644 --- a/apps/client/src/environments/environment.ts +++ b/apps/client/src/environments/environment.ts @@ -1,11 +1,12 @@ +import type { GfEnvironment } from '@ghostfolio/ui/environment'; + // This file can be replaced during build by using the `fileReplacements` array. // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. // The list of file replacements can be found in `angular.json`. -export const environment = { +export const environment: GfEnvironment = { lastPublish: null, - production: false, - stripePublicKey: '' + production: false }; /* diff --git a/apps/client/src/locales/messages.ca.xlf b/apps/client/src/locales/messages.ca.xlf index 762f8f73a..cf0ede34d 100644 --- a/apps/client/src/locales/messages.ca.xlf +++ b/apps/client/src/locales/messages.ca.xlf @@ -102,7 +102,7 @@ El risc d’assumir pèrdues en les inversions és substancial. No és recomanable invertir diners que pugui necessitar a curt termini. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -295,7 +295,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -358,14 +358,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Realment vol revocar aquest accés? @@ -387,7 +379,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -403,7 +395,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -411,7 +403,7 @@ Balanç de Caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -435,7 +427,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -447,7 +439,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -463,11 +455,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -479,7 +471,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -495,7 +487,7 @@ Total libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -507,7 +499,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -519,11 +511,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -539,15 +531,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -555,11 +547,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -571,7 +563,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -595,15 +587,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -627,11 +619,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -639,7 +635,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -655,7 +651,7 @@ Realment vol suprimir aquest compte? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -695,7 +691,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -715,7 +711,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -763,7 +759,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -827,7 +823,7 @@ Data apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -863,7 +859,7 @@ Punts de referència apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -871,19 +867,11 @@ Divises apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 - - - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 + 95 @@ -891,7 +879,7 @@ ETFs sense País apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -899,7 +887,7 @@ ETFs sense Sector apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -907,7 +895,7 @@ Filtra per... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -927,7 +915,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -947,7 +935,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -1015,7 +1003,7 @@ Oooh! No s’han pogut recopilar les dades históriques. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -1023,7 +1011,7 @@ El preu de mercat actual és apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -1047,7 +1035,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -1079,7 +1067,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -1091,7 +1079,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1099,7 +1087,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -1111,7 +1099,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1123,7 +1111,7 @@ Mapatge de Símbols apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -1139,7 +1127,7 @@ Configuració del Proveïdor de Dades apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -1147,7 +1135,7 @@ Prova apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -1155,11 +1143,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1175,7 +1163,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -1183,7 +1171,7 @@ Notes apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1191,7 +1179,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1235,7 +1223,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1243,7 +1231,7 @@ Està segur qeu vol eliminar aquest cupó? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -1251,7 +1239,7 @@ Està segur que vol eliminar aquest missatge del sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -1259,7 +1247,7 @@ Està segur que vol depurar el cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -1267,7 +1255,7 @@ Si us plau, afegeixi el seu missatge del sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -1331,7 +1319,7 @@ Recollida de Dades apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1403,7 +1391,15 @@ Està segur que vol eliminar aquesta plataforma? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1427,7 +1423,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -1443,7 +1439,7 @@ Plataformes apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1451,7 +1447,7 @@ Etiquetes apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1475,7 +1471,7 @@ Està segur que vol eliminar aquesta etiqueta? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -1499,7 +1495,7 @@ Està segur que vol eliminar aquest usuari? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -1535,7 +1531,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1567,11 +1563,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -1607,7 +1603,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -1619,7 +1615,7 @@ Punt de Referència apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1659,7 +1655,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -1675,7 +1671,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -1703,7 +1699,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -1731,7 +1727,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1739,7 +1735,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1759,7 +1755,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1783,7 +1779,7 @@ Informar d’un Problema amb les Dades apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1823,7 +1819,7 @@ Gestionar Activitats apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -1955,7 +1951,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1975,7 +1971,7 @@ Import total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2003,7 +1999,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -2047,7 +2043,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -2111,7 +2107,7 @@ Rendiment brut absolut apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -2119,11 +2115,11 @@ Rendiment net absolut apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -2131,11 +2127,11 @@ Rendiment net apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -2143,7 +2139,7 @@ Actius totals apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -2151,7 +2147,7 @@ Actius apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -2159,7 +2155,7 @@ Poder adquisitiu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -2167,7 +2163,7 @@ Exclòs de l’anàlisi apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2175,7 +2171,7 @@ Passius apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -2187,7 +2183,7 @@ Valor net apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -2195,7 +2191,7 @@ Rendiment anualitzat apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -2235,7 +2231,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -2255,7 +2251,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -2271,7 +2267,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2287,7 +2283,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2299,7 +2295,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2315,7 +2311,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2355,7 +2351,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -2363,11 +2359,11 @@ YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -2375,11 +2371,11 @@ 1 any apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -2387,11 +2383,19 @@ 5 anys apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Performance with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -2399,11 +2403,11 @@ Màx apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -2455,11 +2459,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2519,7 +2523,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2547,7 +2551,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -2555,7 +2559,7 @@ De debò vols tancar el teu compte de Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -2563,7 +2567,7 @@ De debò vols eliminar aquest mètode d’inici de sessió? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -2571,7 +2575,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -2579,7 +2583,7 @@ Ups! Hi ha hagut un error en configurar l’autenticació biomètrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -2587,7 +2591,7 @@ Vista del presentador apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -2595,7 +2599,7 @@ Protecció per a informació sensible com ara rendiments absoluts i valors de quantitat apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -2627,11 +2631,11 @@ Localització apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -2639,7 +2643,7 @@ Format de data i número apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -2647,7 +2651,7 @@ Aparença apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -2655,7 +2659,7 @@ Llum apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -2663,7 +2667,7 @@ Fosc apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -2671,7 +2675,7 @@ Mode Zen apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -2683,7 +2687,7 @@ Experiència sense distraccions per a temps turbulents apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -2699,7 +2703,7 @@ Autenticació biomètrica apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -2707,7 +2711,7 @@ Inicieu la sessió amb l’empremta digital apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -2715,7 +2719,7 @@ Característiques experimentals apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -2723,7 +2727,7 @@ Doneu un cop d’ull a les properes funcionalitats apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -2731,7 +2735,7 @@ Exporta dades apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -2739,7 +2743,7 @@ Zona de perill apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -2747,7 +2751,7 @@ Tanca el compte apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -2947,7 +2951,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -3047,7 +3051,7 @@ Dades de mercat apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -3099,11 +3103,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -3227,11 +3231,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -3247,7 +3251,7 @@ Com que ja has iniciat sessió, no pots accedir al compte de demostració. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3275,7 +3279,7 @@ General apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -3283,7 +3287,7 @@ Núvol apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -3295,7 +3299,7 @@ Autoallotjament apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -3416,7 +3420,7 @@ Programari de codi obert apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -3428,7 +3432,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -3440,11 +3444,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3496,7 +3500,7 @@ Mercats apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3520,7 +3524,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3912,7 +3916,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -4004,7 +4008,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -4028,7 +4032,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -4040,7 +4044,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -4108,7 +4112,7 @@ Actualitzar el saldo d’efectiu apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4116,7 +4120,7 @@ Preu unitari apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -4356,7 +4360,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -4380,7 +4384,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -4388,7 +4392,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4400,7 +4404,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4412,7 +4416,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4472,7 +4476,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4488,7 +4492,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4496,11 +4500,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -4520,15 +4524,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -4536,7 +4540,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -4544,7 +4548,7 @@ Mensualment apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -4552,7 +4556,7 @@ Anualment apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -4560,7 +4564,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -4568,7 +4572,7 @@ Rendiment absolut dels actius apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -4576,7 +4580,7 @@ Rendiment de l’actiu apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -4584,7 +4588,7 @@ Rendiment absolut de la moneda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -4592,7 +4596,7 @@ Rendiment de la moneda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -4600,7 +4604,7 @@ A dalt apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -4608,7 +4612,7 @@ A baix apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -4616,7 +4620,7 @@ Evolució de la cartera apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -4624,7 +4628,7 @@ Cronologia de la inversió apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -4632,7 +4636,7 @@ Ratxa actual apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4640,7 +4644,7 @@ Ratxa més llarga apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4648,7 +4652,7 @@ Cronologia de dividends apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -4824,7 +4828,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4840,7 +4844,7 @@ Suport per correu electrònic i xat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4848,7 +4852,7 @@ Pagament únic, sense renovació automàtica. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -4856,11 +4860,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -4868,7 +4872,7 @@ És gratuït. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4884,7 +4888,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -4892,7 +4896,7 @@ Vols refinar la teva estratègia d’inversió personal? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -4908,7 +4912,7 @@ Ghostfolio us permet fer un seguiment de la vostra riquesa. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -5001,7 +5005,7 @@ Suïssa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -5013,7 +5017,7 @@ Global apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -5281,7 +5285,7 @@ Pertinença apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5297,7 +5301,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5349,7 +5353,7 @@ Realment voleu eliminar el saldo d’aquest compte? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5413,7 +5417,7 @@ De veritat vols suprimir aquestes activitats? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -5421,7 +5425,7 @@ Realment vols suprimir aquesta activitat? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -5429,7 +5433,7 @@ Setmana fins avui libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5437,11 +5441,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5449,7 +5453,7 @@ Mes fins a la data libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5457,11 +5461,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5469,7 +5473,7 @@ Any fins a la data libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5477,7 +5481,7 @@ any apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -5489,7 +5493,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -5497,11 +5501,11 @@ anys apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -5509,7 +5513,7 @@ Perfils d’actius apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -5585,7 +5589,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5649,7 +5653,7 @@ Dipòsit libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -5661,11 +5665,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -5677,7 +5681,7 @@ Estalvi libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -5685,11 +5689,11 @@ Assignació libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5705,7 +5709,7 @@ Mostra-ho tot libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -5749,7 +5753,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5757,7 +5761,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -5781,7 +5785,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5789,7 +5793,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -5841,7 +5845,7 @@ Fons d’emergència apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -5917,7 +5921,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -5928,6 +5932,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Provisió de jubilació @@ -5936,6 +5948,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satèl·lit @@ -6001,7 +6021,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -6037,7 +6057,7 @@ Comissió apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -6081,7 +6101,7 @@ Efectiu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -6137,7 +6157,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -6281,7 +6301,7 @@ Vàlid fins a apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -6305,7 +6325,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -6313,11 +6333,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -6337,7 +6357,7 @@ Alternativa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6345,7 +6365,7 @@ Aplicació apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6353,7 +6373,7 @@ Pressupost apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6369,47 +6389,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6417,7 +6441,7 @@ Oficina familiar apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6425,7 +6449,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6437,7 +6461,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6449,7 +6473,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6457,7 +6481,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6465,7 +6489,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6473,7 +6497,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6481,7 +6505,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6489,7 +6513,7 @@ Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6497,7 +6521,7 @@ Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6657,7 +6681,7 @@ Error apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6709,7 +6733,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6741,7 +6765,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6749,7 +6773,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6761,7 +6785,7 @@ Close apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6787,13 +6811,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6805,7 +6833,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6845,7 +6873,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6957,7 +6985,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7061,7 +7089,7 @@ Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7097,7 +7125,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7113,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7167,7 +7195,7 @@ of apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7175,7 +7203,7 @@ daily requests apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7183,7 +7211,7 @@ Remove API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7191,7 +7219,7 @@ Do you really want to delete the API key? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7211,7 +7239,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7283,7 +7311,7 @@ Save apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7319,11 +7347,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7359,7 +7387,15 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Change with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7367,7 +7403,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7383,7 +7419,7 @@ Lazy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7391,7 +7427,7 @@ Instant apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7399,7 +7435,7 @@ Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7407,7 +7443,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7415,7 +7451,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7423,7 +7459,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7431,7 +7467,7 @@ end of day apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7439,7 +7475,7 @@ real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7447,7 +7483,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7463,11 +7499,11 @@ Change libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7483,15 +7519,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -7518,6 +7554,14 @@ 67 + + Total amount + Total amount + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Armenia @@ -7587,7 +7631,7 @@ Security token apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7599,7 +7643,7 @@ Do you really want to generate a new security token for this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7607,7 +7651,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7672,7 +7716,7 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7680,7 +7724,7 @@ An error occurred while updating to (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7696,7 +7740,7 @@ with API access for apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7776,7 +7820,7 @@ Do you really want to delete this item? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7817,7 +7861,7 @@ Demo user account has been synced. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7852,7 +7896,7 @@ 150 - + Fee Ratio Fee Ratio @@ -7860,17 +7904,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7995,7 +8039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8007,7 +8051,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8031,7 +8075,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8039,11 +8083,11 @@ new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8256,7 +8300,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8676,7 +8720,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.de.xlf b/apps/client/src/locales/messages.de.xlf index 9a429cfad..cad4fcc92 100644 --- a/apps/client/src/locales/messages.de.xlf +++ b/apps/client/src/locales/messages.de.xlf @@ -26,7 +26,7 @@ Das Ausfallrisiko beim Börsenhandel kann erheblich sein. Es ist nicht ratsam, Geld zu investieren, welches du kurzfristig benötigst. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -42,7 +42,7 @@ bitte apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -89,14 +89,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Möchtest du diese Zugangsberechtigung wirklich widerrufen? @@ -114,7 +106,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -126,7 +118,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -142,11 +134,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -158,7 +150,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -174,7 +166,7 @@ Gesamt libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -186,15 +178,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -202,11 +194,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -218,7 +210,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -242,15 +234,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -274,11 +266,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -286,7 +282,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -302,7 +298,7 @@ Möchtest du dieses Konto wirklich löschen? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -330,7 +326,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -370,7 +366,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -386,7 +382,7 @@ Anlageprofile apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -402,7 +398,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -442,7 +438,7 @@ Datum apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -490,7 +486,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -510,7 +506,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -518,7 +514,7 @@ Möchtest du diesen Gutscheincode wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -526,7 +522,7 @@ Möchtest du den Cache wirklich leeren? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -534,7 +530,7 @@ Bitte gebe deine Systemmeldung ein: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -654,7 +650,7 @@ Möchtest du diesen Benutzer wirklich löschen? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -690,7 +686,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -730,7 +726,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -742,11 +738,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -790,7 +786,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -798,7 +794,7 @@ Aktivitäten verwalten apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -830,7 +826,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -874,7 +870,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -914,7 +910,7 @@ Absolute Brutto Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -922,11 +918,11 @@ Absolute Netto Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -934,11 +930,11 @@ Netto Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -946,7 +942,7 @@ Gesamtanlagevermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -954,7 +950,7 @@ Kaufkraft apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -962,7 +958,7 @@ Gesamtvermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -970,7 +966,7 @@ Performance pro Jahr apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -990,7 +986,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -998,7 +994,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -1010,7 +1006,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1022,7 +1018,7 @@ Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1038,7 +1034,7 @@ Datenfehler melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1046,11 +1042,11 @@ Allokation libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -1066,7 +1062,7 @@ Alle anzeigen libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -1078,7 +1074,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -1086,11 +1082,11 @@ YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -1098,11 +1094,11 @@ 1J apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -1110,11 +1106,19 @@ 5J apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Performance mit Währungseffekt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -1122,11 +1126,11 @@ Max apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -1234,7 +1238,7 @@ Möchtest du diese Anmeldemethode wirklich löschen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -1254,7 +1258,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1278,7 +1282,7 @@ Präsentationsansicht apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -1294,11 +1298,11 @@ Lokalität apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -1306,7 +1310,7 @@ Datums- und Zahlenformat apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -1314,7 +1318,7 @@ Zen Modus apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -1326,7 +1330,7 @@ Einloggen mit Fingerabdruck apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -1338,11 +1342,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1394,7 +1398,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1434,7 +1438,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1446,11 +1450,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1470,7 +1474,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -1486,7 +1490,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -1626,7 +1630,7 @@ Da du bereits eingeloggt bist, kannst du nicht auf die Live Demo zugreifen. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1690,11 +1694,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1710,7 +1714,7 @@ Märkte apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1734,7 +1738,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -1834,7 +1838,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -1854,7 +1858,7 @@ Zeitstrahl der Investitionen apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -1862,7 +1866,7 @@ Gewinner apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -1870,7 +1874,7 @@ Verlierer apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -1930,7 +1934,7 @@ Aktuelle Woche apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1974,7 +1978,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1986,7 +1990,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1994,7 +1998,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -2002,7 +2006,7 @@ Stückpreis apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -2014,7 +2018,7 @@ Kommentar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2022,7 +2026,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2034,7 +2038,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2058,7 +2062,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2070,7 +2074,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -2146,7 +2150,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -2158,7 +2162,7 @@ Kontinente apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -2174,7 +2178,7 @@ Ghostfolio verschafft dir den Überblick über dein Vermögen. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2322,7 +2326,7 @@ Möchtest du diese Aktivität wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2338,7 +2342,7 @@ kontaktiere uns apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2454,7 +2458,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -2478,7 +2482,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -2486,7 +2490,7 @@ Neueste Aktivitäten apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2498,7 +2502,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2510,7 +2514,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2526,7 +2530,7 @@ Monatlich apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -2542,7 +2546,7 @@ Einlage libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -2554,11 +2558,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -2570,7 +2574,7 @@ Ersparnisse libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -2626,7 +2630,7 @@ Filtern nach... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -2654,7 +2658,7 @@ Experimentelle Funktionen apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -2662,11 +2666,11 @@ Das Formular konnte nicht validiert werden apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -2682,7 +2686,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2702,7 +2706,7 @@ Von der Analyse ausgenommen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2714,7 +2718,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -2722,7 +2726,7 @@ Aussehen apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -2730,7 +2734,7 @@ Hell apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -2738,7 +2742,7 @@ Dunkel apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -2746,7 +2750,7 @@ Gesamtbetrag apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2754,7 +2758,7 @@ Portfolio Wertentwicklung apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -2798,7 +2802,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2806,7 +2810,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2862,7 +2866,7 @@ Bargeld apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2910,7 +2914,7 @@ Authentifizierung apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -2974,7 +2978,7 @@ Notfallfonds apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2994,7 +2998,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -3006,7 +3010,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -3014,11 +3018,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3122,7 +3126,7 @@ Symbol Zuordnung apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -3130,7 +3134,7 @@ Zeitstrahl der Dividenden apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -3138,7 +3142,7 @@ Suchst du nach einem Studentenrabatt? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3154,7 +3158,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3162,11 +3166,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -3186,7 +3190,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3194,7 +3198,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3230,7 +3234,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3238,7 +3242,7 @@ Marktdaten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -3290,7 +3294,7 @@ Jährlich apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -3314,7 +3318,7 @@ Gültig bis apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3353,6 +3357,14 @@ 22 + + No Activities + Keine Aktivitäten + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Altersvorsorge @@ -3361,6 +3373,14 @@ 28 + + Everything in Basic, plus + Alles von Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satellit @@ -3374,7 +3394,7 @@ Ausblenden von sensiblen Informationen wie absoluter Performance und Stückzahl apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -3382,7 +3402,7 @@ Unbeschwertes Erlebnis für turbulente Zeiten apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -3390,7 +3410,7 @@ Vorschau auf kommende Funktionalität apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -3414,7 +3434,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3430,7 +3450,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3446,7 +3466,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3462,7 +3482,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3510,7 +3530,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3594,7 +3614,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3610,7 +3630,7 @@ Einmalige Zahlung, keine automatische Erneuerung. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3618,11 +3638,11 @@ Das Anlageprofil konnte nicht gespeichert werden apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -3630,7 +3650,7 @@ Es ist kostenlos. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3642,7 +3662,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3662,7 +3682,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3706,7 +3726,7 @@ E-Mail und Chat Support apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3758,7 +3778,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3782,7 +3802,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3814,7 +3834,7 @@ Möchtest du diese Aktivitäten wirklich löschen? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3825,6 +3845,14 @@ 306 + + Explore + Entdecke + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By Bis @@ -3846,7 +3874,7 @@ Aktuelles Jahr apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -3862,11 +3890,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3882,7 +3910,7 @@ Das Anlageprofil wurde gespeichert apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -3890,7 +3918,7 @@ Möchtest du diese Plattform wirklich löschen? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 @@ -3898,7 +3926,7 @@ Plattformen apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3906,7 +3934,7 @@ Cash-Bestand aktualisieren apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4026,7 +4054,7 @@ Aktueller Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4034,7 +4062,7 @@ Längster Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4078,7 +4106,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -4086,7 +4114,7 @@ Verbindlichkeiten apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4218,7 +4246,7 @@ Open Source Software apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -4242,7 +4270,7 @@ Scraper Konfiguration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4481,20 +4509,12 @@ 43 - - Everything in - Alles von - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETFs ohne Länder apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -4502,7 +4522,7 @@ ETFs ohne Sektoren apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -4510,7 +4530,7 @@ Anlagevermögen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4638,7 +4658,7 @@ Biometrische Authentifizierung apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -4730,7 +4750,7 @@ Daten exportieren apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -4738,11 +4758,11 @@ Währungen apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4790,11 +4810,11 @@ Die Scraper Konfiguration konnte nicht geparsed werden apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -5348,7 +5368,7 @@ Schweiz apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -5360,7 +5380,7 @@ Weltweit apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -5388,7 +5408,7 @@ mit deiner Universitäts-E-Mail-Adresse apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5456,7 +5476,7 @@ Gebühr apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5488,7 +5508,7 @@ Möchtest du diesen Tag wirklich löschen? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -5556,7 +5576,7 @@ Mitgliedschaft apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5572,7 +5592,7 @@ Fordere ihn an apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5712,7 +5732,7 @@ Ups! Die historischen Daten konnten nicht geparsed werden. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -5720,7 +5740,7 @@ Möchtest du diese Systemmeldung wirklich löschen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -5744,7 +5764,7 @@ Cash-Bestände apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5764,7 +5784,7 @@ Möchtest du diesen Cash-Bestand wirklich löschen? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5780,7 +5800,7 @@ Der aktuelle Marktpreis ist apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5788,7 +5808,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5876,15 +5896,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -5892,7 +5912,7 @@ hier apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5900,7 +5920,7 @@ Position abschliessen apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5908,7 +5928,7 @@ Absolute Anlage Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5916,7 +5936,7 @@ Anlage Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5924,7 +5944,7 @@ Absolute Währungsperformance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5932,7 +5952,7 @@ Währungsperformance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5940,7 +5960,7 @@ Seit Wochenbeginn libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5948,11 +5968,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5960,7 +5980,7 @@ Seit Monatsbeginn libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5968,11 +5988,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5980,7 +6000,7 @@ Seit Jahresbeginn libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -6016,7 +6036,7 @@ Jahr apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6028,7 +6048,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6036,11 +6056,11 @@ Jahre apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6056,7 +6076,7 @@ Finanzmarktdaten synchronisieren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6068,7 +6088,7 @@ Allgemein apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6076,7 +6096,7 @@ Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6088,7 +6108,7 @@ Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6233,7 +6253,7 @@ Möchtest du dieses Ghostfolio Konto wirklich schliessen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6241,7 +6261,7 @@ Gefahrenzone apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6249,7 +6269,7 @@ Konto schliessen apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6281,7 +6301,7 @@ Berücksichtigen in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6289,7 +6309,7 @@ Ups! Beim Einrichten der biometrischen Authentifizierung ist ein Fehler aufgetreten. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6305,7 +6325,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6353,7 +6373,7 @@ Möchtest du deine persönliche Anlagestrategie verfeinern? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6361,7 +6381,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6369,7 +6389,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6377,7 +6397,7 @@ Budgetierung apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6393,47 +6413,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6441,7 +6465,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6449,7 +6473,7 @@ Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6461,7 +6485,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6473,7 +6497,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6481,7 +6505,7 @@ Datenschutz apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6489,7 +6513,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6497,7 +6521,7 @@ Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6505,7 +6529,7 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6513,7 +6537,7 @@ Vermögen apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6521,7 +6545,7 @@ Vermögensverwaltung apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6681,7 +6705,7 @@ Fehler apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6733,7 +6757,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6765,7 +6789,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6773,7 +6797,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6785,7 +6809,7 @@ Schliessen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6811,13 +6835,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6829,7 +6857,7 @@ Rolle apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6869,7 +6897,7 @@ Wenn du die Eröffnung eines Kontos planst bei apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6981,7 +7009,7 @@ um unseren Empfehlungslink zu verwenden und eine Ghostfolio Premium-Mitgliedschaft für ein Jahr zu erhalten apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7085,7 +7113,7 @@ API-Schlüssel setzen apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7121,7 +7149,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7137,7 +7165,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7191,7 +7219,7 @@ von apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7199,7 +7227,7 @@ täglichen Anfragen apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7207,7 +7235,7 @@ API-Schlüssel löschen apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7215,7 +7243,7 @@ Möchtest du den API-Schlüssel wirklich löschen? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7235,7 +7263,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7307,7 +7335,7 @@ Speichern apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7343,11 +7371,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7383,7 +7411,15 @@ Bitte gebe deinen Ghostfolio API-Schlüssel ein. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Änderung mit Währungseffekt + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7391,7 +7427,7 @@ KI-Anweisung wurde in die Zwischenablage kopiert apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7407,7 +7443,7 @@ Verzögert apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7415,7 +7451,7 @@ Sofort apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7423,7 +7459,7 @@ Standardmarktpreis apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7431,7 +7467,7 @@ Modus apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7439,7 +7475,7 @@ Selektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7447,7 +7483,7 @@ HTTP Request-Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7455,7 +7491,7 @@ Tagesende apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7463,7 +7499,7 @@ in Echtzeit apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7471,7 +7507,7 @@ Öffne Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7487,11 +7523,11 @@ Änderung libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7507,15 +7543,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -7542,6 +7578,14 @@ 67 + + Total amount + Gesamtbetrag + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Armenien @@ -7611,7 +7655,7 @@ Sicherheits-Token apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7623,7 +7667,7 @@ Möchtest du für diesen Benutzer wirklich ein neues Sicherheits-Token generieren? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7631,7 +7675,7 @@ Konto, Position oder Seite finden... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7696,7 +7740,7 @@ () wird bereits verwendet. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7704,7 +7748,7 @@ Bei der Änderung zu () ist ein Fehler aufgetreten. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7720,7 +7764,7 @@ inklusive API-Zugriff für apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7776,7 +7820,7 @@ Möchtest du diesen Eintrag wirklich löschen? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7817,12 +7861,12 @@ Demo Benutzerkonto wurde synchronisiert. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 Sync Demo User Account - Synchronisiere Demo Benutzerkonto + Synchronisiere Demo Benutzerkonto apps/client/src/app/components/admin-overview/admin-overview.html 195 @@ -7852,7 +7896,7 @@ 150 - + Fee Ratio Gebührenverhältnis @@ -7860,17 +7904,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Die Gebühren übersteigen ${thresholdMax}% deiner ursprünglichen Investition (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Die Gebühren übersteigen ${thresholdMax}% deines gesamten Investitionsvolumens (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Die Gebühren übersteigen ${thresholdMax}% deiner ursprünglichen Investition (${feeRatio}%) nicht + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Die Gebühren übersteigen ${thresholdMax}% deines gesamten Investitionsvolumens (${feeRatio}%) nicht apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7995,7 +8039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8007,7 +8051,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8031,7 +8075,7 @@ Aktueller Monat apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8039,11 +8083,11 @@ neu apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8256,7 +8300,7 @@ Anlageprofil verwalten apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8676,7 +8720,7 @@ Registrierungsdatum apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.es.xlf b/apps/client/src/locales/messages.es.xlf index 9be8108bd..a904cbae8 100644 --- a/apps/client/src/locales/messages.es.xlf +++ b/apps/client/src/locales/messages.es.xlf @@ -27,7 +27,7 @@ El riesgo de pérdida en trading puede ser sustancial. No es aconsejable invertir dinero que puedas necesitar a corto plazo. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -40,10 +40,10 @@ please - please + por favor apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -84,20 +84,12 @@ with - with + con apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? ¿Quieres revocar el acceso concedido? @@ -115,7 +107,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -127,7 +119,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -143,11 +135,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -159,7 +151,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -175,7 +167,7 @@ Total libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -187,15 +179,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -203,11 +195,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -219,7 +211,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -243,15 +235,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -275,11 +267,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -287,7 +283,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -303,7 +299,7 @@ ¿Estás seguro de eliminar esta cuenta? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -331,7 +327,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -371,12 +367,12 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 and is driven by the efforts of its contributors - and is driven by the efforts of its contributors + y es impulsado por los esfuerzos de sus contribuidores apps/client/src/app/pages/about/overview/about-overview-page.html 49 @@ -387,7 +383,7 @@ Perfiles de activos. apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -403,7 +399,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -443,7 +439,7 @@ Fecha apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -491,7 +487,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -511,7 +507,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -519,7 +515,7 @@ ¿Estás seguro de eliminar este cupón? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -527,7 +523,7 @@ ¿Estás seguro de limpiar la caché? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -535,7 +531,7 @@ Por favor, establece tu mensaje del sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -639,7 +635,7 @@ ¿Estás seguro de eliminar este usuario? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -660,7 +656,7 @@ No auto-renewal on membership. - No auto-renewal on membership. + No se renueva automáticamente la membresía. apps/client/src/app/components/user-account-membership/user-account-membership.html 74 @@ -675,7 +671,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -715,7 +711,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -727,11 +723,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -775,7 +771,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -783,7 +779,7 @@ Gestión de las operaciones apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -815,7 +811,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -859,7 +855,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -899,7 +895,7 @@ Rendimiento bruto absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -907,11 +903,11 @@ Rendimiento neto absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -919,11 +915,11 @@ Rendimiento neto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -931,7 +927,7 @@ Total de activos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -939,7 +935,7 @@ Capacidad de compra apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -947,7 +943,7 @@ Patrimonio neto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -955,7 +951,7 @@ Rendimiento anualizado apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -975,7 +971,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -983,7 +979,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -995,7 +991,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1007,7 +1003,7 @@ Etiquetas apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1023,7 +1019,7 @@ Reporta un anomalía de los datos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1031,11 +1027,11 @@ Distribución libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -1051,7 +1047,7 @@ Mostrar todos libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -1063,7 +1059,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -1071,11 +1067,11 @@ Desde principio de año apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -1083,11 +1079,11 @@ 1 año apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -1095,11 +1091,19 @@ 5 años apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Rendimiento con el efecto del tipo de cambio de divisa + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -1107,11 +1111,11 @@ Máximo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -1219,7 +1223,7 @@ ¿Estás seguro de eliminar este método de acceso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -1239,7 +1243,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1263,7 +1267,7 @@ Vista del presentador apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -1279,11 +1283,11 @@ Ubicación apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -1291,7 +1295,7 @@ Formato de fecha y número apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -1299,7 +1303,7 @@ Modo Zen apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -1311,7 +1315,7 @@ Iniciar sesión con huella digital apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -1323,11 +1327,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1379,7 +1383,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1419,7 +1423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1431,11 +1435,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1455,7 +1459,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -1471,7 +1475,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -1611,7 +1615,7 @@ Como estás conectado, no puedes acceder a la cuenta de demostración. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1675,11 +1679,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1695,7 +1699,7 @@ Mercados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1719,7 +1723,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -1819,7 +1823,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -1839,7 +1843,7 @@ Cronología de la inversión apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -1847,7 +1851,7 @@ Lo mejor apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -1855,7 +1859,7 @@ Lo peor apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -1912,10 +1916,10 @@ Current week - Current week + Semana actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1959,7 +1963,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1971,7 +1975,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1979,7 +1983,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1987,7 +1991,7 @@ Precio unitario apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1999,7 +2003,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2007,7 +2011,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2019,7 +2023,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2043,7 +2047,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2055,7 +2059,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -2076,7 +2080,7 @@ or start a discussion at - or start a discussion at + o iniciar una discusión en apps/client/src/app/pages/about/overview/about-overview-page.html 94 @@ -2131,7 +2135,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -2143,12 +2147,12 @@ Continentes apps/client/src/app/pages/public/public-page.html - 132 + 131 Sustainable retirement income - Sustainable retirement income + Ingreso sostenible de retiro apps/client/src/app/pages/portfolio/fire/fire-page.html 41 @@ -2159,7 +2163,7 @@ Ghostfolio te permite hacer un seguimiento de tu riqueza. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2307,7 +2311,7 @@ ¿Estás seguro de eliminar esta operación? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2320,10 +2324,10 @@ contact us - contact us + contactarnos apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2415,15 +2419,15 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 Latest activities - Latest activities + Últimas actividades apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2443,7 +2447,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2455,7 +2459,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2487,7 +2491,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -2511,7 +2515,7 @@ Ahorros libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -2523,11 +2527,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -2536,7 +2540,7 @@ annual interest rate - annual interest rate + tasa de interés anual apps/client/src/app/pages/portfolio/fire/fire-page.html 185 @@ -2547,7 +2551,7 @@ Depósito libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -2555,7 +2559,7 @@ Mensual apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -2611,7 +2615,7 @@ Filtrar por... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -2639,7 +2643,7 @@ Funcionalidades experimentales apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -2647,7 +2651,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2656,14 +2660,14 @@ Could not validate form - Could not validate form + No se pudo validar el formulario apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -2687,7 +2691,7 @@ Excluido del análisis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2699,7 +2703,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -2707,7 +2711,7 @@ Apariencia apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -2715,7 +2719,7 @@ Claro apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -2723,7 +2727,7 @@ Oscuro apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -2731,7 +2735,7 @@ Importe total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2739,7 +2743,7 @@ Evolución cartera apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -2783,7 +2787,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2791,7 +2795,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2847,7 +2851,7 @@ Efectivo apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2892,10 +2896,10 @@ Authentication - Authentication + Autenticación apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -2959,7 +2963,7 @@ Fondo de emergencia apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2979,7 +2983,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -2991,7 +2995,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -2999,11 +3003,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3044,7 +3048,7 @@ If you retire today, you would be able to withdraw - If you retire today, you would be able to withdraw + Si te retirases hoy, podrías sacar apps/client/src/app/pages/portfolio/fire/fire-page.html 68 @@ -3107,15 +3111,15 @@ Mapeo de símbolos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 Looking for a student discount? - Looking for a student discount? + ¿Buscando un descuento para estudiantes? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3131,7 +3135,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3139,11 +3143,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -3155,7 +3159,7 @@ Calendario de dividendos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -3171,7 +3175,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3179,7 +3183,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3215,7 +3219,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3223,7 +3227,7 @@ Datos del mercado apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -3275,7 +3279,7 @@ Anual apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -3299,7 +3303,7 @@ Válido hasta apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3338,6 +3342,14 @@ 22 + + No Activities + Sin actividades + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Provisión de jubilación @@ -3346,6 +3358,14 @@ 28 + + Everything in Basic, plus + Todo en Básico, más + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satélite @@ -3359,7 +3379,7 @@ Protección de información confidencial como rendimientos absolutos y valores cuantitativos apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -3367,7 +3387,7 @@ Experiencia sin distracciones para tiempos turbulentos apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -3375,7 +3395,7 @@ Un adelanto de las próximas funciones apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -3399,7 +3419,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3415,7 +3435,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3431,7 +3451,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3447,7 +3467,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3495,7 +3515,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3579,7 +3599,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3595,19 +3615,19 @@ Pago único, sin renovación automática. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 Could not save asset profile - Could not save asset profile + No se pudo guardar el perfil del activo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -3615,7 +3635,7 @@ Es gratis. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3627,7 +3647,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3647,7 +3667,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3691,7 +3711,7 @@ Soporte a Traves de Email y Chat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3735,7 +3755,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3759,7 +3779,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3791,7 +3811,7 @@ ¿Realmente deseas eliminar estas actividades? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3802,9 +3822,17 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By - By + Por apps/client/src/app/pages/portfolio/fire/fire-page.html 139 @@ -3820,10 +3848,10 @@ Current year - Current year + Año actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -3839,11 +3867,11 @@ ¿La URL? apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3856,10 +3884,10 @@ Asset profile has been saved - Asset profile has been saved + El perfil del activo ha sido guardado apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -3867,7 +3895,7 @@ ¿Realmente deseas eliminar esta plataforma? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 @@ -3875,7 +3903,7 @@ Plataformas apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3883,7 +3911,7 @@ Actualizar saldo en efectivo apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4003,7 +4031,7 @@ Racha actual apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4011,7 +4039,7 @@ Racha más larga apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4048,14 +4076,14 @@ View Details - View Details + Ver detalles apps/client/src/app/components/admin-users/admin-users.html 225 libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -4063,7 +4091,7 @@ Pasivos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4184,7 +4212,7 @@ per week - per week + por semana apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 130 @@ -4195,7 +4223,7 @@ Software de código abierto apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -4208,7 +4236,7 @@ and we share aggregated key metrics of the platform’s performance - and we share aggregated key metrics of the platform’s performance + y compartimos agregados métricas clave del rendimiento de la plataforma apps/client/src/app/pages/about/overview/about-overview-page.html 32 @@ -4219,7 +4247,7 @@ Configuración del scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4252,7 +4280,7 @@ Website of Thomas Kaul - Website of Thomas Kaul + Sitio web de Thomas Kaul apps/client/src/app/pages/about/overview/about-overview-page.html 44 @@ -4432,7 +4460,7 @@ Sign in with OpenID Connect - Sign in with OpenID Connect + Iniciar sesión con OpenID Connect apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 55 @@ -4458,20 +4486,12 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETFs sin países apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -4479,7 +4499,7 @@ ETFs sin sectores apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -4487,7 +4507,7 @@ Activos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4532,7 +4552,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - The source code is fully available as open source software (OSS) under the AGPL-3.0 license + El código fuente está disponible completamente en software de código abierto (OSS) bajo la licencia AGPL-3.0 apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -4604,7 +4624,7 @@ this is projected to increase to - this is projected to increase to + esto se proyecta a aumentar a apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -4615,7 +4635,7 @@ Autenticación biométrica apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -4656,7 +4676,7 @@ Job ID - Job ID + ID de trabajo apps/client/src/app/components/admin-jobs/admin-jobs.html 34 @@ -4707,7 +4727,7 @@ Exportar datos apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -4715,11 +4735,11 @@ Monedas apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4740,7 +4760,7 @@ for - for + para apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 128 @@ -4764,14 +4784,14 @@ Could not parse scraper configuration - Could not parse scraper configuration + No se pudo analizar la configuración del scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -4808,7 +4828,7 @@ Edit access - Edit access + Editar acceso apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 11 @@ -4880,7 +4900,7 @@ Get access to 80’000+ tickers from over 50 exchanges - Get access to 80’000+ tickers from over 50 exchanges + Obtén acceso a más de 80,000 tickers de más de 50 exchanges apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 84 @@ -5064,7 +5084,7 @@ less than - less than + menos que apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 129 @@ -5325,7 +5345,7 @@ Suiza apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -5337,7 +5357,7 @@ Global apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -5354,7 +5374,7 @@ Ghostfolio Status - Ghostfolio Status + Estado de Ghostfolio apps/client/src/app/pages/about/overview/about-overview-page.html 62 @@ -5362,10 +5382,10 @@ with your university e-mail address - with your university e-mail address + con tu dirección de correo electrónico de la universidad apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5382,7 +5402,7 @@ and a safe withdrawal rate (SWR) of - and a safe withdrawal rate (SWR) of + y una tasa de retiro segura (SWR) de apps/client/src/app/pages/portfolio/fire/fire-page.html 108 @@ -5433,7 +5453,7 @@ Tarifa apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5465,7 +5485,7 @@ ¿Realmente deseas eliminar esta etiqueta? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -5533,7 +5553,7 @@ Membresía apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5546,10 +5566,10 @@ Request it - Request it + Solicitar apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5602,7 +5622,7 @@ , - , + , apps/client/src/app/pages/portfolio/fire/fire-page.html 145 @@ -5618,7 +5638,7 @@ per month - per month + por mes apps/client/src/app/pages/portfolio/fire/fire-page.html 94 @@ -5689,7 +5709,7 @@ ¡Ups! No se pudieron analizar los datos históricos. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -5697,7 +5717,7 @@ ¿Realmente deseas eliminar este mensaje del sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -5721,7 +5741,7 @@ Saldos de efectivo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5741,7 +5761,7 @@ ¿Realmente desea eliminar el saldo de esta cuenta? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5757,7 +5777,7 @@ El precio actual de mercado es apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5765,7 +5785,7 @@ Prueba apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5853,31 +5873,31 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 here - here + aquí apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 Close Holding - Close Holding + Cerrar posición apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5885,7 +5905,7 @@ Rendimiento absoluto de los activos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5893,7 +5913,7 @@ Rendimiento de activos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5901,7 +5921,7 @@ Rendimiento absoluto de divisas apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5909,7 +5929,7 @@ Rendimiento de la moneda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5917,7 +5937,7 @@ Semana hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5925,11 +5945,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5937,7 +5957,7 @@ Mes hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5945,11 +5965,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5957,7 +5977,7 @@ El año hasta la fecha libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5993,7 +6013,7 @@ año apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6005,7 +6025,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6013,11 +6033,11 @@ años apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6033,7 +6053,7 @@ Recopilación de datos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6045,7 +6065,7 @@ General apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6053,7 +6073,7 @@ Nube apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6065,7 +6085,7 @@ Autoalojamiento apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6175,7 +6195,7 @@ {VAR_PLURAL, plural, =1 {activity} other {activities}} - {VAR_PLURAL, plural, =1 {activity} other {activities}} + {VAR_PLURAL, plural, =1 {actividad} other {actividades}} apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 14 @@ -6210,7 +6230,7 @@ ¿Estás seguro de querer borrar tu cuenta de Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6218,7 +6238,7 @@ Zona peligrosa apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6226,7 +6246,7 @@ Eliminar cuenta apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6255,10 +6275,10 @@ Include in - Include in + Incluir en apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6266,7 +6286,7 @@ ¡Ups! Hubo un error al configurar la autenticación biométrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6282,7 +6302,7 @@ Puntos de referencia apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6330,7 +6350,7 @@ ¿Te gustaría refinar tu estrategia de inversión personal? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6338,7 +6358,7 @@ Alternativa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6346,7 +6366,7 @@ Aplicación apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6354,7 +6374,7 @@ Presupuestación apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6370,47 +6390,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6418,7 +6442,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6426,7 +6450,7 @@ Inversor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6438,7 +6462,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6450,7 +6474,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6458,7 +6482,7 @@ Privacidad apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6466,7 +6490,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6474,7 +6498,7 @@ Herramienta apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6482,7 +6506,7 @@ Experiencia del usuario apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6490,7 +6514,7 @@ Riqueza apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6498,7 +6522,7 @@ Gestión de patrimonios apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6535,7 +6559,7 @@ View Holding - View Holding + Ver fondos libs/ui/src/lib/activities-table/activities-table.component.html 450 @@ -6658,7 +6682,7 @@ Error apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6679,7 +6703,7 @@ Oops! Could not update access. - Oops! Could not update access. + Oops! No se pudo actualizar el acceso. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 178 @@ -6687,7 +6711,7 @@ , based on your total assets of - , based on your total assets of + , basado en tus activos totales de apps/client/src/app/pages/portfolio/fire/fire-page.html 96 @@ -6710,7 +6734,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6742,7 +6766,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6750,7 +6774,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6759,10 +6783,10 @@ Close - Cerca + Cerrar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6788,13 +6812,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6803,10 +6831,10 @@ Role - Role + Rol apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6835,7 +6863,7 @@ Change with currency effect Change - Change with currency effect Change + Cambiar con efecto de cambio dedivisa Cambiar apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 63 @@ -6843,15 +6871,15 @@ If you plan to open an account at - If you plan to open an account at + Si planeas abrir una cuenta en apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 Performance with currency effect Performance - Performance with currency effect Performance + Rendimiento con cambio de divisa Rendimiento apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html 83 @@ -6875,7 +6903,7 @@ send an e-mail to - send an e-mail to + enviar un correo electrónico a apps/client/src/app/pages/about/overview/about-overview-page.html 87 @@ -6947,7 +6975,7 @@ , assuming a - , assuming a + , asumiendo un apps/client/src/app/pages/portfolio/fire/fire-page.html 174 @@ -6955,10 +6983,10 @@ to use our referral link and get a Ghostfolio Premium membership for one year - to use our referral link and get a Ghostfolio Premium membership for one year + para usar nuestro enlace de referido y obtener una membresía Ghostfolio Premium por un año apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7035,7 +7063,7 @@ Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. - Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. + Ghostfolio es una aplicación de gestión de patrimonio para aquellos individuos que desean realizar un seguimiento de acciones, ETFs o criptomonedas y tomar decisiones de inversión sólidas y basadas en datos. apps/client/src/app/pages/about/overview/about-overview-page.html 10 @@ -7062,7 +7090,7 @@ Configurar clave API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7098,7 +7126,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7114,7 +7142,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7168,7 +7196,7 @@ de apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7176,7 +7204,7 @@ solicitudes diarias apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7184,7 +7212,7 @@ Eliminar clave API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7192,7 +7220,7 @@ ¿Realmente deseas eliminar la clave API? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7212,7 +7240,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7284,7 +7312,7 @@ Ahorrar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7320,11 +7348,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7349,7 +7377,7 @@ Check the system status at - Check the system status at + Verificar el estado del sistema en apps/client/src/app/pages/about/overview/about-overview-page.html 57 @@ -7360,7 +7388,15 @@ Por favor, ingresa tu clave API de Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Cambiar con el efecto del tipo de cambio de divisa + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7368,7 +7404,7 @@ El aviso de IA ha sido copiado al portapapeles apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7384,7 +7420,7 @@ Perezoso apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7392,7 +7428,7 @@ Instantáneo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7400,7 +7436,7 @@ Precio de mercado por defecto apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7408,7 +7444,7 @@ Modo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7416,7 +7452,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7424,7 +7460,7 @@ Encabezados de solicitud HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7432,7 +7468,7 @@ final del día apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7440,7 +7476,7 @@ en tiempo real apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7448,7 +7484,7 @@ Abrir Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7464,11 +7500,11 @@ Cambiar libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7484,20 +7520,20 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 The project has been initiated by - The project has been initiated by + El proyecto ha sido iniciado por apps/client/src/app/pages/about/overview/about-overview-page.html 40 @@ -7519,6 +7555,14 @@ 67 + + Total amount + Cantidad total + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Armenia @@ -7588,7 +7632,7 @@ Token de seguridad apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7600,15 +7644,15 @@ ¿Realmente deseas generar un nuevo token de seguridad para este usuario? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 Find account, holding or page... - Find account, holding or page... + Buscar cuenta, posición o página... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7673,7 +7717,7 @@ () ya está en uso. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7681,7 +7725,7 @@ Ocurrió un error al actualizar a (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7697,7 +7741,7 @@ con acceso a la API para apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7777,7 +7821,7 @@ ¿Realmente deseas eliminar este elemento? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7818,7 +7862,7 @@ La cuenta de usuario de demostración se ha sincronizado. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7853,7 +7897,7 @@ 150 - + Fee Ratio Relación de tarifas @@ -7861,17 +7905,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Las tarifas superan el ${thresholdMax}% de su inversión inicial (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Las tarifas superan el ${thresholdMax}% de su volumen total de inversión (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Las tarifas no superan el ${thresholdMax}% de su inversión inicial (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + Las tarifas no superan el ${thresholdMax}% de su volumen total de inversión (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7996,7 +8040,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8008,7 +8052,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8029,10 +8073,10 @@ Current month - Current month + Mes actual apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8040,11 +8084,11 @@ nuevo apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8214,7 +8258,7 @@ If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ - If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ + Si encuentras un error, deseas sugerir una mejora o una nueva característica, por favor únete a la comunidad Ghostfolio Slack, publica en @ghostfolio_ apps/client/src/app/pages/about/overview/about-overview-page.html 69 @@ -8246,7 +8290,7 @@ - + apps/client/src/app/components/admin-users/admin-users.html 39 @@ -8257,7 +8301,7 @@ Gestionar perfil de activo apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8314,7 +8358,7 @@ Economic Market Cluster Risks - Economic Market Cluster Risks + Riesgos del clúster de mercados económicos apps/client/src/app/pages/i18n/i18n-page.html 106 @@ -8322,7 +8366,7 @@ Emergency Fund - Emergency Fund + Fondo de emergencia apps/client/src/app/pages/i18n/i18n-page.html 144 @@ -8330,7 +8374,7 @@ Fees - Fees + Comisiones apps/client/src/app/pages/i18n/i18n-page.html 161 @@ -8338,7 +8382,7 @@ Liquidity - Liquidity + Liquidez apps/client/src/app/pages/i18n/i18n-page.html 70 @@ -8346,7 +8390,7 @@ Buying Power - Buying Power + Poder de compra apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -8354,7 +8398,7 @@ Your buying power is below ${thresholdMin} ${baseCurrency} - Your buying power is below ${thresholdMin} ${baseCurrency} + Tu poder de compra es inferior a ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 73 @@ -8362,7 +8406,7 @@ Your buying power is 0 ${baseCurrency} - Your buying power is 0 ${baseCurrency} + Tu poder de compra es 0 ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 77 @@ -8370,7 +8414,7 @@ Your buying power exceeds ${thresholdMin} ${baseCurrency} - Your buying power exceeds ${thresholdMin} ${baseCurrency} + Tu poder de compra excede ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 80 @@ -8402,7 +8446,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% + La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 112 @@ -8410,7 +8454,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% + La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 117 @@ -8418,7 +8462,7 @@ The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución a los mercados desarrollados de tu inversión actual (${developedMarketsValueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 122 @@ -8434,7 +8478,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% + La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 130 @@ -8442,7 +8486,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% + La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 135 @@ -8450,7 +8494,7 @@ The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución a los mercados emergentes de tu inversión actual (${emergingMarketsValueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 140 @@ -8474,7 +8518,7 @@ Asia-Pacific - Asia-Pacific + Asia-Pacífico apps/client/src/app/pages/i18n/i18n-page.html 165 @@ -8482,7 +8526,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 167 @@ -8490,7 +8534,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 171 @@ -8498,7 +8542,7 @@ The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución al mercado de Asia-Pacífico de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 175 @@ -8506,7 +8550,7 @@ Emerging Markets - Emerging Markets + Mercados emergentes apps/client/src/app/pages/i18n/i18n-page.html 180 @@ -8514,7 +8558,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 183 @@ -8522,7 +8566,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 187 @@ -8530,7 +8574,7 @@ The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución a los mercados emergentes de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 191 @@ -8538,7 +8582,7 @@ Europe - Europe + Europa apps/client/src/app/pages/i18n/i18n-page.html 195 @@ -8546,7 +8590,7 @@ The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% - The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + La contribución al mercado europeo de tu inversión actual (${valueRatio}%) supera el ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 197 @@ -8554,7 +8598,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% - The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + La contribución al mercado europeo de tu inversión actual (${valueRatio}%) es inferior al ${thresholdMin}% apps/client/src/app/pages/i18n/i18n-page.html 201 @@ -8562,7 +8606,7 @@ The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% - The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + La contribución al mercado europeo de tu inversión actual (${valueRatio}%) está dentro del rango de ${thresholdMin}% y ${thresholdMax}% apps/client/src/app/pages/i18n/i18n-page.html 205 @@ -8674,10 +8718,10 @@ Registration Date - Registration Date + Fecha de registro apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.fr.xlf b/apps/client/src/locales/messages.fr.xlf index 5bb9d6489..f01a3a505 100644 --- a/apps/client/src/locales/messages.fr.xlf +++ b/apps/client/src/locales/messages.fr.xlf @@ -6,7 +6,7 @@ Le risque de perte en investissant peut être important. Il est déconseillé d’investir de l’argent dont vous pourriez avoir besoin à court terme. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -34,7 +34,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -81,14 +81,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Voulez-vous vraiment révoquer cet accès ? @@ -110,7 +102,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -122,7 +114,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -134,7 +126,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -150,11 +142,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -166,7 +158,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -182,7 +174,7 @@ Total libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -194,7 +186,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -206,11 +198,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -230,7 +222,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -242,15 +234,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -258,11 +250,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -274,7 +266,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -298,15 +290,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -330,11 +322,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -342,7 +338,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -358,7 +354,7 @@ Voulez-vous vraiment supprimer ce compte ? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -378,7 +374,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -418,7 +414,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -442,7 +438,7 @@ Profils d’Actifs apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -458,7 +454,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -498,7 +494,7 @@ Date apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -534,7 +530,7 @@ Filtrer par... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -554,7 +550,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -574,7 +570,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -642,7 +638,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -654,7 +650,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -662,7 +658,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -674,7 +670,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -686,7 +682,7 @@ Équivalence de Symboles apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -694,7 +690,7 @@ Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -702,7 +698,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -710,7 +706,7 @@ Voulez-vous vraiment supprimer ce code promotionnel ? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -718,7 +714,7 @@ Voulez-vous vraiment vider le cache ? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -726,7 +722,7 @@ Veuillez définir votre message système : apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -766,7 +762,7 @@ Étiquettes apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -850,7 +846,7 @@ Voulez-vous vraiment supprimer cet·te utilisateur·rice ? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -886,7 +882,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -902,11 +898,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -934,7 +930,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -946,7 +942,7 @@ Référence apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1010,7 +1006,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -1018,7 +1014,7 @@ Gérer les Activités apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -1070,7 +1066,7 @@ Montant Total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1098,7 +1094,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -1142,7 +1138,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1182,7 +1178,7 @@ Performance Absolue Brute apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1190,11 +1186,11 @@ Performance Absolue Nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -1202,11 +1198,11 @@ Performance nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -1214,7 +1210,7 @@ Actifs Totaux apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1222,7 +1218,7 @@ Pouvoir d’Achat apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1230,7 +1226,7 @@ Exclus de l’Analyse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1238,7 +1234,7 @@ Fortune apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1246,7 +1242,7 @@ Performance annualisée apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1282,7 +1278,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1290,7 +1286,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1298,7 +1294,7 @@ Signaler une Erreur de Données apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1310,7 +1306,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -1318,11 +1314,11 @@ CDA apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -1330,11 +1326,11 @@ 1A apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -1342,11 +1338,19 @@ 5A apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Performance with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -1354,11 +1358,11 @@ Max apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -1474,7 +1478,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -1514,7 +1518,7 @@ Voulez-vous vraiment supprimer cette méthode de connexion ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -1534,7 +1538,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1558,7 +1562,7 @@ Vue de Présentation apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -1582,11 +1586,11 @@ Paramètres régionaux apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -1594,7 +1598,7 @@ Format de date et d’heure apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -1602,7 +1606,7 @@ Apparence apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -1610,7 +1614,7 @@ Clair apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -1618,7 +1622,7 @@ Sombre apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -1626,7 +1630,7 @@ Mode Zen apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -1638,7 +1642,7 @@ Se connecter avec empreinte apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -1646,7 +1650,7 @@ Fonctionnalités expérimentales apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -1658,11 +1662,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1714,7 +1718,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1758,7 +1762,7 @@ Données du marché apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -1902,7 +1906,7 @@ Puisque vous êtes déjà connecté·e, vous ne pouvez pas accéder au compte de démonstration. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1990,7 +1994,7 @@ Marchés apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -2014,7 +2018,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -2042,7 +2046,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2066,7 +2070,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2078,7 +2082,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -2094,7 +2098,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -2138,7 +2142,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -2146,7 +2150,7 @@ Prix Unitaire apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -2218,7 +2222,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -2310,7 +2314,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -2334,7 +2338,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -2342,7 +2346,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2354,7 +2358,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2366,7 +2370,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2386,7 +2390,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -2402,7 +2406,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -2410,11 +2414,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -2434,7 +2438,7 @@ Dépôt libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -2442,7 +2446,7 @@ Mensuel apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -2450,7 +2454,7 @@ Haut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -2458,7 +2462,7 @@ Bas apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -2466,7 +2470,7 @@ Évolution du Portefeuille apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -2474,7 +2478,7 @@ Historique des Investissements apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -2482,7 +2486,7 @@ Historique des Dividendes apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -2546,7 +2550,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -2562,7 +2566,7 @@ Ghostfolio vous aide à garder un aperçu de votre patrimoine. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2574,7 +2578,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -2586,11 +2590,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -2714,11 +2718,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2798,7 +2802,7 @@ Voulez-vous vraiment supprimer cette activité ? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2814,7 +2818,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2850,11 +2854,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -2866,7 +2870,7 @@ Épargne libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -2874,11 +2878,11 @@ Part libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -2894,7 +2898,7 @@ Montrer tout libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -2930,7 +2934,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2938,7 +2942,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2962,7 +2966,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2970,7 +2974,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -2982,7 +2986,7 @@ Fonds d’Urgence apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -3002,7 +3006,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -3050,7 +3054,7 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -3098,7 +3102,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -3230,7 +3234,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -3238,11 +3242,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3274,7 +3278,7 @@ Annuel apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -3298,7 +3302,7 @@ Valide jusqu’au apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3337,6 +3341,14 @@ 22 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Réserve pour retraite @@ -3345,6 +3357,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satellite @@ -3358,7 +3378,7 @@ Protection pour les informations sensibles telles que la performance absolue et les montants apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -3366,7 +3386,7 @@ Expérience sans distraction pour les périodes tumultueuses apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -3374,7 +3394,7 @@ Avant-première de fonctionnalités futures apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -3398,7 +3418,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3414,7 +3434,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3430,7 +3450,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3446,7 +3466,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3494,7 +3514,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3578,7 +3598,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3594,7 +3614,7 @@ Paiement unique, sans auto-renouvellement. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3602,11 +3622,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -3614,7 +3634,7 @@ C’est gratuit. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3626,7 +3646,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3646,7 +3666,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3690,7 +3710,7 @@ Support par E-mail et Tchat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3734,7 +3754,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3758,7 +3778,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3790,7 +3810,7 @@ Voulez-vous vraiment supprimer toutes vos activités ? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3801,6 +3821,14 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By By @@ -3822,7 +3850,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -3838,11 +3866,11 @@ Lien apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3858,7 +3886,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -3866,7 +3894,7 @@ Voulez-vous vraiment supprimer cette plateforme ? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 @@ -3874,7 +3902,7 @@ Platformes apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3882,7 +3910,7 @@ Mettre à jour le Solde apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4002,7 +4030,7 @@ Série en cours apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4010,7 +4038,7 @@ Série la plus longue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4054,7 +4082,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -4062,7 +4090,7 @@ Dettes apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4194,7 +4222,7 @@ Logiciel Open Source apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -4218,7 +4246,7 @@ Configuration du Scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4457,20 +4485,12 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETF sans Pays apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -4478,7 +4498,7 @@ ETF sans Secteurs apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -4486,7 +4506,7 @@ Actifs apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4614,7 +4634,7 @@ Authentication biométrique apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -4706,7 +4726,7 @@ Exporter les Data apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -4714,11 +4734,11 @@ Devises apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4766,11 +4786,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -5324,7 +5344,7 @@ Suisse apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -5336,7 +5356,7 @@ Mondial apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -5364,7 +5384,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5432,7 +5452,7 @@ Frais apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5464,7 +5484,7 @@ Confirmez la suppression de ce tag ? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -5532,7 +5552,7 @@ Statut apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5548,7 +5568,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5688,7 +5708,7 @@ Oops! Echec du parsing des données historiques. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -5696,7 +5716,7 @@ Confirmer la suppresion de ce message système? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -5720,7 +5740,7 @@ Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5760,7 @@ Voulez-vous vraiment supprimer ce solde de compte ? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5776,7 @@ Le prix actuel du marché est apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5764,7 +5784,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5852,15 +5872,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -5868,7 +5888,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5876,7 +5896,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5884,7 +5904,7 @@ Performance des Actifs en valeur absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5892,7 +5912,7 @@ Performance des Actifs apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5900,7 +5920,7 @@ Performance des devises en valeur absolue apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5908,7 +5928,7 @@ Performance des devises apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5916,7 +5936,7 @@ Week to date libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5924,11 +5944,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5936,7 +5956,7 @@ Month to date libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5944,11 +5964,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5956,7 +5976,7 @@ Year to date libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5992,7 +6012,7 @@ année apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6024,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6012,11 +6032,11 @@ années apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6032,7 +6052,7 @@ Collecter les données apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6064,7 @@ Général apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6072,7 @@ Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6084,7 @@ Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6209,7 +6229,7 @@ Confirmer la suppresion de votre compte Ghostfolio ? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6217,7 +6237,7 @@ Zone de danger apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6225,7 +6245,7 @@ Supprimer le compte apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6257,7 +6277,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6285,7 @@ Oops! Une erreur s’est produite lors de la configuration de l’authentification biométrique. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6281,7 +6301,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6329,7 +6349,7 @@ Souhaitez-vous affiner votre stratégie d’investissement personnelle? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6337,7 +6357,7 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6345,7 +6365,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6353,7 +6373,7 @@ Budget apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6369,47 +6389,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6417,7 +6441,7 @@ Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6425,7 +6449,7 @@ Investisseur apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6437,7 +6461,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6449,7 +6473,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6457,7 +6481,7 @@ Confidentialité apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6465,7 +6489,7 @@ Logiciels apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6473,7 +6497,7 @@ Outils apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6481,7 +6505,7 @@ Expérience Utilisateur apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6489,7 +6513,7 @@ Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6497,7 +6521,7 @@ Gestion de Patrimoine apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6657,7 +6681,7 @@ Erreur apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6709,7 +6733,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6741,7 +6765,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6749,7 +6773,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6761,7 +6785,7 @@ Fermer apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6787,13 +6811,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6805,7 +6833,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6845,7 +6873,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6957,7 +6985,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7061,7 +7089,7 @@ Définir clé API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7097,7 +7125,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7113,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7167,7 +7195,7 @@ sur apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7175,7 +7203,7 @@ requêtes journalières apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7183,7 +7211,7 @@ Retirer la clé API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7191,7 +7219,7 @@ Voulez-vous vraiment supprimer la clé API? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7211,7 +7239,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7283,7 +7311,7 @@ Sauvegarder apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7319,11 +7347,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7359,7 +7387,15 @@ Veuillez saisir votre clé API Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Change with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7367,7 +7403,7 @@ Le prompt IA a été copié dans le presse-papiers apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7383,7 +7419,7 @@ Paresseux apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7391,7 +7427,7 @@ Instantané apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7399,7 +7435,7 @@ Prix du marché par défaut apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7407,7 +7443,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7415,7 +7451,7 @@ Selecteur apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7423,7 +7459,7 @@ En-têtes de requête HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7431,7 +7467,7 @@ fin de journée apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7439,7 +7475,7 @@ temps réel apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7447,7 +7483,7 @@ Ouvrir Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7463,11 +7499,11 @@ Variation libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7483,15 +7519,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -7518,6 +7554,14 @@ 67 + + Total amount + Total amount + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Arménie @@ -7587,7 +7631,7 @@ Jeton de sécurité apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7599,7 +7643,7 @@ Voulez-vous vraiment générer un nouveau jeton de sécurité pour cet utilisateur ? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7607,7 +7651,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7672,7 +7716,7 @@ () est déjà utilisé. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7680,7 +7724,7 @@ Une erreur s’est produite lors de la mise à jour vers (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7696,7 +7740,7 @@ avec accès API pour apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7776,7 +7820,7 @@ Voulez-vous vraiment supprimer cet élément? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7817,7 +7861,7 @@ Le compte utilisateur de démonstration a été synchronisé. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7852,25 +7896,25 @@ 150 - + Fee Ratio - Ratio de frais + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Les frais dépassent ${thresholdMax}% de votre investissement initial (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Les frais ne dépassent pas ${thresholdMax}% de votre investissement initial (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7995,7 +8039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8007,7 +8051,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8031,7 +8075,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8039,11 +8083,11 @@ new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8256,7 +8300,7 @@ Gérer le profil d’actif apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8676,7 +8720,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.it.xlf b/apps/client/src/locales/messages.it.xlf index 2986e8ee4..5f06af0b4 100644 --- a/apps/client/src/locales/messages.it.xlf +++ b/apps/client/src/locales/messages.it.xlf @@ -27,7 +27,7 @@ Il rischio di perdita nel trading può essere notevole. Non è consigliabile investire denaro di cui potresti avere bisogno a breve termine. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -43,7 +43,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -90,14 +90,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Vuoi davvero revocare l’accesso concesso? @@ -115,7 +107,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -127,7 +119,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -143,11 +135,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -159,7 +151,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -175,7 +167,7 @@ Totale libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -187,15 +179,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -203,11 +195,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -219,7 +211,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -243,15 +235,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -275,11 +267,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -287,7 +283,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -303,7 +299,7 @@ Vuoi davvero eliminare questo account? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -331,7 +327,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -371,7 +367,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -387,7 +383,7 @@ Profilo dell’asset apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -403,7 +399,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -443,7 +439,7 @@ Data apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -491,7 +487,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -511,7 +507,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -519,7 +515,7 @@ Vuoi davvero eliminare questo buono? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -527,7 +523,7 @@ Vuoi davvero svuotare la cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -535,7 +531,7 @@ Imposta il messaggio di sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -639,7 +635,7 @@ Vuoi davvero eliminare questo utente? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -675,7 +671,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -715,7 +711,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -727,11 +723,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -775,7 +771,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -783,7 +779,7 @@ Gestione delle attività apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -815,7 +811,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -859,7 +855,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -899,7 +895,7 @@ Prestazioni lorde assolute apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -907,11 +903,11 @@ Prestazioni nette assolute apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -919,11 +915,11 @@ Prestazioni nette apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -931,7 +927,7 @@ Asset totali apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -939,7 +935,7 @@ Potere d’acquisto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -947,7 +943,7 @@ Patrimonio netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -955,7 +951,7 @@ Prestazioni annualizzate apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -975,7 +971,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -983,7 +979,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -995,7 +991,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1007,7 +1003,7 @@ Tag apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1023,7 +1019,7 @@ Segnala un’anomalia dei dati apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1031,11 +1027,11 @@ Allocazione libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -1051,7 +1047,7 @@ Mostra tutti libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -1063,7 +1059,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -1071,11 +1067,11 @@ anno corrente apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -1083,11 +1079,11 @@ 1 anno apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -1095,11 +1091,19 @@ 5 anni apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Performance with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -1107,11 +1111,11 @@ Massimo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -1219,7 +1223,7 @@ Vuoi davvero rimuovere questo metodo di accesso? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -1239,7 +1243,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1263,7 +1267,7 @@ Vista presentatore apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -1279,11 +1283,11 @@ Locale apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -1291,7 +1295,7 @@ Formato data e numero apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -1299,7 +1303,7 @@ Modalità Zen apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -1311,7 +1315,7 @@ Accesso con impronta digitale apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -1323,11 +1327,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1379,7 +1383,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1419,7 +1423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1431,11 +1435,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1455,7 +1459,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -1471,7 +1475,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -1611,7 +1615,7 @@ Poiché hai già effettuato l’accesso, non puoi accedere all’account demo. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1675,11 +1679,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1695,7 +1699,7 @@ Mercati apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1719,7 +1723,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -1819,7 +1823,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -1839,7 +1843,7 @@ Cronologia degli investimenti apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -1847,7 +1851,7 @@ In alto apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -1855,7 +1859,7 @@ In basso apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -1915,7 +1919,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1959,7 +1963,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1971,7 +1975,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1979,7 +1983,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1987,7 +1991,7 @@ Prezzo unitario apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1999,7 +2003,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2007,7 +2011,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2019,7 +2023,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2043,7 +2047,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2055,7 +2059,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -2131,7 +2135,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -2143,7 +2147,7 @@ Continenti apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -2159,7 +2163,7 @@ Ghostfolio ti permette di tenere traccia della tua ricchezza. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2307,7 +2311,7 @@ Vuoi davvero eliminare questa attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2323,7 +2327,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2415,7 +2419,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -2423,7 +2427,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2443,7 +2447,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2455,7 +2459,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2487,7 +2491,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -2511,7 +2515,7 @@ Risparmio libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -2523,11 +2527,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -2547,7 +2551,7 @@ Deposito libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -2555,7 +2559,7 @@ Mensile apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -2611,7 +2615,7 @@ Filtra per... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -2639,7 +2643,7 @@ Funzionalità sperimentali apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -2647,7 +2651,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2659,11 +2663,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -2687,7 +2691,7 @@ Escluso dall’analisi apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2699,7 +2703,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -2707,7 +2711,7 @@ Aspetto apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -2715,7 +2719,7 @@ Chiaro apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -2723,7 +2727,7 @@ Scuro apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -2731,7 +2735,7 @@ Importo totale apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2739,7 +2743,7 @@ Evoluzione del portafoglio apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -2783,7 +2787,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2791,7 +2795,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2847,7 +2851,7 @@ Contanti apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2895,7 +2899,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -2959,7 +2963,7 @@ Fondo di emergenza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2979,7 +2983,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -2991,7 +2995,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -2999,11 +3003,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3107,7 +3111,7 @@ Mappatura dei simboli apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -3115,7 +3119,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3131,7 +3135,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3139,11 +3143,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -3155,7 +3159,7 @@ Cronologia dei dividendi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -3171,7 +3175,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3179,7 +3183,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3215,7 +3219,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3223,7 +3227,7 @@ Dati del mercato apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -3240,7 +3244,7 @@ Summary - Summario + Riepilogo apps/client/src/app/components/home-summary/home-summary.html 2 @@ -3275,7 +3279,7 @@ Annuale apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -3299,7 +3303,7 @@ Valido fino a apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3338,6 +3342,14 @@ 22 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Fondo pensione @@ -3346,6 +3358,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satellite @@ -3359,7 +3379,7 @@ Protezione delle informazioni sensibili come le prestazioni assolute e i valori quantitativi apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -3367,7 +3387,7 @@ Esperienza priva di distrazioni per i periodi più turbolenti apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -3375,7 +3395,7 @@ Un’anteprima delle funzionalità in arrivo apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -3399,7 +3419,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3415,7 +3435,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3431,7 +3451,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3447,7 +3467,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3495,7 +3515,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3579,7 +3599,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3595,7 +3615,7 @@ Pagamento una tantum, senza rinnovo automatico. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3603,11 +3623,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -3615,7 +3635,7 @@ È gratuito. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3627,7 +3647,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3647,7 +3667,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3691,7 +3711,7 @@ Supporto via email e chat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3735,7 +3755,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3759,7 +3779,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3791,7 +3811,7 @@ Vuoi davvero eliminare tutte le tue attività? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3802,6 +3822,14 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By By @@ -3823,7 +3851,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -3839,11 +3867,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3859,7 +3887,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -3867,7 +3895,7 @@ Vuoi davvero eliminare questa piattaforma? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 @@ -3875,7 +3903,7 @@ Piattaforme apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3883,7 +3911,7 @@ Aggiornamento del saldo di cassa apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4003,7 +4031,7 @@ Serie attuale apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4011,7 +4039,7 @@ Serie più lunga apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4055,7 +4083,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -4063,7 +4091,7 @@ Passività apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4195,7 +4223,7 @@ Software open source apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -4219,7 +4247,7 @@ Configurazione dello scraper apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4458,20 +4486,12 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETF senza paesi apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -4479,7 +4499,7 @@ ETF senza settori apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -4487,7 +4507,7 @@ Asset apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4615,7 +4635,7 @@ Autenticazione biometrica apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -4707,7 +4727,7 @@ Esporta dati apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -4715,11 +4735,11 @@ Valute apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4767,11 +4787,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -5325,7 +5345,7 @@ Svizzera apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -5337,7 +5357,7 @@ Globale apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -5365,7 +5385,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5433,7 +5453,7 @@ Commissione apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5465,7 +5485,7 @@ Sei sicuro di voler eliminare questo tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -5533,7 +5553,7 @@ Iscrizione apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5549,7 +5569,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5689,7 +5709,7 @@ Ops! Impossibile elaborare i dati storici. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -5697,7 +5717,7 @@ Confermi di voler cancellare questo messaggio di sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -5721,7 +5741,7 @@ Saldi di cassa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5741,7 +5761,7 @@ Vuoi veramente elimnare il saldo di questo conto? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5757,7 +5777,7 @@ L’attuale prezzo di mercato è apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5765,7 +5785,7 @@ Prova apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5853,15 +5873,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -5869,7 +5889,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5877,7 +5897,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5885,7 +5905,7 @@ Rendimento assoluto dell’Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5893,7 +5913,7 @@ Rendimento dell’Asset apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5901,7 +5921,7 @@ Rendimento assoluto della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5909,7 +5929,7 @@ Rendimento della Valuta apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5917,7 +5937,7 @@ Da inizio settimana libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5925,11 +5945,11 @@ Settimana corrente apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5937,7 +5957,7 @@ Da inizio mese libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5945,11 +5965,11 @@ Mese corrente apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5957,7 +5977,7 @@ Da inizio anno libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5993,7 +6013,7 @@ anno apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6005,7 +6025,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6013,11 +6033,11 @@ anni apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6033,7 +6053,7 @@ Raccolta Dati apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6045,7 +6065,7 @@ Generale apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6053,7 +6073,7 @@ Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6065,7 +6085,7 @@ Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6210,7 +6230,7 @@ Confermi di voler chiudere il tuo account Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6218,7 +6238,7 @@ Zona di Pericolo apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6226,7 +6246,7 @@ Chiudi l’account apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6258,7 +6278,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6266,7 +6286,7 @@ Ops! C’è stato un errore impostando l’autenticazione biometrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6282,7 +6302,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6330,7 +6350,7 @@ Vorresti perfezionare la tua strategia personale di investimento? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6338,7 +6358,7 @@ Alternativa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6346,7 +6366,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6354,7 +6374,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6370,47 +6390,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6418,7 +6442,7 @@ Ufficio familiare apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6426,7 +6450,7 @@ Investitore apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6438,7 +6462,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6450,7 +6474,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6458,7 +6482,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6466,7 +6490,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6474,7 +6498,7 @@ Strumento apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6482,7 +6506,7 @@ Esperienza Utente apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6490,7 +6514,7 @@ Ricchezza apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6498,7 +6522,7 @@ Gestione Patrimoniale apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6658,7 +6682,7 @@ Errore apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6710,7 +6734,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6742,7 +6766,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6750,7 +6774,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6762,7 +6786,7 @@ Chiudi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6788,13 +6812,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6806,7 +6834,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6846,7 +6874,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6958,7 +6986,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7062,7 +7090,7 @@ Imposta API Key apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7098,7 +7126,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7114,7 +7142,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7168,7 +7196,7 @@ di apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7176,7 +7204,7 @@ richieste giornaliere apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7184,7 +7212,7 @@ Rimuovi API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7192,7 +7220,7 @@ Vuoi davvero eliminare l’API key? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7212,7 +7240,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7284,7 +7312,7 @@ Salva apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7320,11 +7348,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7360,7 +7388,15 @@ Inserisci la tua API key di Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Change with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7368,7 +7404,7 @@ L’AI prompt è stato copiato negli appunti apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7384,7 +7420,7 @@ Pigro apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7392,7 +7428,7 @@ Istantaneo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7400,7 +7436,7 @@ Prezzo di mercato predefinito apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7408,7 +7444,7 @@ Modalità apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7416,7 +7452,7 @@ Selettore apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7424,7 +7460,7 @@ Intestazioni della richiesta HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7432,7 +7468,7 @@ fine giornata apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7440,7 +7476,7 @@ in tempo reale apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7448,7 +7484,7 @@ Apri Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7464,11 +7500,11 @@ Cambia libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7484,15 +7520,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -7519,6 +7555,14 @@ 67 + + Total amount + Total amount + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Armenia @@ -7588,7 +7632,7 @@ Token di sicurezza apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7600,7 +7644,7 @@ Vuoi davvero generare un nuovo token di sicurezza per questo utente? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7608,7 +7652,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7673,7 +7717,7 @@ () e gia in uso. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7681,7 +7725,7 @@ Si è verificato un errore durante l’aggiornamento di (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7697,7 +7741,7 @@ con accesso API per apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7777,7 +7821,7 @@ Vuoi davvero eliminare questo elemento? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7818,7 +7862,7 @@ L’account utente demo è stato sincronizzato. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7853,25 +7897,25 @@ 150 - + Fee Ratio - Rapporto tariffario + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Le commissioni superano il ${thresholdMax}% del tuo investimento iniziale (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Le commissioni non superano il ${thresholdMax}% del tuo investimento iniziale (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7996,7 +8040,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8008,7 +8052,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8032,7 +8076,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8040,11 +8084,11 @@ nuovo apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8257,7 +8301,7 @@ Gestisci profilo risorsa apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8677,7 +8721,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.ko.xlf b/apps/client/src/locales/messages.ko.xlf new file mode 100644 index 000000000..bb361b515 --- /dev/null +++ b/apps/client/src/locales/messages.ko.xlf @@ -0,0 +1,8753 @@ + + + + + + about + about + kebab-case + + libs/common/src/lib/routes/routes.ts + 176 + + + libs/common/src/lib/routes/routes.ts + 177 + + + libs/common/src/lib/routes/routes.ts + 182 + + + libs/common/src/lib/routes/routes.ts + 190 + + + libs/common/src/lib/routes/routes.ts + 198 + + + libs/common/src/lib/routes/routes.ts + 206 + + + libs/common/src/lib/routes/routes.ts + 214 + + + + faq + faq + kebab-case + + libs/common/src/lib/routes/routes.ts + 234 + + + libs/common/src/lib/routes/routes.ts + 235 + + + libs/common/src/lib/routes/routes.ts + 239 + + + libs/common/src/lib/routes/routes.ts + 245 + + + + features + features + kebab-case + + libs/common/src/lib/routes/routes.ts + 254 + + + libs/common/src/lib/routes/routes.ts + 255 + + + + license + license + kebab-case + + libs/common/src/lib/routes/routes.ts + 188 + + + libs/common/src/lib/routes/routes.ts + 191 + + + + markets + markets + kebab-case + + libs/common/src/lib/routes/routes.ts + 259 + + + libs/common/src/lib/routes/routes.ts + 260 + + + + pricing + pricing + kebab-case + + libs/common/src/lib/routes/routes.ts + 269 + + + libs/common/src/lib/routes/routes.ts + 270 + + + + privacy-policy + privacy-policy + kebab-case + + libs/common/src/lib/routes/routes.ts + 204 + + + libs/common/src/lib/routes/routes.ts + 207 + + + + register + register + kebab-case + + libs/common/src/lib/routes/routes.ts + 279 + + + libs/common/src/lib/routes/routes.ts + 280 + + + + resources + resources + kebab-case + + libs/common/src/lib/routes/routes.ts + 284 + + + libs/common/src/lib/routes/routes.ts + 285 + + + libs/common/src/lib/routes/routes.ts + 290 + + + libs/common/src/lib/routes/routes.ts + 298 + + + libs/common/src/lib/routes/routes.ts + 306 + + + libs/common/src/lib/routes/routes.ts + 314 + + + libs/common/src/lib/routes/routes.ts + 322 + + + + You are using the Live Demo. + 현재 라이브 데모를 사용 중입니다. + + apps/client/src/app/app.component.html + 12 + + + + Create Account + 계정 생성 + + apps/client/src/app/app.component.html + 13 + + + apps/client/src/app/pages/register/register-page.html + 28 + + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 2 + + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 101 + + + + Frequently Asked Questions (FAQ) + 자주 묻는 질문 + + apps/client/src/app/pages/faq/overview/faq-overview-page.html + 5 + + + apps/client/src/app/pages/faq/saas/saas-page.html + 5 + + + apps/client/src/app/pages/faq/self-hosting/self-hosting-page.html + 5 + + + + The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term. + 거래에는 상당한 손실 위험이 따를 수 있습니다. 단기적으로 필요할 수 있는 자금의 투자는 권장되지 않습니다. + + apps/client/src/app/components/footer/footer.component.html + 182 + + + + Alias + 별칭 + + apps/client/src/app/components/access-table/access-table.component.html + 4 + + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 17 + + + + Grantee + 권한 수신자 + + apps/client/src/app/components/access-table/access-table.component.html + 11 + + + + please + 부탁드립니다 + + apps/client/src/app/pages/pricing/pricing-page.html + 333 + + + + Type + 유형 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 48 + + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 28 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 15 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 163 + + + + Details + 상세 + + apps/client/src/app/components/access-table/access-table.component.html + 33 + + + + Revoke + 회수 + + apps/client/src/app/components/access-table/access-table.component.html + 96 + + + + with + 와(과) + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 87 + + + + Do you really want to revoke this granted access? + 이 부여된 접근 권한을 정말로 회수하시겠습니까? + + apps/client/src/app/components/access-table/access-table.component.ts + 113 + + + + Cash Balance + 현금 잔액 + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 45 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 34 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 143 + + + + Platform + 플랫폼 + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 90 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 48 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 93 + + + + Cash Balances + 현금 잔액 + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 146 + + + + Transfer Cash Balance + 현금 잔액 이체 + + apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html + 7 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 10 + + + + Name + 이름 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 88 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 310 + + + apps/client/src/app/components/admin-platform/admin-platform.component.html + 22 + + + apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html + 15 + + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 58 + + + apps/client/src/app/components/admin-tag/admin-tag.component.html + 22 + + + apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html + 15 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 15 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 135 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 50 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 137 + + + libs/ui/src/lib/benchmark/benchmark.component.html + 12 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 23 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 16 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 88 + + + + Total + 합계 + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 62 + + + + Currency + 통화 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 199 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 317 + + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 45 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 25 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 141 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 72 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 283 + + + + Value + 평가액 + + apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html + 53 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 201 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 204 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 207 + + + libs/ui/src/lib/account-balances/account-balances.component.html + 34 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 178 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 213 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 264 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 300 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 93 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 25 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 102 + + + + Edit + 편집 + + apps/client/src/app/components/access-table/access-table.component.html + 76 + + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 267 + + + apps/client/src/app/components/admin-platform/admin-platform.component.html + 78 + + + apps/client/src/app/components/admin-tag/admin-tag.component.html + 71 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 320 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 457 + + + + Delete + 삭제 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 289 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 87 + + + apps/client/src/app/components/admin-overview/admin-overview.html + 131 + + + apps/client/src/app/components/admin-platform/admin-platform.component.html + 89 + + + apps/client/src/app/components/admin-tag/admin-tag.component.html + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 + + + libs/ui/src/lib/account-balances/account-balances.component.html + 80 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 331 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 484 + + + libs/ui/src/lib/benchmark/benchmark.component.html + 176 + + + + Do you really want to delete this account? + 이 계정을 정말 삭제하시겠습니까? + + libs/ui/src/lib/accounts-table/accounts-table.component.ts + 148 + + + + Asset Profile + 자산 프로필 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 52 + + + + Historical Market Data + 과거 시장 데이터 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 54 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 451 + + + + Data Source + 데이터 소스 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 82 + + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 105 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 180 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 151 + + + libs/ui/src/lib/i18n.ts + 15 + + + + Attempts + 시도 횟수 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 120 + + + + Created + 생성됨 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 134 + + + + Finished + 완료됨 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 143 + + + + Status + 상태 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 152 + + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 104 + + + + and is driven by the efforts of its contributors + 기여자들의 노력으로 발전하고 있습니다 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 49 + + + + Delete Jobs + 작업 삭제 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 193 + + + + View Data + 데이터 보기 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 208 + + + + View Stacktrace + 스택트레이스 보기 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 216 + + + + Delete Job + 작업 삭제 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 224 + + + + Details for + 에 대한 세부정보 + + libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html + 2 + + + + Date + 날짜 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 157 + + + libs/ui/src/lib/account-balances/account-balances.component.html + 12 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 172 + + + libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html + 6 + + + + Market Price + 시장 가격 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 132 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 113 + + + libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html + 26 + + + + Currencies + 통화 + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 131 + + + apps/client/src/app/pages/public/public-page.html + 95 + + + + ETFs without Countries + 국가 정보 없는 ETF + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 136 + + + + ETFs without Sectors + 섹터 정보 없는 ETF + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 141 + + + + Do you really want to delete this asset profile? + 이 자산 프로필을 정말 삭제하시겠습니까? + + apps/client/src/app/components/admin-market-data/admin-market-data.service.ts + 37 + + + + Filter by... + 다음 기준으로 필터... + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 390 + + + + First Activity + 첫 활동 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 147 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 217 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 219 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 45 + + + + Activities Count + 활동 수 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 156 + + + + Historical Data + 과거 데이터 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 165 + + + libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html + 40 + + + + Sectors Count + 섹터 수 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 174 + + + + Countries Count + 국가 수 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 183 + + + + Gather Recent Historical Market Data + 최근 과거 시장 데이터 수집 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 225 + + + + Gather All Historical Market Data + 전체 과거 시장 데이터 수집 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 230 + + + + Gather Profile Data + 프로필 데이터 수집 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 234 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 66 + + + + Oops! Could not parse historical data. + 이런! 과거 데이터를 파싱할 수 없습니다. + + libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts + 284 + + + + Refresh + 새로고침 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 21 + + + + Gather Historical Market Data + 과거 시장 데이터 수집 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 34 + + + + Import + 가져오기 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 155 + + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 190 + + + libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html + 67 + + + + Sector + 섹터 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 262 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 268 + + + + Country + 국가 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 273 + + + apps/client/src/app/components/admin-users/admin-users.html + 60 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 278 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 72 + + + + Sectors + 섹터 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 279 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 399 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 284 + + + apps/client/src/app/pages/public/public-page.html + 113 + + + + Countries + 국가 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 289 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 410 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 296 + + + + Symbol Mapping + 심볼 매핑 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 387 + + + + and we share aggregated key metrics of the platform’s performance + 또한 플랫폼 성과에 대한 집계된 핵심 지표를 공유합니다 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 32 + + + + Scraper Configuration + 스크래퍼 설정 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 474 + + + + Note + 메모 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 435 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 78 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 271 + + + + Add Asset Profile + 자산 프로필 추가 + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 7 + + + + Search + 검색 + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 16 + + + + Add Manually + 수동 추가 + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 18 + + + + Name, symbol or ISIN + 이름, 심볼 또는 ISIN + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 133 + + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 27 + + + apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.html + 10 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 120 + + + + Do you really want to delete this coupon? + 이 쿠폰을 정말 삭제하시겠습니까? + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 193 + + + + Do you really want to delete this system message? + 이 시스템 메시지를 정말 삭제하시겠습니까? + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 206 + + + + Do you really want to flush the cache? + 정말로 캐시를 플러시하시겠습니까? + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 230 + + + + Please set your system message: + 시스템 메시지를 설정하십시오: + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 250 + + + + Version + 버전 + + apps/client/src/app/components/admin-overview/admin-overview.html + 7 + + + + User Count + 사용자 수 + + apps/client/src/app/components/admin-overview/admin-overview.html + 13 + + + + Activity Count + 활동 수 + + apps/client/src/app/components/admin-overview/admin-overview.html + 19 + + + + per User + 사용자당 + + apps/client/src/app/components/admin-overview/admin-overview.html + 28 + + + + Add Currency + 통화 추가 + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 20 + + + + User Signup + 사용자 가입 + + apps/client/src/app/components/admin-overview/admin-overview.html + 34 + + + + Read-only Mode + 읽기 전용 모드 + + apps/client/src/app/components/admin-overview/admin-overview.html + 48 + + + + System Message + 시스템 메시지 + + apps/client/src/app/components/admin-overview/admin-overview.html + 72 + + + + Set Message + 메시지 설정 + + apps/client/src/app/components/admin-overview/admin-overview.html + 94 + + + + Coupons + 쿠폰 + + apps/client/src/app/components/admin-overview/admin-overview.html + 102 + + + + Add + 추가 + + apps/client/src/app/components/admin-overview/admin-overview.html + 176 + + + libs/ui/src/lib/account-balances/account-balances.component.html + 93 + + + + Housekeeping + 유지 관리 + + apps/client/src/app/components/admin-overview/admin-overview.html + 184 + + + + Flush Cache + 캐시 플러시 + + apps/client/src/app/components/admin-overview/admin-overview.html + 200 + + + + Add Platform + 플랫폼 추가 + + apps/client/src/app/components/admin-platform/admin-platform.component.html + 9 + + + + Url + 링크 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 422 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 553 + + + apps/client/src/app/components/admin-platform/admin-platform.component.html + 38 + + + apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html + 25 + + + + Asset profile has been saved + Asset profile has been saved + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 594 + + + + Do you really want to delete this platform? + 정말로 이 플랫폼을 삭제하시겠습니까? + + apps/client/src/app/components/admin-platform/admin-platform.component.ts + 112 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + + + By + 에 의해 + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 139 + + + + Update platform + 플랫폼 업데이트 + + apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html + 8 + + + + Current year + 올해 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 204 + + + + Add platform + 플랫폼 추가 + + apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html + 10 + + + + Platforms + 플랫폼 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 212 + + + + Tags + 태그 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 218 + + + libs/ui/src/lib/tags-selector/tags-selector.component.html + 4 + + + libs/ui/src/lib/tags-selector/tags-selector.component.html + 16 + + + + Add Tag + 태그 추가 + + apps/client/src/app/components/admin-tag/admin-tag.component.html + 9 + + + + Do you really want to delete this tag? + 이 태그를 정말로 삭제하시겠습니까? + + apps/client/src/app/components/admin-tag/admin-tag.component.ts + 109 + + + + Update tag + 태그 업데이트 + + apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html + 8 + + + + Add tag + 태그 추가 + + apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html + 10 + + + + Do you really want to delete this user? + 이 사용자를 정말로 삭제하시겠습니까? + + apps/client/src/app/components/admin-users/admin-users.component.ts + 218 + + + + User + 사용자 + + apps/client/src/app/components/admin-tag/admin-tag.component.html + 31 + + + apps/client/src/app/components/admin-users/admin-users.html + 12 + + + apps/client/src/app/components/header/header.component.html + 231 + + + + No auto-renewal on membership. + 멤버십 자동 갱신은 없습니다. + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 74 + + + + Engagement per Day + 일일 참여 + + apps/client/src/app/components/admin-users/admin-users.html + 140 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 108 + + + + Last Request + 마지막 요청 + + apps/client/src/app/components/admin-users/admin-users.html + 186 + + + + Impersonate User + 사용자 대리 접속 + + apps/client/src/app/components/admin-users/admin-users.html + 233 + + + + Delete User + 사용자 삭제 + + apps/client/src/app/components/admin-users/admin-users.html + 254 + + + + Could not validate form + Could not validate form + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 570 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 573 + + + + Compare with... + 비교해보세요... + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 18 + + + + Manage Benchmarks + 벤치마크 관리 + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 35 + + + + Portfolio + 포트폴리오 + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts + 140 + + + apps/client/src/app/components/header/header.component.html + 44 + + + apps/client/src/app/components/header/header.component.html + 258 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 95 + + + libs/common/src/lib/routes/routes.ts + 151 + + + + Benchmark + 기준 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 379 + + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts + 152 + + + + Current Market Mood + 현재 시장 분위기 + + apps/client/src/app/components/fear-and-greed-index/fear-and-greed-index.component.html + 12 + + + + About Ghostfolio + 고스트폴리오 소개 + + apps/client/src/app/components/header/header.component.html + 326 + + + apps/client/src/app/pages/about/overview/about-overview-page.html + 5 + + + + Sign in + 로그인 + + apps/client/src/app/components/header/header.component.html + 422 + + + apps/client/src/app/components/header/header.component.ts + 297 + + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 79 + + + libs/common/src/lib/routes/routes.ts + 81 + + + libs/common/src/lib/routes/routes.ts + 157 + + + + Oops! Incorrect Security Token. + 이런! 잘못된 보안 토큰. + + apps/client/src/app/components/header/header.component.ts + 312 + + + apps/client/src/app/components/user-account-access/user-account-access.component.ts + 154 + + + apps/client/src/app/components/user-account-settings/user-account-settings.component.ts + 193 + + + + Manage Activities + 활동 관리 + + apps/client/src/app/components/home-holdings/home-holdings.html + 65 + + + + Fear + 두려움 + + apps/client/src/app/components/home-market/home-market.component.ts + 42 + + + apps/client/src/app/components/markets/markets.component.ts + 47 + + + libs/ui/src/lib/i18n.ts + 108 + + + + Greed + 탐욕 + + apps/client/src/app/components/home-market/home-market.component.ts + 43 + + + apps/client/src/app/components/markets/markets.component.ts + 48 + + + libs/ui/src/lib/i18n.ts + 109 + + + + Last Days + 지난 + + apps/client/src/app/components/home-market/home-market.html + 7 + + + apps/client/src/app/components/markets/markets.html + 17 + + + + Welcome to Ghostfolio + Ghostfolio에 오신 것을 환영합니다 + + apps/client/src/app/components/home-overview/home-overview.html + 11 + + + + Ready to take control of your personal finances? + 개인 재정을 관리할 준비가 되셨나요? + + apps/client/src/app/components/home-overview/home-overview.html + 12 + + + + The source code is fully available as open source software (OSS) under the AGPL-3.0 license + 소스 코드는 오픈 소스 소프트웨어로 완전히 공개되어 있으며, AGPL-3.0 라이선스 하에 제공됩니다 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 16 + + + + Setup your accounts + 계정 설정 + + apps/client/src/app/components/home-overview/home-overview.html + 19 + + + + Get a comprehensive financial overview by adding your bank and brokerage accounts. + 은행 및 중개 계좌를 추가하여 포괄적인 재무 개요를 확인하세요. + + apps/client/src/app/components/home-overview/home-overview.html + 21 + + + + Capture your activities + 활동을 캡처하세요 + + apps/client/src/app/components/home-overview/home-overview.html + 28 + + + + Record your investment activities to keep your portfolio up to date. + 투자 활동을 기록하여 포트폴리오를 최신 상태로 유지하세요. + + apps/client/src/app/components/home-overview/home-overview.html + 30 + + + + Monitor and analyze your portfolio + 포트폴리오를 모니터링하고 분석하세요. + + apps/client/src/app/components/home-overview/home-overview.html + 37 + + + + Track your progress in real-time with comprehensive analysis and insights. + 포괄적인 분석과 통찰력을 통해 진행 상황을 실시간으로 추적하세요. + + apps/client/src/app/components/home-overview/home-overview.html + 39 + + + + Setup accounts + 계정 설정 + + apps/client/src/app/components/home-overview/home-overview.html + 52 + + + + Current week + 이번주 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 196 + + + + Add activity + 활동 추가 + + apps/client/src/app/components/home-overview/home-overview.html + 60 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 8 + + + + Total Amount + 총액 + + apps/client/src/app/components/investment-chart/investment-chart.component.ts + 146 + + + + Savings Rate + 저축률 + + apps/client/src/app/components/investment-chart/investment-chart.component.ts + 202 + + + + Security Token + 보안 토큰 + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 8 + + + apps/client/src/app/components/user-account-access/user-account-access.html + 3 + + + apps/client/src/app/components/user-account-access/user-account-access.html + 15 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 288 + + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 64 + + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 72 + + + + or + 또는 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 30 + + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 32 + + + apps/client/src/app/pages/landing/landing-page.html + 47 + + + apps/client/src/app/pages/landing/landing-page.html + 348 + + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 97 + + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 83 + + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 161 + + + apps/client/src/app/pages/pricing/pricing-page.html + 326 + + + apps/client/src/app/pages/register/register-page.html + 33 + + + apps/client/src/app/pages/webauthn/webauthn-page.html + 30 + + + + Sign in with Google + 구글로 로그인 + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 44 + + + + Stay signed in + 로그인 상태 유지 + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 66 + + + + Time in Market + 시장 참여 기간 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 3 + + + + Absolute Gross Performance + 절대 총 성과 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 77 + + + + Fees + 수수료 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 208 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 92 + + + + Absolute Net Performance + 절대 순 성과 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 111 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 259 + + + + Net Performance + 순 성과 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 127 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 278 + + + + Total Assets + 총자산 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 153 + + + + Assets + 자산 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 233 + + + + Buying Power + 매수 가능 금액 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 248 + + + + Excluded from Analysis + 분석에서 제외됨 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 274 + + + + Liabilities + 부채 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 302 + + + apps/client/src/app/pages/features/features-page.html + 102 + + + + Net Worth + 순자산 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 324 + + + + Annualized Performance + 연환산 성과 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 338 + + + + Please set the amount of your emergency fund. + 비상금 금액을 설정해 주세요. + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts + 111 + + + + Minimum Price + 최저가 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 130 + + + + Maximum Price + 최고가 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 147 + + + + Quantity + 수량 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 157 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 185 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 193 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 69 + + + + Report Data Glitch + 데이터 결함 보고 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 450 + + + + Are you an ambitious investor who needs the full picture? + 당신은 전체 그림이 필요한 야심찬 투자자이신가요? + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 15 + + + + Upgrade to Ghostfolio Premium today and gain access to exclusive features to enhance your investment experience: + 지금 Ghostfolio 프리미엄으로 업그레이드하고, 투자 경험을 향상시키는 독점 기능을 이용하세요: + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 18 + + + + Portfolio Summary + 포트폴리오 요약 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 24 + + + apps/client/src/app/pages/pricing/pricing-page.html + 47 + + + apps/client/src/app/pages/pricing/pricing-page.html + 204 + + + + Portfolio Allocations + 포트폴리오 자산배분 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 28 + + + apps/client/src/app/pages/features/features-page.html + 161 + + + apps/client/src/app/pages/pricing/pricing-page.html + 51 + + + apps/client/src/app/pages/pricing/pricing-page.html + 208 + + + + Performance Benchmarks + 성과 벤치마크 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 32 + + + apps/client/src/app/pages/pricing/pricing-page.html + 55 + + + apps/client/src/app/pages/pricing/pricing-page.html + 212 + + + + FIRE Calculator + 파이어(FIRE) 계산기 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 36 + + + apps/client/src/app/pages/pricing/pricing-page.html + 59 + + + apps/client/src/app/pages/pricing/pricing-page.html + 216 + + + + Professional Data Provider + 전문 데이터 제공자 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 40 + + + apps/client/src/app/pages/pricing/pricing-page.html + 220 + + + + and more Features... + 그리고 더 많은 기능... + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 44 + + + apps/client/src/app/pages/pricing/pricing-page.html + 75 + + + apps/client/src/app/pages/pricing/pricing-page.html + 243 + + + + Get the tools to effectively manage your finances and refine your personal investment strategy. + 재무를 효율적으로 관리하고 개인 투자 전략을 고도화할 수 있는 도구를 제공합니다. + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 48 + + + + Skip + 건너뛰다 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 59 + + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 99 + + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 141 + + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 181 + + + + Upgrade Plan + 업그레이드 계획 + + apps/client/src/app/components/header/header.component.html + 193 + + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 70 + + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 110 + + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 153 + + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 21 + + + apps/client/src/app/pages/pricing/pricing-page.html + 281 + + + + Today + 오늘 + + apps/client/src/app/pages/public/public-page.html + 24 + + + libs/ui/src/lib/assistant/assistant.component.ts + 362 + + + + YTD + 연초 대비 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 204 + + + libs/ui/src/lib/assistant/assistant.component.ts + 374 + + + + 1Y + 1년 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 208 + + + libs/ui/src/lib/assistant/assistant.component.ts + 384 + + + + 5Y + 5년 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 212 + + + libs/ui/src/lib/assistant/assistant.component.ts + 408 + + + + Performance with currency effect + Performance with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 + + + + Max + 맥스 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 216 + + + libs/ui/src/lib/assistant/assistant.component.ts + 414 + + + + Grant access + 액세스 권한 부여 + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 9 + + + + Public + 공공의 + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 31 + + + + Granted Access + 액세스 권한 부여 + + apps/client/src/app/components/user-account-access/user-account-access.html + 57 + + + + Please enter your coupon code. + 쿠폰 코드를 입력해주세요. + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 210 + + + + Could not redeem coupon code + 쿠폰 코드를 사용할 수 없습니다. + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 174 + + + + Coupon code has been redeemed + 쿠폰 코드가 사용되었습니다. + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 187 + + + + Reload + 새로고침 + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 188 + + + + per year + 연간 + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 33 + + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 80 + + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 158 + + + apps/client/src/app/pages/pricing/pricing-page.html + 265 + + + + Try Premium + 프리미엄을 사용해 보세요 + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 53 + + + + Redeem Coupon + 쿠폰 사용 + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 67 + + + + Auto + 자동 + + apps/client/src/app/components/user-account-settings/user-account-settings.component.ts + 70 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 181 + + + + Do you really want to remove this sign in method? + 이 로그인 방법을 정말로 제거하시겠습니까? + + apps/client/src/app/components/user-account-settings/user-account-settings.component.ts + 282 + + + + Presenter View + 발표자 보기 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 192 + + + + Protection for sensitive information like absolute performances and quantity values + 절대 성과 및 수량 값과 같은 민감한 정보를 보호합니다. + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 194 + + + + Base Currency + 기본 통화 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 9 + + + + Language + 언어 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 56 + + + + Locale + 장소 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 512 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 142 + + + + Date and number format + 날짜 및 숫자 형식 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 144 + + + + Appearance + 테마 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 167 + + + + Light + 라이트 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 182 + + + + Dark + 다크 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 183 + + + + Zen Mode + 프라이버시 모드 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 210 + + + apps/client/src/app/pages/features/features-page.html + 246 + + + + Distraction-free experience for turbulent times + 격동의 시대에 방해받지 않는 경험 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 212 + + + + this is projected to increase to + 이는 다음과 같이 증가할 것으로 예상된다. + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 147 + + + + Biometric Authentication + 생체인증 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 227 + + + + Sign in with fingerprint + 지문으로 로그인 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 228 + + + + Experimental Features + 실험적 기능 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 244 + + + + Sneak peek at upcoming functionality + 곧 출시될 기능 미리보기 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 246 + + + + User ID + 사용자 ID + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 51 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 261 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 30 + + + + Export Data + 데이터 내보내기 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 269 + + + + This feature is currently unavailable. + 이 기능은 현재 사용할 수 없습니다. + + apps/client/src/app/core/http-response.interceptor.ts + 55 + + + + Please try again later. + 나중에 다시 시도해 주세요. + + apps/client/src/app/core/http-response.interceptor.ts + 57 + + + apps/client/src/app/core/http-response.interceptor.ts + 88 + + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts + 195 + + + + Oops! Something went wrong. + 이런! 문제가 발생했습니다. + + apps/client/src/app/core/http-response.interceptor.ts + 86 + + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts + 193 + + + + Okay + 좋아요 + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 149 + + + apps/client/src/app/core/http-response.interceptor.ts + 89 + + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts + 196 + + + + About + 소개 + + apps/client/src/app/components/footer/footer.component.html + 20 + + + apps/client/src/app/components/header/header.component.html + 124 + + + apps/client/src/app/components/header/header.component.html + 375 + + + apps/client/src/app/pages/about/overview/about-overview-page.routes.ts + 12 + + + libs/common/src/lib/routes/routes.ts + 220 + + + + Changelog + 변경 내역 + + apps/client/src/app/components/footer/footer.component.html + 27 + + + apps/client/src/app/pages/about/changelog/changelog-page.html + 4 + + + libs/common/src/lib/routes/routes.ts + 185 + + + + License + 특허 + + apps/client/src/app/components/footer/footer.component.html + 39 + + + apps/client/src/app/pages/about/license/license-page.html + 4 + + + libs/common/src/lib/routes/routes.ts + 193 + + + + Privacy Policy + 개인 정보 보호 정책 + + apps/client/src/app/components/footer/footer.component.html + 55 + + + apps/client/src/app/pages/about/privacy-policy/privacy-policy-page.html + 4 + + + libs/common/src/lib/routes/routes.ts + 209 + + + + Our + 우리의 + + apps/client/src/app/pages/about/oss-friends/oss-friends-page.html + 6 + + + + Discover other exciting Open Source Software projects + 다른 흥미로운 오픈 소스 소프트웨어 프로젝트를 찾아보세요 + + apps/client/src/app/pages/about/oss-friends/oss-friends-page.html + 9 + + + + Visit + 방문하다 + + apps/client/src/app/pages/about/oss-friends/oss-friends-page.html + 28 + + + + for + ~을 위한 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 128 + + + + Accounts + 계정 + + apps/client/src/app/components/admin-platform/admin-platform.component.html + 52 + + + apps/client/src/app/components/admin-users/admin-users.html + 97 + + + apps/client/src/app/components/header/header.component.html + 58 + + + apps/client/src/app/components/header/header.component.html + 268 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 375 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 85 + + + apps/client/src/app/pages/accounts/accounts-page.html + 4 + + + libs/common/src/lib/routes/routes.ts + 69 + + + libs/ui/src/lib/assistant/assistant.html + 84 + + + + Oops, cash balance transfer has failed. + 죄송합니다. 현금 잔액 이체가 실패했습니다. + + apps/client/src/app/pages/accounts/accounts-page.component.ts + 341 + + + + Update account + 계정 업데이트 + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 8 + + + + Add account + 계정 추가 + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 10 + + + + Account ID + 계정 ID + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 96 + + + + From + 에서 + + apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html + 11 + + + + To + 에게 + + apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html + 32 + + + + Transfer + 옮기다 + + apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html + 72 + + + + Admin Control + 관리자 제어 + + apps/client/src/app/components/header/header.component.html + 74 + + + apps/client/src/app/components/header/header.component.html + 289 + + + libs/common/src/lib/routes/routes.ts + 64 + + + + Market Data + 시장 데이터 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 397 + + + libs/common/src/lib/routes/routes.ts + 51 + + + + Settings + 설정 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 2 + + + libs/common/src/lib/routes/routes.ts + 34 + + + libs/common/src/lib/routes/routes.ts + 56 + + + + Users + 사용자 + + libs/common/src/lib/routes/routes.ts + 61 + + + + Overview + 개요 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 114 + + + apps/client/src/app/components/header/header.component.html + 30 + + + apps/client/src/app/components/header/header.component.html + 248 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 47 + + + apps/client/src/app/pages/admin/admin-page.component.ts + 45 + + + apps/client/src/app/pages/resources/resources-page.component.ts + 29 + + + libs/common/src/lib/routes/routes.ts + 113 + + + libs/common/src/lib/routes/routes.ts + 170 + + + + Blog + 블로그 + + apps/client/src/app/components/footer/footer.component.html + 24 + + + apps/client/src/app/pages/blog/2021/07/hallo-ghostfolio/hallo-ghostfolio-page.html + 205 + + + apps/client/src/app/pages/blog/2021/07/hello-ghostfolio/hello-ghostfolio-page.html + 185 + + + apps/client/src/app/pages/blog/2022/01/first-months-in-open-source/first-months-in-open-source-page.html + 185 + + + apps/client/src/app/pages/blog/2022/07/ghostfolio-meets-internet-identity/ghostfolio-meets-internet-identity-page.html + 185 + + + apps/client/src/app/pages/blog/2022/07/how-do-i-get-my-finances-in-order/how-do-i-get-my-finances-in-order-page.html + 210 + + + apps/client/src/app/pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.html + 197 + + + apps/client/src/app/pages/blog/2022/10/hacktoberfest-2022/hacktoberfest-2022-page.html + 182 + + + apps/client/src/app/pages/blog/2022/11/black-friday-2022/black-friday-2022-page.html + 142 + + + apps/client/src/app/pages/blog/2022/12/the-importance-of-tracking-your-personal-finances/the-importance-of-tracking-your-personal-finances-page.html + 169 + + + apps/client/src/app/pages/blog/2023/01/ghostfolio-auf-sackgeld-vorgestellt/ghostfolio-auf-sackgeld-vorgestellt-page.html + 179 + + + apps/client/src/app/pages/blog/2023/02/ghostfolio-meets-umbrel/ghostfolio-meets-umbrel-page.html + 203 + + + apps/client/src/app/pages/blog/2023/03/1000-stars-on-github/1000-stars-on-github-page.html + 254 + + + apps/client/src/app/pages/blog/2023/05/unlock-your-financial-potential-with-ghostfolio/unlock-your-financial-potential-with-ghostfolio-page.html + 234 + + + apps/client/src/app/pages/blog/2023/07/exploring-the-path-to-fire/exploring-the-path-to-fire-page.html + 244 + + + apps/client/src/app/pages/blog/2023/08/ghostfolio-joins-oss-friends/ghostfolio-joins-oss-friends-page.html + 155 + + + apps/client/src/app/pages/blog/2023/09/ghostfolio-2/ghostfolio-2-page.html + 274 + + + apps/client/src/app/pages/blog/2023/09/hacktoberfest-2023/hacktoberfest-2023-page.html + 184 + + + apps/client/src/app/pages/blog/2023/11/black-week-2023/black-week-2023-page.html + 149 + + + apps/client/src/app/pages/blog/2023/11/hacktoberfest-2023-debriefing/hacktoberfest-2023-debriefing-page.html + 271 + + + apps/client/src/app/pages/blog/2024/09/hacktoberfest-2024/hacktoberfest-2024-page.html + 190 + + + apps/client/src/app/pages/blog/2024/11/black-weeks-2024/black-weeks-2024-page.html + 168 + + + apps/client/src/app/pages/blog/2025/09/hacktoberfest-2025/hacktoberfest-2025-page.html + 189 + + + apps/client/src/app/pages/blog/2025/11/black-weeks-2025/black-weeks-2025-page.html + 147 + + + apps/client/src/app/pages/blog/blog-page.html + 5 + + + libs/common/src/lib/routes/routes.ts + 225 + + + + Could not parse scraper configuration + Could not parse scraper configuration + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 525 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 528 + + + + Discover the latest Ghostfolio updates and insights on personal finance + 개인 금융에 대한 최신 Ghostfolio 업데이트와 통찰력을 알아보세요 + + apps/client/src/app/pages/blog/blog-page.html + 7 + + + + As you are already logged in, you cannot access the demo account. + 이미 로그인되어 있으므로 데모 계정에 접근할 수 없습니다. + + apps/client/src/app/pages/demo/demo-page.component.ts + 32 + + + + Frequently Asked Questions (FAQ) + 자주 묻는 질문 + + apps/client/src/app/components/footer/footer.component.html + 33 + + + apps/client/src/app/pages/about/overview/about-overview-page.html + 189 + + + apps/client/src/app/pages/faq/overview/faq-overview-page.routes.ts + 12 + + + libs/common/src/lib/routes/routes.ts + 251 + + + + Features + 특징 + + apps/client/src/app/components/footer/footer.component.html + 29 + + + apps/client/src/app/components/header/header.component.html + 361 + + + apps/client/src/app/pages/features/features-page.html + 5 + + + libs/common/src/lib/routes/routes.ts + 256 + + + + Check out the numerous features of Ghostfolio to manage your wealth + 자산 관리를 위한 Ghostfolio의 다양한 기능을 확인해보세요 + + apps/client/src/app/pages/features/features-page.html + 7 + + + + ETFs + ETF + + apps/client/src/app/pages/features/features-page.html + 25 + + + + Bonds + 채권 + + apps/client/src/app/pages/features/features-page.html + 38 + + + + Wealth Items + 자산 항목 + + apps/client/src/app/pages/features/features-page.html + 76 + + + + Import and Export + 가져오기 및 내보내기 + + apps/client/src/app/pages/features/features-page.html + 116 + + + + Multi-Accounts + 다중 계정 + + apps/client/src/app/pages/features/features-page.html + 127 + + + + Portfolio Calculations + 포트폴리오 계산 + + apps/client/src/app/pages/features/features-page.html + 141 + + + + Dark Mode + 다크 모드 + + apps/client/src/app/pages/features/features-page.html + 233 + + + + Market Mood + 시장 분위기 + + apps/client/src/app/pages/features/features-page.html + 215 + + + + Static Analysis + 정적 분석 + + apps/client/src/app/pages/features/features-page.html + 179 + + + + Multi-Language + 다국어 + + apps/client/src/app/pages/features/features-page.html + 259 + + + + per week + 주당 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 130 + + + + Open Source Software + 오픈 소스 소프트웨어 + + apps/client/src/app/pages/features/features-page.html + 296 + + + + Get Started + 시작하기 + + apps/client/src/app/components/header/header.component.html + 433 + + + apps/client/src/app/pages/features/features-page.html + 321 + + + apps/client/src/app/pages/landing/landing-page.html + 41 + + + apps/client/src/app/pages/landing/landing-page.html + 344 + + + apps/client/src/app/pages/pricing/pricing-page.html + 360 + + + apps/client/src/app/pages/public/public-page.html + 241 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 334 + + + + Holdings + 보유 종목 + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 102 + + + apps/client/src/app/components/home-holdings/home-holdings.html + 4 + + + apps/client/src/app/pages/public/public-page.html + 70 + + + libs/common/src/lib/routes/routes.ts + 90 + + + libs/common/src/lib/routes/routes.ts + 167 + + + libs/ui/src/lib/assistant/assistant.html + 110 + + + + Summary + 요약 + + apps/client/src/app/components/home-summary/home-summary.html + 2 + + + libs/common/src/lib/routes/routes.ts + 105 + + + + Markets + 시장 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 381 + + + apps/client/src/app/components/footer/footer.component.html + 11 + + + apps/client/src/app/components/header/header.component.html + 408 + + + apps/client/src/app/components/home-market/home-market.html + 2 + + + apps/client/src/app/components/markets/markets.html + 2 + + + apps/client/src/app/pages/resources/markets/resources-markets.component.html + 2 + + + apps/client/src/app/pages/resources/resources-page.component.ts + 39 + + + libs/common/src/lib/routes/routes.ts + 95 + + + libs/common/src/lib/routes/routes.ts + 100 + + + libs/common/src/lib/routes/routes.ts + 261 + + + libs/common/src/lib/routes/routes.ts + 309 + + + + Ghostfolio is a personal finance dashboard to keep track of your net worth including cash, stocks, ETFs and cryptocurrencies across multiple platforms. + Ghostfolio는 여러 플랫폼에 분산된 현금, 주식, ETF, 암호화폐를 포함한 순자산을 추적할 수 있는 개인 재무 대시보드입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 5 + + + + app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3 + 앱, 자산, 암호화폐, 대시보드, ETF, 금융, 관리, 성과, 포트폴리오, 소프트웨어, 주식, 트레이딩, 자산관리, 웹3 + + apps/client/src/app/pages/i18n/i18n-page.html + 10 + + + + Open Source Wealth Management Software + 오픈 소스 자산관리 소프트웨어 + + apps/client/src/app/pages/i18n/i18n-page.html + 237 + + + + Manage your wealth like a boss + 전문가처럼 자산을 관리하세요 + + apps/client/src/app/pages/landing/landing-page.html + 6 + + + + Ghostfolio is a privacy-first, open source dashboard for your personal finances. Break down your asset allocation, know your net worth and make solid, data-driven investment decisions. + Ghostfolio는 프라이버시를 최우선으로 하는 오픈 소스 개인 재무 대시보드입니다. 자산배분을 분석하고 순자산을 파악하여, 데이터 기반의 합리적인 투자 의사결정을 내리세요. + + apps/client/src/app/pages/landing/landing-page.html + 10 + + + + Edit access + 접근 권한 편집 + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 11 + + + + Monthly Active Users + 월간 활성 사용자 + + apps/client/src/app/pages/landing/landing-page.html + 69 + + + + Stars on GitHub + 깃허브 스타 + + apps/client/src/app/pages/landing/landing-page.html + 87 + + + apps/client/src/app/pages/open/open-page.html + 103 + + + + Pulls on Docker Hub + 도커 허브에서 가져오기 + + apps/client/src/app/pages/landing/landing-page.html + 105 + + + apps/client/src/app/pages/open/open-page.html + 117 + + + + As seen in + 에서 볼 수 있듯이 + + apps/client/src/app/pages/landing/landing-page.html + 114 + + + + Protect your assets. Refine your personal investment strategy. + 자산을 보호하세요. 개인 투자 전략을 정교화하세요. + + apps/client/src/app/pages/landing/landing-page.html + 124 + + + + Ghostfolio empowers busy people to keep track of stocks, ETFs or cryptocurrencies without being tracked. + Ghostfolio는 바쁜 사람들이 추적당하지 않으면서도 주식, ETF, 암호화폐를 손쉽게 추적할 수 있도록 돕습니다. + + apps/client/src/app/pages/landing/landing-page.html + 128 + + + + 360° View + 360° 보기 + + apps/client/src/app/pages/landing/landing-page.html + 138 + + + + Get the full picture of your personal finances across multiple platforms. + 여러 플랫폼에 걸쳐 개인 재정에 대한 전체 그림을 얻으세요. + + apps/client/src/app/pages/landing/landing-page.html + 141 + + + + Web3 Ready + 웹3 준비 + + apps/client/src/app/pages/landing/landing-page.html + 149 + + + + Use Ghostfolio anonymously and own your financial data. + 익명으로 Ghostfolio를 사용하고 금융 데이터를 소유하세요. + + apps/client/src/app/pages/landing/landing-page.html + 152 + + + + Benefit from continuous improvements through a strong community. + 강력한 커뮤니티를 통해 지속적인 개선의 혜택을 누리세요. + + apps/client/src/app/pages/landing/landing-page.html + 162 + + + + Get access to 80’000+ tickers from over 50 exchanges + 50개 이상의 거래소에서 80,000개 이상의 티커에 접근하세요 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 84 + + + + Why Ghostfolio? + Ghostfolio인가요? + + apps/client/src/app/pages/landing/landing-page.html + 170 + + + + Ghostfolio is for you if you are... + Ghostfolio는 당신을 위한 것입니다... + + apps/client/src/app/pages/landing/landing-page.html + 172 + + + + trading stocks, ETFs or cryptocurrencies on multiple platforms + 여러 플랫폼에서 주식, ETF 또는 암호화폐 거래 + + apps/client/src/app/pages/landing/landing-page.html + 178 + + + + pursuing a buy & hold strategy + 매수 후 보유 전략을 추구 + + apps/client/src/app/pages/landing/landing-page.html + 184 + + + + interested in getting insights of your portfolio composition + 포트폴리오 구성에 대한 인사이트가 필요하신가요 + + apps/client/src/app/pages/landing/landing-page.html + 189 + + + + valuing privacy and data ownership + 개인 정보 보호 및 데이터 소유권을 소중히 여깁니다. + + apps/client/src/app/pages/landing/landing-page.html + 194 + + + + into minimalism + 미니멀리즘으로 + + apps/client/src/app/pages/landing/landing-page.html + 197 + + + + caring about diversifying your financial resources + 재정 자원을 다양화하는 데 관심을 가짐 + + apps/client/src/app/pages/landing/landing-page.html + 201 + + + + interested in financial independence + 재정적 독립에 관심 + + apps/client/src/app/pages/landing/landing-page.html + 205 + + + + saying no to spreadsheets in + 의 스프레드시트에 거부 의사 표시 + + apps/client/src/app/pages/landing/landing-page.html + 209 + + + + still reading this list + 아직도 이 목록을 읽고 있어요 + + apps/client/src/app/pages/landing/landing-page.html + 212 + + + + Learn more about Ghostfolio + Ghostfolio에 대해 자세히 알아보기 + + apps/client/src/app/pages/landing/landing-page.html + 217 + + + + What our users are saying + 사용자의 이야기 + + apps/client/src/app/pages/landing/landing-page.html + 226 + + + + Members from around the globe are using Ghostfolio Premium + 전 세계의 사용자들이 Ghostfolio 프리미엄을 사용하고 있습니다 + + apps/client/src/app/pages/landing/landing-page.html + 265 + + + + How does Ghostfolio work? + Ghostfolio는 어떻게 동작하나요? + + apps/client/src/app/pages/landing/landing-page.html + 282 + + + + Get started in only 3 steps + 단 3단계만으로 시작하세요 + + apps/client/src/app/pages/landing/landing-page.html + 284 + + + + less than + 미만 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 129 + + + + Sign up anonymously* + 익명으로 가입* + + apps/client/src/app/pages/landing/landing-page.html + 290 + + + + * no e-mail address nor credit card required + * 이메일 주소 및 신용카드 정보가 필요하지 않습니다 + + apps/client/src/app/pages/landing/landing-page.html + 292 + + + + Add any of your historical transactions + 과거 거래를 추가하세요. + + apps/client/src/app/pages/landing/landing-page.html + 304 + + + + Get valuable insights of your portfolio composition + 포트폴리오 구성에 대한 유의미한 인사이트를 확인하세요 + + apps/client/src/app/pages/landing/landing-page.html + 316 + + + + Are you ready? + 준비되셨나요? + + apps/client/src/app/pages/landing/landing-page.html + 330 + + + + At Ghostfolio, transparency is at the core of our values. We publish the source code as open source software (OSS) under the AGPL-3.0 license and we openly share aggregated key metrics of the platform’s operational status. + Ghostfolio는 투명성을 핵심 가치로 삼습니다. 우리는 소스 코드를 오픈 소스 소프트웨어로 공개하며, AGPL-3.0 라이선스 하에 배포합니다. 또한 플랫폼 운영 현황에 대한 집계된 핵심 지표를 공개적으로 공유합니다. + + apps/client/src/app/pages/open/open-page.html + 7 + + + + (Last 24 hours) + (지난 24시간) + + apps/client/src/app/pages/open/open-page.html + 37 + + + + Ghostfolio Status + 고스트폴리오 상태 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 62 + + + + with your university e-mail address + 대학 이메일 주소로 + + apps/client/src/app/pages/pricing/pricing-page.html + 348 + + + + Active Users + 활성 사용자 + + apps/client/src/app/pages/open/open-page.html + 40 + + + apps/client/src/app/pages/open/open-page.html + 62 + + + + (Last 30 days) + (지난 30일) + + apps/client/src/app/pages/open/open-page.html + 48 + + + apps/client/src/app/pages/open/open-page.html + 59 + + + + and a safe withdrawal rate (SWR) of + 안전 인출률(SWR)은 다음과 같습니다. + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 108 + + + + New Users + 신규 사용자 + + apps/client/src/app/pages/open/open-page.html + 51 + + + + Users in Slack community + 슬랙 커뮤니티의 사용자 + + apps/client/src/app/pages/open/open-page.html + 75 + + + + Job ID + 작업 ID + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 34 + + + + Contributors on GitHub + 깃허브의 기여자 + + apps/client/src/app/pages/open/open-page.html + 89 + + + + (Last 90 days) + (지난 90일) + + apps/client/src/app/pages/open/open-page.html + 127 + + + + Uptime + 가동 시간 + + apps/client/src/app/pages/open/open-page.html + 132 + + + + Activities + 활동 + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 86 + + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 113 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 226 + + + apps/client/src/app/components/admin-tag/admin-tag.component.html + 45 + + + apps/client/src/app/components/admin-users/admin-users.html + 118 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 231 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 342 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 94 + + + apps/client/src/app/pages/portfolio/activities/activities-page.html + 4 + + + libs/common/src/lib/routes/routes.ts + 128 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 126 + + + + Do you really want to delete these activities? + 정말로 이 활동을 삭제하시겠습니까? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 282 + + + + Update activity + 활동 업데이트 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 10 + + + + Stocks, ETFs, bonds, cryptocurrencies, commodities + 주식, ETF, 채권, 암호화폐, 원자재 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 25 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 65 + + + + One-time fee, annual account fees + 일회성 수수료, 연간 계정 수수료 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 33 + + + + Distribution of corporate earnings + 기업 수익 분배 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 41 + + + + Revenue for lending out money + 이자 수익 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 49 + + + + Mortgages, personal loans, credit cards + 모기지, 개인 대출, 신용카드 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 57 + + + + Luxury items, real estate, private companies + 명품, 부동산, 민간 기업 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 73 + + + + Update Cash Balance + 현금 잔액 업데이트 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 108 + + + + Unit Price + 단가 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 210 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 217 + + + + Import Activities + 활동 가져오기 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts + 92 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 9 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 383 + + + + Import Dividends + 배당금 가져오기 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts + 137 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 29 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 397 + + + + Importing data... + 데이터 가져오는 중... + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts + 175 + + + + Import has been completed + 가져오기가 완료되었습니다. + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts + 185 + + + + or start a discussion at + 또는 다음에서 토론을 시작하세요. + + apps/client/src/app/pages/about/overview/about-overview-page.html + 94 + + + + Validating data... + 데이터 유효성을 검사하는 중... + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.component.ts + 299 + + + + Select Holding + 보유 종목 선택 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 19 + + + + Select File + 파일 선택 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 21 + + + + Holding + 보유 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 32 + + + libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html + 26 + + + + Load Dividends + 배당금 불러오기 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 68 + + + + Choose or drop a file here + 여기에 파일을 선택하거나 드롭하세요. + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 84 + + + + The following file formats are supported: + 다음 파일 형식이 지원됩니다. + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 90 + + + + Select Dividends + 배당금 선택 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 113 + + + + Select Activities + 활동 선택 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 115 + + + + Back + 뒤쪽에 + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 146 + + + apps/client/src/app/pages/portfolio/activities/import-activities-dialog/import-activities-dialog.html + 182 + + + + Allocations + 할당 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 4 + + + apps/client/src/app/pages/portfolio/allocations/allocations-page.routes.ts + 12 + + + libs/common/src/lib/routes/routes.ts + 133 + + + + Proportion of Net Worth + 순자산 비율 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 12 + + + + By Platform + 플랫폼별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 44 + + + + By Currency + 통화별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 63 + + + + By Asset Class + 자산 클래스별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 85 + + + + By Holding + 보유 종목별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 107 + + + + By Sector + 부문별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 130 + + + + By Continent + 대륙별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 153 + + + + By Market + 시장별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 175 + + + + Regions + 지역 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 198 + + + apps/client/src/app/pages/public/public-page.html + 150 + + + + Exclude from Analysis + 분석에서 제외 + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 90 + + + libs/ui/src/lib/i18n.ts + 17 + + + + Developed Markets + 선진시장 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 222 + + + apps/client/src/app/pages/public/public-page.html + 167 + + + + Latest activities + 최신 활동 + + apps/client/src/app/pages/public/public-page.html + 210 + + + + Emerging Markets + 신흥시장 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 231 + + + apps/client/src/app/pages/public/public-page.html + 176 + + + + Other Markets + 기타 시장 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 240 + + + apps/client/src/app/pages/public/public-page.html + 185 + + + + By Account + 계정별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 286 + + + + By ETF Provider + ETF 제공자별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 306 + + + + By Country + 국가별 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 264 + + + + Analysis + 분석 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 2 + + + libs/common/src/lib/routes/routes.ts + 138 + + + + Looking for a student discount? + 학생 할인을 찾고 계십니까? + + apps/client/src/app/pages/pricing/pricing-page.html + 342 + + + + Dividend + 배당금 + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 81 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 186 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 372 + + + apps/client/src/app/pages/features/features-page.html + 63 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 198 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 76 + + + libs/ui/src/lib/i18n.ts + 38 + + + + annual interest rate + 연간 이자율 + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 185 + + + + Deposit + 보증금 + + libs/ui/src/lib/fire-calculator/fire-calculator.component.ts + 390 + + + + Monthly + 월간 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 91 + + + + Yearly + 매년 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 92 + + + + Top + 상위 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 305 + + + + Bottom + 하위 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 354 + + + + Portfolio Evolution + 포트폴리오 진화 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 407 + + + + Investment Timeline + 투자 일정 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 434 + + + + Current Streak + 현재 연속 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 455 + + + + Longest Streak + 최장 연속 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 464 + + + + Dividend Timeline + 배당 일정 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 491 + + + + FIRE + + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 4 + + + + Calculator + 계산자 + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 7 + + + + Pricing + 가격 + + apps/client/src/app/components/footer/footer.component.html + 49 + + + apps/client/src/app/components/header/header.component.html + 105 + + + apps/client/src/app/components/header/header.component.html + 313 + + + apps/client/src/app/components/header/header.component.html + 389 + + + apps/client/src/app/pages/pricing/pricing-page.routes.ts + 12 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 287 + + + libs/common/src/lib/routes/routes.ts + 271 + + + + Pricing Plans + 가격 계획 + + apps/client/src/app/pages/pricing/pricing-page.html + 4 + + + + Our official Ghostfolio Premium cloud offering is the easiest way to get started. Due to the time it saves, this will be the best option for most people. Revenue is used to cover operational costs for the hosting infrastructure and professional data providers, and to fund ongoing development. + 공식 Ghostfolio 프리미엄 클라우드 서비스는 시작하는 가장 쉬운 방법입니다. 시간이 절약되므로 이는 대부분의 사람들에게 최선의 선택이 될 것입니다. 수익은 호스팅 인프라 및 전문 데이터 제공업체의 운영 비용을 충당하고 지속적인 개발 자금을 조달하는 데 사용됩니다. + + apps/client/src/app/pages/pricing/pricing-page.html + 7 + + + + If you prefer to run Ghostfolio on your own infrastructure, please find the source code and further instructions on GitHub. + 자체 인프라에서 Ghostfolio를 운영하고 싶다면, 깃허브에서 소스 코드와 추가 안내를 확인하세요. + + apps/client/src/app/pages/pricing/pricing-page.html + 14 + + + + For tech-savvy investors who prefer to run Ghostfolio on their own infrastructure. + 자체 인프라에서 Ghostfolio를 실행하기를 선호하는 기술에 정통한 투자자를 위한 것입니다. + + apps/client/src/app/pages/pricing/pricing-page.html + 26 + + + + Unlimited Transactions + 무제한 거래 + + apps/client/src/app/pages/pricing/pricing-page.html + 35 + + + apps/client/src/app/pages/pricing/pricing-page.html + 127 + + + + Unlimited Accounts + 무제한 계정 + + apps/client/src/app/pages/pricing/pricing-page.html + 39 + + + apps/client/src/app/pages/pricing/pricing-page.html + 131 + + + + Portfolio Performance + 포트폴리오 성과 + + apps/client/src/app/pages/pricing/pricing-page.html + 43 + + + apps/client/src/app/pages/pricing/pricing-page.html + 135 + + + + Data Import and Export + 데이터 가져오기 및 내보내기 + + apps/client/src/app/pages/pricing/pricing-page.html + 63 + + + apps/client/src/app/pages/pricing/pricing-page.html + 139 + + + + Community Support + 커뮤니티 지원 + + apps/client/src/app/pages/pricing/pricing-page.html + 80 + + + + Self-hosted, update manually. + 자체 호스팅, 수동으로 업데이트합니다. + + apps/client/src/app/pages/pricing/pricing-page.html + 84 + + + + Free + 무료 + + apps/client/src/app/pages/pricing/pricing-page.html + 86 + + + apps/client/src/app/pages/pricing/pricing-page.html + 152 + + + + For new investors who are just getting started with trading. + 이제 막 거래를 시작한 신규 투자자를 위한 제품입니다. + + apps/client/src/app/pages/pricing/pricing-page.html + 119 + + + + Fully managed Ghostfolio cloud offering. + 완전 관리형 Ghostfolio 클라우드 제품. + + apps/client/src/app/pages/pricing/pricing-page.html + 150 + + + apps/client/src/app/pages/pricing/pricing-page.html + 252 + + + + For ambitious investors who need the full picture of their financial assets. + 자신의 금융 자산에 대한 전체 그림이 필요한 야심찬 투자자를 위한 제품입니다. + + apps/client/src/app/pages/pricing/pricing-page.html + 193 + + + + Email and Chat Support + 이메일 및 채팅 지원 + + apps/client/src/app/pages/pricing/pricing-page.html + 248 + + + + Renew Plan + 플랜 갱신 + + apps/client/src/app/components/header/header.component.html + 191 + + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 19 + + + apps/client/src/app/pages/pricing/pricing-page.html + 279 + + + + One-time payment, no auto-renewal. + 일회성 결제, 자동 갱신 없음. + + apps/client/src/app/pages/pricing/pricing-page.html + 285 + + + + Could not save asset profile + Could not save asset profile + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 604 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 607 + + + + It’s free. + 무료입니다. + + apps/client/src/app/pages/pricing/pricing-page.html + 362 + + + + Hello, has shared a Portfolio with you! + 안녕하세요. 님이 포트폴리오를 공유했습니다! + + apps/client/src/app/pages/public/public-page.html + 5 + + + + Continents + 대륙 + + apps/client/src/app/pages/public/public-page.html + 131 + + + + Sustainable retirement income + 지속 가능한 퇴직 소득 + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 41 + + + + Ghostfolio empowers you to keep track of your wealth. + Ghostfolio는 귀하의 재산을 추적할 수 있도록 해줍니다. + + apps/client/src/app/pages/public/public-page.html + 237 + + + + Registration + 등록 + + apps/client/src/app/components/admin-users/admin-users.html + 80 + + + libs/common/src/lib/routes/routes.ts + 281 + + + + Continue with Google + 구글로 계속하기 + + apps/client/src/app/pages/register/register-page.html + 43 + + + + Copy to clipboard + 클립보드에 복사 + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 88 + + + + Personal Finance Tools + 개인 금융 도구 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 351 + + + libs/common/src/lib/routes/routes.ts + 329 + + + + open-source-alternative-to + open-source-alternative-to + kebab-case + + libs/common/src/lib/routes/routes.ts + 320 + + + libs/common/src/lib/routes/routes.ts + 324 + + + + Discover Open Source Alternatives for Personal Finance Tools + 개인 금융 도구를 위한 오픈 소스 대안을 찾아보세요 + + apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html + 5 + + + + This overview page features a curated collection of personal finance tools compared to the open source alternative Ghostfolio. If you value transparency, data privacy, and community collaboration, Ghostfolio provides an excellent opportunity to take control of your financial management. + 이 개요 페이지에는 오픈 소스 대안인 Ghostfolio와 비교하여 엄선된 개인 금융 도구 컬렉션이 포함되어 있습니다. 투명성, 데이터 개인 정보 보호 및 커뮤니티 협업을 중요하게 생각한다면 Ghostfolio는 재무 관리를 제어할 수 있는 훌륭한 기회를 제공합니다. + + apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html + 9 + + + + Explore the links below to compare a variety of personal finance tools with Ghostfolio. + Ghostfolio와 다양한 개인 금융 도구를 비교하려면 아래 링크를 탐색하십시오. + + apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html + 17 + + + + Open Source Alternative to + 의 오픈 소스 대안 + + apps/client/src/app/pages/resources/personal-finance-tools/personal-finance-tools-page.html + 42 + + + + The Open Source Alternative to + 오픈 소스 대안 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 8 + + + + Are you looking for an open source alternative to ? Ghostfolio is a powerful portfolio management tool that provides individuals with a comprehensive platform to track, analyze, and optimize their investments. Whether you are an experienced investor or just starting out, Ghostfolio offers an intuitive user interface and a wide range of functionalities to help you make informed decisions and take control of your financial future. + 에 대한 오픈소스 대안을 찾고 계십니까? Ghostfolio는 개인에게 투자를 추적, 분석, 최적화할 수 있는 포괄적인 플랫폼을 제공하는 강력한 포트폴리오 관리 도구입니다. 숙련된 투자자이든 이제 막 시작한 투자자이든 Ghostfolio는 직관적인 사용자 인터페이스와 다양한 기능을 제공하여 정보에 입각한 결정을 내리고 재정적 미래를 관리하는 데 도움을 줍니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 19 + + + + Ghostfolio is an open source software (OSS), providing a cost-effective alternative to making it particularly suitable for individuals on a tight budget, such as those pursuing Financial Independence, Retire Early (FIRE). By leveraging the collective efforts of a community of developers and personal finance enthusiasts, Ghostfolio continuously enhances its capabilities, security, and user experience. + Ghostfolio는 오픈 소스 소프트웨어로, 에 대한 비용 효율적인 대안을 제공하므로 재정적 독립, 조기 퇴직(FIRE)을 추구하는 사람과 같이 예산이 부족한 개인에게 특히 적합합니다. Ghostfolio는 개발자 커뮤니티와 개인 금융 애호가들의 공동 노력을 활용하여 기능, 보안 및 사용자 경험을 지속적으로 향상시킵니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 33 + + + + Let’s dive deeper into the detailed Ghostfolio vs comparison table below to gain a thorough understanding of how Ghostfolio positions itself relative to . We will explore various aspects such as features, data privacy, pricing, and more, allowing you to make a well-informed choice for your personal requirements. + Ghostfolio가 과 관련하여 어떻게 위치하는지 철저하게 이해하기 위해 아래의 자세한 Ghostfolio 대 비교표를 자세히 살펴보겠습니다. 우리는 기능, 데이터 개인 정보 보호, 가격 등과 같은 다양한 측면을 탐색하여 귀하의 개인 요구 사항에 맞는 정보를 바탕으로 선택할 수 있도록 할 것입니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 44 + + + + per month + 매월 + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 94 + + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 172 + + + + Ghostfolio vs comparison table + Ghostfolio와 비교표 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 55 + + + + Website of Thomas Kaul + 토마스 카울의 웹사이트 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 44 + + + + Founded + 설립 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 77 + + + + Origin + 기원 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 82 + + + + Region + 지역 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 87 + + + + Available in + 사용 가능 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 109 + + + + ✅ Yes + ✅ 예 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 140 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 157 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 179 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 196 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 218 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 235 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 257 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 274 + + + + ❌ No + ❌ 아니요 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 147 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 164 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 186 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 203 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 225 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 242 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 264 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 281 + + + + Self-Hosting + 셀프 호스팅 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 171 + + + + Use anonymously + 익명으로 사용 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 210 + + + + Free Plan + 무료 플랜 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 249 + + + + Starting from + 에서 시작 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 289 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 294 + + + + Notes + 메모 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 302 + + + + Please note that the information provided in the Ghostfolio vs comparison table is based on our independent research and analysis. This website is not affiliated with or any other product mentioned in the comparison. As the landscape of personal finance tools evolves, it is essential to verify any specific details or changes directly from the respective product page. Data needs a refresh? Help us maintain accurate data on GitHub. + Ghostfolio와 비교표에 제공된 정보는 당사의 독립적인 연구 및 분석을 기반으로 한 것입니다. 이 웹사이트는 또는 비교에 언급된 다른 제품과 관련이 없습니다. 개인 금융 도구의 환경이 발전함에 따라 각 제품 페이지에서 직접 특정 세부 정보나 변경 사항을 확인하는 것이 중요합니다. 데이터를 새로 고쳐야 합니까? 깃허브에서 정확한 데이터를 유지할 수 있도록 도와주세요. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 312 + + + + Ready to take your investments to the next level? + 투자다음 단계로 발전시킬 준비가 되셨나요? + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 325 + + + + Effortlessly track, analyze, and visualize your wealth with Ghostfolio. + Ghostfolio를 사용하여 귀하의 재산을 쉽게 추적, 분석 및 시각화하십시오. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 329 + + + + Switzerland + 스위스 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 58 + + + libs/ui/src/lib/i18n.ts + 99 + + + + Global + 글로벌 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 59 + + + libs/ui/src/lib/i18n.ts + 18 + + + + Resources + 리소스 + + apps/client/src/app/components/footer/footer.component.html + 14 + + + apps/client/src/app/components/header/header.component.html + 88 + + + apps/client/src/app/components/header/header.component.html + 301 + + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 4 + + + libs/common/src/lib/routes/routes.ts + 332 + + + + Membership + 멤버십 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 67 + + + libs/common/src/lib/routes/routes.ts + 31 + + + libs/ui/src/lib/membership-card/membership-card.component.html + 40 + + + + Request it + 요청하세요 + + apps/client/src/app/pages/pricing/pricing-page.html + 344 + + + + Access + 입장 + + libs/common/src/lib/routes/routes.ts + 26 + + + + My Ghostfolio + 나의 고스트폴리오 + + apps/client/src/app/components/header/header.component.html + 277 + + + apps/client/src/app/pages/user-account/user-account-page.routes.ts + 33 + + + + Oops, authentication has failed. + 앗, 인증에 실패했습니다. + + apps/client/src/app/pages/webauthn/webauthn-page.html + 19 + + + + Try again + 다시 시도하세요 + + apps/client/src/app/pages/webauthn/webauthn-page.html + 27 + + + + Go back to Home Page + 홈 페이지로 돌아가기 + + apps/client/src/app/pages/webauthn/webauthn-page.html + 33 + + + + Do you really want to delete this account balance? + 정말로 이 계정 잔액을 삭제하시겠습니까? + + libs/ui/src/lib/account-balances/account-balances.component.ts + 113 + + + + Export Activities + 수출 활동 + + libs/ui/src/lib/activities-table/activities-table.component.html + 41 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 411 + + + + Export Drafts as ICS + 초안을 달력 파일로 내보내기 + + libs/ui/src/lib/activities-table/activities-table.component.html + 54 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 424 + + + + Draft + 초안 + + libs/ui/src/lib/activities-table/activities-table.component.html + 144 + + + + Clone + 클론 + + libs/ui/src/lib/activities-table/activities-table.component.html + 463 + + + + Export Draft as ICS + 초안을 달력 파일로 내보내기 + + libs/ui/src/lib/activities-table/activities-table.component.html + 473 + + + + Do you really want to delete this activity? + 정말로 이 활동을 삭제하시겠습니까? + + libs/ui/src/lib/activities-table/activities-table.component.ts + 292 + + + + Asset Profiles + 자산 프로필 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 123 + + + libs/ui/src/lib/assistant/assistant.html + 140 + + + + 50-Day Trend + 50일 추세 + + libs/ui/src/lib/benchmark/benchmark.component.html + 32 + + + + 200-Day Trend + 200일 추세 + + libs/ui/src/lib/benchmark/benchmark.component.html + 61 + + + + , + , + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 145 + + + + Last All Time High + 마지막 역대 최고치 + + libs/ui/src/lib/benchmark/benchmark.component.html + 90 + + + + Change from All Time High + 역대 최고치에서 변화 + + libs/ui/src/lib/benchmark/benchmark.component.html + 117 + + + + contact us + 저희에게 연락주세요 + + apps/client/src/app/pages/pricing/pricing-page.html + 336 + + + + from ATH + ATH에서 + + libs/ui/src/lib/benchmark/benchmark.component.html + 119 + + + + Market data provided by + 시장 데이터 제공: + + libs/ui/src/lib/data-provider-credits/data-provider-credits.component.html + 2 + + + + Savings Rate per Month + 월별 저축률 + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 10 + + + + Annual Interest Rate + 연이자율 + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 21 + + + + Retirement Date + 퇴직일 + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 32 + + + + Projected Total Amount + 예상총액 + + libs/ui/src/lib/fire-calculator/fire-calculator.component.html + 59 + + + + Interest + 관심 + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 69 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 359 + + + libs/ui/src/lib/fire-calculator/fire-calculator.component.ts + 400 + + + libs/ui/src/lib/i18n.ts + 40 + + + + Savings + 저금 + + libs/ui/src/lib/fire-calculator/fire-calculator.component.ts + 410 + + + + Allocation + 배당 + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 248 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 117 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 40 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 116 + + + + Show all + 모두 표시 + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 212 + + + + Account + 계정 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 85 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 315 + + + libs/ui/src/lib/i18n.ts + 4 + + + libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html + 4 + + + + Asia-Pacific + 아시아·태평양 + + libs/ui/src/lib/i18n.ts + 5 + + + + Asset Class + 자산 클래스 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 114 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 235 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 327 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 242 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 286 + + + libs/ui/src/lib/i18n.ts + 6 + + + libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html + 64 + + + + Asset Sub Class + 자산 하위 클래스 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 123 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 244 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 343 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 251 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 305 + + + libs/ui/src/lib/i18n.ts + 7 + + + + Core + 핵심 + + libs/ui/src/lib/i18n.ts + 10 + + + + Switch to Ghostfolio Premium or Ghostfolio Open Source easily + Ghostfolio 프리미엄 또는 Ghostfolio Open Source로 쉽게 전환하세요 + + libs/ui/src/lib/i18n.ts + 12 + + + + Switch to Ghostfolio Premium easily + Ghostfolio 프리미엄으로 쉽게 전환하세요 + + libs/ui/src/lib/i18n.ts + 13 + + + + Switch to Ghostfolio Open Source or Ghostfolio Basic easily + Ghostfolio Open Source 또는 Ghostfolio Basic으로 쉽게 전환하세요 + + libs/ui/src/lib/i18n.ts + 14 + + + + Emergency Fund + 비상자금 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 168 + + + apps/client/src/app/pages/features/features-page.html + 89 + + + libs/ui/src/lib/i18n.ts + 16 + + + + Grant + 승인하다 + + libs/ui/src/lib/i18n.ts + 19 + + + + Higher Risk + 더 높은 위험 + + libs/ui/src/lib/i18n.ts + 20 + + + + This activity already exists. + 이 활동은 이미 존재합니다. + + libs/ui/src/lib/i18n.ts + 21 + + + + Japan + 일본 + + libs/ui/src/lib/i18n.ts + 92 + + + + Lower Risk + 위험 감소 + + libs/ui/src/lib/i18n.ts + 22 + + + + Month + + + libs/ui/src/lib/i18n.ts + 23 + + + + Months + 개월 + + libs/ui/src/lib/i18n.ts + 24 + + + + Other + 다른 + + libs/ui/src/lib/i18n.ts + 25 + + + libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts + 449 + + + + Preset + 프리셋 + + libs/ui/src/lib/i18n.ts + 27 + + + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + + + Retirement Provision + 퇴직금 + + libs/ui/src/lib/i18n.ts + 28 + + + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + + + Satellite + 위성 + + libs/ui/src/lib/i18n.ts + 29 + + + + Symbol + 상징 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 68 + + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 74 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 169 + + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 37 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 315 + + + libs/ui/src/lib/i18n.ts + 30 + + + + Tag + 꼬리표 + + libs/ui/src/lib/i18n.ts + 31 + + + libs/ui/src/lib/portfolio-filter-form/portfolio-filter-form.component.html + 53 + + + + Year + 년도 + + libs/ui/src/lib/i18n.ts + 32 + + + + View Details + 세부정보 보기 + + apps/client/src/app/components/admin-users/admin-users.html + 225 + + + libs/ui/src/lib/accounts-table/accounts-table.component.html + 314 + + + + Years + 연령 + + libs/ui/src/lib/i18n.ts + 33 + + + + Sign in with OpenID Connect + OpenID Connect로 로그인 + + apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html + 55 + + + + Buy + 구입하다 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 31 + + + libs/ui/src/lib/i18n.ts + 37 + + + + Fee + 요금 + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 258 + + + libs/ui/src/lib/activities-table/activities-table.component.html + 241 + + + libs/ui/src/lib/i18n.ts + 39 + + + + Valuable + 귀중한 + + libs/ui/src/lib/i18n.ts + 43 + + + + Liability + 책임 + + libs/ui/src/lib/i18n.ts + 41 + + + + Sell + 팔다 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 44 + + + libs/ui/src/lib/i18n.ts + 42 + + + + Cash + 현금 + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 219 + + + libs/ui/src/lib/i18n.ts + 55 + + + + Commodity + 상품 + + libs/ui/src/lib/i18n.ts + 47 + + + + Equity + 주식 + + apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html + 57 + + + libs/ui/src/lib/i18n.ts + 48 + + + + Fixed Income + 채권 + + libs/ui/src/lib/i18n.ts + 49 + + + + Real Estate + 부동산 + + libs/ui/src/lib/i18n.ts + 51 + + + + Authentication + 입증 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 54 + + + + Bond + 노예 + + libs/ui/src/lib/i18n.ts + 54 + + + + Cryptocurrency + 암호화폐 + + libs/ui/src/lib/i18n.ts + 57 + + + + ETF + ETF + + libs/ui/src/lib/i18n.ts + 58 + + + + Mutual Fund + 뮤추얼 펀드 + + libs/ui/src/lib/i18n.ts + 59 + + + + Precious Metal + 귀금속 + + libs/ui/src/lib/i18n.ts + 60 + + + + Private Equity + 사모펀드 + + libs/ui/src/lib/i18n.ts + 61 + + + + Stock + 재고 + + libs/ui/src/lib/i18n.ts + 62 + + + + Africa + 아프리카 + + libs/ui/src/lib/i18n.ts + 69 + + + + Asia + 아시아 + + libs/ui/src/lib/i18n.ts + 70 + + + + Europe + 유럽 + + libs/ui/src/lib/i18n.ts + 71 + + + + North America + 북미 + + libs/ui/src/lib/i18n.ts + 72 + + + + If you retire today, you would be able to withdraw + 오늘 퇴사하면 탈퇴 가능 + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 68 + + + + Oceania + 오세아니아 + + libs/ui/src/lib/i18n.ts + 73 + + + + South America + 남아메리카 + + libs/ui/src/lib/i18n.ts + 74 + + + + Extreme Fear + 극심한 공포 + + libs/ui/src/lib/i18n.ts + 106 + + + + Extreme Greed + 극도의 탐욕 + + libs/ui/src/lib/i18n.ts + 107 + + + + Neutral + 중립적 + + libs/ui/src/lib/i18n.ts + 110 + + + + Valid until + 유효기간 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 86 + + + libs/ui/src/lib/membership-card/membership-card.component.html + 45 + + + + Time to add your first activity. + 첫 번째 활동을 추가할 시간입니다. + + libs/ui/src/lib/no-transactions-info/no-transactions-info.component.html + 12 + + + + No data available + 사용 가능한 데이터가 없습니다. + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 250 + + + apps/client/src/app/pages/public/public-page.html + 195 + + + libs/ui/src/lib/benchmark/benchmark.component.html + 209 + + + libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts + 451 + + + libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts + 465 + + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 181 + + + + If a translation is missing, kindly support us in extending it here. + 번역이 누락된 경우 여기에서 번역을 확장할 수 있도록 지원해 주시기 바랍니다. + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 59 + + + + Date Range + 기간 + + libs/ui/src/lib/assistant/assistant.html + 170 + + + + The current market price is + 현재 시장가격은 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 722 + + + + Test + 시험 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 571 + + + + Oops! Could not grant access. + 이런! 액세스 권한을 부여할 수 없습니다. + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts + 141 + + + + Argentina + 아르헨티나 + + libs/ui/src/lib/i18n.ts + 78 + + + + Restricted view + 제한된 보기 + + apps/client/src/app/components/access-table/access-table.component.html + 26 + + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 40 + + + + Permission + 허가 + + apps/client/src/app/components/access-table/access-table.component.html + 18 + + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 38 + + + + Private + 사적인 + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 30 + + + + Job Queue + 작업 대기열 + + libs/common/src/lib/routes/routes.ts + 46 + + + + Market data is delayed for + 시장 데이터가 지연됩니다. + + apps/client/src/app/components/portfolio-performance/portfolio-performance.component.ts + 95 + + + + Absolute Currency Performance + 절대적인 통화 성과 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 211 + + + + Close Holding + 닫기 보유 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 441 + + + + Absolute Asset Performance + 절대자산성과 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 168 + + + + Investment + 투자 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 171 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 60 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 81 + + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 97 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 89 + + + + here + 여기 + + apps/client/src/app/pages/pricing/pricing-page.html + 347 + + + + Asset Performance + 자산 성과 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 190 + + + + Currency Performance + 통화 성과 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 236 + + + + Year to date + 연초 현재 + + libs/ui/src/lib/assistant/assistant.component.ts + 374 + + + + Week to date + 이번주 현재까지 + + libs/ui/src/lib/assistant/assistant.component.ts + 366 + + + + Month to date + 월간 누계 + + libs/ui/src/lib/assistant/assistant.component.ts + 370 + + + + MTD + MTD + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 200 + + + libs/ui/src/lib/assistant/assistant.component.ts + 370 + + + + WTD + WTD + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 196 + + + libs/ui/src/lib/assistant/assistant.component.ts + 366 + + + + Oops! A data provider is experiencing the hiccups. + 이런! 데이터 제공업체에 문제가 발생했습니다. + + apps/client/src/app/components/portfolio-performance/portfolio-performance.component.html + 8 + + + + View + 보다 + + apps/client/src/app/components/access-table/access-table.component.html + 23 + + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 42 + + + + Reset Filters + 필터 재설정 + + libs/ui/src/lib/assistant/assistant.html + 204 + + + + year + 년도 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 208 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 290 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 296 + + + libs/ui/src/lib/assistant/assistant.component.ts + 384 + + + + years + 연령 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 212 + + + libs/ui/src/lib/assistant/assistant.component.ts + 408 + + + + Apply Filters + 필터 적용 + + libs/ui/src/lib/assistant/assistant.html + 217 + + + + self-hosting + self-hosting + kebab-case + + libs/common/src/lib/routes/routes.ts + 243 + + + libs/common/src/lib/routes/routes.ts + 246 + + + + Self-Hosting + 셀프 호스팅 + + apps/client/src/app/pages/faq/faq-page.component.ts + 52 + + + libs/common/src/lib/routes/routes.ts + 248 + + + + Data Gathering + 데이터 수집 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 594 + + + apps/client/src/app/components/admin-overview/admin-overview.html + 60 + + + + General + 일반적인 + + apps/client/src/app/pages/faq/faq-page.component.ts + 41 + + + + Cloud + 구름 + + apps/client/src/app/pages/faq/faq-page.component.ts + 46 + + + libs/common/src/lib/routes/routes.ts + 240 + + + + Oops! It looks like you’re making too many requests. Please slow down a bit. + 이런! 요청을 너무 많이 하시는 것 같습니다. 조금 천천히 해주세요. + + apps/client/src/app/core/http-response.interceptor.ts + 106 + + + + My Account + 내 계정 + + apps/client/src/app/pages/i18n/i18n-page.html + 13 + + + + Closed + 닫은 + + apps/client/src/app/components/home-holdings/home-holdings.component.ts + 65 + + + + Active + 활동적인 + + apps/client/src/app/components/home-holdings/home-holdings.component.ts + 64 + + + + Indonesia + 인도네시아 공화국 + + libs/ui/src/lib/i18n.ts + 90 + + + + Activity + 활동 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 229 + + + + Dividend Yield + 배당수익률 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 196 + + + + Execute Job + 작업 실행 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 220 + + + + This action is not allowed. + 이 작업은 허용되지 않습니다. + + apps/client/src/app/core/http-response.interceptor.ts + 67 + + + + Priority + 우선 사항 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 96 + + + + Liquidity + 유동성 + + libs/ui/src/lib/i18n.ts + 50 + + + + Buy and sell + 구매 및 판매 + + libs/ui/src/lib/i18n.ts + 8 + + + + {VAR_PLURAL, plural, =1 {activity} other {activities}} + {VAR_PLURAL, 복수형, =1 {활동} 기타 {활동}} + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html + 14 + + + + Delete Activities + 활동 삭제 + + libs/ui/src/lib/activities-table/activities-table.component.html + 69 + + + + Internationalization + 국제화 + + libs/common/src/lib/routes/routes.ts + 119 + + + + Close Account + 계정 폐쇄 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 316 + + + + Do you really want to close your Ghostfolio account? + 정말로 Ghostfolio 계정을 폐쇄하시겠습니까? + + apps/client/src/app/components/user-account-settings/user-account-settings.component.ts + 208 + + + + Danger Zone + 위험지대 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 281 + + + + Approximation based on the top holdings of each ETF + 각 ETF의 상위 보유량을 기준으로 한 근사치 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 340 + + + + By ETF Holding + ETF 홀딩으로 + + apps/client/src/app/pages/portfolio/allocations/allocations-page.html + 333 + + + + Join now or check out the example account + 지금 가입하거나 예시 계정을 확인하세요. + + apps/client/src/app/pages/landing/landing-page.html + 333 + + + + Include in + 포함 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 377 + + + + Oops! There was an error setting up biometric authentication. + 이런! 생체 인증을 설정하는 중에 오류가 발생했습니다. + + apps/client/src/app/components/user-account-settings/user-account-settings.component.ts + 336 + + + + Show more + 더 보기 + + libs/ui/src/lib/top-holdings/top-holdings.component.html + 174 + + + + Do you really want to delete these profiles? + 이 프로필을 정말로 삭제하시겠습니까? + + apps/client/src/app/components/admin-market-data/admin-market-data.service.ts + 68 + + + + Delete Profiles + 프로필 삭제 + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 242 + + + + Oops! Could not delete profiles. + 이런! 프로필을 삭제할 수 없습니다. + + apps/client/src/app/components/admin-market-data/admin-market-data.service.ts + 56 + + + + Benchmarks + 벤치마크 + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 126 + + + + Chart + 차트 + + apps/client/src/app/components/home-holdings/home-holdings.html + 19 + + + + Table + 테이블 + + apps/client/src/app/components/home-holdings/home-holdings.html + 16 + + + + Would you like to refine your personal investment strategy? + 개인 투자 전략개선하시겠습니까? + + apps/client/src/app/pages/public/public-page.html + 233 + + + + Wealth + 재산 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 99 + + + + Community + 지역 사회 + + apps/client/src/app/components/footer/footer.component.html + 80 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 85 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 91 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 95 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 99 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 103 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 109 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 114 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 118 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 122 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 + + + apps/client/src/app/pages/features/features-page.html + 277 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 86 + + + + Thailand + 태국 + + libs/ui/src/lib/i18n.ts + 100 + + + + India + 인도 + + libs/ui/src/lib/i18n.ts + 89 + + + + Austria + 오스트리아 + + libs/ui/src/lib/i18n.ts + 80 + + + + Poland + 폴란드 + + libs/ui/src/lib/i18n.ts + 95 + + + + Italy + 이탈리아 + + libs/ui/src/lib/i18n.ts + 91 + + + + User Experience + 사용자 경험 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 98 + + + + App + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 84 + + + + Tool + 도구 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 97 + + + + Investor + 투자자 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 90 + + + + Wealth Management + 자산관리 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 100 + + + + View Holding + 보유보기 + + libs/ui/src/lib/activities-table/activities-table.component.html + 450 + + + + Canada + 캐나다 + + libs/ui/src/lib/i18n.ts + 84 + + + + New Zealand + 뉴질랜드 + + libs/ui/src/lib/i18n.ts + 94 + + + + Netherlands + 네덜란드 + + libs/ui/src/lib/i18n.ts + 93 + + + + Alternative + 대안 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 83 + + + + Family Office + 패밀리오피스 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 87 + + + + Personal Finance + 개인 금융 + + apps/client/src/app/components/footer/footer.component.html + 7 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 93 + + + + Software + 소프트웨어 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 96 + + + + Romania + 루마니아 + + libs/ui/src/lib/i18n.ts + 96 + + + + Germany + 독일 + + libs/ui/src/lib/i18n.ts + 88 + + + + United States + 미국 + + libs/ui/src/lib/i18n.ts + 103 + + + + Budgeting + 예산 편성 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 85 + + + + Belgium + 벨기에 + + libs/ui/src/lib/i18n.ts + 81 + + + + Open Source + 오픈 소스 + + apps/client/src/app/pages/landing/landing-page.html + 159 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 91 + + + + Czech Republic + 체코 + + libs/ui/src/lib/i18n.ts + 85 + + + + Australia + 호주 + + libs/ui/src/lib/i18n.ts + 79 + + + + South Africa + 남아프리카 + + libs/ui/src/lib/i18n.ts + 98 + + + + Bulgaria + 불가리아 + + libs/ui/src/lib/i18n.ts + 83 + + + + Privacy + 은둔 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts + 94 + + + + Finland + 핀란드 + + libs/ui/src/lib/i18n.ts + 86 + + + + France + 프랑스 + + libs/ui/src/lib/i18n.ts + 87 + + + + Error + 오류 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 713 + + + + Cancel + 취소 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 162 + + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 599 + + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 57 + + + apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html + 44 + + + apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html + 27 + + + apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.html + 17 + + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 66 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 105 + + + apps/client/src/app/pages/accounts/transfer-balance/transfer-balance-dialog.html + 65 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 341 + + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 48 + + + libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html + 47 + + + libs/ui/src/lib/i18n.ts + 9 + + + + Role + 역할 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 33 + + + + Yes + + + libs/ui/src/lib/i18n.ts + 34 + + + + , based on your total assets of + , 귀하의 총 자산을 기준으로 + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 96 + + + + Inactive + 비활성 + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 88 + + + + Close + 닫다 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 601 + + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 59 + + + apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html + 46 + + + apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html + 29 + + + apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.html + 19 + + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 130 + + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 68 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 107 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 343 + + + libs/ui/src/lib/i18n.ts + 11 + + + + Activate + 활성화 + + apps/client/src/app/components/rule/rule.component.html + 83 + + + + Oops! Could not update access. + 이런! 액세스를 업데이트할 수 없습니다. + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts + 178 + + + + Deactivate + 비활성화 + + apps/client/src/app/components/rule/rule.component.html + 78 + + + + Threshold Max + 임계값 최대 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 93 + + + + send an e-mail to + 에게 이메일을 보내다 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 87 + + + + Customize + 사용자 정의 + + apps/client/src/app/components/rule/rule.component.html + 69 + + + + Portfolio Snapshot + 포트폴리오 스냅샷 + + apps/client/src/app/components/admin-jobs/admin-jobs.html + 56 + + + + Threshold Min + 임계값 최소 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 55 + + + + If you plan to open an account at + 에서 계좌를 개설할 계획이라면 + + apps/client/src/app/pages/pricing/pricing-page.html + 312 + + + + Performance with currency effect Performance + 환율 효과가 있는 실적 실적 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 83 + + + + Copy link to clipboard + 링크를 클립보드에 복사 + + apps/client/src/app/components/access-table/access-table.component.html + 84 + + + + Change with currency effect Change + 통화 효과로 변경 변경 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 63 + + + + From the beginning + 처음부터 + + apps/client/src/app/pages/public/public-page.html + 60 + + + + This year + 올해 + + apps/client/src/app/pages/public/public-page.html + 42 + + + + offers a free plan + 은(는) 무료 요금제를 제공합니다 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 256 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 273 + + + + does not offer a free plan + 은(는) 무료 요금제를 제공하지 않습니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 263 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 280 + + + + Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. + Ghostfolio는 개인이 주식, ETF 또는 암호화폐를 추적하고 확실한 데이터 기반 투자 결정을 내릴 수 있는 경량 자산 관리 애플리케이션입니다. + + apps/client/src/app/pages/about/overview/about-overview-page.html + 10 + + + + , assuming a + , 가정 + + apps/client/src/app/pages/portfolio/fire/fire-page.html + 174 + + + + to use our referral link and get a Ghostfolio Premium membership for one year + 추천 링크를 사용하고 1년 동안 Ghostfolio 프리미엄 멤버십을 얻으려면 + + apps/client/src/app/pages/pricing/pricing-page.html + 340 + + + + can be self-hosted + 은(는) 자체 호스팅 가능 + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 178 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 195 + + + + cannot be self-hosted + 은(는) 자체 호스팅할 수 없습니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 185 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 202 + + + + can be used anonymously + 은(는) 익명으로 사용할 수 있습니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 217 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 234 + + + + cannot be used anonymously + 은(는) 익명으로 사용할 수 없습니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 224 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 241 + + + + is not Open Source Software + 은(는) 오픈 소스 소프트웨어가 아닙니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 146 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 163 + + + + is Open Source Software + 은(는) 오픈 소스 소프트웨어입니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 139 + + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 156 + + + + This page has been archived. + 이 페이지는 보관되었습니다. + + apps/client/src/app/pages/resources/personal-finance-tools/product-page.html + 14 + + + + Oops! Invalid currency. + 이런! 통화가 잘못되었습니다. + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 48 + + + + Oops! Could not find any assets. + 이런! 자산을 찾을 수 없습니다. + + libs/ui/src/lib/symbol-autocomplete/symbol-autocomplete.component.html + 40 + + + + Ukraine + 우크라이나 + + libs/ui/src/lib/i18n.ts + 101 + + + + Set API key + API 키 설정 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 188 + + + + Get access to 80’000+ tickers from over 50 exchanges + 50개 이상의 거래소에서 80,000개 이상의 티커에 접근하세요 + + libs/ui/src/lib/i18n.ts + 26 + + + + Data Providers + 데이터 제공자 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 4 + + + + Join now + 지금 가입하세요 + + apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html + 193 + + + + Glossary + 용어집 + + apps/client/src/app/pages/resources/glossary/resources-glossary.component.html + 4 + + + apps/client/src/app/pages/resources/resources-page.component.ts + 44 + + + libs/common/src/lib/routes/routes.ts + 293 + + + + glossary + glossary + kebab-case + + libs/common/src/lib/routes/routes.ts + 288 + + + libs/common/src/lib/routes/routes.ts + 291 + + + + Guides + 가이드 + + apps/client/src/app/pages/resources/guides/resources-guides.component.html + 4 + + + apps/client/src/app/pages/resources/resources-page.component.ts + 33 + + + libs/common/src/lib/routes/routes.ts + 301 + + + + guides + guides + kebab-case + + libs/common/src/lib/routes/routes.ts + 296 + + + libs/common/src/lib/routes/routes.ts + 299 + + + + Threshold range + 임계값 범위 + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 9 + + + + Ghostfolio X-ray uses static analysis to uncover potential issues and risks in your portfolio. Adjust the rules below and set custom thresholds to align with your personal investment strategy. + Ghostfolio X-ray는 정적 분석을 사용하여 포트폴리오의 잠재적인 문제와 위험을 찾아냅니다. 아래 규칙을 조정하고 개인 투자 전략에 맞게 맞춤 임계값을 설정하세요. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 6 + + + + Please enter your Ghostfolio API key: + Ghostfolio API 키를 입력하세요: + + apps/client/src/app/pages/api/api-page.component.ts + 43 + + + + of + ~의 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 152 + + + + Do you really want to delete the API key? + API 키를 정말로 삭제하시겠습니까? + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 133 + + + + Remove API key + API 키 제거 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 178 + + + + daily requests + 일일 요청 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 154 + + + + Generate Ghostfolio Premium Data Provider API key for self-hosted environments... + 자체 호스팅 환경을 위한 Ghostfolio 프리미엄 데이터 공급자 API 키 생성... + + libs/ui/src/lib/membership-card/membership-card.component.html + 29 + + + + API Key + API 키 + + libs/ui/src/lib/membership-card/membership-card.component.html + 21 + + + + API Requests Today + 오늘의 API 요청 + + apps/client/src/app/components/admin-users/admin-users.html + 161 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 117 + + + + Could not generate an API key + API 키를 생성할 수 없습니다. + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 136 + + + + Do you really want to generate a new API key? + 정말로 새 API 키를 생성하시겠습니까? + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 159 + + + + Ghostfolio Premium Data Provider API Key + Ghostfolio 프리미엄 데이터 공급자 API 키 + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 154 + + + + Set this API key in your self-hosted environment: + 자체 호스팅 환경에서 이 API 키를 설정하세요. + + apps/client/src/app/components/user-account-membership/user-account-membership.component.ts + 151 + + + + rules align with your portfolio. + 규칙은 귀하의 포트폴리오와 일치합니다. + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 58 + + + + out of + 밖으로 + + apps/client/src/app/pages/portfolio/x-ray/x-ray-page.component.html + 56 + + + + Save + 구하다 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 610 + + + apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html + 68 + + + apps/client/src/app/components/admin-platform/create-or-update-platform-dialog/create-or-update-platform-dialog.html + 55 + + + apps/client/src/app/components/admin-tag/create-or-update-tag-dialog/create-or-update-tag-dialog.html + 38 + + + apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.html + 28 + + + apps/client/src/app/components/portfolio-summary/portfolio-summary.component.ts + 109 + + + apps/client/src/app/components/rule/rule-settings-dialog/rule-settings-dialog.html + 136 + + + apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html + 81 + + + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html + 116 + + + apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html + 352 + + + libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html + 49 + + + + Received Access + 수신된 액세스 + + apps/client/src/app/components/user-account-access/user-account-access.html + 53 + + + + Check the system status at + 시스템 상태를 확인하세요. + + apps/client/src/app/pages/about/overview/about-overview-page.html + 57 + + + + Me + + + apps/client/src/app/components/header/header.component.html + 213 + + + apps/client/src/app/components/user-account-access/user-account-access.component.ts + 260 + + + + Please enter your Ghostfolio API key. + Ghostfolio API 키를 입력하세요. + + apps/client/src/app/components/admin-settings/admin-settings.component.ts + 152 + + + + Change with currency effect + Change with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 + + + + AI prompt has been copied to the clipboard + AI 프롬프트가 클립보드에 복사되었습니다. + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 201 + + + + Link has been copied to the clipboard + 링크가 클립보드에 복사되었습니다. + + apps/client/src/app/components/access-table/access-table.component.ts + 99 + + + + Mode + 방법 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 521 + + + + Default Market Price + 기본 시장 가격 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 484 + + + + Selector + 선택자 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 537 + + + + Instant + 즉각적인 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 234 + + + + Lazy + 게으른 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 230 + + + + HTTP Request Headers + HTTP 요청 헤더 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 497 + + + + real-time + 실시간 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 234 + + + + end of day + 하루의 끝 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 230 + + + + Open Duck.ai + 오픈 Duck.ai + + apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts + 202 + + + + Create + 만들다 + + libs/ui/src/lib/tags-selector/tags-selector.component.html + 50 + + + + Change + 변화 + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 138 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 375 + + + + Performance + 성능 + + apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html + 6 + + + apps/client/src/app/components/home-overview/home-overview.component.ts + 55 + + + libs/ui/src/lib/holdings-table/holdings-table.component.html + 161 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 375 + + + libs/ui/src/lib/treemap-chart/treemap-chart.component.ts + 388 + + + + The project has been initiated by + 프로젝트는 다음에 의해 시작되었습니다. + + apps/client/src/app/pages/about/overview/about-overview-page.html + 40 + + + + Copy AI prompt to clipboard for analysis + 분석을 위해 AI 프롬프트를 클립보드에 복사 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 67 + + + + Singapore + 싱가포르 + + libs/ui/src/lib/i18n.ts + 97 + + + + Total amount + Total amount + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + + + Armenia + 아르메니아 + + libs/ui/src/lib/i18n.ts + 77 + + + + British Virgin Islands + 영국령 버진아일랜드 + + libs/ui/src/lib/i18n.ts + 82 + + + + Copy portfolio data to clipboard for AI prompt + AI 프롬프트를 위해 포트폴리오 데이터를 클립보드에 복사 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 42 + + + + I understand that if I lose my security token, I cannot recover my account + 보안 토큰을 분실하면 계정을 복구할 수 없다는 점을 이해합니다. + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 28 + + + + Please keep your security token safe. If you lose it, you will not be able to recover your account. + 보안 토큰을 안전하게 보관하세요. 분실한 경우 계정을 복구할 수 없습니다. + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 18 + + + + Here is your security token. It is only visible once, please store and keep it in a safe place. + 여기 보안 토큰이 있습니다. 한 번만 볼 수 있으므로 안전한 곳에 보관하여 보관하시기 바랍니다. + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 67 + + + + Continue + 계속하다 + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 57 + + + + Terms and Conditions + 이용약관 + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 15 + + + + Do you really want to generate a new security token for this user? + 정말로 이 사용자에 대한 새 보안 토큰을 생성하시겠습니까? + + apps/client/src/app/components/admin-users/admin-users.component.ts + 244 + + + + Find account, holding or page... + 계정, 보유 또는 페이지 찾기... + + libs/ui/src/lib/assistant/assistant.component.ts + 115 + + + + Security token + 보안 토큰 + + apps/client/src/app/components/admin-users/admin-users.component.ts + 239 + + + apps/client/src/app/components/user-account-access/user-account-access.component.ts + 170 + + + + Generate Security Token + 보안 토큰 생성 + + apps/client/src/app/components/admin-users/admin-users.html + 243 + + + + United Kingdom + 영국 + + libs/ui/src/lib/i18n.ts + 102 + + + + Terms of Service + 이용약관 + + apps/client/src/app/components/footer/footer.component.html + 62 + + + libs/common/src/lib/routes/routes.ts + 217 + + + + terms-of-service + terms-of-service + kebab-case + + libs/common/src/lib/routes/routes.ts + 212 + + + libs/common/src/lib/routes/routes.ts + 215 + + + + Terms of Service + 이용약관 + + apps/client/src/app/pages/about/terms-of-service/terms-of-service-page.html + 5 + + + + and I agree to the Terms of Service. + 서비스 약관에 동의합니다. + + apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html + 34 + + + + () is already in use. + ()은(는) 이미 사용 중입니다. + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 649 + + + + An error occurred while updating to (). + ()로 업데이트하는 동안 오류가 발생했습니다. + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 657 + + + + Apply + 적용하다 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html + 154 + + + + with API access for + 다음에 대한 API 액세스 권한이 있는 + + apps/client/src/app/pages/pricing/pricing-page.html + 235 + + + + Data Gathering is off + 데이터 수집이 사용 중지되었습니다. + + apps/client/src/app/components/admin-market-data/admin-market-data.html + 38 + + + + Performance Calculation + 성능 계산 + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 31 + + + + someone + 누구 + + apps/client/src/app/pages/public/public-page.component.ts + 59 + + + + Add asset to watchlist + 관심 목록에 자산 추가 + + apps/client/src/app/components/home-watchlist/create-watchlist-item-dialog/create-watchlist-item-dialog.html + 7 + + + + Watchlist + 관심 목록 + + apps/client/src/app/components/home-watchlist/home-watchlist.html + 4 + + + apps/client/src/app/pages/features/features-page.html + 197 + + + libs/common/src/lib/routes/routes.ts + 110 + + + + Do you really want to delete this item? + 이 항목을 정말로 삭제하시겠습니까? + + libs/ui/src/lib/benchmark/benchmark.component.ts + 144 + + + + Log out + 로그아웃 + + apps/client/src/app/components/header/header.component.html + 329 + + + + Calculations are based on delayed market data and may not be displayed in real-time. + 계산은 지연된 시장 데이터를 기반으로 하며 실시간으로 표시되지 않을 수 있습니다. + + apps/client/src/app/components/home-market/home-market.html + 45 + + + apps/client/src/app/components/markets/markets.html + 54 + + + + changelog + changelog + kebab-case + + libs/common/src/lib/routes/routes.ts + 180 + + + libs/common/src/lib/routes/routes.ts + 183 + + + + Sync Demo User Account + 데모 사용자 계정 동기화 + + apps/client/src/app/components/admin-overview/admin-overview.html + 195 + + + + Demo user account has been synced. + 데모 사용자 계정이 동기화되었습니다. + + apps/client/src/app/components/admin-overview/admin-overview.component.ts + 274 + + + + Set up + 설정 + + apps/client/src/app/pages/i18n/i18n-page.html + 145 + + + + No emergency fund has been set up + 비상금은 마련되지 않았습니다 + + apps/client/src/app/pages/i18n/i18n-page.html + 147 + + + + An emergency fund has been set up + 비상금이 마련됐어요 + + apps/client/src/app/pages/i18n/i18n-page.html + 150 + + + + Fee Ratio + Fee Ratio + + apps/client/src/app/pages/i18n/i18n-page.html + 152 + + + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + + apps/client/src/app/pages/i18n/i18n-page.html + 154 + + + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + + apps/client/src/app/pages/i18n/i18n-page.html + 158 + + + + Quick Links + 빠른 링크 + + libs/ui/src/lib/assistant/assistant.html + 58 + + + + Live Demo + 라이브 데모 + + apps/client/src/app/pages/landing/landing-page.html + 48 + + + apps/client/src/app/pages/landing/landing-page.html + 349 + + + libs/common/src/lib/routes/routes.ts + 231 + + + + Open Source Alternative to + 오픈 소스 대안 + + libs/common/src/lib/routes/routes.ts + 326 + + + + Single Account + 단일 계정 + + apps/client/src/app/pages/i18n/i18n-page.html + 28 + + + + Your net worth is managed by a single account + 귀하의 순자산은 단일 계정으로 관리됩니다 + + apps/client/src/app/pages/i18n/i18n-page.html + 30 + + + + Your net worth is managed by ${accountsLength} accounts + 귀하의 순자산은 ${accountsLength} 계정에서 관리됩니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 36 + + + + personal-finance-tools + personal-finance-tools + kebab-case + + libs/common/src/lib/routes/routes.ts + 312 + + + libs/common/src/lib/routes/routes.ts + 315 + + + libs/common/src/lib/routes/routes.ts + 323 + + + + markets + markets + kebab-case + + libs/common/src/lib/routes/routes.ts + 304 + + + libs/common/src/lib/routes/routes.ts + 307 + + + + Get Access + 액세스 권한 얻기 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 27 + + + + Fuel your self-hosted Ghostfolio with a powerful data provider to access 80,000+ tickers from over 50 exchanges worldwide. + 자체 호스팅 Ghostfolio강력한 데이터 제공업체와 함께 활용하여 전 세계 50개 이상의 거래소에서 80,000개 이상의 시세에 액세스하세요. + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 16 + + + + Learn more + 자세히 알아보기 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 38 + + + + Limited Offer! + 한정 상품! + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 41 + + + apps/client/src/app/pages/pricing/pricing-page.html + 294 + + + + Get extra + 추가 구매 + + apps/client/src/app/components/user-account-membership/user-account-membership.html + 44 + + + apps/client/src/app/pages/pricing/pricing-page.html + 297 + + + + Unavailable + 없는 + + apps/client/src/app/components/data-provider-status/data-provider-status.component.html + 5 + + + + Available + 사용 가능 + + apps/client/src/app/components/data-provider-status/data-provider-status.component.html + 3 + + + + Current month + 이번 달 + + apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts + 200 + + + + new + 새로운 + + apps/client/src/app/components/admin-settings/admin-settings.component.html + 79 + + + apps/client/src/app/pages/admin/admin-page.component.ts + 53 + + + + Investment + 투자 + + apps/client/src/app/pages/i18n/i18n-page.html + 15 + + + + Over ${thresholdMax}% of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) + 현재 투자의 ${thresholdMax}% 이상이 ${maxAccountName} (${maxInvestmentRatio}%)에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 17 + + + + The major part of your current investment is at ${maxAccountName} (${maxInvestmentRatio}%) and does not exceed ${thresholdMax}% + 현재 투자의 주요 부분은 ${maxAccountName} (${maxInvestmentRatio}%)이며 ${thresholdMax}%를 초과하지 않습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 24 + + + + Equity + 주식 + + apps/client/src/app/pages/i18n/i18n-page.html + 41 + + + + The equity contribution of your current investment (${equityValueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 지분 기여도(${equityValueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 43 + + + + The equity contribution of your current investment (${equityValueRatio}%) is below ${thresholdMin}% + 현재 투자의 지분 기여도(${equityValueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 47 + + + + The equity contribution of your current investment (${equityValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 지분 기여도(${equityValueRatio}%)가 ${thresholdMin}% 및 ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 51 + + + + Fixed Income + 채권 + + apps/client/src/app/pages/i18n/i18n-page.html + 55 + + + + The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 고정 수입 기여도(${fixedIncomeValueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 57 + + + + The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is below ${thresholdMin}% + 현재 투자의 고정 수입 기여도(${fixedIncomeValueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 61 + + + + The fixed income contribution of your current investment (${fixedIncomeValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 고정 수입 기여도(${fixedIncomeValueRatio}%)가 ${thresholdMin}% ~ ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 66 + + + + Investment: Base Currency + 투자: 기본 통화 + + apps/client/src/app/pages/i18n/i18n-page.html + 85 + + + + The major part of your current investment is not in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) + 현재 투자의 주요 부분이 기본 통화(${baseCurrency}의 ${baseCurrencyValueRatio}%)로 되어 있지 않습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 88 + + + + The major part of your current investment is in your base currency (${baseCurrencyValueRatio}% in ${baseCurrency}) + 현재 투자의 주요 부분은 기본 통화(${baseCurrency}의 ${baseCurrencyValueRatio}%)입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 92 + + + + Investment + 투자 + + apps/client/src/app/pages/i18n/i18n-page.html + 95 + + + + Over ${thresholdMax}% of your current investment is in ${currency} (${maxValueRatio}%) + 현재 투자의 ${thresholdMax}% 이상이 ${currency}(${maxValueRatio}%)에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 97 + + + + The major part of your current investment is in ${currency} (${maxValueRatio}%) and does not exceed ${thresholdMax}% + 현재 투자의 주요 부분은 ${currency} (${maxValueRatio}%)이며 ${thresholdMax}%를 초과하지 않습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 101 + + + + start + start + kebab-case + + libs/common/src/lib/routes/routes.ts + 336 + + + libs/common/src/lib/routes/routes.ts + 337 + + + + Generate + 생성하다 + + apps/client/src/app/components/user-account-access/user-account-access.html + 43 + + + + If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ + 버그가 발생하거나 개선 사항이나 새로운 기능을 제안하고 싶다면 Ghostfolio 슬랙 커뮤니티에 가입하고 @ghostfolio_에 게시하세요. + + apps/client/src/app/pages/about/overview/about-overview-page.html + 69 + + + + Do you really want to generate a new security token? + 정말로 새로운 보안 토큰을 생성하시겠습니까? + + apps/client/src/app/components/user-account-access/user-account-access.component.ts + 175 + + + + Cryptocurrencies + 암호화폐 + + apps/client/src/app/components/markets/markets.component.ts + 53 + + + apps/client/src/app/pages/features/features-page.html + 51 + + + + Stocks + 주식 + + apps/client/src/app/components/markets/markets.component.ts + 52 + + + apps/client/src/app/pages/features/features-page.html + 15 + + + + + + + apps/client/src/app/components/admin-users/admin-users.html + 39 + + + + Manage Asset Profile + 자산 프로필 관리 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 465 + + + + Alternative Investment + 대체투자 + + libs/ui/src/lib/i18n.ts + 46 + + + + Collectible + 소장용 + + libs/ui/src/lib/i18n.ts + 56 + + + + Average Unit Price + 평균단가 + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.component.ts + 113 + + + apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html + 101 + + + + No results found... + 검색된 결과가 없습니다... + + libs/ui/src/lib/assistant/assistant.html + 51 + + + + Account Cluster Risks + 계정 클러스터 위험 + + apps/client/src/app/pages/i18n/i18n-page.html + 14 + + + + Asset Class Cluster Risks + 자산 클래스 클러스터 위험 + + apps/client/src/app/pages/i18n/i18n-page.html + 39 + + + + Currency Cluster Risks + 통화 클러스터 위험 + + apps/client/src/app/pages/i18n/i18n-page.html + 83 + + + + Economic Market Cluster Risks + 경제 시장 클러스터 위험 + + apps/client/src/app/pages/i18n/i18n-page.html + 106 + + + + Emergency Fund + 비상자금 + + apps/client/src/app/pages/i18n/i18n-page.html + 144 + + + + Fees + 수수료 + + apps/client/src/app/pages/i18n/i18n-page.html + 161 + + + + Liquidity + 유동성 + + apps/client/src/app/pages/i18n/i18n-page.html + 70 + + + + Buying Power + 매수 가능 금액 + + apps/client/src/app/pages/i18n/i18n-page.html + 71 + + + + Your buying power is below ${thresholdMin} ${baseCurrency} + 귀하의 구매력은 ${thresholdMin} ${baseCurrency} 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 73 + + + + Your buying power is 0 ${baseCurrency} + 귀하의 구매력은 0입니다 ${baseCurrency} + + apps/client/src/app/pages/i18n/i18n-page.html + 77 + + + + Your buying power exceeds ${thresholdMin} ${baseCurrency} + 매수 가능 금액이 ${thresholdMin} ${baseCurrency}을(를) 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 80 + + + + Regional Market Cluster Risks + 지역 시장 클러스터 위험 + + apps/client/src/app/pages/i18n/i18n-page.html + 163 + + + + Developed Markets + 선진시장 + + apps/client/src/app/pages/i18n/i18n-page.html + 109 + + + + The developed markets contribution of your current investment (${developedMarketsValueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 선진국 시장 기여도(${개발된MarketsValueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 112 + + + + The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is below ${thresholdMin}% + 현재 투자의 선진국 시장 기여도(${개발된MarketsValueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 117 + + + + The developed markets contribution of your current investment (${developedMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 선진국 시장 기여도(${개발된MarketsValueRatio}%)는 ${thresholdMin}% 및 ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 122 + + + + Emerging Markets + 신흥시장 + + apps/client/src/app/pages/i18n/i18n-page.html + 127 + + + + The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 신흥 시장 기여도(${emergingMarketsValueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 130 + + + + The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is below ${thresholdMin}% + 현재 투자의 신흥 시장 기여도(${emergingMarketsValueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 135 + + + + The emerging markets contribution of your current investment (${emergingMarketsValueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 신흥 시장 기여도(${emergingMarketsValueRatio}%)가 ${thresholdMin}% 및 ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 140 + + + + No accounts have been set up + 설정된 계정이 없습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 21 + + + + Your net worth is managed by 0 accounts + 귀하의 순자산은 0개의 계정에서 관리됩니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 33 + + + + Asia-Pacific + 아시아·태평양 + + apps/client/src/app/pages/i18n/i18n-page.html + 165 + + + + The Asia-Pacific market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 아시아 태평양 시장 기여도(${valueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 167 + + + + The Asia-Pacific market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + 현재 투자의 아시아 태평양 시장 기여도(${valueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 171 + + + + The Asia-Pacific market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 아시아 태평양 시장 기여도(${valueRatio}%)가 ${thresholdMin}% 및 ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 175 + + + + Emerging Markets + 신흥시장 + + apps/client/src/app/pages/i18n/i18n-page.html + 180 + + + + The Emerging Markets contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 신흥 시장 기여도(${valueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 183 + + + + The Emerging Markets contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + 현재 투자의 신흥 시장 기여도(${valueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 187 + + + + The Emerging Markets contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 신흥 시장 기여도(${valueRatio}%)가 ${thresholdMin}% 및 ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 191 + + + + Europe + 유럽 + + apps/client/src/app/pages/i18n/i18n-page.html + 195 + + + + The Europe market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 유럽 시장 기여도(${valueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 197 + + + + The Europe market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + 현재 투자의 유럽 시장 기여도(${valueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 201 + + + + The Europe market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 유럽 시장 기여도(${valueRatio}%)는 ${thresholdMin}% 및 ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 205 + + + + Japan + 일본 + + apps/client/src/app/pages/i18n/i18n-page.html + 209 + + + + The Japan market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 일본 시장 기여도(${valueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 211 + + + + The Japan market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + 현재 투자의 일본 시장 기여도(${valueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 215 + + + + The Japan market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 일본 시장 기여도(${valueRatio}%)는 ${thresholdMin}% 및 ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 219 + + + + North America + 북미 + + apps/client/src/app/pages/i18n/i18n-page.html + 223 + + + + The North America market contribution of your current investment (${valueRatio}%) exceeds ${thresholdMax}% + 현재 투자의 북미 시장 기여도(${valueRatio}%)가 ${thresholdMax}%를 초과합니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 225 + + + + The North America market contribution of your current investment (${valueRatio}%) is below ${thresholdMin}% + 현재 투자의 북미 시장 기여도(${valueRatio}%)가 ${thresholdMin}% 미만입니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 229 + + + + The North America market contribution of your current investment (${valueRatio}%) is within the range of ${thresholdMin}% and ${thresholdMax}% + 현재 투자의 북미 시장 기여도(${valueRatio}%)가 ${thresholdMin}% 및 ${thresholdMax}% 범위 내에 있습니다. + + apps/client/src/app/pages/i18n/i18n-page.html + 233 + + + + Support Ghostfolio + 고스트폴리오 지원 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 166 + + + + Find Ghostfolio on GitHub + 깃허브에서 Ghostfolio 찾기 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 99 + + + apps/client/src/app/pages/about/overview/about-overview-page.html + 138 + + + + Ghostfolio is an independent & bootstrapped business + Ghostfolio는 독립적이고 부트스트랩된 사업입니다. + + apps/client/src/app/pages/about/overview/about-overview-page.html + 157 + + + + Send an e-mail + 이메일 보내기 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 89 + + + apps/client/src/app/pages/about/overview/about-overview-page.html + 128 + + + + Registration Date + 등록일 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 45 + + + + Join the Ghostfolio Slack community + Ghostfolio 슬랙 커뮤니티에 참여하세요 + + apps/client/src/app/pages/about/overview/about-overview-page.html + 109 + + + + Follow Ghostfolio on LinkedIn + LinkedIn에서 Ghostfolio를 팔로우하세요. + + apps/client/src/app/pages/about/overview/about-overview-page.html + 147 + + + + Follow Ghostfolio on X (formerly Twitter) + X(이전의 Twitter)에서 Ghostfolio를 팔로우하세요. + + apps/client/src/app/pages/about/overview/about-overview-page.html + 118 + + + + + diff --git a/apps/client/src/locales/messages.nl.xlf b/apps/client/src/locales/messages.nl.xlf index c34f259bc..fbd87961c 100644 --- a/apps/client/src/locales/messages.nl.xlf +++ b/apps/client/src/locales/messages.nl.xlf @@ -26,7 +26,7 @@ Het risico op verlies bij handelen kan aanzienlijk zijn. Het is niet aan te raden om geld te investeren dat je misschien op korte termijn nodig heeft. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -39,10 +39,10 @@ please - please + alsjeblieft apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -83,20 +83,12 @@ with - with + met apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Wil je deze verleende toegang echt intrekken? @@ -114,7 +106,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -126,7 +118,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -142,11 +134,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -158,7 +150,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -174,7 +166,7 @@ Totaal libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -186,15 +178,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -202,11 +194,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -218,7 +210,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -242,15 +234,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -274,11 +266,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -286,7 +282,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -302,7 +298,7 @@ Wil je deze rekening echt verwijderen? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -330,7 +326,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -370,12 +366,12 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 and is driven by the efforts of its contributors - and is driven by the efforts of its contributors + en wordt gedreven door de inspanningen van zijn bijdragers apps/client/src/app/pages/about/overview/about-overview-page.html 49 @@ -386,7 +382,7 @@ Activa Profiel apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -402,7 +398,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -442,7 +438,7 @@ Datum apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -490,7 +486,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -510,7 +506,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -518,7 +514,7 @@ Wil je deze coupon echt verwijderen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -526,7 +522,7 @@ Wil je echt de cache legen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -534,7 +530,7 @@ Stel je systeemboodschap in: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -638,7 +634,7 @@ Wilt je deze gebruiker echt verwijderen? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -659,7 +655,7 @@ No auto-renewal on membership. - No auto-renewal on membership. + Het lidmaatschap wordt niet automatisch verlengd. apps/client/src/app/components/user-account-membership/user-account-membership.html 74 @@ -674,7 +670,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -714,7 +710,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -726,11 +722,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -774,7 +770,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -782,7 +778,7 @@ Activiteiten beheren apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -814,7 +810,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -858,7 +854,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -898,7 +894,7 @@ Absoluut bruto rendement apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -906,11 +902,11 @@ Absoluut netto rendement apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -918,11 +914,11 @@ Netto rendement apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -930,7 +926,7 @@ Totaal Activa apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -938,7 +934,7 @@ Koopkracht apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -946,7 +942,7 @@ Netto waarde apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -954,7 +950,7 @@ Rendement per jaar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -974,7 +970,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -982,7 +978,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -994,7 +990,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1006,7 +1002,7 @@ Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1022,7 +1018,7 @@ Gegevensstoring melden apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1030,11 +1026,11 @@ Allocatie libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -1050,7 +1046,7 @@ Toon alle libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -1062,7 +1058,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -1070,11 +1066,11 @@ YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -1082,11 +1078,11 @@ 1J apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -1094,11 +1090,19 @@ 5J apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Prestaties met valuta-effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -1106,11 +1110,11 @@ Max apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -1218,7 +1222,7 @@ Wil je deze aanmeldingsmethode echt verwijderen? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -1238,7 +1242,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1262,7 +1266,7 @@ Presentatie weergave apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -1278,11 +1282,11 @@ Locatie apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -1290,7 +1294,7 @@ Datum- en getalnotatie apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -1298,7 +1302,7 @@ Zen-modus apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -1310,7 +1314,7 @@ Aanmelden met vingerafdruk apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -1322,11 +1326,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1378,7 +1382,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1418,7 +1422,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -1430,11 +1434,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1454,7 +1458,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -1470,7 +1474,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -1610,7 +1614,7 @@ Aangezien je al ingelogd bent, heb je geen toegang tot de demo-account. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1674,11 +1678,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1694,7 +1698,7 @@ Markten apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1718,7 +1722,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -1818,7 +1822,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -1838,7 +1842,7 @@ Tijdlijn investeringen apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -1846,7 +1850,7 @@ Winnaars apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -1854,7 +1858,7 @@ Verliezers apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -1911,10 +1915,10 @@ Current week - Current week + Huidige week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1958,7 +1962,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1970,7 +1974,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1978,7 +1982,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1986,7 +1990,7 @@ Prijs per eenheid apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1998,7 +2002,7 @@ Opmerking apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2006,7 +2010,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2018,7 +2022,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2042,7 +2046,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2054,7 +2058,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -2075,7 +2079,7 @@ or start a discussion at - or start a discussion at + of start een discussie op apps/client/src/app/pages/about/overview/about-overview-page.html 94 @@ -2130,7 +2134,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -2142,12 +2146,12 @@ Continenten apps/client/src/app/pages/public/public-page.html - 132 + 131 Sustainable retirement income - Sustainable retirement income + Duurzaam pensioeninkomen apps/client/src/app/pages/portfolio/fire/fire-page.html 41 @@ -2158,7 +2162,7 @@ Ghostfolio stelt je in staat om je vermogen bij te houden. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2306,7 +2310,7 @@ Wil je deze activiteit echt verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2319,10 +2323,10 @@ contact us - contact us + contacteer ons apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2395,7 +2399,7 @@ Exclude from Analysis - Exclude from Analysis + Uitsluiten van analyse apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 90 @@ -2414,15 +2418,15 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 Latest activities - Latest activities + Laatste activiteiten apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2442,7 +2446,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2454,7 +2458,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2486,7 +2490,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -2510,7 +2514,7 @@ Besparingen libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -2522,11 +2526,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -2535,7 +2539,7 @@ annual interest rate - annual interest rate + jaarlijkse rente apps/client/src/app/pages/portfolio/fire/fire-page.html 185 @@ -2546,7 +2550,7 @@ Storting libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -2554,7 +2558,7 @@ Maandelijks apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -2610,7 +2614,7 @@ Filter op... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -2638,7 +2642,7 @@ Experimentele functies apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -2646,7 +2650,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -2655,14 +2659,14 @@ Could not validate form - Could not validate form + Het formulier kon niet worden gevalideerd. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -2686,7 +2690,7 @@ Uitgesloten van analyse apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2698,7 +2702,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -2706,7 +2710,7 @@ Weergave apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -2714,7 +2718,7 @@ Licht apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -2722,7 +2726,7 @@ Donker apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -2730,7 +2734,7 @@ Totaalbedrag apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2738,7 +2742,7 @@ Waardeontwikkeling van portefeuille apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -2782,7 +2786,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2790,7 +2794,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2846,7 +2850,7 @@ Contant geld apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2891,10 +2895,10 @@ Authentication - Authentication + Authenticatie apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -2958,7 +2962,7 @@ Noodfonds apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2978,7 +2982,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -2990,7 +2994,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -2998,11 +3002,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3043,7 +3047,7 @@ If you retire today, you would be able to withdraw - If you retire today, you would be able to withdraw + Als u vandaag met pensioen gaat, kunt u apps/client/src/app/pages/portfolio/fire/fire-page.html 68 @@ -3106,15 +3110,15 @@ Symbool toewijzen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 Looking for a student discount? - Looking for a student discount? + Op zoek naar studentenkorting? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3130,7 +3134,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3138,11 +3142,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -3154,7 +3158,7 @@ Tijdlijn dividend apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -3170,7 +3174,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3178,7 +3182,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3214,7 +3218,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3222,7 +3226,7 @@ Marktgegevens apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -3274,7 +3278,7 @@ Jaarlijks apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -3298,7 +3302,7 @@ Geldig tot apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3337,6 +3341,14 @@ 22 + + No Activities + Geen activiteiten + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Pensioen @@ -3345,6 +3357,14 @@ 28 + + Everything in Basic, plus + Alles van Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satelliet @@ -3358,7 +3378,7 @@ Bescherming voor gevoelige informatie zoals absoluut rendement en hoeveelheden apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -3366,7 +3386,7 @@ Afleidingsvrije ervaring voor roerige tijden apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -3374,7 +3394,7 @@ Voorproefje van nieuwe functionaliteit apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -3398,7 +3418,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3414,7 +3434,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3430,7 +3450,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3446,7 +3466,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3494,7 +3514,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3578,7 +3598,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3594,19 +3614,19 @@ Eenmalige betaling, geen automatische verlenging. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 Could not save asset profile - Could not save asset profile + Kon het assetprofiel niet opslaan apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -3614,7 +3634,7 @@ Het is gratis. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3626,7 +3646,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3646,7 +3666,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3690,7 +3710,7 @@ Ondersteuning via e-mail en chat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3734,7 +3754,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3758,7 +3778,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3790,7 +3810,7 @@ Weet je zeker dat je alle activiteiten wilt verwijderen? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3801,9 +3821,17 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By - By + Tegen apps/client/src/app/pages/portfolio/fire/fire-page.html 139 @@ -3819,10 +3847,10 @@ Current year - Current year + Huidig jaar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -3838,11 +3866,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3855,10 +3883,10 @@ Asset profile has been saved - Asset profile has been saved + Het activaprofiel is opgeslagen. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -3866,7 +3894,7 @@ Wil je dit platform echt verwijderen? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 @@ -3874,7 +3902,7 @@ Platforms apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3882,7 +3910,7 @@ Saldo bijwerken apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4002,7 +4030,7 @@ Huidige reeks apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4010,7 +4038,7 @@ Langste reeks apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4047,14 +4075,14 @@ View Details - View Details + Bekijk details apps/client/src/app/components/admin-users/admin-users.html 225 libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -4062,7 +4090,7 @@ Verplichtingen apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4183,7 +4211,7 @@ per week - per week + per week apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 130 @@ -4194,7 +4222,7 @@ Open Source Software apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -4207,7 +4235,7 @@ and we share aggregated key metrics of the platform’s performance - and we share aggregated key metrics of the platform’s performance + en we delen geaggregeerde belangrijke prestatiegegevens van het platform apps/client/src/app/pages/about/overview/about-overview-page.html 32 @@ -4218,7 +4246,7 @@ Scraper instellingen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4251,7 +4279,7 @@ Website of Thomas Kaul - Website of Thomas Kaul + Website van Thomas Kaul apps/client/src/app/pages/about/overview/about-overview-page.html 44 @@ -4431,7 +4459,7 @@ Sign in with OpenID Connect - Sign in with OpenID Connect + Meld je aan met OpenID Connect apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 55 @@ -4457,20 +4485,12 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETF’s zonder Landen apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -4478,7 +4498,7 @@ ETF’s zonder Sectoren apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -4486,7 +4506,7 @@ Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4531,7 +4551,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - The source code is fully available as open source software (OSS) under the AGPL-3.0 license + De broncode is volledig beschikbaar als open source software (OSS) onder de AGPL-3.0-licentie apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -4603,7 +4623,7 @@ this is projected to increase to - this is projected to increase to + zal dit naar verwachting stijgen tot apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -4614,7 +4634,7 @@ Biometrische authenticatie apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -4655,7 +4675,7 @@ Job ID - Job ID + Opdracht ID apps/client/src/app/components/admin-jobs/admin-jobs.html 34 @@ -4706,7 +4726,7 @@ Exporteer Data apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -4714,11 +4734,11 @@ Valuta apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4739,7 +4759,7 @@ for - for + voor apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 128 @@ -4763,14 +4783,14 @@ Could not parse scraper configuration - Could not parse scraper configuration + De scraperconfiguratie kon niet worden geparseerd apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -4807,7 +4827,7 @@ Edit access - Edit access + Toegang bewerken apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 11 @@ -4879,7 +4899,7 @@ Get access to 80’000+ tickers from over 50 exchanges - Get access to 80’000+ tickers from over 50 exchanges + Krijg toegang tot meer dan 80.000+ tickers van meer dan 50 beurzen apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 84 @@ -5063,7 +5083,7 @@ less than - less than + minder dan apps/client/src/app/components/subscription-interstitial-dialog/subscription-interstitial-dialog.html 129 @@ -5324,7 +5344,7 @@ Zwitserland apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -5336,7 +5356,7 @@ Wereldwijd apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -5353,7 +5373,7 @@ Ghostfolio Status - Ghostfolio Status + Ghostfolio Status apps/client/src/app/pages/about/overview/about-overview-page.html 62 @@ -5361,10 +5381,10 @@ with your university e-mail address - with your university e-mail address + met uw universitaire e-mailadres apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5381,7 +5401,7 @@ and a safe withdrawal rate (SWR) of - and a safe withdrawal rate (SWR) of + en een veilige opnameratio (SWR) van apps/client/src/app/pages/portfolio/fire/fire-page.html 108 @@ -5432,7 +5452,7 @@ Kosten apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5464,7 +5484,7 @@ Weet u zetker dat u dit label wilt verwijderen? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -5532,7 +5552,7 @@ Lidmaatschap apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5545,10 +5565,10 @@ Request it - Request it + Aanvragen apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5601,7 +5621,7 @@ , - , + , apps/client/src/app/pages/portfolio/fire/fire-page.html 145 @@ -5617,7 +5637,7 @@ per month - per month + per maand apps/client/src/app/pages/portfolio/fire/fire-page.html 94 @@ -5688,7 +5708,7 @@ Oeps! Ophalen van historische data is mislukt. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -5696,7 +5716,7 @@ Wilt u dit systeembericht echt verwijderen? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -5720,7 +5740,7 @@ Contant Saldo apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5760,7 @@ Wilt u dit rekeningsaldo echt verwijderen? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5776,7 @@ De huidige markt waarde is apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5764,7 +5784,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5809,7 +5829,7 @@ Argentina - Argentina + Argentinië libs/ui/src/lib/i18n.ts 78 @@ -5852,31 +5872,31 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 here - here + hier apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 Close Holding - Close Holding + Sluit Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5884,7 +5904,7 @@ Absolute Activaprestaties apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5892,7 +5912,7 @@ Activaprestaties apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5900,7 +5920,7 @@ Absolute Valutaprestaties apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5908,7 +5928,7 @@ Valutaprestaties apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5916,7 +5936,7 @@ Week tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5924,11 +5944,11 @@ Week tot nu toe apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5936,7 +5956,7 @@ Maand tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5944,11 +5964,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5956,7 +5976,7 @@ Jaar tot nu toe libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5992,7 +6012,7 @@ jaar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6024,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6012,11 +6032,11 @@ jaren apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6032,7 +6052,7 @@ Data Verzamelen apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6064,7 @@ Algemeen apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6072,7 @@ Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6084,7 @@ Zelf Hosten apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6209,7 +6229,7 @@ Wilt u uw Ghostfolio account echt sluiten? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6217,7 +6237,7 @@ Gevarenzone apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6225,7 +6245,7 @@ Account Sluiten apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6254,10 +6274,10 @@ Include in - Include in + Opnemen in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6285,7 @@ Oeps! Er is een fout opgetreden met het instellen van de biometrische authenticatie. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6281,7 +6301,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6329,7 +6349,7 @@ Wilt u uw persoonlijke belegginngsstrategie verfijnen? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6337,7 +6357,7 @@ Alternatief apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6345,7 +6365,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6353,7 +6373,7 @@ Budgetteren apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6369,47 +6389,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6417,7 +6441,7 @@ Familiekantoor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6425,7 +6449,7 @@ Investeerder apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6437,7 +6461,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6449,7 +6473,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6457,7 +6481,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6465,7 +6489,7 @@ Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6473,7 +6497,7 @@ Hulpmiddel apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6481,7 +6505,7 @@ Gebruikers Ervaring apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6489,7 +6513,7 @@ Vermogen apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6497,7 +6521,7 @@ Vermogensbeheer apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6534,7 +6558,7 @@ View Holding - View Holding + Bekijk Holding libs/ui/src/lib/activities-table/activities-table.component.html 450 @@ -6657,7 +6681,7 @@ Fout apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6678,7 +6702,7 @@ Oops! Could not update access. - Oops! Could not update access. + Oops! Kan de toegang niet updaten. apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.component.ts 178 @@ -6686,7 +6710,7 @@ , based on your total assets of - , based on your total assets of + opnemen, dit is gebaseerd op uw totale vermogen van apps/client/src/app/pages/portfolio/fire/fire-page.html 96 @@ -6709,7 +6733,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6741,7 +6765,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6749,7 +6773,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6761,7 +6785,7 @@ Sluiten apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6787,13 +6811,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6802,10 +6830,10 @@ Role - Role + Rol apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6842,10 +6870,10 @@ If you plan to open an account at - If you plan to open an account at + Als u van plan bent een rekening te openen bij apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6874,7 +6902,7 @@ send an e-mail to - send an e-mail to + stuur een e-mail naar apps/client/src/app/pages/about/overview/about-overview-page.html 87 @@ -6946,7 +6974,7 @@ , assuming a - , assuming a + , uitgaande van apps/client/src/app/pages/portfolio/fire/fire-page.html 174 @@ -6957,7 +6985,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7034,7 +7062,7 @@ Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. - Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. + Ghostfolio is een gebruiksvriendelijke applicatie voor vermogensbeheer waarmee particulieren hun aandelen, ETF's of cryptovaluta kunnen volgen en weloverwogen, datagestuurde beleggingsbeslissingen kunnen nemen. apps/client/src/app/pages/about/overview/about-overview-page.html 10 @@ -7061,7 +7089,7 @@ API-sleutel instellen apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7097,7 +7125,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7113,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7167,7 +7195,7 @@ van apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7175,7 +7203,7 @@ dagelijkse verzoeken apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7183,7 +7211,7 @@ Verwijder API-sleutel apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7191,7 +7219,7 @@ Wilt u de API-sleutel echt verwijderen? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7211,7 +7239,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7283,7 +7311,7 @@ Opslaan apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7319,11 +7347,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7359,7 +7387,15 @@ Voer uw Ghostfolio API-sleutel in. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Verandering met valuta-effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7367,7 +7403,7 @@ AI-prompt is naar het klembord gekopieerd apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7383,7 +7419,7 @@ Lui apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7391,7 +7427,7 @@ Direct apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7399,7 +7435,7 @@ Standaard Marktprijs apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7407,7 +7443,7 @@ Modus apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7415,7 +7451,7 @@ Kiezer apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7423,7 +7459,7 @@ HTTP Verzoek Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7431,7 +7467,7 @@ eind van de dag apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7439,7 +7475,7 @@ real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7447,7 +7483,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7463,11 +7499,11 @@ Aanpassen libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7483,20 +7519,20 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 The project has been initiated by - The project has been initiated by + Het project is geïnitieerd door apps/client/src/app/pages/about/overview/about-overview-page.html 40 @@ -7518,6 +7554,14 @@ 67 + + Total amount + Totaal bedrag + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Armenië @@ -7587,7 +7631,7 @@ Beveiligingstoken apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7599,15 +7643,15 @@ Wilt u echt een nieuw beveiligingstoken voor deze gebruiker aanmaken? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 Find account, holding or page... - Find account, holding or page... + Vindt een account, holding of pagina... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7672,7 +7716,7 @@ () is al in gebruik. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7680,7 +7724,7 @@ Er is een fout opgetreden tijdens het updaten naar (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7696,7 +7740,7 @@ met API toegang tot apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7776,7 +7820,7 @@ Wilt u dit item echt verwijderen? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7817,7 +7861,7 @@ Demo-gebruikersaccount is gesynchroniseerd. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7852,7 +7896,7 @@ 150 - + Fee Ratio Vergoedingsverhouding @@ -7860,17 +7904,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - De kosten overschrijden ${thresholdMax}% van uw initiële investering (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + De kosten overschrijden ${thresholdMax}% van uw totale investeringsvolume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - De kosten bedragen niet meer dan ${thresholdMax}% van uw initiële investering (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + De kosten bedragen maximaal ${thresholdMax}% van uw totale investeringsvolume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7995,7 +8039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8007,7 +8051,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8028,10 +8072,10 @@ Current month - Current month + Huidige maand apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8039,11 +8083,11 @@ nieuw apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8213,7 +8257,7 @@ If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ - If you encounter a bug, would like to suggest an improvement or a new feature, please join the Ghostfolio Slack community, post to @ghostfolio_ + Als je een bug tegenkomt, een verbetering wilt voorstellen of een nieuwe functie wilt toevoegen, word dan lid van de Ghostfolio Slack-community. Stuur een bericht naar @ghostfolio_ apps/client/src/app/pages/about/overview/about-overview-page.html 69 @@ -8256,7 +8300,7 @@ Beheer activaprofiel apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8337,7 +8381,7 @@ Liquidity - Liquidity + Liquiditeit apps/client/src/app/pages/i18n/i18n-page.html 70 @@ -8345,7 +8389,7 @@ Buying Power - Buying Power + Koopkracht apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -8353,7 +8397,7 @@ Your buying power is below ${thresholdMin} ${baseCurrency} - Your buying power is below ${thresholdMin} ${baseCurrency} + Uw koopkracht ligt onder ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 73 @@ -8361,7 +8405,7 @@ Your buying power is 0 ${baseCurrency} - Your buying power is 0 ${baseCurrency} + Uw koopkracht is 0 ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 77 @@ -8369,7 +8413,7 @@ Your buying power exceeds ${thresholdMin} ${baseCurrency} - Your buying power exceeds ${thresholdMin} ${baseCurrency} + Uw koopkracht overschrijdt ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 80 @@ -8673,10 +8717,10 @@ Registration Date - Registration Date + Registratiedatum apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.pl.xlf b/apps/client/src/locales/messages.pl.xlf index 2241e6a9a..e2083ccf7 100644 --- a/apps/client/src/locales/messages.pl.xlf +++ b/apps/client/src/locales/messages.pl.xlf @@ -215,7 +215,7 @@ Ryzyko strat na rynku może być znaczne. Nie jest zalecane inwestowanie pieniędzy, które mogą być potrzebne w krótkim okresie. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -243,7 +243,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -290,14 +290,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Czy na pewno chcesz cofnąć przyznany dostęp? @@ -319,7 +311,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -335,7 +327,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -359,7 +351,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -371,7 +363,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -387,11 +379,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -403,7 +395,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -419,7 +411,7 @@ Suma libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -431,7 +423,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -443,11 +435,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -463,15 +455,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -479,11 +471,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -495,7 +487,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -519,15 +511,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -551,11 +543,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -563,7 +559,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -579,7 +575,7 @@ Czy na pewno chcesz usunąć to konto? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -599,7 +595,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -619,7 +615,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -659,12 +655,12 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 and is driven by the efforts of its contributors - and is driven by the efforts of its contributors + i jest rozwijany dzięki pracy jego współtwórców apps/client/src/app/pages/about/overview/about-overview-page.html 49 @@ -715,7 +711,7 @@ Data apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -751,19 +747,11 @@ Waluty apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 - - - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 + 95 @@ -771,7 +759,7 @@ ETF-y bez Krajów apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -779,7 +767,7 @@ ETF-y bez Sektorów apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -795,7 +783,7 @@ Filtruj według... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -815,7 +803,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -835,7 +823,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -871,7 +859,7 @@ Ups! Nie udało się sparsować danych historycznych. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -895,7 +883,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -927,7 +915,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -939,7 +927,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -947,7 +935,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -959,7 +947,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -971,7 +959,7 @@ Mapowanie Symboli apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -987,7 +975,7 @@ Konfiguracja Scrapera apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -995,7 +983,7 @@ Notatka apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1003,7 +991,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1047,7 +1035,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1055,7 +1043,7 @@ Czy naprawdę chcesz usunąć ten kupon? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -1063,7 +1051,7 @@ Czy naprawdę chcesz usunąć tę wiadomość systemową? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -1071,7 +1059,7 @@ Czy naprawdę chcesz wyczyścić pamięć podręczną? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -1079,7 +1067,7 @@ Proszę ustawić swoją wiadomość systemową: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -1203,11 +1191,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1223,7 +1211,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -1231,7 +1219,15 @@ Czy naprawdę chcesz usunąć tę platformę? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1255,7 +1251,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -1271,7 +1267,7 @@ Platformy apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1279,7 +1275,7 @@ Tagi apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1303,7 +1299,7 @@ Czy naprawdę chcesz usunąć ten tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -1327,7 +1323,7 @@ Czy na pewno chcesz usunąć tego użytkownika? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -1363,7 +1359,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1395,11 +1391,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -1435,7 +1431,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -1447,7 +1443,7 @@ Poziom Odniesienia (Benchmark) apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1511,7 +1507,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -1519,7 +1515,7 @@ Zarządzaj Aktywnościami apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -1584,7 +1580,7 @@ The source code is fully available as open source software (OSS) under the AGPL-3.0 license - The source code is fully available as open source software (OSS) under the AGPL-3.0 license + Kod źródłowy jest w pełni dostępny jako oprogramowanie open source (OSS) na licencji AGPL-3.0 license apps/client/src/app/pages/about/overview/about-overview-page.html 16 @@ -1651,7 +1647,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1671,7 +1667,7 @@ Całkowita Kwota apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1699,7 +1695,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -1743,7 +1739,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1783,7 +1779,7 @@ Bezwzględne Osiągi Brutto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1795,7 +1791,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1803,11 +1799,11 @@ Bezwzględne Osiągi Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -1815,11 +1811,11 @@ Osiągi Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -1827,7 +1823,7 @@ Suma Aktywów apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1835,7 +1831,7 @@ Aktywa apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -1843,7 +1839,7 @@ Siła Nabywcza apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1851,7 +1847,7 @@ Wykluczone z Analizy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1859,7 +1855,7 @@ Pasywa (Zobowiązania Finansowe) apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1871,7 +1867,7 @@ Wartość Netto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1879,7 +1875,7 @@ Osiągi w Ujęciu Rocznym apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1915,7 +1911,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1923,7 +1919,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1931,7 +1927,7 @@ Zgłoś Błąd Danych apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1963,7 +1959,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -1983,7 +1979,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -1999,7 +1995,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2015,7 +2011,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2027,7 +2023,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2043,7 +2039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2099,7 +2095,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -2111,7 +2107,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -2119,11 +2115,11 @@ Liczony od początku roku (year-to-date) apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -2131,11 +2127,11 @@ 1 rok apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -2143,11 +2139,19 @@ 5 lat apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Wynik z efektem walutowym + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -2155,11 +2159,11 @@ Maksimum apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -2235,7 +2239,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2263,7 +2267,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -2271,7 +2275,7 @@ Czy na pewno chcesz usunąć tą metode logowania? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -2279,7 +2283,7 @@ Widok Prezentera apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -2287,7 +2291,7 @@ Ochrona dla wrażliwych informacji takich jak wyniki i wartości ilościowe apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -2311,11 +2315,11 @@ Ustawienia Regionalne apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -2323,7 +2327,7 @@ Format daty i liczb apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -2331,7 +2335,7 @@ Wygląd (tryb) apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -2339,7 +2343,7 @@ Jasny apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -2347,7 +2351,7 @@ Ciemny apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -2355,7 +2359,7 @@ Tryb Zen apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -2367,12 +2371,12 @@ Doświadczenie bez zakłóceń w niespokojnych czasach apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 this is projected to increase to - this is projected to increase to + prognozuje się wzrost tej kwoty do apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -2383,7 +2387,7 @@ Uwierzytelnianie Biometryczne apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -2391,7 +2395,7 @@ Logowanie za pomocą linii papilarnych apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -2399,7 +2403,7 @@ Funkcje Eksperymentalne apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -2407,7 +2411,7 @@ Podgląd nadchodzących funkcjonalności apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -2419,11 +2423,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2431,7 +2435,7 @@ Eksportuj Dane apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -2615,7 +2619,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2707,7 +2711,7 @@ Dane Rynkowe apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -2759,11 +2763,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2887,11 +2891,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -2907,7 +2911,7 @@ Ponieważ jesteś już zalogowany, nie możesz uzyskać dostępu do konta demo. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3051,7 +3055,7 @@ Oprogramowanie Open Source apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -3063,7 +3067,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -3075,11 +3079,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3131,7 +3135,7 @@ Rynki apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3155,7 +3159,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3531,7 +3535,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -3560,7 +3564,7 @@ and a safe withdrawal rate (SWR) of - and a safe withdrawal rate (SWR) of + oraz bezpiecznej stopy wypłaty (SWR) na poziomie apps/client/src/app/pages/portfolio/fire/fire-page.html 108 @@ -3623,7 +3627,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3647,7 +3651,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3659,7 +3663,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -3667,7 +3671,7 @@ Czy na pewno chcesz usunąć te aktywności? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3735,7 +3739,7 @@ Zaktualizuj Saldo Gotówkowe apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -3743,7 +3747,7 @@ Cena Jednostkowa apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3983,7 +3987,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -4007,7 +4011,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -4015,7 +4019,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4027,7 +4031,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4039,7 +4043,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4083,7 +4087,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4099,7 +4103,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4107,11 +4111,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -4120,7 +4124,7 @@ annual interest rate - annual interest rate + rocznej stopy zwrotu apps/client/src/app/pages/portfolio/fire/fire-page.html 185 @@ -4131,7 +4135,7 @@ Depozyt libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -4139,7 +4143,7 @@ Miesięcznie apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -4147,7 +4151,7 @@ Rocznie apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -4155,7 +4159,7 @@ Największe wzrosty apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -4163,7 +4167,7 @@ Największy spadek apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -4171,7 +4175,7 @@ Rozwój portfela apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -4179,7 +4183,7 @@ Oś czasu inwestycji apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -4187,7 +4191,7 @@ Obecna passa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4195,7 +4199,7 @@ Najdłuższa passa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4203,7 +4207,7 @@ Oś czasu dywidend apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -4379,7 +4383,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4395,7 +4399,7 @@ Wsparcie przez E-mail i Czat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4411,7 +4415,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4419,7 +4423,7 @@ Płatność jednorazowa, bez automatycznego odnawiania. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -4427,11 +4431,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -4439,7 +4443,7 @@ Jest bezpłatny. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4455,12 +4459,12 @@ Kontynenty apps/client/src/app/pages/public/public-page.html - 132 + 131 Sustainable retirement income - Sustainable retirement income + Zrównoważony dochód na emeryturze apps/client/src/app/pages/portfolio/fire/fire-page.html 41 @@ -4471,7 +4475,7 @@ Ghostfolio umożliwia śledzenie wartości swojego majątku. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4593,7 +4597,7 @@ per month - per month + miesięcznie apps/client/src/app/pages/portfolio/fire/fire-page.html 94 @@ -4784,7 +4788,7 @@ Szwajcaria apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -4796,7 +4800,7 @@ Globalny apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -4832,7 +4836,7 @@ Członkostwo apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -4848,7 +4852,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -4948,7 +4952,7 @@ Czy na pewno chcesz usunąć tę działalność? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -4956,7 +4960,7 @@ Profile aktywów apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -4992,7 +4996,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5052,11 +5056,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -5068,7 +5072,7 @@ Oszczędności libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -5076,11 +5080,11 @@ Podział libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5096,7 +5100,7 @@ Pokaż wszystko libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -5140,7 +5144,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5148,7 +5152,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -5172,7 +5176,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5180,7 +5184,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -5224,7 +5228,7 @@ Fundusz Rezerwowy apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -5300,7 +5304,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -5311,6 +5315,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Świadczenia Emerytalne @@ -5319,6 +5331,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satelita @@ -5377,14 +5397,14 @@ View Details - View Details + Zobacz szczegóły apps/client/src/app/components/admin-users/admin-users.html 225 libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -5405,7 +5425,7 @@ Buy - Zakup + Kupno apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 31 @@ -5420,7 +5440,7 @@ Opłata apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5449,7 +5469,7 @@ Sell - Sprzedaj + Sprzedaż apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html 44 @@ -5464,7 +5484,7 @@ Gotówka apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5512,7 +5532,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5605,7 +5625,7 @@ If you retire today, you would be able to withdraw - If you retire today, you would be able to withdraw + Gdybyś przeszedł na emeryturę dziś, mógłbyś wypłacać apps/client/src/app/pages/portfolio/fire/fire-page.html 68 @@ -5656,7 +5676,7 @@ Ważność do apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -5680,7 +5700,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5688,11 +5708,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5720,7 +5740,7 @@ Salda Gotówkowe apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5760,7 @@ Czy na pewno chcesz usunąć saldo tego konta? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5776,7 @@ Obecna cena rynkowa wynosi apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5764,7 +5784,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5852,15 +5872,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -5868,7 +5888,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5876,7 +5896,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5884,7 +5904,7 @@ Łączny wynik aktywów apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5892,7 +5912,7 @@ Wyniki aktywów apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5900,7 +5920,7 @@ Łączny wynik walut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5908,7 +5928,7 @@ Wynik walut apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5916,7 +5936,7 @@ Dotychczasowy tydzień libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5924,11 +5944,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5936,7 +5956,7 @@ Od początku miesiąca libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5944,11 +5964,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5956,7 +5976,7 @@ Od początku roku libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5992,7 +6012,7 @@ rok apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6024,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6012,11 +6032,11 @@ lata apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6032,7 +6052,7 @@ Gromadzenie Danych apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6064,7 @@ Informacje Ogólne apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6072,7 @@ Rozwiązanie w Chmurze apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6084,7 @@ Własny Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6209,7 +6229,7 @@ Czy na pewno chcesz zamknąć swoje konto Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6217,7 +6237,7 @@ Strefa Zagrożenia apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6225,7 +6245,7 @@ Zamknij Konto apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6257,7 +6277,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6285,7 @@ Ups! Wystąpił błąd podczas konfigurowania uwierzytelniania biometrycznego. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6281,7 +6301,7 @@ Punkty Odniesienia apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6329,7 +6349,7 @@ Chcesz udoskonalić swoją osobistą strategię inwestycyjną? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6337,7 +6357,7 @@ Alternatywa apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6345,7 +6365,7 @@ Aplikacja apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6353,7 +6373,7 @@ Budżetowanie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6369,47 +6389,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6417,7 +6441,7 @@ Biuro Rodzinne apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6425,7 +6449,7 @@ Inwestor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6437,7 +6461,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6449,7 +6473,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6457,7 +6481,7 @@ Prywatność apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6465,7 +6489,7 @@ Oprogramowanie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6473,7 +6497,7 @@ Narzędzie apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6481,7 +6505,7 @@ Doświadczenie Użytkownika apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6489,7 +6513,7 @@ Majątek apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6497,7 +6521,7 @@ Zarządzanie Majątkiem apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6657,7 +6681,7 @@ Błąd apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6686,7 +6710,7 @@ , based on your total assets of - , based on your total assets of + , na podstawie całkowitej wartości aktywów wynoszącej apps/client/src/app/pages/portfolio/fire/fire-page.html 96 @@ -6709,7 +6733,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6741,7 +6765,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6749,7 +6773,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6761,7 +6785,7 @@ Zamknij apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6787,13 +6811,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6805,7 +6833,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6845,7 +6873,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6946,7 +6974,7 @@ , assuming a - , assuming a + , przyjmując apps/client/src/app/pages/portfolio/fire/fire-page.html 174 @@ -6957,7 +6985,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7034,7 +7062,7 @@ Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. - Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies and make solid, data-driven investment decisions. + Ghostfolio to aplikacja do zarządzania majątkiem, przeznaczona dla osób prywatnych do śledzenia akcji, ETF‑ów i kryptowalut oraz podejmowania solidnych, opartych na danych decyzji inwestycyjnych. apps/client/src/app/pages/about/overview/about-overview-page.html 10 @@ -7061,7 +7089,7 @@ Skonfiguruj klucz API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7097,7 +7125,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7113,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7167,7 +7195,7 @@ z apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7175,7 +7203,7 @@ codzienne żądania apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7183,7 +7211,7 @@ Usuń klucz API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7191,7 +7219,7 @@ Czy na pewno chcesz usunąć klucz API?? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7211,7 +7239,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7283,7 +7311,7 @@ Zapisz apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7319,11 +7347,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7359,7 +7387,15 @@ Wprowadź swój klucz API Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Zmiana z efektem walutowym + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7367,7 +7403,7 @@ Prompt AI został skopiowany do schowka apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7383,7 +7419,7 @@ Leniwy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7391,7 +7427,7 @@ Natychmiastowy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7399,7 +7435,7 @@ Domyślna cena rynkowa apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7407,7 +7443,7 @@ Tryb apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7415,7 +7451,7 @@ Selektor apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7423,7 +7459,7 @@ Nagłówki żądań HTTP apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7431,7 +7467,7 @@ koniec dnia apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7439,7 +7475,7 @@ w czasie rzeczywistym apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7447,7 +7483,7 @@ Otwórz Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7463,11 +7499,11 @@ Zmiana libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7483,20 +7519,20 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 The project has been initiated by - The project has been initiated by + Projekt został zainicjowany przez apps/client/src/app/pages/about/overview/about-overview-page.html 40 @@ -7518,6 +7554,14 @@ 67 + + Total amount + Wartość portfela + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Armenia @@ -7587,7 +7631,7 @@ Token bezpieczeństwa apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7599,7 +7643,7 @@ Czy napewno chcesz wygenerować nowy token bezpieczeństwa dla tego użytkownika? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7607,7 +7651,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7672,7 +7716,7 @@ () jest już w użyciu. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7680,7 +7724,7 @@ Wystąpił błąd podczas aktualizacji do (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7696,7 +7740,7 @@ z dostępem API dla apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7776,7 +7820,7 @@ Czy na pewno chcesz usunąć ten element? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7817,7 +7861,7 @@ Konto użytkownika demonstracyjnego zostało zsynchronizowane. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7852,25 +7896,25 @@ 150 - + Fee Ratio - Stosunek opłat + Wskaźnik opłat apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Opłaty przekraczają ${thresholdMax}% początkowej inwestycji (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Opłaty nie przekraczają ${thresholdMax}% początkowej inwestycji (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7995,7 +8039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8007,7 +8051,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8031,7 +8075,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8039,11 +8083,11 @@ nowy apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8256,7 +8300,7 @@ Zarządzaj profilem aktywów apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8289,7 +8333,7 @@ Account Cluster Risks - Account Cluster Risks + Ryzyka skupienia w obrębie rachunków apps/client/src/app/pages/i18n/i18n-page.html 14 @@ -8297,7 +8341,7 @@ Asset Class Cluster Risks - Asset Class Cluster Risks + Ryzyka skupienia w obrębie klas aktywów apps/client/src/app/pages/i18n/i18n-page.html 39 @@ -8305,7 +8349,7 @@ Currency Cluster Risks - Currency Cluster Risks + Ryzyka koncentracji walutowej apps/client/src/app/pages/i18n/i18n-page.html 83 @@ -8313,7 +8357,7 @@ Economic Market Cluster Risks - Economic Market Cluster Risks + Ryzyka skupienia w obrębie segmentów rynku gospodarczego apps/client/src/app/pages/i18n/i18n-page.html 106 @@ -8329,7 +8373,7 @@ Fees - Fees + Opłaty apps/client/src/app/pages/i18n/i18n-page.html 161 @@ -8337,7 +8381,7 @@ Liquidity - Liquidity + Płynność apps/client/src/app/pages/i18n/i18n-page.html 70 @@ -8345,7 +8389,7 @@ Buying Power - Buying Power + Siła nabywcza apps/client/src/app/pages/i18n/i18n-page.html 71 @@ -8369,7 +8413,7 @@ Your buying power exceeds ${thresholdMin} ${baseCurrency} - Your buying power exceeds ${thresholdMin} ${baseCurrency} + Twoja siła nabywcza przekracza ${thresholdMin} ${baseCurrency} apps/client/src/app/pages/i18n/i18n-page.html 80 @@ -8377,7 +8421,7 @@ Regional Market Cluster Risks - Regional Market Cluster Risks + Ryzyka skupienia w obrębie regionów rynkowych apps/client/src/app/pages/i18n/i18n-page.html 163 @@ -8393,7 +8437,7 @@ Developed Markets - Developed Markets + Rynki rozwinięte apps/client/src/app/pages/i18n/i18n-page.html 109 @@ -8425,7 +8469,7 @@ Emerging Markets - Emerging Markets + Rynki wschodzące apps/client/src/app/pages/i18n/i18n-page.html 127 @@ -8537,7 +8581,7 @@ Europe - Europe + Europa apps/client/src/app/pages/i18n/i18n-page.html 195 @@ -8569,7 +8613,7 @@ Japan - Japan + Japonia apps/client/src/app/pages/i18n/i18n-page.html 209 @@ -8676,7 +8720,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.pt.xlf b/apps/client/src/locales/messages.pt.xlf index 188bda9c8..72c1e6a3e 100644 --- a/apps/client/src/locales/messages.pt.xlf +++ b/apps/client/src/locales/messages.pt.xlf @@ -6,7 +6,7 @@ O risco de perda em investimentos pode ser substancial. Não é aconselhável investir dinheiro que possa vir a precisar a curto prazo. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -34,7 +34,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -81,14 +81,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Pretende realmente revogar este acesso concedido? @@ -110,7 +102,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -122,7 +114,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -134,7 +126,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -150,11 +142,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -166,7 +158,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -182,7 +174,7 @@ Total libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -194,7 +186,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -206,11 +198,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -230,7 +222,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -242,15 +234,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -258,11 +250,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -274,7 +266,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -298,15 +290,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -330,11 +322,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -342,7 +338,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -358,7 +354,7 @@ Pretende realmente eliminar esta conta? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -378,7 +374,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -418,7 +414,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -442,7 +438,7 @@ Perfil de Ativos apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -458,7 +454,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -498,7 +494,7 @@ Data apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -534,7 +530,7 @@ Filtrar por... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -554,7 +550,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -574,7 +570,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -610,7 +606,7 @@ Deseja realmente eliminar este cupão? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -618,7 +614,7 @@ Deseja realmente limpar a cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -626,7 +622,7 @@ Por favor, defina a sua mensagem do sistema: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -718,7 +714,7 @@ Deseja realmente excluir este utilizador? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -754,7 +750,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -770,11 +766,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -802,7 +798,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -814,7 +810,7 @@ Referência apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -878,7 +874,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -886,7 +882,7 @@ Gerir Atividades apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -946,7 +942,7 @@ Depósito libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -954,7 +950,7 @@ Valor Total apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -982,7 +978,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -1026,7 +1022,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1066,7 +1062,7 @@ Desempenho Bruto Absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1074,11 +1070,11 @@ Desempenho Líquido Absoluto apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -1086,11 +1082,11 @@ Desempenho Líquido apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -1098,7 +1094,7 @@ Ativos Totais apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1106,7 +1102,7 @@ Poder de Compra apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1114,7 +1110,7 @@ Excluído da Análise apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1122,7 +1118,7 @@ Valor Líquido apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1130,7 +1126,7 @@ Desempenho Anual apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1166,7 +1162,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1174,7 +1170,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1206,7 +1202,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -1218,7 +1214,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1226,7 +1222,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -1238,7 +1234,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1250,7 +1246,7 @@ Marcadores apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1266,7 +1262,7 @@ Dados do Relatório com Problema apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1274,11 +1270,11 @@ Alocação libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -1294,7 +1290,7 @@ Mostrar tudo libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -1306,7 +1302,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -1314,11 +1310,11 @@ AATD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -1326,11 +1322,11 @@ 1A apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -1338,11 +1334,19 @@ 5A apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Performance with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -1350,11 +1354,11 @@ Máx apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -1470,7 +1474,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -1510,7 +1514,7 @@ Deseja realmente remover este método de início de sessão? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -1530,7 +1534,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -1554,7 +1558,7 @@ Vista do Apresentador apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -1586,11 +1590,11 @@ Localidade apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -1598,7 +1602,7 @@ Formato de números e datas apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -1606,7 +1610,7 @@ Modo Zen apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -1618,7 +1622,7 @@ Aparência apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -1626,7 +1630,7 @@ Claro apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -1634,7 +1638,7 @@ Escuro apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -1642,7 +1646,7 @@ Iniciar sessão com impressão digital apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -1650,7 +1654,7 @@ Funcionalidades Experimentais apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -1662,11 +1666,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -1718,7 +1722,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -1886,7 +1890,7 @@ Como já tem sessão iniciada, não pode aceder à conta de demonstração. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -1950,11 +1954,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -1970,7 +1974,7 @@ Mercados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -1994,7 +1998,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -2022,7 +2026,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -2046,7 +2050,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -2058,7 +2062,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -2074,7 +2078,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -2118,7 +2122,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -2126,7 +2130,7 @@ Preço por Unidade apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -2138,7 +2142,7 @@ Nota apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -2146,7 +2150,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -2282,7 +2286,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -2306,7 +2310,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -2314,7 +2318,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -2326,7 +2330,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -2338,7 +2342,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -2358,7 +2362,7 @@ Mensalmente apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -2366,7 +2370,7 @@ Topo apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -2374,7 +2378,7 @@ Fundo apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -2382,7 +2386,7 @@ Evolução do Portefólio apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -2390,7 +2394,7 @@ Cronograma de Investimento apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -2482,7 +2486,7 @@ Continentes apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -2498,7 +2502,7 @@ O Ghostfolio permite-lhe estar a par e gerir a sua riqueza. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -2510,7 +2514,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -2522,11 +2526,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -2698,7 +2702,7 @@ Deseja realmente eliminar esta atividade? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -2714,7 +2718,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -2750,11 +2754,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -2766,7 +2770,7 @@ Poupanças libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -2802,7 +2806,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -2810,7 +2814,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -2826,7 +2830,7 @@ Fundo de Emergência apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -2846,7 +2850,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -2894,7 +2898,7 @@ Dinheiro apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -2942,7 +2946,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -3074,7 +3078,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -3082,11 +3086,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -3114,7 +3118,7 @@ Mapeamento de Símbolo apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -3130,7 +3134,7 @@ Dados de Mercado apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -3170,7 +3174,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3178,7 +3182,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3194,7 +3198,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3202,11 +3206,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -3218,7 +3222,7 @@ Cronograma de Dividendos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -3234,7 +3238,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -3242,7 +3246,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -3274,7 +3278,7 @@ Anualmente apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -3298,7 +3302,7 @@ Válido até apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -3337,6 +3341,14 @@ 22 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Provisão de Reforma @@ -3345,6 +3357,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Satélite @@ -3358,7 +3378,7 @@ Proteção para informações sensíveis, como desempenhos absolutos e valores quantitativos apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -3366,7 +3386,7 @@ Experiência sem distrações para tempos turbulentos apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -3374,7 +3394,7 @@ Acesso antecipado a funcionalidades futuras apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -3398,7 +3418,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -3414,7 +3434,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -3430,7 +3450,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -3446,7 +3466,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -3494,7 +3514,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -3578,7 +3598,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3594,7 +3614,7 @@ Pagamento único, sem renovação automática. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3602,11 +3622,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -3614,7 +3634,7 @@ É gratuito. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3626,7 +3646,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -3646,7 +3666,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -3690,7 +3710,7 @@ Suporte por Email e Chat apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3734,7 +3754,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -3758,7 +3778,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3790,7 +3810,7 @@ Deseja mesmo eliminar estas atividades? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3801,6 +3821,14 @@ 306 + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 + + By By @@ -3822,7 +3850,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -3838,11 +3866,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -3858,7 +3886,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -3866,7 +3894,7 @@ Deseja mesmo eliminar esta plataforma? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 @@ -3874,7 +3902,7 @@ Plataformas apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -3882,7 +3910,7 @@ Atualizar saldo em Dinheiro apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4002,7 +4030,7 @@ Série Atual apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4010,7 +4038,7 @@ Série mais Longa apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4054,7 +4082,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -4062,7 +4090,7 @@ Responsabilidades apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -4194,7 +4222,7 @@ Software de código aberto apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -4218,7 +4246,7 @@ Configuração do raspador apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -4457,20 +4485,12 @@ 43 - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 - - ETFs without Countries ETFs sem países apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -4478,7 +4498,7 @@ ETFs sem setores apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -4486,7 +4506,7 @@ Ativos apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -4614,7 +4634,7 @@ Autenticação biométrica apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -4706,7 +4726,7 @@ Exportar dados apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -4714,11 +4734,11 @@ Moedas apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 + 95 @@ -4766,11 +4786,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -5324,7 +5344,7 @@ Suíça apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -5336,7 +5356,7 @@ Global apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -5364,7 +5384,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5432,7 +5452,7 @@ Taxa apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5464,7 +5484,7 @@ Você realmente deseja excluir esta tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -5532,7 +5552,7 @@ Associação apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5548,7 +5568,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5688,7 +5708,7 @@ Ops! Não foi possível analisar os dados históricos. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -5696,7 +5716,7 @@ Você realmente deseja excluir esta mensagem do sistema? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -5720,7 +5740,7 @@ Saldos de caixa apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5760,7 @@ Você realmente deseja excluir o saldo desta conta? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5776,7 @@ O preço de mercado atual é apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5764,7 +5784,7 @@ Teste apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5852,15 +5872,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -5868,7 +5888,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5876,7 +5896,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5884,7 +5904,7 @@ Desempenho absoluto de ativos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5892,7 +5912,7 @@ Desempenho de ativos apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5900,7 +5920,7 @@ Desempenho absoluto da moeda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5908,7 +5928,7 @@ Desempenho da moeda apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5916,7 +5936,7 @@ Semana até agora libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5924,11 +5944,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5936,7 +5956,7 @@ Do mês até a data libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5944,11 +5964,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5956,7 +5976,7 @@ No acumulado do ano libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5992,7 +6012,7 @@ ano apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6024,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6012,11 +6032,11 @@ anos apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6032,7 +6052,7 @@ Coleta de dados apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6064,7 @@ geral apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6072,7 @@ Nuvem apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6084,7 @@ Auto-hospedagem apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6209,7 +6229,7 @@ Você realmente deseja encerrar sua conta Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6217,7 +6237,7 @@ Zona de perigo apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6225,7 +6245,7 @@ Fechar conta apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6257,7 +6277,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6285,7 @@ Ops! Ocorreu um erro ao configurar a autenticação biométrica. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6281,7 +6301,7 @@ Referências apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6329,7 +6349,7 @@ Você gostaria de refinar seu estratégia de investimento pessoal? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6337,7 +6357,7 @@ Alternativo apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6345,7 +6365,7 @@ Aplicativo apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6353,7 +6373,7 @@ Orçamento apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6369,47 +6389,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6417,7 +6441,7 @@ Escritório Familiar apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6425,7 +6449,7 @@ Investidor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6437,7 +6461,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6449,7 +6473,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6457,7 +6481,7 @@ Privacidade apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6465,7 +6489,7 @@ Programas apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6473,7 +6497,7 @@ Ferramenta apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6481,7 +6505,7 @@ Experiência do usuário apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6489,7 +6513,7 @@ Fortuna apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6497,7 +6521,7 @@ Gestão de patrimônio apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6657,7 +6681,7 @@ Erro apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6709,7 +6733,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6741,7 +6765,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6749,7 +6773,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6761,7 +6785,7 @@ Fechar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6787,13 +6811,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6805,7 +6833,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6845,7 +6873,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6957,7 +6985,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7061,7 +7089,7 @@ Definir chave de API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7097,7 +7125,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7113,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7167,7 +7195,7 @@ de apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7175,7 +7203,7 @@ solicitações diárias apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7183,7 +7211,7 @@ Remover chave de API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7191,7 +7219,7 @@ Você realmente deseja excluir a chave de API? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7211,7 +7239,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7283,7 +7311,7 @@ Guardar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7319,11 +7347,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7359,7 +7387,15 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Change with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7367,7 +7403,7 @@ AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7383,7 +7419,7 @@ Lazy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7391,7 +7427,7 @@ Instant apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7399,7 +7435,7 @@ Preço de mercado padrão apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7407,7 +7443,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7415,7 +7451,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7423,7 +7459,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7431,7 +7467,7 @@ end of day apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7439,7 +7475,7 @@ real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7447,7 +7483,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7463,11 +7499,11 @@ Mudar libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7483,15 +7519,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -7518,6 +7554,14 @@ 67 + + Total amount + Total amount + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Armenia @@ -7587,7 +7631,7 @@ Security token apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7599,7 +7643,7 @@ Do you really want to generate a new security token for this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7607,7 +7651,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7672,7 +7716,7 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7680,7 +7724,7 @@ An error occurred while updating to (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7696,7 +7740,7 @@ with API access for apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7776,7 +7820,7 @@ Do you really want to delete this item? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7817,7 +7861,7 @@ Demo user account has been synced. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7852,7 +7896,7 @@ 150 - + Fee Ratio Fee Ratio @@ -7860,17 +7904,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7995,7 +8039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8007,7 +8051,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8031,7 +8075,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8039,11 +8083,11 @@ new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8256,7 +8300,7 @@ Gerenciar perfil de ativos apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8676,7 +8720,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.tr.xlf b/apps/client/src/locales/messages.tr.xlf index cd713e26a..7f51580d7 100644 --- a/apps/client/src/locales/messages.tr.xlf +++ b/apps/client/src/locales/messages.tr.xlf @@ -187,7 +187,7 @@ Alım satımda kayıp riski büyük boyutta olabilir. Kısa vadede ihtiyaç duyabileceğiniz parayla yatırım yapmak tavsiye edilmez. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -215,7 +215,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -262,14 +262,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Bu erişim iznini geri almayı gerçekten istiyor musunuz? @@ -291,7 +283,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -307,7 +299,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -319,7 +311,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -331,7 +323,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -347,11 +339,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -363,7 +355,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -379,7 +371,7 @@ Toplam libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -391,7 +383,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -403,11 +395,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -423,15 +415,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -439,11 +431,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -455,7 +447,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -479,15 +471,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -511,11 +503,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -523,7 +519,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -539,7 +535,7 @@ Bu hesabı silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -559,7 +555,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -599,7 +595,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -623,7 +619,7 @@ Varlık Profili apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -639,7 +635,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -679,7 +675,7 @@ Tarih apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -715,19 +711,11 @@ Para Birimleri apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 - - - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 + 95 @@ -735,7 +723,7 @@ Ülkesi Olmayan ETF’ler apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -743,7 +731,7 @@ Sektörü Olmayan ETF’ler apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -751,7 +739,7 @@ Filtrele... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -771,7 +759,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -791,7 +779,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -859,7 +847,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -871,7 +859,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -879,7 +867,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -891,7 +879,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -903,7 +891,7 @@ Sembol Eşleştirme apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -919,7 +907,7 @@ Veri Toplayıcı Yapılandırması apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -927,7 +915,7 @@ Not apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -935,7 +923,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -963,7 +951,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -971,7 +959,7 @@ Bu kuponu gerçekten silmek istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -979,7 +967,7 @@ Önbelleği temizlemeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -987,7 +975,7 @@ Lütfen sistem mesajınızı belirleyin: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -1027,7 +1015,7 @@ Etiketler apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1119,11 +1107,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1139,7 +1127,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -1147,7 +1135,15 @@ Bu platformu silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1171,7 +1167,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -1187,7 +1183,7 @@ Platformlar apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1195,7 +1191,7 @@ Bu kullanıcıyı silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -1231,7 +1227,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1263,11 +1259,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -1303,7 +1299,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -1315,7 +1311,7 @@ Karşılaştırma Ölçütü apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1379,7 +1375,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -1387,7 +1383,7 @@ İşlemleri Yönet apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -1519,7 +1515,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1539,7 +1535,7 @@ Toplam Tutar apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1567,7 +1563,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -1611,7 +1607,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1651,7 +1647,7 @@ Toplam Brüt Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1659,11 +1655,11 @@ Toplam Net Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -1671,11 +1667,11 @@ Net Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -1683,7 +1679,7 @@ Toplam Varlıklar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1691,7 +1687,7 @@ Varlıklar apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -1699,7 +1695,7 @@ Alım Limiti apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1707,7 +1703,7 @@ Analize Dahil Edilmemiştir. apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1715,7 +1711,7 @@ Yükümlülükler apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1727,7 +1723,7 @@ Toplam Varlık apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1735,7 +1731,7 @@ Yıllıklandırılmış Performans apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1771,7 +1767,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1779,7 +1775,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1791,7 +1787,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1799,7 +1795,7 @@ Rapor Veri Sorunu apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1831,7 +1827,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -1851,7 +1847,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -1867,7 +1863,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -1883,7 +1879,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -1895,7 +1891,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -1911,7 +1907,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -1967,7 +1963,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -1979,7 +1975,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -1987,11 +1983,11 @@ YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -1999,11 +1995,11 @@ 1Y apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -2011,11 +2007,19 @@ 5Y apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Performance with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -2023,11 +2027,11 @@ Maks. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -2211,7 +2215,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2271,7 +2275,7 @@ Piyasa Verileri apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -2323,11 +2327,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2451,11 +2455,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -2471,7 +2475,7 @@ Oturum açmış olduğunuz için demo hesabına erişemezsiniz. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -2583,7 +2587,7 @@ Zen Modu apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -2627,7 +2631,7 @@ Açık Kaynak Yazılım apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -2639,7 +2643,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -2651,11 +2655,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -2707,7 +2711,7 @@ Piyasalar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -2731,7 +2735,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3123,7 +3127,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3147,7 +3151,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3159,7 +3163,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -3167,7 +3171,7 @@ Tüm işlemlerinizi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3211,7 +3215,7 @@ Nakit Bakiyesini Güncelle apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -3219,7 +3223,7 @@ Birim Fiyat apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3375,7 +3379,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -3467,7 +3471,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -3491,7 +3495,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -3499,7 +3503,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -3511,7 +3515,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -3523,7 +3527,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -3567,7 +3571,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3583,7 +3587,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3591,11 +3595,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -3615,7 +3619,7 @@ Para Yatırma libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -3623,7 +3627,7 @@ Aylık apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -3631,7 +3635,7 @@ Yıllık apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -3639,7 +3643,7 @@ Üst apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -3647,7 +3651,7 @@ Alt apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -3655,7 +3659,7 @@ Portföyün Gelişimi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -3663,7 +3667,7 @@ Yatırım Zaman Çizelgesi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -3671,7 +3675,7 @@ Güncel Seri apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -3679,7 +3683,7 @@ En Uzun Seri apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -3687,7 +3691,7 @@ Temettü Zaman Çizelgesi apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -3863,7 +3867,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -3879,7 +3883,7 @@ E-posta ve Sohbet Desteği apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -3895,7 +3899,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -3903,7 +3907,7 @@ Tek seferlik ödeme, otomatik yenileme yok. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -3911,11 +3915,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -3923,7 +3927,7 @@ Ücretsiz. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -3939,7 +3943,7 @@ Kıtalar apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -3955,7 +3959,7 @@ Ghostfolio, varlıklarınızı takip etmenizi sağlar. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4268,7 +4272,7 @@ İsviçre apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -4280,7 +4284,7 @@ Küresel apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -4348,7 +4352,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -4388,7 +4392,7 @@ Bu giriş yöntemini kaldırmayı gerçekten istiyor musunuz? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -4396,7 +4400,7 @@ Geçerli tarih apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -4420,7 +4424,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -4444,7 +4448,7 @@ Sunum Görünümü apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -4452,7 +4456,7 @@ Gerçek performans ve miktar değerleri gibi hassas bilgilerin saklanması için apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -4476,11 +4480,11 @@ Yerel Ayarlar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -4488,7 +4492,7 @@ Tarih ve Sayı Formatları apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -4496,7 +4500,7 @@ Görünüm apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -4504,7 +4508,7 @@ Açık apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -4512,7 +4516,7 @@ Koyu apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -4520,7 +4524,7 @@ Çalkantılı zamanlar için dikkat dağıtmayan bir deneyim apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -4536,7 +4540,7 @@ Biyometrik Kimlik Doğrulama apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -4544,7 +4548,7 @@ Parmak iziyle oturum aç apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -4552,7 +4556,7 @@ Deneysel Özellikler apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -4560,7 +4564,7 @@ Gelecek özelliklere göz atın apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -4572,11 +4576,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -4584,7 +4588,7 @@ Verileri Dışa Aktar apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -4672,7 +4676,7 @@ TBu işlemi silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -4688,7 +4692,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -4748,11 +4752,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -4764,7 +4768,7 @@ Tasarruflar libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -4772,11 +4776,11 @@ Dağılım libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -4792,7 +4796,7 @@ Tümünü göster libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -4836,7 +4840,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -4844,7 +4848,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -4868,7 +4872,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -4876,7 +4880,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -4920,7 +4924,7 @@ Acil Durum Fonu apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -4996,7 +5000,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -5007,6 +5011,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Yaşlılık Provizyonu @@ -5015,6 +5027,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Uydu @@ -5080,7 +5100,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -5144,7 +5164,7 @@ Nakit apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5192,7 +5212,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5324,7 +5344,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5332,11 +5352,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5372,7 +5392,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -5440,7 +5460,7 @@ Ücret apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5464,7 +5484,7 @@ Bu etiketi silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -5532,7 +5552,7 @@ Üyelik apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -5548,7 +5568,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -5688,7 +5708,7 @@ Hay Allah! Geçmiş veriler ayrıştırılamadı. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -5696,7 +5716,7 @@ Bu sistem mesajını silmeyi gerçekten istiyor musunuz? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -5720,7 +5740,7 @@ Nakit Bakiyeleri apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -5740,7 +5760,7 @@ Bu nakit bakiyesini silmeyi gerçekten istiyor musunuz? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -5756,7 +5776,7 @@ Şu anki piyasa fiyatı apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5764,7 +5784,7 @@ Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5852,15 +5872,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -5868,7 +5888,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5876,7 +5896,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5884,7 +5904,7 @@ Mutlak Varlık Performansı apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5892,7 +5912,7 @@ Varlık Performansı apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5900,7 +5920,7 @@ Mutlak Para Performansı apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5908,7 +5928,7 @@ Para Performansı apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5916,7 +5936,7 @@ Hafta içi libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5924,11 +5944,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5936,7 +5956,7 @@ Ay içi libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5944,11 +5964,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5956,7 +5976,7 @@ Yıl içi libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5992,7 +6012,7 @@ Yıl apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6004,7 +6024,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6012,11 +6032,11 @@ Yıllar apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6032,7 +6052,7 @@ Veri Toplama apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6044,7 +6064,7 @@ Genel apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6052,7 +6072,7 @@ Bulut apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6064,7 +6084,7 @@ Kendini Barındırma apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6209,7 +6229,7 @@ Ghostfolio hesabınızı kapatmak istediğinize emin misiniz? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6217,7 +6237,7 @@ Tehlikeli Alan apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6225,7 +6245,7 @@ Hesabı Kapat apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6257,7 +6277,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6265,7 +6285,7 @@ Oops! Biyometrik kimlik doğrulama ayarlanırken bir hata oluştu. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6281,7 +6301,7 @@ Kıyaslamalar apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6329,7 +6349,7 @@ Senin özel yatırım stratejinizi iyileştirmek ister misin? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6337,7 +6357,7 @@ Alternatif apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6345,7 +6365,7 @@ App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6353,7 +6373,7 @@ Bütçeleme apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6369,47 +6389,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6417,7 +6441,7 @@ Aile Ofisi apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6425,7 +6449,7 @@ Yatırımcı apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6437,7 +6461,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6449,7 +6473,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6457,7 +6481,7 @@ Gizlilik apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6465,7 +6489,7 @@ Yazılım apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6473,7 +6497,7 @@ Araç apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6481,7 +6505,7 @@ Kullanıcı Deneyimi apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6489,7 +6513,7 @@ Zenginlik apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6497,7 +6521,7 @@ Zenginlik Yönetimi apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6657,7 +6681,7 @@ Hata apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6709,7 +6733,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6741,7 +6765,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6749,7 +6773,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6761,7 +6785,7 @@ Kapat apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6787,13 +6811,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6805,7 +6833,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6845,7 +6873,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6957,7 +6985,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7061,7 +7089,7 @@ API anahtarını ayarla apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7097,7 +7125,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7113,7 +7141,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7167,7 +7195,7 @@ ın apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7175,7 +7203,7 @@ günlük istekler apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7183,7 +7211,7 @@ API anahtarını kaldır apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7191,7 +7219,7 @@ API anahtarını silmek istediğinize emin misiniz? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7211,7 +7239,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7283,7 +7311,7 @@ Kaydet apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7319,11 +7347,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7359,7 +7387,15 @@ Lütfen Ghostfolio API anahtarınızı girin. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + Change with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7367,7 +7403,7 @@ Yapay zeka istemi panoya kopyalandı apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7383,7 +7419,7 @@ Tembel apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7391,7 +7427,7 @@ Anında apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7399,7 +7435,7 @@ Varsayılan Piyasa Fiyatı apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7407,7 +7443,7 @@ Mod apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7415,7 +7451,7 @@ Seçici apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7423,7 +7459,7 @@ HTTP İstek Başlıkları apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7431,7 +7467,7 @@ gün sonu apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7439,7 +7475,7 @@ gerçek zamanlı apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7447,7 +7483,7 @@ Duck.ai’yi aç apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7463,11 +7499,11 @@ Değişim libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7483,15 +7519,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -7518,6 +7554,14 @@ 67 + + Total amount + Total amount + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Ermenistan @@ -7587,7 +7631,7 @@ Güvenlik belirteci apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7599,7 +7643,7 @@ Bu kullanıcı için yeni bir güvenlik belirteci oluşturmak istediğinize emin misiniz? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7607,7 +7651,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7672,7 +7716,7 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7680,7 +7724,7 @@ Güncelleştirilirken bir hata oluştu (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7696,7 +7740,7 @@ API erişimi için apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7776,7 +7820,7 @@ Bu öğeyi silmek istediğinize emin misiniz? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7817,7 +7861,7 @@ Demo kullanıcı hesabı senkronize edildi. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7852,25 +7896,25 @@ 150 - + Fee Ratio - Ücret Oranı + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Ücretler, ilk yatırımınızın %${thresholdMax} kadarını aşıyor (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - Ücretler, ilk yatırımınızın %${thresholdMax}’ını (${feeRatio}%) aşmaz + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7995,7 +8039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8007,7 +8051,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8031,7 +8075,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8039,11 +8083,11 @@ yeni apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8256,7 +8300,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8676,7 +8720,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.uk.xlf b/apps/client/src/locales/messages.uk.xlf index c38c8d417..54bf5a08b 100644 --- a/apps/client/src/locales/messages.uk.xlf +++ b/apps/client/src/locales/messages.uk.xlf @@ -102,7 +102,7 @@ Ризик втрат у торгівлі може бути суттєвим. Не рекомендується інвестувати гроші, які можуть знадобитися в короткостроковій перспективі. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -295,7 +295,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -374,14 +374,6 @@ 99 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? Ви дійсно хочете відкликати цей наданий доступ? @@ -403,7 +395,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -419,7 +411,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -427,7 +419,7 @@ Баланс готівки apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -451,7 +443,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -463,7 +455,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -479,11 +471,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -495,7 +487,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -511,7 +503,7 @@ Загалом libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -523,7 +515,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -535,11 +527,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -555,15 +547,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -571,11 +563,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -587,7 +579,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -611,15 +603,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -643,11 +635,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -655,7 +651,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -671,7 +667,7 @@ Ви дійсно хочете видалити цей обліковий запис? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -711,7 +707,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -739,7 +735,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -787,7 +783,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -843,7 +839,7 @@ Порівняльні показники apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -851,19 +847,11 @@ Валюти apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 - - - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 + 95 @@ -871,7 +859,7 @@ ETF без країн apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -879,7 +867,7 @@ ETF без секторів apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -887,7 +875,7 @@ Фільтрувати за... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -923,7 +911,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -943,7 +931,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -1011,7 +999,7 @@ Помилка apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -1019,7 +1007,7 @@ Поточна ринкова ціна apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -1059,7 +1047,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -1071,7 +1059,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1079,7 +1067,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -1091,7 +1079,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -1103,7 +1091,7 @@ Зіставлення символів apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -1119,7 +1107,7 @@ Конфігурація скребка apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -1127,7 +1115,7 @@ Тест apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -1135,11 +1123,11 @@ URL apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1155,7 +1143,7 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -1163,7 +1151,7 @@ Примітка apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1171,7 +1159,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1223,7 +1211,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1239,7 +1227,7 @@ Ви дійсно хочете видалити цей купон? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -1247,7 +1235,7 @@ Ви дійсно хочете видалити це системне повідомлення? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -1255,7 +1243,7 @@ Ви дійсно хочете очистити кеш? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -1263,7 +1251,7 @@ Будь ласка, встановіть ваше системне повідомлення: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -1319,7 +1307,7 @@ Збір даних apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -1391,7 +1379,15 @@ Ви дійсно хочете видалити цю платформу? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1415,7 +1411,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -1439,7 +1435,7 @@ Дійсне до apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -1451,7 +1447,7 @@ з apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -1459,7 +1455,7 @@ щоденних запитів apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -1467,7 +1463,7 @@ Вилучити ключ API apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -1475,7 +1471,7 @@ Встановити ключ API apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -1483,7 +1479,7 @@ Платформи apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1491,7 +1487,7 @@ Теги apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1507,7 +1503,7 @@ Ви дійсно хочете видалити ключ API? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -1515,7 +1511,7 @@ Будь ласка, введіть ваш ключ API Ghostfolio. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 @@ -1551,7 +1547,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1599,7 +1595,7 @@ Ви дійсно хочете видалити цей тег? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -1623,7 +1619,7 @@ Ви дійсно хочете видалити цього користувача? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -1635,7 +1631,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1647,7 +1643,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -1679,11 +1675,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -1719,7 +1715,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -1731,7 +1727,7 @@ Порівняльний показник apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1771,7 +1767,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -1787,7 +1783,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -1815,7 +1811,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -1831,7 +1827,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -1867,7 +1863,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1875,7 +1871,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1895,7 +1891,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1919,7 +1915,7 @@ Повідомити про збій даних apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1959,7 +1955,7 @@ Керування діяльністю apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -2091,7 +2087,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -2111,7 +2107,7 @@ Загальна сума apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -2139,7 +2135,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -2203,7 +2199,7 @@ Абсолютний валовий дохід apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -2211,11 +2207,11 @@ Абсолютний чистий прибуток apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -2223,11 +2219,11 @@ Чистий прибуток apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -2235,7 +2231,7 @@ Загальні активи apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -2243,7 +2239,7 @@ Активи apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -2251,7 +2247,7 @@ Купівельна спроможність apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -2259,7 +2255,7 @@ Виключено з аналізу apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -2267,7 +2263,7 @@ Зобов’язання apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -2279,7 +2275,7 @@ Чиста вартість apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -2287,7 +2283,7 @@ Річна доходність apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -2295,7 +2291,7 @@ Зберегти apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -2331,11 +2327,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -2439,7 +2435,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -2459,7 +2455,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -2475,7 +2471,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2491,7 +2487,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2503,7 +2499,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2519,7 +2515,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2567,7 +2563,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -2575,11 +2571,11 @@ З початку року apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -2587,11 +2583,11 @@ 1 рік apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -2599,11 +2595,19 @@ 5 років apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + Performance with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -2611,11 +2615,11 @@ Максимум apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -2667,11 +2671,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2807,7 +2811,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2835,7 +2839,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -2843,7 +2847,7 @@ Ви дійсно хочете закрити ваш обліковий запис Ghostfolio? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -2851,7 +2855,7 @@ Ви дійсно хочете вилучити цей спосіб входу? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -2859,7 +2863,7 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -2867,7 +2871,7 @@ Упс! Виникла помилка під час налаштування біометричної автентифікації. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -2875,7 +2879,7 @@ Режим доповідача apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -2883,7 +2887,7 @@ Захист конфіденційної інформації, такої як абсолютні показники та кількісні значення apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -2915,11 +2919,11 @@ Локалізація apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -2927,7 +2931,7 @@ Формат дати та чисел apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -2935,7 +2939,7 @@ Зовнішній вигляд apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -2943,7 +2947,7 @@ Світлий apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -2951,7 +2955,7 @@ Темний apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -2959,7 +2963,7 @@ Режим дзен apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -2971,7 +2975,7 @@ Досвід без відволікань для неспокійних часів apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -2987,7 +2991,7 @@ Біометрична аутентифікація apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -2995,7 +2999,7 @@ Увійти з відбитком пальця apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -3003,7 +3007,7 @@ Експериментальні функції apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -3011,7 +3015,7 @@ Попередній перегляд майбутніх функцій apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -3019,7 +3023,7 @@ Експортувати дані apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -3027,7 +3031,7 @@ Зона небезпеки apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -3035,7 +3039,7 @@ Закрити обліковий запис apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -3219,7 +3223,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -3319,7 +3323,7 @@ Ринкові дані apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -3371,11 +3375,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -3507,11 +3511,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -3527,7 +3531,7 @@ Оскільки ви вже ввійшли, ви не можете отримати доступ до демонстраційного обліковий запис. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3555,7 +3559,7 @@ Загальні apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -3563,7 +3567,7 @@ Хмара apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -3575,7 +3579,7 @@ Самохостинг apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -3696,7 +3700,7 @@ Програмне забезпечення з відкритим кодом apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -3708,7 +3712,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -3720,11 +3724,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3776,7 +3780,7 @@ Ринки apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3800,7 +3804,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -4192,7 +4196,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -4284,7 +4288,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -4308,7 +4312,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -4320,7 +4324,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -4388,7 +4392,7 @@ Оновити баланс готівки apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -4396,7 +4400,7 @@ Дата apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -4416,7 +4420,7 @@ Ціна за одиницю apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -4580,7 +4584,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -4672,7 +4676,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -4696,7 +4700,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -4704,7 +4708,7 @@ Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4716,7 +4720,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4728,7 +4732,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4788,7 +4792,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4804,7 +4808,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4812,11 +4816,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -4836,15 +4840,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -4852,7 +4856,7 @@ here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -4860,7 +4864,7 @@ Щомісячно apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -4868,7 +4872,7 @@ Щорічно apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -4876,7 +4880,7 @@ Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -4884,7 +4888,7 @@ Абсолютна прибутковість активів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -4892,7 +4896,7 @@ Прибутковість активів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -4900,7 +4904,7 @@ Абсолютна прибутковість валюти apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -4908,7 +4912,7 @@ Прибутковість валюти apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -4916,7 +4920,7 @@ Топ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -4924,7 +4928,7 @@ Низ apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -4932,7 +4936,7 @@ Еволюція портфеля apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -4940,7 +4944,7 @@ Інвестиційний графік apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -4948,7 +4952,7 @@ Поточна серія apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4956,7 +4960,7 @@ Найдовша серія apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4964,7 +4968,7 @@ Графік дивідендів apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -5180,7 +5184,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -5196,7 +5200,7 @@ Підтримка електронної пошти та чату apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -5204,7 +5208,7 @@ Разова оплата, без автоматичного поновлення. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 @@ -5212,11 +5216,11 @@ Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -5224,7 +5228,7 @@ Це безкоштовно. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -5256,7 +5260,7 @@ Континенти apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -5264,7 +5268,7 @@ Чи хотіли б ви удосконалити вашу особисту інвестиційну стратегію? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -5280,7 +5284,7 @@ Ghostfolio надає можливість вам стежити за вашим багатством. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -5320,7 +5324,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -5336,7 +5340,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -5431,7 +5435,7 @@ Швейцарія apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -5443,7 +5447,7 @@ Глобальний apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -5455,7 +5459,7 @@ Альтернатива apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -5463,7 +5467,7 @@ Додаток apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -5471,7 +5475,7 @@ Бюджетування apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -5487,47 +5491,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -5535,7 +5543,7 @@ Сімейний офіс apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -5543,7 +5551,7 @@ Інвестор apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -5555,7 +5563,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -5567,7 +5575,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -5575,7 +5583,7 @@ Конфіденційність apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -5583,7 +5591,7 @@ Програмне забезпечення apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -5591,7 +5599,7 @@ Інструмент apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -5599,7 +5607,7 @@ Користувацький досвід apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -5607,7 +5615,7 @@ Багатство apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -5615,7 +5623,7 @@ Управління багатством apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -5835,7 +5843,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -6007,7 +6015,7 @@ Членство apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -6023,7 +6031,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -6075,7 +6083,7 @@ Ви дійсно хочете видалити цей рахунок? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -6139,7 +6147,7 @@ Ви дійсно хочете видалити ці дії? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -6147,7 +6155,7 @@ Ви дійсно хочете видалити цю активність? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -6155,7 +6163,7 @@ Тиждень до дати libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -6163,11 +6171,11 @@ WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -6175,7 +6183,7 @@ Місяць до дати libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -6183,11 +6191,11 @@ MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -6195,7 +6203,7 @@ Рік до дати libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -6203,7 +6211,7 @@ рік apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6215,7 +6223,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6223,11 +6231,11 @@ роки apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6235,7 +6243,7 @@ Профілі активів apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -6311,7 +6319,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -6375,7 +6383,7 @@ Депозит libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -6387,11 +6395,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -6403,7 +6411,7 @@ Заощадження libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -6419,7 +6427,7 @@ Упс! Не вдалося отримати історичні дані. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -6427,11 +6435,11 @@ Розподіл libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -6447,7 +6455,7 @@ Показати все libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -6491,7 +6499,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -6499,7 +6507,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -6523,7 +6531,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -6531,7 +6539,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -6555,7 +6563,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6587,7 +6595,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6595,7 +6603,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6615,7 +6623,7 @@ Закрити apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6641,13 +6649,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6683,7 +6695,7 @@ Резервний фонд apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -6751,7 +6763,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -6770,6 +6782,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision Пенсійне накопичення @@ -6778,6 +6798,14 @@ 28 + + Everything in Basic, plus + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + Satellite Супутник @@ -6843,7 +6871,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -6859,7 +6887,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6895,7 +6923,7 @@ Комісія apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -6939,7 +6967,7 @@ Готівка apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -6995,7 +7023,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -7335,7 +7363,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -7343,11 +7371,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -7370,12 +7398,20 @@ 174 + + Change with currency effect + Change with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 + + AI prompt has been copied to the clipboard Запит AI скопійовано в буфер обміну apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7383,7 +7419,7 @@ Lazy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7391,7 +7427,7 @@ Instant apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7399,7 +7435,7 @@ Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7407,7 +7443,7 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7415,7 +7451,7 @@ Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7423,7 +7459,7 @@ HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7431,7 +7467,7 @@ end of day apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7439,7 +7475,7 @@ real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7447,7 +7483,7 @@ Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7463,11 +7499,11 @@ Change libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7483,15 +7519,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -7518,6 +7554,14 @@ 67 + + Total amount + Total amount + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia Armenia @@ -7587,7 +7631,7 @@ Security token apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7599,7 +7643,7 @@ Do you really want to generate a new security token for this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7607,7 +7651,7 @@ Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7672,7 +7716,7 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7680,7 +7724,7 @@ An error occurred while updating to (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7696,7 +7740,7 @@ with API access for apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7776,7 +7820,7 @@ Do you really want to delete this item? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7817,7 +7861,7 @@ Demo user account has been synced. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7852,7 +7896,7 @@ 150 - + Fee Ratio Fee Ratio @@ -7860,17 +7904,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7995,7 +8039,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8007,7 +8051,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8031,7 +8075,7 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8039,11 +8083,11 @@ new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8256,7 +8300,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8676,7 +8720,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.xlf b/apps/client/src/locales/messages.xlf index 6888369ab..7db54e0c4 100644 --- a/apps/client/src/locales/messages.xlf +++ b/apps/client/src/locales/messages.xlf @@ -203,7 +203,7 @@ The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term. apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -228,7 +228,7 @@ please apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -271,13 +271,6 @@ 87 - - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? @@ -297,7 +290,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -312,14 +305,14 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 Cash Balances apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -341,7 +334,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -353,7 +346,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -369,11 +362,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -385,7 +378,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -400,7 +393,7 @@ Total libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -411,7 +404,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -423,11 +416,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -442,15 +435,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -458,11 +451,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -474,7 +467,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -497,15 +490,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -528,11 +521,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -540,7 +537,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -555,7 +552,7 @@ Do you really want to delete this account? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -573,7 +570,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -592,7 +589,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -628,7 +625,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -677,7 +674,7 @@ Date apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -711,32 +708,25 @@ Currencies apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 - - - - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 + 95 ETFs without Countries apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 ETFs without Sectors apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -750,7 +740,7 @@ Filter by... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -769,7 +759,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -787,7 +777,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -833,7 +823,7 @@ Oops! Could not parse historical data. libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -862,7 +852,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -892,7 +882,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -903,7 +893,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -911,7 +901,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -922,7 +912,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -933,7 +923,7 @@ Symbol Mapping apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -947,14 +937,14 @@ Scraper Configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 Note apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -962,7 +952,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1002,35 +992,35 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 Do you really want to delete this coupon? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 Do you really want to delete this system message? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 Do you really want to flush the cache? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 Please set your system message: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -1139,11 +1129,11 @@ Url apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1158,14 +1148,21 @@ Asset profile has been saved apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 Do you really want to delete this platform? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 + + + + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 @@ -1186,7 +1183,7 @@ Current year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -1200,14 +1197,14 @@ Platforms apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 Tags apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1229,7 +1226,7 @@ Do you really want to delete this tag? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -1250,7 +1247,7 @@ Do you really want to delete this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -1283,7 +1280,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1311,11 +1308,11 @@ Could not validate form apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -1348,7 +1345,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -1359,7 +1356,7 @@ Benchmark apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1419,14 +1416,14 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 Manage Activities apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -1544,7 +1541,7 @@ Current week apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1562,7 +1559,7 @@ Total Amount apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1588,7 +1585,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -1631,7 +1628,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1667,7 +1664,7 @@ Absolute Gross Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1678,64 +1675,64 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 Absolute Net Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 Net Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 Total Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 Assets apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 Buying Power apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 Excluded from Analysis apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 Liabilities apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1746,14 +1743,14 @@ Net Worth apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 Annualized Performance apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1785,7 +1782,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1793,14 +1790,14 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 Report Data Glitch apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1829,7 +1826,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -1848,7 +1845,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -1863,7 +1860,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -1878,7 +1875,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -1889,7 +1886,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -1904,7 +1901,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -1957,7 +1954,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -1968,51 +1965,58 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 YTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 1Y apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 5Y apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 Max apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -2080,7 +2084,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2105,28 +2109,28 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 Do you really want to remove this sign in method? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 Presenter View apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 Protection for sensitive information like absolute performances and quantity values apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -2147,46 +2151,46 @@ Locale apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 Date and number format apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 Appearance apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 Light apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 Dark apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 Zen Mode apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -2197,7 +2201,7 @@ Distraction-free experience for turbulent times apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 @@ -2211,28 +2215,28 @@ Biometric Authentication apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 Sign in with fingerprint apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 Experimental Features apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 Sneak peek at upcoming functionality apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -2243,18 +2247,18 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 Export Data apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -2425,7 +2429,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2508,7 +2512,7 @@ Market Data apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -2557,11 +2561,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2683,11 +2687,11 @@ Could not parse scraper configuration apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -2701,7 +2705,7 @@ As you are already logged in, you cannot access the demo account. apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -2830,7 +2834,7 @@ Open Source Software apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -2841,7 +2845,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -2853,11 +2857,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -2906,7 +2910,7 @@ Markets apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -2930,7 +2934,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3097,6 +3101,13 @@ 172 + + Everything in Basic, plus + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + trading stocks, ETFs or cryptocurrencies on multiple platforms @@ -3262,7 +3273,7 @@ with your university e-mail address apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -3344,7 +3355,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3368,7 +3379,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3380,14 +3391,14 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 Do you really want to delete these activities? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3447,14 +3458,14 @@ Update Cash Balance apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 Unit Price apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3669,7 +3680,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -3691,14 +3702,14 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 Latest activities apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -3709,7 +3720,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -3720,7 +3731,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -3759,7 +3770,7 @@ Looking for a student discount? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -3774,7 +3785,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -3782,11 +3793,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -3804,70 +3815,70 @@ Deposit libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 Monthly apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 Yearly apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 Top apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 Bottom apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 Portfolio Evolution apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 Investment Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 Current Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 Longest Streak apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 Dividend Timeline apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -4027,7 +4038,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4041,7 +4052,7 @@ Email and Chat Support apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4056,32 +4067,32 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 One-time payment, no auto-renewal. apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 Could not save asset profile apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 It’s free. apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4095,7 +4106,7 @@ Continents apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -4109,7 +4120,7 @@ Ghostfolio empowers you to keep track of your wealth. apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4403,7 +4414,7 @@ Switzerland apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -4414,7 +4425,7 @@ Global apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -4448,7 +4459,7 @@ Membership apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -4463,7 +4474,7 @@ Request it apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -4509,7 +4520,7 @@ Do you really want to delete this account balance? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -4559,14 +4570,14 @@ Do you really want to delete this activity? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 Asset Profiles apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -4612,7 +4623,7 @@ contact us apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -4665,11 +4676,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -4680,18 +4691,18 @@ Savings libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 Allocation libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -4706,7 +4717,7 @@ Show all libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -4747,7 +4758,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -4755,7 +4766,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -4778,7 +4789,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -4786,7 +4797,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -4825,7 +4836,7 @@ Emergency Fund apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -4893,7 +4904,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -4903,6 +4914,13 @@ 27 + + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision @@ -4970,7 +4988,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -5002,7 +5020,7 @@ Fee apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5042,7 +5060,7 @@ Cash apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5085,7 +5103,7 @@ Authentication apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5211,7 +5229,7 @@ Valid until apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -5233,7 +5251,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5241,11 +5259,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5270,14 +5288,14 @@ The current market price is apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 Test apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5341,21 +5359,21 @@ Absolute Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 Close Holding apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 Absolute Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5370,79 +5388,79 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 here apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 Asset Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 Currency Performance apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 Year to date libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 Week to date libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 Month to date libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 MTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 WTD apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5474,7 +5492,7 @@ year apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -5486,18 +5504,18 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 years apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -5523,7 +5541,7 @@ Self-Hosting apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -5534,7 +5552,7 @@ Data Gathering apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -5545,14 +5563,14 @@ General apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 Cloud apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -5668,21 +5686,21 @@ Close Account apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 Do you really want to close your Ghostfolio account? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 Danger Zone apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -5710,14 +5728,14 @@ Include in apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 Oops! There was an error setting up biometric authentication. apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -5752,7 +5770,7 @@ Benchmarks apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -5773,14 +5791,14 @@ Would you like to refine your personal investment strategy? apps/client/src/app/pages/public/public-page.html - 234 + 233 Wealth apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -5795,47 +5813,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -5877,35 +5899,35 @@ User Experience apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 App apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 Tool apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 Investor apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 Wealth Management apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -5940,14 +5962,14 @@ Alternative apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 Family Office apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -5958,14 +5980,14 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 Software apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -5993,7 +6015,7 @@ Budgeting apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6011,7 +6033,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6046,7 +6068,7 @@ Privacy apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6067,7 +6089,7 @@ Error apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6078,7 +6100,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6110,7 +6132,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6118,7 +6140,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6129,7 +6151,7 @@ Role apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6157,7 +6179,7 @@ Close apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6183,13 +6205,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6256,7 +6282,7 @@ If you plan to open an account at apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6334,7 +6360,7 @@ to use our referral link and get a Ghostfolio Premium membership for one year apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -6435,7 +6461,7 @@ Set API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -6467,7 +6493,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -6494,7 +6520,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -6538,28 +6564,28 @@ of apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 Do you really want to delete the API key? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 Remove API key apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 daily requests apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -6584,7 +6610,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -6633,7 +6659,7 @@ Save apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6669,11 +6695,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -6705,14 +6731,21 @@ Please enter your Ghostfolio API key. apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 AI prompt has been copied to the clipboard apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -6726,63 +6759,63 @@ Mode apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 Default Market Price apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 Selector apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 Instant apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 Lazy apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 HTTP Request Headers apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 real-time apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 end of day apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 Open Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -6796,11 +6829,11 @@ Change libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -6815,15 +6848,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -6847,6 +6880,13 @@ 97 + + Total amount + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia @@ -6907,21 +6947,21 @@ Do you really want to generate a new security token for this user? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 Find account, holding or page... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 Security token apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -6983,14 +7023,14 @@ () is already in use. apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 An error occurred while updating to (). apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7004,7 +7044,7 @@ with API access for apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7054,7 +7094,7 @@ Do you really want to delete this item? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7098,7 +7138,7 @@ Demo user account has been synced. apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7122,22 +7162,22 @@ 150 - + Fee Ratio apps/client/src/app/pages/i18n/i18n-page.html 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7250,7 +7290,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -7261,7 +7301,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -7282,18 +7322,18 @@ Current month apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 new apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -7481,7 +7521,7 @@ Manage Asset Profile apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -7850,7 +7890,7 @@ Registration Date apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/locales/messages.zh.xlf b/apps/client/src/locales/messages.zh.xlf index 02f90631d..be465e9df 100644 --- a/apps/client/src/locales/messages.zh.xlf +++ b/apps/client/src/locales/messages.zh.xlf @@ -216,7 +216,7 @@ 交易存在巨大亏损风险,因此不应投入您短期内可能急需的资金。 apps/client/src/app/components/footer/footer.component.html - 171 + 182 @@ -244,7 +244,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 336 + 333 @@ -291,14 +291,6 @@ 87 - - plus - plus - - apps/client/src/app/pages/pricing/pricing-page.html - 202 - - Do you really want to revoke this granted access? 您真的要撤销此访问权限吗? @@ -320,7 +312,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 136 + 143 @@ -336,7 +328,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 86 + 93 @@ -344,7 +336,7 @@ 现金余额 apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 148 + 146 @@ -368,7 +360,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 309 + 310 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -380,7 +372,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 46 + 58 apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -396,11 +388,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 139 + 135 libs/ui/src/lib/accounts-table/accounts-table.component.html - 43 + 50 libs/ui/src/lib/activities-table/activities-table.component.html @@ -412,7 +404,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 28 + 23 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -428,7 +420,7 @@ 总计 libs/ui/src/lib/accounts-table/accounts-table.component.html - 55 + 62 @@ -440,7 +432,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 316 + 317 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -452,11 +444,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 145 + 141 libs/ui/src/lib/accounts-table/accounts-table.component.html - 65 + 72 libs/ui/src/lib/activities-table/activities-table.component.html @@ -472,15 +464,15 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 205 + 201 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 208 + 204 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 211 + 207 libs/ui/src/lib/account-balances/account-balances.component.html @@ -488,11 +480,11 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 171 + 178 libs/ui/src/lib/accounts-table/accounts-table.component.html - 206 + 213 libs/ui/src/lib/activities-table/activities-table.component.html @@ -504,7 +496,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 98 + 93 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -528,15 +520,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 74 + 78 apps/client/src/app/components/admin-tag/admin-tag.component.html - 67 + 71 libs/ui/src/lib/accounts-table/accounts-table.component.html - 313 + 320 libs/ui/src/lib/activities-table/activities-table.component.html @@ -560,11 +552,15 @@ apps/client/src/app/components/admin-platform/admin-platform.component.html - 85 + 89 apps/client/src/app/components/admin-tag/admin-tag.component.html - 78 + 82 + + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 22 libs/ui/src/lib/account-balances/account-balances.component.html @@ -572,7 +568,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 324 + 331 libs/ui/src/lib/activities-table/activities-table.component.html @@ -588,7 +584,7 @@ 您确定要删除此账户吗? libs/ui/src/lib/accounts-table/accounts-table.component.ts - 150 + 148 @@ -608,7 +604,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 448 + 451 @@ -628,7 +624,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 155 + 151 libs/ui/src/lib/i18n.ts @@ -668,7 +664,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 92 + 104 @@ -724,7 +720,7 @@ 日期 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 161 + 157 libs/ui/src/lib/account-balances/account-balances.component.html @@ -760,19 +756,11 @@ 货币 apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 132 + 131 apps/client/src/app/pages/public/public-page.html - 96 - - - - Everything in - Everything in - - apps/client/src/app/pages/pricing/pricing-page.html - 199 + 95 @@ -780,7 +768,7 @@ 没有国家的 ETF apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 137 + 136 @@ -788,7 +776,7 @@ 无行业类别的 ETF apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 142 + 141 @@ -804,7 +792,7 @@ 过滤... apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 386 + 390 @@ -824,7 +812,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 50 + 45 @@ -844,7 +832,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 44 + 40 @@ -880,7 +868,7 @@ 哎呀!无法解析历史数据。 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.ts - 263 + 284 @@ -904,7 +892,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor.component.html - 71 + 67 @@ -936,7 +924,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 53 + 72 @@ -948,7 +936,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 396 + 399 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -956,7 +944,7 @@ apps/client/src/app/pages/public/public-page.html - 114 + 113 @@ -968,7 +956,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 407 + 410 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -980,7 +968,7 @@ 代码映射 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 384 + 387 @@ -996,7 +984,7 @@ 刮削配置 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 471 + 474 @@ -1004,7 +992,7 @@ 笔记 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 432 + 435 apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html @@ -1012,7 +1000,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 275 + 271 @@ -1056,7 +1044,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 124 + 120 @@ -1064,7 +1052,7 @@ 您确实要删除此优惠券吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 194 + 193 @@ -1072,7 +1060,7 @@ 您真的要删除这条系统消息吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 207 + 206 @@ -1080,7 +1068,7 @@ 您真的要刷新缓存吗? apps/client/src/app/components/admin-overview/admin-overview.component.ts - 231 + 230 @@ -1088,7 +1076,7 @@ 请设置您的系统消息: apps/client/src/app/components/admin-overview/admin-overview.component.ts - 251 + 250 @@ -1212,11 +1200,11 @@ 网址 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 419 + 422 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 550 + 553 apps/client/src/app/components/admin-platform/admin-platform.component.html @@ -1229,10 +1217,10 @@ Asset profile has been saved - Asset profile has been saved + 资产概况已保存 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 579 + 594 @@ -1240,12 +1228,20 @@ 您真的要删除这个平台吗? apps/client/src/app/components/admin-platform/admin-platform.component.ts - 107 + 112 + + + + Explore + Explore + + apps/client/src/app/pages/resources/overview/resources-overview.component.html + 11 By - By + 预计到 apps/client/src/app/pages/portfolio/fire/fire-page.html 139 @@ -1264,7 +1260,7 @@ 当前年份 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 @@ -1280,7 +1276,7 @@ 平台 apps/client/src/app/components/admin-settings/admin-settings.component.html - 195 + 212 @@ -1288,7 +1284,7 @@ 标签 apps/client/src/app/components/admin-settings/admin-settings.component.html - 201 + 218 libs/ui/src/lib/tags-selector/tags-selector.component.html @@ -1312,7 +1308,7 @@ 您真的要删除此标签吗? apps/client/src/app/components/admin-tag/admin-tag.component.ts - 103 + 109 @@ -1336,7 +1332,7 @@ 您真的要删除该用户吗? apps/client/src/app/components/admin-users/admin-users.component.ts - 216 + 218 @@ -1357,7 +1353,7 @@ No auto-renewal on membership. - No auto-renewal on membership. + 会员资格不自动续订。 apps/client/src/app/components/user-account-membership/user-account-membership.html 74 @@ -1372,7 +1368,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 89 + 108 @@ -1401,14 +1397,14 @@ Could not validate form - Could not validate form + 无法验证表单 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 555 + 570 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 558 + 573 @@ -1444,7 +1440,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 94 + 95 libs/common/src/lib/routes/routes.ts @@ -1456,7 +1452,7 @@ 基准 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 376 + 379 apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts @@ -1520,7 +1516,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 192 + 193 @@ -1528,7 +1524,7 @@ 管理活动 apps/client/src/app/components/home-holdings/home-holdings.html - 67 + 65 @@ -1660,7 +1656,7 @@ 当前周 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 @@ -1680,7 +1676,7 @@ 总金额 apps/client/src/app/components/investment-chart/investment-chart.component.ts - 143 + 146 @@ -1708,7 +1704,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 279 + 288 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -1752,7 +1748,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 329 + 326 apps/client/src/app/pages/register/register-page.html @@ -1792,7 +1788,7 @@ 绝对总业绩 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 73 + 77 @@ -1804,7 +1800,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 88 + 92 @@ -1812,11 +1808,11 @@ 绝对净绩效 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 107 + 111 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 193 + 259 @@ -1824,11 +1820,11 @@ 净绩效 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 123 + 127 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 212 + 278 @@ -1836,7 +1832,7 @@ 总资产 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 149 + 153 @@ -1844,7 +1840,7 @@ 资产 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 226 + 233 @@ -1852,7 +1848,7 @@ 购买力 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 241 + 248 @@ -1860,7 +1856,7 @@ 从分析中排除 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 267 + 274 @@ -1868,7 +1864,7 @@ 负债 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 295 + 302 apps/client/src/app/pages/features/features-page.html @@ -1880,7 +1876,7 @@ 净值 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 317 + 324 @@ -1888,7 +1884,7 @@ 年化业绩 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 331 + 338 @@ -1924,7 +1920,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 189 + 185 libs/ui/src/lib/activities-table/activities-table.component.html @@ -1932,7 +1928,7 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 74 + 69 @@ -1940,7 +1936,7 @@ 报告数据故障 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 451 + 450 @@ -1972,7 +1968,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 207 + 204 @@ -1992,7 +1988,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 211 + 208 @@ -2008,7 +2004,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 215 + 212 @@ -2024,7 +2020,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 219 + 216 @@ -2036,7 +2032,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 223 + 220 @@ -2052,7 +2048,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 246 + 243 @@ -2108,7 +2104,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 284 + 281 @@ -2120,7 +2116,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 365 + 362 @@ -2128,11 +2124,11 @@ 年初至今 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 200 + 204 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -2140,11 +2136,11 @@ 1年 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -2152,11 +2148,19 @@ 5年 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 + + + + Performance with currency effect + 含货币影响的表现 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 135 @@ -2164,11 +2168,11 @@ 最大限度 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 212 + 216 libs/ui/src/lib/assistant/assistant.component.ts - 417 + 414 @@ -2244,7 +2248,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 268 + 265 @@ -2272,7 +2276,7 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 172 + 181 @@ -2280,7 +2284,7 @@ 您确实要删除此登录方法吗? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 281 + 282 @@ -2288,7 +2292,7 @@ 演示者视图 apps/client/src/app/components/user-account-settings/user-account-settings.html - 183 + 192 @@ -2296,7 +2300,7 @@ 保护绝对业绩、金额等敏感信息 apps/client/src/app/components/user-account-settings/user-account-settings.html - 185 + 194 @@ -2320,11 +2324,11 @@ 语言环境 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 509 + 512 apps/client/src/app/components/user-account-settings/user-account-settings.html - 133 + 142 @@ -2332,7 +2336,7 @@ 日期和数字格式 apps/client/src/app/components/user-account-settings/user-account-settings.html - 135 + 144 @@ -2340,7 +2344,7 @@ 外观 apps/client/src/app/components/user-account-settings/user-account-settings.html - 158 + 167 @@ -2348,7 +2352,7 @@ 明亮 apps/client/src/app/components/user-account-settings/user-account-settings.html - 173 + 182 @@ -2356,7 +2360,7 @@ 黑暗 apps/client/src/app/components/user-account-settings/user-account-settings.html - 174 + 183 @@ -2364,7 +2368,7 @@ 极简模式 apps/client/src/app/components/user-account-settings/user-account-settings.html - 201 + 210 apps/client/src/app/pages/features/features-page.html @@ -2376,12 +2380,12 @@ 动荡时期的无干扰体验 apps/client/src/app/components/user-account-settings/user-account-settings.html - 203 + 212 this is projected to increase to - this is projected to increase to + 预计将增至 apps/client/src/app/pages/portfolio/fire/fire-page.html 147 @@ -2392,7 +2396,7 @@ 生物识别认证 apps/client/src/app/components/user-account-settings/user-account-settings.html - 218 + 227 @@ -2400,7 +2404,7 @@ 使用指纹登录 apps/client/src/app/components/user-account-settings/user-account-settings.html - 219 + 228 @@ -2408,7 +2412,7 @@ 实验性功能 apps/client/src/app/components/user-account-settings/user-account-settings.html - 235 + 244 @@ -2416,7 +2420,7 @@ 预览即将推出的功能 apps/client/src/app/components/user-account-settings/user-account-settings.html - 237 + 246 @@ -2428,11 +2432,11 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 252 + 261 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 11 + 30 @@ -2440,7 +2444,7 @@ 导出数据 apps/client/src/app/components/user-account-settings/user-account-settings.html - 260 + 269 @@ -2624,7 +2628,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 66 + 85 apps/client/src/app/pages/accounts/accounts-page.html @@ -2716,7 +2720,7 @@ 市场数据 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 398 + 397 libs/common/src/lib/routes/routes.ts @@ -2768,11 +2772,11 @@ apps/client/src/app/pages/admin/admin-page.component.ts - 48 + 45 apps/client/src/app/pages/resources/resources-page.component.ts - 30 + 29 libs/common/src/lib/routes/routes.ts @@ -2893,14 +2897,14 @@ Could not parse scraper configuration - Could not parse scraper configuration + 无法解析抓取器配置 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 510 + 525 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 513 + 528 @@ -2916,7 +2920,7 @@ 由于您已经登录,因此无法访问模拟帐户。 apps/client/src/app/pages/demo/demo-page.component.ts - 35 + 32 @@ -3060,7 +3064,7 @@ 开源软件 apps/client/src/app/pages/features/features-page.html - 295 + 296 @@ -3072,7 +3076,7 @@ apps/client/src/app/pages/features/features-page.html - 320 + 321 apps/client/src/app/pages/landing/landing-page.html @@ -3084,11 +3088,11 @@ apps/client/src/app/pages/pricing/pricing-page.html - 363 + 360 apps/client/src/app/pages/public/public-page.html - 242 + 241 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -3140,7 +3144,7 @@ 市场 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 378 + 381 apps/client/src/app/components/footer/footer.component.html @@ -3164,7 +3168,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 40 + 39 libs/common/src/lib/routes/routes.ts @@ -3351,6 +3355,14 @@ 172 + + Everything in Basic, plus + 包含 Basic 所有功能,以及 + + apps/client/src/app/pages/pricing/pricing-page.html + 199 + + trading stocks, ETFs or cryptocurrencies on multiple platforms 在多个平台上交易股票、ETF 或加密货币 @@ -3540,7 +3552,7 @@ 使用您的学校电子邮件地址 apps/client/src/app/pages/pricing/pricing-page.html - 351 + 348 @@ -3632,7 +3644,7 @@ apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html - 115 + 113 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html @@ -3656,7 +3668,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 75 + 94 apps/client/src/app/pages/portfolio/activities/activities-page.html @@ -3668,7 +3680,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 119 + 126 @@ -3676,7 +3688,7 @@ 您确定要删除这些活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 278 + 282 @@ -3744,7 +3756,7 @@ 更新现金余额 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 112 + 108 @@ -3752,7 +3764,7 @@ 单价 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 214 + 210 libs/ui/src/lib/activities-table/activities-table.component.html @@ -3992,7 +4004,7 @@ apps/client/src/app/pages/public/public-page.html - 151 + 150 @@ -4016,7 +4028,7 @@ apps/client/src/app/pages/public/public-page.html - 168 + 167 @@ -4024,7 +4036,7 @@ 最新活动 apps/client/src/app/pages/public/public-page.html - 211 + 210 @@ -4036,7 +4048,7 @@ apps/client/src/app/pages/public/public-page.html - 177 + 176 @@ -4048,7 +4060,7 @@ apps/client/src/app/pages/public/public-page.html - 186 + 185 @@ -4092,7 +4104,7 @@ 寻找学生折扣? apps/client/src/app/pages/pricing/pricing-page.html - 345 + 342 @@ -4108,7 +4120,7 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 365 + 372 apps/client/src/app/pages/features/features-page.html @@ -4116,11 +4128,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 202 + 198 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 75 + 76 libs/ui/src/lib/i18n.ts @@ -4129,7 +4141,7 @@ annual interest rate - annual interest rate + 年利率 apps/client/src/app/pages/portfolio/fire/fire-page.html 185 @@ -4140,7 +4152,7 @@ 存款 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 377 + 390 @@ -4148,7 +4160,7 @@ 每月 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 90 + 91 @@ -4156,7 +4168,7 @@ 每年 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 91 + 92 @@ -4164,7 +4176,7 @@ 顶部 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 239 + 305 @@ -4172,7 +4184,7 @@ 底部 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 288 + 354 @@ -4180,7 +4192,7 @@ 投资组合演变 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 341 + 407 @@ -4188,7 +4200,7 @@ 投资时间表 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 368 + 434 @@ -4196,7 +4208,7 @@ 当前连胜 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 389 + 455 @@ -4204,7 +4216,7 @@ 最长连续纪录 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 398 + 464 @@ -4212,7 +4224,7 @@ 股息时间表 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 425 + 491 @@ -4361,7 +4373,7 @@ Free - 自由的 + 免费 apps/client/src/app/pages/pricing/pricing-page.html 86 @@ -4388,7 +4400,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 255 + 252 @@ -4404,7 +4416,7 @@ 电子邮件和聊天支持 apps/client/src/app/pages/pricing/pricing-page.html - 251 + 248 @@ -4420,7 +4432,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 282 + 279 @@ -4428,19 +4440,19 @@ 一次性付款,无自动续订。 apps/client/src/app/pages/pricing/pricing-page.html - 288 + 285 Could not save asset profile - Could not save asset profile + 无法保存资产概况 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 589 + 604 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 592 + 607 @@ -4448,7 +4460,7 @@ 免费。 apps/client/src/app/pages/pricing/pricing-page.html - 365 + 362 @@ -4464,7 +4476,7 @@ 大陆 apps/client/src/app/pages/public/public-page.html - 132 + 131 @@ -4480,7 +4492,7 @@ Ghostfolio 使您能够跟踪您的财富。 apps/client/src/app/pages/public/public-page.html - 238 + 237 @@ -4805,7 +4817,7 @@ 瑞士 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 57 + 58 libs/ui/src/lib/i18n.ts @@ -4817,7 +4829,7 @@ 全球的 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 58 + 59 libs/ui/src/lib/i18n.ts @@ -4853,7 +4865,7 @@ 会员资格 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 48 + 67 libs/common/src/lib/routes/routes.ts @@ -4869,7 +4881,7 @@ 请求它 apps/client/src/app/pages/pricing/pricing-page.html - 347 + 344 @@ -4921,7 +4933,7 @@ 您确实要删除该帐户余额吗? libs/ui/src/lib/account-balances/account-balances.component.ts - 120 + 113 @@ -4977,7 +4989,7 @@ 您确实要删除此活动吗? libs/ui/src/lib/activities-table/activities-table.component.ts - 288 + 292 @@ -4985,7 +4997,7 @@ 资产概况 apps/client/src/app/components/admin-settings/admin-settings.component.html - 106 + 123 libs/ui/src/lib/assistant/assistant.html @@ -5037,7 +5049,7 @@ 联系我们 apps/client/src/app/pages/pricing/pricing-page.html - 339 + 336 @@ -5097,11 +5109,11 @@ apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 352 + 359 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 387 + 400 libs/ui/src/lib/i18n.ts @@ -5113,7 +5125,7 @@ 储蓄 libs/ui/src/lib/fire-calculator/fire-calculator.component.ts - 397 + 410 @@ -5121,11 +5133,11 @@ 分配 libs/ui/src/lib/accounts-table/accounts-table.component.html - 241 + 248 libs/ui/src/lib/holdings-table/holdings-table.component.html - 122 + 117 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5141,7 +5153,7 @@ 显示所有 libs/ui/src/lib/holdings-table/holdings-table.component.html - 221 + 212 @@ -5185,7 +5197,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 326 + 327 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5193,7 +5205,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 290 + 286 libs/ui/src/lib/i18n.ts @@ -5217,7 +5229,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 342 + 343 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html @@ -5225,7 +5237,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 309 + 305 libs/ui/src/lib/i18n.ts @@ -5269,7 +5281,7 @@ 应急基金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 164 + 168 apps/client/src/app/pages/features/features-page.html @@ -5345,7 +5357,7 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 437 + 449 @@ -5356,6 +5368,14 @@ 27 + + No Activities + No Activities + + apps/client/src/app/components/admin-market-data/admin-market-data.component.ts + 146 + + Retirement Provision 退休金 @@ -5429,7 +5449,7 @@ libs/ui/src/lib/accounts-table/accounts-table.component.html - 307 + 314 @@ -5442,7 +5462,7 @@ Sign in with OpenID Connect - Sign in with OpenID Connect + 使用 OpenID Connect 登录 apps/client/src/app/components/login-with-access-token-dialog/login-with-access-token-dialog.html 55 @@ -5465,7 +5485,7 @@ 费用 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 262 + 258 libs/ui/src/lib/activities-table/activities-table.component.html @@ -5509,7 +5529,7 @@ 现金 apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html - 212 + 219 libs/ui/src/lib/i18n.ts @@ -5554,10 +5574,10 @@ Authentication - Authentication + 认证 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 35 + 54 @@ -5701,7 +5721,7 @@ 有效期至 apps/client/src/app/components/admin-settings/admin-settings.component.html - 74 + 86 libs/ui/src/lib/membership-card/membership-card.component.html @@ -5725,7 +5745,7 @@ apps/client/src/app/pages/public/public-page.html - 196 + 195 libs/ui/src/lib/benchmark/benchmark.component.html @@ -5733,11 +5753,11 @@ libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 439 + 451 libs/ui/src/lib/portfolio-proportion-chart/portfolio-proportion-chart.component.ts - 452 + 465 libs/ui/src/lib/top-holdings/top-holdings.component.html @@ -5765,7 +5785,7 @@ 当前市场价格为 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 707 + 722 @@ -5773,7 +5793,7 @@ 测试 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 568 + 571 @@ -5845,7 +5865,7 @@ 绝对货币表现 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 145 + 211 @@ -5853,7 +5873,7 @@ 关闭持仓 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 442 + 441 @@ -5861,7 +5881,7 @@ 绝对资产回报 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 102 + 168 @@ -5877,15 +5897,15 @@ apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 80 + 81 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 96 + 97 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 88 + 89 @@ -5893,7 +5913,7 @@ 这里 apps/client/src/app/pages/pricing/pricing-page.html - 350 + 347 @@ -5901,7 +5921,7 @@ 资产回报 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 124 + 190 @@ -5909,7 +5929,7 @@ 货币表现 apps/client/src/app/pages/portfolio/analysis/analysis-page.html - 170 + 236 @@ -5917,7 +5937,7 @@ 今年迄今为止 libs/ui/src/lib/assistant/assistant.component.ts - 377 + 374 @@ -5925,7 +5945,7 @@ 本周至今 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5933,7 +5953,7 @@ 本月至今 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5941,11 +5961,11 @@ 本月至今 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 libs/ui/src/lib/assistant/assistant.component.ts - 373 + 370 @@ -5953,11 +5973,11 @@ 本周至今 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 192 + 196 libs/ui/src/lib/assistant/assistant.component.ts - 369 + 366 @@ -5993,7 +6013,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 204 + 208 apps/client/src/app/pages/resources/personal-finance-tools/product-page.html @@ -6005,7 +6025,7 @@ libs/ui/src/lib/assistant/assistant.component.ts - 387 + 384 @@ -6013,11 +6033,11 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 208 + 212 libs/ui/src/lib/assistant/assistant.component.ts - 411 + 408 @@ -6046,7 +6066,7 @@ 自托管 apps/client/src/app/pages/faq/faq-page.component.ts - 60 + 52 libs/common/src/lib/routes/routes.ts @@ -6058,7 +6078,7 @@ 数据收集 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 587 + 594 apps/client/src/app/components/admin-overview/admin-overview.html @@ -6070,7 +6090,7 @@ 一般的 apps/client/src/app/pages/faq/faq-page.component.ts - 49 + 41 @@ -6078,7 +6098,7 @@ apps/client/src/app/pages/faq/faq-page.component.ts - 54 + 46 libs/common/src/lib/routes/routes.ts @@ -6210,7 +6230,7 @@ 您确定要关闭您的 Ghostfolio 账户吗? apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 207 + 208 @@ -6218,7 +6238,7 @@ 危险区域 apps/client/src/app/components/user-account-settings/user-account-settings.html - 272 + 281 @@ -6226,7 +6246,7 @@ 关闭账户 apps/client/src/app/components/user-account-settings/user-account-settings.html - 307 + 316 @@ -6258,7 +6278,7 @@ 包含在 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 374 + 377 @@ -6266,7 +6286,7 @@ 哎呀!设置生物识别认证时发生错误。 apps/client/src/app/components/user-account-settings/user-account-settings.component.ts - 335 + 336 @@ -6282,7 +6302,7 @@ 基准 apps/client/src/app/components/admin-market-data/admin-market-data.component.ts - 127 + 126 @@ -6330,7 +6350,7 @@ 您想 优化 您的 个人投资策略吗? apps/client/src/app/pages/public/public-page.html - 234 + 233 @@ -6338,7 +6358,7 @@ 另类 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 82 + 83 @@ -6346,7 +6366,7 @@ 应用 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 83 + 84 @@ -6354,7 +6374,7 @@ 预算管理 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 84 + 85 @@ -6370,47 +6390,51 @@ apps/client/src/app/components/user-account-settings/user-account-settings.html - 90 + 91 apps/client/src/app/components/user-account-settings/user-account-settings.html - 94 + 95 apps/client/src/app/components/user-account-settings/user-account-settings.html - 98 + 99 apps/client/src/app/components/user-account-settings/user-account-settings.html - 102 + 103 apps/client/src/app/components/user-account-settings/user-account-settings.html - 106 + 109 apps/client/src/app/components/user-account-settings/user-account-settings.html - 110 + 114 apps/client/src/app/components/user-account-settings/user-account-settings.html - 114 + 118 apps/client/src/app/components/user-account-settings/user-account-settings.html - 118 + 122 apps/client/src/app/components/user-account-settings/user-account-settings.html - 123 + 126 + + + apps/client/src/app/components/user-account-settings/user-account-settings.html + 132 apps/client/src/app/pages/features/features-page.html - 276 + 277 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 85 + 86 @@ -6418,7 +6442,7 @@ 家族办公室 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 86 + 87 @@ -6426,7 +6450,7 @@ 投资者 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 89 + 90 @@ -6438,7 +6462,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 90 + 91 @@ -6450,7 +6474,7 @@ apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 92 + 93 @@ -6458,7 +6482,7 @@ 隐私 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 93 + 94 @@ -6466,7 +6490,7 @@ 软件 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 95 + 96 @@ -6474,7 +6498,7 @@ 工具 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 96 + 97 @@ -6482,7 +6506,7 @@ 用户体验 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 97 + 98 @@ -6490,7 +6514,7 @@ 财富 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 98 + 99 @@ -6498,7 +6522,7 @@ 财富管理 apps/client/src/app/pages/resources/personal-finance-tools/product-page.component.ts - 99 + 100 @@ -6658,7 +6682,7 @@ 错误 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 698 + 713 @@ -6687,7 +6711,7 @@ , based on your total assets of - 基于您总资产的 + 基于您总资产的 apps/client/src/app/pages/portfolio/fire/fire-page.html 96 @@ -6710,7 +6734,7 @@ apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 592 + 599 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6742,7 +6766,7 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 345 + 341 apps/client/src/app/pages/register/user-account-registration-dialog/user-account-registration-dialog.html @@ -6750,7 +6774,7 @@ libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 46 + 47 libs/ui/src/lib/i18n.ts @@ -6762,7 +6786,7 @@ 关闭 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 594 + 601 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -6788,13 +6812,17 @@ apps/client/src/app/components/user-account-access/create-or-update-access-dialog/create-or-update-access-dialog.html 68 + + apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html + 127 + apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html 107 apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 347 + 343 libs/ui/src/lib/i18n.ts @@ -6806,7 +6834,7 @@ 角色 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 14 + 33 @@ -6846,7 +6874,7 @@ 如果您计划开通账户在 apps/client/src/app/pages/pricing/pricing-page.html - 315 + 312 @@ -6947,7 +6975,7 @@ , assuming a - , assuming a + , 假设一个 apps/client/src/app/pages/portfolio/fire/fire-page.html 174 @@ -6958,7 +6986,7 @@ 使用我们的推荐链接并获得一年的Ghostfolio Premium会员资格 apps/client/src/app/pages/pricing/pricing-page.html - 343 + 340 @@ -7062,7 +7090,7 @@ 设置 API 密钥 apps/client/src/app/components/admin-settings/admin-settings.component.html - 171 + 188 @@ -7098,7 +7126,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 45 + 44 libs/common/src/lib/routes/routes.ts @@ -7114,7 +7142,7 @@ apps/client/src/app/pages/resources/resources-page.component.ts - 34 + 33 libs/common/src/lib/routes/routes.ts @@ -7168,7 +7196,7 @@ apps/client/src/app/components/admin-settings/admin-settings.component.html - 135 + 152 @@ -7176,7 +7204,7 @@ 每日请求 apps/client/src/app/components/admin-settings/admin-settings.component.html - 137 + 154 @@ -7184,7 +7212,7 @@ 移除 API 密钥 apps/client/src/app/components/admin-settings/admin-settings.component.html - 161 + 178 @@ -7192,7 +7220,7 @@ 您确定要删除此 API 密钥吗? apps/client/src/app/components/admin-settings/admin-settings.component.ts - 128 + 133 @@ -7212,7 +7240,7 @@ apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 98 + 117 @@ -7284,7 +7312,7 @@ 保存 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 603 + 610 apps/client/src/app/components/admin-market-data/create-asset-profile-dialog/create-asset-profile-dialog.html @@ -7320,11 +7348,11 @@ apps/client/src/app/pages/portfolio/activities/create-or-update-activity-dialog/create-or-update-activity-dialog.html - 356 + 352 libs/ui/src/lib/historical-market-data-editor/historical-market-data-editor-dialog/historical-market-data-editor-dialog.html - 48 + 49 @@ -7360,7 +7388,15 @@ 请输入您的 Ghostfolio API 密钥。 apps/client/src/app/components/admin-settings/admin-settings.component.ts - 147 + 152 + + + + Change with currency effect + 含货币影响的涨跌 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 116 @@ -7368,7 +7404,7 @@ AI 提示已复制到剪贴板 apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 199 + 201 @@ -7384,7 +7420,7 @@ 延迟 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7392,7 +7428,7 @@ 即时 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7400,7 +7436,7 @@ 默认市场价格 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 481 + 484 @@ -7408,7 +7444,7 @@ 模式 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 518 + 521 @@ -7416,7 +7452,7 @@ 选择器 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 534 + 537 @@ -7424,7 +7460,7 @@ HTTP 请求标头 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.html - 494 + 497 @@ -7432,7 +7468,7 @@ 收盘 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 226 + 230 @@ -7440,7 +7476,7 @@ 实时 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 230 + 234 @@ -7448,7 +7484,7 @@ 打开 Duck.ai apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts - 200 + 202 @@ -7464,11 +7500,11 @@ 涨跌 libs/ui/src/lib/holdings-table/holdings-table.component.html - 143 + 138 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 @@ -7484,15 +7520,15 @@ libs/ui/src/lib/holdings-table/holdings-table.component.html - 166 + 161 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 368 + 375 libs/ui/src/lib/treemap-chart/treemap-chart.component.ts - 381 + 388 @@ -7519,6 +7555,14 @@ 67 + + Total amount + 总金额 + + apps/client/src/app/pages/portfolio/analysis/analysis-page.html + 95 + + Armenia 亚美尼亚 @@ -7588,7 +7632,7 @@ 安全令牌 apps/client/src/app/components/admin-users/admin-users.component.ts - 237 + 239 apps/client/src/app/components/user-account-access/user-account-access.component.ts @@ -7600,7 +7644,7 @@ 您确定要为此用户生成新的安全令牌吗? apps/client/src/app/components/admin-users/admin-users.component.ts - 242 + 244 @@ -7608,7 +7652,7 @@ 查找账户、持仓或页面... libs/ui/src/lib/assistant/assistant.component.ts - 153 + 115 @@ -7673,7 +7717,7 @@ () 已在使用中。 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 634 + 649 @@ -7681,7 +7725,7 @@ 在更新到 () 时发生错误。 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 642 + 657 @@ -7697,7 +7741,7 @@ 包含 API 访问权限,适用于 apps/client/src/app/pages/pricing/pricing-page.html - 238 + 235 @@ -7777,7 +7821,7 @@ 您确定要删除此项目吗? libs/ui/src/lib/benchmark/benchmark.component.ts - 139 + 144 @@ -7818,7 +7862,7 @@ 演示用户账户已同步。 apps/client/src/app/components/admin-overview/admin-overview.component.ts - 275 + 274 @@ -7853,7 +7897,7 @@ 150 - + Fee Ratio 费率 @@ -7861,17 +7905,17 @@ 152 - - The fees do exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - 费用超过了您初始投资的 ${thresholdMax}% (${feeRatio}%) + + The fees do exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + 费用已超过您总投资金额的 ${thresholdMax}%(${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 154 - - The fees do not exceed ${thresholdMax}% of your initial investment (${feeRatio}%) - 费用未超过您初始投资的 ${thresholdMax}% (${feeRatio}%) + + The fees do not exceed ${thresholdMax}% of your total investment volume (${feeRatio}%) + 费用未超过您总投资金额的 ${thresholdMax}%(${feeRatio}%) apps/client/src/app/pages/i18n/i18n-page.html 158 @@ -7996,7 +8040,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 297 + 294 @@ -8008,7 +8052,7 @@ apps/client/src/app/pages/pricing/pricing-page.html - 300 + 297 @@ -8032,7 +8076,7 @@ 当前月份 apps/client/src/app/components/admin-market-data/asset-profile-dialog/asset-profile-dialog.component.ts - 196 + 200 @@ -8040,11 +8084,11 @@ 新增 apps/client/src/app/components/admin-settings/admin-settings.component.html - 67 + 79 apps/client/src/app/pages/admin/admin-page.component.ts - 56 + 53 @@ -8257,7 +8301,7 @@ 管理资产概况 apps/client/src/app/components/holding-detail-dialog/holding-detail-dialog.html - 466 + 465 @@ -8677,7 +8721,7 @@ 注册日期 apps/client/src/app/components/user-detail-dialog/user-detail-dialog.html - 26 + 45 diff --git a/apps/client/src/main.ts b/apps/client/src/main.ts index c15703645..f596de5f4 100644 --- a/apps/client/src/main.ts +++ b/apps/client/src/main.ts @@ -1,5 +1,6 @@ import { InfoResponse } from '@ghostfolio/common/interfaces'; import { filterGlobalPermissions } from '@ghostfolio/common/permissions'; +import { GF_ENVIRONMENT } from '@ghostfolio/ui/environment'; import { GfNotificationModule } from '@ghostfolio/ui/notifications'; import { Platform } from '@angular/cdk/platform'; @@ -89,6 +90,10 @@ import { environment } from './environments/environment'; provide: DateAdapter, useClass: CustomDateAdapter }, + { + provide: GF_ENVIRONMENT, + useValue: environment + }, { provide: MAT_DATE_FORMATS, useValue: DateFormats diff --git a/apps/client/src/styles.scss b/apps/client/src/styles.scss index b7a031bfa..142d2ea53 100644 --- a/apps/client/src/styles.scss +++ b/apps/client/src/styles.scss @@ -2,7 +2,7 @@ @import './styles/table'; @import './styles/variables'; -@import 'svgmap/dist/svgMap'; +@import 'svgmap/style.min'; :root { --dark-background: rgb(25, 25, 25); diff --git a/eslint.config.cjs b/eslint.config.cjs index 5962e261d..76d627d18 100644 --- a/eslint.config.cjs +++ b/eslint.config.cjs @@ -28,9 +28,7 @@ module.exports = [ onlyDependOnLibsWithTags: ['*'] } ], - enforceBuildableLibDependency: true, - // Temporary fix, should be removed eventually - ignoredCircularDependencies: [['client', 'ui']] + enforceBuildableLibDependency: true } ], '@typescript-eslint/no-extra-semi': 'error', diff --git a/libs/common/eslint.config.cjs b/libs/common/eslint.config.cjs index a78dde897..990c264b4 100644 --- a/libs/common/eslint.config.cjs +++ b/libs/common/eslint.config.cjs @@ -18,7 +18,9 @@ module.exports = [ { files: ['**/*.ts', '**/*.tsx'], // Override or add rules here - rules: {} + rules: { + '@typescript-eslint/prefer-nullish-coalescing': 'error' + } }, { files: ['**/*.js', '**/*.jsx'], diff --git a/libs/common/src/lib/calculation-helper.ts b/libs/common/src/lib/calculation-helper.ts index d67384a30..2097fa52a 100644 --- a/libs/common/src/lib/calculation-helper.ts +++ b/libs/common/src/lib/calculation-helper.ts @@ -9,7 +9,7 @@ import { subDays, subYears } from 'date-fns'; -import { isNumber } from 'lodash'; +import { isFinite, isNumber } from 'lodash'; import { resetHours } from './helper'; import { DateRange } from './types'; @@ -28,7 +28,7 @@ export function getAnnualizedPerformancePercent({ exponent ); - if (!isNaN(growthFactor)) { + if (isFinite(growthFactor)) { return new Big(growthFactor).minus(1); } } @@ -36,14 +36,16 @@ export function getAnnualizedPerformancePercent({ return new Big(0); } -export function getIntervalFromDateRange( - aDateRange: DateRange, - portfolioStart = new Date(0) -) { - let endDate = endOfDay(new Date()); - let startDate = portfolioStart; +export function getIntervalFromDateRange(params: { + dateRange: DateRange; + endDate?: Date; + startDate?: Date; +}) { + const { dateRange } = params; + let endDate = params.endDate ?? endOfDay(new Date()); + let startDate = params.startDate ?? new Date(0); - switch (aDateRange) { + switch (dateRange) { case '1d': startDate = max([startDate, subDays(resetHours(new Date()), 1)]); break; @@ -75,8 +77,8 @@ export function getIntervalFromDateRange( break; default: // '2024', '2023', '2022', etc. - endDate = endOfYear(new Date(aDateRange)); - startDate = max([startDate, new Date(aDateRange)]); + endDate = endOfYear(new Date(dateRange)); + startDate = max([startDate, new Date(dateRange)]); } return { endDate, startDate }; diff --git a/libs/common/src/lib/chart-helper.ts b/libs/common/src/lib/chart-helper.ts index 697f39467..1f385e901 100644 --- a/libs/common/src/lib/chart-helper.ts +++ b/libs/common/src/lib/chart-helper.ts @@ -1,4 +1,13 @@ -import { Chart, TooltipPosition } from 'chart.js'; +import type { ElementRef } from '@angular/core'; +import type { + Chart, + ChartType, + ControllerDatasetOptions, + Plugin, + Point, + TooltipOptions, + TooltipPosition +} from 'chart.js'; import { format } from 'date-fns'; import { @@ -15,7 +24,7 @@ export function formatGroupedDate({ date, groupBy }: { - date: Date; + date: number; groupBy: GroupBy; }) { if (groupBy === 'month') { @@ -27,47 +36,55 @@ export function formatGroupedDate({ return format(date, DATE_FORMAT); } -export function getTooltipOptions({ +export function getTooltipOptions({ colorScheme, currency = '', groupBy, locale = getLocale(), unit = '' }: { - colorScheme?: ColorScheme; + colorScheme: ColorScheme; currency?: string; groupBy?: GroupBy; locale?: string; unit?: string; -} = {}) { +}): Partial> { return { backgroundColor: getBackgroundColor(colorScheme), bodyColor: `rgb(${getTextColor(colorScheme)})`, borderWidth: 1, borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`, + // @ts-expect-error: no need to set all attributes in callbacks callbacks: { label: (context) => { - let label = context.dataset.label || ''; + let label = (context.dataset as ControllerDatasetOptions).label ?? ''; + if (label) { label += ': '; } - if (context.parsed.y !== null) { + + const yPoint = (context.parsed as Point).y; + + if (yPoint !== null) { if (currency) { - label += `${context.parsed.y.toLocaleString(locale, { + label += `${yPoint.toLocaleString(locale, { maximumFractionDigits: 2, minimumFractionDigits: 2 })} ${currency}`; } else if (unit) { - label += `${context.parsed.y.toFixed(2)} ${unit}`; + label += `${yPoint.toFixed(2)} ${unit}`; } else { - label += context.parsed.y.toFixed(2); + label += yPoint.toFixed(2); } } + return label; }, title: (contexts) => { - if (groupBy) { - return formatGroupedDate({ groupBy, date: contexts[0].parsed.x }); + const xPoint = (contexts[0].parsed as Point).x; + + if (groupBy && xPoint !== null) { + return formatGroupedDate({ groupBy, date: xPoint }); } return contexts[0].label; @@ -92,16 +109,17 @@ export function getTooltipPositionerMapTop( if (!position || !chart?.chartArea) { return false; } + return { x: position.x, y: chart.chartArea.top }; } -export function getVerticalHoverLinePlugin( - chartCanvas, - colorScheme?: ColorScheme -) { +export function getVerticalHoverLinePlugin( + chartCanvas: ElementRef, + colorScheme: ColorScheme +): Plugin { return { afterDatasetsDraw: (chart, _, options) => { const active = chart.getActiveElements(); @@ -110,8 +128,8 @@ export function getVerticalHoverLinePlugin( return; } - const color = options.color || `rgb(${getTextColor(colorScheme)})`; - const width = options.width || 1; + const color = options.color ?? `rgb(${getTextColor(colorScheme)})`; + const width = options.width ?? 1; const { chartArea: { bottom, top } @@ -119,13 +137,16 @@ export function getVerticalHoverLinePlugin( const xValue = active[0].element.x; const context = chartCanvas.nativeElement.getContext('2d'); - context.lineWidth = width; - context.strokeStyle = color; - context.beginPath(); - context.moveTo(xValue, top); - context.lineTo(xValue, bottom); - context.stroke(); + if (context) { + context.lineWidth = width; + context.strokeStyle = color; + + context.beginPath(); + context.moveTo(xValue, top); + context.lineTo(xValue, bottom); + context.stroke(); + } }, id: 'verticalHoverLine' }; diff --git a/libs/common/src/lib/class-transformer.ts b/libs/common/src/lib/class-transformer.ts index 328e2bf9e..60e0eab60 100644 --- a/libs/common/src/lib/class-transformer.ts +++ b/libs/common/src/lib/class-transformer.ts @@ -16,7 +16,7 @@ export function transformToMapOfBig({ return mapOfBig; } -export function transformToBig({ value }: { value: string }): Big { +export function transformToBig({ value }: { value: string }): Big | null { if (value === null) { return null; } diff --git a/libs/common/src/lib/config.ts b/libs/common/src/lib/config.ts index 169ab80c1..08fa2f030 100644 --- a/libs/common/src/lib/config.ts +++ b/libs/common/src/lib/config.ts @@ -51,6 +51,14 @@ export const ASSET_CLASS_MAPPING = new Map([ [AssetClass.REAL_ESTATE, []] ]); +export const BULL_BOARD_COOKIE_NAME = 'bull_board_token'; + +/** + * WARNING: This route is mirrored in `apps/client/proxy.conf.json`. + * If you update this value, you must also update the proxy configuration. + */ +export const BULL_BOARD_ROUTE = '/admin/queues'; + export const CACHE_TTL_NO_CACHE = 1; export const CACHE_TTL_INFINITE = 0; @@ -78,6 +86,63 @@ 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_REDACTED_PATHS = [ + 'accounts[*].balance', + 'accounts[*].balanceInBaseCurrency', + 'accounts[*].comment', + 'accounts[*].dividendInBaseCurrency', + 'accounts[*].interestInBaseCurrency', + 'accounts[*].value', + 'accounts[*].valueInBaseCurrency', + 'activities[*].account.balance', + 'activities[*].account.comment', + 'activities[*].comment', + 'activities[*].fee', + 'activities[*].feeInAssetProfileCurrency', + 'activities[*].feeInBaseCurrency', + 'activities[*].quantity', + 'activities[*].SymbolProfile.symbolMapping', + 'activities[*].SymbolProfile.watchedByCount', + 'activities[*].value', + 'activities[*].valueInBaseCurrency', + 'balance', + 'balanceInBaseCurrency', + 'balances[*].account.balance', + 'balances[*].account.comment', + 'balances[*].value', + 'balances[*].valueInBaseCurrency', + 'comment', + 'dividendInBaseCurrency', + 'feeInBaseCurrency', + 'grossPerformance', + 'grossPerformanceWithCurrencyEffect', + 'historicalData[*].quantity', + 'holdings[*].dividend', + 'holdings[*].grossPerformance', + 'holdings[*].grossPerformanceWithCurrencyEffect', + 'holdings[*].holdings[*].valueInBaseCurrency', + 'holdings[*].investment', + 'holdings[*].netPerformance', + 'holdings[*].netPerformanceWithCurrencyEffect', + 'holdings[*].quantity', + 'holdings[*].valueInBaseCurrency', + 'interestInBaseCurrency', + 'investmentInBaseCurrencyWithCurrencyEffect', + 'netPerformance', + 'netPerformanceWithCurrencyEffect', + 'platforms[*].balance', + 'platforms[*].valueInBaseCurrency', + 'quantity', + 'SymbolProfile.symbolMapping', + 'SymbolProfile.watchedByCount', + 'totalBalanceInBaseCurrency', + 'totalDividendInBaseCurrency', + 'totalInterestInBaseCurrency', + 'totalValueInBaseCurrency', + 'value', + 'valueInBaseCurrency' +]; + // USX is handled separately export const DERIVED_CURRENCIES = [ { @@ -147,6 +212,7 @@ export const PROPERTY_BETTER_UPTIME_MONITOR_ID = 'BETTER_UPTIME_MONITOR_ID'; export const PROPERTY_COUNTRIES_OF_SUBSCRIBERS = 'COUNTRIES_OF_SUBSCRIBERS'; export const PROPERTY_COUPONS = 'COUPONS'; export const PROPERTY_CURRENCIES = 'CURRENCIES'; +export const PROPERTY_CUSTOM_CRYPTOCURRENCIES = 'CUSTOM_CRYPTOCURRENCIES'; export const PROPERTY_DATA_SOURCE_MAPPING = 'DATA_SOURCE_MAPPING'; export const PROPERTY_DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS = 'DATA_SOURCES_GHOSTFOLIO_DATA_PROVIDER_MAX_REQUESTS'; @@ -193,6 +259,7 @@ export const SUPPORTED_LANGUAGE_CODES = [ 'es', 'fr', 'it', + 'ko', 'nl', 'pl', 'pt', diff --git a/libs/common/src/lib/dtos/create-asset-profile.dto.ts b/libs/common/src/lib/dtos/create-asset-profile.dto.ts index 80d45ba42..85ad73cc0 100644 --- a/libs/common/src/lib/dtos/create-asset-profile.dto.ts +++ b/libs/common/src/lib/dtos/create-asset-profile.dto.ts @@ -5,7 +5,6 @@ import { IsArray, IsBoolean, IsEnum, - IsObject, IsOptional, IsString, IsUrl @@ -66,10 +65,6 @@ export class CreateAssetProfileDto { @IsString() name?: string; - @IsObject() - @IsOptional() - scraperConfiguration?: Prisma.InputJsonObject; - @IsArray() @IsOptional() sectors?: Prisma.InputJsonArray; @@ -77,12 +72,6 @@ export class CreateAssetProfileDto { @IsString() symbol: string; - @IsObject() - @IsOptional() - symbolMapping?: { - [dataProvider: string]: string; - }; - @IsOptional() @IsUrl({ protocols: ['https'], diff --git a/libs/common/src/lib/helper.spec.ts b/libs/common/src/lib/helper.spec.ts index 25779cf39..a339c6dab 100644 --- a/libs/common/src/lib/helper.spec.ts +++ b/libs/common/src/lib/helper.spec.ts @@ -25,7 +25,7 @@ describe('Helper', () => { it('Get decimal number with group (dot notation)', () => { expect( - extractNumberFromString({ locale: 'de-CH', value: '99’999.99' }) + extractNumberFromString({ locale: 'de-CH', value: `99'999.99` }) ).toEqual(99999.99); }); @@ -54,12 +54,12 @@ describe('Helper', () => { }); it('Get de-CH number format group', () => { - expect(getNumberFormatGroup('de-CH')).toEqual('’'); + expect(getNumberFormatGroup('de-CH')).toEqual(`'`); }); it('Get de-CH number format group when it is default', () => { languageGetter.mockReturnValue('de-CH'); - expect(getNumberFormatGroup()).toEqual('’'); + expect(getNumberFormatGroup()).toEqual(`'`); }); it('Get de-DE number format group', () => { diff --git a/libs/common/src/lib/helper.ts b/libs/common/src/lib/helper.ts index 7452b604c..4db1fcf2d 100644 --- a/libs/common/src/lib/helper.ts +++ b/libs/common/src/lib/helper.ts @@ -11,7 +11,21 @@ import { parseISO, subDays } from 'date-fns'; -import { ca, de, es, fr, it, nl, pl, pt, tr, uk, zhCN } from 'date-fns/locale'; +import { + ca, + de, + es, + fr, + it, + ko, + nl, + pl, + pt, + tr, + uk, + zhCN +} from 'date-fns/locale'; +import { get, isNil, isString } from 'lodash'; import { DEFAULT_CURRENCY, @@ -130,7 +144,7 @@ export function extractNumberFromString({ }: { locale?: string; value: string; -}): number { +}): number | undefined { try { // Remove non-numeric characters (excluding international formatting characters) const numericValue = value.replace(/[^\d.,'’\s]/g, ''); @@ -184,6 +198,8 @@ export function getDateFnsLocale(aLanguageCode: string) { return fr; } else if (aLanguageCode === 'it') { return it; + } else if (aLanguageCode === 'ko') { + return ko; } else if (aLanguageCode === 'nl') { return nl; } else if (aLanguageCode === 'pl') { @@ -207,8 +223,8 @@ export function getDateFormatString(aLocale?: string) { ); return formatObject - .map((object) => { - switch (object.type) { + .map(({ type, value }) => { + switch (type) { case 'day': return 'dd'; case 'month': @@ -216,7 +232,7 @@ export function getDateFormatString(aLocale?: string) { case 'year': return 'yyyy'; default: - return object.value; + return value; } }) .join(''); @@ -242,12 +258,22 @@ export function getLocale() { return navigator.language ?? locale; } +export function getLowercase(object: object, path: string) { + const value = get(object, path); + + if (isNil(value)) { + return ''; + } + + return isString(value) ? value.toLocaleLowerCase() : value; +} + export function getNumberFormatDecimal(aLocale?: string) { const formatObject = new Intl.NumberFormat(aLocale).formatToParts(9999.99); - return formatObject.find((object) => { - return object.type === 'decimal'; - }).value; + return formatObject.find(({ type }) => { + return type === 'decimal'; + })?.value; } export function getNumberFormatGroup(aLocale = getLocale()) { @@ -255,9 +281,9 @@ export function getNumberFormatGroup(aLocale = getLocale()) { useGrouping: true }).formatToParts(9999.99); - return formatObject.find((object) => { - return object.type === 'group'; - }).value; + return formatObject.find(({ type }) => { + return type === 'group'; + })?.value; } export function getStartOfUtcDate(aDate: Date) { @@ -368,7 +394,7 @@ export function isRootCurrency(aCurrency: string) { }); } -export function parseDate(date: string): Date { +export function parseDate(date: string): Date | undefined { if (!date) { return undefined; } diff --git a/libs/common/src/lib/interfaces/activities.interface.ts b/libs/common/src/lib/interfaces/activities.interface.ts index 8c88cc2cf..b9e64984b 100644 --- a/libs/common/src/lib/interfaces/activities.interface.ts +++ b/libs/common/src/lib/interfaces/activities.interface.ts @@ -8,7 +8,7 @@ export interface Activity extends Order { error?: ActivityError; feeInAssetProfileCurrency: number; feeInBaseCurrency: number; - SymbolProfile?: EnhancedSymbolProfile; + SymbolProfile: EnhancedSymbolProfile; tagIds?: string[]; tags?: Tag[]; unitPriceInAssetProfileCurrency: number; diff --git a/libs/common/src/lib/interfaces/admin-data.interface.ts b/libs/common/src/lib/interfaces/admin-data.interface.ts index 23821a86b..dd25b516d 100644 --- a/libs/common/src/lib/interfaces/admin-data.interface.ts +++ b/libs/common/src/lib/interfaces/admin-data.interface.ts @@ -1,12 +1,12 @@ import { DataProviderInfo } from './data-provider-info.interface'; export interface AdminData { + activitiesCount: number; dataProviders: (DataProviderInfo & { assetProfileCount: number; useForExchangeRates: boolean; })[]; settings: { [key: string]: boolean | object | string | string[] }; - transactionCount: number; userCount: number; version: string; } diff --git a/libs/common/src/lib/interfaces/index.ts b/libs/common/src/lib/interfaces/index.ts index 7cf93691c..ad747d94e 100644 --- a/libs/common/src/lib/interfaces/index.ts +++ b/libs/common/src/lib/interfaces/index.ts @@ -34,7 +34,6 @@ import type { PortfolioPerformance } from './portfolio-performance.interface'; import type { PortfolioPosition } from './portfolio-position.interface'; import type { PortfolioReportRule } from './portfolio-report-rule.interface'; import type { PortfolioSummary } from './portfolio-summary.interface'; -import type { Position } from './position.interface'; import type { Product } from './product'; import type { AccessTokenResponse } from './responses/access-token-response.interface'; import type { AccountBalancesResponse } from './responses/account-balances-response.interface'; @@ -172,7 +171,6 @@ export { PortfolioReportResponse, PortfolioReportRule, PortfolioSummary, - Position, Product, PublicKeyCredentialCreationOptionsJSON, PublicKeyCredentialRequestOptionsJSON, diff --git a/libs/common/src/lib/interfaces/info-item.interface.ts b/libs/common/src/lib/interfaces/info-item.interface.ts index 119a94a7c..01897c066 100644 --- a/libs/common/src/lib/interfaces/info-item.interface.ts +++ b/libs/common/src/lib/interfaces/info-item.interface.ts @@ -1,4 +1,4 @@ -import { Platform, SymbolProfile } from '@prisma/client'; +import { SymbolProfile } from '@prisma/client'; import { Statistics } from './statistics.interface'; import { SubscriptionOffer } from './subscription-offer.interface'; @@ -13,10 +13,6 @@ export interface InfoItem { globalPermissions: string[]; isDataGatheringEnabled?: string; isReadOnlyMode?: boolean; - - /** @deprecated */ - platforms: Platform[]; - statistics: Statistics; subscriptionOffer?: SubscriptionOffer; } diff --git a/libs/common/src/lib/interfaces/lookup-item.interface.ts b/libs/common/src/lib/interfaces/lookup-item.interface.ts index fa91ed690..6cedeca09 100644 --- a/libs/common/src/lib/interfaces/lookup-item.interface.ts +++ b/libs/common/src/lib/interfaces/lookup-item.interface.ts @@ -7,7 +7,7 @@ export interface LookupItem { assetSubClass: AssetSubClass; currency: string; dataProviderInfo: DataProviderInfo; - dataSource: DataSource; + dataSource: DataSource | null; name: string; symbol: string; } diff --git a/libs/common/src/lib/interfaces/portfolio-performance.interface.ts b/libs/common/src/lib/interfaces/portfolio-performance.interface.ts index c0c3802d8..0698004d5 100644 --- a/libs/common/src/lib/interfaces/portfolio-performance.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-performance.interface.ts @@ -7,4 +7,5 @@ export interface PortfolioPerformance { netPerformancePercentageWithCurrencyEffect: number; netPerformanceWithCurrencyEffect: number; totalInvestment: number; + totalInvestmentValueWithCurrencyEffect: number; } diff --git a/libs/common/src/lib/interfaces/portfolio-position.interface.ts b/libs/common/src/lib/interfaces/portfolio-position.interface.ts index e277ba468..c4ef2e3dc 100644 --- a/libs/common/src/lib/interfaces/portfolio-position.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-position.interface.ts @@ -3,18 +3,52 @@ import { Market, MarketAdvanced } from '@ghostfolio/common/types'; import { AssetClass, AssetSubClass, DataSource, Tag } from '@prisma/client'; import { Country } from './country.interface'; +import { EnhancedSymbolProfile } from './enhanced-symbol-profile.interface'; import { Holding } from './holding.interface'; import { Sector } from './sector.interface'; export interface PortfolioPosition { + activitiesCount: number; allocationInPercentage: number; + + /** @deprecated */ assetClass?: AssetClass; + + /** @deprecated */ assetClassLabel?: string; + + assetProfile: Pick< + EnhancedSymbolProfile, + | 'assetClass' + | 'assetSubClass' + | 'countries' + | 'currency' + | 'dataSource' + | 'holdings' + | 'name' + | 'sectors' + | 'symbol' + | 'url' + > & { + assetClassLabel?: string; + assetSubClassLabel?: string; + }; + + /** @deprecated */ assetSubClass?: AssetSubClass; + + /** @deprecated */ assetSubClassLabel?: string; + + /** @deprecated */ countries: Country[]; + + /** @deprecated */ currency: string; + + /** @deprecated */ dataSource: DataSource; + dateOfFirstActivity: Date; dividend: number; exchange?: string; @@ -22,25 +56,38 @@ export interface PortfolioPosition { grossPerformancePercent: number; grossPerformancePercentWithCurrencyEffect: number; grossPerformanceWithCurrencyEffect: number; + + /** @deprecated */ holdings: Holding[]; + investment: number; marketChange?: number; marketChangePercent?: number; marketPrice: number; markets?: { [key in Market]: number }; marketsAdvanced?: { [key in MarketAdvanced]: number }; + + /** @deprecated */ name: string; + netPerformance: number; netPerformancePercent: number; netPerformancePercentWithCurrencyEffect: number; netPerformanceWithCurrencyEffect: number; quantity: number; + + /** @deprecated */ sectors: Sector[]; + + /** @deprecated */ symbol: string; + tags?: Tag[]; - transactionCount: number; type?: string; + + /** @deprecated */ url?: string; + valueInBaseCurrency?: number; valueInPercentage?: number; } diff --git a/libs/common/src/lib/interfaces/portfolio-summary.interface.ts b/libs/common/src/lib/interfaces/portfolio-summary.interface.ts index ccf94dcf7..8db6b39bb 100644 --- a/libs/common/src/lib/interfaces/portfolio-summary.interface.ts +++ b/libs/common/src/lib/interfaces/portfolio-summary.interface.ts @@ -6,7 +6,6 @@ export interface PortfolioSummary extends PortfolioPerformance { annualizedPerformancePercent: number; annualizedPerformancePercentWithCurrencyEffect: number; cash: number; - committedFunds: number; dateOfFirstActivity: Date; dividendInBaseCurrency: number; emergencyFund: { diff --git a/libs/common/src/lib/interfaces/position.interface.ts b/libs/common/src/lib/interfaces/position.interface.ts deleted file mode 100644 index d1f74380b..000000000 --- a/libs/common/src/lib/interfaces/position.interface.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { MarketState } from '@ghostfolio/common/types'; - -import { AssetClass, AssetSubClass, DataSource } from '@prisma/client'; - -export interface Position { - assetClass: AssetClass; - assetSubClass: AssetSubClass; - averagePrice: number; - currency: string; - dataSource: DataSource; - firstBuyDate: string; - grossPerformance?: number; - grossPerformancePercentage?: number; - investment: number; - investmentInOriginalCurrency?: number; - marketPrice?: number; - marketState?: MarketState; - name?: string; - netPerformance?: number; - netPerformancePercentage?: number; - netPerformancePercentageWithCurrencyEffect?: number; - netPerformanceWithCurrencyEffect?: number; - quantity: number; - symbol: string; - transactionCount: number; - url?: string; -} diff --git a/libs/common/src/lib/interfaces/responses/accounts-response.interface.ts b/libs/common/src/lib/interfaces/responses/accounts-response.interface.ts index 0a6af978f..90f1303e0 100644 --- a/libs/common/src/lib/interfaces/responses/accounts-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/accounts-response.interface.ts @@ -2,9 +2,9 @@ import { AccountWithValue } from '@ghostfolio/common/types'; export interface AccountsResponse { accounts: AccountWithValue[]; + activitiesCount: number; totalBalanceInBaseCurrency: number; totalDividendInBaseCurrency: number; totalInterestInBaseCurrency: number; totalValueInBaseCurrency: number; - transactionCount: number; } diff --git a/libs/common/src/lib/interfaces/responses/create-stripe-checkout-session-response.interface.ts b/libs/common/src/lib/interfaces/responses/create-stripe-checkout-session-response.interface.ts index 1222ac6e9..8ac1a8279 100644 --- a/libs/common/src/lib/interfaces/responses/create-stripe-checkout-session-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/create-stripe-checkout-session-response.interface.ts @@ -1,6 +1,3 @@ export interface CreateStripeCheckoutSessionResponse { - /** @deprecated */ - sessionId: string; - sessionUrl: string; } diff --git a/libs/common/src/lib/interfaces/responses/export-response.interface.ts b/libs/common/src/lib/interfaces/responses/export-response.interface.ts index 8b1697ca4..fa592faf2 100644 --- a/libs/common/src/lib/interfaces/responses/export-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/export-response.interface.ts @@ -27,7 +27,12 @@ export interface ExportResponse { > & { dataSource: DataSource; date: string; symbol: string })[]; assetProfiles: (Omit< SymbolProfile, - 'createdAt' | 'id' | 'updatedAt' | 'userId' + | 'createdAt' + | 'id' + | 'scraperConfiguration' + | 'symbolMapping' + | 'updatedAt' + | 'userId' > & { marketData: MarketData[]; })[]; diff --git a/libs/common/src/lib/interfaces/responses/portfolio-holding-response.interface.ts b/libs/common/src/lib/interfaces/responses/portfolio-holding-response.interface.ts index 31f027ee9..76bc7dc02 100644 --- a/libs/common/src/lib/interfaces/responses/portfolio-holding-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/portfolio-holding-response.interface.ts @@ -1,5 +1,4 @@ import { - Activity, Benchmark, DataProviderInfo, EnhancedSymbolProfile, @@ -9,15 +8,14 @@ import { import { Tag } from '@prisma/client'; export interface PortfolioHoldingResponse { - activities: Activity[]; activitiesCount: number; averagePrice: number; dataProviderInfo: DataProviderInfo; + dateOfFirstActivity: string; dividendInBaseCurrency: number; dividendYieldPercent: number; dividendYieldPercentWithCurrencyEffect: number; feeInBaseCurrency: number; - firstBuyDate: string; grossPerformance: number; grossPerformancePercent: number; grossPerformancePercentWithCurrencyEffect: number; diff --git a/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts b/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts index cb06800be..eae14cec6 100644 --- a/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts +++ b/libs/common/src/lib/interfaces/responses/public-portfolio-response.interface.ts @@ -14,16 +14,31 @@ export interface PublicPortfolioResponse extends PublicPortfolioResponseV1 { [symbol: string]: Pick< PortfolioPosition, | 'allocationInPercentage' + + /** @deprecated */ | 'assetClass' + | 'assetProfile' + + /** @deprecated */ | 'countries' | 'currency' + + /** @deprecated */ | 'dataSource' | 'dateOfFirstActivity' | 'markets' + + /** @deprecated */ | 'name' | 'netPerformancePercentWithCurrencyEffect' + + /** @deprecated */ | 'sectors' + + /** @deprecated */ | 'symbol' + + /** @deprecated */ | 'url' | 'valueInBaseCurrency' | 'valueInPercentage' @@ -39,7 +54,7 @@ export interface PublicPortfolioResponse extends PublicPortfolioResponseV1 { })[]; markets: { [key in Market]: Pick< - PortfolioDetails['markets'][key], + NonNullable[key], 'id' | 'valueInPercentage' >; }; diff --git a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts index bdef3e169..60a76d468 100644 --- a/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts +++ b/libs/common/src/lib/interfaces/x-ray-rules-settings.interface.ts @@ -9,7 +9,7 @@ export interface XRayRulesSettings { EconomicMarketClusterRiskDevelopedMarkets?: RuleSettings; EconomicMarketClusterRiskEmergingMarkets?: RuleSettings; EmergencyFundSetup?: RuleSettings; - FeeRatioInitialInvestment?: RuleSettings; + FeeRatioTotalInvestmentVolume?: RuleSettings; RegionalMarketClusterRiskAsiaPacific?: RuleSettings; RegionalMarketClusterRiskEmergingMarkets?: RuleSettings; RegionalMarketClusterRiskEurope?: RuleSettings; diff --git a/libs/common/src/lib/models/timeline-position.ts b/libs/common/src/lib/models/timeline-position.ts index f683c0951..13f9001d5 100644 --- a/libs/common/src/lib/models/timeline-position.ts +++ b/libs/common/src/lib/models/timeline-position.ts @@ -9,12 +9,15 @@ import { Big } from 'big.js'; import { Transform, Type } from 'class-transformer'; export class TimelinePosition { + activitiesCount: number; + @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) averagePrice: Big; currency: string; dataSource: DataSource; + dateOfFirstActivity: string; @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) @@ -32,8 +35,6 @@ export class TimelinePosition { @Type(() => Big) feeInBaseCurrency: Big; - firstBuyDate: string; - @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) grossPerformance: Big; @@ -50,6 +51,8 @@ export class TimelinePosition { @Type(() => Big) grossPerformanceWithCurrencyEffect: Big; + includeInTotalAssetValue?: boolean; + @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) investment: Big; @@ -90,8 +93,6 @@ export class TimelinePosition { @Type(() => Big) timeWeightedInvestmentWithCurrencyEffect: Big; - transactionCount: number; - @Transform(transformToBig, { toClassOnly: true }) @Type(() => Big) valueInBaseCurrency: Big; diff --git a/libs/common/src/lib/permissions.ts b/libs/common/src/lib/permissions.ts index cb4eb175b..a70e61bac 100644 --- a/libs/common/src/lib/permissions.ts +++ b/libs/common/src/lib/permissions.ts @@ -4,15 +4,16 @@ import { Role } from '@prisma/client'; export const permissions = { accessAdminControl: 'accessAdminControl', + accessAdminControlBullBoard: 'accessAdminControlBullBoard', accessAssistant: 'accessAssistant', accessHoldingsChart: 'accessHoldingsChart', createAccess: 'createAccess', createAccount: 'createAccount', createAccountBalance: 'createAccountBalance', + createActivity: 'createActivity', createApiKey: 'createApiKey', createMarketData: 'createMarketData', createMarketDataOfOwnAssetProfile: 'createMarketDataOfOwnAssetProfile', - createOrder: 'createOrder', createOwnTag: 'createOwnTag', createPlatform: 'createPlatform', createTag: 'createTag', @@ -21,8 +22,8 @@ export const permissions = { deleteAccess: 'deleteAccess', deleteAccount: 'deleteAccount', deleteAccountBalance: 'deleteAccountBalance', + deleteActivity: 'deleteActivity', deleteAuthDevice: 'deleteAuthDevice', - deleteOrder: 'deleteOrder', deleteOwnUser: 'deleteOwnUser', deletePlatform: 'deletePlatform', deleteTag: 'deleteTag', @@ -53,10 +54,10 @@ export const permissions = { toggleReadOnlyMode: 'toggleReadOnlyMode', updateAccount: 'updateAccount', updateAccess: 'updateAccess', + updateActivity: 'updateActivity', updateAuthDevice: 'updateAuthDevice', updateMarketData: 'updateMarketData', updateMarketDataOfOwnAssetProfile: 'updateMarketDataOfOwnAssetProfile', - updateOrder: 'updateOrder', updateOwnAccessToken: 'updateOwnAccessToken', updatePlatform: 'updatePlatform', updateTag: 'updateTag', @@ -74,19 +75,19 @@ export function getPermissions(aRole: Role): string[] { permissions.createAccess, permissions.createAccount, permissions.createAccountBalance, + permissions.createActivity, permissions.createWatchlistItem, permissions.deleteAccountBalance, permissions.deleteWatchlistItem, permissions.createMarketData, permissions.createMarketDataOfOwnAssetProfile, - permissions.createOrder, permissions.createOwnTag, permissions.createPlatform, permissions.createTag, permissions.deleteAccess, permissions.deleteAccount, + permissions.deleteActivity, permissions.deleteAuthDevice, - permissions.deleteOrder, permissions.deletePlatform, permissions.deleteTag, permissions.deleteUser, @@ -99,10 +100,10 @@ export function getPermissions(aRole: Role): string[] { permissions.readWatchlist, permissions.updateAccount, permissions.updateAccess, + permissions.updateActivity, permissions.updateAuthDevice, permissions.updateMarketData, permissions.updateMarketDataOfOwnAssetProfile, - permissions.updateOrder, permissions.updatePlatform, permissions.updateTag, permissions.updateUserSettings, @@ -125,15 +126,15 @@ export function getPermissions(aRole: Role): string[] { permissions.createAccess, permissions.createAccount, permissions.createAccountBalance, + permissions.createActivity, permissions.createMarketDataOfOwnAssetProfile, - permissions.createOrder, permissions.createOwnTag, permissions.createWatchlistItem, permissions.deleteAccess, permissions.deleteAccount, permissions.deleteAccountBalance, + permissions.deleteActivity, permissions.deleteAuthDevice, - permissions.deleteOrder, permissions.deleteWatchlistItem, permissions.readAiPrompt, permissions.readMarketDataOfOwnAssetProfile, @@ -141,9 +142,9 @@ export function getPermissions(aRole: Role): string[] { permissions.readWatchlist, permissions.updateAccount, permissions.updateAccess, + permissions.updateActivity, permissions.updateAuthDevice, permissions.updateMarketDataOfOwnAssetProfile, - permissions.updateOrder, permissions.updateUserSettings, permissions.updateViewMode ]; diff --git a/libs/common/src/lib/personal-finance-tools.ts b/libs/common/src/lib/personal-finance-tools.ts index 6d0a85fb2..063b4254c 100644 --- a/libs/common/src/lib/personal-finance-tools.ts +++ b/libs/common/src/lib/personal-finance-tools.ts @@ -33,6 +33,15 @@ export const personalFinanceTools: Product[] = [ origin: 'Switzerland', slogan: 'Simplicity for Complex Wealth' }, + { + founded: 2018, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'altruist', + name: 'Altruist', + origin: 'United States', + slogan: 'The wealth platform built for independent advisors' + }, { founded: 2023, hasFreePlan: false, @@ -116,6 +125,17 @@ export const personalFinanceTools: Product[] = [ origin: 'Switzerland', slogan: 'Schweizer Budget App für einfache & smarte Budgetplanung' }, + { + founded: 2015, + hasFreePlan: true, + hasSelfHostingAbility: false, + key: 'boldin', + name: 'Boldin', + note: 'Originally named as NewRetirement', + origin: 'United States', + pricingPerYear: '$144', + slogan: 'Take control with retirement planning tools that begin with you' + }, { key: 'budgetpulse', name: 'BudgetPulse', @@ -841,6 +861,16 @@ export const personalFinanceTools: Product[] = [ pricingPerYear: '$108', slogan: 'Build Financial Plans You Love.' }, + { + founded: 2022, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'prostocktracker', + name: 'Pro Stock Tracker', + origin: 'United Kingdom', + pricingPerYear: '$60', + slogan: 'The stock portfolio tracker built for long-term investors' + }, { founded: 2015, hasSelfHostingAbility: false, @@ -1014,6 +1044,16 @@ export const personalFinanceTools: Product[] = [ regions: ['Austria', 'Germany', 'Switzerland'], slogan: 'Dein Vermögen immer im Blick' }, + { + founded: 2025, + hasFreePlan: false, + hasSelfHostingAbility: false, + key: 'turbobulls', + name: 'Turbobulls', + origin: 'Romania', + pricingPerYear: '€39.99', + slogan: 'Your complete financial dashboard. Actually private.' + }, { hasFreePlan: true, hasSelfHostingAbility: false, diff --git a/libs/common/src/lib/routes/interfaces/internal-route.interface.ts b/libs/common/src/lib/routes/interfaces/internal-route.interface.ts index 02f205979..f08cf8b5c 100644 --- a/libs/common/src/lib/routes/interfaces/internal-route.interface.ts +++ b/libs/common/src/lib/routes/interfaces/internal-route.interface.ts @@ -2,7 +2,7 @@ import { User } from '@ghostfolio/common/interfaces'; export interface InternalRoute { excludeFromAssistant?: boolean | ((aUser: User) => boolean); - path: string; + path?: string; routerLink: string[]; subRoutes?: Record; title: string; diff --git a/libs/common/src/lib/types/account-with-value.type.ts b/libs/common/src/lib/types/account-with-value.type.ts index 08af86454..23cb14749 100644 --- a/libs/common/src/lib/types/account-with-value.type.ts +++ b/libs/common/src/lib/types/account-with-value.type.ts @@ -1,12 +1,12 @@ import { Account as AccountModel, Platform } from '@prisma/client'; export type AccountWithValue = AccountModel & { + activitiesCount: number; allocationInPercentage: number; balanceInBaseCurrency: number; dividendInBaseCurrency: number; interestInBaseCurrency: number; platform?: Platform; - transactionCount: number; value: number; valueInBaseCurrency: number; }; diff --git a/libs/common/src/lib/types/market-data-preset.type.ts b/libs/common/src/lib/types/market-data-preset.type.ts index 0dbf914fa..2622feac3 100644 --- a/libs/common/src/lib/types/market-data-preset.type.ts +++ b/libs/common/src/lib/types/market-data-preset.type.ts @@ -2,4 +2,5 @@ export type MarketDataPreset = | 'BENCHMARKS' | 'CURRENCIES' | 'ETF_WITHOUT_COUNTRIES' - | 'ETF_WITHOUT_SECTORS'; + | 'ETF_WITHOUT_SECTORS' + | 'NO_ACTIVITIES'; diff --git a/libs/common/src/lib/utils/form.util.ts b/libs/common/src/lib/utils/form.util.ts index 425aa4699..b510e6215 100644 --- a/libs/common/src/lib/utils/form.util.ts +++ b/libs/common/src/lib/utils/form.util.ts @@ -29,7 +29,7 @@ export async function validateObjectForForm({ if (formControl) { formControl.setErrors({ - validationError: Object.values(constraints)[0] + validationError: Object.values(constraints ?? {})[0] }); } @@ -37,7 +37,7 @@ export async function validateObjectForForm({ if (formControlInCustomCurrency) { formControlInCustomCurrency.setErrors({ - validationError: Object.values(constraints)[0] + validationError: Object.values(constraints ?? {})[0] }); } } diff --git a/libs/common/src/lib/validators/is-currency-code.ts b/libs/common/src/lib/validators/is-currency-code.ts index 76c6f4fe2..52d99816b 100644 --- a/libs/common/src/lib/validators/is-currency-code.ts +++ b/libs/common/src/lib/validators/is-currency-code.ts @@ -9,7 +9,7 @@ import { import { isISO4217CurrencyCode } from 'class-validator'; export function IsCurrencyCode(validationOptions?: ValidationOptions) { - return function (object: Object, propertyName: string) { + return function (object: object, propertyName: string) { registerDecorator({ propertyName, constraints: [], diff --git a/libs/common/tsconfig.json b/libs/common/tsconfig.json index a14e0fc44..2b4603b71 100644 --- a/libs/common/tsconfig.json +++ b/libs/common/tsconfig.json @@ -12,6 +12,7 @@ ], "compilerOptions": { "module": "preserve", - "lib": ["dom", "es2022"] + "lib": ["dom", "es2022"], + "strictNullChecks": true } } diff --git a/libs/ui/src/lib/account-balances/account-balances.component.html b/libs/ui/src/lib/account-balances/account-balances.component.html index caef922ed..29037a985 100644 --- a/libs/ui/src/lib/account-balances/account-balances.component.html +++ b/libs/ui/src/lib/account-balances/account-balances.component.html @@ -12,7 +12,7 @@ Date
    + Name @@ -102,7 +114,12 @@ - + Asset Profiles @@ -193,13 +210,13 @@

    Platforms

    - +

    Tags

    - +
    diff --git a/apps/client/src/app/components/admin-settings/admin-settings.component.ts b/apps/client/src/app/components/admin-settings/admin-settings.component.ts index cabf4e589..d030abb82 100644 --- a/apps/client/src/app/components/admin-settings/admin-settings.component.ts +++ b/apps/client/src/app/components/admin-settings/admin-settings.component.ts @@ -1,8 +1,6 @@ import { GfAdminPlatformComponent } from '@ghostfolio/client/components/admin-platform/admin-platform.component'; import { GfAdminTagComponent } from '@ghostfolio/client/components/admin-tag/admin-tag.component'; import { GfDataProviderStatusComponent } from '@ghostfolio/client/components/data-provider-status/data-provider-status.component'; -import { AdminService } from '@ghostfolio/client/services/admin.service'; -import { DataService } from '@ghostfolio/client/services/data.service'; import { UserService } from '@ghostfolio/client/services/user/user.service'; import { PROPERTY_API_KEY_GHOSTFOLIO } from '@ghostfolio/common/config'; import { ConfirmationDialogType } from '@ghostfolio/common/enums'; @@ -16,6 +14,7 @@ import { publicRoutes } from '@ghostfolio/common/routes/routes'; import { GfEntityLogoComponent } from '@ghostfolio/ui/entity-logo'; import { NotificationService } from '@ghostfolio/ui/notifications'; import { GfPremiumIndicatorComponent } from '@ghostfolio/ui/premium-indicator'; +import { AdminService, DataService } from '@ghostfolio/ui/services'; import { GfValueComponent } from '@ghostfolio/ui/value'; import { CommonModule } from '@angular/common'; @@ -23,20 +22,24 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, - OnDestroy, - OnInit + DestroyRef, + OnInit, + ViewChild } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { MatButtonModule } from '@angular/material/button'; import { MatCardModule } from '@angular/material/card'; import { MatMenuModule } from '@angular/material/menu'; import { MatProgressBarModule } from '@angular/material/progress-bar'; +import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatTableDataSource, MatTableModule } from '@angular/material/table'; import { RouterModule } from '@angular/router'; import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { ellipsisHorizontal, trashOutline } from 'ionicons/icons'; +import { get } from 'lodash'; import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader'; -import { catchError, filter, of, Subject, takeUntil } from 'rxjs'; +import { catchError, filter, of } from 'rxjs'; @Component({ changeDetection: ChangeDetectionStrategy.OnPush, @@ -53,6 +56,7 @@ import { catchError, filter, of, Subject, takeUntil } from 'rxjs'; MatCardModule, MatMenuModule, MatProgressBarModule, + MatSortModule, MatTableModule, NgxSkeletonLoaderModule, RouterModule @@ -61,7 +65,9 @@ import { catchError, filter, of, Subject, takeUntil } from 'rxjs'; styleUrls: ['./admin-settings.component.scss'], templateUrl: './admin-settings.component.html' }) -export class GfAdminSettingsComponent implements OnDestroy, OnInit { +export class GfAdminSettingsComponent implements OnInit { + @ViewChild(MatSort) sort: MatSort; + public dataSource = new MatTableDataSource(); public defaultDateFormat: string; public displayedColumns = [ @@ -75,14 +81,13 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { public isGhostfolioApiKeyValid: boolean; public isLoading = false; public pricingUrl: string; - - private unsubscribeSubject = new Subject(); - private user: User; + public user: User; public constructor( private adminService: AdminService, private changeDetectorRef: ChangeDetectorRef, private dataService: DataService, + private destroyRef: DestroyRef, private notificationService: NotificationService, private userService: UserService ) { @@ -91,7 +96,7 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { public ngOnInit() { this.userService.stateChanged - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((state) => { if (state?.user) { this.user = state.user; @@ -148,11 +153,6 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { }); } - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } - private initialize() { this.isLoading = true; @@ -160,13 +160,15 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { this.adminService .fetchAdminData() - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(({ dataProviders, settings }) => { const filteredProviders = dataProviders.filter(({ dataSource }) => { return dataSource !== 'MANUAL'; }); this.dataSource = new MatTableDataSource(filteredProviders); + this.dataSource.sort = this.sort; + this.dataSource.sortingDataAccessor = get; const ghostfolioApiKey = settings[ PROPERTY_API_KEY_GHOSTFOLIO @@ -186,7 +188,7 @@ export class GfAdminSettingsComponent implements OnDestroy, OnInit { filter((status) => { return status !== null; }), - takeUntil(this.unsubscribeSubject) + takeUntilDestroyed(this.destroyRef) ) .subscribe((status) => { this.ghostfolioApiStatus = status; diff --git a/apps/client/src/app/components/admin-tag/admin-tag.component.html b/apps/client/src/app/components/admin-tag/admin-tag.component.html index 98919abd8..463a817ff 100644 --- a/apps/client/src/app/components/admin-tag/admin-tag.component.html +++ b/apps/client/src/app/components/admin-tag/admin-tag.component.html @@ -45,7 +45,11 @@ Activities
    - {{ element.activityCount }} + - + @@ -37,7 +37,7 @@
    @@ -48,7 +48,7 @@
    - {{ accountCurrency }} + {{ accountCurrency() }}
    @@ -58,7 +58,7 @@
    - @if (showActions) { + @if (showActions()) {
    diff --git a/libs/ui/src/lib/account-balances/account-balances.component.ts b/libs/ui/src/lib/account-balances/account-balances.component.ts index 608ee1c75..7b26263b0 100644 --- a/libs/ui/src/lib/account-balances/account-balances.component.ts +++ b/libs/ui/src/lib/account-balances/account-balances.component.ts @@ -10,12 +10,12 @@ import { ChangeDetectionStrategy, Component, EventEmitter, - Input, OnChanges, - OnDestroy, OnInit, Output, - ViewChild + inject, + input, + viewChild } from '@angular/core'; import { FormGroup, @@ -39,8 +39,7 @@ import { ellipsisHorizontal, trashOutline } from 'ionicons/icons'; -import { get } from 'lodash'; -import { Subject } from 'rxjs'; +import { get, isNil } from 'lodash'; import { GfValueComponent } from '../value'; @@ -63,50 +62,44 @@ import { GfValueComponent } from '../value'; styleUrls: ['./account-balances.component.scss'], templateUrl: './account-balances.component.html' }) -export class GfAccountBalancesComponent - implements OnChanges, OnDestroy, OnInit -{ - @Input() accountBalances: AccountBalancesResponse['balances']; - @Input() accountCurrency: string; - @Input() accountId: string; - @Input() locale = getLocale(); - @Input() showActions = true; - +export class GfAccountBalancesComponent implements OnChanges, OnInit { @Output() accountBalanceCreated = new EventEmitter(); @Output() accountBalanceDeleted = new EventEmitter(); - @ViewChild(MatSort) sort: MatSort; + public readonly accountBalances = + input.required(); + public readonly accountCurrency = input.required(); + public readonly accountId = input.required(); + public readonly displayedColumns: string[] = ['date', 'value', 'actions']; + public readonly locale = input(getLocale()); + public readonly showActions = input(true); + public readonly sort = viewChild(MatSort); public accountBalanceForm = new FormGroup({ - balance: new FormControl(0, Validators.required), - date: new FormControl(new Date(), Validators.required) + balance: new FormControl(0, (control) => Validators.required(control)), + date: new FormControl(new Date(), (control) => Validators.required(control)) }); public dataSource = new MatTableDataSource< AccountBalancesResponse['balances'][0] >(); - public displayedColumns: string[] = ['date', 'value', 'actions']; - public Validators = Validators; - - private unsubscribeSubject = new Subject(); + private dateAdapter = inject>(DateAdapter); + private notificationService = inject(NotificationService); - public constructor( - private dateAdapter: DateAdapter, - private notificationService: NotificationService - ) { + public constructor() { addIcons({ calendarClearOutline, ellipsisHorizontal, trashOutline }); } public ngOnInit() { - this.dateAdapter.setLocale(this.locale); + this.dateAdapter.setLocale(this.locale()); } public ngOnChanges() { - if (this.accountBalances) { - this.dataSource = new MatTableDataSource(this.accountBalances); + if (this.accountBalances()) { + this.dataSource = new MatTableDataSource(this.accountBalances()); - this.dataSource.sort = this.sort; + this.dataSource.sort = this.sort(); this.dataSource.sortingDataAccessor = get; } } @@ -122,10 +115,16 @@ export class GfAccountBalancesComponent } public async onSubmitAccountBalance() { + const { balance, date } = this.accountBalanceForm.value; + + if (isNil(balance) || !date) { + return; + } + const accountBalance: CreateAccountBalanceDto = { - accountId: this.accountId, - balance: this.accountBalanceForm.get('balance').value, - date: format(this.accountBalanceForm.get('date').value, DATE_FORMAT) + balance, + accountId: this.accountId(), + date: format(date, DATE_FORMAT) }; try { @@ -141,9 +140,4 @@ export class GfAccountBalancesComponent this.accountBalanceCreated.emit(accountBalance); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/libs/ui/src/lib/accounts-table/accounts-table.component.html b/libs/ui/src/lib/accounts-table/accounts-table.component.html index d127b4bf3..15f5bb21f 100644 --- a/libs/ui/src/lib/accounts-table/accounts-table.component.html +++ b/libs/ui/src/lib/accounts-table/accounts-table.component.html @@ -1,4 +1,4 @@ -@if (showActions) { +@if (showActions()) {
    -@if (isLoading) { +@if (isLoading()) { (); - @Output() accountToUpdate = new EventEmitter(); - @Output() transferBalance = new EventEmitter(); - - @ViewChild(MatSort) sort: MatSort; - - public dataSource = new MatTableDataSource(); - public displayedColumns = []; - public isLoading = true; - public routeQueryParams: Subscription; - - private unsubscribeSubject = new Subject(); - - public constructor( - private notificationService: NotificationService, - private router: Router - ) { - addIcons({ - arrowRedoOutline, - createOutline, - documentTextOutline, - ellipsisHorizontal, - eyeOffOutline, - trashOutline, - walletOutline - }); - } - - public ngOnChanges() { - this.displayedColumns = ['status', 'account', 'platform']; - - if (this.showTransactions) { - this.displayedColumns.push('transactions'); +export class GfAccountsTableComponent { + public readonly accounts = input.required(); + public readonly activitiesCount = input(); + public readonly baseCurrency = input(); + public readonly hasPermissionToOpenDetails = input(true); + public readonly locale = input(getLocale()); + public readonly showActions = input(); + public readonly showActivitiesCount = input(true); + public readonly showAllocationInPercentage = input(); + public readonly showBalance = input(true); + public readonly showFooter = input(true); + public readonly showValue = input(true); + public readonly showValueInBaseCurrency = input(false); + public readonly totalBalanceInBaseCurrency = input(); + public readonly totalValueInBaseCurrency = input(); + + public readonly accountDeleted = output(); + public readonly accountToUpdate = output(); + public readonly transferBalance = output(); + + public readonly sort = viewChild.required(MatSort); + + protected readonly dataSource = new MatTableDataSource([]); + + protected readonly displayedColumns = computed(() => { + const columns = ['status', 'account', 'platform']; + + if (this.showActivitiesCount()) { + columns.push('activitiesCount'); } - if (this.showBalance) { - this.displayedColumns.push('balance'); + if (this.showBalance()) { + columns.push('balance'); } - if (this.showValue) { - this.displayedColumns.push('value'); + if (this.showValue()) { + columns.push('value'); } - this.displayedColumns.push('currency'); + columns.push('currency'); - if (this.showValueInBaseCurrency) { - this.displayedColumns.push('valueInBaseCurrency'); + if (this.showValueInBaseCurrency()) { + columns.push('valueInBaseCurrency'); } - if (this.showAllocationInPercentage) { - this.displayedColumns.push('allocation'); + if (this.showAllocationInPercentage()) { + columns.push('allocation'); } - this.displayedColumns.push('comment'); + columns.push('comment'); - if (this.showActions) { - this.displayedColumns.push('actions'); + if (this.showActions()) { + columns.push('actions'); } - this.isLoading = true; + return columns; + }); - this.dataSource = new MatTableDataSource(this.accounts); - this.dataSource.sort = this.sort; - this.dataSource.sortingDataAccessor = get; + protected readonly isLoading = computed(() => !this.accounts()); - if (this.accounts) { - this.isLoading = false; - } + private readonly notificationService = inject(NotificationService); + private readonly router = inject(Router); + + public constructor() { + addIcons({ + arrowRedoOutline, + createOutline, + documentTextOutline, + ellipsisHorizontal, + eyeOffOutline, + trashOutline, + walletOutline + }); + + this.dataSource.sortingDataAccessor = getLowercase; + + // Reactive data update + effect(() => { + this.dataSource.data = this.accounts(); + }); + + // Reactive view connection + effect(() => { + this.dataSource.sort = this.sort(); + }); } - public onDeleteAccount(aId: string) { + protected onDeleteAccount(aId: string) { this.notificationService.confirm({ confirmFn: () => { this.accountDeleted.emit(aId); @@ -151,30 +149,25 @@ export class GfAccountsTableComponent implements OnChanges, OnDestroy { }); } - public onOpenAccountDetailDialog(accountId: string) { - if (this.hasPermissionToOpenDetails) { + protected onOpenAccountDetailDialog(accountId: string) { + if (this.hasPermissionToOpenDetails()) { this.router.navigate([], { queryParams: { accountId, accountDetailDialog: true } }); } } - public onOpenComment(aComment: string) { + protected onOpenComment(aComment: string) { this.notificationService.alert({ title: aComment }); } - public onTransferBalance() { + protected onTransferBalance() { this.transferBalance.emit(); } - public onUpdateAccount(aAccount: Account) { + protected onUpdateAccount(aAccount: Account) { this.accountToUpdate.emit(aAccount); } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); - } } diff --git a/libs/ui/src/lib/activities-filter/activities-filter.component.html b/libs/ui/src/lib/activities-filter/activities-filter.component.html index fd22ed351..d87ce16ce 100644 --- a/libs/ui/src/lib/activities-filter/activities-filter.component.html +++ b/libs/ui/src/lib/activities-filter/activities-filter.component.html @@ -10,7 +10,7 @@ [removable]="true" (removed)="onRemoveFilter(filter)" > - {{ filter.label | gfSymbol }} + {{ filter.label ?? '' | gfSymbol }} @@ -23,7 +23,7 @@ [matAutocomplete]="autocomplete" [matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" - [placeholder]="placeholder" + [placeholder]="placeholder()" (matChipInputTokenEnd)="onAddFilter($event)" /> @@ -35,7 +35,7 @@ @for (filter of filterGroup.filters; track filter) { - {{ filter.label | gfSymbol }} + {{ filter.label ?? '' | gfSymbol }} } @@ -46,7 +46,7 @@ disabled mat-icon-button matSuffix - [ngClass]="{ 'd-none': !isLoading }" + [ngClass]="{ 'd-none': !isLoading() }" > diff --git a/libs/ui/src/lib/activities-filter/activities-filter.component.ts b/libs/ui/src/lib/activities-filter/activities-filter.component.ts index 34f883c67..6b58e6aec 100644 --- a/libs/ui/src/lib/activities-filter/activities-filter.component.ts +++ b/libs/ui/src/lib/activities-filter/activities-filter.component.ts @@ -7,15 +7,16 @@ import { CUSTOM_ELEMENTS_SCHEMA, ChangeDetectionStrategy, Component, + DestroyRef, ElementRef, - EventEmitter, Input, OnChanges, - OnDestroy, - Output, SimpleChanges, - ViewChild + ViewChild, + input, + output } from '@angular/core'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { FormControl, ReactiveFormsModule } from '@angular/forms'; import { MatAutocomplete, @@ -30,8 +31,7 @@ import { IonIcon } from '@ionic/angular/standalone'; import { addIcons } from 'ionicons'; import { closeOutline, searchOutline } from 'ionicons/icons'; import { groupBy } from 'lodash'; -import { BehaviorSubject, Observable, Subject } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; +import { BehaviorSubject } from 'rxjs'; import { translate } from '../i18n'; @@ -53,28 +53,26 @@ import { translate } from '../i18n'; styleUrls: ['./activities-filter.component.scss'], templateUrl: './activities-filter.component.html' }) -export class GfActivitiesFilterComponent implements OnChanges, OnDestroy { +export class GfActivitiesFilterComponent implements OnChanges { @Input() allFilters: Filter[]; - @Input() isLoading: boolean; - @Input() placeholder: string; - @Output() valueChanged = new EventEmitter(); + @ViewChild('autocomplete') protected matAutocomplete: MatAutocomplete; + @ViewChild('searchInput') protected searchInput: ElementRef; - @ViewChild('autocomplete') matAutocomplete: MatAutocomplete; - @ViewChild('searchInput') searchInput: ElementRef; + public readonly isLoading = input.required(); + public readonly placeholder = input.required(); + public readonly valueChanged = output(); - public filterGroups$: Subject = new BehaviorSubject([]); - public filters$: Subject = new BehaviorSubject([]); - public filters: Observable = this.filters$.asObservable(); - public searchControl = new FormControl(undefined); - public selectedFilters: Filter[] = []; - public separatorKeysCodes: number[] = [ENTER, COMMA]; + protected readonly filterGroups$ = new BehaviorSubject([]); + protected readonly searchControl = new FormControl( + null + ); + protected selectedFilters: Filter[] = []; + protected readonly separatorKeysCodes: number[] = [ENTER, COMMA]; - private unsubscribeSubject = new Subject(); - - public constructor() { + public constructor(private destroyRef: DestroyRef) { this.searchControl.valueChanges - .pipe(takeUntil(this.unsubscribeSubject)) + .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((filterOrSearchTerm) => { if (filterOrSearchTerm) { const searchTerm = @@ -97,41 +95,39 @@ export class GfActivitiesFilterComponent implements OnChanges, OnDestroy { } } - public onAddFilter({ input, value }: MatChipInputEvent) { + public onAddFilter({ chipInput, value }: MatChipInputEvent) { if (value?.trim()) { this.updateFilters(); } // Reset the input value - if (input) { - input.value = ''; + if (chipInput.inputElement) { + chipInput.inputElement.value = ''; } - this.searchControl.setValue(undefined); + this.searchControl.setValue(null); } public onRemoveFilter(aFilter: Filter) { - this.selectedFilters = this.selectedFilters.filter((filter) => { - return filter.id !== aFilter.id; + this.selectedFilters = this.selectedFilters.filter(({ id }) => { + return id !== aFilter.id; }); this.updateFilters(); } public onSelectFilter(event: MatAutocompleteSelectedEvent) { - this.selectedFilters.push( - this.allFilters.find((filter) => { - return filter.id === event.option.value; - }) - ); + const filter = this.allFilters.find(({ id }) => { + return id === event.option.value; + }); + + if (filter) { + this.selectedFilters.push(filter); + } + this.updateFilters(); this.searchInput.nativeElement.value = ''; - this.searchControl.setValue(undefined); - } - - public ngOnDestroy() { - this.unsubscribeSubject.next(); - this.unsubscribeSubject.complete(); + this.searchControl.setValue(null); } private getGroupedFilters(searchTerm?: string) { @@ -139,23 +135,23 @@ export class GfActivitiesFilterComponent implements OnChanges, OnDestroy { this.allFilters .filter((filter) => { // Filter selected filters - return !this.selectedFilters.some((selectedFilter) => { - return selectedFilter.id === filter.id; + return !this.selectedFilters.some(({ id }) => { + return id === filter.id; }); }) .filter((filter) => { if (searchTerm) { // Filter by search term return filter.label - .toLowerCase() + ?.toLowerCase() .includes(searchTerm.toLowerCase()); } return filter; }) - .sort((a, b) => a.label?.localeCompare(b.label)), - (filter) => { - return filter.type; + .sort((a, b) => (a.label ?? '').localeCompare(b.label ?? '')), + ({ type }) => { + return type; } ); diff --git a/libs/ui/src/lib/activities-table/activities-table.component.html b/libs/ui/src/lib/activities-table/activities-table.component.html index b8e1882d4..bdb1e6373 100644 --- a/libs/ui/src/lib/activities-table/activities-table.component.html +++ b/libs/ui/src/lib/activities-table/activities-table.component.html @@ -21,7 +21,7 @@
    @@ -201,7 +201,7 @@
    @@ -225,7 +225,7 @@
    @@ -249,7 +249,7 @@ @@ -272,7 +272,7 @@ @@ -304,7 +304,7 @@ @@ -388,7 +388,7 @@ @if (hasPermissionToCreateActivity) {