Compare commits

..

46 Commits

Author SHA1 Message Date
5b51a6840a Release 1.205.0 (#1367) 2022-10-16 19:36:51 +02:00
36bd6164e6 Feature/improve wording on landing page (#1366)
* Improve wording

* Update changelog
2022-10-16 19:35:09 +02:00
eac52a215b Feature/refactor appearance to color scheme (#1364)
* Refactor appearance to colorScheme

* Update changelog
2022-10-16 14:54:26 +02:00
9ff8cd5471 Feature/improve portfolio evolution chart (#1362)
* Switch inputs

* Update changelog
2022-10-16 10:01:31 +02:00
33cc7e4e7e Feature/remove rakuten from data source (#1361)
* Remove Rakuten

* Update changelog
2022-10-16 09:42:18 +02:00
47f84dab06 Remove postfix (#1360) 2022-10-16 09:41:41 +02:00
384d18b2a6 Feature/persist user language on url change (#1359)
* Persist user language

* Update changelog
2022-10-16 08:45:52 +02:00
2363983bdc Release 1.204.1 (#1357) 2022-10-15 18:07:18 +02:00
4af76764be Release 1.204.0 (#1356) 2022-10-15 17:47:35 +02:00
a65424aafa Feature/add total amount chart to investment timeline (#1344)
* Add total amount chart

* Update changelog
2022-10-15 17:45:34 +02:00
f9cd629470 Update messages.es.xlf (#1355) 2022-10-15 17:44:20 +02:00
ccb8c86596 Feature/minor improvements in chart components (#1353)
* Move y axis to the right

* Update changelog
2022-10-15 11:27:55 +02:00
246de7aa86 Consider current month in FIRE calculation (#1349) 2022-10-15 10:45:11 +02:00
a323313c71 Bugfix/fix alignment of value component on allocation page (#1351)
* Fix alignment

* Update changelog
2022-10-15 10:32:08 +02:00
538c8947cd Feature/rename data source from rakuten to rapid api (#1350)
* Rename Rakuten to Rapid API

* Update changelog
2022-10-15 10:31:46 +02:00
1ec5fd12fe Feature/setup prettier plugin organize attributes (#1346)
* Setup prettier plugin: prettier-plugin-organize-attributes

* Update changelog
2022-10-15 10:30:12 +02:00
4376b8903e Bugifx/fix url in blog posts (#1347)
* Fix url

* Update changelog
2022-10-14 19:52:00 +02:00
a8e096f9ac Feature/minor improvements for appearance selector (#1345)
* Improve appearance selector

* Update changelog
2022-10-12 13:38:58 +02:00
8e577592f6 Fix issue with $localize in storybook (#1343) 2022-10-12 09:48:33 +02:00
c896bf9199 Add appearance option in settings (#1342)
* Add appearance option in settings
2022-10-11 21:34:52 +02:00
16145f18d9 Improve template (#1324)
* Improve template
2022-10-09 10:42:02 +02:00
5398da0dc8 Feature/simplify admin settings management (#1340)
* Simplify settings management

* Update changelog
2022-10-08 17:35:18 +02:00
2466f4ff5d Release 1.203.0 (#1338) 2022-10-08 14:22:43 +02:00
8f3a9bdfbb Feature/refactor animation configuration (#1337)
* Refactor animation configuration

* Update changelog
2022-10-08 14:21:17 +02:00
44dfd2bd48 Add animation to line chart (#1328) 2022-10-08 13:47:48 +02:00
3fc2228f1d Feature/switch to new performance calculation (#1336)
* Switch to new performance calculation

* Update changelog
2022-10-08 13:20:52 +02:00
b018819a1f Bugfix/fix todays performance and chart calculation (#1333)
* Fix today's performance and chart calculation

* Update changelog
2022-10-08 13:20:25 +02:00
ac9311d783 Bugfix/fix alignment in users table (#1335)
* Fix alignment

* Update changelog
2022-10-08 11:38:58 +02:00
e23ce0f35d Feature/improve gui of benchmark comparator (#1334)
* Improve GUI

* Update changelog
2022-10-08 11:07:42 +02:00
f4b52aa41c Add Italian localization for the 4% rule (#1329)
* Update messages.it.xlf
2022-10-08 11:05:53 +02:00
655b040d4d Add missing title (#1332) 2022-10-07 20:54:05 +02:00
0f637a5d0f Release 1.202.0 (#1331) 2022-10-07 20:49:57 +02:00
3f85c327f5 Bugfix/fix text truncation in value component (#1330)
* Fix text truncation

* Update changelog
2022-10-07 20:48:39 +02:00
c2df99072d Feature/refactor filters (#1299)
* Refactor filters

Co-Authored-By: Zakaria YAHI <9142557+ZakYahi@users.noreply.github.com>
2022-10-07 20:39:29 +02:00
e8afbcad9c Feature/localize 4 percentage rule (#1327)
* Setup translation for 4% rule

* Update changelog
2022-10-07 20:21:52 +02:00
e6d8de781b Feature/improve wording in twitter bot service (#1326)
* Improve wording

* Update changelog
2022-10-06 20:52:34 +02:00
6e1935899f Bugfix/fix cryptocurrency symbols with less than 3 characters (#1325)
* Fix cryptocurrency symbols with less than 3 characters

* Update changelog
2022-10-06 15:15:36 +02:00
169cb85b66 Improve Italian translation (#1318)
* Update messages.it.xlf
2022-10-05 07:53:03 +02:00
fe6658d0ac Update messages.es.xlf (#1319) 2022-10-04 17:43:25 +02:00
1f0381228e Feature/improve caching of benchmarks (#1320)
* Improve caching

* Update changelog
2022-10-04 17:39:51 +02:00
f4b63b5de5 Release 1.201.0 (#1313) 2022-10-01 18:39:15 +02:00
e45a0ad068 Spanish (#1312)
* Update messages.es.xlf
2022-10-01 18:36:41 +02:00
81c6cc021d Feature/add blog post hacktoberfest 2022 (#1310)
* Add blog post: Hacktoberfest 2022

* Update changelog
2022-10-01 18:35:55 +02:00
859b24aa5b Fix alignment (#1311) 2022-10-01 18:35:27 +02:00
2bc325f182 Update messages.es.xlf (#1305)
* Update messages.es.xlf

Co-authored-by: fdp10381 <63880387+fdp10381@users.noreply.github.com>
2022-10-01 16:45:44 +02:00
a6186c23e2 Feature/improve usage of value component (#1308)
* Improve usage of value component

* Update changelog
2022-10-01 13:53:43 +02:00
98 changed files with 1950 additions and 1276 deletions

View File

@ -1,37 +1,45 @@
---
name: Bug report
about: Create a report to help us improve
title: "[BUG]"
title: '[BUG]'
labels: ''
assignees: ''
---
The Issue tracker is **ONLY** used for reporting bugs. New features should be discussed on our [Slack channel](https://ghostfolio.slack.com) or in [Discussions](https://github.com/ghostfolio/ghostfolio/discussions).
**Describe the bug**
**Bug Description**
<!-- A clear and concise description of what the bug is. -->
**To Reproduce**
Steps to reproduce the behavior:
<!-- Steps to reproduce the behavior -->
1.
2.
3.
4.
**Expected behavior**
<!-- A clear and concise description of what you expected to happen. -->
**Screenshots**
<!-- If applicable, add screenshots to help explain your problem. -->
**Logs**
<!-- If applicable, add logs to help explain your problem. -->
**Environment (please complete the following information):**
- Ghostfolio Version [e.g. 1.194.0]
- Browser [e.g. chrome]
- OS
**Environment**
<!-- Please complete the following information -->
- Ghostfolio Version X.Y.Z
- Browser
- OS
**Additional context**
<!-- Add any other context about the problem here. -->

View File

@ -1,4 +1,13 @@
{
"attributeGroups": [
"$ANGULAR_ELEMENT_REF",
"$ANGULAR_STRUCTURAL_DIRECTIVE",
"$DEFAULT",
"$ANGULAR_INPUT",
"$ANGULAR_TWO_WAY_BINDING",
"$ANGULAR_OUTPUT"
],
"attributeSort": "ASC",
"endOfLine": "auto",
"printWidth": 80,
"singleQuote": true,

View File

@ -5,6 +5,86 @@ 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).
## 1.205.0 - 16.10.2022
### Changed
- Persisted the language on url change
- Improved the portfolio evolution chart
- Removed the data source type `RAKUTEN`
- Refactored the appearance (dark mode) in user settings (from `appearance` to `colorScheme`)
- Improved the wording on the landing page
## 1.204.1 - 15.10.2022
### Added
- Added support to change the appearance (dark mode) in user settings
- Added the total amount chart to the investment timeline
- Setup the `prettier` plugin `prettier-plugin-organize-attributes`
### Changed
- Respected the current date in the _FIRE_ calculator
- Simplified the settings management in the admin control panel
- Renamed the data source type `RAKUTEN` to `RAPID_API`
### Fixed
- Fixed some links in the blog posts
- Fixed the alignment of the value component on the allocations page
### Todo
- Rename the environment variable from `RAKUTEN_RAPID_API_KEY` to `RAPID_API_API_KEY`
## 1.203.0 - 08.10.2022
### Added
- Supported a progressive line animation in the line chart component
### Changed
- Moved the benchmark comparator from experimental to general availability
- Improved the user interface of the benchmark comparator
### Fixed
- Fixed an issue in the performance and chart calculation of today
- Fixed the alignment of the value component in the admin control panel
## 1.202.0 - 07.10.2022
### Added
- Added support for a translated 4% rule in the _FIRE_ section
### Changed
- Improved the caching of the benchmarks in the markets overview (only cache if fetching was successful)
- Improved the wording in the twitter bot service
### Fixed
- Fixed the support for cryptocurrencies having a symbol with less than 3 characters (e.g. `SC-USD`)
- Fixed the text truncation in the value component
## 1.201.0 - 01.10.2022
### Added
- Added a blog post: _Hacktoberfest 2022_
### Changed
- Improved the usage of the value component in the admin control panel
- Improved the language localization for Español (`es`)
### Fixed
- Fixed the usage of the value component on the allocations page
## 1.200.0 - 01.10.2022
### Added
@ -902,8 +982,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
- Display the value in base currency in the accounts table on mobile
- Display the value in base currency in the activities table on mobile
- Displayed the value in base currency in the accounts table on mobile
- Displayed the value in base currency in the activities table on mobile
- Renamed `orders` to `activities` in import and export functionality
- Harmonized the algebraic sign of `currentGrossPerformancePercent` and `currentNetPerformancePercent` with `currentGrossPerformance` and `currentNetPerformance`
- Improved the pricing page

View File

@ -95,11 +95,10 @@ export class AccountController {
);
let accountsWithAggregations =
await this.portfolioService.getAccountsWithAggregations(
impersonationUserId || this.request.user.id,
undefined,
true
);
await this.portfolioService.getAccountsWithAggregations({
userId: impersonationUserId || this.request.user.id,
withExcludedAccounts: true
});
if (
impersonationUserId ||
@ -139,11 +138,11 @@ export class AccountController {
);
let accountsWithAggregations =
await this.portfolioService.getAccountsWithAggregations(
impersonationUserId || this.request.user.id,
[{ id, type: 'ACCOUNT' }],
true
);
await this.portfolioService.getAccountsWithAggregations({
filters: [{ id, type: 'ACCOUNT' }],
userId: impersonationUserId || this.request.user.id,
withExcludedAccounts: true
});
if (
impersonationUserId ||

View File

@ -181,10 +181,10 @@ export class AdminService {
public async putSetting(key: string, value: string) {
let response: Property;
if (value === '') {
response = await this.propertyService.delete({ key });
} else {
if (value) {
response = await this.propertyService.put({ key, value });
} else {
response = await this.propertyService.delete({ key });
}
if (key === PROPERTY_CURRENCIES) {

View File

@ -73,6 +73,7 @@ export class BenchmarkService {
}
const allTimeHighs = await Promise.all(promises);
let storeInCache = true;
benchmarks = allTimeHighs.map((allTimeHigh, index) => {
const { marketPrice } =
@ -85,6 +86,8 @@ export class BenchmarkService {
allTimeHigh,
marketPrice
);
} else {
storeInCache = false;
}
return {
@ -100,11 +103,13 @@ export class BenchmarkService {
};
});
await this.redisCacheService.set(
this.CACHE_KEY_BENCHMARKS,
JSON.stringify(benchmarks),
ms('4 hours') / 1000
);
if (storeInCache) {
await this.redisCacheService.set(
this.CACHE_KEY_BENCHMARKS,
JSON.stringify(benchmarks),
ms('4 hours') / 1000
);
}
return benchmarks;
}

View File

@ -58,6 +58,11 @@ export class FrontendMiddleware implements NestMiddleware {
req.path === '/en/blog/2022/08/500-stars-on-github/'
) {
featureGraphicPath = 'assets/images/blog/500-stars-on-github.jpg';
} else if (
req.path === '/en/blog/2022/10/hacktoberfest-2022' ||
req.path === '/en/blog/2022/10/hacktoberfest-2022/'
) {
featureGraphicPath = 'assets/images/blog/hacktoberfest-2022.png';
}
if (

View File

@ -3,8 +3,8 @@ import { nullifyValuesInObjects } from '@ghostfolio/api/helper/object.helper';
import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response.interceptor';
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor';
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor';
import { ApiService } from '@ghostfolio/api/services/api/api.service';
import { ImpersonationService } from '@ghostfolio/api/services/impersonation.service';
import { Filter } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import type { RequestWithUser } from '@ghostfolio/common/types';
import {
@ -36,6 +36,7 @@ import { UpdateOrderDto } from './update-order.dto';
@Controller('order')
export class OrderController {
public constructor(
private readonly apiService: ApiService,
private readonly impersonationService: ImpersonationService,
private readonly orderService: OrderService,
@Inject(REQUEST) private readonly request: RequestWithUser,
@ -73,30 +74,11 @@ export class OrderController {
@Query('assetClasses') filterByAssetClasses?: string,
@Query('tags') filterByTags?: string
): Promise<Activities> {
const accountIds = filterByAccounts?.split(',') ?? [];
const assetClasses = filterByAssetClasses?.split(',') ?? [];
const tagIds = filterByTags?.split(',') ?? [];
const filters: Filter[] = [
...accountIds.map((accountId) => {
return <Filter>{
id: accountId,
type: 'ACCOUNT'
};
}),
...assetClasses.map((assetClass) => {
return <Filter>{
id: assetClass,
type: 'ASSET_CLASS'
};
}),
...tagIds.map((tagId) => {
return <Filter>{
id: tagId,
type: 'TAG'
};
})
];
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,
filterByTags
});
const impersonationUserId =
await this.impersonationService.validateImpersonationId(

View File

@ -2,6 +2,7 @@ import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { CacheModule } from '@ghostfolio/api/app/cache/cache.module';
import { RedisCacheModule } from '@ghostfolio/api/app/redis-cache/redis-cache.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
@ -18,6 +19,7 @@ import { OrderService } from './order.service';
controllers: [OrderController],
exports: [OrderService],
imports: [
ApiModule,
CacheModule,
ConfigurationModule,
DataGatheringModule,

View File

@ -14,6 +14,7 @@ import {
format,
isAfter,
isBefore,
isSameDay,
isSameMonth,
isSameYear,
max,
@ -187,7 +188,9 @@ export class PortfolioCalculator {
day = addDays(day, step);
}
dates.push(resetHours(end));
if (!isSameDay(last(dates), end)) {
dates.push(resetHours(end));
}
for (const item of transactionPointsBeforeEndDate[firstIndex - 1].items) {
dataGatheringItems.push({
@ -284,7 +287,10 @@ export class PortfolioCalculator {
date,
netPerformanceInPercentage,
netPerformance: totalNetPerformanceValues[date].toNumber(),
value: netPerformanceInPercentage
totalInvestment: totalInvestmentValues[date].toNumber(),
value: totalInvestmentValues[date]
.plus(totalNetPerformanceValues[date])
.toNumber()
};
});
}

View File

@ -7,18 +7,16 @@ import {
import { RedactValuesInResponseInterceptor } from '@ghostfolio/api/interceptors/redact-values-in-response.interceptor';
import { TransformDataSourceInRequestInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-request.interceptor';
import { TransformDataSourceInResponseInterceptor } from '@ghostfolio/api/interceptors/transform-data-source-in-response.interceptor';
import { ApiService } from '@ghostfolio/api/services/api/api.service';
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data.service';
import { parseDate } from '@ghostfolio/common/helper';
import {
Filter,
PortfolioChart,
PortfolioDetails,
PortfolioInvestments,
PortfolioPerformanceResponse,
PortfolioPublicDetails,
PortfolioReport,
PortfolioSummary
PortfolioReport
} from '@ghostfolio/common/interfaces';
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
import type {
@ -40,6 +38,7 @@ import {
} from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import Big from 'big.js';
import { StatusCodes, getReasonPhrase } from 'http-status-codes';
import { PortfolioPositionDetail } from './interfaces/portfolio-position-detail.interface';
@ -52,6 +51,7 @@ export class PortfolioController {
public constructor(
private readonly accessService: AccessService,
private readonly apiService: ApiService,
private readonly configurationService: ConfigurationService,
private readonly exchangeRateDataService: ExchangeRateDataService,
private readonly portfolioService: PortfolioService,
@ -61,55 +61,6 @@ export class PortfolioController {
this.baseCurrency = this.configurationService.get('BASE_CURRENCY');
}
@Get('chart')
@UseGuards(AuthGuard('jwt'))
public async getChart(
@Headers('impersonation-id') impersonationId: string,
@Query('range') range
): Promise<PortfolioChart> {
const historicalDataContainer = await this.portfolioService.getChart(
impersonationId,
range
);
let chartData = historicalDataContainer.items;
let hasError = false;
chartData.forEach((chartDataItem) => {
if (hasNotDefinedValuesInObject(chartDataItem)) {
hasError = true;
}
});
if (
impersonationId ||
this.userService.isRestrictedView(this.request.user)
) {
let maxValue = 0;
chartData.forEach((portfolioItem) => {
if (portfolioItem.value > maxValue) {
maxValue = portfolioItem.value;
}
});
chartData = chartData.map((historicalDataItem) => {
return {
...historicalDataItem,
marketPrice: Number((historicalDataItem.value / maxValue).toFixed(2))
};
});
}
return {
hasError,
chart: chartData,
isAllTimeHigh: historicalDataContainer.isAllTimeHigh,
isAllTimeLow: historicalDataContainer.isAllTimeLow
};
}
@Get('details')
@UseGuards(AuthGuard('jwt'))
@UseInterceptors(RedactValuesInResponseInterceptor)
@ -118,37 +69,16 @@ export class PortfolioController {
@Headers('impersonation-id') impersonationId: string,
@Query('accounts') filterByAccounts?: string,
@Query('assetClasses') filterByAssetClasses?: string,
@Query('range') range?: DateRange,
@Query('range') dateRange: DateRange = 'max',
@Query('tags') filterByTags?: string
): Promise<PortfolioDetails & { hasError: boolean }> {
let hasError = false;
const accountIds = filterByAccounts?.split(',') ?? [];
const assetClasses = filterByAssetClasses?.split(',') ?? [];
const tagIds = filterByTags?.split(',') ?? [];
const filters: Filter[] = [
...accountIds.map((accountId) => {
return <Filter>{
id: accountId,
type: 'ACCOUNT'
};
}),
...assetClasses.map((assetClass) => {
return <Filter>{
id: assetClass,
type: 'ASSET_CLASS'
};
}),
...tagIds.map((tagId) => {
return <Filter>{
id: tagId,
type: 'TAG'
};
})
];
let portfolioSummary: PortfolioSummary;
const filters = this.apiService.buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,
filterByTags
});
const {
accounts,
@ -158,18 +88,18 @@ export class PortfolioController {
holdings,
summary,
totalValueInBaseCurrency
} = await this.portfolioService.getDetails(
} = await this.portfolioService.getDetails({
dateRange,
filters,
impersonationId,
this.request.user.id,
range,
filters
);
userId: this.request.user.id
});
if (hasErrors || hasNotDefinedValuesInObject(holdings)) {
hasError = true;
}
portfolioSummary = summary;
let portfolioSummary = summary;
if (
impersonationId ||
@ -254,6 +184,7 @@ export class PortfolioController {
@UseGuards(AuthGuard('jwt'))
public async getInvestments(
@Headers('impersonation-id') impersonationId: string,
@Query('range') dateRange: DateRange = 'max',
@Query('groupBy') groupBy?: GroupBy
): Promise<PortfolioInvestments> {
if (
@ -269,12 +200,16 @@ export class PortfolioController {
let investments: InvestmentItem[];
if (groupBy === 'month') {
investments = await this.portfolioService.getInvestments(
investments = await this.portfolioService.getInvestments({
dateRange,
impersonationId,
'month'
);
groupBy: 'month'
});
} else {
investments = await this.portfolioService.getInvestments(impersonationId);
investments = await this.portfolioService.getInvestments({
dateRange,
impersonationId
});
}
if (
@ -292,33 +227,7 @@ export class PortfolioController {
}));
}
return { firstOrderDate: parseDate(investments[0]?.date), investments };
}
@Get('performance')
@UseGuards(AuthGuard('jwt'))
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getPerformance(
@Headers('impersonation-id') impersonationId: string,
@Query('range') range
): Promise<PortfolioPerformanceResponse> {
const performanceInformation = await this.portfolioService.getPerformance(
impersonationId,
range
);
if (
impersonationId ||
this.request.user.Settings.settings.viewMode === 'ZEN' ||
this.userService.isRestrictedView(this.request.user)
) {
performanceInformation.performance = nullifyValuesInObject(
performanceInformation.performance,
['currentGrossPerformance', 'currentValue']
);
}
return performanceInformation;
return { investments };
}
@Get('performance')
@ -327,23 +236,41 @@ export class PortfolioController {
@Version('2')
public async getPerformanceV2(
@Headers('impersonation-id') impersonationId: string,
@Query('range') dateRange
@Query('range') dateRange: DateRange = 'max'
): Promise<PortfolioPerformanceResponse> {
const performanceInformation = await this.portfolioService.getPerformanceV2(
{
dateRange,
impersonationId
}
);
const performanceInformation = await this.portfolioService.getPerformance({
dateRange,
impersonationId
});
if (
impersonationId ||
this.request.user.Settings.settings.viewMode === 'ZEN' ||
this.userService.isRestrictedView(this.request.user)
) {
performanceInformation.chart = performanceInformation.chart.map(
({ date, netPerformanceInPercentage, totalInvestment, value }) => {
return {
date,
netPerformanceInPercentage,
totalInvestment: new Big(totalInvestment)
.div(performanceInformation.performance.totalInvestment)
.toNumber(),
value: new Big(value)
.div(performanceInformation.performance.currentValue)
.toNumber()
};
}
);
performanceInformation.performance = nullifyValuesInObject(
performanceInformation.performance,
['currentGrossPerformance', 'currentNetPerformance', 'currentValue']
[
'currentGrossPerformance',
'currentNetPerformance',
'currentValue',
'totalInvestment'
]
);
}
@ -355,11 +282,11 @@ export class PortfolioController {
@UseInterceptors(TransformDataSourceInResponseInterceptor)
public async getPositions(
@Headers('impersonation-id') impersonationId: string,
@Query('range') range
@Query('range') dateRange: DateRange = 'max'
): Promise<PortfolioPositions> {
const result = await this.portfolioService.getPositions(
impersonationId,
range
dateRange
);
if (
@ -400,12 +327,12 @@ export class PortfolioController {
hasDetails = user.subscription.type === 'Premium';
}
const { holdings } = await this.portfolioService.getDetails(
access.userId,
access.userId,
'max',
[{ id: 'EQUITY', type: 'ASSET_CLASS' }]
);
const { holdings } = await this.portfolioService.getDetails({
dateRange: 'max',
filters: [{ id: 'EQUITY', type: 'ASSET_CLASS' }],
impersonationId: access.userId,
userId: access.userId
});
const portfolioPublicDetails: PortfolioPublicDetails = {
hasDetails,

View File

@ -2,6 +2,7 @@ import { AccessModule } from '@ghostfolio/api/app/access/access.module';
import { AccountService } from '@ghostfolio/api/app/account/account.service';
import { OrderModule } from '@ghostfolio/api/app/order/order.module';
import { UserModule } from '@ghostfolio/api/app/user/user.module';
import { ApiModule } from '@ghostfolio/api/services/api/api.module';
import { ConfigurationModule } from '@ghostfolio/api/services/configuration.module';
import { DataGatheringModule } from '@ghostfolio/api/services/data-gathering.module';
import { DataProviderModule } from '@ghostfolio/api/services/data-provider/data-provider.module';
@ -22,6 +23,7 @@ import { RulesService } from './rules.service';
exports: [PortfolioService],
imports: [
AccessModule,
ApiModule,
ConfigurationModule,
DataGatheringModule,
DataProviderModule,

View File

@ -107,15 +107,19 @@ export class PortfolioService {
this.baseCurrency = this.configurationService.get('BASE_CURRENCY');
}
public async getAccounts(
aUserId: string,
aFilters?: Filter[],
public async getAccounts({
filters,
userId,
withExcludedAccounts = false
): Promise<AccountWithValue[]> {
const where: Prisma.AccountWhereInput = { userId: aUserId };
}: {
filters?: Filter[];
userId: string;
withExcludedAccounts?: boolean;
}): Promise<AccountWithValue[]> {
const where: Prisma.AccountWhereInput = { userId: userId };
if (aFilters?.[0].id && aFilters?.[0].type === 'ACCOUNT') {
where.id = aFilters[0].id;
if (filters?.[0].id && filters?.[0].type === 'ACCOUNT') {
where.id = filters[0].id;
}
const [accounts, details] = await Promise.all([
@ -124,13 +128,12 @@ export class PortfolioService {
include: { Order: true, Platform: true },
orderBy: { name: 'asc' }
}),
this.getDetails(
aUserId,
aUserId,
undefined,
aFilters,
withExcludedAccounts
)
this.getDetails({
filters,
userId,
withExcludedAccounts,
impersonationId: userId
})
]);
const userCurrency = this.request.user.Settings.settings.baseCurrency;
@ -168,16 +171,20 @@ export class PortfolioService {
});
}
public async getAccountsWithAggregations(
aUserId: string,
aFilters?: Filter[],
public async getAccountsWithAggregations({
filters,
userId,
withExcludedAccounts = false
): Promise<Accounts> {
const accounts = await this.getAccounts(
aUserId,
aFilters,
}: {
filters?: Filter[];
userId: string;
withExcludedAccounts?: boolean;
}): Promise<Accounts> {
const accounts = await this.getAccounts({
filters,
userId,
withExcludedAccounts
);
});
let totalBalanceInBaseCurrency = new Big(0);
let totalValueInBaseCurrency = new Big(0);
let transactionCount = 0;
@ -200,11 +207,16 @@ export class PortfolioService {
};
}
public async getInvestments(
aImpersonationId: string,
groupBy?: GroupBy
): Promise<InvestmentItem[]> {
const userId = await this.getUserId(aImpersonationId, this.request.user.id);
public async getInvestments({
dateRange,
impersonationId,
groupBy
}: {
dateRange: DateRange;
impersonationId: string;
groupBy?: GroupBy;
}): Promise<InvestmentItem[]> {
const userId = await this.getUserId(impersonationId, this.request.user.id);
const { portfolioOrders, transactionPoints } =
await this.getTransactionPoints({
@ -276,101 +288,21 @@ export class PortfolioService {
}
}
return sortBy(investments, (investment) => {
investments = sortBy(investments, (investment) => {
return investment.date;
});
}
public async getChart(
aImpersonationId: string,
aDateRange: DateRange = 'max'
): Promise<HistoricalDataContainer> {
const userId = await this.getUserId(aImpersonationId, this.request.user.id);
const startDate = this.getStartDate(
dateRange,
parseDate(investments[0]?.date)
);
const { portfolioOrders, transactionPoints } =
await this.getTransactionPoints({
userId
});
const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.settings.baseCurrency,
currentRateService: this.currentRateService,
orders: portfolioOrders
return investments.filter(({ date }) => {
return !isBefore(parseDate(date), startDate);
});
portfolioCalculator.setTransactionPoints(transactionPoints);
if (transactionPoints.length === 0) {
return {
isAllTimeHigh: false,
isAllTimeLow: false,
items: []
};
}
let portfolioStart = parse(
transactionPoints[0].date,
DATE_FORMAT,
new Date()
);
// Get start date for the full portfolio because of because of the
// min and max calculation
portfolioStart = this.getStartDate('max', portfolioStart);
const timelineSpecification: TimelineSpecification[] = [
{
start: format(portfolioStart, DATE_FORMAT),
accuracy: 'day'
}
];
const timelineInfo = await portfolioCalculator.calculateTimeline(
timelineSpecification,
format(new Date(), DATE_FORMAT)
);
const timeline = timelineInfo.timelinePeriods;
const items = timeline
.filter((timelineItem) => timelineItem !== null)
.map((timelineItem) => ({
date: timelineItem.date,
value: timelineItem.netPerformance.toNumber()
}));
let lastItem = null;
if (timeline.length > 0) {
lastItem = timeline[timeline.length - 1];
}
let isAllTimeHigh = timelineInfo.maxNetPerformance?.eq(
lastItem?.netPerformance ?? 0
);
let isAllTimeLow = timelineInfo.minNetPerformance?.eq(
lastItem?.netPerformance ?? 0
);
if (isAllTimeHigh && isAllTimeLow) {
isAllTimeHigh = false;
isAllTimeLow = false;
}
portfolioStart = startOfDay(
this.getStartDate(
aDateRange,
parse(transactionPoints[0].date, DATE_FORMAT, new Date())
)
);
return {
isAllTimeHigh,
isAllTimeLow,
items: items.filter((item) => {
// Filter items of date range
return !isAfter(portfolioStart, parseDate(item.date));
})
};
}
public async getChartV2({
public async getChart({
dateRange = 'max',
impersonationId
}: {
@ -421,14 +353,21 @@ export class PortfolioService {
};
}
public async getDetails(
aImpersonationId: string,
aUserId: string,
aDateRange: DateRange = 'max',
aFilters?: Filter[],
public async getDetails({
impersonationId,
userId,
dateRange = 'max',
filters,
withExcludedAccounts = false
): Promise<PortfolioDetails & { hasErrors: boolean }> {
const userId = await this.getUserId(aImpersonationId, aUserId);
}: {
impersonationId: string;
userId: string;
dateRange?: DateRange;
filters?: Filter[];
withExcludedAccounts?: boolean;
}): Promise<PortfolioDetails & { hasErrors: boolean }> {
// TODO
userId = await this.getUserId(impersonationId, userId);
const user = await this.userService.user({ id: userId });
const emergencyFund = new Big(
@ -441,9 +380,9 @@ export class PortfolioService {
const { orders, portfolioOrders, transactionPoints } =
await this.getTransactionPoints({
filters,
userId,
withExcludedAccounts,
filters: aFilters
withExcludedAccounts
});
const portfolioCalculator = new PortfolioCalculator({
@ -457,15 +396,15 @@ export class PortfolioService {
const portfolioStart = parseDate(
transactionPoints[0]?.date ?? format(new Date(), DATE_FORMAT)
);
const startDate = this.getStartDate(aDateRange, portfolioStart);
const startDate = this.getStartDate(dateRange, portfolioStart);
const currentPositions = await portfolioCalculator.getCurrentPositions(
startDate
);
const cashDetails = await this.accountService.getCashDetails({
filters,
userId,
currency: userCurrency,
filters: aFilters
currency: userCurrency
});
const holdings: PortfolioDetails['holdings'] = {};
@ -475,10 +414,10 @@ export class PortfolioService {
let filteredValueInBaseCurrency = currentPositions.currentValue;
if (
aFilters?.length === 0 ||
(aFilters?.length === 1 &&
aFilters[0].type === 'ASSET_CLASS' &&
aFilters[0].id === 'CASH')
filters?.length === 0 ||
(filters?.length === 1 &&
filters[0].type === 'ASSET_CLASS' &&
filters[0].id === 'CASH')
) {
filteredValueInBaseCurrency = filteredValueInBaseCurrency.plus(
cashDetails.balanceInBaseCurrency
@ -574,10 +513,10 @@ export class PortfolioService {
}
if (
aFilters?.length === 0 ||
(aFilters?.length === 1 &&
aFilters[0].type === 'ASSET_CLASS' &&
aFilters[0].id === 'CASH')
filters?.length === 0 ||
(filters?.length === 1 &&
filters[0].type === 'ASSET_CLASS' &&
filters[0].id === 'CASH')
) {
const cashPositions = await this.getCashPositions({
cashDetails,
@ -593,15 +532,15 @@ export class PortfolioService {
}
const accounts = await this.getValueOfAccounts({
filters,
orders,
portfolioItemsNow,
userCurrency,
userId,
withExcludedAccounts,
filters: aFilters
withExcludedAccounts
});
const summary = await this.getSummary(aImpersonationId);
const summary = await this.getSummary({ impersonationId });
return {
accounts,
@ -942,78 +881,7 @@ export class PortfolioService {
};
}
public async getPerformance(
aImpersonationId: string,
aDateRange: DateRange = 'max'
): Promise<PortfolioPerformanceResponse> {
const userId = await this.getUserId(aImpersonationId, this.request.user.id);
const { portfolioOrders, transactionPoints } =
await this.getTransactionPoints({
userId
});
const portfolioCalculator = new PortfolioCalculator({
currency: this.request.user.Settings.settings.baseCurrency,
currentRateService: this.currentRateService,
orders: portfolioOrders
});
if (transactionPoints?.length <= 0) {
return {
hasErrors: false,
performance: {
currentGrossPerformance: 0,
currentGrossPerformancePercent: 0,
currentNetPerformance: 0,
currentNetPerformancePercent: 0,
currentValue: 0
}
};
}
portfolioCalculator.setTransactionPoints(transactionPoints);
const portfolioStart = parseDate(transactionPoints[0].date);
const startDate = this.getStartDate(aDateRange, portfolioStart);
const currentPositions = await portfolioCalculator.getCurrentPositions(
startDate
);
const hasErrors = currentPositions.hasErrors;
const currentValue = currentPositions.currentValue.toNumber();
const currentGrossPerformance = currentPositions.grossPerformance;
let currentGrossPerformancePercent =
currentPositions.grossPerformancePercentage;
const currentNetPerformance = currentPositions.netPerformance;
let currentNetPerformancePercent =
currentPositions.netPerformancePercentage;
if (currentGrossPerformance.mul(currentGrossPerformancePercent).lt(0)) {
// If algebraic sign is different, harmonize it
currentGrossPerformancePercent = currentGrossPerformancePercent.mul(-1);
}
if (currentNetPerformance.mul(currentNetPerformancePercent).lt(0)) {
// If algebraic sign is different, harmonize it
currentNetPerformancePercent = currentNetPerformancePercent.mul(-1);
}
return {
errors: currentPositions.errors,
hasErrors: currentPositions.hasErrors || hasErrors,
performance: {
currentValue,
currentGrossPerformance: currentGrossPerformance.toNumber(),
currentGrossPerformancePercent:
currentGrossPerformancePercent.toNumber(),
currentNetPerformance: currentNetPerformance.toNumber(),
currentNetPerformancePercent: currentNetPerformancePercent.toNumber()
}
};
}
public async getPerformanceV2({
public async getPerformance({
dateRange = 'max',
impersonationId
}: {
@ -1036,13 +904,15 @@ export class PortfolioService {
if (transactionPoints?.length <= 0) {
return {
chart: [],
firstOrderDate: undefined,
hasErrors: false,
performance: {
currentGrossPerformance: 0,
currentGrossPerformancePercent: 0,
currentNetPerformance: 0,
currentNetPerformancePercent: 0,
currentValue: 0
currentValue: 0,
totalInvestment: 0
}
};
}
@ -1063,6 +933,7 @@ export class PortfolioService {
let currentNetPerformance = currentPositions.netPerformance;
let currentNetPerformancePercent =
currentPositions.netPerformancePercentage;
const totalInvestment = currentPositions.totalInvestment;
// if (currentGrossPerformance.mul(currentGrossPerformancePercent).lt(0)) {
// // If algebraic sign is different, harmonize it
@ -1074,7 +945,7 @@ export class PortfolioService {
// currentNetPerformancePercent = currentNetPerformancePercent.mul(-1);
// }
const historicalDataContainer = await this.getChartV2({
const historicalDataContainer = await this.getChart({
dateRange,
impersonationId
});
@ -1092,14 +963,24 @@ export class PortfolioService {
return {
chart: historicalDataContainer.items.map(
({ date, netPerformanceInPercentage }) => {
({
date,
netPerformance,
netPerformanceInPercentage,
totalInvestment,
value
}) => {
return {
date,
value: netPerformanceInPercentage
netPerformance,
netPerformanceInPercentage,
totalInvestment,
value
};
}
),
errors: currentPositions.errors,
firstOrderDate: parseDate(historicalDataContainer.items[0]?.date),
hasErrors: currentPositions.hasErrors || hasErrors,
performance: {
currentValue,
@ -1107,7 +988,8 @@ export class PortfolioService {
currentGrossPerformancePercent:
currentGrossPerformancePercent.toNumber(),
currentNetPerformance: currentNetPerformance.toNumber(),
currentNetPerformancePercent: currentNetPerformancePercent.toNumber()
currentNetPerformancePercent: currentNetPerformancePercent.toNumber(),
totalInvestment: totalInvestment.toNumber()
}
};
}
@ -1379,14 +1261,18 @@ export class PortfolioService {
return portfolioStart;
}
private async getSummary(
aImpersonationId: string
): Promise<PortfolioSummary> {
private async getSummary({
impersonationId
}: {
impersonationId: string;
}): Promise<PortfolioSummary> {
const userCurrency = this.request.user.Settings.settings.baseCurrency;
const userId = await this.getUserId(aImpersonationId, this.request.user.id);
const userId = await this.getUserId(impersonationId, this.request.user.id);
const user = await this.userService.user({ id: userId });
const performanceInformation = await this.getPerformance(aImpersonationId);
const performanceInformation = await this.getPerformance({
impersonationId
});
const { balanceInBaseCurrency } = await this.accountService.getCashDetails({
userId,

View File

@ -1,4 +1,8 @@
import type { DateRange, ViewMode } from '@ghostfolio/common/types';
import type {
ColorScheme,
DateRange,
ViewMode
} from '@ghostfolio/common/types';
import {
IsBoolean,
IsIn,
@ -16,6 +20,10 @@ export class UpdateUserSettingDto {
@IsOptional()
benchmark?: string;
@IsIn(<ColorScheme[]>['DARK', 'LIGHT'])
@IsOptional()
colorScheme?: ColorScheme;
@IsIn(<DateRange[]>['1d', '1y', '5y', 'max', 'ytd'])
@IsOptional()
dateRange?: DateRange;

View File

@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { ApiService } from './api.service';
@Module({
exports: [ApiService],
providers: [ApiService]
})
export class ApiModule {}

View File

@ -0,0 +1,42 @@
import { Filter } from '@ghostfolio/common/interfaces';
import { Injectable } from '@nestjs/common';
@Injectable()
export class ApiService {
public constructor() {}
public buildFiltersFromQueryParams({
filterByAccounts,
filterByAssetClasses,
filterByTags
}: {
filterByAccounts?: string;
filterByAssetClasses?: string;
filterByTags?: string;
}): Filter[] {
const accountIds = filterByAccounts?.split(',') ?? [];
const assetClasses = filterByAssetClasses?.split(',') ?? [];
const tagIds = filterByTags?.split(',') ?? [];
return [
...accountIds.map((accountId) => {
return <Filter>{
id: accountId,
type: 'ACCOUNT'
};
}),
...assetClasses.map((assetClass) => {
return <Filter>{
id: assetClass,
type: 'ASSET_CLASS'
};
}),
...tagIds.map((tagId) => {
return <Filter>{
id: tagId,
type: 'TAG'
};
})
];
}
}

View File

@ -38,7 +38,7 @@ export class ConfigurationService {
MAX_ACTIVITIES_TO_IMPORT: num({ default: Number.MAX_SAFE_INTEGER }),
MAX_ITEM_IN_CACHE: num({ default: 9999 }),
PORT: port({ default: 3333 }),
RAKUTEN_RAPID_API_KEY: str({ default: '' }),
RAPID_API_API_KEY: str({ default: '' }),
REDIS_HOST: host({ default: 'localhost' }),
REDIS_PASSWORD: str({ default: '' }),
REDIS_PORT: port({ default: 6379 }),

View File

@ -280,7 +280,7 @@ export class DataGatheringService {
return (
dataSource !== DataSource.GHOSTFOLIO &&
dataSource !== DataSource.MANUAL &&
dataSource !== DataSource.RAKUTEN
dataSource !== DataSource.RAPID_API
);
})
.map(({ dataSource, symbol }) => {

View File

@ -5,7 +5,7 @@ import { EodHistoricalDataService } from '@ghostfolio/api/services/data-provider
import { GhostfolioScraperApiService } from '@ghostfolio/api/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service';
import { GoogleSheetsService } from '@ghostfolio/api/services/data-provider/google-sheets/google-sheets.service';
import { ManualService } from '@ghostfolio/api/services/data-provider/manual/manual.service';
import { RakutenRapidApiService } from '@ghostfolio/api/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service';
import { RapidApiService } from '@ghostfolio/api/services/data-provider/rapid-api/rapid-api.service';
import { YahooFinanceService } from '@ghostfolio/api/services/data-provider/yahoo-finance/yahoo-finance.service';
import { PrismaModule } from '@ghostfolio/api/services/prisma.module';
import { SymbolProfileModule } from '@ghostfolio/api/services/symbol-profile.module';
@ -27,7 +27,7 @@ import { DataProviderService } from './data-provider.service';
GhostfolioScraperApiService,
GoogleSheetsService,
ManualService,
RakutenRapidApiService,
RapidApiService,
YahooFinanceService,
{
inject: [
@ -36,7 +36,7 @@ import { DataProviderService } from './data-provider.service';
GhostfolioScraperApiService,
GoogleSheetsService,
ManualService,
RakutenRapidApiService,
RapidApiService,
YahooFinanceService
],
provide: 'DataProviderInterfaces',
@ -46,7 +46,7 @@ import { DataProviderService } from './data-provider.service';
ghostfolioScraperApiService,
googleSheetsService,
manualService,
rakutenRapidApiService,
rapidApiService,
yahooFinanceService
) => [
alphaVantageService,
@ -54,7 +54,7 @@ import { DataProviderService } from './data-provider.service';
ghostfolioScraperApiService,
googleSheetsService,
manualService,
rakutenRapidApiService,
rapidApiService,
yahooFinanceService
]
}

View File

@ -1 +0,0 @@
export interface IRakutenRapidApiResponse {}

View File

@ -0,0 +1 @@
export interface IRapidApiResponse {}

View File

@ -15,14 +15,14 @@ import bent from 'bent';
import { format, subMonths, subWeeks, subYears } from 'date-fns';
@Injectable()
export class RakutenRapidApiService implements DataProviderInterface {
export class RapidApiService implements DataProviderInterface {
public constructor(
private readonly configurationService: ConfigurationService,
private readonly prismaService: PrismaService
) {}
public canHandle(symbol: string) {
return !!this.configurationService.get('RAKUTEN_RAPID_API_KEY');
return !!this.configurationService.get('RAPID_API_API_KEY');
}
public async getAssetProfile(
@ -103,7 +103,7 @@ export class RakutenRapidApiService implements DataProviderInterface {
}
public getName(): DataSource {
return DataSource.RAKUTEN;
return DataSource.RAPID_API;
}
public async getQuotes(
@ -129,7 +129,7 @@ export class RakutenRapidApiService implements DataProviderInterface {
};
}
} catch (error) {
Logger.error(error, 'RakutenRapidApiService');
Logger.error(error, 'RapidApiService');
}
return {};
@ -155,16 +155,14 @@ export class RakutenRapidApiService implements DataProviderInterface {
{
useQueryString: true,
'x-rapidapi-host': 'fear-and-greed-index.p.rapidapi.com',
'x-rapidapi-key': this.configurationService.get(
'RAKUTEN_RAPID_API_KEY'
)
'x-rapidapi-key': this.configurationService.get('RAPID_API_API_KEY')
}
);
const { fgi } = await get();
return fgi;
} catch (error) {
Logger.error(error, 'RakutenRapidApiService');
Logger.error(error, 'RapidApiService');
return undefined;
}

View File

@ -58,8 +58,15 @@ export class YahooFinanceService implements DataProviderInterface {
* DOGEUSD -> DOGE-USD
*/
public convertToYahooFinanceSymbol(aSymbol: string) {
if (aSymbol.includes(this.baseCurrency) && aSymbol.length >= 6) {
if (isCurrency(aSymbol.substring(0, aSymbol.length - 3))) {
if (
aSymbol.includes(this.baseCurrency) &&
aSymbol.length > this.baseCurrency.length
) {
if (
isCurrency(
aSymbol.substring(0, aSymbol.length - this.baseCurrency.length)
)
) {
return `${aSymbol}=X`;
} else if (
this.cryptocurrencyService.isCryptocurrency(

View File

@ -26,7 +26,7 @@ export interface Environment extends CleanedEnvAccessors {
MAX_ACTIVITIES_TO_IMPORT: number;
MAX_ITEM_IN_CACHE: number;
PORT: number;
RAKUTEN_RAPID_API_KEY: string;
RAPID_API_API_KEY: string;
REDIS_HOST: string;
REDIS_PASSWORD: string;
REDIS_PORT: number;

View File

@ -1,6 +1,7 @@
import { IsString } from 'class-validator';
import { IsOptional, IsString } from 'class-validator';
export class PropertyDto {
@IsOptional()
@IsString()
value: string;
}

View File

@ -53,13 +53,15 @@ export class TwitterBotService {
symbolItem.marketPrice
);
let status = `Current Market Mood: ${emoji} ${text} (${symbolItem.marketPrice}/100)`;
let status = `Current market mood is ${emoji} ${text.toLowerCase()} (${
symbolItem.marketPrice
}/100)`;
const benchmarkListing = await this.getBenchmarkListing(3);
if (benchmarkListing?.length > 1) {
status += '\n\n';
status += % from ATH\n';
status += '± from ATH in %\n';
status += benchmarkListing;
}

View File

@ -95,6 +95,13 @@ const routes: Routes = [
'./pages/blog/2022/08/500-stars-on-github/500-stars-on-github-page.module'
).then((m) => m.FiveHundredStarsOnGitHubPageModule)
},
{
path: 'blog/2022/10/hacktoberfest-2022',
loadChildren: () =>
import(
'./pages/blog/2022/10/hacktoberfest-2022/hacktoberfest-2022-page.module'
).then((m) => m.Hacktoberfest2022PageModule)
},
{
path: 'demo',
loadChildren: () =>

View File

@ -13,6 +13,7 @@ import {
} from '@ghostfolio/common/config';
import { InfoItem, User } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { ColorScheme } from '@ghostfolio/common/types';
import { MaterialCssVarsService } from 'angular-material-css-vars';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
@ -77,6 +78,8 @@ export class AppComponent implements OnDestroy, OnInit {
permissions.createUserAccount
);
this.initializeTheme(this.user?.settings.colorScheme);
this.changeDetectorRef.markForCheck();
});
}
@ -97,13 +100,17 @@ export class AppComponent implements OnDestroy, OnInit {
this.unsubscribeSubject.complete();
}
private initializeTheme() {
this.materialCssVarsService.setDarkTheme(
window.matchMedia('(prefers-color-scheme: dark)').matches
);
private initializeTheme(userPreferredColorScheme?: ColorScheme) {
const isDarkTheme = userPreferredColorScheme
? userPreferredColorScheme === 'DARK'
: window.matchMedia('(prefers-color-scheme: dark)').matches;
this.materialCssVarsService.setDarkTheme(isDarkTheme);
window.matchMedia('(prefers-color-scheme: dark)').addListener((event) => {
this.materialCssVarsService.setDarkTheme(event.matches);
if (!this.user?.settings.colorScheme) {
this.materialCssVarsService.setDarkTheme(event.matches);
}
});
this.materialCssVarsService.setPrimaryColor(primaryColorHex);

View File

@ -2,6 +2,7 @@
<gf-line-chart
class="mb-4"
[historicalDataItems]="historicalDataItems"
[isAnimated]="true"
[locale]="locale"
[showXAxis]="true"
[showYAxis]="true"

View File

@ -99,7 +99,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
...this.coupons,
{ code: this.generateCouponCode(16), duration: this.couponDuration }
];
this.putCoupons(coupons);
this.putAdminSetting({ key: PROPERTY_COUPONS, value: coupons });
}
public onAddCurrency() {
@ -107,7 +107,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
if (currency) {
const currencies = uniq([...this.customCurrencies, currency]);
this.putCurrencies(currencies);
this.putAdminSetting({ key: PROPERTY_CURRENCIES, value: currencies });
}
}
@ -124,7 +124,7 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
const coupons = this.coupons.filter((coupon) => {
return coupon.code !== aCouponCode;
});
this.putCoupons(coupons);
this.putAdminSetting({ key: PROPERTY_COUPONS, value: coupons });
}
}
@ -137,12 +137,12 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
const currencies = this.customCurrencies.filter((currency) => {
return currency !== aCurrency;
});
this.putCurrencies(currencies);
this.putAdminSetting({ key: PROPERTY_CURRENCIES, value: currencies });
}
}
public onDeleteSystemMessage() {
this.putSystemMessage('');
this.putAdminSetting({ key: PROPERTY_SYSTEM_MESSAGE, value: undefined });
}
public onFlushCache() {
@ -192,14 +192,20 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
}
public onReadOnlyModeChange(aEvent: MatSlideToggleChange) {
this.setReadOnlyMode(aEvent.checked);
this.putAdminSetting({
key: PROPERTY_IS_READ_ONLY_MODE,
value: aEvent.checked ? true : undefined
});
}
public onSetSystemMessage() {
const systemMessage = prompt($localize`Please set your system message:`);
if (systemMessage) {
this.putSystemMessage(systemMessage);
this.putAdminSetting({
key: PROPERTY_SYSTEM_MESSAGE,
value: systemMessage
});
}
}
@ -236,49 +242,10 @@ export class AdminOverviewComponent implements OnDestroy, OnInit {
return couponCode;
}
private putCoupons(aCoupons: Coupon[]) {
private putAdminSetting({ key, value }: { key: string; value: any }) {
this.dataService
.putAdminSetting(PROPERTY_COUPONS, {
value: JSON.stringify(aCoupons)
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
setTimeout(() => {
window.location.reload();
}, 300);
});
}
private putCurrencies(aCurrencies: string[]) {
this.dataService
.putAdminSetting(PROPERTY_CURRENCIES, {
value: JSON.stringify(aCurrencies)
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
setTimeout(() => {
window.location.reload();
}, 300);
});
}
private putSystemMessage(aSystemMessage: string) {
this.dataService
.putAdminSetting(PROPERTY_SYSTEM_MESSAGE, {
value: aSystemMessage
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {
setTimeout(() => {
window.location.reload();
}, 300);
});
}
private setReadOnlyMode(aValue: boolean) {
this.dataService
.putAdminSetting(PROPERTY_IS_READ_ONLY_MODE, {
value: aValue ? 'true' : ''
.putAdminSetting(key, {
value: value ? JSON.stringify(value) : undefined
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(() => {

View File

@ -5,15 +5,26 @@
<mat-card-content>
<div class="d-flex my-3">
<div class="w-50" i18n>User Count</div>
<div class="w-50">{{ userCount }}</div>
<div class="w-50">
<gf-value
precision="0"
[locale]="user?.settings?.locale"
[value]="userCount"
></gf-value>
</div>
</div>
<div class="d-flex my-3">
<div class="w-50" i18n>Activity Count</div>
<div class="w-50">
<ng-container *ngIf="transactionCount">
{{ transactionCount }} ({{ transactionCount / userCount | number
: '1.2-2' }} <span i18n>per User</span>)
</ng-container>
<gf-value
precision="0"
[locale]="user?.settings?.locale"
[value]="transactionCount"
></gf-value>
<div *ngIf="transactionCount && userCount">
{{ transactionCount / userCount | number : '1.2-2' }}
<span i18n>per User</span>
</div>
</div>
</div>
<div class="d-flex my-3">
@ -108,10 +119,20 @@
</div>
</div>
</div>
<div class="align-items-start d-flex my-3">
<div class="w-50" i18n>Benchmarks</div>
<div class="w-50">
<table>
<tr *ngFor="let benchmark of info?.benchmarks">
<td class="pl-1">{{ benchmark.symbol }}</td>
</tr>
</table>
</div>
</div>
<div *ngIf="hasPermissionForSystemMessage" class="d-flex my-3">
<div class="w-50" i18n>System Message</div>
<div class="w-50">
<div *ngIf="info.systemMessage">
<div *ngIf="info?.systemMessage">
<span>{{ info.systemMessage }}</span>
<button
class="mini-icon mx-1 no-min-width px-2"
@ -122,7 +143,7 @@
</button>
</div>
<button
*ngIf="!info.systemMessage"
*ngIf="!info?.systemMessage"
color="accent"
mat-flat-button
(click)="onSetSystemMessage()"

View File

@ -43,23 +43,23 @@
<td class="mat-cell px-1 py-2 text-right">
{{ formatDistanceToNow(userItem.createdAt) }}
</td>
<td class="mat-cell px-1 py-2">
<td class="mat-cell px-1 py-2 text-right">
<gf-value
class="align-items-end"
class="d-inline-block justify-content-end"
[locale]="user?.settings?.locale"
[value]="userItem.accountCount"
></gf-value>
</td>
<td class="mat-cell px-1 py-2">
<td class="mat-cell px-1 py-2 text-right">
<gf-value
class="align-items-end"
class="d-inline-block justify-content-end"
[locale]="user?.settings?.locale"
[value]="userItem.transactionCount"
></gf-value>
</td>
<td class="mat-cell px-1 py-2">
<td class="mat-cell px-1 py-2 text-right">
<gf-value
class="align-items-end"
class="d-inline-block justify-content-end"
[locale]="user?.settings?.locale"
[precision]="0"
[value]="userItem.engagement"

View File

@ -1,8 +1,7 @@
<div class="row">
<div class="mb-2 row">
<div class="col-md-6 col-xs-12 d-flex">
<div class="align-items-center d-flex flex-grow-1 h5 mb-0 text-truncate">
<span i18n>Benchmarks</span>
<sup i18n>Beta</sup>
<span i18n>Performance</span>
<gf-premium-indicator
*ngIf="user?.subscription?.type === 'Basic'"
class="ml-1"
@ -14,6 +13,7 @@
appearance="outline"
class="w-100 without-hint"
color="accent"
[hidden]="benchmarks?.length === 0"
>
<mat-label i18n>Compare with...</mat-label>
<mat-select
@ -21,6 +21,7 @@
[value]="benchmark"
(selectionChange)="onChangeBenchmark($event.value)"
>
<mat-option [value]="null"></mat-option>
<mat-option
*ngFor="let symbolProfile of benchmarks"
[value]="symbolProfile.id"
@ -30,14 +31,6 @@
</mat-form-field>
</div>
</div>
<div *ngIf="user.settings.viewMode !== 'ZEN'" class="my-2 text-center">
<gf-toggle
[defaultValue]="user?.settings?.dateRange"
[isLoading]="isLoading"
[options]="dateRangeOptions"
(change)="onChangeDateRange($event.value)"
></gf-toggle>
</div>
<div class="chart-container">
<ngx-skeleton-loader
*ngIf="isLoading"

View File

@ -10,7 +10,6 @@ import {
Output,
ViewChild
} from '@angular/core';
import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.component';
import {
getTooltipOptions,
getTooltipPositionerMapTop,
@ -24,7 +23,8 @@ import {
parseDate
} from '@ghostfolio/common/helper';
import { LineChartItem, User } from '@ghostfolio/common/interfaces';
import { DateRange } from '@ghostfolio/common/types';
import { ColorScheme } from '@ghostfolio/common/types';
import { SymbolProfile } from '@prisma/client';
import {
Chart,
LineController,
@ -35,7 +35,6 @@ import {
Tooltip
} from 'chart.js';
import annotationPlugin from 'chartjs-plugin-annotation';
import { SymbolProfile } from '@prisma/client';
@Component({
selector: 'gf-benchmark-comparator',
@ -47,6 +46,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
@Input() benchmarkDataItems: LineChartItem[] = [];
@Input() benchmark: string;
@Input() benchmarks: Partial<SymbolProfile>[];
@Input() colorScheme: ColorScheme;
@Input() daysInMarket: number;
@Input() isLoading: boolean;
@Input() locale: string;
@ -54,12 +54,10 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
@Input() user: User;
@Output() benchmarkChanged = new EventEmitter<string>();
@Output() dateRangeChanged = new EventEmitter<DateRange>();
@ViewChild('chartCanvas') chartCanvas;
public chart: Chart<any>;
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
public constructor() {
Chart.register(
@ -86,10 +84,6 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
this.benchmarkChanged.next(symbolProfileId);
}
public onChangeDateRange(dateRange: DateRange) {
this.dateRangeChanged.next(dateRange);
}
public ngOnDestroy() {
this.chart?.destroy();
}
@ -135,7 +129,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
tension: 0
},
point: {
hoverBackgroundColor: getBackgroundColor(),
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
hoverRadius: 2,
radius: 0
}
@ -146,7 +140,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
annotation: {
annotations: {
yAxis: {
borderColor: `rgba(${getTextColor()}, 0.1)`,
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
borderWidth: 1,
scaleID: 'y',
type: 'line',
@ -159,7 +153,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
},
tooltip: this.getTooltipPluginConfiguration(),
verticalHoverLine: {
color: `rgba(${getTextColor()}, 0.1)`
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
}
},
responsive: true,
@ -167,9 +161,9 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
x: {
display: true,
grid: {
borderColor: `rgba(${getTextColor()}, 0.1)`,
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
borderWidth: 1,
color: `rgba(${getTextColor()}, 0.8)`,
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
display: false
},
type: 'time',
@ -181,8 +175,8 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
y: {
display: true,
grid: {
borderColor: `rgba(${getTextColor()}, 0.1)`,
color: `rgba(${getTextColor()}, 0.8)`,
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
display: false,
drawBorder: false
},
@ -198,7 +192,9 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
}
}
},
plugins: [getVerticalHoverLinePlugin(this.chartCanvas)],
plugins: [
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
],
type: 'line'
});
}
@ -208,6 +204,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
private getTooltipPluginConfiguration() {
return {
...getTooltipOptions({
colorScheme: this.colorScheme,
locale: this.locale,
unit: '%'
}),

View File

@ -2,7 +2,6 @@ import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatSelectModule } from '@angular/material/select';
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
import { BenchmarkComparatorComponent } from './benchmark-comparator.component';
@ -13,7 +12,6 @@ import { BenchmarkComparatorComponent } from './benchmark-comparator.component';
imports: [
CommonModule,
FormsModule,
GfToggleModule,
MatSelectModule,
NgxSkeletonLoaderModule,
ReactiveFormsModule

View File

@ -127,6 +127,7 @@ export class HomeHoldingsComponent implements OnDestroy, OnInit {
dataSource,
symbol,
baseCurrency: this.user?.settings?.baseCurrency,
colorScheme: this.user?.settings?.colorScheme,
deviceType: this.deviceType,
hasImpersonationId: this.hasImpersonationId,
hasPermissionToReportDataGlitch: hasPermission(

View File

@ -24,7 +24,7 @@ export class HomeMarketComponent implements OnDestroy, OnInit {
public fearLabel = $localize`Fear`;
public greedLabel = $localize`Greed`;
public hasPermissionToAccessFearAndGreedIndex: boolean;
public historicalData: HistoricalDataItem[];
public historicalDataItems: HistoricalDataItem[];
public info: InfoItem;
public isLoading = true;
public readonly numberOfDays = 180;
@ -67,7 +67,7 @@ export class HomeMarketComponent implements OnDestroy, OnInit {
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ historicalData, marketPrice }) => {
this.fearAndGreedIndex = marketPrice;
this.historicalData = [
this.historicalDataItems = [
...historicalData,
{
date: resetHours(new Date()).toISOString(),

View File

@ -10,7 +10,8 @@
symbol="Fear & Greed Index"
yMax="100"
yMin="0"
[historicalDataItems]="historicalData"
[historicalDataItems]="historicalDataItems"
[isAnimated]="true"
[locale]="user?.settings?.locale"
[showXAxis]="true"
[showYAxis]="true"

View File

@ -107,8 +107,7 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
this.dataService
.fetchPortfolioPerformance({
range: this.user?.settings?.dateRange,
version: this.user?.settings?.isExperimentalFeatures ? 2 : 1
range: this.user?.settings?.dateRange
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((response) => {
@ -117,35 +116,14 @@ export class HomeOverviewComponent implements OnDestroy, OnInit {
this.performance = response.performance;
this.isLoadingPerformance = false;
if (this.user?.settings?.isExperimentalFeatures) {
this.historicalDataItems = response.chart.map(({ date, value }) => {
this.historicalDataItems = response.chart.map(
({ date, netPerformanceInPercentage }) => {
return {
date,
value
value: netPerformanceInPercentage
};
});
} else {
this.dataService
.fetchChart({
range: this.user?.settings?.dateRange,
version: 1
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((chartData) => {
this.historicalDataItems = chartData.chart.map(
({ date, value }) => {
return {
date,
value
};
}
);
this.isAllTimeHigh = chartData.isAllTimeHigh;
this.isAllTimeLow = chartData.isAllTimeLow;
this.changeDetectorRef.markForCheck();
});
}
}
);
this.changeDetectorRef.markForCheck();
});

View File

@ -15,16 +15,17 @@
<gf-line-chart
class="position-absolute"
symbol="Performance"
[currency]="user?.settings?.isExperimentalFeatures ? undefined : user?.settings?.baseCurrency"
[historicalDataItems]="historicalDataItems"
unit="%"
[colorScheme]="user?.settings?.colorScheme"
[hidden]="historicalDataItems?.length === 0"
[historicalDataItems]="historicalDataItems"
[isAnimated]="user?.settings?.dateRange === '1d' ? false : true"
[locale]="user?.settings?.locale"
[ngClass]="{ 'pr-3': deviceType === 'mobile' }"
[showGradient]="true"
[showLoader]="false"
[showXAxis]="false"
[showYAxis]="false"
[unit]="user?.settings?.isExperimentalFeatures ? '%' : undefined"
></gf-line-chart>
</div>
</div>

View File

@ -15,14 +15,16 @@ import {
} from '@ghostfolio/common/chart-helper';
import { primaryColorRgb, secondaryColorRgb } from '@ghostfolio/common/config';
import {
DATE_FORMAT,
getBackgroundColor,
getDateFormatString,
getTextColor,
parseDate,
transformTickToAbbreviation
} from '@ghostfolio/common/helper';
import { LineChartItem } from '@ghostfolio/common/interfaces';
import { InvestmentItem } from '@ghostfolio/common/interfaces/investment-item.interface';
import { GroupBy } from '@ghostfolio/common/types';
import { ColorScheme, DateRange, GroupBy } from '@ghostfolio/common/types';
import {
BarController,
BarElement,
@ -35,7 +37,7 @@ import {
Tooltip
} from 'chart.js';
import annotationPlugin from 'chartjs-plugin-annotation';
import { addDays, isAfter, parseISO, subDays } from 'date-fns';
import { addDays, format, isAfter, parseISO, subDays } from 'date-fns';
@Component({
selector: 'gf-investment-chart',
@ -44,17 +46,20 @@ import { addDays, isAfter, parseISO, subDays } from 'date-fns';
styleUrls: ['./investment-chart.component.scss']
})
export class InvestmentChartComponent implements OnChanges, OnDestroy {
@Input() benchmarkDataItems: InvestmentItem[] = [];
@Input() colorScheme: ColorScheme;
@Input() currency: string;
@Input() daysInMarket: number;
@Input() groupBy: GroupBy;
@Input() investments: InvestmentItem[];
@Input() historicalDataItems: LineChartItem[] = [];
@Input() isInPercent = false;
@Input() locale: string;
@Input() range: DateRange = 'max';
@Input() savingsRate = 0;
@ViewChild('chartCanvas') chartCanvas;
public chart: Chart;
public chart: Chart<any>;
public isLoading = true;
private data: InvestmentItem[];
@ -77,7 +82,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
}
public ngOnChanges() {
if (this.investments) {
if (this.benchmarkDataItems && this.historicalDataItems) {
this.initialize();
}
}
@ -90,55 +95,71 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
this.isLoading = true;
// Create a clone
this.data = this.investments.map((a) => Object.assign({}, a));
this.data = this.benchmarkDataItems.map((item) => Object.assign({}, item));
if (!this.groupBy && this.data?.length > 0) {
// Extend chart by 5% of days in market (before)
const firstItem = this.data[0];
this.data.unshift({
...firstItem,
date: subDays(
parseISO(firstItem.date),
this.daysInMarket * 0.05 || 90
).toISOString(),
investment: 0
});
if (this.range === 'max') {
// Extend chart by 5% of days in market (before)
const firstItem = this.data[0];
this.data.unshift({
...firstItem,
date: format(
subDays(parseISO(firstItem.date), this.daysInMarket * 0.05 || 90),
DATE_FORMAT
),
investment: 0
});
}
// Extend chart by 5% of days in market (after)
const lastItem = this.data[this.data.length - 1];
this.data.push({
...lastItem,
date: addDays(
parseDate(lastItem.date),
this.daysInMarket * 0.05 || 90
).toISOString()
date: format(
addDays(parseDate(lastItem.date), this.daysInMarket * 0.05 || 90),
DATE_FORMAT
)
});
}
const data = {
labels: this.data.map((investmentItem) => {
return investmentItem.date;
labels: this.historicalDataItems.map(({ date }) => {
return parseDate(date);
}),
datasets: [
{
backgroundColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderWidth: this.groupBy ? 0 : 2,
data: this.data.map((position) => {
return this.isInPercent
? position.investment * 100
: position.investment;
backgroundColor: `rgb(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b})`,
borderColor: `rgb(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b})`,
borderWidth: this.groupBy ? 0 : 1,
data: this.data.map(({ date, investment }) => {
return {
x: parseDate(date),
y: this.isInPercent ? investment * 100 : investment
};
}),
label: $localize`Deposit`,
segment: {
borderColor: (context: unknown) =>
this.isInFuture(
context,
`rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.67)`
`rgba(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b}, 0.67)`
),
borderDash: (context: unknown) => this.isInFuture(context, [2, 2])
},
stepped: true
},
{
borderColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderWidth: 2,
data: this.historicalDataItems.map(({ date, value }) => {
return {
x: parseDate(date),
y: this.isInPercent ? value * 100 : value
};
}),
fill: false,
label: $localize`Total Amount`,
pointRadius: 0
}
]
};
@ -160,7 +181,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
tension: 0
},
point: {
hoverBackgroundColor: getBackgroundColor(),
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
hoverRadius: 2,
radius: 0
}
@ -172,13 +193,13 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
annotations: {
savingsRate: this.savingsRate
? {
borderColor: `rgba(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b}, 0.75)`,
borderColor: `rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.75)`,
borderWidth: 1,
label: {
backgroundColor: `rgb(${secondaryColorRgb.r}, ${secondaryColorRgb.g}, ${secondaryColorRgb.b})`,
backgroundColor: `rgb(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b})`,
borderRadius: 2,
color: 'white',
content: 'Savings Rate',
content: $localize`Savings Rate`,
display: true,
font: { size: '10px', weight: 'normal' },
padding: {
@ -193,7 +214,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
}
: undefined,
yAxis: {
borderColor: `rgba(${getTextColor()}, 0.1)`,
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
borderWidth: 1,
scaleID: 'y',
type: 'line',
@ -206,7 +227,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
},
tooltip: this.getTooltipPluginConfiguration(),
verticalHoverLine: {
color: `rgba(${getTextColor()}, 0.1)`
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
}
},
responsive: true,
@ -214,9 +235,9 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
x: {
display: true,
grid: {
borderColor: `rgba(${getTextColor()}, 0.1)`,
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
borderWidth: this.groupBy ? 0 : 1,
color: `rgba(${getTextColor()}, 0.8)`,
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
display: false
},
type: 'time',
@ -228,8 +249,8 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
y: {
display: !this.isInPercent,
grid: {
borderColor: `rgba(${getTextColor()}, 0.1)`,
color: `rgba(${getTextColor()}, 0.8)`,
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
display: false,
drawBorder: false
},
@ -245,7 +266,9 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
}
}
},
plugins: [getVerticalHoverLinePlugin(this.chartCanvas)],
plugins: [
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
],
type: this.groupBy ? 'bar' : 'line'
});
}
@ -257,6 +280,7 @@ export class InvestmentChartComponent implements OnChanges, OnDestroy {
private getTooltipPluginConfiguration() {
return {
...getTooltipOptions({
colorScheme: this.colorScheme,
currency: this.isInPercent ? undefined : this.currency,
locale: this.isInPercent ? undefined : this.locale,
unit: this.isInPercent ? '%' : undefined

View File

@ -1,7 +1,9 @@
import { ColorScheme } from '@ghostfolio/common/types';
import { DataSource } from '@prisma/client';
export interface PositionDetailDialogParams {
baseCurrency: string;
colorScheme: ColorScheme;
dataSource: DataSource;
deviceType: string;
hasImpersonationId: boolean;

View File

@ -20,11 +20,13 @@
</div>
<gf-line-chart
class="mb-4"
benchmarkLabel="Average Unit Price"
class="mb-4"
[benchmarkDataItems]="benchmarkDataItems"
[colorScheme]="data.colorScheme"
[currency]="SymbolProfile?.currency"
[historicalDataItems]="historicalDataItems"
[isAnimated]="true"
[locale]="data.locale"
[showGradient]="true"
[showXAxis]="true"
@ -187,6 +189,7 @@
<div class="h5" i18n>Sectors</div>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="data.colorScheme"
[isInPercent]="true"
[keys]="['name']"
[locale]="user?.settings?.locale"
@ -198,6 +201,7 @@
<div class="h5" i18n>Countries</div>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="data.colorScheme"
[isInPercent]="true"
[keys]="['name']"
[locale]="user?.settings?.locale"

View File

@ -5,6 +5,7 @@ import {
Router,
RouterStateSnapshot
} from '@angular/router';
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 { EMPTY } from 'rxjs';
@ -30,6 +31,7 @@ export class AuthGuard implements CanActivate {
];
constructor(
private dataService: DataService,
private router: Router,
private settingsStorageService: SettingsStorageService,
private userService: UserService
@ -74,7 +76,12 @@ export class AuthGuard implements CanActivate {
const userLanguage = user?.settings?.language;
if (userLanguage && document.documentElement.lang !== userLanguage) {
window.location.href = `../${userLanguage}`;
this.dataService
.putUserSetting({ language: userLanguage })
.subscribe(() => {
this.userService.remove();
});
resolve(false);
return;
} else if (

View File

@ -42,6 +42,7 @@ export class AccountPageComponent implements OnDestroy, OnInit {
signInWithFingerprintElement: MatSlideToggle;
public accesses: Access[];
public appearancePlaceholder = $localize`Auto`;
public baseCurrency: string;
public coupon: number;
public couponId: string;

View File

@ -167,7 +167,7 @@
</mat-form-field>
</div>
</div>
<div class="d-flex">
<div class="d-flex mb-2">
<div class="align-items-center d-flex pr-1 pt-1 w-50">
<ng-container i18n>View Mode</ng-container>
</div>
@ -190,6 +190,30 @@
</div>
</div>
</div>
<div class="d-flex">
<div class="align-items-center d-flex pr-1 pt-1 w-50">
<ng-container i18n>Appearance</ng-container>
</div>
<div class="pl-1 w-50">
<mat-form-field
appearance="outline"
class="compact-with-outline w-100 without-hint"
>
<mat-select
class="with-placeholder-as-option"
name="colorScheme"
[disabled]="!hasPermissionToUpdateUserSettings"
[placeholder]="appearancePlaceholder"
[value]="user?.settings?.colorScheme"
(selectionChange)="onChangeUserSetting('colorScheme', $event.value)"
>
<mat-option i18n [value]="null">Auto</mat-option>
<mat-option i18n value="LIGHT">Light</mat-option>
<mat-option i18n value="DARK">Dark</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
</form>
</div>
<div class="align-items-center d-flex mt-4 py-1">
@ -243,8 +267,8 @@
class="align-items-center d-flex justify-content-center"
color="primary"
mat-fab
[routerLink]="[]"
[queryParams]="{ createDialog: true }"
[routerLink]="[]"
>
<ion-icon name="add-outline" size="large"></ion-icon>
</a>

View File

@ -119,7 +119,7 @@
Anlagestrategie? Ich freue mich über alle, die Ghostfolio
ausprobieren. Bist du überzeugt vom Potential der Software? Jede
Unterstützung für Ghostfolio ist willkommen. Sei es mit einer
<a href="https://ghostfol.io/pricing">Ghostfolio Premium</a>
<a [routerLink]="['/pricing']">Ghostfolio Premium</a>
Subscription zur Finanzierung des Hostings, einem positiven Rating
im
<a

View File

@ -115,7 +115,7 @@
strategy? I'm happy for everyone who tries Ghostfolio. Are you
convinced of its potential? Any support for Ghostfolio is welcome.
Be it with a
<a href="https://ghostfol.io/pricing">Ghostfolio Premium</a>
<a [routerLink]="['/pricing']">Ghostfolio Premium</a>
Subscription to finance the hosting, a positive rating in the
<a
href="https://play.google.com/store/apps/details?id=ch.dotsilver.ghostfolio.twa"

View File

@ -74,7 +74,7 @@
<a [routerLink]="['/markets']">economic situation</a> at this time,
the goal set at the beginning of the year to build a sustainable
business and reach break-even with the SaaS offering (<a
[routerLink]="['/markets']"
[routerLink]="['/pricing']"
>Ghostfolio Premium</a
>) has been achieved. We will continue to leverage the revenue to
further improve the fully managed cloud offering for our paying

View File

@ -0,0 +1,20 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from '@ghostfolio/client/core/auth.guard';
import { Hacktoberfest2022PageComponent } from './hacktoberfest-2022-page.component';
const routes: Routes = [
{
canActivate: [AuthGuard],
component: Hacktoberfest2022PageComponent,
path: '',
title: 'Hacktoberfest 2022'
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class Hacktoberfest2022RoutingModule {}

View File

@ -0,0 +1,9 @@
import { Component } from '@angular/core';
@Component({
host: { class: 'page' },
selector: 'gf-hacktoberfest-2022-page',
styleUrls: ['./hacktoberfest-2022-page.scss'],
templateUrl: './hacktoberfest-2022-page.html'
})
export class Hacktoberfest2022PageComponent {}

View File

@ -0,0 +1,178 @@
<div class="blog container">
<div class="row">
<div class="col-md-8 offset-md-2">
<article>
<div class="mb-4 text-center">
<h1 class="mb-1">Hacktoberfest 2022</h1>
<div class="mb-3 text-muted"><small>2022-10-01</small></div>
<img
alt="Hacktoberfest 2022 with Ghostfolio Teaser"
class="rounded w-100"
src="../assets/images/blog/hacktoberfest-2022.png"
title="Hacktoberfest 2022 with Ghostfolio"
/>
</div>
<section class="mb-4">
<p>
We are very excited to join
<a href="https://hacktoberfest.com">Hacktoberfest</a> for the first
time with <a href="https://ghostfol.io">Ghostfolio</a> and meet new
and ambitious open-source contributors. Hacktoberfest is a
month-long celebration of open-source projects, their maintainers,
and the entire community of contributors. Each October, open source
maintainers from all over the world give extra attention to new
contributors while guiding them through their first pull requests on
<a href="https://github.com/ghostfolio/ghostfolio">GitHub</a>.
</p>
</section>
<section class="mb-4">
<h2 class="h4">About Ghostfolio</h2>
<p>
Ghostfolio is a modern web application to manage your personal
finance. The software presents the current assets in real time and
supports the decision making of future investments. Whether
rebalancing the asset classes (stocks, ETFs, cryptocurrencies, etc.)
of your portfolio or financing an apartment, Ghostfolio offers
solid, data-driven decision support.
</p>
<p>
Ghostfolio is written in
<a href="https://www.typescriptlang.org">TypeScript</a> and
organized as an <a href="https://nx.dev">Nx</a> workspace. The
backend is based on <a href="https://nestjs.com">NestJS</a> using
<a href="https://www.postgresql.org">PostgreSQL</a> as a database
together with <a href="https://www.prisma.io">Prisma</a> and
<a href="https://redis.io">Redis</a> for caching. The frontend is
built with <a href="https://angular.io">Angular</a>.
</p>
</section>
<section class="mb-4">
<h2 class="h4">How to contribute?</h2>
<p>
Every contribution matters. This can be implementing new features,
fixing bugs, refactoring the code, improving the documentation,
adding more unit tests, or translating into another language.
</p>
<p>
Are you not yet familiar with our code base? That is not a problem.
We have applied the label <code>hacktoberfest</code> to a few
<a
href="https://github.com/ghostfolio/ghostfolio/issues?q=is%3Aissue+is%3Aopen+label%3Ahacktoberfest"
>issues</a
>
and
<a
href="https://github.com/ghostfolio/ghostfolio/discussions?discussions_q=label%3Ahacktoberfest"
>ideas</a
>
that are well suited for newcomers.
</p>
<p>
The official Hacktoberfest website provides some valuable
<a
href="https://hacktoberfest.com/participation/#beginner-resources"
>resources for beginners</a
>
to start contributing in open source.
</p>
</section>
<section class="mb-4">
<h2 class="h4">Get support</h2>
<p>
If you have further questions or ideas, please join our growing
<a href="https://ghostfolio.slack.com">Slack community</a> or get in
touch on Twitter
<a href="https://twitter.com/ghostfolio_">@ghostfolio_</a> or by
email via <a href="mailto:hi@ghostfol.io">hi@ghostfol.io</a>.
</p>
<p>
We look forward to hearing from you.<br />
Thomas from Ghostfolio
</p>
</section>
<section class="mb-4">
<ul class="list-inline">
<li class="list-inline-item">
<span class="badge badge-light">Angular</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Community</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Cryptocurrency</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">ETF</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Finance</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Fintech</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Ghostfolio</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">GitHub</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Hacktoberfest</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Investment</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">NestJS</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Nx</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">October</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Open Source</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">OSS</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Personal Finance</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Portfolio</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Portfolio Tracker</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Prisma</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Software</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Stock</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">TypeScript</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Wealth</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Wealth Management</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Web3</span>
</li>
<li class="list-inline-item">
<span class="badge badge-light">Web 3.0</span>
</li>
</ul>
</section>
</article>
</div>
</div>
</div>

View File

@ -0,0 +1,13 @@
import { CommonModule } from '@angular/common';
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { Hacktoberfest2022RoutingModule } from './hacktoberfest-2022-page-routing.module';
import { Hacktoberfest2022PageComponent } from './hacktoberfest-2022-page.component';
@NgModule({
declarations: [Hacktoberfest2022PageComponent],
imports: [CommonModule, Hacktoberfest2022RoutingModule, RouterModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class Hacktoberfest2022PageModule {}

View File

@ -0,0 +1,3 @@
:host {
display: block;
}

View File

@ -2,6 +2,30 @@
<div class="mb-5 row">
<div class="col">
<h3 class="mb-3 text-center" i18n>Blog</h3>
<mat-card class="mb-3">
<mat-card-content>
<div class="container p-0">
<div class="flex-nowrap no-gutters row">
<a
class="d-flex w-100"
href="../en/blog/2022/10/hacktoberfest-2022"
>
<div class="flex-grow-1">
<div class="h6 m-0 text-truncate">Hacktoberfest 2022</div>
<div class="d-flex text-muted">2022-10-01</div>
</div>
<div class="align-items-center d-flex">
<ion-icon
class="chevron text-muted"
name="chevron-forward-outline"
size="small"
></ion-icon>
</div>
</a>
</div>
</div>
</mat-card-content>
</mat-card>
<mat-card class="mb-3">
<mat-card-content>
<div class="container p-0">

View File

@ -3,6 +3,7 @@ import { DataService } from '@ghostfolio/client/services/data.service';
import { Statistics } from '@ghostfolio/common/interfaces/statistics.interface';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { format } from 'date-fns';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
@Component({
@ -14,6 +15,7 @@ import { Subject } from 'rxjs';
export class LandingPageComponent implements OnDestroy, OnInit {
public currentYear = format(new Date(), 'yyyy');
public demoAuthToken: string;
public deviceType: string;
public hasPermissionForStatistics: boolean;
public statistics: Statistics;
public testimonials = [
@ -41,7 +43,10 @@ export class LandingPageComponent implements OnDestroy, OnInit {
private unsubscribeSubject = new Subject<void>();
public constructor(private dataService: DataService) {
public constructor(
private dataService: DataService,
private deviceService: DeviceDetectorService
) {
const { globalPermissions, statistics } = this.dataService.fetchInfo();
this.hasPermissionForStatistics = hasPermission(
@ -52,7 +57,9 @@ export class LandingPageComponent implements OnDestroy, OnInit {
this.statistics = statistics;
}
public ngOnInit() {}
public ngOnInit() {
this.deviceType = this.deviceService.getDeviceInfo().deviceType;
}
public ngOnDestroy() {
this.unsubscribeSubject.next();

View File

@ -1,10 +1,15 @@
<div class="container">
<div class="row">
<div class="col text-center">
<h1 class="font-weight-bold intro my-5">
<h1 class="font-weight-bold intro mt-5">
Manage your wealth like a boss
</h1>
<div>
<p class="lead mb-4">
Ghostfolio is a privacy-first, open source dashboard to manage your
personal finances. Break down your asset allocation, know your net worth
and make solid, data-driven investment decisions.
</p>
<div class="mb-4">
<a
href="https://www.youtube.com/watch?v=yY6ObSQVJZk"
target="_blank"
@ -23,9 +28,9 @@
</div>
<div class="container">
<div class="button-container row">
<div class="button-container mb-5 row">
<div class="align-items-center col d-flex justify-content-center">
<div class="py-5 text-center">
<div class="text-center">
<a
class="d-inline-block"
color="primary"
@ -43,7 +48,10 @@
</div>
<div *ngIf="hasPermissionForStatistics" class="row mb-5">
<div class="col-md-4 d-flex my-1">
<div
class="col-md-4 d-flex my-1"
[ngClass]="{ 'justify-content-center': this.deviceType !== 'mobile' }"
>
<a
class="d-block"
title="Ghostfolio in Numbers: Monthly Active Users (MAU)"
@ -57,7 +65,10 @@
>
</a>
</div>
<div class="col-md-4 d-flex my-1">
<div
class="col-md-4 d-flex my-1"
[ngClass]="{ 'justify-content-center': this.deviceType !== 'mobile' }"
>
<a
class="d-block"
title="Ghostfolio in Numbers: Stars on GitHub"
@ -71,7 +82,10 @@
>
</a>
</div>
<div class="col-md-4 d-flex my-1">
<div
class="col-md-4 d-flex my-1"
[ngClass]="{ 'justify-content-center': this.deviceType !== 'mobile' }"
>
<a
class="d-block"
title="Ghostfolio in Numbers: Pulls on Docker Hub"
@ -139,15 +153,15 @@
</div>
</div>
<div class="row my-5">
<div class="pt-3 row">
<div class="col text-center">
<h2 class="h4 mb-1 text-center">
Protect your <strong>assets</strong>. Refine your
<strong>personal investment strategy</strong>.
</h2>
<p class="lead">
<p class="lead m-0">
Ghostfolio empowers busy people to keep track of stocks, ETFs or
cryptocurrencies and make solid, data-driven investment decisions.
cryptocurrencies without being tracked.
</p>
</div>
</div>
@ -220,7 +234,7 @@
</li>
</ul>
<div class="mt-4 text-center">
<a [routerLink]="['/about']" mat-stroked-button
<a mat-stroked-button [routerLink]="['/about']"
>Learn more about Ghostfolio</a
>
</div>

View File

@ -450,6 +450,7 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
dataSource,
symbol,
baseCurrency: this.user?.settings?.baseCurrency,
colorScheme: this.user?.settings?.colorScheme,
deviceType: this.deviceType,
hasImpersonationId: this.hasImpersonationId,
hasPermissionToReportDataGlitch: hasPermission(

View File

@ -13,12 +13,12 @@
<div class="row">
<div class="col">
<mat-card class="mb-3">
<mat-card-header class="overflow-hidden w-100">
<mat-card-title class="text-truncate" i18n
<mat-card-header class="mb-2 overflow-hidden w-100">
<mat-card-title class="m-0 text-truncate" i18n
>Proportion of Net Worth</mat-card-title
>
<gf-value
class="align-items-end flex-grow-1 ml-2"
class="justify-content-end l-2"
size="medium"
[isPercent]="true"
[value]="isLoading ? undefined : portfolioDetails?.filteredValueInPercentage"
@ -50,6 +50,7 @@
<gf-portfolio-proportion-chart
cursor="pointer"
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="user?.settings?.colorScheme"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['id']"
[locale]="user?.settings?.locale"
@ -79,6 +80,7 @@
<mat-card-content>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="user?.settings?.colorScheme"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['currency']"
[locale]="user?.settings?.locale"
@ -107,6 +109,7 @@
<mat-card-content>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="user?.settings?.colorScheme"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['assetClass', 'assetSubClass']"
[locale]="user?.settings?.locale"
@ -133,6 +136,7 @@
class="mx-auto"
cursor="pointer"
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="user?.settings?.colorScheme"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['symbol']"
[locale]="user?.settings?.locale"
@ -163,6 +167,7 @@
<mat-card-content>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="user?.settings?.colorScheme"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['name']"
[locale]="user?.settings?.locale"
@ -192,6 +197,7 @@
<mat-card-content>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="user?.settings?.colorScheme"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['name']"
[locale]="user?.settings?.locale"
@ -220,6 +226,7 @@
<mat-card-content>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[colorScheme]="user?.settings?.colorScheme"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[keys]="['name']"
[locale]="user?.settings?.locale"

View File

@ -1,4 +1,5 @@
import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { ToggleComponent } from '@ghostfolio/client/components/toggle/toggle.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';
@ -26,6 +27,7 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
public benchmarkDataItems: HistoricalDataItem[] = [];
public benchmarks: Partial<SymbolProfile>[];
public bottom3: Position[];
public dateRangeOptions = ToggleComponent.DEFAULT_DATE_RANGE_OPTIONS;
public daysInMarket: number;
public deviceType: string;
public firstOrderDate: Date;
@ -33,12 +35,12 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
public investments: InvestmentItem[];
public investmentsByMonth: InvestmentItem[];
public isLoadingBenchmarkComparator: boolean;
public mode: GroupBy;
public mode: GroupBy = 'month';
public modeOptions: ToggleOption[] = [
{ label: $localize`Monthly`, value: 'month' },
{ label: $localize`Accumulating`, value: undefined }
{ label: $localize`Monthly`, value: 'month' }
];
public performanceDataItems: HistoricalDataItem[];
public performanceDataItemsInPercentage: HistoricalDataItem[];
public top3: Position[];
public user: User;
@ -122,37 +124,48 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
}
private update() {
if (this.user.settings.isExperimentalFeatures) {
this.isLoadingBenchmarkComparator = true;
this.dataService
.fetchPortfolioPerformance({
range: this.user?.settings?.dateRange,
version: 2
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ chart }) => {
this.firstOrderDate = new Date(chart?.[0]?.date ?? new Date());
this.performanceDataItems = chart;
this.updateBenchmarkDataItems();
this.changeDetectorRef.markForCheck();
});
}
this.isLoadingBenchmarkComparator = true;
this.dataService
.fetchInvestments()
.fetchPortfolioPerformance({
range: this.user?.settings?.dateRange
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ firstOrderDate, investments }) => {
.subscribe(({ chart, firstOrderDate }) => {
this.firstOrderDate = firstOrderDate ?? new Date();
this.daysInMarket = differenceInDays(new Date(), firstOrderDate);
this.investments = investments;
this.investments = [];
this.performanceDataItems = [];
this.performanceDataItemsInPercentage = [];
for (const {
date,
netPerformanceInPercentage,
totalInvestment,
value
} of chart) {
this.investments.push({ date, investment: totalInvestment });
this.performanceDataItems.push({
date,
value
});
this.performanceDataItemsInPercentage.push({
date,
value: netPerformanceInPercentage
});
}
this.updateBenchmarkDataItems();
this.changeDetectorRef.markForCheck();
});
this.dataService
.fetchInvestmentsByMonth()
.fetchInvestments({
groupBy: 'month',
range: this.user?.settings?.dateRange
})
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ investments }) => {
this.investmentsByMonth = investments;
@ -161,7 +174,7 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
});
this.dataService
.fetchPositions({ range: 'max' })
.fetchPositions({ range: this.user?.settings?.dateRange })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(({ positions }) => {
const positionsSorted = sortBy(
@ -210,6 +223,8 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
this.changeDetectorRef.markForCheck();
});
} else {
this.benchmarkDataItems = [];
this.isLoadingBenchmarkComparator = false;
}
}

View File

@ -1,19 +1,27 @@
<div class="container">
<h3 class="d-flex justify-content-center mb-3" i18n>Analysis</h3>
<div *ngIf="user?.settings?.isExperimentalFeatures" class="mb-5 row">
<h3 class="d-flex justify-content-center" i18n>Analysis</h3>
<div *ngIf="user?.settings?.viewMode !== 'ZEN'" class="my-4 text-center">
<gf-toggle
[defaultValue]="user?.settings?.dateRange"
[isLoading]="isLoadingBenchmarkComparator"
[options]="dateRangeOptions"
(change)="onChangeDateRange($event.value)"
></gf-toggle>
</div>
<div class="mb-5 row">
<div class="col-lg">
<gf-benchmark-comparator
class="h-100"
[benchmark]="user?.settings?.benchmark"
[benchmarkDataItems]="benchmarkDataItems"
[benchmarks]="benchmarks"
[colorScheme]="user?.settings?.colorScheme"
[daysInMarket]="daysInMarket"
[isLoading]="isLoadingBenchmarkComparator"
[locale]="user?.settings?.locale"
[performanceDataItems]="performanceDataItems"
[performanceDataItems]="performanceDataItemsInPercentage"
[user]="user"
(benchmarkChanged)="onChangeBenchmark($event)"
(dateRangeChanged)="onChangeDateRange($event)"
></gf-benchmark-comparator>
</div>
</div>
@ -96,6 +104,34 @@
</div>
</div>
<div class="mb-5 row">
<div class="col-lg">
<div class="align-items-center d-flex mb-4">
<div
class="align-items-center d-flex flex-grow-1 h5 mb-0 text-truncate"
>
<span i18n>Portfolio Evolution</span>
<gf-premium-indicator
*ngIf="user?.subscription?.type === 'Basic'"
class="ml-1"
></gf-premium-indicator>
</div>
</div>
<div class="chart-container">
<gf-investment-chart
class="h-100"
[benchmarkDataItems]="investments"
[currency]="user?.settings?.baseCurrency"
[daysInMarket]="daysInMarket"
[historicalDataItems]="performanceDataItems"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[locale]="user?.settings?.locale"
[range]="user?.settings?.dateRange"
></gf-investment-chart>
</div>
</div>
</div>
<div class="row">
<div class="col-lg">
<div class="align-items-center d-flex mb-4">
@ -117,24 +153,15 @@
></gf-toggle>
</div>
<div class="chart-container">
<gf-investment-chart
class="h-100"
[currency]="user?.settings?.baseCurrency"
[daysInMarket]="daysInMarket"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[investments]="investments"
[locale]="user?.settings?.locale"
[ngClass]="{ 'd-none': mode }"
></gf-investment-chart>
<gf-investment-chart
class="h-100"
groupBy="month"
[benchmarkDataItems]="investmentsByMonth"
[currency]="user?.settings?.baseCurrency"
[daysInMarket]="daysInMarket"
[isInPercent]="hasImpersonationId || user.settings.isRestrictedView"
[investments]="investmentsByMonth"
[locale]="user?.settings?.locale"
[ngClass]="{ 'd-none': !mode }"
[range]="user?.settings?.dateRange"
[savingsRate]="(hasImpersonationId || user.settings.isRestrictedView) ? undefined : user?.settings?.savingsRate"
></gf-investment-chart>
</div>

View File

@ -5,6 +5,7 @@
<div>
<h4 class="mb-3" i18n>Calculator</h4>
<gf-fire-calculator
[colorScheme]="user?.settings?.colorScheme"
[currency]="user?.settings?.baseCurrency"
[deviceType]="deviceType"
[fireWealth]="fireWealth?.toNumber()"
@ -35,7 +36,7 @@
}"
></ngx-skeleton-loader>
</div>
<div *ngIf="!isLoading">
<div *ngIf="!isLoading" i18n>
If you retire today, you would be able to withdraw
<span class="font-weight-bold"
><gf-value

View File

@ -192,6 +192,7 @@ export class HoldingsPageComponent implements OnDestroy, OnInit {
dataSource,
symbol,
baseCurrency: this.user?.settings?.baseCurrency,
colorScheme: this.user?.settings?.colorScheme,
deviceType: this.deviceType,
hasImpersonationId: this.hasImpersonationId,
hasPermissionToReportDataGlitch: hasPermission(

View File

@ -405,6 +405,7 @@ export class TransactionsPageComponent implements OnDestroy, OnInit {
dataSource,
symbol,
baseCurrency: this.user?.settings?.baseCurrency,
colorScheme: this.user?.settings?.colorScheme,
deviceType: this.deviceType,
hasImpersonationId: this.hasImpersonationId,
hasPermissionToReportDataGlitch: hasPermission(

View File

@ -25,7 +25,6 @@ import {
Filter,
InfoItem,
OAuthResponse,
PortfolioChart,
PortfolioDetails,
PortfolioInvestments,
PortfolioPerformanceResponse,
@ -74,60 +73,19 @@ export class DataService {
}: {
filters?: Filter[];
}): Observable<Activities> {
let params = new HttpParams();
if (filters?.length > 0) {
const {
ACCOUNT: filtersByAccount,
ASSET_CLASS: filtersByAssetClass,
TAG: filtersByTag
} = groupBy(filters, (filter) => {
return filter.type;
});
if (filtersByAccount) {
params = params.append(
'accounts',
filtersByAccount
.map(({ id }) => {
return id;
})
.join(',')
);
}
if (filtersByAssetClass) {
params = params.append(
'assetClasses',
filtersByAssetClass
.map(({ id }) => {
return id;
})
.join(',')
);
}
if (filtersByTag) {
params = params.append(
'tags',
filtersByTag
.map(({ id }) => {
return id;
})
.join(',')
);
}
}
return this.http.get<any>('/api/v1/order', { params }).pipe(
map(({ activities }) => {
for (const activity of activities) {
activity.createdAt = parseISO(activity.createdAt);
activity.date = parseISO(activity.date);
}
return { activities };
return this.http
.get<any>('/api/v1/order', {
params: this.buildFiltersAsQueryParams({ filters })
})
);
.pipe(
map(({ activities }) => {
for (const activity of activities) {
activity.createdAt = parseISO(activity.createdAt);
activity.date = parseISO(activity.date);
}
return { activities };
})
);
}
public fetchAdminData() {
@ -135,30 +93,8 @@ export class DataService {
}
public fetchAdminMarketData({ filters }: { filters?: Filter[] }) {
let params = new HttpParams();
if (filters?.length > 0) {
const { ASSET_SUB_CLASS: filtersByAssetSubClass } = groupBy(
filters,
(filter) => {
return filter.type;
}
);
if (filtersByAssetSubClass) {
params = params.append(
'assetSubClasses',
filtersByAssetSubClass
.map(({ id }) => {
return id;
})
.join(',')
);
}
}
return this.http.get<AdminMarketData>('/api/v1/admin/market-data', {
params
params: this.buildFiltersAsQueryParams({ filters })
});
}
@ -201,12 +137,6 @@ export class DataService {
return this.http.get<BenchmarkResponse>('/api/v1/benchmark');
}
public fetchChart({ range, version }: { range: DateRange; version: number }) {
return this.http.get<PortfolioChart>(`/api/v${version}/portfolio/chart`, {
params: { range }
});
}
public fetchExport(activityIds?: string[]) {
let params = new HttpParams();
@ -233,34 +163,19 @@ export class DataService {
return info;
}
public fetchInvestments(): Observable<PortfolioInvestments> {
return this.http.get<any>('/api/v1/portfolio/investments').pipe(
map((response) => {
if (response.firstOrderDate) {
response.firstOrderDate = parseISO(response.firstOrderDate);
}
return response;
})
public fetchInvestments({
groupBy,
range
}: {
groupBy?: 'month';
range: DateRange;
}) {
return this.http.get<PortfolioInvestments>(
'/api/v1/portfolio/investments',
{ params: { groupBy, range } }
);
}
public fetchInvestmentsByMonth(): Observable<PortfolioInvestments> {
return this.http
.get<any>('/api/v1/portfolio/investments', {
params: { groupBy: 'month' }
})
.pipe(
map((response) => {
if (response.firstOrderDate) {
response.firstOrderDate = parseISO(response.firstOrderDate);
}
return response;
})
);
}
public fetchSymbolItem({
dataSource,
includeHistoricalData,
@ -306,54 +221,9 @@ export class DataService {
}: {
filters?: Filter[];
}): Observable<PortfolioDetails> {
let params = new HttpParams();
if (filters?.length > 0) {
const {
ACCOUNT: filtersByAccount,
ASSET_CLASS: filtersByAssetClass,
TAG: filtersByTag
} = groupBy(filters, (filter) => {
return filter.type;
});
if (filtersByAccount) {
params = params.append(
'accounts',
filtersByAccount
.map(({ id }) => {
return id;
})
.join(',')
);
}
if (filtersByAssetClass) {
params = params.append(
'assetClasses',
filtersByAssetClass
.map(({ id }) => {
return id;
})
.join(',')
);
}
if (filtersByTag) {
params = params.append(
'tags',
filtersByTag
.map(({ id }) => {
return id;
})
.join(',')
);
}
}
return this.http
.get<any>('/api/v1/portfolio/details', {
params
params: this.buildFiltersAsQueryParams({ filters })
})
.pipe(
map((response) => {
@ -368,16 +238,21 @@ export class DataService {
}
public fetchPortfolioPerformance({
range,
version
range
}: {
range: DateRange;
version: number;
}) {
return this.http.get<PortfolioPerformanceResponse>(
`/api/v${version}/portfolio/performance`,
{ params: { range } }
);
}): Observable<PortfolioPerformanceResponse> {
return this.http
.get<any>(`/api/v2/portfolio/performance`, { params: { range } })
.pipe(
map((response) => {
if (response.firstOrderDate) {
response.firstOrderDate = parseISO(response.firstOrderDate);
}
return response;
})
);
}
public fetchPortfolioPublic(aId: string) {
@ -458,4 +333,53 @@ export class DataService {
couponCode
});
}
private buildFiltersAsQueryParams({ filters }: { filters?: Filter[] }) {
let params = new HttpParams();
if (filters?.length > 0) {
const {
ACCOUNT: filtersByAccount,
ASSET_CLASS: filtersByAssetClass,
TAG: filtersByTag
} = groupBy(filters, (filter) => {
return filter.type;
});
if (filtersByAccount) {
params = params.append(
'accounts',
filtersByAccount
.map(({ id }) => {
return id;
})
.join(',')
);
}
if (filtersByAssetClass) {
params = params.append(
'assetClasses',
filtersByAssetClass
.map(({ id }) => {
return id;
})
.join(',')
);
}
if (filtersByTag) {
params = params.append(
'tags',
filtersByTag
.map(({ id }) => {
return id;
})
.join(',')
);
}
}
return params;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -6,70 +6,74 @@
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>https://ghostfol.io</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/de/blog/2021/07/hallo-ghostfolio</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/about/changelog</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2021/07/hello-ghostfolio</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/01/ghostfolio-first-months-in-open-source</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/07/ghostfolio-meets-internet-identity</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/07/how-do-i-get-my-finances-in-order</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/08/500-stars-on-github</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/blog/2022/10/hacktoberfest-2022</loc>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/demo</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/faq</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/features</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/markets</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/pricing</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/register</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
<url>
<loc>https://ghostfol.io/en/resources</loc>
<lastmod>2022-09-01T00:00:00+00:00</lastmod>
<lastmod>2022-10-16T00:00:00+00:00</lastmod>
</url>
</urlset>

View File

@ -6,65 +6,65 @@
<meta charset="utf-8" />
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta
content="Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies across multiple platforms."
name="description"
content="Ghostfolio is a lightweight application to keep track of your financial assets like stocks, ETFs or cryptocurrencies across multiple platforms."
/>
<meta
content="app, asset, cryptocurrency, dashboard, etf, finance, management, performance, portfolio, software, stock, trading, wealth, web3"
name="keywords"
content="app, asset, cryptocurrency, etf, finance, management, performance, portfolio, software, stock, tracker, trading, wealth"
/>
<meta name="mobile-web-app-capable" content="yes" />
<meta name="twitter:card" content="summary_large_image" />
<meta content="yes" name="mobile-web-app-capable" />
<meta content="summary_large_image" name="twitter:card" />
<meta
content="Ghostfolio is a personal finance dashboard to keep track of your assets like stocks, ETFs or cryptocurrencies"
name="twitter:description"
content="Ghostfolio is a lightweight wealth management application for individuals to keep track of stocks, ETFs or cryptocurrencies"
/>
<meta name="twitter:image" content="${rootUrl}/${featureGraphicPath}" />
<meta content="${rootUrl}/${featureGraphicPath}" name="twitter:image" />
<meta
content="Ghostfolio Open Source Wealth Management Software"
name="twitter:title"
content="Ghostfolio Open Source Wealth Management Software"
/>
<meta
name="viewport"
content="initial-scale=1, viewport-fit=cover, width=device-width"
name="viewport"
/>
<meta property="og:description" content="" />
<meta content="" property="og:description" />
<meta
content="Ghostfolio Open Source Wealth Management Software"
property="og:title"
content="Ghostfolio Open Source Wealth Management Software"
/>
<meta property="og:type" content="website" />
<meta property="og:url" content="${rootUrl}${path}" />
<meta property="og:image" content="${rootUrl}/${featureGraphicPath}" />
<meta property="og:updated_time" content="2022-08-18T00:00:00+00:00" />
<meta content="website" property="og:type" />
<meta content="${rootUrl}${path}" property="og:url" />
<meta content="${rootUrl}/${featureGraphicPath}" property="og:image" />
<meta content="2022-10-16T00:00:00+00:00" property="og:updated_time" />
<meta
property="og:site_name"
content="Ghostfolio Open Source Wealth Management Software"
property="og:site_name"
/>
<link
href="../assets/apple-touch-icon.png"
rel="apple-touch-icon"
sizes="180x180"
href="../assets/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="../assets/favicon-32x32.png"
rel="icon"
sizes="32x32"
type="image/png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="../assets/favicon-16x16.png"
rel="icon"
sizes="16x16"
type="image/png"
/>
<link rel="manifest" href="../assets/site.webmanifest" />
<link href="../assets/site.webmanifest" rel="manifest" />
</head>
<body>
<gf-root></gf-root>
<script type="module" src="../ionicons/ionicons.esm.js"></script>
<script src="../ionicons/ionicons.esm.js" type="module"></script>
<script nomodule="" src="ionicons.js"></script>
<noscript

View File

@ -15,7 +15,7 @@
</trans-unit>
<trans-unit id="ccb2a809018b32a96c813ae69126ce05976109ce" datatype="html">
<source>The risk of loss in trading can be substantial. It is not advisable to invest money you may need in the short term.</source>
<target state="translated">Das Ausfallrisiko beim Börsenhandel kann erheblich sein. Es ist nicht ratsam, Geld zu investieren, welches Sie kurzfristig benötigen.</target>
<target state="translated">Das Ausfallrisiko beim Börsenhandel kann erheblich sein. Es ist nicht ratsam, Geld zu investieren, welches du kurzfristig benötigst.</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
<context context-type="linenumber">55,56</context>
@ -98,7 +98,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">214</context>
<context context-type="linenumber">215</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/portfolio-page.html</context>
@ -354,7 +354,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">75</context>
<context context-type="linenumber">76</context>
</context-group>
</trans-unit>
<trans-unit id="d7b35c384aecd25a516200d6921836374613dfe7" datatype="html">
@ -418,7 +418,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">11</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="5eebcc824c2d34b17abba8c9ef718c5ce118a5c8" datatype="html">
@ -474,7 +474,7 @@
<target state="translated">Bitte gebe deine Systemmeldung ein:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">199</context>
<context context-type="linenumber">202</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -490,7 +490,7 @@
<target state="translated">pro Benutzer</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">15</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="5067ede95804e0e0e2b078747848367a7373cc9b" datatype="html">
@ -498,7 +498,7 @@
<target state="translated">Letzte Daten einholen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">33</context>
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="27e27f3f7338baefacfd5668bad03ece9c5955df" datatype="html">
@ -506,7 +506,7 @@
<target state="translated">Alle Daten einholen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">46</context>
<context context-type="linenumber">57</context>
</context-group>
</trans-unit>
<trans-unit id="cc65b67b46b69cf06ff1f16a909e61612c9d57b8" datatype="html">
@ -518,7 +518,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">60</context>
<context context-type="linenumber">71</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
@ -526,7 +526,7 @@
<target state="translated">Wechselkurse</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">78</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
@ -534,7 +534,7 @@
<target state="translated">Währung hinzufügen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">106</context>
<context context-type="linenumber">117</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -542,7 +542,7 @@
<target state="translated">Systemmeldung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">112</context>
<context context-type="linenumber">133</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -550,7 +550,7 @@
<target state="translated">Systemmeldung setzen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">134</context>
<context context-type="linenumber">155</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -558,7 +558,7 @@
<target state="translated">Lese-Modus</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -566,7 +566,7 @@
<target state="translated">Gutscheincodes</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">152</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -574,7 +574,7 @@
<target state="translated">Hinzufügen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">208</context>
</context-group>
</trans-unit>
<trans-unit id="e799e6b926557f0098f41888cdf8df868eff3d47" datatype="html">
@ -582,7 +582,7 @@
<target state="translated">Verwaltung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">194</context>
<context context-type="linenumber">215</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -590,7 +590,7 @@
<target state="translated">Cache leeren</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">219</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -946,7 +946,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">117</context>
<context context-type="linenumber">118</context>
</context-group>
</trans-unit>
<trans-unit id="a64cd8d0131a583e3de081c9e6458af7aecdafbc" datatype="html">
@ -1066,7 +1066,7 @@
<target state="translated">Sektoren</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">188</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -1078,7 +1078,7 @@
<target state="translated">Länder</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">199</context>
</context-group>
</trans-unit>
<trans-unit id="cafc87479686947e2590b9f588a88040aeaf660b" datatype="html">
@ -1086,7 +1086,7 @@
<target state="translated">Tags</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">234</context>
<context context-type="linenumber">235</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -1098,7 +1098,7 @@
<target state="translated">Datenfehler melden</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">250</context>
</context-group>
</trans-unit>
<trans-unit id="2ee26d58f2707416e636887111d5603b35346c4a" datatype="html">
@ -1112,9 +1112,13 @@
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
<source>Performance</source>
<target state="translated">Performance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/positions-table/positions-table.component.html</context>
@ -1270,7 +1274,7 @@
<target state="translated">Bitte gebe deinen Gutscheincode ein:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">225</context>
<context context-type="linenumber">226</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1278,7 +1282,7 @@
<target state="translated">Gutscheincode konnte nicht eingelöst werden</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">235</context>
<context context-type="linenumber">236</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1286,7 +1290,7 @@
<target state="translated">Gutscheincode wurde eingelöst</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">247</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1294,7 +1298,7 @@
<target state="translated">Neu laden</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">248</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1302,7 +1306,7 @@
<target state="translated">Möchtest du diese Anmeldemethode wirklich löschen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">294</context>
<context context-type="linenumber">295</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1414,7 +1418,7 @@
<target state="translated">Einloggen mit Fingerabdruck</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">220</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -1422,7 +1426,7 @@
<target state="translated">Benutzer ID</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">223</context>
<context context-type="linenumber">247</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -1430,7 +1434,7 @@
<target state="translated">Zugangsberechtigung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">232</context>
<context context-type="linenumber">256</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1718,7 +1722,7 @@
<target state="translated">Zeitstrahl der Investitionen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">105</context>
<context context-type="linenumber">140</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -1726,7 +1730,7 @@
<target state="translated">Gewinner</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">26</context>
<context context-type="linenumber">33</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -1734,7 +1738,7 @@
<target state="translated">Verlierer</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">62</context>
<context context-type="linenumber">69</context>
</context-group>
</trans-unit>
<trans-unit id="5857197365507636437" datatype="html">
@ -1954,7 +1958,7 @@
<target state="translated">Anzahl</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">108</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2006,7 +2010,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">146</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2050,7 +2054,7 @@
<target state="translated">Portfolio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">99</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
@ -2284,10 +2288,6 @@
<trans-unit id="313fcf0f8dac5ff5800a3e6bd67cb1955089ccca" datatype="html">
<source>Beta</source>
<target state="translated">Beta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">119</context>
@ -2314,7 +2314,7 @@
<target state="translated">Datenverwaltung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="3ccabfc3dc288eaa2355ba43298c739f85951ec3" datatype="html">
@ -2358,7 +2358,7 @@
<target state="translated">Änderung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="3c5ec7bc638db6f37c402e4afab2084f8763e268" datatype="html">
@ -2366,7 +2366,7 @@
<target state="translated">Ø Preis pro Einheit</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">65</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="b1c1c6a43da1ad3e41b7a6e3aa5dcc24226cf580" datatype="html">
@ -2374,7 +2374,7 @@
<target state="translated">Minimum Preis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">86</context>
<context context-type="linenumber">87</context>
</context-group>
</trans-unit>
<trans-unit id="6dd84054c52e1edf631f37accb054de0c4071069" datatype="html">
@ -2382,7 +2382,7 @@
<target state="translated">Maximum Preis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">97</context>
<context context-type="linenumber">98</context>
</context-group>
</trans-unit>
<trans-unit id="bf3df1f4eb29a071630eed167406c06f974480b2" datatype="html">
@ -2390,7 +2390,7 @@
<target state="translated">Datum des Erstkaufs</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
<trans-unit id="27fe3d097c64eaec7ff564358f80fb7ba795f484" datatype="html">
@ -2402,7 +2402,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">155</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2414,7 +2414,7 @@
<target state="translated">Sektor</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="a43f25a9ac40e8e2441ff0be7a36b8e5d15534df" datatype="html">
@ -2422,7 +2422,7 @@
<target state="translated">Land</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">181</context>
<context context-type="linenumber">182</context>
</context-group>
</trans-unit>
<trans-unit id="034c2b473d0b76acbc938453375b13cb2491dc17" datatype="html">
@ -2466,7 +2466,7 @@
<target state="translated">Transaktionen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">136</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
@ -2498,15 +2498,7 @@
<target state="translated">Monatlich</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">38</context>
</context-group>
</trans-unit>
<trans-unit id="1975246224413290232" datatype="html">
<source>Accumulating</source>
<target state="translated">Aufsummiert</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2514,11 +2506,11 @@
<target state="translated">Einlage</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">132</context>
<context context-type="linenumber">139</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">276</context>
<context context-type="linenumber">279</context>
</context-group>
</trans-unit>
<trans-unit id="3441715041566940420" datatype="html">
@ -2526,7 +2518,7 @@
<target state="translated">Verzinsung</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">286</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit id="1054498214311181686" datatype="html">
@ -2534,7 +2526,7 @@
<target state="translated">Ersparnisse</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">296</context>
<context context-type="linenumber">299</context>
</context-group>
</trans-unit>
<trans-unit id="aad5320acd7453f912bc8714e72c2fa71e8ab18e" datatype="html">
@ -2622,15 +2614,15 @@
<target state="translated">Experimentelle Funktionen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
<context context-type="linenumber">235</context>
</context-group>
</trans-unit>
<trans-unit id="1b25c6e22f822e07a3e4d5aae4edc5b41fe083c2" datatype="html">
<source>Benchmarks</source>
<target state="translated">Benchmarks</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
@ -2646,7 +2638,7 @@
<target state="translated">Benchmark</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">116</context>
<context context-type="linenumber">108</context>
</context-group>
</trans-unit>
<trans-unit id="4210837540bca56dca96fcc451518659d06ad02a" datatype="html">
@ -2659,7 +2651,7 @@
</trans-unit>
<trans-unit id="ac598d664f86ba5783915d65f2664a7f38a9d23a" datatype="html">
<source>Account Type</source>
<target state="new">Account Type</target>
<target state="translated">Kontotyp</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html</context>
<context context-type="linenumber">25</context>
@ -2667,12 +2659,84 @@
</trans-unit>
<trans-unit id="98fc3013bfcbf452b9f37bbfcdb77b9b882866e3" datatype="html">
<source>Excluded from Analysis</source>
<target state="new">Excluded from Analysis</target>
<target state="translated">Von der Analyse ausgenommen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">176</context>
</context-group>
</trans-unit>
<trans-unit id="458363f8e413759aa9e3235a53fd0f64cc916395" datatype="html">
<source> If you retire today, you would be able to withdraw <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per year<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> or <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per month<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/>, based on your total assets of <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> and a withdrawal rate of 4%. </source>
<target state="translated"> Wenn du heute in den Ruhestand gehen würdest, könnest du <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> pro Jahr<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> oder <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> pro Monat<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> entnehmen, bezogen auf dein Gesamtanlagevermögen von <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> und einer Entnahmerate von 4%. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">38,66</context>
</context-group>
</trans-unit>
<trans-unit id="616064537937996961" datatype="html">
<source>Auto</source>
<target state="translated">Automatisch</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
<source>Appearance</source>
<target state="translated">Aussehen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">195</context>
</context-group>
</trans-unit>
<trans-unit id="5fb13fb4a8447e59cdf05dc196ade39c02a6f8aa" datatype="html">
<source>Auto</source>
<target state="translated">Automatisch</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">210</context>
</context-group>
</trans-unit>
<trans-unit id="693d14f486a25e86bc515dfcfc4462d5201217ef" datatype="html">
<source>Light</source>
<target state="translated">Hell</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="adb4562d2dbd3584370e44496969d58c511ecb63" datatype="html">
<source>Dark</source>
<target state="translated">Dunkel</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">212</context>
</context-group>
</trans-unit>
<trans-unit id="112783260724635106" datatype="html">
<source>Total Amount</source>
<target state="translated">Gesamtbetrag</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
<source>Portfolio Evolution</source>
<target state="translated">Portfolio Wertentwicklung</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<target state="translated">Sparrate</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -99,7 +99,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">214</context>
<context context-type="linenumber">215</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/portfolio-page.html</context>
@ -355,7 +355,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">75</context>
<context context-type="linenumber">76</context>
</context-group>
</trans-unit>
<trans-unit id="d7b35c384aecd25a516200d6921836374613dfe7" datatype="html">
@ -419,7 +419,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">11</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="5eebcc824c2d34b17abba8c9ef718c5ce118a5c8" datatype="html">
@ -475,7 +475,7 @@
<target state="translated">Por favor, establece tu mensaje del sistema:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">199</context>
<context context-type="linenumber">202</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -491,7 +491,7 @@
<target state="translated">por usario</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">15</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="5067ede95804e0e0e2b078747848367a7373cc9b" datatype="html">
@ -499,7 +499,7 @@
<target state="translated">Recoger datos recientes</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">33</context>
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="27e27f3f7338baefacfd5668bad03ece9c5955df" datatype="html">
@ -507,7 +507,7 @@
<target state="translated">Recoger todos los datos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">46</context>
<context context-type="linenumber">57</context>
</context-group>
</trans-unit>
<trans-unit id="cc65b67b46b69cf06ff1f16a909e61612c9d57b8" datatype="html">
@ -519,7 +519,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">60</context>
<context context-type="linenumber">71</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
@ -527,7 +527,7 @@
<target state="translated">Tipos de cambio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">78</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
@ -535,7 +535,7 @@
<target state="translated">Añadir divisa</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">106</context>
<context context-type="linenumber">117</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -543,7 +543,7 @@
<target state="translated">Mensaje del sistema</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">112</context>
<context context-type="linenumber">133</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -551,7 +551,7 @@
<target state="translated">Establecer mensaje</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">134</context>
<context context-type="linenumber">155</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -559,7 +559,7 @@
<target state="translated">Modo de solo lectura</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -567,7 +567,7 @@
<target state="translated">Cupones</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">152</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -575,7 +575,7 @@
<target state="translated">Añadir</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">208</context>
</context-group>
</trans-unit>
<trans-unit id="e799e6b926557f0098f41888cdf8df868eff3d47" datatype="html">
@ -583,7 +583,7 @@
<target state="translated">Tareas domésticas</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">194</context>
<context context-type="linenumber">215</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -591,7 +591,7 @@
<target state="translated">Limpiar caché</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">219</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -947,7 +947,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">117</context>
<context context-type="linenumber">118</context>
</context-group>
</trans-unit>
<trans-unit id="a64cd8d0131a583e3de081c9e6458af7aecdafbc" datatype="html">
@ -968,7 +968,7 @@
</trans-unit>
<trans-unit id="e5c369abfbe1bd70f577aa03b2679797e38d7590" datatype="html">
<source> Fees for <x id="INTERPOLATION" equiv-text="{{ summary?.ordersCount }}"/> <x id="ICU" equiv-text="{summary?.ordersCount, plural, =1 {transaction} other {transactions}}"/> </source>
<target state="translated">Comisiones por <x id="INTERPOLATION" equiv-text="{{ summary?.ordersCount }}"/> <x id="ICU" equiv-text="{summary?.ordersCount, plural, =1 {transaction} otras {transactions}}"/> </target>
<target state="translated">Comisiones por <x id="INTERPOLATION" equiv-text="{{ summary?.ordersCount }}"/> <x id="ICU" equiv-text="{summary?.ordersCount, plural, =1 {transacción} other {transacciones}}"/> </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">77,80</context>
@ -976,7 +976,7 @@
</trans-unit>
<trans-unit id="272c7fd98af55bfa5b9d579176f1cfa25cd5489f" datatype="html">
<source>{VAR_PLURAL, plural, =1 {transaction} other {transactions}}</source>
<target state="translated">{VAR_PLURAL, plural, =1 {transaction} otras {transactions}}</target>
<target state="translated">{VAR_PLURAL, plural, =1 {transacción} other {transacciones}}</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">78,79</context>
@ -1067,7 +1067,7 @@
<target state="translated">Sectores</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">188</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -1079,7 +1079,7 @@
<target state="translated">Países</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">199</context>
</context-group>
</trans-unit>
<trans-unit id="cafc87479686947e2590b9f588a88040aeaf660b" datatype="html">
@ -1087,7 +1087,7 @@
<target state="translated">Etiquetas</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">234</context>
<context context-type="linenumber">235</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -1099,7 +1099,7 @@
<target state="translated">Reporta un anomalía de los datos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">250</context>
</context-group>
</trans-unit>
<trans-unit id="2ee26d58f2707416e636887111d5603b35346c4a" datatype="html">
@ -1113,9 +1113,13 @@
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
<source>Performance</source>
<target state="translated">Rendimiento</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/positions-table/positions-table.component.html</context>
@ -1271,7 +1275,7 @@
<target state="translated">Por favor, ingresa tu código de cupón:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">225</context>
<context context-type="linenumber">226</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1279,7 +1283,7 @@
<target state="translated">No se puede canjear este código de cupón</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">235</context>
<context context-type="linenumber">236</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1287,7 +1291,7 @@
<target state="translated">El codigo de cupón ha sido canjeado</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">247</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1295,7 +1299,7 @@
<target state="translated">Refrescar</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">248</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1303,7 +1307,7 @@
<target state="translated">¿Estás seguro de eliminar este método de acceso?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">294</context>
<context context-type="linenumber">295</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1415,7 +1419,7 @@
<target state="translated">Accede con huella digital</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">220</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -1423,7 +1427,7 @@
<target state="translated">ID usuario</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">223</context>
<context context-type="linenumber">247</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -1431,7 +1435,7 @@
<target state="translated">Acceso concedido</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">232</context>
<context context-type="linenumber">256</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1460,7 +1464,7 @@
</trans-unit>
<trans-unit id="220a4641dcde60d1d86ceec62886b1878f1578d3" datatype="html">
<source>Update account</source>
<target state="translated">Mejorar cuenta</target>
<target state="translated">Editar cuenta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/accounts/create-or-update-account-dialog/create-or-update-account-dialog.html</context>
<context context-type="linenumber">2</context>
@ -1719,7 +1723,7 @@
<target state="translated">Cronología de la inversión</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">105</context>
<context context-type="linenumber">140</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -1727,7 +1731,7 @@
<target state="translated">Lo mejor</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">26</context>
<context context-type="linenumber">33</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -1735,7 +1739,7 @@
<target state="translated">Lo peor</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">62</context>
<context context-type="linenumber">69</context>
</context-group>
</trans-unit>
<trans-unit id="5857197365507636437" datatype="html">
@ -1955,7 +1959,7 @@
<target state="translated">Cantidad</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">108</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2007,7 +2011,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">146</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2051,7 +2055,7 @@
<target state="translated">Cartera</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">99</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
@ -2285,10 +2289,6 @@
<trans-unit id="313fcf0f8dac5ff5800a3e6bd67cb1955089ccca" datatype="html">
<source>Beta</source>
<target state="translated">Beta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">119</context>
@ -2315,7 +2315,7 @@
<target state="translated">Gestión de los datos</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="3ccabfc3dc288eaa2355ba43298c739f85951ec3" datatype="html">
@ -2359,7 +2359,7 @@
<target state="translated">Modificar</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="034c2b473d0b76acbc938453375b13cb2491dc17" datatype="html">
@ -2383,7 +2383,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">155</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2395,7 +2395,7 @@
<target state="translated">Precio unitario medio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">65</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="6dd84054c52e1edf631f37accb054de0c4071069" datatype="html">
@ -2403,7 +2403,7 @@
<target state="translated">Precio máximo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">97</context>
<context context-type="linenumber">98</context>
</context-group>
</trans-unit>
<trans-unit id="7233cd3a1ef8913fa5c6db7a29c88044646ceacc" datatype="html">
@ -2435,7 +2435,7 @@
<target state="translated">Sector</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="a43f25a9ac40e8e2441ff0be7a36b8e5d15534df" datatype="html">
@ -2443,7 +2443,7 @@
<target state="translated">País</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">181</context>
<context context-type="linenumber">182</context>
</context-group>
</trans-unit>
<trans-unit id="b1c1c6a43da1ad3e41b7a6e3aa5dcc24226cf580" datatype="html">
@ -2451,7 +2451,7 @@
<target state="translated">Precio mínimo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">86</context>
<context context-type="linenumber">87</context>
</context-group>
</trans-unit>
<trans-unit id="bf3df1f4eb29a071630eed167406c06f974480b2" datatype="html">
@ -2459,7 +2459,7 @@
<target state="translated">Fecha de la primera compra</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
<trans-unit id="add4cd82e3e38a3110fe67b3c7df56e9602644ee" datatype="html">
@ -2467,7 +2467,7 @@
<target state="translated">Transacciones</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">136</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
@ -2483,15 +2483,7 @@
<target state="translated">Ahorros</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">296</context>
</context-group>
</trans-unit>
<trans-unit id="1975246224413290232" datatype="html">
<source>Accumulating</source>
<target state="translated">Acumulando</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">299</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
@ -2507,7 +2499,7 @@
<target state="translated">Interés</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">286</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2515,11 +2507,11 @@
<target state="translated">Depósito</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">132</context>
<context context-type="linenumber">139</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">276</context>
<context context-type="linenumber">279</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
@ -2535,7 +2527,7 @@
<target state="translated">Mensual</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">38</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
@ -2623,7 +2615,7 @@
<target state="translated">Funcionalidades experimentales</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
<context context-type="linenumber">235</context>
</context-group>
</trans-unit>
<trans-unit id="1931353503905413384" datatype="html">
@ -2631,15 +2623,15 @@
<target state="translated">Benchmark</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">116</context>
<context context-type="linenumber">108</context>
</context-group>
</trans-unit>
<trans-unit id="1b25c6e22f822e07a3e4d5aae4edc5b41fe083c2" datatype="html">
<source>Benchmarks</source>
<target state="translated">Benchmark</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
@ -2660,7 +2652,7 @@
</trans-unit>
<trans-unit id="ac598d664f86ba5783915d65f2664a7f38a9d23a" datatype="html">
<source>Account Type</source>
<target state="new">Account Type</target>
<target state="translated">Tipo de cuenta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html</context>
<context context-type="linenumber">25</context>
@ -2668,12 +2660,84 @@
</trans-unit>
<trans-unit id="98fc3013bfcbf452b9f37bbfcdb77b9b882866e3" datatype="html">
<source>Excluded from Analysis</source>
<target state="new">Excluded from Analysis</target>
<target state="translated">Excluido del análisis</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">176</context>
</context-group>
</trans-unit>
<trans-unit id="458363f8e413759aa9e3235a53fd0f64cc916395" datatype="html">
<source> If you retire today, you would be able to withdraw <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per year<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> or <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per month<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/>, based on your total assets of <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> and a withdrawal rate of 4%. </source>
<target state="translated"> Si te jubilas hoy, podrías retirar <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> por año<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> o <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> por mes<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/>, calculado sobre el total de activos de <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> y una tasa de disposición del 4%. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">38,66</context>
</context-group>
</trans-unit>
<trans-unit id="616064537937996961" datatype="html">
<source>Auto</source>
<target state="translated">Automático</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
<source>Appearance</source>
<target state="translated">Apariencia</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">195</context>
</context-group>
</trans-unit>
<trans-unit id="5fb13fb4a8447e59cdf05dc196ade39c02a6f8aa" datatype="html">
<source>Auto</source>
<target state="translated">Automático</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">210</context>
</context-group>
</trans-unit>
<trans-unit id="693d14f486a25e86bc515dfcfc4462d5201217ef" datatype="html">
<source>Light</source>
<target state="translated">Claro</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="adb4562d2dbd3584370e44496969d58c511ecb63" datatype="html">
<source>Dark</source>
<target state="translated">Oscuro</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">212</context>
</context-group>
</trans-unit>
<trans-unit id="112783260724635106" datatype="html">
<source>Total Amount</source>
<target state="new">Total Amount</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
<source>Portfolio Evolution</source>
<target state="new">Portfolio Evolution</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<target state="translated">Tasa de ahorro</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -99,7 +99,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">214</context>
<context context-type="linenumber">215</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/portfolio-page.html</context>
@ -355,7 +355,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">75</context>
<context context-type="linenumber">76</context>
</context-group>
</trans-unit>
<trans-unit id="d7b35c384aecd25a516200d6921836374613dfe7" datatype="html">
@ -419,7 +419,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">11</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="5eebcc824c2d34b17abba8c9ef718c5ce118a5c8" datatype="html">
@ -475,7 +475,7 @@
<target state="translated">Imposta il messaggio di sistema:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">199</context>
<context context-type="linenumber">202</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -491,7 +491,7 @@
<target state="translated">per utente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">15</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="5067ede95804e0e0e2b078747848367a7373cc9b" datatype="html">
@ -499,7 +499,7 @@
<target state="translated">Raccogli dati recenti</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">33</context>
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="27e27f3f7338baefacfd5668bad03ece9c5955df" datatype="html">
@ -507,7 +507,7 @@
<target state="translated">Raccogli tutti i dati</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">46</context>
<context context-type="linenumber">57</context>
</context-group>
</trans-unit>
<trans-unit id="cc65b67b46b69cf06ff1f16a909e61612c9d57b8" datatype="html">
@ -519,7 +519,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">60</context>
<context context-type="linenumber">71</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
@ -527,7 +527,7 @@
<target state="translated">Tassi di cambio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">78</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
@ -535,7 +535,7 @@
<target state="translated">Aggiungi valuta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">106</context>
<context context-type="linenumber">117</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -543,7 +543,7 @@
<target state="translated">Messaggio di sistema</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">112</context>
<context context-type="linenumber">133</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -551,7 +551,7 @@
<target state="translated">Imposta messaggio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">134</context>
<context context-type="linenumber">155</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -559,7 +559,7 @@
<target state="translated">Modalità di sola lettura</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -567,7 +567,7 @@
<target state="translated">Buoni sconto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">152</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -575,7 +575,7 @@
<target state="translated">Aggiungi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">208</context>
</context-group>
</trans-unit>
<trans-unit id="e799e6b926557f0098f41888cdf8df868eff3d47" datatype="html">
@ -583,7 +583,7 @@
<target state="translated">Bilancio domestico</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">194</context>
<context context-type="linenumber">215</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -591,7 +591,7 @@
<target state="translated">Svuota la cache</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">219</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -947,7 +947,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">117</context>
<context context-type="linenumber">118</context>
</context-group>
</trans-unit>
<trans-unit id="a64cd8d0131a583e3de081c9e6458af7aecdafbc" datatype="html">
@ -968,7 +968,7 @@
</trans-unit>
<trans-unit id="e5c369abfbe1bd70f577aa03b2679797e38d7590" datatype="html">
<source> Fees for <x id="INTERPOLATION" equiv-text="{{ summary?.ordersCount }}"/> <x id="ICU" equiv-text="{summary?.ordersCount, plural, =1 {transaction} other {transactions}}"/> </source>
<target state="translated">Commissioni per <x id="INTERPOLATION" equiv-text="{{ summary?.ordersCount }}"/> <x id="ICU" equiv-text="{summary?.ordersCount, plural, =1 {transaction} other {transactions}}"/> </target>
<target state="translated">Commissioni per <x id="INTERPOLATION" equiv-text="{{ summary?.ordersCount }}"/> <x id="ICU" equiv-text="{summary?.ordersCount, plural, =1 {transazione} other {transazioni}}"/> </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">77,80</context>
@ -976,7 +976,7 @@
</trans-unit>
<trans-unit id="272c7fd98af55bfa5b9d579176f1cfa25cd5489f" datatype="html">
<source>{VAR_PLURAL, plural, =1 {transaction} other {transactions}}</source>
<target state="translated">{VAR_PLURAL, plural, =1 {transaction} altre {transactions}}</target>
<target state="translated">{VAR_PLURAL, plural, =1 {transazione} other {transazioni}}</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">78,79</context>
@ -1067,7 +1067,7 @@
<target state="translated">Settori</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">188</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -1079,7 +1079,7 @@
<target state="translated">Paesi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">199</context>
</context-group>
</trans-unit>
<trans-unit id="cafc87479686947e2590b9f588a88040aeaf660b" datatype="html">
@ -1087,7 +1087,7 @@
<target state="translated">Tag</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">234</context>
<context context-type="linenumber">235</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -1099,7 +1099,7 @@
<target state="translated">Segnala un&apos;anomalia dei dati</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">250</context>
</context-group>
</trans-unit>
<trans-unit id="2ee26d58f2707416e636887111d5603b35346c4a" datatype="html">
@ -1113,9 +1113,13 @@
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
<source>Performance</source>
<target state="translated">Prestazioni </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/positions-table/positions-table.component.html</context>
@ -1271,7 +1275,7 @@
<target state="translated">Inserisci il tuo codice del buono:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">225</context>
<context context-type="linenumber">226</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1279,7 +1283,7 @@
<target state="translated">Impossibile riscattare il codice del buono</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">235</context>
<context context-type="linenumber">236</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1287,7 +1291,7 @@
<target state="translated">Il codice del buono è stato riscattato</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">247</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1295,7 +1299,7 @@
<target state="translated">Ricarica</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">248</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1303,7 +1307,7 @@
<target state="translated">Vuoi davvero rimuovere questo metodo di accesso?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">294</context>
<context context-type="linenumber">295</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1415,7 +1419,7 @@
<target state="translated">Accesso con impronta digitale</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">220</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -1423,7 +1427,7 @@
<target state="translated">ID utente</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">223</context>
<context context-type="linenumber">247</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -1431,7 +1435,7 @@
<target state="translated">Accesso concesso</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">232</context>
<context context-type="linenumber">256</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1719,7 +1723,7 @@
<target state="translated">Cronologia degli investimenti</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">105</context>
<context context-type="linenumber">140</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -1727,7 +1731,7 @@
<target state="translated">In alto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">26</context>
<context context-type="linenumber">33</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -1735,7 +1739,7 @@
<target state="translated">In basso</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">62</context>
<context context-type="linenumber">69</context>
</context-group>
</trans-unit>
<trans-unit id="5857197365507636437" datatype="html">
@ -1955,7 +1959,7 @@
<target state="translated">Quantità</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">108</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2007,7 +2011,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">146</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2051,7 +2055,7 @@
<target state="translated">Portafoglio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">99</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
@ -2285,10 +2289,6 @@
<trans-unit id="313fcf0f8dac5ff5800a3e6bd67cb1955089ccca" datatype="html">
<source>Beta</source>
<target state="translated">Beta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">119</context>
@ -2315,7 +2315,7 @@
<target state="translated">Gestione dei dati</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="3ccabfc3dc288eaa2355ba43298c739f85951ec3" datatype="html">
@ -2359,7 +2359,7 @@
<target state="translated">Modifica</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="034c2b473d0b76acbc938453375b13cb2491dc17" datatype="html">
@ -2383,7 +2383,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">155</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2395,7 +2395,7 @@
<target state="translated">Prezzo unitario medio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">65</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="6dd84054c52e1edf631f37accb054de0c4071069" datatype="html">
@ -2403,7 +2403,7 @@
<target state="translated">Prezzo massimo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">97</context>
<context context-type="linenumber">98</context>
</context-group>
</trans-unit>
<trans-unit id="7233cd3a1ef8913fa5c6db7a29c88044646ceacc" datatype="html">
@ -2435,7 +2435,7 @@
<target state="translated">Settore</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="a43f25a9ac40e8e2441ff0be7a36b8e5d15534df" datatype="html">
@ -2443,7 +2443,7 @@
<target state="translated">Paese</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">181</context>
<context context-type="linenumber">182</context>
</context-group>
</trans-unit>
<trans-unit id="b1c1c6a43da1ad3e41b7a6e3aa5dcc24226cf580" datatype="html">
@ -2451,7 +2451,7 @@
<target state="translated">Prezzo minimo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">86</context>
<context context-type="linenumber">87</context>
</context-group>
</trans-unit>
<trans-unit id="bf3df1f4eb29a071630eed167406c06f974480b2" datatype="html">
@ -2459,7 +2459,7 @@
<target state="translated">Data del primo acquisto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
<trans-unit id="add4cd82e3e38a3110fe67b3c7df56e9602644ee" datatype="html">
@ -2467,7 +2467,7 @@
<target state="translated">Transazioni</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">136</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
@ -2483,15 +2483,7 @@
<target state="translated">Risparmio</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">296</context>
</context-group>
</trans-unit>
<trans-unit id="1975246224413290232" datatype="html">
<source>Accumulating</source>
<target state="translated">Accumulo</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">299</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
@ -2507,7 +2499,7 @@
<target state="translated">Interesse</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">286</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2515,11 +2507,11 @@
<target state="translated">Deposito</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">132</context>
<context context-type="linenumber">139</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">276</context>
<context context-type="linenumber">279</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
@ -2535,7 +2527,7 @@
<target state="translated">Mensile</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">38</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
@ -2623,7 +2615,7 @@
<target state="translated">Funzionalità sperimentali</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
<context context-type="linenumber">235</context>
</context-group>
</trans-unit>
<trans-unit id="1931353503905413384" datatype="html">
@ -2631,15 +2623,15 @@
<target state="translated">Benchmark</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">116</context>
<context context-type="linenumber">108</context>
</context-group>
</trans-unit>
<trans-unit id="1b25c6e22f822e07a3e4d5aae4edc5b41fe083c2" datatype="html">
<source>Benchmarks</source>
<target state="translated">Benchmark</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
@ -2658,22 +2650,94 @@
<context context-type="linenumber">18</context>
</context-group>
</trans-unit>
<trans-unit id="ac598d664f86ba5783915d65f2664a7f38a9d23a" datatype="html">
<source>Account Type</source>
<target state="new">Account Type</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html</context>
<context context-type="linenumber">25</context>
</context-group>
</trans-unit>
<trans-unit id="98fc3013bfcbf452b9f37bbfcdb77b9b882866e3" datatype="html">
<source>Excluded from Analysis</source>
<target state="new">Excluded from Analysis</target>
<target state="translated">Escluso dall&apos;analisi</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
<context context-type="linenumber">176</context>
</context-group>
</trans-unit>
<trans-unit id="ac598d664f86ba5783915d65f2664a7f38a9d23a" datatype="html">
<source>Account Type</source>
<target state="translated">Tipo di account</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/account-detail-dialog/account-detail-dialog.html</context>
<context context-type="linenumber">25</context>
</context-group>
</trans-unit>
<trans-unit id="458363f8e413759aa9e3235a53fd0f64cc916395" datatype="html">
<source> If you retire today, you would be able to withdraw <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per year<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> or <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per month<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/>, based on your total assets of <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> and a withdrawal rate of 4%. </source>
<target state="translated">Se andassi in pensione oggi, potresti ritirare <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> all&apos;anno<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> o <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> al mese<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/>, sulla base dei tuoi asset totali pari a <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> e un tasso di prelievo del 4%. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">38,66</context>
</context-group>
</trans-unit>
<trans-unit id="616064537937996961" datatype="html">
<source>Auto</source>
<target state="new">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
<source>Appearance</source>
<target state="new">Appearance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">195</context>
</context-group>
</trans-unit>
<trans-unit id="5fb13fb4a8447e59cdf05dc196ade39c02a6f8aa" datatype="html">
<source>Auto</source>
<target state="new">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">210</context>
</context-group>
</trans-unit>
<trans-unit id="693d14f486a25e86bc515dfcfc4462d5201217ef" datatype="html">
<source>Light</source>
<target state="new">Light</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="adb4562d2dbd3584370e44496969d58c511ecb63" datatype="html">
<source>Dark</source>
<target state="new">Dark</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">212</context>
</context-group>
</trans-unit>
<trans-unit id="112783260724635106" datatype="html">
<source>Total Amount</source>
<target state="new">Total Amount</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
<source>Portfolio Evolution</source>
<target state="new">Portfolio Evolution</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<target state="translated">Tasso di risparmio</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -98,7 +98,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">214</context>
<context context-type="linenumber">215</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/portfolio-page.html</context>
@ -354,7 +354,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">75</context>
<context context-type="linenumber">76</context>
</context-group>
</trans-unit>
<trans-unit id="d7b35c384aecd25a516200d6921836374613dfe7" datatype="html">
@ -418,7 +418,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">11</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="5eebcc824c2d34b17abba8c9ef718c5ce118a5c8" datatype="html">
@ -474,7 +474,7 @@
<target state="translated">Stel uw systeemboodschap in:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">199</context>
<context context-type="linenumber">202</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -490,7 +490,7 @@
<target state="translated">per gebruiker</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">15</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="5067ede95804e0e0e2b078747848367a7373cc9b" datatype="html">
@ -498,7 +498,7 @@
<target state="translated">Verzamel recente gegevens</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">33</context>
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="27e27f3f7338baefacfd5668bad03ece9c5955df" datatype="html">
@ -506,7 +506,7 @@
<target state="translated">Alle gegevens verzamelen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">46</context>
<context context-type="linenumber">57</context>
</context-group>
</trans-unit>
<trans-unit id="cc65b67b46b69cf06ff1f16a909e61612c9d57b8" datatype="html">
@ -518,7 +518,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">60</context>
<context context-type="linenumber">71</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
@ -526,7 +526,7 @@
<target state="translated">Wisselkoersen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">78</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
@ -534,7 +534,7 @@
<target state="translated">Valuta toevoegen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">106</context>
<context context-type="linenumber">117</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
@ -542,7 +542,7 @@
<target state="translated">Systeembericht</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">112</context>
<context context-type="linenumber">133</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
@ -550,7 +550,7 @@
<target state="translated">Bericht instellen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">134</context>
<context context-type="linenumber">155</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
@ -558,7 +558,7 @@
<target state="translated">Alleen lezen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
@ -566,7 +566,7 @@
<target state="translated">Coupons</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">152</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
@ -574,7 +574,7 @@
<target state="translated">Toevoegen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">208</context>
</context-group>
</trans-unit>
<trans-unit id="e799e6b926557f0098f41888cdf8df868eff3d47" datatype="html">
@ -582,7 +582,7 @@
<target state="translated">Huishouding</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">194</context>
<context context-type="linenumber">215</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
@ -590,7 +590,7 @@
<target state="translated">Cache legen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">219</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -946,7 +946,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">117</context>
<context context-type="linenumber">118</context>
</context-group>
</trans-unit>
<trans-unit id="a64cd8d0131a583e3de081c9e6458af7aecdafbc" datatype="html">
@ -1066,7 +1066,7 @@
<target state="translated">Sectoren</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">188</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -1078,7 +1078,7 @@
<target state="translated">Landen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">199</context>
</context-group>
</trans-unit>
<trans-unit id="cafc87479686947e2590b9f588a88040aeaf660b" datatype="html">
@ -1086,7 +1086,7 @@
<target state="translated">Tags</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">234</context>
<context context-type="linenumber">235</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -1098,7 +1098,7 @@
<target state="translated">Gegevensstoring melden</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">250</context>
</context-group>
</trans-unit>
<trans-unit id="2ee26d58f2707416e636887111d5603b35346c4a" datatype="html">
@ -1112,9 +1112,13 @@
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
<source>Performance</source>
<target state="translated">Prestaties</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/positions-table/positions-table.component.html</context>
@ -1270,7 +1274,7 @@
<target state="translated">Voer uw couponcode in:</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">225</context>
<context context-type="linenumber">226</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
@ -1278,7 +1282,7 @@
<target state="translated">Kon kortingscode niet inwisselen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">235</context>
<context context-type="linenumber">236</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
@ -1286,7 +1290,7 @@
<target state="translated">Couponcode is ingewisseld</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">247</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
@ -1294,7 +1298,7 @@
<target state="translated">Herladen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">248</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
@ -1302,7 +1306,7 @@
<target state="translated">Wilt u deze aanmeldingsmethode echt verwijderen?</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">294</context>
<context context-type="linenumber">295</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1414,7 +1418,7 @@
<target state="translated">Aanmelden met vingerafdruk</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">220</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
@ -1422,7 +1426,7 @@
<target state="translated">Gebruikers-ID</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">223</context>
<context context-type="linenumber">247</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
@ -1430,7 +1434,7 @@
<target state="translated">Verleende toegang</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">232</context>
<context context-type="linenumber">256</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1718,7 +1722,7 @@
<target state="translated">Tijdlijn investeringen</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">105</context>
<context context-type="linenumber">140</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
@ -1726,7 +1730,7 @@
<target state="translated">Top</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">26</context>
<context context-type="linenumber">33</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
@ -1734,7 +1738,7 @@
<target state="translated">Onder</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">62</context>
<context context-type="linenumber">69</context>
</context-group>
</trans-unit>
<trans-unit id="5857197365507636437" datatype="html">
@ -1954,7 +1958,7 @@
<target state="translated">Hoeveelheid</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">108</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2006,7 +2010,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">146</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2050,7 +2054,7 @@
<target state="translated">Portefeuille</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">99</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
@ -2284,10 +2288,6 @@
<trans-unit id="313fcf0f8dac5ff5800a3e6bd67cb1955089ccca" datatype="html">
<source>Beta</source>
<target state="translated">Beta</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">119</context>
@ -2314,7 +2314,7 @@
<target state="translated">Gegevensbeheer</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="3ccabfc3dc288eaa2355ba43298c739f85951ec3" datatype="html">
@ -2358,7 +2358,7 @@
<target state="translated">Verandering</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="034c2b473d0b76acbc938453375b13cb2491dc17" datatype="html">
@ -2382,7 +2382,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">155</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2394,7 +2394,7 @@
<target state="translated">Gemiddelde prijs per eenheid</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">65</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="6dd84054c52e1edf631f37accb054de0c4071069" datatype="html">
@ -2402,7 +2402,7 @@
<target state="translated">Maximale prijs</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">97</context>
<context context-type="linenumber">98</context>
</context-group>
</trans-unit>
<trans-unit id="7233cd3a1ef8913fa5c6db7a29c88044646ceacc" datatype="html">
@ -2434,7 +2434,7 @@
<target state="translated">Sector</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="a43f25a9ac40e8e2441ff0be7a36b8e5d15534df" datatype="html">
@ -2442,7 +2442,7 @@
<target state="translated">Land</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">181</context>
<context context-type="linenumber">182</context>
</context-group>
</trans-unit>
<trans-unit id="b1c1c6a43da1ad3e41b7a6e3aa5dcc24226cf580" datatype="html">
@ -2450,7 +2450,7 @@
<target state="translated">Minimale prijs</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">86</context>
<context context-type="linenumber">87</context>
</context-group>
</trans-unit>
<trans-unit id="bf3df1f4eb29a071630eed167406c06f974480b2" datatype="html">
@ -2458,7 +2458,7 @@
<target state="translated">Eerste aankoopdatum</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
<trans-unit id="add4cd82e3e38a3110fe67b3c7df56e9602644ee" datatype="html">
@ -2466,7 +2466,7 @@
<target state="translated">Transacties</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">136</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
@ -2482,15 +2482,7 @@
<target state="translated">Besparingen</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">296</context>
</context-group>
</trans-unit>
<trans-unit id="1975246224413290232" datatype="html">
<source>Accumulating</source>
<target state="translated">Accumuleren</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">299</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
@ -2506,7 +2498,7 @@
<target state="translated">Rente</target>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">286</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
@ -2514,11 +2506,11 @@
<target state="translated">Storting</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">132</context>
<context context-type="linenumber">139</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">276</context>
<context context-type="linenumber">279</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
@ -2534,7 +2526,7 @@
<target state="translated">Maandelijks</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">38</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
@ -2622,7 +2614,7 @@
<target state="translated">Experimentele functies</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
<context context-type="linenumber">235</context>
</context-group>
</trans-unit>
<trans-unit id="1931353503905413384" datatype="html">
@ -2630,15 +2622,15 @@
<target state="translated">Benchmark</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">116</context>
<context context-type="linenumber">108</context>
</context-group>
</trans-unit>
<trans-unit id="1b25c6e22f822e07a3e4d5aae4edc5b41fe083c2" datatype="html">
<source>Benchmarks</source>
<target state="translated">Benchmarks</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
@ -2673,6 +2665,78 @@
<context context-type="linenumber">176</context>
</context-group>
</trans-unit>
<trans-unit id="458363f8e413759aa9e3235a53fd0f64cc916395" datatype="html">
<source> If you retire today, you would be able to withdraw <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per year<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> or <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per month<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/>, based on your total assets of <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> and a withdrawal rate of 4%. </source>
<target state="new"> If you retire today, you would be able to withdraw <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per year<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> or <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per month<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/>, based on your total assets of <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> and a withdrawal rate of 4%. </target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">38,66</context>
</context-group>
</trans-unit>
<trans-unit id="616064537937996961" datatype="html">
<source>Auto</source>
<target state="new">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
<source>Appearance</source>
<target state="new">Appearance</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">195</context>
</context-group>
</trans-unit>
<trans-unit id="5fb13fb4a8447e59cdf05dc196ade39c02a6f8aa" datatype="html">
<source>Auto</source>
<target state="new">Auto</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">210</context>
</context-group>
</trans-unit>
<trans-unit id="693d14f486a25e86bc515dfcfc4462d5201217ef" datatype="html">
<source>Light</source>
<target state="new">Light</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="adb4562d2dbd3584370e44496969d58c511ecb63" datatype="html">
<source>Dark</source>
<target state="new">Dark</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">212</context>
</context-group>
</trans-unit>
<trans-unit id="112783260724635106" datatype="html">
<source>Total Amount</source>
<target state="new">Total Amount</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
<source>Portfolio Evolution</source>
<target state="new">Portfolio Evolution</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<target state="translated">Spaarquote</target>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -91,7 +91,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">214</context>
<context context-type="linenumber">215</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/portfolio-page.html</context>
@ -326,7 +326,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">75</context>
<context context-type="linenumber">76</context>
</context-group>
</trans-unit>
<trans-unit id="d7b35c384aecd25a516200d6921836374613dfe7" datatype="html">
@ -386,7 +386,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">11</context>
<context context-type="linenumber">17</context>
</context-group>
</trans-unit>
<trans-unit id="5eebcc824c2d34b17abba8c9ef718c5ce118a5c8" datatype="html">
@ -435,7 +435,7 @@
<source>Please set your system message:</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.component.ts</context>
<context context-type="linenumber">199</context>
<context context-type="linenumber">202</context>
</context-group>
</trans-unit>
<trans-unit id="ec03f5c28b327fc7ecfc4b20a0a7cf14a75843ff" datatype="html">
@ -449,21 +449,21 @@
<source>per User</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">15</context>
<context context-type="linenumber">26</context>
</context-group>
</trans-unit>
<trans-unit id="5067ede95804e0e0e2b078747848367a7373cc9b" datatype="html">
<source>Gather Recent Data</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">33</context>
<context context-type="linenumber">44</context>
</context-group>
</trans-unit>
<trans-unit id="27e27f3f7338baefacfd5668bad03ece9c5955df" datatype="html">
<source>Gather All Data</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">46</context>
<context context-type="linenumber">57</context>
</context-group>
</trans-unit>
<trans-unit id="cc65b67b46b69cf06ff1f16a909e61612c9d57b8" datatype="html">
@ -474,70 +474,70 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">60</context>
<context context-type="linenumber">71</context>
</context-group>
</trans-unit>
<trans-unit id="37ff0697aa81b2777250c483d2ce1ebdaa5ab042" datatype="html">
<source>Exchange Rates</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">67</context>
<context context-type="linenumber">78</context>
</context-group>
</trans-unit>
<trans-unit id="4567a660a7f67e254bbf13219906843e34d9f807" datatype="html">
<source>Add Currency</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">106</context>
<context context-type="linenumber">117</context>
</context-group>
</trans-unit>
<trans-unit id="860e5f056b59410ec8db65cb53955505c6931752" datatype="html">
<source>System Message</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">112</context>
<context context-type="linenumber">133</context>
</context-group>
</trans-unit>
<trans-unit id="657028d5fc9c3da8f2d667b6b15cd0df8b9a3729" datatype="html">
<source>Set Message</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">134</context>
<context context-type="linenumber">155</context>
</context-group>
</trans-unit>
<trans-unit id="7fd64c34428887e4cd56d05534b89c100b8544ad" datatype="html">
<source>Read-only Mode</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">139</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="e698b03c34b459b1b006d7f0473a49b9fcf5dfc1" datatype="html">
<source>Coupons</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">152</context>
<context context-type="linenumber">173</context>
</context-group>
</trans-unit>
<trans-unit id="f6755cff4957d5c3c89bafce5651f1b6fa2b1fd9" datatype="html">
<source>Add</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">208</context>
</context-group>
</trans-unit>
<trans-unit id="e799e6b926557f0098f41888cdf8df868eff3d47" datatype="html">
<source>Housekeeping</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">194</context>
<context context-type="linenumber">215</context>
</context-group>
</trans-unit>
<trans-unit id="c7ac907e52a7ce2ac70b1786eb5f403ce306ce1f" datatype="html">
<source>Flush Cache</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">219</context>
</context-group>
</trans-unit>
<trans-unit id="2817099043823177227" datatype="html">
@ -859,7 +859,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">117</context>
<context context-type="linenumber">118</context>
</context-group>
</trans-unit>
<trans-unit id="a64cd8d0131a583e3de081c9e6458af7aecdafbc" datatype="html">
@ -964,7 +964,7 @@
<source>Sectors</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">187</context>
<context context-type="linenumber">188</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
@ -975,14 +975,14 @@
<source>Countries</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">198</context>
<context context-type="linenumber">199</context>
</context-group>
</trans-unit>
<trans-unit id="cafc87479686947e2590b9f588a88040aeaf660b" datatype="html">
<source>Tags</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">234</context>
<context context-type="linenumber">235</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -993,7 +993,7 @@
<source>Report Data Glitch</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">249</context>
<context context-type="linenumber">250</context>
</context-group>
</trans-unit>
<trans-unit id="2ee26d58f2707416e636887111d5603b35346c4a" datatype="html">
@ -1005,9 +1005,13 @@
</trans-unit>
<trans-unit id="3cc9c2ae277393b3946b38c088dabff671b1ee1b" datatype="html">
<source>Performance</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">55</context>
<context context-type="linenumber">56</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/positions-table/positions-table.component.html</context>
@ -1145,35 +1149,35 @@
<source>Please enter your coupon code:</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">225</context>
<context context-type="linenumber">226</context>
</context-group>
</trans-unit>
<trans-unit id="4420880039966769543" datatype="html">
<source>Could not redeem coupon code</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">235</context>
<context context-type="linenumber">236</context>
</context-group>
</trans-unit>
<trans-unit id="4819099731531004979" datatype="html">
<source>Coupon code has been redeemed</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">247</context>
<context context-type="linenumber">248</context>
</context-group>
</trans-unit>
<trans-unit id="7967484035994732534" datatype="html">
<source>Reload</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">248</context>
<context context-type="linenumber">249</context>
</context-group>
</trans-unit>
<trans-unit id="7963559562180316948" datatype="html">
<source>Do you really want to remove this sign in method?</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">294</context>
<context context-type="linenumber">295</context>
</context-group>
</trans-unit>
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
@ -1272,21 +1276,21 @@
<source>Sign in with fingerprint</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">196</context>
<context context-type="linenumber">220</context>
</context-group>
</trans-unit>
<trans-unit id="83c4d4d764d2e2725ab8e919ec16ac400e1f290a" datatype="html">
<source>User ID</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">223</context>
<context context-type="linenumber">247</context>
</context-group>
</trans-unit>
<trans-unit id="9021c579c084e68d9db06a569d76f024111c6c54" datatype="html">
<source>Granted Access</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">232</context>
<context context-type="linenumber">256</context>
</context-group>
</trans-unit>
<trans-unit id="5e41f1b4c46ad9e0a9bc83fa36445483aa5cc324" datatype="html">
@ -1543,21 +1547,21 @@
<source>Investment Timeline</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">105</context>
<context context-type="linenumber">140</context>
</context-group>
</trans-unit>
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
<source>Top</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">26</context>
<context context-type="linenumber">33</context>
</context-group>
</trans-unit>
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
<source>Bottom</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">62</context>
<context context-type="linenumber">69</context>
</context-group>
</trans-unit>
<trans-unit id="5857197365507636437" datatype="html">
@ -1751,7 +1755,7 @@
<source>Quantity</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">108</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -1799,7 +1803,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">145</context>
<context context-type="linenumber">146</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -1838,7 +1842,7 @@
<source>Portfolio</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">107</context>
<context context-type="linenumber">99</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
@ -2043,10 +2047,6 @@
</trans-unit>
<trans-unit id="313fcf0f8dac5ff5800a3e6bd67cb1955089ccca" datatype="html">
<source>Beta</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">5</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">119</context>
@ -2070,7 +2070,7 @@
<source>Data Management</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">20</context>
<context context-type="linenumber">31</context>
</context-group>
</trans-unit>
<trans-unit id="3ccabfc3dc288eaa2355ba43298c739f85951ec3" datatype="html">
@ -2109,7 +2109,7 @@
<source>Change</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">44</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="034c2b473d0b76acbc938453375b13cb2491dc17" datatype="html">
@ -2131,7 +2131,7 @@
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">154</context>
<context context-type="linenumber">155</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/transactions/create-or-update-transaction-dialog/create-or-update-transaction-dialog.html</context>
@ -2142,14 +2142,14 @@
<source>Average Unit Price</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">65</context>
<context context-type="linenumber">66</context>
</context-group>
</trans-unit>
<trans-unit id="6dd84054c52e1edf631f37accb054de0c4071069" datatype="html">
<source>Maximum Price</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">97</context>
<context context-type="linenumber">98</context>
</context-group>
</trans-unit>
<trans-unit id="7233cd3a1ef8913fa5c6db7a29c88044646ceacc" datatype="html">
@ -2178,35 +2178,35 @@
<source>Sector</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">169</context>
<context context-type="linenumber">170</context>
</context-group>
</trans-unit>
<trans-unit id="a43f25a9ac40e8e2441ff0be7a36b8e5d15534df" datatype="html">
<source>Country</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">181</context>
<context context-type="linenumber">182</context>
</context-group>
</trans-unit>
<trans-unit id="b1c1c6a43da1ad3e41b7a6e3aa5dcc24226cf580" datatype="html">
<source>Minimum Price</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">86</context>
<context context-type="linenumber">87</context>
</context-group>
</trans-unit>
<trans-unit id="bf3df1f4eb29a071630eed167406c06f974480b2" datatype="html">
<source>First Buy Date</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">127</context>
<context context-type="linenumber">128</context>
</context-group>
</trans-unit>
<trans-unit id="add4cd82e3e38a3110fe67b3c7df56e9602644ee" datatype="html">
<source>Transactions</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/position/position-detail-dialog/position-detail-dialog.html</context>
<context context-type="linenumber">136</context>
<context context-type="linenumber">137</context>
</context-group>
</trans-unit>
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
@ -2220,14 +2220,7 @@
<source>Savings</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">296</context>
</context-group>
</trans-unit>
<trans-unit id="1975246224413290232" datatype="html">
<source>Accumulating</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">39</context>
<context context-type="linenumber">299</context>
</context-group>
</trans-unit>
<trans-unit id="2937311350146031865" datatype="html">
@ -2241,18 +2234,18 @@
<source>Interest</source>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">286</context>
<context context-type="linenumber">289</context>
</context-group>
</trans-unit>
<trans-unit id="5213771062241898526" datatype="html">
<source>Deposit</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">132</context>
<context context-type="linenumber">139</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
<context context-type="linenumber">276</context>
<context context-type="linenumber">279</context>
</context-group>
</trans-unit>
<trans-unit id="6603000223840533819" datatype="html">
@ -2266,7 +2259,7 @@
<source>Monthly</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
<context context-type="linenumber">38</context>
<context context-type="linenumber">40</context>
</context-group>
</trans-unit>
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
@ -2344,21 +2337,21 @@
<source>Experimental Features</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
<context context-type="linenumber">235</context>
</context-group>
</trans-unit>
<trans-unit id="1931353503905413384" datatype="html">
<source>Benchmark</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
<context context-type="linenumber">116</context>
<context context-type="linenumber">108</context>
</context-group>
</trans-unit>
<trans-unit id="1b25c6e22f822e07a3e4d5aae4edc5b41fe083c2" datatype="html">
<source>Benchmarks</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
<context context-type="linenumber">4</context>
<context context-type="sourcefile">apps/client/src/app/components/admin-overview/admin-overview.html</context>
<context context-type="linenumber">123</context>
</context-group>
</trans-unit>
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
@ -2389,6 +2382,69 @@
<context context-type="linenumber">25</context>
</context-group>
</trans-unit>
<trans-unit id="458363f8e413759aa9e3235a53fd0f64cc916395" datatype="html">
<source> If you retire today, you would be able to withdraw <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerYear?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per year<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/> or <x id="START_TAG_SPAN" ctype="x-span" equiv-text="&lt;span class=&quot;font-weight-bold&quot; &gt;"/><x id="START_TAG_GF_VALUE_1" ctype="x-gf_value_1" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;withdrawalRatePerMonth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> per month<x id="CLOSE_TAG_SPAN" ctype="x-span" equiv-text="&lt;/span &gt;"/>, based on your total assets of <x id="START_TAG_GF_VALUE_2" ctype="x-gf_value_2" equiv-text="&lt;gf-value class=&quot;d-inline-block&quot; [currency]=&quot;user?.settings?.baseCurrency&quot; [locale]=&quot;user?.settings?.locale&quot; [value]=&quot;fireWealth?.toNumber()&quot; &gt;"/><x id="CLOSE_TAG_GF_VALUE" ctype="x-gf_value" equiv-text="&lt;/gf-value&gt;"/> and a withdrawal rate of 4%. </source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/fire/fire-page.html</context>
<context context-type="linenumber">38,66</context>
</context-group>
</trans-unit>
<trans-unit id="5fb13fb4a8447e59cdf05dc196ade39c02a6f8aa" datatype="html">
<source>Auto</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">210</context>
</context-group>
</trans-unit>
<trans-unit id="616064537937996961" datatype="html">
<source>Auto</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
<context context-type="linenumber">45</context>
</context-group>
</trans-unit>
<trans-unit id="693d14f486a25e86bc515dfcfc4462d5201217ef" datatype="html">
<source>Light</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">211</context>
</context-group>
</trans-unit>
<trans-unit id="adb4562d2dbd3584370e44496969d58c511ecb63" datatype="html">
<source>Dark</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">212</context>
</context-group>
</trans-unit>
<trans-unit id="bbe41ac2ea4a6c00ea941a41b33105048f8e9f13" datatype="html">
<source>Appearance</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
<context context-type="linenumber">195</context>
</context-group>
</trans-unit>
<trans-unit id="112783260724635106" datatype="html">
<source>Total Amount</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">160</context>
</context-group>
</trans-unit>
<trans-unit id="f1a355a1af2e818050a3af693ac8b521fa7edc5f" datatype="html">
<source>Portfolio Evolution</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
<context context-type="linenumber">112</context>
</context-group>
</trans-unit>
<trans-unit id="8192718423057883427" datatype="html">
<source>Savings Rate</source>
<context-group purpose="location">
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
<context context-type="linenumber">201</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>

View File

@ -97,6 +97,12 @@ body {
color: rgba(var(--light-primary-text));
}
}
.with-placeholder-as-option {
.mat-select-placeholder {
color: rgba(var(--light-primary-text));
}
}
}
}
@ -228,3 +234,9 @@ ngx-skeleton-loader {
.with-info-message {
height: calc(100vh - 5rem - 3.5rem) !important;
}
.with-placeholder-as-option {
.mat-select-placeholder {
color: rgba(var(--dark-primary-text));
}
}

View File

@ -1,21 +1,24 @@
import { Chart, TooltipPosition } from 'chart.js';
import { getBackgroundColor, getTextColor } from './helper';
import { ColorScheme } from './types';
export function getTooltipOptions({
colorScheme,
currency = '',
locale = '',
unit = ''
}: {
colorScheme?: ColorScheme;
currency?: string;
locale?: string;
unit?: string;
} = {}) {
return {
backgroundColor: getBackgroundColor(),
bodyColor: `rgb(${getTextColor()})`,
backgroundColor: getBackgroundColor(colorScheme),
bodyColor: `rgb(${getTextColor(colorScheme)})`,
borderWidth: 1,
borderColor: `rgba(${getTextColor()}, 0.1)`,
borderColor: `rgba(${getTextColor(colorScheme)}, 0.1)`,
callbacks: {
label: (context) => {
let label = context.dataset.label || '';
@ -39,12 +42,12 @@ export function getTooltipOptions({
},
caretSize: 0,
cornerRadius: 2,
footerColor: `rgb(${getTextColor()})`,
footerColor: `rgb(${getTextColor(colorScheme)})`,
itemSort: (a, b) => {
// Reverse order
return b.datasetIndex - a.datasetIndex;
},
titleColor: `rgb(${getTextColor()})`,
titleColor: `rgb(${getTextColor(colorScheme)})`,
usePointStyle: true
};
}
@ -62,7 +65,10 @@ export function getTooltipPositionerMapTop(
};
}
export function getVerticalHoverLinePlugin(chartCanvas) {
export function getVerticalHoverLinePlugin(
chartCanvas,
colorScheme?: ColorScheme
) {
return {
afterDatasetsDraw: (chart, x, options) => {
const active = chart.getActiveElements();
@ -71,7 +77,7 @@ export function getVerticalHoverLinePlugin(chartCanvas) {
return;
}
const color = options.color || `rgb(${getTextColor()})`;
const color = options.color || `rgb(${getTextColor(colorScheme)})`;
const width = options.width || 1;
const {

View File

@ -6,7 +6,7 @@ export const DEMO_USER_ID = '9b112b4d-3b7d-4bad-9bdd-3b0f7b4dac2f';
export const ghostfolioScraperApiSymbolPrefix = '_GF_';
export const ghostfolioCashSymbol = `${ghostfolioScraperApiSymbolPrefix}CASH`;
export const ghostfolioFearAndGreedIndexDataSource = DataSource.RAKUTEN;
export const ghostfolioFearAndGreedIndexDataSource = DataSource.RAPID_API;
export const ghostfolioFearAndGreedIndexSymbol = `${ghostfolioScraperApiSymbolPrefix}FEAR_AND_GREED_INDEX`;
export const locale = 'en-US';

View File

@ -5,6 +5,7 @@ import { de, es, it, nl } from 'date-fns/locale';
import { ghostfolioScraperApiSymbolPrefix, locale } from './config';
import { Benchmark } from './interfaces';
import { ColorScheme } from './types';
const NUMERIC_REGEXP = /[-]{0,1}[\d]*[.,]{0,1}[\d]+/g;
@ -58,9 +59,10 @@ export function extractNumberFromString(aString: string): number {
}
}
export function getBackgroundColor() {
export function getBackgroundColor(aColorScheme: ColorScheme) {
return getCssVariable(
window.matchMedia('(prefers-color-scheme: dark)').matches
aColorScheme === 'DARK' ||
window.matchMedia('(prefers-color-scheme: dark)').matches
? '--dark-background'
: '--light-background'
);
@ -133,9 +135,10 @@ export function getNumberFormatGroup(aLocale?: string) {
}).value;
}
export function getTextColor() {
export function getTextColor(aColorScheme: ColorScheme) {
const cssVariable = getCssVariable(
window.matchMedia('(prefers-color-scheme: dark)').matches
aColorScheme === 'DARK' ||
window.matchMedia('(prefers-color-scheme: dark)').matches
? '--light-primary-text'
: '--dark-primary-text'
);

View File

@ -4,5 +4,6 @@ export interface HistoricalDataItem {
grossPerformancePercent?: number;
netPerformance?: number;
netPerformanceInPercentage?: number;
value: number;
totalInvestment?: number;
value?: number;
}

View File

@ -1,6 +1,5 @@
import { InvestmentItem } from './investment-item.interface';
export interface PortfolioInvestments {
firstOrderDate: Date;
investments: InvestmentItem[];
}

View File

@ -5,4 +5,5 @@ export interface PortfolioPerformance {
currentNetPerformance: number;
currentNetPerformancePercent: number;
currentValue: number;
totalInvestment: number;
}

View File

@ -4,5 +4,6 @@ import { ResponseError } from './errors.interface';
export interface PortfolioPerformanceResponse extends ResponseError {
chart?: HistoricalDataItem[];
firstOrderDate: Date;
performance: PortfolioPerformance;
}

View File

@ -1,8 +1,9 @@
import { DateRange, ViewMode } from '@ghostfolio/common/types';
import { ColorScheme, DateRange, ViewMode } from '@ghostfolio/common/types';
export interface UserSettings {
baseCurrency?: string;
benchmark?: string;
colorScheme?: ColorScheme;
dateRange?: DateRange;
emergencyFund?: number;
isExperimentalFeatures?: boolean;

View File

@ -1,5 +1,6 @@
import { SubscriptionType } from '@ghostfolio/common/types/subscription.type';
import { Account, Settings, User } from '@prisma/client';
import { UserSettings } from './user-settings.interface';
export type UserWithSettings = User & {

View File

@ -0,0 +1 @@
export type ColorScheme = 'DARK' | 'LIGHT';

View File

@ -1,5 +1,6 @@
import type { AccessWithGranteeUser } from './access-with-grantee-user.type';
import { AccountWithValue } from './account-with-value.type';
import type { ColorScheme } from './color-scheme';
import type { DateRange } from './date-range.type';
import type { Granularity } from './granularity.type';
import { GroupBy } from './group-by.type';
@ -13,6 +14,7 @@ import type { ViewMode } from './view-mode.type';
export type {
AccessWithGranteeUser,
AccountWithValue,
ColorScheme,
DateRange,
Granularity,
GroupBy,

View File

@ -1,3 +1 @@
import '@angular/localize/init';
import '!style-loader!css-loader!sass-loader!../../../apps/client/src/styles.scss';

View File

@ -1,3 +1,5 @@
import '@angular/localize/init';
import { CommonModule } from '@angular/common';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';

View File

@ -16,6 +16,7 @@ import { FormBuilder, FormControl } from '@angular/forms';
import { getTooltipOptions } from '@ghostfolio/common/chart-helper';
import { primaryColorRgb } from '@ghostfolio/common/config';
import { transformTickToAbbreviation } from '@ghostfolio/common/helper';
import { ColorScheme } from '@ghostfolio/common/types';
import {
BarController,
BarElement,
@ -25,6 +26,7 @@ import {
Tooltip
} from 'chart.js';
import * as Color from 'color';
import { getMonth } from 'date-fns';
import { isNumber } from 'lodash';
import { Subject, takeUntil } from 'rxjs';
@ -39,6 +41,7 @@ import { FireCalculatorService } from './fire-calculator.service';
export class FireCalculatorComponent
implements AfterViewInit, OnChanges, OnDestroy
{
@Input() colorScheme: ColorScheme;
@Input() currency: string;
@Input() deviceType: string;
@Input() fireWealth: number;
@ -60,6 +63,7 @@ export class FireCalculatorComponent
public isLoading = true;
public projectedTotalAmount: number;
private readonly CONTRIBUTION_PERIOD = 12;
private unsubscribeSubject = new Subject<void>();
public constructor(
@ -180,7 +184,7 @@ export class FireCalculatorComponent
options: {
plugins: {
tooltip: {
...getTooltipOptions(),
...getTooltipOptions({ colorScheme: this.colorScheme }),
mode: 'index',
callbacks: {
footer: (items) => {
@ -232,6 +236,7 @@ export class FireCalculatorComponent
grid: {
display: false
},
position: 'right',
stacked: true,
ticks: {
callback: (value: number) => {
@ -296,11 +301,15 @@ export class FireCalculatorComponent
label: $localize`Savings`
};
const monthsPassedInCurrentYear = getMonth(new Date());
for (let period = 1; period <= t; period++) {
const periodInMonths =
period * this.CONTRIBUTION_PERIOD - monthsPassedInCurrentYear;
const { interest, principal, totalAmount } =
this.fireCalculatorService.calculateCompoundInterest({
P,
period,
periodInMonths,
PMT,
r
});

View File

@ -4,35 +4,32 @@ import Big from 'big.js';
@Injectable()
export class FireCalculatorService {
private readonly COMPOUND_PERIOD = 12;
private readonly CONTRIBUTION_PERIOD = 12;
public constructor() {}
public calculateCompoundInterest({
P,
period,
periodInMonths,
PMT,
r
}: {
P: number;
period: number;
periodInMonths: number;
PMT: number;
r: number;
}) {
let interest = new Big(0);
const principal = new Big(P).plus(
new Big(PMT).mul(this.CONTRIBUTION_PERIOD).mul(period)
);
const principal = new Big(P).plus(new Big(PMT).mul(periodInMonths));
let totalAmount = principal;
if (r) {
const compoundInterestForPrincipal = new Big(1)
.plus(new Big(r).div(this.COMPOUND_PERIOD))
.pow(new Big(this.COMPOUND_PERIOD).mul(period).toNumber());
.pow(periodInMonths);
const compoundInterest = new Big(P).mul(compoundInterestForPrincipal);
const contributionInterest = new Big(
new Big(PMT).mul(compoundInterestForPrincipal.minus(1))
).div(new Big(r).div(this.CONTRIBUTION_PERIOD));
).div(new Big(r).div(this.COMPOUND_PERIOD));
interest = compoundInterest.plus(contributionInterest).minus(principal);
totalAmount = compoundInterest.plus(contributionInterest);
}

View File

@ -230,5 +230,6 @@ Simple.args = {
date: '2021-03-18',
value: 86666.03082624623
}
]
],
isAnimated: true
};

View File

@ -26,6 +26,7 @@ import {
getTextColor
} from '@ghostfolio/common/helper';
import { LineChartItem } from '@ghostfolio/common/interfaces';
import { ColorScheme } from '@ghostfolio/common/types';
import {
Chart,
Filler,
@ -46,8 +47,10 @@ import {
export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
@Input() benchmarkDataItems: LineChartItem[] = [];
@Input() benchmarkLabel = '';
@Input() colorScheme: ColorScheme;
@Input() currency: string;
@Input() historicalDataItems: LineChartItem[];
@Input() isAnimated = false;
@Input() locale: string;
@Input() showGradient = false;
@Input() showLegend = false;
@ -66,6 +69,8 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
public chart: Chart;
public isLoading = true;
private readonly ANIMATION_DURATION = 1200;
public constructor(private changeDetectorRef: ChangeDetectorRef) {
Chart.register(
Filler,
@ -114,7 +119,7 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
private initialize() {
this.isLoading = true;
const benchmarkPrices = [];
const labels = [];
const labels: string[] = [];
const marketPrices = [];
this.historicalDataItems?.forEach((historicalDataItem, index) => {
@ -137,7 +142,7 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
0,
`rgba(${primaryColorRgb.r}, ${primaryColorRgb.g}, ${primaryColorRgb.b}, 0.01)`
);
gradient.addColorStop(1, getBackgroundColor());
gradient.addColorStop(1, getBackgroundColor(this.colorScheme));
}
const data = {
@ -169,16 +174,27 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
this.chart.options.plugins.tooltip = <unknown>(
this.getTooltipPluginConfiguration()
);
this.chart.options.animation =
this.isAnimated &&
<unknown>{
x: this.getAnimationConfigurationForAxis({ labels, axis: 'x' }),
y: this.getAnimationConfigurationForAxis({ labels, axis: 'y' })
};
this.chart.update();
} else {
this.chart = new Chart(this.chartCanvas.nativeElement, {
data,
options: {
animation: false,
animation:
this.isAnimated &&
<unknown>{
x: this.getAnimationConfigurationForAxis({ labels, axis: 'x' }),
y: this.getAnimationConfigurationForAxis({ labels, axis: 'y' })
},
aspectRatio: 16 / 9,
elements: {
point: {
hoverBackgroundColor: getBackgroundColor(),
hoverBackgroundColor: getBackgroundColor(this.colorScheme),
hoverRadius: 2
}
},
@ -191,15 +207,15 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
},
tooltip: this.getTooltipPluginConfiguration(),
verticalHoverLine: {
color: `rgba(${getTextColor()}, 0.1)`
color: `rgba(${getTextColor(this.colorScheme)}, 0.1)`
}
},
scales: {
x: {
display: this.showXAxis,
grid: {
borderColor: `rgba(${getTextColor()}, 0.1)`,
color: `rgba(${getTextColor()}, 0.8)`,
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
display: false
},
time: {
@ -211,14 +227,14 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
y: {
display: this.showYAxis,
grid: {
borderColor: `rgba(${getTextColor()}, 0.1)`,
color: `rgba(${getTextColor()}, 0.8)`,
borderColor: `rgba(${getTextColor(this.colorScheme)}, 0.1)`,
color: `rgba(${getTextColor(this.colorScheme)}, 0.8)`,
display: false
},
max: this.yMax,
min: this.yMin,
position: 'right',
ticks: {
display: this.showYAxis,
callback: (tickValue, index, ticks) => {
if (index === 0 || index === ticks.length - 1) {
// Only print last and first legend entry
@ -240,6 +256,7 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
return '';
},
display: this.showYAxis,
mirror: true,
z: 1
},
@ -248,7 +265,9 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
},
spanGaps: true
},
plugins: [getVerticalHoverLinePlugin(this.chartCanvas)],
plugins: [
getVerticalHoverLinePlugin(this.chartCanvas, this.colorScheme)
],
type: 'line'
});
}
@ -257,9 +276,35 @@ export class LineChartComponent implements AfterViewInit, OnChanges, OnDestroy {
this.isLoading = false;
}
private getAnimationConfigurationForAxis({
axis,
labels
}: {
axis: 'x' | 'y';
labels: string[];
}) {
const delayBetweenPoints = this.ANIMATION_DURATION / labels.length;
return {
delay(context) {
if (context.type !== 'data' || context[`${axis}Started`]) {
return 0;
}
context[`${axis}Started`] = true;
return context.index * delayBetweenPoints;
},
duration: delayBetweenPoints,
easing: 'linear',
from: NaN,
type: 'number'
};
}
private getTooltipPluginConfiguration() {
return {
...getTooltipOptions({
colorScheme: this.colorScheme,
currency: this.currency,
locale: this.locale,
unit: this.unit

View File

@ -14,6 +14,7 @@ import { getTooltipOptions } from '@ghostfolio/common/chart-helper';
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
import { getTextColor } from '@ghostfolio/common/helper';
import { PortfolioPosition, UniqueAsset } from '@ghostfolio/common/interfaces';
import { ColorScheme } from '@ghostfolio/common/types';
import { DataSource } from '@prisma/client';
import Big from 'big.js';
import { ChartConfiguration, Tooltip } from 'chart.js';
@ -34,6 +35,7 @@ export class PortfolioProportionChartComponent
implements AfterViewInit, OnChanges, OnDestroy
{
@Input() baseCurrency: string;
@Input() colorScheme: ColorScheme;
@Input() cursor: string;
@Input() isInPercent = false;
@Input() keys: string[] = [];
@ -59,10 +61,7 @@ export class PortfolioProportionChartComponent
private colorMap: {
[symbol: string]: string;
} = {
[this.OTHER_KEY]: `rgba(${getTextColor()}, 0.24)`,
[UNKNOWN_KEY]: `rgba(${getTextColor()}, 0.12)`
};
} = {};
public constructor() {
Chart.register(ArcElement, DoughnutController, LinearScale, Tooltip);
@ -94,6 +93,10 @@ export class PortfolioProportionChartComponent
value: Big;
};
} = {};
this.colorMap = {
[this.OTHER_KEY]: `rgba(${getTextColor(this.colorScheme)}, 0.24)`,
[UNKNOWN_KEY]: `rgba(${getTextColor(this.colorScheme)}, 0.12)`
};
Object.keys(this.positions).forEach((symbol) => {
if (this.positions[symbol][this.keys[0]]) {
@ -350,6 +353,7 @@ export class PortfolioProportionChartComponent
private getTooltipPluginConfiguration(data: ChartConfiguration['data']) {
return {
...getTooltipOptions({
colorScheme: this.colorScheme,
currency: this.baseCurrency,
locale: this.locale
}),

View File

@ -1,7 +1,7 @@
<div *ngIf="icon" class="align-self-center mr-3">
<ion-icon class="h3 m-0" [name]="icon"></ion-icon>
</div>
<div>
<div class="w-100">
<ng-template #label><ng-content></ng-content></ng-template>
<ng-container *ngIf="value || value === 0 || value === null">
<div

View File

@ -1,6 +1,6 @@
{
"name": "ghostfolio",
"version": "1.200.0",
"version": "1.205.0",
"homepage": "https://ghostfol.io",
"license": "AGPL-3.0",
"scripts": {
@ -181,6 +181,7 @@
"jest-preset-angular": "12.2.2",
"nx": "14.6.4",
"prettier": "2.7.1",
"prettier-plugin-organize-attributes": "0.0.5",
"replace-in-file": "6.2.0",
"rimraf": "3.0.2",
"ts-jest": "28.0.8",

View File

@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "DataSource" ADD VALUE 'RAPID_API';

View File

@ -0,0 +1,9 @@
-- AlterEnum
BEGIN;
CREATE TYPE "DataSource_new" AS ENUM ('ALPHA_VANTAGE', 'EOD_HISTORICAL_DATA', 'GHOSTFOLIO', 'GOOGLE_SHEETS', 'MANUAL', 'RAPID_API', 'YAHOO');
ALTER TABLE "MarketData" ALTER COLUMN "dataSource" TYPE "DataSource_new" USING ("dataSource"::text::"DataSource_new");
ALTER TABLE "SymbolProfile" ALTER COLUMN "dataSource" TYPE "DataSource_new" USING ("dataSource"::text::"DataSource_new");
ALTER TYPE "DataSource" RENAME TO "DataSource_old";
ALTER TYPE "DataSource_new" RENAME TO "DataSource";
DROP TYPE "DataSource_old";
COMMIT;

View File

@ -206,7 +206,7 @@ enum DataSource {
GHOSTFOLIO
GOOGLE_SHEETS
MANUAL
RAKUTEN
RAPID_API
YAHOO
}

View File

@ -16717,6 +16717,11 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==
prettier-plugin-organize-attributes@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-attributes/-/prettier-plugin-organize-attributes-0.0.5.tgz#46e54533936fc42a3cff3d876a738a3f98df0360"
integrity sha512-dSts16q8wd+oq8Zwk5mwmYXo1aN3B+ZkEJqx/ar5fedNHdOvx7S4XDMH/pNK7rmBW0bPXkp/kJX5gAANsWzh3A==
prettier@2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"