|
|
@ -6,9 +6,17 @@ import { |
|
|
|
} from '@ghostfolio/api/services/interfaces/interfaces'; |
|
|
|
import { PrismaService } from '@ghostfolio/api/services/prisma.service'; |
|
|
|
import { SymbolProfileService } from '@ghostfolio/api/services/symbol-profile.service'; |
|
|
|
import { |
|
|
|
DATE_FORMAT, |
|
|
|
extractNumberFromString, |
|
|
|
getYesterday |
|
|
|
} from '@ghostfolio/common/helper'; |
|
|
|
import { Granularity } from '@ghostfolio/common/types'; |
|
|
|
import { Injectable, Logger } from '@nestjs/common'; |
|
|
|
import { DataSource, SymbolProfile } from '@prisma/client'; |
|
|
|
import bent from 'bent'; |
|
|
|
import * as cheerio from 'cheerio'; |
|
|
|
import { addDays, format, isBefore } from 'date-fns'; |
|
|
|
|
|
|
|
@Injectable() |
|
|
|
export class ManualService implements DataProviderInterface { |
|
|
@ -18,7 +26,7 @@ export class ManualService implements DataProviderInterface { |
|
|
|
) {} |
|
|
|
|
|
|
|
public canHandle(symbol: string) { |
|
|
|
return false; |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
public async getAssetProfile( |
|
|
@ -51,7 +59,57 @@ export class ManualService implements DataProviderInterface { |
|
|
|
): Promise<{ |
|
|
|
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; |
|
|
|
}> { |
|
|
|
return {}; |
|
|
|
try { |
|
|
|
const symbol = aSymbol; |
|
|
|
|
|
|
|
const [symbolProfile] = |
|
|
|
await this.symbolProfileService.getSymbolProfilesBySymbols([symbol]); |
|
|
|
const { defaultMarketPrice, selector, url } = |
|
|
|
symbolProfile.scraperConfiguration ?? {}; |
|
|
|
|
|
|
|
if (defaultMarketPrice) { |
|
|
|
const historical: { |
|
|
|
[symbol: string]: { [date: string]: IDataProviderHistoricalResponse }; |
|
|
|
} = { |
|
|
|
[symbol]: {} |
|
|
|
}; |
|
|
|
let date = from; |
|
|
|
|
|
|
|
while (isBefore(date, to)) { |
|
|
|
historical[symbol][format(date, DATE_FORMAT)] = { |
|
|
|
marketPrice: defaultMarketPrice |
|
|
|
}; |
|
|
|
|
|
|
|
date = addDays(date, 1); |
|
|
|
} |
|
|
|
|
|
|
|
return historical; |
|
|
|
} else if (selector === undefined || url === undefined) { |
|
|
|
return {}; |
|
|
|
} |
|
|
|
|
|
|
|
const get = bent(url, 'GET', 'string', 200, {}); |
|
|
|
|
|
|
|
const html = await get(); |
|
|
|
const $ = cheerio.load(html); |
|
|
|
|
|
|
|
const value = extractNumberFromString($(selector).text()); |
|
|
|
|
|
|
|
return { |
|
|
|
[symbol]: { |
|
|
|
[format(getYesterday(), DATE_FORMAT)]: { |
|
|
|
marketPrice: value |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
} catch (error) { |
|
|
|
throw new Error( |
|
|
|
`Could not get historical market data for ${aSymbol} (${this.getName()}) from ${format( |
|
|
|
from, |
|
|
|
DATE_FORMAT |
|
|
|
)} to ${format(to, DATE_FORMAT)}: [${error.name}] ${error.message}` |
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public getName(): DataSource { |
|
|
@ -88,10 +146,9 @@ export class ManualService implements DataProviderInterface { |
|
|
|
response[symbolProfile.symbol] = { |
|
|
|
currency: symbolProfile.currency, |
|
|
|
dataSource: this.getName(), |
|
|
|
marketPrice: |
|
|
|
marketData.find((marketDataItem) => { |
|
|
|
return marketDataItem.symbol === symbolProfile.symbol; |
|
|
|
})?.marketPrice ?? 0, |
|
|
|
marketPrice: marketData.find((marketDataItem) => { |
|
|
|
return marketDataItem.symbol === symbolProfile.symbol; |
|
|
|
})?.marketPrice, |
|
|
|
marketState: 'delayed' |
|
|
|
}; |
|
|
|
} |
|
|
|