Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
c0ace51ee9 | |||
b1b5689242 | |||
b68cdaf8ea | |||
b387a80a0d | |||
6e4660295a | |||
d4c3a9d1e8 | |||
263f6b32f2 | |||
637f31ae3b | |||
547e27c7a1 | |||
f10dc176f2 | |||
0a966e46cd | |||
4f281d25e1 | |||
aaba8c35c2 | |||
7d27cb3398 | |||
91678028b5 | |||
5e3cac8ac9 |
37
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
37
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
---
|
||||||
|
name: Bug report
|
||||||
|
about: Create a report to help us improve
|
||||||
|
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**
|
||||||
|
<!-- A clear and concise description of what the bug is. -->
|
||||||
|
|
||||||
|
**To Reproduce**
|
||||||
|
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
|
||||||
|
|
||||||
|
**Additional context**
|
||||||
|
<!-- Add any other context about the problem here. -->
|
41
CHANGELOG.md
41
CHANGELOG.md
@ -5,6 +5,47 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## 1.195.0 - 20.09.2022
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improved the algorithm of the performance chart calculation
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Improved the chart tooltip of the benchmark comparator
|
||||||
|
|
||||||
|
## 1.194.0 - 17.09.2022
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `NODE_ENV: production` to the `docker-compose` files (`docker-compose.yml` and `docker-compose.build.yml`)
|
||||||
|
- Visualized the percentage of the active filter on the allocations page
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Improved the language localization for German (`de`)
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Respected the end date in the performance chart calculation
|
||||||
|
|
||||||
|
### Todo
|
||||||
|
|
||||||
|
- Set `NODE_ENV: production` as in [docker-compose.yml](https://github.com/ghostfolio/ghostfolio/blob/main/docker/docker-compose.yml)
|
||||||
|
|
||||||
|
## 1.193.0 - 14.09.2022
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Sorted the benchmarks by name
|
||||||
|
- Extended the pricing page
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed the calculations of the exchange rate service by changing `USD` to the base currency
|
||||||
|
- Fixed the missing assets during the local development
|
||||||
|
|
||||||
## 1.192.0 - 11.09.2022
|
## 1.192.0 - 11.09.2022
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
@ -153,6 +153,7 @@ Please follow the instructions of the Ghostfolio [Unraid Community App](https://
|
|||||||
### Setup
|
### Setup
|
||||||
|
|
||||||
1. Run `yarn install`
|
1. Run `yarn install`
|
||||||
|
1. Run `yarn build:dev` to build the source code including the assets
|
||||||
1. Run `docker-compose --env-file ./.env -f docker/docker-compose.dev.yml up -d` to start [PostgreSQL](https://www.postgresql.org) and [Redis](https://redis.io)
|
1. Run `docker-compose --env-file ./.env -f docker/docker-compose.dev.yml up -d` to start [PostgreSQL](https://www.postgresql.org) and [Redis](https://redis.io)
|
||||||
1. Run `yarn database:setup` to initialize the database schema and populate your database with (example) data
|
1. Run `yarn database:setup` to initialize the database schema and populate your database with (example) data
|
||||||
1. Start the server and the client (see [_Development_](#Development))
|
1. Start the server and the client (see [_Development_](#Development))
|
||||||
|
13
angular.json
13
angular.json
@ -136,6 +136,10 @@
|
|||||||
"baseHref": "/en/",
|
"baseHref": "/en/",
|
||||||
"localize": ["en"]
|
"localize": ["en"]
|
||||||
},
|
},
|
||||||
|
"development-it": {
|
||||||
|
"baseHref": "/it/",
|
||||||
|
"localize": ["it"]
|
||||||
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"fileReplacements": [
|
"fileReplacements": [
|
||||||
{
|
{
|
||||||
@ -180,6 +184,9 @@
|
|||||||
"development-en": {
|
"development-en": {
|
||||||
"browserTarget": "client:build:development-en"
|
"browserTarget": "client:build:development-en"
|
||||||
},
|
},
|
||||||
|
"development-it": {
|
||||||
|
"browserTarget": "client:build:development-it"
|
||||||
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"browserTarget": "client:build:production"
|
"browserTarget": "client:build:production"
|
||||||
}
|
}
|
||||||
@ -191,7 +198,7 @@
|
|||||||
"browserTarget": "client:build",
|
"browserTarget": "client:build",
|
||||||
"includeContext": true,
|
"includeContext": true,
|
||||||
"outputPath": "src/locales",
|
"outputPath": "src/locales",
|
||||||
"targetFiles": ["messages.de.xlf"]
|
"targetFiles": ["messages.de.xlf", "messages.it.xlf"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lint": {
|
"lint": {
|
||||||
@ -214,6 +221,10 @@
|
|||||||
"de": {
|
"de": {
|
||||||
"baseHref": "/de/",
|
"baseHref": "/de/",
|
||||||
"translation": "apps/client/src/locales/messages.de.xlf"
|
"translation": "apps/client/src/locales/messages.de.xlf"
|
||||||
|
},
|
||||||
|
"it": {
|
||||||
|
"baseHref": "/it/",
|
||||||
|
"translation": "apps/client/src/locales/messages.it.xlf"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sourceLocale": "en"
|
"sourceLocale": "en"
|
||||||
|
@ -4,7 +4,10 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data
|
|||||||
import { MarketDataService } from '@ghostfolio/api/services/market-data.service';
|
import { MarketDataService } from '@ghostfolio/api/services/market-data.service';
|
||||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||||
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service';
|
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service';
|
||||||
import { PROPERTY_BENCHMARKS } from '@ghostfolio/common/config';
|
import {
|
||||||
|
MAX_CHART_ITEMS,
|
||||||
|
PROPERTY_BENCHMARKS
|
||||||
|
} from '@ghostfolio/common/config';
|
||||||
import { DATE_FORMAT } from '@ghostfolio/common/helper';
|
import { DATE_FORMAT } from '@ghostfolio/common/helper';
|
||||||
import {
|
import {
|
||||||
BenchmarkMarketDataDetails,
|
BenchmarkMarketDataDetails,
|
||||||
@ -16,7 +19,6 @@ import { SymbolProfile } from '@prisma/client';
|
|||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import ms from 'ms';
|
import ms from 'ms';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BenchmarkService {
|
export class BenchmarkService {
|
||||||
@ -119,14 +121,16 @@ export class BenchmarkService {
|
|||||||
const assetProfiles =
|
const assetProfiles =
|
||||||
await this.symbolProfileService.getSymbolProfilesByIds(symbolProfileIds);
|
await this.symbolProfileService.getSymbolProfilesByIds(symbolProfileIds);
|
||||||
|
|
||||||
return assetProfiles.map(({ dataSource, id, name, symbol }) => {
|
return assetProfiles
|
||||||
|
.map(({ dataSource, id, name, symbol }) => {
|
||||||
return {
|
return {
|
||||||
dataSource,
|
dataSource,
|
||||||
id,
|
id,
|
||||||
name,
|
name,
|
||||||
symbol
|
symbol
|
||||||
};
|
};
|
||||||
});
|
})
|
||||||
|
.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getMarketDataBySymbol({
|
public async getMarketDataBySymbol({
|
||||||
@ -155,16 +159,18 @@ export class BenchmarkService {
|
|||||||
})
|
})
|
||||||
]);
|
]);
|
||||||
|
|
||||||
marketDataItems.push({
|
const step = Math.round(
|
||||||
...currentSymbolItem,
|
marketDataItems.length / Math.min(marketDataItems.length, MAX_CHART_ITEMS)
|
||||||
createdAt: new Date(),
|
);
|
||||||
date: new Date(),
|
|
||||||
id: uuidv4()
|
|
||||||
});
|
|
||||||
|
|
||||||
const marketPriceAtStartDate = marketDataItems?.[0]?.marketPrice ?? 0;
|
const marketPriceAtStartDate = marketDataItems?.[0]?.marketPrice ?? 0;
|
||||||
return {
|
return {
|
||||||
marketData: marketDataItems.map((marketDataItem) => {
|
marketData: [
|
||||||
|
...marketDataItems
|
||||||
|
.filter((marketDataItem, index) => {
|
||||||
|
return index % step === 0;
|
||||||
|
})
|
||||||
|
.map((marketDataItem) => {
|
||||||
return {
|
return {
|
||||||
date: format(marketDataItem.date, DATE_FORMAT),
|
date: format(marketDataItem.date, DATE_FORMAT),
|
||||||
value:
|
value:
|
||||||
@ -175,7 +181,16 @@ export class BenchmarkService {
|
|||||||
marketDataItem.marketPrice
|
marketDataItem.marketPrice
|
||||||
) * 100
|
) * 100
|
||||||
};
|
};
|
||||||
})
|
}),
|
||||||
|
{
|
||||||
|
date: format(new Date(), DATE_FORMAT),
|
||||||
|
value:
|
||||||
|
this.calculateChangeInPercentage(
|
||||||
|
marketPriceAtStartDate,
|
||||||
|
currentSymbolItem.marketPrice
|
||||||
|
) * 100
|
||||||
|
}
|
||||||
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,22 +4,36 @@ import * as path from 'path';
|
|||||||
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
import { ConfigurationService } from '@ghostfolio/api/services/configuration.service';
|
||||||
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
|
import { DEFAULT_LANGUAGE_CODE } from '@ghostfolio/common/config';
|
||||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Request, Response } from 'express';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FrontendMiddleware implements NestMiddleware {
|
export class FrontendMiddleware implements NestMiddleware {
|
||||||
public indexHtmlDe = fs.readFileSync(
|
public indexHtmlDe = '';
|
||||||
|
public indexHtmlEn = '';
|
||||||
|
public isProduction: boolean;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private readonly configService: ConfigService,
|
||||||
|
private readonly configurationService: ConfigurationService
|
||||||
|
) {
|
||||||
|
const NODE_ENV =
|
||||||
|
this.configService.get<'development' | 'production'>('NODE_ENV') ??
|
||||||
|
'development';
|
||||||
|
|
||||||
|
this.isProduction = NODE_ENV === 'production';
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.indexHtmlDe = fs.readFileSync(
|
||||||
this.getPathOfIndexHtmlFile('de'),
|
this.getPathOfIndexHtmlFile('de'),
|
||||||
'utf8'
|
'utf8'
|
||||||
);
|
);
|
||||||
public indexHtmlEn = fs.readFileSync(
|
this.indexHtmlEn = fs.readFileSync(
|
||||||
this.getPathOfIndexHtmlFile(DEFAULT_LANGUAGE_CODE),
|
this.getPathOfIndexHtmlFile(DEFAULT_LANGUAGE_CODE),
|
||||||
'utf8'
|
'utf8'
|
||||||
);
|
);
|
||||||
|
} catch {}
|
||||||
public constructor(
|
}
|
||||||
private readonly configurationService: ConfigurationService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
public use(req: Request, res: Response, next: NextFunction) {
|
public use(req: Request, res: Response, next: NextFunction) {
|
||||||
let featureGraphicPath = 'assets/cover.png';
|
let featureGraphicPath = 'assets/cover.png';
|
||||||
@ -31,7 +45,11 @@ export class FrontendMiddleware implements NestMiddleware {
|
|||||||
featureGraphicPath = 'assets/images/blog/500-stars-on-github.jpg';
|
featureGraphicPath = 'assets/images/blog/500-stars-on-github.jpg';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.path.startsWith('/api/') || this.isFileRequest(req.url)) {
|
if (
|
||||||
|
req.path.startsWith('/api/') ||
|
||||||
|
this.isFileRequest(req.url) ||
|
||||||
|
!this.isProduction
|
||||||
|
) {
|
||||||
// Skip
|
// Skip
|
||||||
next();
|
next();
|
||||||
} else if (req.path === '/de' || req.path.startsWith('/de/')) {
|
} else if (req.path === '/de' || req.path.startsWith('/de/')) {
|
||||||
|
@ -16,12 +16,11 @@ import {
|
|||||||
isBefore,
|
isBefore,
|
||||||
isSameMonth,
|
isSameMonth,
|
||||||
isSameYear,
|
isSameYear,
|
||||||
isWithinInterval,
|
|
||||||
max,
|
max,
|
||||||
min,
|
min,
|
||||||
set
|
set
|
||||||
} from 'date-fns';
|
} from 'date-fns';
|
||||||
import { first, flatten, isNumber, sortBy } from 'lodash';
|
import { first, flatten, isNumber, last, sortBy } from 'lodash';
|
||||||
|
|
||||||
import { CurrentRateService } from './current-rate.service';
|
import { CurrentRateService } from './current-rate.service';
|
||||||
import { CurrentPositions } from './interfaces/current-positions.interface';
|
import { CurrentPositions } from './interfaces/current-positions.interface';
|
||||||
@ -168,6 +167,131 @@ export class PortfolioCalculator {
|
|||||||
this.transactionPoints = transactionPoints;
|
this.transactionPoints = transactionPoints;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getChartData(start: Date, end = new Date(Date.now()), step = 1) {
|
||||||
|
const symbols: { [symbol: string]: boolean } = {};
|
||||||
|
|
||||||
|
const transactionPointsBeforeEndDate =
|
||||||
|
this.transactionPoints?.filter((transactionPoint) => {
|
||||||
|
return isBefore(parseDate(transactionPoint.date), end);
|
||||||
|
}) ?? [];
|
||||||
|
|
||||||
|
const firstIndex = transactionPointsBeforeEndDate.length;
|
||||||
|
const dates: Date[] = [];
|
||||||
|
const dataGatheringItems: IDataGatheringItem[] = [];
|
||||||
|
const currencies: { [symbol: string]: string } = {};
|
||||||
|
|
||||||
|
let day = start;
|
||||||
|
|
||||||
|
while (isBefore(day, end)) {
|
||||||
|
dates.push(resetHours(day));
|
||||||
|
day = addDays(day, step);
|
||||||
|
}
|
||||||
|
|
||||||
|
dates.push(resetHours(end));
|
||||||
|
|
||||||
|
for (const item of transactionPointsBeforeEndDate[firstIndex - 1].items) {
|
||||||
|
dataGatheringItems.push({
|
||||||
|
dataSource: item.dataSource,
|
||||||
|
symbol: item.symbol
|
||||||
|
});
|
||||||
|
currencies[item.symbol] = item.currency;
|
||||||
|
symbols[item.symbol] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const marketSymbols = await this.currentRateService.getValues({
|
||||||
|
currencies,
|
||||||
|
dataGatheringItems,
|
||||||
|
dateQuery: {
|
||||||
|
in: dates
|
||||||
|
},
|
||||||
|
userCurrency: this.currency
|
||||||
|
});
|
||||||
|
|
||||||
|
const marketSymbolMap: {
|
||||||
|
[date: string]: { [symbol: string]: Big };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
for (const marketSymbol of marketSymbols) {
|
||||||
|
const dateString = format(marketSymbol.date, DATE_FORMAT);
|
||||||
|
if (!marketSymbolMap[dateString]) {
|
||||||
|
marketSymbolMap[dateString] = {};
|
||||||
|
}
|
||||||
|
if (marketSymbol.marketPriceInBaseCurrency) {
|
||||||
|
marketSymbolMap[dateString][marketSymbol.symbol] = new Big(
|
||||||
|
marketSymbol.marketPriceInBaseCurrency
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const netPerformanceValuesBySymbol: {
|
||||||
|
[symbol: string]: { [date: string]: Big };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
const investmentValuesBySymbol: {
|
||||||
|
[symbol: string]: { [date: string]: Big };
|
||||||
|
} = {};
|
||||||
|
|
||||||
|
const totalNetPerformanceValues: { [date: string]: Big } = {};
|
||||||
|
const totalInvestmentValues: { [date: string]: Big } = {};
|
||||||
|
|
||||||
|
for (const symbol of Object.keys(symbols)) {
|
||||||
|
const { netPerformanceValues, investmentValues } = this.getSymbolMetrics({
|
||||||
|
end,
|
||||||
|
marketSymbolMap,
|
||||||
|
start,
|
||||||
|
step,
|
||||||
|
symbol,
|
||||||
|
isChartMode: true
|
||||||
|
});
|
||||||
|
|
||||||
|
netPerformanceValuesBySymbol[symbol] = netPerformanceValues;
|
||||||
|
investmentValuesBySymbol[symbol] = investmentValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const currentDate of dates) {
|
||||||
|
const dateString = format(currentDate, DATE_FORMAT);
|
||||||
|
|
||||||
|
for (const symbol of Object.keys(netPerformanceValuesBySymbol)) {
|
||||||
|
totalNetPerformanceValues[dateString] =
|
||||||
|
totalNetPerformanceValues[dateString] ?? new Big(0);
|
||||||
|
|
||||||
|
if (netPerformanceValuesBySymbol[symbol]?.[dateString]) {
|
||||||
|
totalNetPerformanceValues[dateString] = totalNetPerformanceValues[
|
||||||
|
dateString
|
||||||
|
].add(netPerformanceValuesBySymbol[symbol][dateString]);
|
||||||
|
}
|
||||||
|
|
||||||
|
totalInvestmentValues[dateString] =
|
||||||
|
totalInvestmentValues[dateString] ?? new Big(0);
|
||||||
|
|
||||||
|
if (investmentValuesBySymbol[symbol]?.[dateString]) {
|
||||||
|
totalInvestmentValues[dateString] = totalInvestmentValues[
|
||||||
|
dateString
|
||||||
|
].add(investmentValuesBySymbol[symbol][dateString]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isInPercentage = true;
|
||||||
|
|
||||||
|
return Object.keys(totalNetPerformanceValues).map((date) => {
|
||||||
|
return isInPercentage
|
||||||
|
? {
|
||||||
|
date,
|
||||||
|
value: totalInvestmentValues[date].eq(0)
|
||||||
|
? 0
|
||||||
|
: totalNetPerformanceValues[date]
|
||||||
|
.div(totalInvestmentValues[date])
|
||||||
|
.mul(100)
|
||||||
|
.toNumber()
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
date,
|
||||||
|
value: totalNetPerformanceValues[date].toNumber()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public async getCurrentPositions(
|
public async getCurrentPositions(
|
||||||
start: Date,
|
start: Date,
|
||||||
end = new Date(Date.now())
|
end = new Date(Date.now())
|
||||||
@ -710,15 +834,19 @@ export class PortfolioCalculator {
|
|||||||
|
|
||||||
private getSymbolMetrics({
|
private getSymbolMetrics({
|
||||||
end,
|
end,
|
||||||
|
isChartMode = false,
|
||||||
marketSymbolMap,
|
marketSymbolMap,
|
||||||
start,
|
start,
|
||||||
|
step = 1,
|
||||||
symbol
|
symbol
|
||||||
}: {
|
}: {
|
||||||
end: Date;
|
end: Date;
|
||||||
|
isChartMode?: boolean;
|
||||||
marketSymbolMap: {
|
marketSymbolMap: {
|
||||||
[date: string]: { [symbol: string]: Big };
|
[date: string]: { [symbol: string]: Big };
|
||||||
};
|
};
|
||||||
start: Date;
|
start: Date;
|
||||||
|
step?: number;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
}) {
|
}) {
|
||||||
let orders: PortfolioOrderItem[] = this.orders.filter((order) => {
|
let orders: PortfolioOrderItem[] = this.orders.filter((order) => {
|
||||||
@ -767,10 +895,12 @@ export class PortfolioCalculator {
|
|||||||
let grossPerformanceFromSells = new Big(0);
|
let grossPerformanceFromSells = new Big(0);
|
||||||
let initialValue: Big;
|
let initialValue: Big;
|
||||||
let investmentAtStartDate: Big;
|
let investmentAtStartDate: Big;
|
||||||
|
const investmentValues: { [date: string]: Big } = {};
|
||||||
let lastAveragePrice = new Big(0);
|
let lastAveragePrice = new Big(0);
|
||||||
let lastTransactionInvestment = new Big(0);
|
let lastTransactionInvestment = new Big(0);
|
||||||
let lastValueOfInvestmentBeforeTransaction = new Big(0);
|
let lastValueOfInvestmentBeforeTransaction = new Big(0);
|
||||||
let maxTotalInvestment = new Big(0);
|
let maxTotalInvestment = new Big(0);
|
||||||
|
const netPerformanceValues: { [date: string]: Big } = {};
|
||||||
let timeWeightedGrossPerformancePercentage = new Big(1);
|
let timeWeightedGrossPerformancePercentage = new Big(1);
|
||||||
let timeWeightedNetPerformancePercentage = new Big(1);
|
let timeWeightedNetPerformancePercentage = new Big(1);
|
||||||
let totalInvestment = new Big(0);
|
let totalInvestment = new Big(0);
|
||||||
@ -805,6 +935,41 @@ export class PortfolioCalculator {
|
|||||||
unitPrice: unitPriceAtEndDate
|
unitPrice: unitPriceAtEndDate
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let day = start;
|
||||||
|
let lastUnitPrice: Big;
|
||||||
|
|
||||||
|
if (isChartMode) {
|
||||||
|
const datesWithOrders = {};
|
||||||
|
|
||||||
|
for (const order of orders) {
|
||||||
|
datesWithOrders[order.date] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (isBefore(day, end)) {
|
||||||
|
const hasDate = datesWithOrders[format(day, DATE_FORMAT)];
|
||||||
|
|
||||||
|
if (!hasDate) {
|
||||||
|
orders.push({
|
||||||
|
symbol,
|
||||||
|
currency: null,
|
||||||
|
date: format(day, DATE_FORMAT),
|
||||||
|
dataSource: null,
|
||||||
|
fee: new Big(0),
|
||||||
|
name: '',
|
||||||
|
quantity: new Big(0),
|
||||||
|
type: TypeOfOrder.BUY,
|
||||||
|
unitPrice:
|
||||||
|
marketSymbolMap[format(day, DATE_FORMAT)]?.[symbol] ??
|
||||||
|
lastUnitPrice
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lastUnitPrice = last(orders).unitPrice;
|
||||||
|
|
||||||
|
day = addDays(day, step);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sort orders so that the start and end placeholder order are at the right
|
// Sort orders so that the start and end placeholder order are at the right
|
||||||
// position
|
// position
|
||||||
orders = sortBy(orders, (order) => {
|
orders = sortBy(orders, (order) => {
|
||||||
@ -967,6 +1132,18 @@ export class PortfolioCalculator {
|
|||||||
feesAtStartDate = fees;
|
feesAtStartDate = fees;
|
||||||
grossPerformanceAtStartDate = grossPerformance;
|
grossPerformanceAtStartDate = grossPerformance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isChartMode && i > indexOfStartOrder) {
|
||||||
|
netPerformanceValues[order.date] = grossPerformance
|
||||||
|
.minus(grossPerformanceAtStartDate)
|
||||||
|
.minus(fees.minus(feesAtStartDate));
|
||||||
|
|
||||||
|
investmentValues[order.date] = totalInvestment;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i === indexOfEndOrder) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
timeWeightedGrossPerformancePercentage =
|
timeWeightedGrossPerformancePercentage =
|
||||||
@ -1052,7 +1229,9 @@ export class PortfolioCalculator {
|
|||||||
return {
|
return {
|
||||||
initialValue,
|
initialValue,
|
||||||
grossPerformancePercentage,
|
grossPerformancePercentage,
|
||||||
|
investmentValues,
|
||||||
netPerformancePercentage,
|
netPerformancePercentage,
|
||||||
|
netPerformanceValues,
|
||||||
hasErrors: totalUnits.gt(0) && (!initialValue || !unitPriceAtEndDate),
|
hasErrors: totalUnits.gt(0) && (!initialValue || !unitPriceAtEndDate),
|
||||||
netPerformance: totalNetPerformance,
|
netPerformance: totalNetPerformance,
|
||||||
grossPerformance: totalGrossPerformance
|
grossPerformance: totalGrossPerformance
|
||||||
|
@ -168,8 +168,14 @@ export class PortfolioController {
|
|||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
const { accounts, holdings, hasErrors } =
|
const {
|
||||||
await this.portfolioService.getDetails(
|
accounts,
|
||||||
|
filteredValueInBaseCurrency,
|
||||||
|
filteredValueInPercentage,
|
||||||
|
hasErrors,
|
||||||
|
holdings,
|
||||||
|
totalValueInBaseCurrency
|
||||||
|
} = await this.portfolioService.getDetails(
|
||||||
impersonationId,
|
impersonationId,
|
||||||
this.request.user.id,
|
this.request.user.id,
|
||||||
range,
|
range,
|
||||||
@ -234,8 +240,11 @@ export class PortfolioController {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
accounts,
|
accounts,
|
||||||
|
filteredValueInBaseCurrency,
|
||||||
|
filteredValueInPercentage,
|
||||||
hasError,
|
hasError,
|
||||||
holdings
|
holdings,
|
||||||
|
totalValueInBaseCurrency
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import { ImpersonationService } from '@ghostfolio/api/services/impersonation.ser
|
|||||||
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service';
|
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service';
|
||||||
import {
|
import {
|
||||||
ASSET_SUB_CLASS_EMERGENCY_FUND,
|
ASSET_SUB_CLASS_EMERGENCY_FUND,
|
||||||
|
MAX_CHART_ITEMS,
|
||||||
UNKNOWN_KEY
|
UNKNOWN_KEY
|
||||||
} from '@ghostfolio/common/config';
|
} from '@ghostfolio/common/config';
|
||||||
import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper';
|
import { DATE_FORMAT, parseDate } from '@ghostfolio/common/helper';
|
||||||
@ -57,7 +58,6 @@ import {
|
|||||||
} from '@prisma/client';
|
} from '@prisma/client';
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
import {
|
import {
|
||||||
addDays,
|
|
||||||
differenceInDays,
|
differenceInDays,
|
||||||
endOfToday,
|
endOfToday,
|
||||||
format,
|
format,
|
||||||
@ -72,7 +72,7 @@ import {
|
|||||||
subDays,
|
subDays,
|
||||||
subYears
|
subYears
|
||||||
} from 'date-fns';
|
} from 'date-fns';
|
||||||
import { isEmpty, last, sortBy, uniq, uniqBy } from 'lodash';
|
import { isEmpty, sortBy, uniq, uniqBy } from 'lodash';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
HistoricalDataContainer,
|
HistoricalDataContainer,
|
||||||
@ -86,7 +86,6 @@ const emergingMarkets = require('../../assets/countries/emerging-markets.json');
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PortfolioService {
|
export class PortfolioService {
|
||||||
private static readonly MAX_CHART_ITEMS = 250;
|
|
||||||
private baseCurrency: string;
|
private baseCurrency: string;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
@ -388,43 +387,19 @@ export class PortfolioService {
|
|||||||
|
|
||||||
const daysInMarket = differenceInDays(new Date(), startDate);
|
const daysInMarket = differenceInDays(new Date(), startDate);
|
||||||
const step = Math.round(
|
const step = Math.round(
|
||||||
daysInMarket / Math.min(daysInMarket, PortfolioService.MAX_CHART_ITEMS)
|
daysInMarket / Math.min(daysInMarket, MAX_CHART_ITEMS)
|
||||||
);
|
);
|
||||||
|
|
||||||
const items: HistoricalDataItem[] = [];
|
const items = await portfolioCalculator.getChartData(
|
||||||
|
|
||||||
let currentEndDate = startDate;
|
|
||||||
|
|
||||||
while (isBefore(currentEndDate, endDate)) {
|
|
||||||
const currentPositions = await portfolioCalculator.getCurrentPositions(
|
|
||||||
startDate,
|
startDate,
|
||||||
currentEndDate
|
endDate,
|
||||||
|
step
|
||||||
);
|
);
|
||||||
|
|
||||||
items.push({
|
|
||||||
date: format(currentEndDate, DATE_FORMAT),
|
|
||||||
value: currentPositions.netPerformancePercentage.toNumber() * 100
|
|
||||||
});
|
|
||||||
|
|
||||||
currentEndDate = addDays(currentEndDate, step);
|
|
||||||
}
|
|
||||||
|
|
||||||
const today = new Date();
|
|
||||||
|
|
||||||
if (last(items)?.date !== format(today, DATE_FORMAT)) {
|
|
||||||
// Add today
|
|
||||||
const { netPerformancePercentage } =
|
|
||||||
await portfolioCalculator.getCurrentPositions(startDate, today);
|
|
||||||
items.push({
|
|
||||||
date: format(today, DATE_FORMAT),
|
|
||||||
value: netPerformancePercentage.toNumber() * 100
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
items,
|
||||||
isAllTimeHigh: false,
|
isAllTimeHigh: false,
|
||||||
isAllTimeLow: false,
|
isAllTimeLow: false
|
||||||
items: items
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,12 +449,21 @@ export class PortfolioService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const holdings: PortfolioDetails['holdings'] = {};
|
const holdings: PortfolioDetails['holdings'] = {};
|
||||||
const totalInvestment = currentPositions.totalInvestment.plus(
|
const totalInvestmentInBaseCurrency = currentPositions.totalInvestment.plus(
|
||||||
cashDetails.balanceInBaseCurrency
|
cashDetails.balanceInBaseCurrency
|
||||||
);
|
);
|
||||||
const totalValue = currentPositions.currentValue.plus(
|
let filteredValueInBaseCurrency = currentPositions.currentValue;
|
||||||
|
|
||||||
|
if (
|
||||||
|
aFilters?.length === 0 ||
|
||||||
|
(aFilters?.length === 1 &&
|
||||||
|
aFilters[0].type === 'ASSET_CLASS' &&
|
||||||
|
aFilters[0].id === 'CASH')
|
||||||
|
) {
|
||||||
|
filteredValueInBaseCurrency = filteredValueInBaseCurrency.plus(
|
||||||
cashDetails.balanceInBaseCurrency
|
cashDetails.balanceInBaseCurrency
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const dataGatheringItems = currentPositions.positions.map((position) => {
|
const dataGatheringItems = currentPositions.positions.map((position) => {
|
||||||
return {
|
return {
|
||||||
@ -540,10 +524,12 @@ export class PortfolioService {
|
|||||||
|
|
||||||
holdings[item.symbol] = {
|
holdings[item.symbol] = {
|
||||||
markets,
|
markets,
|
||||||
allocationCurrent: totalValue.eq(0)
|
allocationCurrent: filteredValueInBaseCurrency.eq(0)
|
||||||
? 0
|
? 0
|
||||||
: value.div(totalValue).toNumber(),
|
: value.div(filteredValueInBaseCurrency).toNumber(),
|
||||||
allocationInvestment: item.investment.div(totalInvestment).toNumber(),
|
allocationInvestment: item.investment
|
||||||
|
.div(totalInvestmentInBaseCurrency)
|
||||||
|
.toNumber(),
|
||||||
assetClass: symbolProfile.assetClass,
|
assetClass: symbolProfile.assetClass,
|
||||||
assetSubClass: symbolProfile.assetSubClass,
|
assetSubClass: symbolProfile.assetSubClass,
|
||||||
countries: symbolProfile.countries,
|
countries: symbolProfile.countries,
|
||||||
@ -577,8 +563,8 @@ export class PortfolioService {
|
|||||||
cashDetails,
|
cashDetails,
|
||||||
emergencyFund,
|
emergencyFund,
|
||||||
userCurrency,
|
userCurrency,
|
||||||
investment: totalInvestment,
|
investment: totalInvestmentInBaseCurrency,
|
||||||
value: totalValue
|
value: filteredValueInBaseCurrency
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const symbol of Object.keys(cashPositions)) {
|
for (const symbol of Object.keys(cashPositions)) {
|
||||||
@ -594,7 +580,18 @@ export class PortfolioService {
|
|||||||
filters: aFilters
|
filters: aFilters
|
||||||
});
|
});
|
||||||
|
|
||||||
return { accounts, holdings, hasErrors: currentPositions.hasErrors };
|
const summary = await this.getSummary(aImpersonationId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
accounts,
|
||||||
|
holdings,
|
||||||
|
filteredValueInBaseCurrency: filteredValueInBaseCurrency.toNumber(),
|
||||||
|
filteredValueInPercentage: summary.netWorth
|
||||||
|
? filteredValueInBaseCurrency.div(summary.netWorth).toNumber()
|
||||||
|
: 0,
|
||||||
|
hasErrors: currentPositions.hasErrors,
|
||||||
|
totalValueInBaseCurrency: summary.netWorth
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getPosition(
|
public async getPosition(
|
||||||
|
@ -41,6 +41,14 @@ export class RedactValuesInResponseInterceptor<T>
|
|||||||
return activity;
|
return activity;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.filteredValueInBaseCurrency) {
|
||||||
|
data.filteredValueInBaseCurrency = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.totalValueInBaseCurrency) {
|
||||||
|
data.totalValueInBaseCurrency = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
|
@ -183,10 +183,10 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
for (const historicalItem of historicalResult) {
|
for (const historicalItem of historicalResult) {
|
||||||
let marketPrice = historicalItem.close;
|
let marketPrice = historicalItem.close;
|
||||||
|
|
||||||
if (symbol === 'USDGBp') {
|
if (symbol === `${this.baseCurrency}GBp`) {
|
||||||
// Convert GPB to GBp (pence)
|
// Convert GPB to GBp (pence)
|
||||||
marketPrice = new Big(marketPrice).mul(100).toNumber();
|
marketPrice = new Big(marketPrice).mul(100).toNumber();
|
||||||
} else if (symbol === 'USDILA') {
|
} else if (symbol === `${this.baseCurrency}ILA`) {
|
||||||
// Convert ILS to ILA
|
// Convert ILS to ILA
|
||||||
marketPrice = new Big(marketPrice).mul(100).toNumber();
|
marketPrice = new Big(marketPrice).mul(100).toNumber();
|
||||||
}
|
}
|
||||||
@ -246,9 +246,12 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
marketPrice: quote.regularMarketPrice || 0
|
marketPrice: quote.regularMarketPrice || 0
|
||||||
};
|
};
|
||||||
|
|
||||||
if (symbol === 'USDGBP' && yahooFinanceSymbols.includes('USDGBp=X')) {
|
if (
|
||||||
|
symbol === `${this.baseCurrency}GBP` &&
|
||||||
|
yahooFinanceSymbols.includes(`${this.baseCurrency}GBp=X`)
|
||||||
|
) {
|
||||||
// Convert GPB to GBp (pence)
|
// Convert GPB to GBp (pence)
|
||||||
response['USDGBp'] = {
|
response[`${this.baseCurrency}GBp`] = {
|
||||||
...response[symbol],
|
...response[symbol],
|
||||||
currency: 'GBp',
|
currency: 'GBp',
|
||||||
marketPrice: new Big(response[symbol].marketPrice)
|
marketPrice: new Big(response[symbol].marketPrice)
|
||||||
@ -256,11 +259,11 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
.toNumber()
|
.toNumber()
|
||||||
};
|
};
|
||||||
} else if (
|
} else if (
|
||||||
symbol === 'USDILS' &&
|
symbol === `${this.baseCurrency}ILS` &&
|
||||||
yahooFinanceSymbols.includes('USDILA=X')
|
yahooFinanceSymbols.includes(`${this.baseCurrency}ILA=X`)
|
||||||
) {
|
) {
|
||||||
// Convert ILS to ILA
|
// Convert ILS to ILA
|
||||||
response['USDILA'] = {
|
response[`${this.baseCurrency}ILA`] = {
|
||||||
...response[symbol],
|
...response[symbol],
|
||||||
currency: 'ILA',
|
currency: 'ILA',
|
||||||
marketPrice: new Big(response[symbol].marketPrice)
|
marketPrice: new Big(response[symbol].marketPrice)
|
||||||
@ -270,9 +273,9 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yahooFinanceSymbols.includes('USDUSX=X')) {
|
if (yahooFinanceSymbols.includes(`${this.baseCurrency}USX=X`)) {
|
||||||
// Convert USD to USX (cent)
|
// Convert USD to USX (cent)
|
||||||
response['USDUSX'] = {
|
response[`${this.baseCurrency}USX`] = {
|
||||||
currency: 'USX',
|
currency: 'USX',
|
||||||
dataSource: this.getName(),
|
dataSource: this.getName(),
|
||||||
marketPrice: new Big(1).mul(100).toNumber(),
|
marketPrice: new Big(1).mul(100).toNumber(),
|
||||||
|
@ -99,10 +99,12 @@ export class ExchangeRateDataService {
|
|||||||
this.exchangeRates[symbol] = resultExtended[symbol]?.[date]?.marketPrice;
|
this.exchangeRates[symbol] = resultExtended[symbol]?.[date]?.marketPrice;
|
||||||
|
|
||||||
if (!this.exchangeRates[symbol]) {
|
if (!this.exchangeRates[symbol]) {
|
||||||
// Not found, calculate indirectly via USD
|
// Not found, calculate indirectly via base currency
|
||||||
this.exchangeRates[symbol] =
|
this.exchangeRates[symbol] =
|
||||||
resultExtended[`${currency1}${'USD'}`]?.[date]?.marketPrice *
|
resultExtended[`${currency1}${this.baseCurrency}`]?.[date]
|
||||||
resultExtended[`${'USD'}${currency2}`]?.[date]?.marketPrice;
|
?.marketPrice *
|
||||||
|
resultExtended[`${this.baseCurrency}${currency2}`]?.[date]
|
||||||
|
?.marketPrice;
|
||||||
|
|
||||||
// Calculate the opposite direction
|
// Calculate the opposite direction
|
||||||
this.exchangeRates[`${currency2}${currency1}`] =
|
this.exchangeRates[`${currency2}${currency1}`] =
|
||||||
@ -126,9 +128,11 @@ export class ExchangeRateDataService {
|
|||||||
if (this.exchangeRates[`${aFromCurrency}${aToCurrency}`]) {
|
if (this.exchangeRates[`${aFromCurrency}${aToCurrency}`]) {
|
||||||
factor = this.exchangeRates[`${aFromCurrency}${aToCurrency}`];
|
factor = this.exchangeRates[`${aFromCurrency}${aToCurrency}`];
|
||||||
} else {
|
} else {
|
||||||
// Calculate indirectly via USD
|
// Calculate indirectly via base currency
|
||||||
const factor1 = this.exchangeRates[`${aFromCurrency}${'USD'}`];
|
const factor1 =
|
||||||
const factor2 = this.exchangeRates[`${'USD'}${aToCurrency}`];
|
this.exchangeRates[`${aFromCurrency}${this.baseCurrency}`];
|
||||||
|
const factor2 =
|
||||||
|
this.exchangeRates[`${this.baseCurrency}${aToCurrency}`];
|
||||||
|
|
||||||
factor = factor1 * factor2;
|
factor = factor1 * factor2;
|
||||||
|
|
||||||
|
@ -23,11 +23,7 @@ import {
|
|||||||
getTextColor,
|
getTextColor,
|
||||||
parseDate
|
parseDate
|
||||||
} from '@ghostfolio/common/helper';
|
} from '@ghostfolio/common/helper';
|
||||||
import {
|
import { LineChartItem, User } from '@ghostfolio/common/interfaces';
|
||||||
LineChartItem,
|
|
||||||
UniqueAsset,
|
|
||||||
User
|
|
||||||
} from '@ghostfolio/common/interfaces';
|
|
||||||
import { DateRange } from '@ghostfolio/common/types';
|
import { DateRange } from '@ghostfolio/common/types';
|
||||||
import {
|
import {
|
||||||
Chart,
|
Chart,
|
||||||
@ -215,7 +211,7 @@ export class BenchmarkComparatorComponent implements OnChanges, OnDestroy {
|
|||||||
locale: this.locale,
|
locale: this.locale,
|
||||||
unit: '%'
|
unit: '%'
|
||||||
}),
|
}),
|
||||||
mode: 'index',
|
mode: 'x',
|
||||||
position: <unknown>'top',
|
position: <unknown>'top',
|
||||||
xAlign: 'center',
|
xAlign: 'center',
|
||||||
yAlign: 'bottom'
|
yAlign: 'bottom'
|
||||||
|
@ -108,7 +108,6 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-xs-12 col-md-4 my-2">
|
<div class="col-xs-12 col-md-4 my-2">
|
||||||
<gf-value
|
<gf-value
|
||||||
i18n
|
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 24 hours)"
|
subLabel="(Last 24 hours)"
|
||||||
[value]="statistics?.activeUsers1d ?? '-'"
|
[value]="statistics?.activeUsers1d ?? '-'"
|
||||||
@ -117,7 +116,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-4 my-2">
|
<div class="col-xs-12 col-md-4 my-2">
|
||||||
<gf-value
|
<gf-value
|
||||||
i18n
|
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 30 days)"
|
subLabel="(Last 30 days)"
|
||||||
[value]="statistics?.newUsers30d ?? '-'"
|
[value]="statistics?.newUsers30d ?? '-'"
|
||||||
@ -126,7 +124,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="col-xs-12 col-md-4 my-2">
|
<div class="col-xs-12 col-md-4 my-2">
|
||||||
<gf-value
|
<gf-value
|
||||||
i18n
|
|
||||||
size="large"
|
size="large"
|
||||||
subLabel="(Last 30 days)"
|
subLabel="(Last 30 days)"
|
||||||
[value]="statistics?.activeUsers30d ?? '-'"
|
[value]="statistics?.activeUsers30d ?? '-'"
|
||||||
@ -139,7 +136,6 @@
|
|||||||
href="https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg"
|
href="https://join.slack.com/t/ghostfolio/shared_invite/zt-vsaan64h-F_I0fEo5M0P88lP9ibCxFg"
|
||||||
>
|
>
|
||||||
<gf-value
|
<gf-value
|
||||||
i18n
|
|
||||||
size="large"
|
size="large"
|
||||||
[value]="statistics?.slackCommunityUsers ?? '-'"
|
[value]="statistics?.slackCommunityUsers ?? '-'"
|
||||||
>Users in Slack community</gf-value
|
>Users in Slack community</gf-value
|
||||||
@ -152,7 +148,6 @@
|
|||||||
href="https://github.com/ghostfolio/ghostfolio/graphs/contributors"
|
href="https://github.com/ghostfolio/ghostfolio/graphs/contributors"
|
||||||
>
|
>
|
||||||
<gf-value
|
<gf-value
|
||||||
i18n
|
|
||||||
size="large"
|
size="large"
|
||||||
[value]="statistics?.gitHubContributors ?? '-'"
|
[value]="statistics?.gitHubContributors ?? '-'"
|
||||||
>Contributors on GitHub</gf-value
|
>Contributors on GitHub</gf-value
|
||||||
@ -165,7 +160,6 @@
|
|||||||
href="https://github.com/ghostfolio/ghostfolio/stargazers"
|
href="https://github.com/ghostfolio/ghostfolio/stargazers"
|
||||||
>
|
>
|
||||||
<gf-value
|
<gf-value
|
||||||
i18n
|
|
||||||
size="large"
|
size="large"
|
||||||
[value]="statistics?.gitHubStargazers ?? '-'"
|
[value]="statistics?.gitHubStargazers ?? '-'"
|
||||||
>Stars on GitHub</gf-value
|
>Stars on GitHub</gf-value
|
||||||
|
@ -10,6 +10,22 @@
|
|||||||
></gf-activities-filter>
|
></gf-activities-filter>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col">
|
||||||
|
<mat-card class="mb-3">
|
||||||
|
<mat-card-header>
|
||||||
|
<mat-card-title i18n>Proportion of Net Worth</mat-card-title>
|
||||||
|
</mat-card-header>
|
||||||
|
<mat-card-content>
|
||||||
|
<mat-progress-bar
|
||||||
|
mode="determinate"
|
||||||
|
[title]="(portfolioDetails?.filteredValueInPercentage * 100).toFixed(2) + '%'"
|
||||||
|
[value]="portfolioDetails?.filteredValueInPercentage * 100"
|
||||||
|
></mat-progress-bar>
|
||||||
|
</mat-card-content>
|
||||||
|
</mat-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="proportion-charts row">
|
<div class="proportion-charts row">
|
||||||
<div class="col-md-4">
|
<div class="col-md-4">
|
||||||
<mat-card class="mb-3">
|
<mat-card class="mb-3">
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
|
import { GfToggleModule } from '@ghostfolio/client/components/toggle/toggle.module';
|
||||||
import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module';
|
import { GfWorldMapChartModule } from '@ghostfolio/client/components/world-map-chart/world-map-chart.module';
|
||||||
import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module';
|
import { GfActivitiesFilterModule } from '@ghostfolio/ui/activities-filter/activities-filter.module';
|
||||||
@ -22,7 +23,8 @@ import { AllocationsPageComponent } from './allocations-page.component';
|
|||||||
GfToggleModule,
|
GfToggleModule,
|
||||||
GfWorldMapChartModule,
|
GfWorldMapChartModule,
|
||||||
GfValueModule,
|
GfValueModule,
|
||||||
MatCardModule
|
MatCardModule,
|
||||||
|
MatProgressBarModule
|
||||||
],
|
],
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
})
|
})
|
||||||
|
@ -28,4 +28,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mat-progress-bar {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
height: 0.5rem;
|
||||||
|
|
||||||
|
::ng-deep {
|
||||||
|
.mat-progress-bar-background {
|
||||||
|
fill: rgb(var(--palette-background-unselected-chip));
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-progress-bar-buffer {
|
||||||
|
background-color: rgb(var(--palette-background-unselected-chip));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:host-context(.is-dark-theme) {
|
||||||
|
.mat-progress-bar {
|
||||||
|
::ng-deep {
|
||||||
|
.mat-progress-bar-background {
|
||||||
|
fill: rgb(var(--palette-background-unselected-chip-dark));
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-progress-bar-buffer {
|
||||||
|
background-color: rgb(var(--palette-background-unselected-chip-dark));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,15 @@
|
|||||||
get started. Due to the time it saves, this will be the best option
|
get started. Due to the time it saves, this will be the best option
|
||||||
for most people. The revenue is used for covering the hosting costs.
|
for most people. The revenue is used for covering the hosting costs.
|
||||||
</p>
|
</p>
|
||||||
|
<p *ngIf="user?.subscription?.type === 'Basic'">
|
||||||
|
If you plan to open an account at <i>DEGIRO</i>, <i>frankly</i>,
|
||||||
|
<i>Interactive Brokers</i>, <i>Swissquote</i>, or <i>VIAC</i>, please
|
||||||
|
<a href="mailto:hi@ghostfol.io?Subject=Referral link for..."
|
||||||
|
>contact us</a
|
||||||
|
>
|
||||||
|
to use our referral link and get a Ghostfolio Premium membership for
|
||||||
|
one year.
|
||||||
|
</p>
|
||||||
<p>
|
<p>
|
||||||
If you prefer to run Ghostfolio on your own infrastructure, please
|
If you prefer to run Ghostfolio on your own infrastructure, please
|
||||||
find the source code and further instructions on
|
find the source code and further instructions on
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="ccb2a809018b32a96c813ae69126ce05976109ce" datatype="html">
|
<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>
|
<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 Sie kurzfristig benötigen.</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
|
<context context-type="sourcefile">apps/client/src/app/app.component.html</context>
|
||||||
<context context-type="linenumber">55,56</context>
|
<context context-type="linenumber">55,56</context>
|
||||||
@ -1031,7 +1031,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="67251f04518ae452230c68a748b3fa2838b4db74" datatype="html">
|
<trans-unit id="67251f04518ae452230c68a748b3fa2838b4db74" datatype="html">
|
||||||
<source>Net Worth</source>
|
<source>Net Worth</source>
|
||||||
<target state="translated">Reinvermögen</target>
|
<target state="translated">Gesamtvermögen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
|
<context context-type="sourcefile">apps/client/src/app/components/portfolio-summary/portfolio-summary.component.html</context>
|
||||||
<context context-type="linenumber">179</context>
|
<context context-type="linenumber">179</context>
|
||||||
@ -1262,7 +1262,7 @@
|
|||||||
<target state="translated">Bitte gebe deinen Gutscheincode ein:</target>
|
<target state="translated">Bitte gebe deinen Gutscheincode ein:</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<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">225</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4420880039966769543" datatype="html">
|
<trans-unit id="4420880039966769543" datatype="html">
|
||||||
@ -1270,7 +1270,7 @@
|
|||||||
<target state="translated">Gutscheincode konnte nicht eingelöst werden</target>
|
<target state="translated">Gutscheincode konnte nicht eingelöst werden</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
||||||
<context context-type="linenumber">258</context>
|
<context context-type="linenumber">235</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4819099731531004979" datatype="html">
|
<trans-unit id="4819099731531004979" datatype="html">
|
||||||
@ -1278,7 +1278,7 @@
|
|||||||
<target state="translated">Gutscheincode wurde eingelöst</target>
|
<target state="translated">Gutscheincode wurde eingelöst</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
||||||
<context context-type="linenumber">270</context>
|
<context context-type="linenumber">247</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7967484035994732534" datatype="html">
|
<trans-unit id="7967484035994732534" datatype="html">
|
||||||
@ -1286,7 +1286,7 @@
|
|||||||
<target state="translated">Neu laden</target>
|
<target state="translated">Neu laden</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
||||||
<context context-type="linenumber">271</context>
|
<context context-type="linenumber">248</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7963559562180316948" datatype="html">
|
<trans-unit id="7963559562180316948" datatype="html">
|
||||||
@ -1294,7 +1294,7 @@
|
|||||||
<target state="translated">Möchtest du diese Anmeldemethode wirklich löschen?</target>
|
<target state="translated">Möchtest du diese Anmeldemethode wirklich löschen?</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
||||||
<context context-type="linenumber">317</context>
|
<context context-type="linenumber">294</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
|
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
|
||||||
@ -1323,7 +1323,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="f147d0f7f965cccee2e77294cba8e1b88021fa08" datatype="html">
|
<trans-unit id="f147d0f7f965cccee2e77294cba8e1b88021fa08" datatype="html">
|
||||||
<source>Upgrade</source>
|
<source>Upgrade</source>
|
||||||
<target state="new">Upgrade</target>
|
<target state="translated">Upgrade</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
|
||||||
<context context-type="linenumber">37</context>
|
<context context-type="linenumber">37</context>
|
||||||
@ -1379,7 +1379,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6b939b00e8481ed8aa8a24d8add7a209d7116759" datatype="html">
|
<trans-unit id="6b939b00e8481ed8aa8a24d8add7a209d7116759" datatype="html">
|
||||||
<source>Locale</source>
|
<source>Locale</source>
|
||||||
<target state="new">Locale</target>
|
<target state="translated">Lokalität</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
|
||||||
<context context-type="linenumber">135</context>
|
<context context-type="linenumber">135</context>
|
||||||
@ -1618,7 +1618,7 @@
|
|||||||
<target state="translated">Nach Konto</target>
|
<target state="translated">Nach Konto</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">17</context>
|
<context context-type="linenumber">33</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
|
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
|
||||||
@ -1626,7 +1626,7 @@
|
|||||||
<target state="translated">Nach Währung</target>
|
<target state="translated">Nach Währung</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">42</context>
|
<context context-type="linenumber">58</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
|
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
|
||||||
@ -1634,7 +1634,7 @@
|
|||||||
<target state="translated">Nach Asset Class</target>
|
<target state="translated">Nach Asset Class</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">70</context>
|
<context context-type="linenumber">86</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
|
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
|
||||||
@ -1642,7 +1642,7 @@
|
|||||||
<target state="translated">Nach Position</target>
|
<target state="translated">Nach Position</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">98</context>
|
<context context-type="linenumber">114</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
|
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
|
||||||
@ -1650,7 +1650,7 @@
|
|||||||
<target state="translated">Nach Sektor</target>
|
<target state="translated">Nach Sektor</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">126</context>
|
<context context-type="linenumber">142</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
|
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
|
||||||
@ -1658,7 +1658,7 @@
|
|||||||
<target state="translated">Nach Kontinent</target>
|
<target state="translated">Nach Kontinent</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">155</context>
|
<context context-type="linenumber">171</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
|
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
|
||||||
@ -1666,7 +1666,7 @@
|
|||||||
<target state="translated">Nach Land</target>
|
<target state="translated">Nach Land</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">183</context>
|
<context context-type="linenumber">199</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
|
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
|
||||||
@ -1674,7 +1674,7 @@
|
|||||||
<target state="translated">Regionen</target>
|
<target state="translated">Regionen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">214</context>
|
<context context-type="linenumber">230</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
@ -1706,7 +1706,7 @@
|
|||||||
<target state="translated">Zeitstrahl der Investitionen</target>
|
<target state="translated">Zeitstrahl der Investitionen</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
||||||
<context context-type="linenumber">102</context>
|
<context context-type="linenumber">105</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
|
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
|
||||||
@ -1714,7 +1714,7 @@
|
|||||||
<target state="translated">Gewinner</target>
|
<target state="translated">Gewinner</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
||||||
<context context-type="linenumber">23</context>
|
<context context-type="linenumber">26</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
|
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
|
||||||
@ -1722,7 +1722,7 @@
|
|||||||
<target state="translated">Verlierer</target>
|
<target state="translated">Verlierer</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
||||||
<context context-type="linenumber">59</context>
|
<context context-type="linenumber">62</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5857197365507636437" datatype="html">
|
<trans-unit id="5857197365507636437" datatype="html">
|
||||||
@ -2036,6 +2036,10 @@
|
|||||||
<trans-unit id="9201103587777813545" datatype="html">
|
<trans-unit id="9201103587777813545" datatype="html">
|
||||||
<source>Portfolio</source>
|
<source>Portfolio</source>
|
||||||
<target state="translated">Portfolio</target>
|
<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">111</context>
|
||||||
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
|
||||||
<context context-type="linenumber">12</context>
|
<context context-type="linenumber">12</context>
|
||||||
@ -2059,7 +2063,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="a3d148b40a389fda0665eb583c9e434ec5ee1ced" datatype="html">
|
<trans-unit id="a3d148b40a389fda0665eb583c9e434ec5ee1ced" datatype="html">
|
||||||
<source> Ghostfolio empowers you to keep track of your wealth. </source>
|
<source> Ghostfolio empowers you to keep track of your wealth. </source>
|
||||||
<target state="new"/>
|
<target state="translated">Ghostfolio verschafft Ihnen den Überblick über Ihr Vermögen.</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
<context context-type="linenumber">132,134</context>
|
<context context-type="linenumber">132,134</context>
|
||||||
@ -2270,7 +2274,7 @@
|
|||||||
<target state="translated">Beta</target>
|
<target state="translated">Beta</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
<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="linenumber">5</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
|
||||||
@ -2414,7 +2418,7 @@
|
|||||||
<target state="translated">Entwickelte Länder</target>
|
<target state="translated">Entwickelte Länder</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">240</context>
|
<context context-type="linenumber">256</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
@ -2426,7 +2430,7 @@
|
|||||||
<target state="translated">Schwellenländer</target>
|
<target state="translated">Schwellenländer</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">249</context>
|
<context context-type="linenumber">265</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
@ -2438,7 +2442,7 @@
|
|||||||
<target state="translated">Andere Länder</target>
|
<target state="translated">Andere Länder</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">258</context>
|
<context context-type="linenumber">274</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
@ -2453,50 +2457,6 @@
|
|||||||
<context context-type="linenumber">136</context>
|
<context context-type="linenumber">136</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
|
|
||||||
<source>Active Users</source>
|
|
||||||
<target state="new">Active Users</target>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">115</context>
|
|
||||||
</context-group>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">133</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
|
|
||||||
<source>New Users</source>
|
|
||||||
<target state="new">New Users</target>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">124</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
|
|
||||||
<source>Users in Slack community</source>
|
|
||||||
<target state="new">Users in Slack community</target>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">145</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
|
|
||||||
<source>Contributors on GitHub</source>
|
|
||||||
<target state="new">Contributors on GitHub</target>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">158</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
|
|
||||||
<source>Stars on GitHub</source>
|
|
||||||
<target state="new">Stars on GitHub</target>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">171</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
|
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
|
||||||
<source>Projected Total Amount</source>
|
<source>Projected Total Amount</source>
|
||||||
<target state="translated">Projizierter Gesamtbetrag</target>
|
<target state="translated">Projizierter Gesamtbetrag</target>
|
||||||
@ -2507,7 +2467,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2937311350146031865" datatype="html">
|
<trans-unit id="2937311350146031865" datatype="html">
|
||||||
<source>Initial</source>
|
<source>Initial</source>
|
||||||
<target state="new">Beginn</target>
|
<target state="translated">Beginn</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.component.ts</context>
|
||||||
<context context-type="linenumber">57</context>
|
<context context-type="linenumber">57</context>
|
||||||
@ -2526,7 +2486,7 @@
|
|||||||
<target state="translated">Monatlich</target>
|
<target state="translated">Monatlich</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
|
||||||
<context context-type="linenumber">30</context>
|
<context context-type="linenumber">38</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1975246224413290232" datatype="html">
|
<trans-unit id="1975246224413290232" datatype="html">
|
||||||
@ -2534,19 +2494,15 @@
|
|||||||
<target state="translated">Aufsummiert</target>
|
<target state="translated">Aufsummiert</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
|
||||||
<context context-type="linenumber">31</context>
|
<context context-type="linenumber">39</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5213771062241898526" datatype="html">
|
<trans-unit id="5213771062241898526" datatype="html">
|
||||||
<source>Deposit</source>
|
<source>Deposit</source>
|
||||||
<target state="translated">Einlage</target>
|
<target state="translated">Einlage</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">131</context>
|
|
||||||
</context-group>
|
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
|
||||||
<context context-type="linenumber">130</context>
|
<context context-type="linenumber">132</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
|
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
|
||||||
@ -2563,7 +2519,7 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1054498214311181686" datatype="html">
|
<trans-unit id="1054498214311181686" datatype="html">
|
||||||
<source>Savings</source>
|
<source>Savings</source>
|
||||||
<target state="new">Ersparnisse</target>
|
<target state="translated">Ersparnisse</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
|
<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">296</context>
|
||||||
@ -2606,7 +2562,7 @@
|
|||||||
<target state="translated">Filtern nach...</target>
|
<target state="translated">Filtern nach...</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.component.ts</context>
|
||||||
<context context-type="linenumber">129</context>
|
<context context-type="linenumber">128</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2078421919111943467" datatype="html">
|
<trans-unit id="2078421919111943467" datatype="html">
|
||||||
@ -2662,7 +2618,7 @@
|
|||||||
<target state="translated">Benchmarks</target>
|
<target state="translated">Benchmarks</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
||||||
<context context-type="linenumber">3</context>
|
<context context-type="linenumber">4</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
|
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
|
||||||
@ -2670,7 +2626,7 @@
|
|||||||
<target state="translated">Vergleichen mit...</target>
|
<target state="translated">Vergleichen mit...</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
||||||
<context context-type="linenumber">12</context>
|
<context context-type="linenumber">14</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1931353503905413384" datatype="html">
|
<trans-unit id="1931353503905413384" datatype="html">
|
||||||
@ -2678,7 +2634,15 @@
|
|||||||
<target state="translated">Benchmark</target>
|
<target state="translated">Benchmark</target>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
|
||||||
<context context-type="linenumber">149</context>
|
<context context-type="linenumber">120</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4210837540bca56dca96fcc451518659d06ad02a" datatype="html">
|
||||||
|
<source>Proportion of Net Worth</source>
|
||||||
|
<target state="translated">Anteil am Gesamtvermögen</target>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
|
2368
apps/client/src/locales/messages.it.xlf
Normal file
2368
apps/client/src/locales/messages.it.xlf
Normal file
File diff suppressed because it is too large
Load Diff
@ -1137,35 +1137,35 @@
|
|||||||
<source>Please enter your coupon code:</source>
|
<source>Please enter your coupon code:</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<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">225</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4420880039966769543" datatype="html">
|
<trans-unit id="4420880039966769543" datatype="html">
|
||||||
<source>Could not redeem coupon code</source>
|
<source>Could not redeem coupon code</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
||||||
<context context-type="linenumber">258</context>
|
<context context-type="linenumber">235</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="4819099731531004979" datatype="html">
|
<trans-unit id="4819099731531004979" datatype="html">
|
||||||
<source>Coupon code has been redeemed</source>
|
<source>Coupon code has been redeemed</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
||||||
<context context-type="linenumber">270</context>
|
<context context-type="linenumber">247</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7967484035994732534" datatype="html">
|
<trans-unit id="7967484035994732534" datatype="html">
|
||||||
<source>Reload</source>
|
<source>Reload</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
||||||
<context context-type="linenumber">271</context>
|
<context context-type="linenumber">248</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7963559562180316948" datatype="html">
|
<trans-unit id="7963559562180316948" datatype="html">
|
||||||
<source>Do you really want to remove this sign in method?</source>
|
<source>Do you really want to remove this sign in method?</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.component.ts</context>
|
||||||
<context context-type="linenumber">317</context>
|
<context context-type="linenumber">294</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
|
<trans-unit id="29881a45dafbe5aa05cd9d0441a4c0c2fb06df92" datatype="html">
|
||||||
@ -1453,56 +1453,56 @@
|
|||||||
<source>By Account</source>
|
<source>By Account</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">17</context>
|
<context context-type="linenumber">33</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
|
<trans-unit id="b79f5520c0cb9a00bd589e8a4c86ffcf5ae439d7" datatype="html">
|
||||||
<source>By Currency</source>
|
<source>By Currency</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">42</context>
|
<context context-type="linenumber">58</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
|
<trans-unit id="8288ff761f2d259625d2e5a3d96db727926d9cd4" datatype="html">
|
||||||
<source>By Asset Class</source>
|
<source>By Asset Class</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">70</context>
|
<context context-type="linenumber">86</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
|
<trans-unit id="b64539bb7815eb3275b55ad723d3897fc6ba8d23" datatype="html">
|
||||||
<source>By Holding</source>
|
<source>By Holding</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">98</context>
|
<context context-type="linenumber">114</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
|
<trans-unit id="9f86714c9a6b74e13c96ab02102ce40c34fe13b9" datatype="html">
|
||||||
<source>By Sector</source>
|
<source>By Sector</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">126</context>
|
<context context-type="linenumber">142</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
|
<trans-unit id="7017e0e26b53ef322c3e3bbf95f06a85487a12b2" datatype="html">
|
||||||
<source>By Continent</source>
|
<source>By Continent</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">155</context>
|
<context context-type="linenumber">171</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
|
<trans-unit id="f27e9dd8de80176286e02312e694cb8d1e485a5d" datatype="html">
|
||||||
<source>By Country</source>
|
<source>By Country</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">183</context>
|
<context context-type="linenumber">199</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
|
<trans-unit id="85780db87ac6c9f202615ac63754551c061e7236" datatype="html">
|
||||||
<source>Regions</source>
|
<source>Regions</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">214</context>
|
<context context-type="linenumber">230</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
@ -1531,21 +1531,21 @@
|
|||||||
<source>Investment Timeline</source>
|
<source>Investment Timeline</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
||||||
<context context-type="linenumber">102</context>
|
<context context-type="linenumber">105</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
|
<trans-unit id="6ae1c94f6bad274424f97e9bc8766242c1577447" datatype="html">
|
||||||
<source>Top</source>
|
<source>Top</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
||||||
<context context-type="linenumber">23</context>
|
<context context-type="linenumber">26</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
|
<trans-unit id="6723d5c967329a3ac75524cf0c1af5ced022b9a3" datatype="html">
|
||||||
<source>Bottom</source>
|
<source>Bottom</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.html</context>
|
||||||
<context context-type="linenumber">59</context>
|
<context context-type="linenumber">62</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5857197365507636437" datatype="html">
|
<trans-unit id="5857197365507636437" datatype="html">
|
||||||
@ -1824,6 +1824,10 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="9201103587777813545" datatype="html">
|
<trans-unit id="9201103587777813545" datatype="html">
|
||||||
<source>Portfolio</source>
|
<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">111</context>
|
||||||
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page-routing.module.ts</context>
|
||||||
<context context-type="linenumber">12</context>
|
<context context-type="linenumber">12</context>
|
||||||
@ -2029,7 +2033,7 @@
|
|||||||
<source>Beta</source>
|
<source>Beta</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
<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="linenumber">5</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/account/account-page.html</context>
|
||||||
@ -2100,7 +2104,7 @@
|
|||||||
<source>Developed Markets</source>
|
<source>Developed Markets</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">240</context>
|
<context context-type="linenumber">256</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
@ -2140,7 +2144,7 @@
|
|||||||
<source>Other Markets</source>
|
<source>Other Markets</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">258</context>
|
<context context-type="linenumber">274</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
@ -2151,7 +2155,7 @@
|
|||||||
<source>Emerging Markets</source>
|
<source>Emerging Markets</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
<context context-type="linenumber">249</context>
|
<context context-type="linenumber">265</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/public/public-page.html</context>
|
||||||
@ -2193,45 +2197,6 @@
|
|||||||
<context context-type="linenumber">136</context>
|
<context context-type="linenumber">136</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1de491c923555d6422bc6f1146357eb2b47853da" datatype="html">
|
|
||||||
<source>Active Users</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">115</context>
|
|
||||||
</context-group>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">133</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="8c4cfd77b7b3d7917de13bec98a8a74890f95618" datatype="html">
|
|
||||||
<source>New Users</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">124</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="8d3932a9eba50bc101c2b8c329e7b4ea033cde97" datatype="html">
|
|
||||||
<source>Stars on GitHub</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">171</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="be99161cc904867871ab172df77b736d3b27dfc5" datatype="html">
|
|
||||||
<source>Contributors on GitHub</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">158</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="c0eb011366e597e23542be386e8bc0d53470b520" datatype="html">
|
|
||||||
<source>Users in Slack community</source>
|
|
||||||
<context-group purpose="location">
|
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/about/about-page.html</context>
|
|
||||||
<context context-type="linenumber">145</context>
|
|
||||||
</context-group>
|
|
||||||
</trans-unit>
|
|
||||||
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
|
<trans-unit id="e34e2478d2d30c9d01758d01b7212411171b9bd5" datatype="html">
|
||||||
<source>Projected Total Amount</source>
|
<source>Projected Total Amount</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
@ -2250,7 +2215,7 @@
|
|||||||
<source>Accumulating</source>
|
<source>Accumulating</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
|
||||||
<context context-type="linenumber">31</context>
|
<context context-type="linenumber">39</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="2937311350146031865" datatype="html">
|
<trans-unit id="2937311350146031865" datatype="html">
|
||||||
@ -2269,13 +2234,9 @@
|
|||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="5213771062241898526" datatype="html">
|
<trans-unit id="5213771062241898526" datatype="html">
|
||||||
<source>Deposit</source>
|
<source>Deposit</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">131</context>
|
|
||||||
</context-group>
|
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/components/investment-chart/investment-chart.component.ts</context>
|
||||||
<context context-type="linenumber">130</context>
|
<context context-type="linenumber">132</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
|
<context context-type="sourcefile">libs/ui/src/lib/fire-calculator/fire-calculator.component.ts</context>
|
||||||
@ -2293,7 +2254,7 @@
|
|||||||
<source>Monthly</source>
|
<source>Monthly</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/analysis/analysis-page.component.ts</context>
|
||||||
<context context-type="linenumber">30</context>
|
<context context-type="linenumber">38</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
|
<trans-unit id="8511b16abcf065252b350d64e337ba2447db3ffb" datatype="html">
|
||||||
@ -2339,7 +2300,7 @@
|
|||||||
<source>Filter by...</source>
|
<source>Filter by...</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/components/admin-market-data/admin-market-data.component.ts</context>
|
||||||
<context context-type="linenumber">129</context>
|
<context context-type="linenumber">128</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="303469635941752458" datatype="html">
|
<trans-unit id="303469635941752458" datatype="html">
|
||||||
@ -2378,21 +2339,28 @@
|
|||||||
<source>Benchmark</source>
|
<source>Benchmark</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
|
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.ts</context>
|
||||||
<context context-type="linenumber">149</context>
|
<context context-type="linenumber">120</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="1b25c6e22f822e07a3e4d5aae4edc5b41fe083c2" datatype="html">
|
<trans-unit id="1b25c6e22f822e07a3e4d5aae4edc5b41fe083c2" datatype="html">
|
||||||
<source>Benchmarks</source>
|
<source>Benchmarks</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
||||||
<context context-type="linenumber">3</context>
|
<context context-type="linenumber">4</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
|
<trans-unit id="44fcf77e86dc038202ebad6b46d1d833d60d781b" datatype="html">
|
||||||
<source>Compare with...</source>
|
<source>Compare with...</source>
|
||||||
<context-group purpose="location">
|
<context-group purpose="location">
|
||||||
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
<context context-type="sourcefile">apps/client/src/app/components/benchmark-comparator/benchmark-comparator.component.html</context>
|
||||||
<context context-type="linenumber">12</context>
|
<context context-type="linenumber">14</context>
|
||||||
|
</context-group>
|
||||||
|
</trans-unit>
|
||||||
|
<trans-unit id="4210837540bca56dca96fcc451518659d06ad02a" datatype="html">
|
||||||
|
<source>Proportion of Net Worth</source>
|
||||||
|
<context-group purpose="location">
|
||||||
|
<context context-type="sourcefile">apps/client/src/app/pages/portfolio/allocations/allocations-page.html</context>
|
||||||
|
<context context-type="linenumber">17</context>
|
||||||
</context-group>
|
</context-group>
|
||||||
</trans-unit>
|
</trans-unit>
|
||||||
</body>
|
</body>
|
||||||
|
@ -6,6 +6,7 @@ services:
|
|||||||
- ../.env
|
- ../.env
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=prefer
|
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=prefer
|
||||||
|
NODE_ENV: production
|
||||||
REDIS_HOST: 'redis'
|
REDIS_HOST: 'redis'
|
||||||
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||||
ports:
|
ports:
|
||||||
|
@ -6,6 +6,7 @@ services:
|
|||||||
- ../.env
|
- ../.env
|
||||||
environment:
|
environment:
|
||||||
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=prefer
|
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}?sslmode=prefer
|
||||||
|
NODE_ENV: production
|
||||||
REDIS_HOST: 'redis'
|
REDIS_HOST: 'redis'
|
||||||
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
REDIS_PASSWORD: ${REDIS_PASSWORD}
|
||||||
ports:
|
ports:
|
||||||
|
@ -67,6 +67,8 @@ export const GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS: JobOptions = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MAX_CHART_ITEMS = 365;
|
||||||
|
|
||||||
export const PROPERTY_BENCHMARKS = 'BENCHMARKS';
|
export const PROPERTY_BENCHMARKS = 'BENCHMARKS';
|
||||||
export const PROPERTY_COUPONS = 'COUPONS';
|
export const PROPERTY_COUPONS = 'COUPONS';
|
||||||
export const PROPERTY_CURRENCIES = 'CURRENCIES';
|
export const PROPERTY_CURRENCIES = 'CURRENCIES';
|
||||||
|
@ -10,5 +10,8 @@ export interface PortfolioDetails {
|
|||||||
original: number;
|
original: number;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
filteredValueInBaseCurrency?: number;
|
||||||
|
filteredValueInPercentage: number;
|
||||||
holdings: { [symbol: string]: PortfolioPosition };
|
holdings: { [symbol: string]: PortfolioPosition };
|
||||||
|
totalValueInBaseCurrency?: number;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "ghostfolio",
|
"name": "ghostfolio",
|
||||||
"version": "1.192.0",
|
"version": "1.195.0",
|
||||||
"homepage": "https://ghostfol.io",
|
"homepage": "https://ghostfol.io",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
Reference in New Issue
Block a user