Browse Source

Extend markets

pull/5076/head
Thomas Kaul 2 months ago
parent
commit
c5ace25acf
  1. 12
      apps/api/src/app/endpoints/market-data/market-data.controller.ts
  2. 30
      apps/client/src/app/components/markets/markets.component.ts
  3. 70
      apps/client/src/app/components/markets/markets.html
  4. 5
      apps/client/src/app/services/data.service.ts
  5. 6
      libs/common/src/lib/interfaces/responses/market-data-of-markets-response.interface.ts

12
apps/api/src/app/endpoints/market-data/market-data.controller.ts

@ -72,11 +72,13 @@ export class MarketDataController {
]); ]);
return { return {
CRYPTOCURRENCIES: { fearAndGreedIndex: {
...marketDataFearAndGreedIndexCryptocurrencies CRYPTOCURRENCIES: {
}, ...marketDataFearAndGreedIndexCryptocurrencies
STOCKS: { },
...marketDataFearAndGreedIndexStocks STOCKS: {
...marketDataFearAndGreedIndexStocks
}
} }
}; };
} }

30
apps/client/src/app/components/markets/markets.component.ts

@ -6,12 +6,10 @@ import { resetHours } from '@ghostfolio/common/helper';
import { import {
Benchmark, Benchmark,
HistoricalDataItem, HistoricalDataItem,
InfoItem,
MarketDataOfMarketsResponse, MarketDataOfMarketsResponse,
ToggleOption, ToggleOption,
User User
} from '@ghostfolio/common/interfaces'; } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { FearAndGreedIndexMode } from '@ghostfolio/common/types'; import { FearAndGreedIndexMode } from '@ghostfolio/common/types';
import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark'; import { GfBenchmarkComponent } from '@ghostfolio/ui/benchmark';
import { GfLineChartComponent } from '@ghostfolio/ui/line-chart'; import { GfLineChartComponent } from '@ghostfolio/ui/line-chart';
@ -47,17 +45,15 @@ export class MarketsComponent implements OnDestroy, OnInit {
public benchmarks: Benchmark[]; public benchmarks: Benchmark[];
public deviceType: string; public deviceType: string;
public fearAndGreedIndex: number; public fearAndGreedIndex: number;
public fearAndGreedIndexData: MarketDataOfMarketsResponse; public fearAndGreedIndexData: MarketDataOfMarketsResponse['fearAndGreedIndex'];
public fearLabel = $localize`Fear`; public fearLabel = $localize`Fear`;
public greedLabel = $localize`Greed`; public greedLabel = $localize`Greed`;
public hasPermissionToAccessFearAndGreedIndex: boolean;
public historicalDataItems: HistoricalDataItem[]; public historicalDataItems: HistoricalDataItem[];
public fearAndGreedIndexMode: FearAndGreedIndexMode = 'STOCKS'; public fearAndGreedIndexMode: FearAndGreedIndexMode = 'STOCKS';
public fearAndGreedIndexModeOptions: ToggleOption[] = [ public fearAndGreedIndexModeOptions: ToggleOption[] = [
{ label: $localize`Stocks`, value: 'STOCKS' }, { label: $localize`Stocks`, value: 'STOCKS' },
{ label: $localize`Cryptocurrencies`, value: 'CRYPTOCURRENCIES' } { label: $localize`Cryptocurrencies`, value: 'CRYPTOCURRENCIES' }
]; ];
public info: InfoItem;
public readonly numberOfDays = 365; public readonly numberOfDays = 365;
public user: User; public user: User;
@ -70,7 +66,6 @@ export class MarketsComponent implements OnDestroy, OnInit {
private userService: UserService private userService: UserService
) { ) {
this.deviceType = this.deviceService.getDeviceInfo().deviceType; this.deviceType = this.deviceService.getDeviceInfo().deviceType;
this.info = this.dataService.fetchInfo();
this.userService.stateChanged this.userService.stateChanged
.pipe(takeUntil(this.unsubscribeSubject)) .pipe(takeUntil(this.unsubscribeSubject))
@ -84,23 +79,16 @@ export class MarketsComponent implements OnDestroy, OnInit {
} }
public ngOnInit() { public ngOnInit() {
this.hasPermissionToAccessFearAndGreedIndex = hasPermission( this.dataService
this.info?.globalPermissions, .fetchMarketDataOfMarkets({ includeHistoricalData: this.numberOfDays })
permissions.enableFearAndGreedIndex .pipe(takeUntil(this.unsubscribeSubject))
); .subscribe(({ fearAndGreedIndex }) => {
this.fearAndGreedIndexData = fearAndGreedIndex;
if (this.hasPermissionToAccessFearAndGreedIndex) {
this.dataService
.fetchMarketDataOfMarkets({ includeHistoricalData: this.numberOfDays })
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe((fearAndGreedIndexData) => {
this.fearAndGreedIndexData = fearAndGreedIndexData;
this.initialize(); this.initialize();
this.changeDetectorRef.markForCheck(); this.changeDetectorRef.markForCheck();
}); });
}
this.dataService this.dataService
.fetchBenchmarks() .fetchBenchmarks()

70
apps/client/src/app/components/markets/markets.html

@ -1,45 +1,41 @@
<div class="container"> <div class="container">
<h1 class="d-none d-sm-block h3 mb-4 text-center" i18n>Markets</h1> <h1 class="d-none d-sm-block h3 mb-4 text-center" i18n>Markets</h1>
@if (hasPermissionToAccessFearAndGreedIndex) { <div class="mb-5 row">
<div class="mb-5 row"> <div class="col-xs-12 col-md-10 offset-md-1">
<div class="col-xs-12 col-md-10 offset-md-1"> <div class="d-flex">
<div class="d-flex"> <div class="align-items-center d-flex flex-grow-1 justify-content-end">
<div <gf-toggle
class="align-items-center d-flex flex-grow-1 justify-content-end" class="d-none d-lg-block"
> [defaultValue]="fearAndGreedIndexMode"
<gf-toggle [isLoading]="false"
class="d-none d-lg-block" [options]="fearAndGreedIndexModeOptions"
[defaultValue]="fearAndGreedIndexMode" (change)="onChangeFearAndGreedIndexMode($event.value)"
[isLoading]="false" />
[options]="fearAndGreedIndexModeOptions"
(change)="onChangeFearAndGreedIndexMode($event.value)"
/>
</div>
</div>
<div class="mb-2 text-center text-muted">
<small i18n>Last {{ numberOfDays }} Days</small>
</div> </div>
<gf-line-chart
class="mb-3"
symbol="Fear & Greed Index"
[colorScheme]="user?.settings?.colorScheme"
[historicalDataItems]="historicalDataItems"
[isAnimated]="true"
[locale]="user?.settings?.locale || undefined"
[showXAxis]="true"
[showYAxis]="true"
[yMax]="100"
[yMaxLabel]="greedLabel"
[yMin]="0"
[yMinLabel]="fearLabel"
/>
<gf-fear-and-greed-index
class="d-flex justify-content-center"
[fearAndGreedIndex]="fearAndGreedIndex"
/>
</div> </div>
<div class="mb-2 text-center text-muted">
<small i18n>Last {{ numberOfDays }} Days</small>
</div>
<gf-line-chart
class="mb-3"
symbol="Fear & Greed Index"
[colorScheme]="user?.settings?.colorScheme"
[historicalDataItems]="historicalDataItems"
[isAnimated]="true"
[locale]="user?.settings?.locale || undefined"
[showXAxis]="true"
[showYAxis]="true"
[yMax]="100"
[yMaxLabel]="greedLabel"
[yMin]="0"
[yMinLabel]="fearLabel"
/>
<gf-fear-and-greed-index
class="d-flex justify-content-center"
[fearAndGreedIndex]="fearAndGreedIndex"
/>
</div> </div>
} </div>
<div class="mb-3 row"> <div class="mb-3 row">
<div class="col-xs-12 col-md-10 offset-md-1"> <div class="col-xs-12 col-md-10 offset-md-1">

5
apps/client/src/app/services/data.service.ts

@ -497,11 +497,12 @@ export class DataService {
return this.http.get<any>('/api/v1/market-data/markets', { params }).pipe( return this.http.get<any>('/api/v1/market-data/markets', { params }).pipe(
map((data) => { map((data) => {
for (const item of data.CRYPTOCURRENCIES.historicalData) { for (const item of data.fearAndGreedIndex.CRYPTOCURRENCIES
.historicalData) {
item.date = parseISO(item.date); item.date = parseISO(item.date);
} }
for (const item of data.STOCKS.historicalData) { for (const item of data.fearAndGreedIndex.STOCKS.historicalData) {
item.date = parseISO(item.date); item.date = parseISO(item.date);
} }

6
libs/common/src/lib/interfaces/responses/market-data-of-markets-response.interface.ts

@ -1,6 +1,8 @@
import { SymbolItem } from '@ghostfolio/api/app/symbol/interfaces/symbol-item.interface'; import { SymbolItem } from '@ghostfolio/api/app/symbol/interfaces/symbol-item.interface';
export interface MarketDataOfMarketsResponse { export interface MarketDataOfMarketsResponse {
CRYPTOCURRENCIES: SymbolItem; fearAndGreedIndex: {
STOCKS: SymbolItem; CRYPTOCURRENCIES: SymbolItem;
STOCKS: SymbolItem;
};
} }

Loading…
Cancel
Save