Feature/refactor get range in market data service (#2631)
* Refactor to unique asset in getRange() * Update changelog
This commit is contained in:
parent
f567e25f27
commit
93b6011ddc
@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Optimized the style of the carousel component on mobile for the testimonial section on the landing page
|
||||
- Introduced action menus in the overview of the admin control panel
|
||||
- Harmonized the name column in the historical market data table of the admin control panel
|
||||
- Refactored the implementation of the data range functionality (`getRange()`) in the market data service
|
||||
|
||||
## 2.21.0 - 2023-11-09
|
||||
|
||||
|
@ -61,6 +61,7 @@ export const CurrentRateServiceMock = {
|
||||
for (const dataGatheringItem of dataGatheringItems) {
|
||||
values.push({
|
||||
date,
|
||||
dataSource: dataGatheringItem.dataSource,
|
||||
marketPriceInBaseCurrency: mockGetValue(
|
||||
dataGatheringItem.symbol,
|
||||
date
|
||||
@ -74,6 +75,7 @@ export const CurrentRateServiceMock = {
|
||||
for (const dataGatheringItem of dataGatheringItems) {
|
||||
values.push({
|
||||
date,
|
||||
dataSource: dataGatheringItem.dataSource,
|
||||
marketPriceInBaseCurrency: mockGetValue(
|
||||
dataGatheringItem.symbol,
|
||||
date
|
||||
|
@ -2,6 +2,7 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
|
||||
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
|
||||
import { PropertyService } from '@ghostfolio/api/services/property/property.service';
|
||||
import { UniqueAsset } from '@ghostfolio/common/interfaces';
|
||||
import { DataSource, MarketData } from '@prisma/client';
|
||||
|
||||
import { CurrentRateService } from './current-rate.service';
|
||||
@ -25,30 +26,30 @@ jest.mock('@ghostfolio/api/services/market-data/market-data.service', () => {
|
||||
getRange: ({
|
||||
dateRangeEnd,
|
||||
dateRangeStart,
|
||||
symbols
|
||||
uniqueAssets
|
||||
}: {
|
||||
dateRangeEnd: Date;
|
||||
dateRangeStart: Date;
|
||||
symbols: string[];
|
||||
uniqueAssets: UniqueAsset[];
|
||||
}) => {
|
||||
return Promise.resolve<MarketData[]>([
|
||||
{
|
||||
createdAt: dateRangeStart,
|
||||
dataSource: DataSource.YAHOO,
|
||||
dataSource: uniqueAssets[0].dataSource,
|
||||
date: dateRangeStart,
|
||||
id: '8fa48fde-f397-4b0d-adbc-fb940e830e6d',
|
||||
marketPrice: 1841.823902,
|
||||
state: 'CLOSE',
|
||||
symbol: symbols[0]
|
||||
symbol: uniqueAssets[0].symbol
|
||||
},
|
||||
{
|
||||
createdAt: dateRangeEnd,
|
||||
dataSource: DataSource.YAHOO,
|
||||
dataSource: uniqueAssets[0].dataSource,
|
||||
date: dateRangeEnd,
|
||||
id: '082d6893-df27-4c91-8a5d-092e84315b56',
|
||||
marketPrice: 1847.839966,
|
||||
state: 'CLOSE',
|
||||
symbol: symbols[0]
|
||||
symbol: uniqueAssets[0].symbol
|
||||
}
|
||||
]);
|
||||
}
|
||||
@ -134,6 +135,7 @@ describe('CurrentRateService', () => {
|
||||
errors: [],
|
||||
values: [
|
||||
{
|
||||
dataSource: 'YAHOO',
|
||||
date: undefined,
|
||||
marketPriceInBaseCurrency: 1841.823902,
|
||||
symbol: 'AMZN'
|
||||
|
@ -2,7 +2,11 @@ import { DataProviderService } from '@ghostfolio/api/services/data-provider/data
|
||||
import { ExchangeRateDataService } from '@ghostfolio/api/services/exchange-rate-data/exchange-rate-data.service';
|
||||
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service';
|
||||
import { resetHours } from '@ghostfolio/common/helper';
|
||||
import { DataProviderInfo, ResponseError } from '@ghostfolio/common/interfaces';
|
||||
import {
|
||||
DataProviderInfo,
|
||||
ResponseError,
|
||||
UniqueAsset
|
||||
} from '@ghostfolio/common/interfaces';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { isBefore, isToday } from 'date-fns';
|
||||
import { flatten, isEmpty, uniqBy } from 'lodash';
|
||||
@ -52,6 +56,7 @@ export class CurrentRateService {
|
||||
|
||||
if (dataResultProvider?.[dataGatheringItem.symbol]?.marketPrice) {
|
||||
result.push({
|
||||
dataSource: dataGatheringItem.dataSource,
|
||||
date: today,
|
||||
marketPriceInBaseCurrency:
|
||||
this.exchangeRateDataService.toCurrency(
|
||||
@ -75,27 +80,30 @@ export class CurrentRateService {
|
||||
);
|
||||
}
|
||||
|
||||
const symbols = dataGatheringItems.map((dataGatheringItem) => {
|
||||
return dataGatheringItem.symbol;
|
||||
});
|
||||
const uniqueAssets: UniqueAsset[] = dataGatheringItems.map(
|
||||
({ dataSource, symbol }) => {
|
||||
return { dataSource, symbol };
|
||||
}
|
||||
);
|
||||
|
||||
promises.push(
|
||||
this.marketDataService
|
||||
.getRange({
|
||||
dateQuery,
|
||||
symbols
|
||||
uniqueAssets
|
||||
})
|
||||
.then((data) => {
|
||||
return data.map((marketDataItem) => {
|
||||
return data.map(({ dataSource, date, marketPrice, symbol }) => {
|
||||
return {
|
||||
date: marketDataItem.date,
|
||||
dataSource,
|
||||
date,
|
||||
symbol,
|
||||
marketPriceInBaseCurrency:
|
||||
this.exchangeRateDataService.toCurrency(
|
||||
marketDataItem.marketPrice,
|
||||
currencies[marketDataItem.symbol],
|
||||
marketPrice,
|
||||
currencies[symbol],
|
||||
userCurrency
|
||||
),
|
||||
symbol: marketDataItem.symbol
|
||||
)
|
||||
};
|
||||
});
|
||||
})
|
||||
@ -112,7 +120,7 @@ export class CurrentRateService {
|
||||
};
|
||||
|
||||
if (!isEmpty(quoteErrors)) {
|
||||
for (const { symbol } of quoteErrors) {
|
||||
for (const { dataSource, symbol } of quoteErrors) {
|
||||
try {
|
||||
// If missing quote, fallback to the latest available historical market price
|
||||
let value: GetValueObject = response.values.find((currentValue) => {
|
||||
@ -121,6 +129,7 @@ export class CurrentRateService {
|
||||
|
||||
if (!value) {
|
||||
value = {
|
||||
dataSource,
|
||||
symbol,
|
||||
date: today,
|
||||
marketPriceInBaseCurrency: 0
|
||||
|
@ -1,5 +1,6 @@
|
||||
export interface GetValueObject {
|
||||
import { UniqueAsset } from '@ghostfolio/common/interfaces';
|
||||
|
||||
export interface GetValueObject extends UniqueAsset {
|
||||
date: Date;
|
||||
marketPriceInBaseCurrency: number;
|
||||
symbol: string;
|
||||
}
|
||||
|
@ -40,7 +40,12 @@ export class SymbolService {
|
||||
|
||||
const marketData = await this.marketDataService.getRange({
|
||||
dateQuery: { gte: subDays(new Date(), days) },
|
||||
symbols: [dataGatheringItem.symbol]
|
||||
uniqueAssets: [
|
||||
{
|
||||
dataSource: dataGatheringItem.dataSource,
|
||||
symbol: dataGatheringItem.symbol
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
historicalData = marketData.map(({ date, marketPrice: value }) => {
|
||||
|
@ -59,10 +59,10 @@ export class MarketDataService {
|
||||
|
||||
public async getRange({
|
||||
dateQuery,
|
||||
symbols
|
||||
uniqueAssets
|
||||
}: {
|
||||
dateQuery: DateQuery;
|
||||
symbols: string[];
|
||||
uniqueAssets: UniqueAsset[];
|
||||
}): Promise<MarketData[]> {
|
||||
return await this.prismaService.marketData.findMany({
|
||||
orderBy: [
|
||||
@ -74,10 +74,17 @@ export class MarketDataService {
|
||||
}
|
||||
],
|
||||
where: {
|
||||
date: dateQuery,
|
||||
symbol: {
|
||||
in: symbols
|
||||
OR: uniqueAssets.map(({ dataSource, symbol }) => {
|
||||
return {
|
||||
AND: [
|
||||
{
|
||||
dataSource,
|
||||
symbol,
|
||||
date: dateQuery
|
||||
}
|
||||
]
|
||||
};
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user