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