diff --git a/apps/api/src/app/portfolio/interfaces/portfolio-position.interface.ts b/apps/api/src/app/portfolio/interfaces/portfolio-position.interface.ts index 820a4b035..cd8e0499a 100644 --- a/apps/api/src/app/portfolio/interfaces/portfolio-position.interface.ts +++ b/apps/api/src/app/portfolio/interfaces/portfolio-position.interface.ts @@ -1,3 +1,4 @@ +import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces'; import { Currency } from '@prisma/client'; export interface PortfolioPosition { @@ -7,10 +8,10 @@ export interface PortfolioPosition { grossPerformancePercent: number; industry?: string; investment: number; - isMarketOpen: boolean; marketChange?: number; marketChangePercent?: number; marketPrice: number; + marketState: MarketState; name: string; platforms: { [name: string]: { current: number; original: number }; diff --git a/apps/api/src/models/portfolio.spec.ts b/apps/api/src/models/portfolio.spec.ts index 01d2b39e3..e2acefb5b 100644 --- a/apps/api/src/models/portfolio.spec.ts +++ b/apps/api/src/models/portfolio.spec.ts @@ -5,9 +5,11 @@ import { Currency, Role, Type } from '@prisma/client'; import { ConfigurationService } from '../services/configuration.service'; import { DataProviderService } from '../services/data-provider.service'; import { AlphaVantageService } from '../services/data-provider/alpha-vantage/alpha-vantage.service'; +import { GhostfolioScraperApiService } from '../services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service'; import { RakutenRapidApiService } from '../services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service'; import { YahooFinanceService } from '../services/data-provider/yahoo-finance/yahoo-finance.service'; import { ExchangeRateDataService } from '../services/exchange-rate-data.service'; +import { MarketState } from '../services/interfaces/interfaces'; import { PrismaService } from '../services/prisma.service'; import { RulesService } from '../services/rules.service'; import { Portfolio } from './portfolio'; @@ -17,6 +19,7 @@ describe('Portfolio', () => { let configurationService: ConfigurationService; let dataProviderService: DataProviderService; let exchangeRateDataService: ExchangeRateDataService; + let ghostfolioScraperApiService: GhostfolioScraperApiService; let portfolio: Portfolio; let prismaService: PrismaService; let rakutenRapidApiService: RakutenRapidApiService; @@ -31,6 +34,7 @@ describe('Portfolio', () => { ConfigurationService, DataProviderService, ExchangeRateDataService, + GhostfolioScraperApiService, PrismaService, RakutenRapidApiService, RulesService, @@ -44,6 +48,9 @@ describe('Portfolio', () => { exchangeRateDataService = app.get( ExchangeRateDataService ); + ghostfolioScraperApiService = app.get( + GhostfolioScraperApiService + ); prismaService = app.get(PrismaService); rakutenRapidApiService = app.get( RakutenRapidApiService @@ -154,8 +161,8 @@ describe('Portfolio', () => { Currency.USD, baseCurrency ), - isMarketOpen: true, // marketPrice: 57973.008, + marketState: MarketState.open, name: 'Bitcoin USD', platforms: { Other: { diff --git a/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts b/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts index 55c3db0cb..1b0d6ba47 100644 --- a/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts +++ b/apps/api/src/services/data-provider/ghostfolio-scraper-api/ghostfolio-scraper-api.service.ts @@ -8,7 +8,8 @@ import { DataProviderInterface } from '../../interfaces/data-provider.interface' import { Granularity } from '../../interfaces/granularity.type'; import { IDataProviderHistoricalResponse, - IDataProviderResponse + IDataProviderResponse, + MarketState } from '../../interfaces/interfaces'; import { PrismaService } from '../../prisma.service'; @@ -41,7 +42,7 @@ export class GhostfolioScraperApiService implements DataProviderInterface { [symbol]: { marketPrice, currency: scraperConfig?.currency, - isMarketOpen: false, + marketState: MarketState.delayed, name: scraperConfig?.name } }; diff --git a/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts b/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts index dda897ce8..bec82d881 100644 --- a/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts +++ b/apps/api/src/services/data-provider/rakuten-rapid-api/rakuten-rapid-api.service.ts @@ -8,7 +8,8 @@ import { DataProviderInterface } from '../../interfaces/data-provider.interface' import { Granularity } from '../../interfaces/granularity.type'; import { IDataProviderHistoricalResponse, - IDataProviderResponse + IDataProviderResponse, + MarketState } from '../../interfaces/interfaces'; import { PrismaService } from '../../prisma.service'; @@ -38,8 +39,8 @@ export class RakutenRapidApiService implements DataProviderInterface { return { 'GF.FEAR_AND_GREED_INDEX': { currency: undefined, - isMarketOpen: true, marketPrice: fgi.now.value, + marketState: MarketState.open, name: RakutenRapidApiService.FEAR_AND_GREED_INDEX_NAME } }; diff --git a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts index 0cb68dca0..ef15f99d4 100644 --- a/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts +++ b/apps/api/src/services/data-provider/yahoo-finance/yahoo-finance.service.ts @@ -9,6 +9,7 @@ import { IDataProviderHistoricalResponse, IDataProviderResponse, Industry, + MarketState, Sector, Type } from '../../interfaces/interfaces'; @@ -49,8 +50,10 @@ export class YahooFinanceService implements DataProviderInterface { response[symbol] = { currency: parseCurrency(value.price?.currency), exchange: this.parseExchange(value.price?.exchangeName), - isMarketOpen: - value.price?.marketState === 'REGULAR' || isCrypto(symbol), + marketState: + value.price?.marketState === 'REGULAR' || isCrypto(symbol) + ? MarketState.open + : MarketState.closed, marketPrice: value.price?.regularMarketPrice || 0, name: value.price?.longName || value.price?.shortName || symbol, type: this.parseType(this.getType(symbol, value)) diff --git a/apps/api/src/services/interfaces/interfaces.ts b/apps/api/src/services/interfaces/interfaces.ts index ba51e346d..8da86143b 100644 --- a/apps/api/src/services/interfaces/interfaces.ts +++ b/apps/api/src/services/interfaces/interfaces.ts @@ -12,6 +12,12 @@ export const Industry = { Software: 'Software' }; +export const MarketState = { + closed: 'closed', + delayed: 'delayed', + open: 'open' +}; + export const Sector = { Consumer: 'Consumer', Healthcare: 'Healthcare', @@ -47,10 +53,10 @@ export interface IDataProviderResponse { currency: Currency; exchange?: string; industry?: Industry; - isMarketOpen: boolean; marketChange?: number; marketChangePercent?: number; marketPrice: number; + marketState: MarketState; name: string; sector?: Sector; type?: Type; @@ -59,6 +65,8 @@ export interface IDataProviderResponse { export type Industry = typeof Industry[keyof typeof Industry]; +export type MarketState = typeof MarketState[keyof typeof MarketState]; + export type Sector = typeof Sector[keyof typeof Sector]; export type Type = typeof Type[keyof typeof Type]; diff --git a/apps/client/src/app/components/position/position.component.html b/apps/client/src/app/components/position/position.component.html index a366261f6..41124ce08 100644 --- a/apps/client/src/app/components/position/position.component.html +++ b/apps/client/src/app/components/position/position.component.html @@ -9,7 +9,7 @@ diff --git a/apps/client/src/app/components/positions/positions.component.ts b/apps/client/src/app/components/positions/positions.component.ts index 1dcc991d3..5f69736e0 100644 --- a/apps/client/src/app/components/positions/positions.component.ts +++ b/apps/client/src/app/components/positions/positions.component.ts @@ -6,6 +6,7 @@ import { OnInit } from '@angular/core'; import { PortfolioPosition } from '@ghostfolio/api/app/portfolio/interfaces/portfolio-position.interface'; +import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces'; @Component({ selector: 'gf-positions', @@ -40,7 +41,10 @@ export class PositionsComponent implements OnChanges, OnInit { this.positionsWithPriority = []; for (const [, portfolioPosition] of Object.entries(this.positions)) { - if (portfolioPosition.isMarketOpen || this.range !== '1d') { + if ( + portfolioPosition.marketState === MarketState.open || + this.range !== '1d' + ) { // Only show positions where the market is open in today's view this.positionsWithPriority.push(portfolioPosition); } else { diff --git a/apps/client/src/app/components/trend-indicator/trend-indicator.component.html b/apps/client/src/app/components/trend-indicator/trend-indicator.component.html index b20e61337..27251fc24 100644 --- a/apps/client/src/app/components/trend-indicator/trend-indicator.component.html +++ b/apps/client/src/app/components/trend-indicator/trend-indicator.component.html @@ -10,12 +10,21 @@ + + + +