|
|
@ -10,6 +10,7 @@ import { |
|
|
|
DATA_GATHERING_QUEUE, |
|
|
|
DATA_GATHERING_QUEUE_PRIORITY_HIGH, |
|
|
|
DATA_GATHERING_QUEUE_PRIORITY_LOW, |
|
|
|
DATA_GATHERING_QUEUE_PRIORITY_MEDIUM, |
|
|
|
GATHER_HISTORICAL_MARKET_DATA_PROCESS, |
|
|
|
GATHER_HISTORICAL_MARKET_DATA_PROCESS_OPTIONS, |
|
|
|
PROPERTY_BENCHMARKS |
|
|
@ -62,9 +63,22 @@ export class DataGatheringService { |
|
|
|
} |
|
|
|
|
|
|
|
public async gather7Days() { |
|
|
|
const dataGatheringItems = await this.getSymbols7D(); |
|
|
|
await this.gatherSymbols({ |
|
|
|
dataGatheringItems, |
|
|
|
dataGatheringItems: await this.getCurrencies7D(), |
|
|
|
priority: DATA_GATHERING_QUEUE_PRIORITY_HIGH |
|
|
|
}); |
|
|
|
|
|
|
|
await this.gatherSymbols({ |
|
|
|
dataGatheringItems: await this.getSymbols7D({ |
|
|
|
withUserSubscription: true |
|
|
|
}), |
|
|
|
priority: DATA_GATHERING_QUEUE_PRIORITY_MEDIUM |
|
|
|
}); |
|
|
|
|
|
|
|
await this.gatherSymbols({ |
|
|
|
dataGatheringItems: await this.getSymbols7D({ |
|
|
|
withUserSubscription: false |
|
|
|
}), |
|
|
|
priority: DATA_GATHERING_QUEUE_PRIORITY_LOW |
|
|
|
}); |
|
|
|
} |
|
|
@ -138,7 +152,7 @@ export class DataGatheringService { |
|
|
|
}); |
|
|
|
|
|
|
|
if (!uniqueAssets) { |
|
|
|
uniqueAssets = await this.getUniqueAssets(); |
|
|
|
uniqueAssets = await this.getAllAssetProfileIdentifiers(); |
|
|
|
} |
|
|
|
|
|
|
|
if (uniqueAssets.length <= 0) { |
|
|
@ -270,7 +284,7 @@ export class DataGatheringService { |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
public async getUniqueAssets(): Promise<UniqueAsset[]> { |
|
|
|
public async getAllAssetProfileIdentifiers(): Promise<UniqueAsset[]> { |
|
|
|
const symbolProfiles = await this.prismaService.symbolProfile.findMany({ |
|
|
|
orderBy: [{ symbol: 'asc' }] |
|
|
|
}); |
|
|
@ -290,73 +304,83 @@ export class DataGatheringService { |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private getEarliestDate(aStartDate: Date) { |
|
|
|
return min([aStartDate, subYears(new Date(), 10)]); |
|
|
|
} |
|
|
|
|
|
|
|
private async getSymbols7D(): Promise<IDataGatheringItem[]> { |
|
|
|
const startDate = subDays(resetHours(new Date()), 7); |
|
|
|
|
|
|
|
const symbolProfiles = await this.prismaService.symbolProfile.findMany({ |
|
|
|
orderBy: [{ symbol: 'asc' }], |
|
|
|
select: { |
|
|
|
dataSource: true, |
|
|
|
scraperConfiguration: true, |
|
|
|
symbol: true |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
// Only consider symbols with incomplete market data for the last
|
|
|
|
// 7 days
|
|
|
|
const symbolsWithCompleteMarketData = ( |
|
|
|
private async getAssetProfileIdentifiersWithCompleteMarketData(): Promise< |
|
|
|
UniqueAsset[] |
|
|
|
> { |
|
|
|
return ( |
|
|
|
await this.prismaService.marketData.groupBy({ |
|
|
|
_count: true, |
|
|
|
by: ['symbol'], |
|
|
|
by: ['dataSource', 'symbol'], |
|
|
|
orderBy: [{ symbol: 'asc' }], |
|
|
|
where: { |
|
|
|
date: { gt: startDate }, |
|
|
|
date: { gt: subDays(resetHours(new Date()), 7) }, |
|
|
|
state: 'CLOSE' |
|
|
|
} |
|
|
|
}) |
|
|
|
) |
|
|
|
.filter((group) => { |
|
|
|
return group._count >= 6; |
|
|
|
.filter(({ _count }) => { |
|
|
|
return _count >= 6; |
|
|
|
}) |
|
|
|
.map((group) => { |
|
|
|
return group.symbol; |
|
|
|
.map(({ dataSource, symbol }) => { |
|
|
|
return { dataSource, symbol }; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private async getCurrencies7D(): Promise<IDataGatheringItem[]> { |
|
|
|
const assetProfileIdentifiersWithCompleteMarketData = |
|
|
|
await this.getAssetProfileIdentifiersWithCompleteMarketData(); |
|
|
|
|
|
|
|
const symbolProfilesToGather = symbolProfiles |
|
|
|
return this.exchangeRateDataService |
|
|
|
.getCurrencyPairs() |
|
|
|
.filter(({ dataSource, symbol }) => { |
|
|
|
return !assetProfileIdentifiersWithCompleteMarketData.some((item) => { |
|
|
|
return item.dataSource === dataSource && item.symbol === symbol; |
|
|
|
}); |
|
|
|
}) |
|
|
|
.map(({ dataSource, symbol }) => { |
|
|
|
return { |
|
|
|
dataSource, |
|
|
|
symbol, |
|
|
|
date: subDays(resetHours(new Date()), 7) |
|
|
|
}; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
private getEarliestDate(aStartDate: Date) { |
|
|
|
return min([aStartDate, subYears(new Date(), 10)]); |
|
|
|
} |
|
|
|
|
|
|
|
private async getSymbols7D({ |
|
|
|
withUserSubscription = false |
|
|
|
}: { |
|
|
|
withUserSubscription?: boolean; |
|
|
|
}): Promise<IDataGatheringItem[]> { |
|
|
|
const symbolProfiles = |
|
|
|
await this.symbolProfileService.getSymbolProfilesByUserSubscription({ |
|
|
|
withUserSubscription |
|
|
|
}); |
|
|
|
|
|
|
|
const assetProfileIdentifiersWithCompleteMarketData = |
|
|
|
await this.getAssetProfileIdentifiersWithCompleteMarketData(); |
|
|
|
|
|
|
|
return symbolProfiles |
|
|
|
.filter(({ dataSource, scraperConfiguration, symbol }) => { |
|
|
|
const manualDataSourceWithScraperConfiguration = |
|
|
|
dataSource === 'MANUAL' && !isEmpty(scraperConfiguration); |
|
|
|
|
|
|
|
return ( |
|
|
|
!symbolsWithCompleteMarketData.includes(symbol) && |
|
|
|
!assetProfileIdentifiersWithCompleteMarketData.some((item) => { |
|
|
|
return item.dataSource === dataSource && item.symbol === symbol; |
|
|
|
}) && |
|
|
|
(dataSource !== 'MANUAL' || manualDataSourceWithScraperConfiguration) |
|
|
|
); |
|
|
|
}) |
|
|
|
.map((symbolProfile) => { |
|
|
|
return { |
|
|
|
...symbolProfile, |
|
|
|
date: startDate |
|
|
|
date: subDays(resetHours(new Date()), 7) |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
const currencyPairsToGather = this.exchangeRateDataService |
|
|
|
.getCurrencyPairs() |
|
|
|
.filter(({ symbol }) => { |
|
|
|
return !symbolsWithCompleteMarketData.includes(symbol); |
|
|
|
}) |
|
|
|
.map(({ dataSource, symbol }) => { |
|
|
|
return { |
|
|
|
dataSource, |
|
|
|
symbol, |
|
|
|
date: startDate |
|
|
|
}; |
|
|
|
}); |
|
|
|
|
|
|
|
return [...currencyPairsToGather, ...symbolProfilesToGather]; |
|
|
|
} |
|
|
|
|
|
|
|
private async getSymbolsMax(): Promise<IDataGatheringItem[]> { |
|
|
|