Browse Source

Add positions by continent chart

pull/148/head
Thomas 4 years ago
parent
commit
592a0f64b4
  1. 21
      apps/api/src/models/portfolio.ts
  2. 43
      apps/client/src/app/pages/tools/analysis/analysis-page.component.ts
  3. 30
      apps/client/src/app/pages/tools/analysis/analysis-page.html
  4. 6
      libs/common/src/lib/interfaces/country.interface.ts
  5. 6
      libs/common/src/lib/interfaces/portfolio-position.interface.ts
  6. 1
      package.json
  7. 5
      yarn.lock

21
apps/api/src/models/portfolio.ts

@ -8,8 +8,10 @@ import {
Position,
UserWithSettings
} from '@ghostfolio/common/interfaces';
import { Country } from '@ghostfolio/common/interfaces/country.interface';
import { DateRange, OrderWithAccount } from '@ghostfolio/common/types';
import { Prisma } from '@prisma/client';
import { continents, countries } from 'countries-list';
import {
add,
format,
@ -207,7 +209,7 @@ export class Portfolio implements PortfolioInterface {
symbols.forEach((symbol) => {
const accounts: PortfolioPosition['accounts'] = {};
let countries: Prisma.JsonArray;
let countriesOfSymbol: Country[];
const [portfolioItem] = portfolioItems;
const ordersBySymbol = this.getOrders().filter((order) => {
@ -248,9 +250,20 @@ export class Portfolio implements PortfolioInterface {
};
}
countries =
countriesOfSymbol = (
(orderOfSymbol.getSymbolProfile()?.countries as Prisma.JsonArray) ??
[];
[]
).map((country) => {
const { code, weight } = country as Prisma.JsonObject;
return {
code: code as string,
continent:
continents[countries[code as string]?.continent] ?? UNKNOWN_KEY,
name: countries[code as string]?.name ?? UNKNOWN_KEY,
weight: weight as number
};
});
});
let now = portfolioItemsNow.positions[symbol].marketPrice;
@ -288,7 +301,6 @@ export class Portfolio implements PortfolioInterface {
details[symbol] = {
...data[symbol],
accounts,
countries,
symbol,
allocationCurrent:
this.exchangeRateDataService.toCurrency(
@ -298,6 +310,7 @@ export class Portfolio implements PortfolioInterface {
) / value,
allocationInvestment:
portfolioItem.positions[symbol].investment / investment,
countries: countriesOfSymbol,
grossPerformance: roundTo(
portfolioItemsNow.positions[symbol].quantity * (now - before),
2

43
apps/client/src/app/pages/tools/analysis/analysis-page.component.ts

@ -9,7 +9,6 @@ import {
PortfolioPosition,
User
} from '@ghostfolio/common/interfaces';
import { Prisma } from '@prisma/client';
import { DeviceDetectorService } from 'ngx-device-detector';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@ -23,8 +22,11 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
public accounts: {
[symbol: string]: Pick<PortfolioPosition, 'name'> & { value: number };
};
public continents: {
[code: string]: { name: string; value: number };
};
public countries: {
[key: string]: { name: string; value: number };
[code: string]: { name: string; value: number };
};
public deviceType: string;
public period = 'current';
@ -102,6 +104,12 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
aPeriod: string
) {
this.accounts = {};
this.continents = {
[UNKNOWN_KEY]: {
name: UNKNOWN_KEY,
value: 0
}
};
this.countries = {
[UNKNOWN_KEY]: {
name: UNKNOWN_KEY,
@ -141,16 +149,28 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
if (position.countries.length > 0) {
for (const country of position.countries) {
const { key, weight } = country as Prisma.JsonObject;
const { code, continent, name, weight } = country;
if (this.continents[continent]?.value) {
this.continents[continent].value += weight * position.value;
} else {
this.continents[continent] = {
name: continent,
value:
weight *
(aPeriod === 'original'
? this.portfolioPositions[symbol].investment
: this.portfolioPositions[symbol].value)
};
}
if (this.countries[<string>key]?.value) {
this.countries[<string>key].value +=
<number>weight * position.value;
if (this.countries[code]?.value) {
this.countries[code].value += weight * position.value;
} else {
this.countries[<string>key] = {
name: <string>key,
this.countries[code] = {
name,
value:
<number>weight *
weight *
(aPeriod === 'original'
? this.portfolioPositions[symbol].investment
: this.portfolioPositions[symbol].value)
@ -158,6 +178,11 @@ export class AnalysisPageComponent implements OnDestroy, OnInit {
}
}
} else {
this.continents[UNKNOWN_KEY].value +=
aPeriod === 'original'
? this.portfolioPositions[symbol].investment
: this.portfolioPositions[symbol].value;
this.countries[UNKNOWN_KEY].value +=
aPeriod === 'original'
? this.portfolioPositions[symbol].investment

30
apps/client/src/app/pages/tools/analysis/analysis-page.html

@ -105,7 +105,7 @@
<div class="col-md-6">
<mat-card class="mb-3">
<mat-card-header class="w-100">
<mat-card-title i18n>By Currency</mat-card-title>
<mat-card-title i18n>By Continent</mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
@ -115,11 +115,11 @@
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
key="currency"
key="name"
[baseCurrency]="user?.settings?.baseCurrency"
[isInPercent]="true"
[isInPercent]="false"
[locale]="user?.settings?.locale"
[positions]="positions"
[positions]="continents"
></gf-portfolio-proportion-chart>
</mat-card-content>
</mat-card>
@ -146,6 +146,28 @@
</mat-card-content>
</mat-card>
</div>
<div class="col-md-6">
<mat-card class="mb-3">
<mat-card-header class="w-100">
<mat-card-title i18n>By Currency</mat-card-title>
<gf-toggle
[defaultValue]="period"
[isLoading]="false"
[options]="periodOptions"
(change)="onChangePeriod($event.value)"
></gf-toggle>
</mat-card-header>
<mat-card-content>
<gf-portfolio-proportion-chart
key="currency"
[baseCurrency]="user?.settings?.baseCurrency"
[isInPercent]="true"
[locale]="user?.settings?.locale"
[positions]="positions"
></gf-portfolio-proportion-chart>
</mat-card-content>
</mat-card>
</div>
<div class="col-md-6">
<mat-card class="mb-3">
<mat-card-header class="w-100">

6
libs/common/src/lib/interfaces/country.interface.ts

@ -0,0 +1,6 @@
export interface Country {
code: string;
continent: string;
name: string;
weight: number;
}

6
libs/common/src/lib/interfaces/portfolio-position.interface.ts

@ -1,5 +1,7 @@
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
import { Currency, Prisma } from '@prisma/client';
import { Currency } from '@prisma/client';
import { Country } from './country.interface';
export interface PortfolioPosition {
accounts: {
@ -7,7 +9,7 @@ export interface PortfolioPosition {
};
allocationCurrent: number;
allocationInvestment: number;
countries: Prisma.JsonArray;
countries: Country[];
currency: Currency;
exchange?: string;
grossPerformance: number;

1
package.json

@ -79,6 +79,7 @@
"cheerio": "1.0.0-rc.6",
"class-transformer": "0.3.2",
"class-validator": "0.13.1",
"countries-list": "2.6.1",
"countup.js": "2.0.7",
"cryptocurrencies": "7.0.0",
"date-fns": "2.19.0",

5
yarn.lock

@ -4698,6 +4698,11 @@ cosmiconfig@^7.0.0:
path-type "^4.0.0"
yaml "^1.10.0"
countries-list@2.6.1:
version "2.6.1"
resolved "https://registry.yarnpkg.com/countries-list/-/countries-list-2.6.1.tgz#d479757ac873b1e596ccea0a925962d20396c0cb"
integrity sha512-jXM1Nv3U56dPQ1DsUSsEaGmLHburo4fnB7m+1yhWDUVvx5gXCd1ok/y3gXCjXzhqyawG+igcPYcAl4qjkvopaQ==
countup.js@2.0.7:
version "2.0.7"
resolved "https://registry.yarnpkg.com/countup.js/-/countup.js-2.0.7.tgz#56b72a87fc0ee3cadb38356c246ccac88fb0a8cc"

Loading…
Cancel
Save