|
|
@ -8,7 +8,12 @@ import { |
|
|
|
import { DATE_FORMAT } from '@ghostfolio/common/helper'; |
|
|
|
import { Granularity } from '@ghostfolio/common/types'; |
|
|
|
import { Injectable, Logger } from '@nestjs/common'; |
|
|
|
import { DataSource, SymbolProfile } from '@prisma/client'; |
|
|
|
import { |
|
|
|
AssetClass, |
|
|
|
AssetSubClass, |
|
|
|
DataSource, |
|
|
|
SymbolProfile |
|
|
|
} from '@prisma/client'; |
|
|
|
import bent from 'bent'; |
|
|
|
import { format, isToday } from 'date-fns'; |
|
|
|
|
|
|
@ -30,12 +35,15 @@ export class EodHistoricalDataService implements DataProviderInterface { |
|
|
|
public async getAssetProfile( |
|
|
|
aSymbol: string |
|
|
|
): Promise<Partial<SymbolProfile>> { |
|
|
|
const { items } = await this.search(aSymbol); |
|
|
|
const [searchResult] = await this.getSearchResult(aSymbol); |
|
|
|
|
|
|
|
return { |
|
|
|
currency: items[0]?.currency, |
|
|
|
assetClass: searchResult?.assetClass, |
|
|
|
assetSubClass: searchResult?.assetSubClass, |
|
|
|
currency: searchResult?.currency, |
|
|
|
dataSource: this.getName(), |
|
|
|
name: items[0]?.name |
|
|
|
isin: searchResult?.isin, |
|
|
|
name: searchResult?.name |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
@ -156,7 +164,27 @@ export class EodHistoricalDataService implements DataProviderInterface { |
|
|
|
} |
|
|
|
|
|
|
|
public async search(aQuery: string): Promise<{ items: LookupItem[] }> { |
|
|
|
let items: LookupItem[] = []; |
|
|
|
const searchResult = await this.getSearchResult(aQuery); |
|
|
|
|
|
|
|
return { |
|
|
|
items: searchResult |
|
|
|
.filter(({ symbol }) => { |
|
|
|
return !symbol.toLowerCase().endsWith('forex'); |
|
|
|
}) |
|
|
|
.map(({ currency, dataSource, name, symbol }) => { |
|
|
|
return { currency, dataSource, name, symbol }; |
|
|
|
}) |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
private async getSearchResult(aQuery: string): Promise< |
|
|
|
(LookupItem & { |
|
|
|
assetClass: AssetClass; |
|
|
|
assetSubClass: AssetSubClass; |
|
|
|
isin: string; |
|
|
|
})[] |
|
|
|
> { |
|
|
|
let searchResult = []; |
|
|
|
|
|
|
|
try { |
|
|
|
const get = bent( |
|
|
@ -167,10 +195,25 @@ export class EodHistoricalDataService implements DataProviderInterface { |
|
|
|
); |
|
|
|
const response = await get(); |
|
|
|
|
|
|
|
items = response.map( |
|
|
|
({ Code, Currency: currency, Exchange, Name: name }) => { |
|
|
|
searchResult = response.map( |
|
|
|
({ |
|
|
|
Code, |
|
|
|
Currency: currency, |
|
|
|
Exchange, |
|
|
|
ISIN: isin, |
|
|
|
Name: name, |
|
|
|
Type |
|
|
|
}) => { |
|
|
|
const { assetClass, assetSubClass } = this.parseAssetClass({ |
|
|
|
Exchange, |
|
|
|
Type |
|
|
|
}); |
|
|
|
|
|
|
|
return { |
|
|
|
assetClass, |
|
|
|
assetSubClass, |
|
|
|
currency, |
|
|
|
isin, |
|
|
|
name, |
|
|
|
dataSource: this.getName(), |
|
|
|
symbol: `${Code}.${Exchange}` |
|
|
@ -181,6 +224,41 @@ export class EodHistoricalDataService implements DataProviderInterface { |
|
|
|
Logger.error(error, 'EodHistoricalDataService'); |
|
|
|
} |
|
|
|
|
|
|
|
return { items }; |
|
|
|
return searchResult; |
|
|
|
} |
|
|
|
|
|
|
|
private parseAssetClass({ |
|
|
|
Exchange, |
|
|
|
Type |
|
|
|
}: { |
|
|
|
Exchange: string; |
|
|
|
Type: string; |
|
|
|
}): { |
|
|
|
assetClass: AssetClass; |
|
|
|
assetSubClass: AssetSubClass; |
|
|
|
} { |
|
|
|
let assetClass: AssetClass; |
|
|
|
let assetSubClass: AssetSubClass; |
|
|
|
|
|
|
|
switch (Type?.toLowerCase()) { |
|
|
|
case 'common stock': |
|
|
|
assetClass = AssetClass.EQUITY; |
|
|
|
assetSubClass = AssetSubClass.STOCK; |
|
|
|
break; |
|
|
|
case 'currency': |
|
|
|
assetClass = AssetClass.CASH; |
|
|
|
|
|
|
|
if (Exchange?.toLowerCase() === 'cc') { |
|
|
|
assetSubClass = AssetSubClass.CRYPTOCURRENCY; |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
case 'etf': |
|
|
|
assetClass = AssetClass.EQUITY; |
|
|
|
assetSubClass = AssetSubClass.ETF; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
return { assetClass, assetSubClass }; |
|
|
|
} |
|
|
|
} |
|
|
|