@ -229,32 +229,59 @@ export class ExchangeRateDataService {
return 0 ;
return 0 ;
}
}
let normalizedValue = aValue ;
let normalizedFromCurrency = aFromCurrency ;
let normalizedToCurrency = aToCurrency ;
const fromDerived = DERIVED_CURRENCIES . find (
( c ) = > c . currency === aFromCurrency
) ;
if ( fromDerived ) {
normalizedFromCurrency = fromDerived . rootCurrency ;
normalizedValue = normalizedValue / fromDerived . factor ;
}
const toDerived = DERIVED_CURRENCIES . find (
( c ) = > c . currency === aToCurrency
) ;
if ( toDerived ) {
normalizedToCurrency = toDerived . rootCurrency ;
normalizedValue = normalizedValue * toDerived . factor ;
}
let factor : number ;
let factor : number ;
if ( aFromCurrency === aToCurrency ) {
if ( norm alized FromCurrency === norm alized ToCurrency) {
factor = 1 ;
factor = 1 ;
} else {
} else {
if ( this . exchangeRates [ ` ${ aFromCurrency } ${ aToCurrency } ` ] ) {
if (
factor = this . exchangeRates [ ` ${ aFromCurrency } ${ aToCurrency } ` ] ;
this . exchangeRates [ ` ${ normalizedFromCurrency } ${ normalizedToCurrency } ` ]
) {
factor =
this . exchangeRates [
` ${ normalizedFromCurrency } ${ normalizedToCurrency } `
] ;
} else {
} else {
// Calculate indirectly via base currency
// Calculate indirectly via base currency
const factor1 =
const factor1 =
this . exchangeRates [ ` ${ aFromCurrency } ${ DEFAULT_CURRENCY } ` ] ;
this . exchangeRates [ ` ${ normalizedFromCurrency } ${ DEFAULT_CURRENCY } ` ] ;
const factor2 = this . exchangeRates [ ` ${ DEFAULT_CURRENCY } ${ aToCurrency } ` ] ;
const factor2 =
this . exchangeRates [ ` ${ DEFAULT_CURRENCY } ${ normalizedToCurrency } ` ] ;
factor = factor1 * factor2 ;
factor = factor1 * factor2 ;
this . exchangeRates [ ` ${ aFromCurrency } ${ aToCurrency } ` ] = factor ;
this . exchangeRates [ ` ${ normalizedFromCurrency } ${ normalizedToCurrency } ` ] =
factor ;
}
}
}
}
if ( isNumber ( factor ) && ! isNaN ( factor ) ) {
if ( isNumber ( factor ) && ! isNaN ( factor ) ) {
return factor * aValue ;
return factor * norm alized Value;
}
}
// Fallback with error, if currencies are not available
// Fallback with error, if currencies are not available
Logger . error (
Logger . error (
` No exchange rate has been found for ${ aFromCurrency } ${ aToCurrency } ` ,
` No exchange rate has been found for ${ norm alized FromCurrency} ${ norm alized ToCurrency} . Please complement market data for USD ${ normalizedFromCurrency } and USD ${ normalizedToCurrency } . ` ,
'ExchangeRateDataService'
'ExchangeRateDataService'
) ;
) ;
@ -271,22 +298,42 @@ export class ExchangeRateDataService {
return 0 ;
return 0 ;
}
}
let normalizedValue = aValue ;
let normalizedFromCurrency = aFromCurrency ;
let normalizedToCurrency = aToCurrency ;
const fromDerived = DERIVED_CURRENCIES . find (
( c ) = > c . currency === aFromCurrency
) ;
if ( fromDerived ) {
normalizedFromCurrency = fromDerived . rootCurrency ;
normalizedValue = normalizedValue / fromDerived . factor ;
}
const toDerived = DERIVED_CURRENCIES . find (
( c ) = > c . currency === aToCurrency
) ;
if ( toDerived ) {
normalizedToCurrency = toDerived . rootCurrency ;
normalizedValue = normalizedValue * toDerived . factor ;
}
if ( isToday ( aDate ) ) {
if ( isToday ( aDate ) ) {
return this . toCurrency ( aValue , aFromCurrency , aToCurrency ) ;
return this . toCurrency (
normalizedValue ,
normalizedFromCurrency ,
normalizedToCurrency
) ;
}
}
const derivedCurrencyFactor =
this . derivedCurrencyFactors [ ` ${ aFromCurrency } ${ aToCurrency } ` ] ;
let factor : number ;
let factor : number ;
if ( aFromCurrency === aToCurrency ) {
if ( norm alized FromCurrency === norm alized ToCurrency) {
factor = 1 ;
factor = 1 ;
} else if ( derivedCurrencyFactor ) {
factor = derivedCurrencyFactor ;
} else {
} else {
const dataSource =
const dataSource =
this . dataProviderService . getDataSourceForExchangeRates ( ) ;
this . dataProviderService . getDataSourceForExchangeRates ( ) ;
const symbol = ` ${ aFromCurrency } ${ aToCurrency } ` ;
const symbol = ` ${ norm alized FromCurrency} ${ norm alized ToCurrency} ` ;
const marketData = await this . marketDataService . get ( {
const marketData = await this . marketDataService . get ( {
dataSource ,
dataSource ,
@ -303,28 +350,28 @@ export class ExchangeRateDataService {
let marketPriceBaseCurrencyToCurrency : number ;
let marketPriceBaseCurrencyToCurrency : number ;
try {
try {
if ( aFromCurrency === DEFAULT_CURRENCY ) {
if ( norm alized FromCurrency === DEFAULT_CURRENCY ) {
marketPriceBaseCurrencyFromCurrency = 1 ;
marketPriceBaseCurrencyFromCurrency = 1 ;
} else {
} else {
marketPriceBaseCurrencyFromCurrency = (
marketPriceBaseCurrencyFromCurrency = (
await this . marketDataService . get ( {
await this . marketDataService . get ( {
dataSource ,
dataSource ,
date : aDate ,
date : aDate ,
symbol : ` ${ DEFAULT_CURRENCY } ${ aFromCurrency } `
symbol : ` ${ DEFAULT_CURRENCY } ${ norm alized FromCurrency} `
} )
} )
) ? . marketPrice ;
) ? . marketPrice ;
}
}
} catch { }
} catch { }
try {
try {
if ( aToCurrency === DEFAULT_CURRENCY ) {
if ( norm alized ToCurrency === DEFAULT_CURRENCY ) {
marketPriceBaseCurrencyToCurrency = 1 ;
marketPriceBaseCurrencyToCurrency = 1 ;
} else {
} else {
marketPriceBaseCurrencyToCurrency = (
marketPriceBaseCurrencyToCurrency = (
await this . marketDataService . get ( {
await this . marketDataService . get ( {
dataSource ,
dataSource ,
date : aDate ,
date : aDate ,
symbol : ` ${ DEFAULT_CURRENCY } ${ aToCurrency } `
symbol : ` ${ DEFAULT_CURRENCY } ${ norm alized ToCurrency} `
} )
} )
) ? . marketPrice ;
) ? . marketPrice ;
}
}
@ -338,18 +385,18 @@ export class ExchangeRateDataService {
}
}
if ( isNumber ( factor ) && ! isNaN ( factor ) ) {
if ( isNumber ( factor ) && ! isNaN ( factor ) ) {
return factor * aValue ;
return factor * norm alized Value;
}
}
Logger . error (
Logger . error (
` No exchange rate has been found for ${ aFromCurrency } ${ aToCurrency } at ${ format (
` No exchange rate has been found for ${ norm alized FromCurrency} ${ norm alized ToCurrency} at ${ format (
aDate ,
aDate ,
DATE_FORMAT
DATE_FORMAT
) } ` ,
) } . Please complement market data for USD $ { normalizedFromCurrency } and USD $ { normalizedToCurrency } . ` ,
'ExchangeRateDataService'
'ExchangeRateDataService'
) ;
) ;
return undefined ;
return aValue ;
}
}
private async getExchangeRates ( {
private async getExchangeRates ( {
@ -366,27 +413,36 @@ export class ExchangeRateDataService {
const dates = eachDayOfInterval ( { end : endDate , start : startDate } ) ;
const dates = eachDayOfInterval ( { end : endDate , start : startDate } ) ;
const factors : { [ dateString : string ] : number } = { } ;
const factors : { [ dateString : string ] : number } = { } ;
if ( currencyFrom === currencyTo ) {
let normalizedCurrencyFrom = currencyFrom ;
for ( const date of dates ) {
let normalizedCurrencyTo = currencyTo ;
factors [ format ( date , DATE_FORMAT ) ] = 1 ;
let conversionFactorFrom = 1 ;
}
let conversionFactorTo = 1 ;
return factors ;
const fromDerived = DERIVED_CURRENCIES . find (
( c ) = > c . currency === currencyFrom
) ;
if ( fromDerived ) {
normalizedCurrencyFrom = fromDerived . rootCurrency ;
conversionFactorFrom = 1 / fromDerived . factor ;
}
}
const derivedCurrencyFactor =
const toDerived = DERIVED_CURRENCIES . find ( ( c ) = > c . currency === currencyTo ) ;
this . derivedCurrencyFactors [ ` ${ currencyFrom } ${ currencyTo } ` ] ;
if ( toDerived ) {
normalizedCurrencyTo = toDerived . rootCurrency ;
conversionFactorTo = toDerived . factor ;
}
if ( derivedCurrencyFactor ) {
if ( normalizedCurrencyFrom === normalizedCurrencyTo ) {
for ( const date of dates ) {
for ( const date of dates ) {
factors [ format ( date , DATE_FORMAT ) ] = derivedCurrencyFactor ;
factors [ format ( date , DATE_FORMAT ) ] =
conversionFactorFrom * conversionFactorTo ;
}
}
return factors ;
return factors ;
}
}
const dataSource = this . dataProviderService . getDataSourceForExchangeRates ( ) ;
const dataSource = this . dataProviderService . getDataSourceForExchangeRates ( ) ;
const symbol = ` ${ currencyFrom } ${ c urrencyTo} ` ;
const symbol = ` ${ normalizedCurrencyFrom } ${ normalizedC urrencyTo} ` ;
const marketData = await this . marketDataService . getRange ( {
const marketData = await this . marketDataService . getRange ( {
assetProfileIdentifiers : [
assetProfileIdentifiers : [
@ -400,7 +456,8 @@ export class ExchangeRateDataService {
if ( marketData ? . length > 0 ) {
if ( marketData ? . length > 0 ) {
for ( const { date , marketPrice } of marketData ) {
for ( const { date , marketPrice } of marketData ) {
factors [ format ( date , DATE_FORMAT ) ] = marketPrice ;
factors [ format ( date , DATE_FORMAT ) ] =
conversionFactorFrom * marketPrice * conversionFactorTo ;
}
}
} else {
} else {
// Calculate indirectly via base currency
// Calculate indirectly via base currency
@ -413,7 +470,7 @@ export class ExchangeRateDataService {
} = { } ;
} = { } ;
try {
try {
if ( c urrencyFrom === DEFAULT_CURRENCY ) {
if ( normalizedC urrencyFrom === DEFAULT_CURRENCY ) {
for ( const date of dates ) {
for ( const date of dates ) {
marketPriceBaseCurrencyFromCurrency [ format ( date , DATE_FORMAT ) ] = 1 ;
marketPriceBaseCurrencyFromCurrency [ format ( date , DATE_FORMAT ) ] = 1 ;
}
}
@ -422,7 +479,7 @@ export class ExchangeRateDataService {
assetProfileIdentifiers : [
assetProfileIdentifiers : [
{
{
dataSource ,
dataSource ,
symbol : ` ${ DEFAULT_CURRENCY } ${ c urrencyFrom} `
symbol : ` ${ DEFAULT_CURRENCY } ${ normalizedC urrencyFrom} `
}
}
] ,
] ,
dateQuery : { gte : startDate , lt : endDate }
dateQuery : { gte : startDate , lt : endDate }
@ -436,7 +493,7 @@ export class ExchangeRateDataService {
} catch { }
} catch { }
try {
try {
if ( c urrencyTo === DEFAULT_CURRENCY ) {
if ( normalizedC urrencyTo === DEFAULT_CURRENCY ) {
for ( const date of dates ) {
for ( const date of dates ) {
marketPriceBaseCurrencyToCurrency [ format ( date , DATE_FORMAT ) ] = 1 ;
marketPriceBaseCurrencyToCurrency [ format ( date , DATE_FORMAT ) ] = 1 ;
}
}
@ -445,7 +502,7 @@ export class ExchangeRateDataService {
assetProfileIdentifiers : [
assetProfileIdentifiers : [
{
{
dataSource ,
dataSource ,
symbol : ` ${ DEFAULT_CURRENCY } ${ c urrencyTo} `
symbol : ` ${ DEFAULT_CURRENCY } ${ normalizedC urrencyTo} `
}
}
] ,
] ,
dateQuery : {
dateQuery : {
@ -471,16 +528,17 @@ export class ExchangeRateDataService {
if ( isNaN ( factor ) ) {
if ( isNaN ( factor ) ) {
throw new Error ( 'Exchange rate is not a number' ) ;
throw new Error ( 'Exchange rate is not a number' ) ;
} else {
} else {
factors [ format ( date , DATE_FORMAT ) ] = factor ;
factors [ format ( date , DATE_FORMAT ) ] =
conversionFactorFrom * factor * conversionFactorTo ;
}
}
} catch {
} catch {
let errorMessage = ` No exchange rate has been found for ${ currencyFrom } ${ c urrencyTo} at ${ format (
let errorMessage = ` No exchange rate has been found for ${ normalizedCurrencyFrom } ${ normalizedC urrencyTo} at ${ format (
date ,
date ,
DATE_FORMAT
DATE_FORMAT
) } . Please complement market data for $ { DEFAULT_CURRENCY } $ { c urrencyFrom} ` ;
) } . Please complement market data for $ { DEFAULT_CURRENCY } $ { normalizedC urrencyFrom} ` ;
if ( DEFAULT_CURRENCY !== c urrencyTo) {
if ( DEFAULT_CURRENCY !== normalizedC urrencyTo) {
errorMessage = ` ${ errorMessage } and ${ DEFAULT_CURRENCY } ${ c urrencyTo} ` ;
errorMessage = ` ${ errorMessage } and ${ DEFAULT_CURRENCY } ${ normalizedC urrencyTo} ` ;
}
}
Logger . error ( ` ${ errorMessage } . ` , 'ExchangeRateDataService' ) ;
Logger . error ( ` ${ errorMessage } . ` , 'ExchangeRateDataService' ) ;