Feature/add countries and sectors to position detail dialog (#692)

* Add asset and asset sub class

* Add countries and sectors to position detail dialog

* Update changelog
This commit is contained in:
Thomas Kaul
2022-02-12 11:22:03 +01:00
committed by GitHub
parent 9344dcd26e
commit fa66cd5bce
11 changed files with 152 additions and 71 deletions

View File

@@ -11,7 +11,7 @@ import { DataService } from '@ghostfolio/client/services/data.service';
import { DATE_FORMAT, downloadAsFile } from '@ghostfolio/common/helper';
import { OrderWithAccount } from '@ghostfolio/common/types';
import { LineChartItem } from '@ghostfolio/ui/line-chart/interfaces/line-chart.interface';
import { AssetSubClass } from '@prisma/client';
import { SymbolProfile } from '@prisma/client';
import { format, isSameMonth, isToday, parseISO } from 'date-fns';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@@ -26,10 +26,11 @@ import { PositionDetailDialogParams } from './interfaces/interfaces';
styleUrls: ['./position-detail-dialog.component.scss']
})
export class PositionDetailDialog implements OnDestroy, OnInit {
public assetSubClass: AssetSubClass;
public averagePrice: number;
public benchmarkDataItems: LineChartItem[];
public currency: string;
public countries: {
[code: string]: { name: string; value: number };
};
public firstBuyDate: string;
public grossPerformance: number;
public grossPerformancePercent: number;
@@ -38,13 +39,15 @@ export class PositionDetailDialog implements OnDestroy, OnInit {
public marketPrice: number;
public maxPrice: number;
public minPrice: number;
public name: string;
public netPerformance: number;
public netPerformancePercent: number;
public orders: OrderWithAccount[];
public quantity: number;
public quantityPrecision = 2;
public symbol: string;
public sectors: {
[name: string]: { name: string; value: number };
};
public SymbolProfile: SymbolProfile;
public transactionCount: number;
public value: number;
@@ -66,9 +69,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit {
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(
({
assetSubClass,
averagePrice,
currency,
firstBuyDate,
grossPerformance,
grossPerformancePercent,
@@ -77,19 +78,17 @@ export class PositionDetailDialog implements OnDestroy, OnInit {
marketPrice,
maxPrice,
minPrice,
name,
netPerformance,
netPerformancePercent,
orders,
quantity,
symbol,
SymbolProfile,
transactionCount,
value
}) => {
this.assetSubClass = assetSubClass;
this.averagePrice = averagePrice;
this.benchmarkDataItems = [];
this.currency = currency;
this.countries = {};
this.firstBuyDate = firstBuyDate;
this.grossPerformance = grossPerformance;
this.grossPerformancePercent = grossPerformancePercent;
@@ -110,15 +109,33 @@ export class PositionDetailDialog implements OnDestroy, OnInit {
this.marketPrice = marketPrice;
this.maxPrice = maxPrice;
this.minPrice = minPrice;
this.name = name;
this.netPerformance = netPerformance;
this.netPerformancePercent = netPerformancePercent;
this.orders = orders;
this.quantity = quantity;
this.symbol = symbol;
this.sectors = {};
this.SymbolProfile = SymbolProfile;
this.transactionCount = transactionCount;
this.value = value;
if (SymbolProfile?.countries?.length > 0) {
for (const country of SymbolProfile.countries) {
this.countries[country.code] = {
name: country.name,
value: country.weight
};
}
}
if (SymbolProfile?.sectors?.length > 0) {
for (const sector of SymbolProfile.sectors) {
this.sectors[sector.name] = {
name: sector.name,
value: sector.weight
};
}
}
if (isToday(parseISO(this.firstBuyDate))) {
// Add average price
this.historicalDataItems.push({
@@ -166,7 +183,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit {
if (Number.isInteger(this.quantity)) {
this.quantityPrecision = 0;
} else if (assetSubClass === 'CRYPTOCURRENCY') {
} else if (this.SymbolProfile?.assetSubClass === 'CRYPTOCURRENCY') {
if (this.quantity < 1) {
this.quantityPrecision = 7;
} else if (this.quantity < 1000) {
@@ -196,7 +213,7 @@ export class PositionDetailDialog implements OnDestroy, OnInit {
.subscribe((data) => {
downloadAsFile(
data,
`ghostfolio-export-${this.symbol}-${format(
`ghostfolio-export-${this.SymbolProfile?.symbol}-${format(
parseISO(data.meta.date),
'yyyyMMddHHmm'
)}.json`,

View File

@@ -2,7 +2,7 @@
mat-dialog-title
position="center"
[deviceType]="data.deviceType"
[title]="name ?? symbol"
[title]="SymbolProfile?.name ?? SymbolProfile?.symbol"
(closeButtonClicked)="onClose()"
></gf-dialog-header>
@@ -55,7 +55,7 @@
<gf-value
label="Ø Buy Price"
size="medium"
[currency]="currency"
[currency]="SymbolProfile?.currency"
[locale]="data.locale"
[value]="averagePrice"
></gf-value>
@@ -64,7 +64,7 @@
<gf-value
label="Market Price"
size="medium"
[currency]="currency"
[currency]="SymbolProfile?.currency"
[locale]="data.locale"
[value]="marketPrice"
></gf-value>
@@ -73,7 +73,7 @@
<gf-value
label="Minimum Price"
size="medium"
[currency]="currency"
[currency]="SymbolProfile?.currency"
[locale]="data.locale"
[ngClass]="{ 'text-danger': minPrice?.toFixed(2) === marketPrice?.toFixed(2) && maxPrice?.toFixed(2) !== minPrice?.toFixed(2) }"
[value]="minPrice"
@@ -83,7 +83,7 @@
<gf-value
label="Maximum Price"
size="medium"
[currency]="currency"
[currency]="SymbolProfile?.currency"
[locale]="data.locale"
[ngClass]="{ 'text-success': maxPrice?.toFixed(2) === marketPrice?.toFixed(2) && maxPrice?.toFixed(2) !== minPrice?.toFixed(2) }"
[value]="maxPrice"
@@ -122,6 +122,72 @@
[value]="transactionCount"
></gf-value>
</div>
<div class="col-6 mb-3">
<gf-value
label="Asset Class"
size="medium"
[value]="SymbolProfile?.assetClass"
></gf-value>
</div>
<div class="col-6 mb-3">
<gf-value
size="medium"
label="Asset Sub Class"
[locale]="data.locale"
[value]="SymbolProfile?.assetSubClass"
></gf-value>
</div>
<ng-container
*ngIf="SymbolProfile?.countries?.length > 0 || SymbolProfile?.sectors?.length > 0"
>
<ng-container
*ngIf="SymbolProfile?.countries?.length === 1 && SymbolProfile?.sectors?.length === 1; else charts"
>
<div
*ngIf="SymbolProfile?.countries?.length === 1"
class="col-6 mb-3"
>
<gf-value
label="Country"
size="medium"
[locale]="data.locale"
[value]="SymbolProfile.countries[0].name"
></gf-value>
</div>
<div *ngIf="SymbolProfile?.sectors?.length === 1" class="col-6 mb-3">
<gf-value
label="Sector"
size="medium"
[locale]="data.locale"
[value]="SymbolProfile.sectors[0].name"
></gf-value>
</div>
</ng-container>
<ng-template #charts>
<div class="col-6 mb-3">
<div class="h4 mb-0" i18n>Countries</div>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[isInPercent]="true"
[keys]="['name']"
[locale]="user?.settings?.locale"
[maxItems]="10"
[positions]="countries"
></gf-portfolio-proportion-chart>
</div>
<div class="col-6 mb-3">
<div class="h4 mb-0" i18n>Sectors</div>
<gf-portfolio-proportion-chart
[baseCurrency]="user?.settings?.baseCurrency"
[isInPercent]="true"
[keys]="['name']"
[locale]="user?.settings?.locale"
[maxItems]="10"
[positions]="sectors"
></gf-portfolio-proportion-chart>
</div>
</ng-template>
</ng-container>
</div>
</div>

View File

@@ -6,6 +6,7 @@ import { GfDialogFooterModule } from '@ghostfolio/client/components/dialog-foote
import { GfDialogHeaderModule } from '@ghostfolio/client/components/dialog-header/dialog-header.module';
import { GfActivitiesTableModule } from '@ghostfolio/ui/activities-table/activities-table.module';
import { GfLineChartModule } from '@ghostfolio/ui/line-chart/line-chart.module';
import { GfPortfolioProportionChartModule } from '@ghostfolio/ui/portfolio-proportion-chart/portfolio-proportion-chart.module';
import { GfValueModule } from '@ghostfolio/ui/value';
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
@@ -20,6 +21,7 @@ import { PositionDetailDialog } from './position-detail-dialog.component';
GfDialogFooterModule,
GfDialogHeaderModule,
GfLineChartModule,
GfPortfolioProportionChartModule,
GfValueModule,
MatButtonModule,
MatDialogModule,