Browse Source

Refactoring

pull/5961/head
Thomas Kaul 1 month ago
parent
commit
17483ca5e4
  1. 315
      apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts

315
apps/api/src/services/exchange-rate-data/exchange-rate-data.service.ts

@ -30,7 +30,7 @@ import ms from 'ms';
export class ExchangeRateDataService { export class ExchangeRateDataService {
private currencies: string[] = []; private currencies: string[] = [];
private currencyPairs: DataGatheringItem[] = []; private currencyPairs: DataGatheringItem[] = [];
private derivedCurrencyFactors = new Map<string, number>(); private derivedCurrencyFactors: { [currencyPair: string]: number } = {};
private exchangeRates: { [currencyPair: string]: number } = {}; private exchangeRates: { [currencyPair: string]: number } = {};
public constructor( public constructor(
@ -136,13 +136,12 @@ export class ExchangeRateDataService {
public async initialize() { public async initialize() {
this.currencies = await this.prepareCurrencies(); this.currencies = await this.prepareCurrencies();
this.currencyPairs = []; this.currencyPairs = [];
this.derivedCurrencyFactors = {};
this.exchangeRates = {}; this.exchangeRates = {};
this.derivedCurrencyFactors = new Map();
// Initialize derived currencies factor map in both directions
for (const { currency, factor, rootCurrency } of DERIVED_CURRENCIES) { for (const { currency, factor, rootCurrency } of DERIVED_CURRENCIES) {
this.derivedCurrencyFactors.set(`${currency}${rootCurrency}`, 1 / factor); this.derivedCurrencyFactors[`${currency}${rootCurrency}`] = 1 / factor;
this.derivedCurrencyFactors.set(`${rootCurrency}${currency}`, factor); this.derivedCurrencyFactors[`${rootCurrency}${currency}`] = factor;
} }
for (const { for (const {
@ -274,70 +273,65 @@ export class ExchangeRateDataService {
return this.toCurrency(aValue, aFromCurrency, aToCurrency); return this.toCurrency(aValue, aFromCurrency, aToCurrency);
} }
const derivedCurrencyFactor =
this.derivedCurrencyFactors[`${aFromCurrency}${aToCurrency}`];
let factor: number; let factor: number;
if (aFromCurrency === aToCurrency) { if (aFromCurrency === aToCurrency) {
factor = 1; factor = 1;
} else if (derivedCurrencyFactor) {
factor = derivedCurrencyFactor;
} else { } else {
const derivedCurrencyFactor = this.getDerivedCurrencyFactor( const dataSource =
aFromCurrency, this.dataProviderService.getDataSourceForExchangeRates();
aToCurrency const symbol = `${aFromCurrency}${aToCurrency}`;
);
if (derivedCurrencyFactor !== null) { const marketData = await this.marketDataService.get({
factor = derivedCurrencyFactor; dataSource,
symbol,
date: aDate
});
if (marketData?.marketPrice) {
factor = marketData?.marketPrice;
} else { } else {
const dataSource = // Calculate indirectly via base currency
this.dataProviderService.getDataSourceForExchangeRates();
const symbol = `${aFromCurrency}${aToCurrency}`;
const marketData = await this.marketDataService.get({ let marketPriceBaseCurrencyFromCurrency: number;
dataSource, let marketPriceBaseCurrencyToCurrency: number;
symbol,
date: aDate
});
if (marketData?.marketPrice) { try {
factor = marketData?.marketPrice; if (aFromCurrency === DEFAULT_CURRENCY) {
} else { marketPriceBaseCurrencyFromCurrency = 1;
// Calculate indirectly via base currency } else {
marketPriceBaseCurrencyFromCurrency = (
let marketPriceBaseCurrencyFromCurrency: number; await this.marketDataService.get({
let marketPriceBaseCurrencyToCurrency: number; dataSource,
date: aDate,
try { symbol: `${DEFAULT_CURRENCY}${aFromCurrency}`
if (aFromCurrency === DEFAULT_CURRENCY) { })
marketPriceBaseCurrencyFromCurrency = 1; )?.marketPrice;
} else { }
marketPriceBaseCurrencyFromCurrency = ( } catch {}
await this.marketDataService.get({
dataSource,
date: aDate,
symbol: `${DEFAULT_CURRENCY}${aFromCurrency}`
})
)?.marketPrice;
}
} catch {}
try {
if (aToCurrency === DEFAULT_CURRENCY) {
marketPriceBaseCurrencyToCurrency = 1;
} else {
marketPriceBaseCurrencyToCurrency = (
await this.marketDataService.get({
dataSource,
date: aDate,
symbol: `${DEFAULT_CURRENCY}${aToCurrency}`
})
)?.marketPrice;
}
} catch {}
// Calculate the opposite direction try {
factor = if (aToCurrency === DEFAULT_CURRENCY) {
(1 / marketPriceBaseCurrencyFromCurrency) * marketPriceBaseCurrencyToCurrency = 1;
marketPriceBaseCurrencyToCurrency; } else {
} marketPriceBaseCurrencyToCurrency = (
await this.marketDataService.get({
dataSource,
date: aDate,
symbol: `${DEFAULT_CURRENCY}${aToCurrency}`
})
)?.marketPrice;
}
} catch {}
// Calculate the opposite direction
factor =
(1 / marketPriceBaseCurrencyFromCurrency) *
marketPriceBaseCurrencyToCurrency;
} }
} }
@ -374,129 +368,120 @@ export class ExchangeRateDataService {
for (const date of dates) { for (const date of dates) {
factors[format(date, DATE_FORMAT)] = 1; factors[format(date, DATE_FORMAT)] = 1;
} }
return factors; return factors;
} }
// Check if this is a conversion between a derived currency and its root currency const derivedCurrencyFactor =
const derivedCurrencyFactor = this.getDerivedCurrencyFactor( this.derivedCurrencyFactors[`${currencyFrom}${currencyTo}`];
currencyFrom,
currencyTo
);
if (derivedCurrencyFactor !== null) { if (derivedCurrencyFactor) {
// Use the fixed mathematical factor for derived currencies
for (const date of dates) { for (const date of dates) {
factors[format(date, DATE_FORMAT)] = derivedCurrencyFactor; factors[format(date, DATE_FORMAT)] = derivedCurrencyFactor;
} }
return factors; return factors;
} }
// Continue with standard exchange rate logic const dataSource = this.dataProviderService.getDataSourceForExchangeRates();
{ const symbol = `${currencyFrom}${currencyTo}`;
const dataSource =
this.dataProviderService.getDataSourceForExchangeRates();
const symbol = `${currencyFrom}${currencyTo}`;
const marketData = await this.marketDataService.getRange({
assetProfileIdentifiers: [
{
dataSource,
symbol
}
],
dateQuery: { gte: startDate, lt: endDate }
});
if (marketData?.length > 0) { const marketData = await this.marketDataService.getRange({
for (const { date, marketPrice } of marketData) { assetProfileIdentifiers: [
factors[format(date, DATE_FORMAT)] = marketPrice; {
dataSource,
symbol
} }
} else { ],
// Calculate indirectly via base currency dateQuery: { gte: startDate, lt: endDate }
});
const marketPriceBaseCurrencyFromCurrency: { if (marketData?.length > 0) {
[dateString: string]: number; for (const { date, marketPrice } of marketData) {
} = {}; factors[format(date, DATE_FORMAT)] = marketPrice;
const marketPriceBaseCurrencyToCurrency: { }
[dateString: string]: number; } else {
} = {}; // Calculate indirectly via base currency
const marketPriceBaseCurrencyFromCurrency: {
[dateString: string]: number;
} = {};
const marketPriceBaseCurrencyToCurrency: {
[dateString: string]: number;
} = {};
try {
if (currencyFrom === DEFAULT_CURRENCY) {
for (const date of dates) {
marketPriceBaseCurrencyFromCurrency[format(date, DATE_FORMAT)] = 1;
}
} else {
const marketData = await this.marketDataService.getRange({
assetProfileIdentifiers: [
{
dataSource,
symbol: `${DEFAULT_CURRENCY}${currencyFrom}`
}
],
dateQuery: { gte: startDate, lt: endDate }
});
try { for (const { date, marketPrice } of marketData) {
if (currencyFrom === DEFAULT_CURRENCY) { marketPriceBaseCurrencyFromCurrency[format(date, DATE_FORMAT)] =
for (const date of dates) { marketPrice;
marketPriceBaseCurrencyFromCurrency[format(date, DATE_FORMAT)] =
1;
}
} else {
const marketData = await this.marketDataService.getRange({
assetProfileIdentifiers: [
{
dataSource,
symbol: `${DEFAULT_CURRENCY}${currencyFrom}`
}
],
dateQuery: { gte: startDate, lt: endDate }
});
for (const { date, marketPrice } of marketData) {
marketPriceBaseCurrencyFromCurrency[format(date, DATE_FORMAT)] =
marketPrice;
}
} }
} catch {} }
} catch {}
try { try {
if (currencyTo === DEFAULT_CURRENCY) { if (currencyTo === DEFAULT_CURRENCY) {
for (const date of dates) { for (const date of dates) {
marketPriceBaseCurrencyToCurrency[format(date, DATE_FORMAT)] = 1; marketPriceBaseCurrencyToCurrency[format(date, DATE_FORMAT)] = 1;
} }
} else { } else {
const marketData = await this.marketDataService.getRange({ const marketData = await this.marketDataService.getRange({
assetProfileIdentifiers: [ assetProfileIdentifiers: [
{ {
dataSource, dataSource,
symbol: `${DEFAULT_CURRENCY}${currencyTo}` symbol: `${DEFAULT_CURRENCY}${currencyTo}`
}
],
dateQuery: {
gte: startDate,
lt: endDate
} }
}); ],
dateQuery: {
for (const { date, marketPrice } of marketData) { gte: startDate,
marketPriceBaseCurrencyToCurrency[format(date, DATE_FORMAT)] = lt: endDate
marketPrice;
} }
});
for (const { date, marketPrice } of marketData) {
marketPriceBaseCurrencyToCurrency[format(date, DATE_FORMAT)] =
marketPrice;
} }
} catch {} }
} catch {}
for (const date of dates) { for (const date of dates) {
try { try {
const factor = const factor =
(1 / (1 /
marketPriceBaseCurrencyFromCurrency[ marketPriceBaseCurrencyFromCurrency[format(date, DATE_FORMAT)]) *
format(date, DATE_FORMAT) marketPriceBaseCurrencyToCurrency[format(date, DATE_FORMAT)];
]) *
marketPriceBaseCurrencyToCurrency[format(date, DATE_FORMAT)];
if (isNaN(factor)) {
throw new Error('Exchange rate is not a number');
} else {
factors[format(date, DATE_FORMAT)] = factor;
}
} catch {
let errorMessage = `No exchange rate has been found for ${currencyFrom}${currencyTo} at ${format(
date,
DATE_FORMAT
)}. Please complement market data for ${DEFAULT_CURRENCY}${currencyFrom}`;
if (DEFAULT_CURRENCY !== currencyTo) {
errorMessage = `${errorMessage} and ${DEFAULT_CURRENCY}${currencyTo}`;
}
Logger.error(`${errorMessage}.`, 'ExchangeRateDataService'); if (isNaN(factor)) {
throw new Error('Exchange rate is not a number');
} else {
factors[format(date, DATE_FORMAT)] = factor;
}
} catch {
let errorMessage = `No exchange rate has been found for ${currencyFrom}${currencyTo} at ${format(
date,
DATE_FORMAT
)}. Please complement market data for ${DEFAULT_CURRENCY}${currencyFrom}`;
if (DEFAULT_CURRENCY !== currencyTo) {
errorMessage = `${errorMessage} and ${DEFAULT_CURRENCY}${currencyTo}`;
} }
Logger.error(`${errorMessage}.`, 'ExchangeRateDataService');
} }
} }
} }
@ -504,16 +489,6 @@ export class ExchangeRateDataService {
return factors; return factors;
} }
private getDerivedCurrencyFactor(
currencyFrom: string,
currencyTo: string
): number | null {
const factor = this.derivedCurrencyFactors.get(
`${currencyFrom}${currencyTo}`
);
return factor ?? null;
}
private async prepareCurrencies(): Promise<string[]> { private async prepareCurrencies(): Promise<string[]> {
let currencies: string[] = [DEFAULT_CURRENCY]; let currencies: string[] = [DEFAULT_CURRENCY];

Loading…
Cancel
Save