Feature/replace type with asset class (#274)
* Improved the asset classification * Add assetClass to symbolProfile * Remove type from position * Update changelog
This commit is contained in:
parent
178166d86b
commit
80d043729d
@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Hid the pagination of tabs
|
- Hid the pagination of tabs
|
||||||
|
- Improved the classification of assets
|
||||||
- Improved the support for future transactions (drafts)
|
- Improved the support for future transactions (drafts)
|
||||||
- Optimized the accounts table for mobile
|
- Optimized the accounts table for mobile
|
||||||
- Upgraded `chart.js` from version `3.3.2` to `3.5.0`
|
- Upgraded `chart.js` from version `3.3.2` to `3.5.0`
|
||||||
|
@ -38,12 +38,7 @@ import {
|
|||||||
} from '@ghostfolio/common/types';
|
} from '@ghostfolio/common/types';
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { REQUEST } from '@nestjs/core';
|
import { REQUEST } from '@nestjs/core';
|
||||||
import {
|
import { Currency, DataSource, Type as TypeOfOrder } from '@prisma/client';
|
||||||
Currency,
|
|
||||||
DataSource,
|
|
||||||
Prisma,
|
|
||||||
Type as TypeOfOrder
|
|
||||||
} from '@prisma/client';
|
|
||||||
import Big from 'big.js';
|
import Big from 'big.js';
|
||||||
import {
|
import {
|
||||||
endOfToday,
|
endOfToday,
|
||||||
@ -239,6 +234,7 @@ export class PortfolioService {
|
|||||||
allocationInvestment: item.investment
|
allocationInvestment: item.investment
|
||||||
.div(currentPositions.totalInvestment)
|
.div(currentPositions.totalInvestment)
|
||||||
.toNumber(),
|
.toNumber(),
|
||||||
|
assetClass: symbolProfile.assetClass,
|
||||||
countries: symbolProfile.countries,
|
countries: symbolProfile.countries,
|
||||||
currency: item.currency,
|
currency: item.currency,
|
||||||
exchange: dataProviderResponse.exchange,
|
exchange: dataProviderResponse.exchange,
|
||||||
@ -252,7 +248,6 @@ export class PortfolioService {
|
|||||||
sectors: symbolProfile.sectors,
|
sectors: symbolProfile.sectors,
|
||||||
symbol: item.symbol,
|
symbol: item.symbol,
|
||||||
transactionCount: item.transactionCount,
|
transactionCount: item.transactionCount,
|
||||||
type: dataProviderResponse.type,
|
|
||||||
value: value.toNumber()
|
value: value.toNumber()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -498,6 +493,7 @@ export class PortfolioService {
|
|||||||
positions: positions.map((position) => {
|
positions: positions.map((position) => {
|
||||||
return {
|
return {
|
||||||
...position,
|
...position,
|
||||||
|
assetClass: symbolProfileMap[position.symbol].assetClass,
|
||||||
averagePrice: new Big(position.averagePrice).toNumber(),
|
averagePrice: new Big(position.averagePrice).toNumber(),
|
||||||
grossPerformance: position.grossPerformance?.toNumber() ?? null,
|
grossPerformance: position.grossPerformance?.toNumber() ?? null,
|
||||||
grossPerformancePercentage:
|
grossPerformancePercentage:
|
||||||
|
@ -134,18 +134,21 @@ export class DataGatheringService {
|
|||||||
|
|
||||||
const currentData = await this.dataProviderService.get(symbols);
|
const currentData = await this.dataProviderService.get(symbols);
|
||||||
|
|
||||||
for (const [symbol, { currency, dataSource, name }] of Object.entries(
|
for (const [
|
||||||
currentData
|
symbol,
|
||||||
)) {
|
{ assetClass, currency, dataSource, name }
|
||||||
|
] of Object.entries(currentData)) {
|
||||||
try {
|
try {
|
||||||
await this.prismaService.symbolProfile.upsert({
|
await this.prismaService.symbolProfile.upsert({
|
||||||
create: {
|
create: {
|
||||||
|
assetClass,
|
||||||
currency,
|
currency,
|
||||||
dataSource,
|
dataSource,
|
||||||
name,
|
name,
|
||||||
symbol
|
symbol
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
|
assetClass,
|
||||||
currency,
|
currency,
|
||||||
name
|
name
|
||||||
},
|
},
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
} from '@ghostfolio/common/helper';
|
} from '@ghostfolio/common/helper';
|
||||||
import { Granularity } from '@ghostfolio/common/types';
|
import { Granularity } from '@ghostfolio/common/types';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { DataSource } from '@prisma/client';
|
import { AssetClass, DataSource } from '@prisma/client';
|
||||||
import * as bent from 'bent';
|
import * as bent from 'bent';
|
||||||
import { format } from 'date-fns';
|
import { format } from 'date-fns';
|
||||||
import * as yahooFinance from 'yahoo-finance';
|
import * as yahooFinance from 'yahoo-finance';
|
||||||
@ -17,8 +17,7 @@ import { DataProviderInterface } from '../../interfaces/data-provider.interface'
|
|||||||
import {
|
import {
|
||||||
IDataProviderHistoricalResponse,
|
IDataProviderHistoricalResponse,
|
||||||
IDataProviderResponse,
|
IDataProviderResponse,
|
||||||
MarketState,
|
MarketState
|
||||||
Type
|
|
||||||
} from '../../interfaces/interfaces';
|
} from '../../interfaces/interfaces';
|
||||||
import {
|
import {
|
||||||
IYahooFinanceHistoricalResponse,
|
IYahooFinanceHistoricalResponse,
|
||||||
@ -61,6 +60,7 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
const symbol = convertFromYahooSymbol(yahooSymbol);
|
const symbol = convertFromYahooSymbol(yahooSymbol);
|
||||||
|
|
||||||
response[symbol] = {
|
response[symbol] = {
|
||||||
|
assetClass: this.parseAssetClass(value.price?.quoteType),
|
||||||
currency: parseCurrency(value.price?.currency),
|
currency: parseCurrency(value.price?.currency),
|
||||||
dataSource: DataSource.YAHOO,
|
dataSource: DataSource.YAHOO,
|
||||||
exchange: this.parseExchange(value.price?.exchangeName),
|
exchange: this.parseExchange(value.price?.exchangeName),
|
||||||
@ -69,8 +69,7 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
? MarketState.open
|
? MarketState.open
|
||||||
: MarketState.closed,
|
: MarketState.closed,
|
||||||
marketPrice: value.price?.regularMarketPrice || 0,
|
marketPrice: value.price?.regularMarketPrice || 0,
|
||||||
name: value.price?.longName || value.price?.shortName || symbol,
|
name: value.price?.longName || value.price?.shortName || symbol
|
||||||
type: this.parseType(this.getType(symbol, value))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const url = value.summaryProfile?.website;
|
const url = value.summaryProfile?.website;
|
||||||
@ -203,14 +202,20 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
return aSymbol;
|
return aSymbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getType(aSymbol: string, aValue: IYahooFinanceQuoteResponse): Type {
|
private parseAssetClass(aString: string): AssetClass {
|
||||||
if (isCrypto(aSymbol)) {
|
let assetClass: AssetClass;
|
||||||
return Type.Cryptocurrency;
|
|
||||||
} else if (aValue.price?.quoteType.toLowerCase() === 'equity') {
|
switch (aString?.toLowerCase()) {
|
||||||
return Type.Stock;
|
case 'cryptocurrency':
|
||||||
|
assetClass = AssetClass.CASH;
|
||||||
|
break;
|
||||||
|
case 'equity':
|
||||||
|
case 'etf':
|
||||||
|
assetClass = AssetClass.EQUITY;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return aValue.price?.quoteType.toLowerCase();
|
return assetClass;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseExchange(aString: string): string {
|
private parseExchange(aString: string): string {
|
||||||
@ -220,18 +225,6 @@ export class YahooFinanceService implements DataProviderInterface {
|
|||||||
|
|
||||||
return aString;
|
return aString;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseType(aString: string): Type {
|
|
||||||
if (aString?.toLowerCase() === 'cryptocurrency') {
|
|
||||||
return Type.Cryptocurrency;
|
|
||||||
} else if (aString?.toLowerCase() === 'etf') {
|
|
||||||
return Type.ETF;
|
|
||||||
} else if (aString?.toLowerCase() === 'stock') {
|
|
||||||
return Type.Stock;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Type.Unknown;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const convertFromYahooSymbol = (aSymbol: string) => {
|
export const convertFromYahooSymbol = (aSymbol: string) => {
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
import { UNKNOWN_KEY } from '@ghostfolio/common/config';
|
import {
|
||||||
import { Account, Currency, DataSource, SymbolProfile } from '@prisma/client';
|
Account,
|
||||||
|
AssetClass,
|
||||||
|
Currency,
|
||||||
|
DataSource,
|
||||||
|
SymbolProfile
|
||||||
|
} from '@prisma/client';
|
||||||
|
|
||||||
import { OrderType } from '../../models/order-type';
|
import { OrderType } from '../../models/order-type';
|
||||||
|
|
||||||
@ -9,14 +14,6 @@ export const MarketState = {
|
|||||||
open: 'open'
|
open: 'open'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Type = {
|
|
||||||
Cash: 'Cash',
|
|
||||||
Cryptocurrency: 'Cryptocurrency',
|
|
||||||
ETF: 'ETF',
|
|
||||||
Stock: 'Stock',
|
|
||||||
Unknown: UNKNOWN_KEY
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IOrder {
|
export interface IOrder {
|
||||||
account: Account;
|
account: Account;
|
||||||
currency: Currency;
|
currency: Currency;
|
||||||
@ -37,6 +34,7 @@ export interface IDataProviderHistoricalResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IDataProviderResponse {
|
export interface IDataProviderResponse {
|
||||||
|
assetClass?: AssetClass;
|
||||||
currency: Currency;
|
currency: Currency;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
exchange?: string;
|
exchange?: string;
|
||||||
@ -45,7 +43,6 @@ export interface IDataProviderResponse {
|
|||||||
marketPrice: number;
|
marketPrice: number;
|
||||||
marketState: MarketState;
|
marketState: MarketState;
|
||||||
name: string;
|
name: string;
|
||||||
type?: Type;
|
|
||||||
url?: string;
|
url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,5 +53,3 @@ export interface IDataGatheringItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type MarketState = typeof MarketState[keyof typeof MarketState];
|
export type MarketState = typeof MarketState[keyof typeof MarketState];
|
||||||
|
|
||||||
export type Type = typeof Type[keyof typeof Type];
|
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Country } from '@ghostfolio/common/interfaces/country.interface';
|
import { Country } from '@ghostfolio/common/interfaces/country.interface';
|
||||||
import { Sector } from '@ghostfolio/common/interfaces/sector.interface';
|
import { Sector } from '@ghostfolio/common/interfaces/sector.interface';
|
||||||
import { Currency, DataSource } from '@prisma/client';
|
import { AssetClass, Currency, DataSource } from '@prisma/client';
|
||||||
|
|
||||||
export interface EnhancedSymbolProfile {
|
export interface EnhancedSymbolProfile {
|
||||||
|
assetClass: AssetClass;
|
||||||
createdAt: Date;
|
createdAt: Date;
|
||||||
currency: Currency | null;
|
currency: Currency | null;
|
||||||
dataSource: DataSource;
|
dataSource: DataSource;
|
||||||
|
@ -10,4 +10,4 @@ import { PortfolioProportionChartComponent } from './portfolio-proportion-chart.
|
|||||||
imports: [CommonModule, NgxSkeletonLoaderModule],
|
imports: [CommonModule, NgxSkeletonLoaderModule],
|
||||||
providers: []
|
providers: []
|
||||||
})
|
})
|
||||||
export class PortfolioProportionChartModule {}
|
export class GfPortfolioProportionChartModule {}
|
||||||
|
@ -83,10 +83,10 @@
|
|||||||
*matRowDef="let row; columns: displayedColumns"
|
*matRowDef="let row; columns: displayedColumns"
|
||||||
mat-row
|
mat-row
|
||||||
[ngClass]="{
|
[ngClass]="{
|
||||||
'cursor-pointer': !this.ignoreTypes.includes(row.type)
|
'cursor-pointer': !this.ignoreAssetClasses.includes(row.assetClass)
|
||||||
}"
|
}"
|
||||||
(click)="
|
(click)="
|
||||||
!this.ignoreTypes.includes(row.type) &&
|
!this.ignoreAssetClasses.includes(row.assetClass) &&
|
||||||
onOpenPositionDialog({ symbol: row.symbol, title: row.name })
|
onOpenPositionDialog({ symbol: row.symbol, title: row.name })
|
||||||
"
|
"
|
||||||
></tr>
|
></tr>
|
||||||
|
@ -14,9 +14,8 @@ import { MatPaginator } from '@angular/material/paginator';
|
|||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Type } from '@ghostfolio/api/services/interfaces/interfaces';
|
|
||||||
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
import { PortfolioPosition } from '@ghostfolio/common/interfaces';
|
||||||
import { Order as OrderModel } from '@prisma/client';
|
import { AssetClass, Order as OrderModel } from '@prisma/client';
|
||||||
import { Subject, Subscription } from 'rxjs';
|
import { Subject, Subscription } from 'rxjs';
|
||||||
import { takeUntil } from 'rxjs/operators';
|
import { takeUntil } from 'rxjs/operators';
|
||||||
|
|
||||||
@ -43,7 +42,7 @@ export class PositionsTableComponent implements OnChanges, OnDestroy, OnInit {
|
|||||||
public dataSource: MatTableDataSource<PortfolioPosition> =
|
public dataSource: MatTableDataSource<PortfolioPosition> =
|
||||||
new MatTableDataSource();
|
new MatTableDataSource();
|
||||||
public displayedColumns = [];
|
public displayedColumns = [];
|
||||||
public ignoreTypes = [Type.Cash];
|
public ignoreAssetClasses = [AssetClass.CASH.toString()];
|
||||||
public isLoading = true;
|
public isLoading = true;
|
||||||
public pageSize = 7;
|
public pageSize = 7;
|
||||||
public routeQueryParams: Subscription;
|
public routeQueryParams: Subscription;
|
||||||
|
@ -5,11 +5,9 @@ import {
|
|||||||
OnChanges,
|
OnChanges,
|
||||||
OnInit
|
OnInit
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import {
|
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
MarketState,
|
|
||||||
Type
|
|
||||||
} from '@ghostfolio/api/services/interfaces/interfaces';
|
|
||||||
import { Position } from '@ghostfolio/common/interfaces';
|
import { Position } from '@ghostfolio/common/interfaces';
|
||||||
|
import { AssetClass } from '@prisma/client';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'gf-positions',
|
selector: 'gf-positions',
|
||||||
@ -28,7 +26,7 @@ export class PositionsComponent implements OnChanges, OnInit {
|
|||||||
public positionsRest: Position[] = [];
|
public positionsRest: Position[] = [];
|
||||||
public positionsWithPriority: Position[] = [];
|
public positionsWithPriority: Position[] = [];
|
||||||
|
|
||||||
private ignoreTypes = [Type.Cash];
|
private ignoreAssetClasses = [AssetClass.CASH.toString()];
|
||||||
|
|
||||||
public constructor() {}
|
public constructor() {}
|
||||||
|
|
||||||
@ -46,7 +44,7 @@ export class PositionsComponent implements OnChanges, OnInit {
|
|||||||
this.positionsWithPriority = [];
|
this.positionsWithPriority = [];
|
||||||
|
|
||||||
for (const portfolioPosition of this.positions) {
|
for (const portfolioPosition of this.positions) {
|
||||||
if (this.ignoreTypes.includes(portfolioPosition.type)) {
|
if (this.ignoreAssetClasses.includes(portfolioPosition.assetClass)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,9 +116,9 @@ export class AllocationsPageComponent implements OnDestroy, OnInit {
|
|||||||
|
|
||||||
for (const [symbol, position] of Object.entries(aPortfolioPositions)) {
|
for (const [symbol, position] of Object.entries(aPortfolioPositions)) {
|
||||||
this.positions[symbol] = {
|
this.positions[symbol] = {
|
||||||
|
assetClass: position.assetClass,
|
||||||
currency: position.currency,
|
currency: position.currency,
|
||||||
exchange: position.exchange,
|
exchange: position.exchange,
|
||||||
type: position.type,
|
|
||||||
value:
|
value:
|
||||||
aPeriod === 'original'
|
aPeriod === 'original'
|
||||||
? position.allocationInvestment
|
? position.allocationInvestment
|
||||||
|
@ -12,28 +12,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="proportion-charts row">
|
<div class="proportion-charts row">
|
||||||
<div class="col-md-6">
|
|
||||||
<mat-card class="mb-3">
|
|
||||||
<mat-card-header class="w-100">
|
|
||||||
<mat-card-title i18n>By Type</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="type"
|
|
||||||
[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">
|
<div class="col-md-6">
|
||||||
<mat-card class="mb-3">
|
<mat-card class="mb-3">
|
||||||
<mat-card-header class="w-100">
|
<mat-card-header class="w-100">
|
||||||
@ -59,7 +37,7 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<mat-card class="mb-3">
|
<mat-card class="mb-3">
|
||||||
<mat-card-header class="w-100">
|
<mat-card-header class="w-100">
|
||||||
<mat-card-title i18n>By Currency</mat-card-title>
|
<mat-card-title i18n>By Asset Class</mat-card-title>
|
||||||
<gf-toggle
|
<gf-toggle
|
||||||
[defaultValue]="period"
|
[defaultValue]="period"
|
||||||
[isLoading]="false"
|
[isLoading]="false"
|
||||||
@ -69,7 +47,7 @@
|
|||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<gf-portfolio-proportion-chart
|
<gf-portfolio-proportion-chart
|
||||||
key="currency"
|
key="assetClass"
|
||||||
[baseCurrency]="user?.settings?.baseCurrency"
|
[baseCurrency]="user?.settings?.baseCurrency"
|
||||||
[isInPercent]="true"
|
[isInPercent]="true"
|
||||||
[locale]="user?.settings?.locale"
|
[locale]="user?.settings?.locale"
|
||||||
@ -81,7 +59,7 @@
|
|||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<mat-card class="mb-3">
|
<mat-card class="mb-3">
|
||||||
<mat-card-header class="w-100">
|
<mat-card-header class="w-100">
|
||||||
<mat-card-title i18n>By Exchange</mat-card-title>
|
<mat-card-title i18n>By Currency</mat-card-title>
|
||||||
<gf-toggle
|
<gf-toggle
|
||||||
[defaultValue]="period"
|
[defaultValue]="period"
|
||||||
[isLoading]="false"
|
[isLoading]="false"
|
||||||
@ -91,7 +69,7 @@
|
|||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<gf-portfolio-proportion-chart
|
<gf-portfolio-proportion-chart
|
||||||
key="exchange"
|
key="currency"
|
||||||
[baseCurrency]="user?.settings?.baseCurrency"
|
[baseCurrency]="user?.settings?.baseCurrency"
|
||||||
[isInPercent]="true"
|
[isInPercent]="true"
|
||||||
[locale]="user?.settings?.locale"
|
[locale]="user?.settings?.locale"
|
||||||
|
@ -1,7 +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 { PortfolioProportionChartModule } from '@ghostfolio/client/components/portfolio-proportion-chart/portfolio-proportion-chart.module';
|
import { GfPortfolioProportionChartModule } from '@ghostfolio/client/components/portfolio-proportion-chart/portfolio-proportion-chart.module';
|
||||||
import { GfPositionsTableModule } from '@ghostfolio/client/components/positions-table/positions-table.module';
|
import { GfPositionsTableModule } from '@ghostfolio/client/components/positions-table/positions-table.module';
|
||||||
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';
|
||||||
@ -15,11 +15,11 @@ import { AllocationsPageComponent } from './allocations-page.component';
|
|||||||
imports: [
|
imports: [
|
||||||
AllocationsPageRoutingModule,
|
AllocationsPageRoutingModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
GfPortfolioProportionChartModule,
|
||||||
GfPositionsTableModule,
|
GfPositionsTableModule,
|
||||||
GfToggleModule,
|
GfToggleModule,
|
||||||
GfWorldMapChartModule,
|
GfWorldMapChartModule,
|
||||||
MatCardModule,
|
MatCardModule
|
||||||
PortfolioProportionChartModule
|
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
import { Currency } from '@prisma/client';
|
import { AssetClass, Currency } from '@prisma/client';
|
||||||
|
|
||||||
import { Country } from './country.interface';
|
import { Country } from './country.interface';
|
||||||
import { Sector } from './sector.interface';
|
import { Sector } from './sector.interface';
|
||||||
@ -10,6 +10,7 @@ export interface PortfolioPosition {
|
|||||||
};
|
};
|
||||||
allocationCurrent: number;
|
allocationCurrent: number;
|
||||||
allocationInvestment: number;
|
allocationInvestment: number;
|
||||||
|
assetClass?: AssetClass;
|
||||||
countries: Country[];
|
countries: Country[];
|
||||||
currency: Currency;
|
currency: Currency;
|
||||||
exchange?: string;
|
exchange?: string;
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import {
|
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||||
MarketState,
|
import { AssetClass, Currency } from '@prisma/client';
|
||||||
Type
|
|
||||||
} from '@ghostfolio/api/services/interfaces/interfaces';
|
|
||||||
import { Currency } from '@prisma/client';
|
|
||||||
|
|
||||||
export interface Position {
|
export interface Position {
|
||||||
|
assetClass: AssetClass;
|
||||||
averagePrice: number;
|
averagePrice: number;
|
||||||
currency: Currency;
|
currency: Currency;
|
||||||
firstBuyDate: string;
|
firstBuyDate: string;
|
||||||
@ -18,6 +16,5 @@ export interface Position {
|
|||||||
quantity: number;
|
quantity: number;
|
||||||
symbol: string;
|
symbol: string;
|
||||||
transactionCount: number;
|
transactionCount: number;
|
||||||
type?: Type;
|
|
||||||
url?: string;
|
url?: string;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "AssetClass" AS ENUM ('CASH', 'COMMODITY', 'EQUITY');
|
||||||
|
|
||||||
|
-- AlterTable
|
||||||
|
ALTER TABLE "SymbolProfile" ADD COLUMN "assetClass" "AssetClass";
|
@ -116,14 +116,15 @@ model Settings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model SymbolProfile {
|
model SymbolProfile {
|
||||||
|
assetClass AssetClass?
|
||||||
countries Json?
|
countries Json?
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
currency Currency?
|
currency Currency?
|
||||||
dataSource DataSource
|
dataSource DataSource
|
||||||
id String @id @default(uuid())
|
id String @id @default(uuid())
|
||||||
name String?
|
name String?
|
||||||
Order Order[]
|
Order Order[]
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
sectors Json?
|
sectors Json?
|
||||||
symbol String
|
symbol String
|
||||||
|
|
||||||
@ -166,6 +167,12 @@ enum AccountType {
|
|||||||
SECURITIES
|
SECURITIES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum AssetClass {
|
||||||
|
CASH
|
||||||
|
COMMODITY
|
||||||
|
EQUITY
|
||||||
|
}
|
||||||
|
|
||||||
enum Currency {
|
enum Currency {
|
||||||
CHF
|
CHF
|
||||||
EUR
|
EUR
|
||||||
|
Loading…
x
Reference in New Issue
Block a user