|
|
@ -1,14 +1,11 @@ |
|
|
|
import { OrderService } from '@ghostfolio/api/app/order/order.service'; |
|
|
|
import { DateQueryHelper } from '@ghostfolio/api/helper/dateQueryHelper'; |
|
|
|
import { DataProviderService } from '@ghostfolio/api/services/data-provider/data-provider.service'; |
|
|
|
import { IDataGatheringItem } from '@ghostfolio/api/services/interfaces/interfaces'; |
|
|
|
import { MarketDataService } from '@ghostfolio/api/services/market-data/market-data.service'; |
|
|
|
import { resetHours } from '@ghostfolio/common/helper'; |
|
|
|
import { |
|
|
|
AssetProfileIdentifier, |
|
|
|
DataProviderInfo, |
|
|
|
ResponseError, |
|
|
|
UniqueAsset |
|
|
|
ResponseError |
|
|
|
} from '@ghostfolio/common/interfaces'; |
|
|
|
import type { RequestWithUser } from '@ghostfolio/common/types'; |
|
|
|
|
|
|
@ -23,8 +20,6 @@ import { GetValuesParams } from './interfaces/get-values-params.interface'; |
|
|
|
|
|
|
|
@Injectable() |
|
|
|
export class CurrentRateService { |
|
|
|
private dateQueryHelper = new DateQueryHelper(); |
|
|
|
|
|
|
|
public constructor( |
|
|
|
private readonly dataProviderService: DataProviderService, |
|
|
|
private readonly marketDataService: MarketDataService, |
|
|
@ -43,33 +38,58 @@ export class CurrentRateService { |
|
|
|
(!dateQuery.lt || isBefore(new Date(), dateQuery.lt)) && |
|
|
|
(!dateQuery.gte || isBefore(dateQuery.gte, new Date())) && |
|
|
|
(!dateQuery.in || this.containsToday(dateQuery.in)); |
|
|
|
let { query, dates } = this.dateQueryHelper.handleDateQueryIn(dateQuery); |
|
|
|
|
|
|
|
const promises: Promise<GetValueObject[]>[] = []; |
|
|
|
const quoteErrors: ResponseError['errors'] = []; |
|
|
|
const today = resetHours(new Date()); |
|
|
|
|
|
|
|
if (includesToday) { |
|
|
|
promises.push( |
|
|
|
this.getTodayPrivate( |
|
|
|
dataGatheringItems, |
|
|
|
dataProviderInfos, |
|
|
|
today, |
|
|
|
quoteErrors |
|
|
|
) |
|
|
|
this.dataProviderService |
|
|
|
.getQuotes({ items: dataGatheringItems, user: this.request?.user }) |
|
|
|
.then((dataResultProvider) => { |
|
|
|
const result: GetValueObject[] = []; |
|
|
|
|
|
|
|
for (const dataGatheringItem of dataGatheringItems) { |
|
|
|
if ( |
|
|
|
dataResultProvider?.[dataGatheringItem.symbol]?.dataProviderInfo |
|
|
|
) { |
|
|
|
dataProviderInfos.push( |
|
|
|
dataResultProvider[dataGatheringItem.symbol].dataProviderInfo |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
const uniqueAssets: UniqueAsset[] = dataGatheringItems.map( |
|
|
|
({ dataSource, symbol }) => { |
|
|
|
return { dataSource, symbol }; |
|
|
|
if (dataResultProvider?.[dataGatheringItem.symbol]?.marketPrice) { |
|
|
|
result.push({ |
|
|
|
dataSource: dataGatheringItem.dataSource, |
|
|
|
date: today, |
|
|
|
marketPrice: |
|
|
|
dataResultProvider?.[dataGatheringItem.symbol]?.marketPrice, |
|
|
|
symbol: dataGatheringItem.symbol |
|
|
|
}); |
|
|
|
} else { |
|
|
|
quoteErrors.push({ |
|
|
|
dataSource: dataGatheringItem.dataSource, |
|
|
|
symbol: dataGatheringItem.symbol |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
}) |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
const assetProfileIdentifiers: AssetProfileIdentifier[] = |
|
|
|
dataGatheringItems.map(({ dataSource, symbol }) => { |
|
|
|
return { dataSource, symbol }; |
|
|
|
}); |
|
|
|
|
|
|
|
promises.push( |
|
|
|
this.marketDataService |
|
|
|
.getRange({ |
|
|
|
dateQuery: query, |
|
|
|
uniqueAssets |
|
|
|
assetProfileIdentifiers, |
|
|
|
dateQuery |
|
|
|
}) |
|
|
|
.then((data) => { |
|
|
|
return data.map(({ dataSource, date, marketPrice, symbol }) => { |
|
|
@ -90,12 +110,9 @@ export class CurrentRateService { |
|
|
|
errors: quoteErrors.map(({ dataSource, symbol }) => { |
|
|
|
return { dataSource, symbol }; |
|
|
|
}), |
|
|
|
values: uniqBy(values, ({ date, symbol }) => `${date}-${symbol}`).filter( |
|
|
|
(v) => |
|
|
|
dates?.length === 0 || |
|
|
|
dates.some((d: Date) => d.getTime() === v.date.getTime()) |
|
|
|
) |
|
|
|
values: uniqBy(values, ({ date, symbol }) => `${date}-${symbol}`) |
|
|
|
}; |
|
|
|
|
|
|
|
if (!isEmpty(quoteErrors)) { |
|
|
|
for (const { dataSource, symbol } of quoteErrors) { |
|
|
|
try { |
|
|
@ -145,61 +162,6 @@ export class CurrentRateService { |
|
|
|
return response; |
|
|
|
} |
|
|
|
|
|
|
|
public async getToday( |
|
|
|
dataGatheringItems: IDataGatheringItem[] |
|
|
|
): Promise<GetValueObject[]> { |
|
|
|
const dataProviderInfos: DataProviderInfo[] = []; |
|
|
|
const quoteErrors: UniqueAsset[] = []; |
|
|
|
const today = resetHours(new Date()); |
|
|
|
|
|
|
|
return this.getTodayPrivate( |
|
|
|
dataGatheringItems, |
|
|
|
dataProviderInfos, |
|
|
|
today, |
|
|
|
quoteErrors |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
private async getTodayPrivate( |
|
|
|
dataGatheringItems: IDataGatheringItem[], |
|
|
|
dataProviderInfos: DataProviderInfo[], |
|
|
|
today: Date, |
|
|
|
quoteErrors: UniqueAsset[] |
|
|
|
): Promise<GetValueObject[]> { |
|
|
|
return this.dataProviderService |
|
|
|
.getQuotes({ items: dataGatheringItems, user: this.request?.user }) |
|
|
|
.then((dataResultProvider) => { |
|
|
|
const result: GetValueObject[] = []; |
|
|
|
|
|
|
|
for (const dataGatheringItem of dataGatheringItems) { |
|
|
|
if ( |
|
|
|
dataResultProvider?.[dataGatheringItem.symbol]?.dataProviderInfo |
|
|
|
) { |
|
|
|
dataProviderInfos.push( |
|
|
|
dataResultProvider[dataGatheringItem.symbol].dataProviderInfo |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
if (dataResultProvider?.[dataGatheringItem.symbol]?.marketPrice) { |
|
|
|
result.push({ |
|
|
|
dataSource: dataGatheringItem.dataSource, |
|
|
|
date: today, |
|
|
|
marketPrice: |
|
|
|
dataResultProvider?.[dataGatheringItem.symbol]?.marketPrice, |
|
|
|
symbol: dataGatheringItem.symbol |
|
|
|
}); |
|
|
|
} else { |
|
|
|
quoteErrors.push({ |
|
|
|
dataSource: dataGatheringItem.dataSource, |
|
|
|
symbol: dataGatheringItem.symbol |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private containsToday(dates: Date[]): boolean { |
|
|
|
for (const date of dates) { |
|
|
|
if (isToday(date)) { |
|
|
|