parent
cf582b2e98
commit
5cb69291f5
@ -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 };
|
||||
|
@ -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>(
|
||||
ExchangeRateDataService
|
||||
);
|
||||
ghostfolioScraperApiService = app.get<GhostfolioScraperApiService>(
|
||||
GhostfolioScraperApiService
|
||||
);
|
||||
prismaService = app.get<PrismaService>(PrismaService);
|
||||
rakutenRapidApiService = app.get<RakutenRapidApiService>(
|
||||
RakutenRapidApiService
|
||||
@ -154,8 +161,8 @@ describe('Portfolio', () => {
|
||||
Currency.USD,
|
||||
baseCurrency
|
||||
),
|
||||
isMarketOpen: true,
|
||||
// marketPrice: 57973.008,
|
||||
marketState: MarketState.open,
|
||||
name: 'Bitcoin USD',
|
||||
platforms: {
|
||||
Other: {
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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))
|
||||
|
@ -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];
|
||||
|
@ -9,7 +9,7 @@
|
||||
<gf-trend-indicator
|
||||
class="d-flex"
|
||||
[isLoading]="isLoading"
|
||||
[isPaused]="!position?.isMarketOpen"
|
||||
[marketState]="position?.marketState"
|
||||
[range]="range"
|
||||
[value]="position?.grossPerformancePercent"
|
||||
></gf-trend-indicator>
|
||||
|
@ -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 {
|
||||
|
@ -10,12 +10,21 @@
|
||||
|
||||
<ng-template #other>
|
||||
<ion-icon
|
||||
*ngIf="isPaused && range === '1d'; else trend"
|
||||
*ngIf="marketState === 'closed' && range === '1d'; else delayed"
|
||||
class="text-muted"
|
||||
name="pause-circle-outline"
|
||||
size="large"
|
||||
>
|
||||
</ion-icon>
|
||||
<ng-template #delayed>
|
||||
<ion-icon
|
||||
*ngIf="marketState === 'delayed' && range === '1d'; else trend"
|
||||
class="text-muted"
|
||||
name="time-outline"
|
||||
size="large"
|
||||
>
|
||||
</ion-icon>
|
||||
</ng-template>
|
||||
<ng-template #trend>
|
||||
<ng-container>
|
||||
<ion-icon
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
Input,
|
||||
OnInit
|
||||
} from '@angular/core';
|
||||
import { MarketState } from '@ghostfolio/api/services/interfaces/interfaces';
|
||||
|
||||
@Component({
|
||||
selector: 'gf-trend-indicator',
|
||||
@ -13,7 +14,7 @@ import {
|
||||
})
|
||||
export class TrendIndicatorComponent implements OnInit {
|
||||
@Input() isLoading: boolean;
|
||||
@Input() isPaused: boolean;
|
||||
@Input() marketState: MarketState;
|
||||
@Input() range: string;
|
||||
@Input() value: number;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user