|
|
|
@ -11,6 +11,7 @@ import { Inject, Injectable, Logger } from '@nestjs/common';
|
|
|
|
|
import { DataSource } from '@prisma/client';
|
|
|
|
|
import { JobOptions, Queue } from 'bull';
|
|
|
|
|
import { format, min, subDays, subYears } from 'date-fns';
|
|
|
|
|
import { isEmpty } from 'lodash';
|
|
|
|
|
|
|
|
|
|
import { DataProviderService } from './data-provider/data-provider.service';
|
|
|
|
|
import { DataEnhancerInterface } from './data-provider/interfaces/data-enhancer.interface';
|
|
|
|
@ -33,7 +34,15 @@ export class DataGatheringService {
|
|
|
|
|
private readonly symbolProfileService: SymbolProfileService
|
|
|
|
|
) {}
|
|
|
|
|
|
|
|
|
|
public async addJobToQueue(name: string, data: any, opts?: JobOptions) {
|
|
|
|
|
public async addJobToQueue({
|
|
|
|
|
data,
|
|
|
|
|
name,
|
|
|
|
|
opts
|
|
|
|
|
}: {
|
|
|
|
|
data: any;
|
|
|
|
|
name: string;
|
|
|
|
|
opts?: JobOptions;
|
|
|
|
|
}) {
|
|
|
|
|
return this.dataGatheringQueue.add(name, data, opts);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -223,48 +232,6 @@ export class DataGatheringService {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getSymbolsMax(): Promise<IDataGatheringItem[]> {
|
|
|
|
|
const startDate =
|
|
|
|
|
(
|
|
|
|
|
await this.prismaService.order.findFirst({
|
|
|
|
|
orderBy: [{ date: 'asc' }]
|
|
|
|
|
})
|
|
|
|
|
)?.date ?? new Date();
|
|
|
|
|
|
|
|
|
|
const currencyPairsToGather = this.exchangeRateDataService
|
|
|
|
|
.getCurrencyPairs()
|
|
|
|
|
.map(({ dataSource, symbol }) => {
|
|
|
|
|
return {
|
|
|
|
|
dataSource,
|
|
|
|
|
symbol,
|
|
|
|
|
date: min([startDate, subYears(new Date(), 10)])
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const symbolProfilesToGather = (
|
|
|
|
|
await this.prismaService.symbolProfile.findMany({
|
|
|
|
|
orderBy: [{ symbol: 'asc' }],
|
|
|
|
|
select: {
|
|
|
|
|
dataSource: true,
|
|
|
|
|
Order: {
|
|
|
|
|
orderBy: [{ date: 'asc' }],
|
|
|
|
|
select: { date: true },
|
|
|
|
|
take: 1
|
|
|
|
|
},
|
|
|
|
|
scraperConfiguration: true,
|
|
|
|
|
symbol: true
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
).map((symbolProfile) => {
|
|
|
|
|
return {
|
|
|
|
|
...symbolProfile,
|
|
|
|
|
date: symbolProfile.Order?.[0]?.date ?? startDate
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return [...currencyPairsToGather, ...symbolProfilesToGather];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getUniqueAssets(): Promise<UniqueAsset[]> {
|
|
|
|
|
const symbolProfiles = await this.prismaService.symbolProfile.findMany({
|
|
|
|
|
orderBy: [{ symbol: 'asc' }]
|
|
|
|
@ -299,7 +266,7 @@ export class DataGatheringService {
|
|
|
|
|
|
|
|
|
|
// Only consider symbols with incomplete market data for the last
|
|
|
|
|
// 7 days
|
|
|
|
|
const symbolsNotToGather = (
|
|
|
|
|
const symbolsWithCompleteMarketData = (
|
|
|
|
|
await this.prismaService.marketData.groupBy({
|
|
|
|
|
_count: true,
|
|
|
|
|
by: ['symbol'],
|
|
|
|
@ -317,8 +284,14 @@ export class DataGatheringService {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const symbolProfilesToGather = symbolProfiles
|
|
|
|
|
.filter(({ symbol }) => {
|
|
|
|
|
return !symbolsNotToGather.includes(symbol);
|
|
|
|
|
.filter(({ dataSource, scraperConfiguration, symbol }) => {
|
|
|
|
|
const manualDataSourceWithScraperConfiguration =
|
|
|
|
|
dataSource === 'MANUAL' && !isEmpty(scraperConfiguration);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
!symbolsWithCompleteMarketData.includes(symbol) &&
|
|
|
|
|
(dataSource !== 'MANUAL' || manualDataSourceWithScraperConfiguration)
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
.map((symbolProfile) => {
|
|
|
|
|
return {
|
|
|
|
@ -330,7 +303,7 @@ export class DataGatheringService {
|
|
|
|
|
const currencyPairsToGather = this.exchangeRateDataService
|
|
|
|
|
.getCurrencyPairs()
|
|
|
|
|
.filter(({ symbol }) => {
|
|
|
|
|
return !symbolsNotToGather.includes(symbol);
|
|
|
|
|
return !symbolsWithCompleteMarketData.includes(symbol);
|
|
|
|
|
})
|
|
|
|
|
.map(({ dataSource, symbol }) => {
|
|
|
|
|
return {
|
|
|
|
@ -342,4 +315,57 @@ export class DataGatheringService {
|
|
|
|
|
|
|
|
|
|
return [...currencyPairsToGather, ...symbolProfilesToGather];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async getSymbolsMax(): Promise<IDataGatheringItem[]> {
|
|
|
|
|
const startDate =
|
|
|
|
|
(
|
|
|
|
|
await this.prismaService.order.findFirst({
|
|
|
|
|
orderBy: [{ date: 'asc' }]
|
|
|
|
|
})
|
|
|
|
|
)?.date ?? new Date();
|
|
|
|
|
|
|
|
|
|
const currencyPairsToGather = this.exchangeRateDataService
|
|
|
|
|
.getCurrencyPairs()
|
|
|
|
|
.map(({ dataSource, symbol }) => {
|
|
|
|
|
return {
|
|
|
|
|
dataSource,
|
|
|
|
|
symbol,
|
|
|
|
|
date: min([startDate, subYears(new Date(), 10)])
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const symbolProfilesToGather = (
|
|
|
|
|
await this.prismaService.symbolProfile.findMany({
|
|
|
|
|
orderBy: [{ symbol: 'asc' }],
|
|
|
|
|
select: {
|
|
|
|
|
dataSource: true,
|
|
|
|
|
Order: {
|
|
|
|
|
orderBy: [{ date: 'asc' }],
|
|
|
|
|
select: { date: true },
|
|
|
|
|
take: 1
|
|
|
|
|
},
|
|
|
|
|
scraperConfiguration: true,
|
|
|
|
|
symbol: true
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
)
|
|
|
|
|
.filter((symbolProfile) => {
|
|
|
|
|
const manualDataSourceWithScraperConfiguration =
|
|
|
|
|
symbolProfile.dataSource === 'MANUAL' &&
|
|
|
|
|
!isEmpty(symbolProfile.scraperConfiguration);
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
symbolProfile.dataSource !== 'MANUAL' ||
|
|
|
|
|
manualDataSourceWithScraperConfiguration
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
.map((symbolProfile) => {
|
|
|
|
|
return {
|
|
|
|
|
...symbolProfile,
|
|
|
|
|
date: symbolProfile.Order?.[0]?.date ?? startDate
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return [...currencyPairsToGather, ...symbolProfilesToGather];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|