- Complete monorepo structure with pnpm workspaces and Turborepo - All packages implemented: types, utils, rules-engine, iso20022, treasury, risk-models, audit - React web application with TypeScript and Tailwind CSS - Full Brazil regulatory compliance (BCB requirements) - ISO 20022 message support (pacs.008, pacs.009, pain.001) - Treasury and subledger management - Risk, capital, and liquidity stress allocation - Audit logging and BCB reporting - E&O +10% uplift implementation
131 lines
3.5 KiB
TypeScript
131 lines
3.5 KiB
TypeScript
/**
|
|
* Currency conversion and USD equivalent calculation utilities
|
|
*/
|
|
|
|
import Decimal from 'decimal.js';
|
|
|
|
export interface ExchangeRate {
|
|
fromCurrency: string;
|
|
toCurrency: string;
|
|
rate: number;
|
|
effectiveDate: Date;
|
|
source?: string;
|
|
}
|
|
|
|
export interface CurrencyConverter {
|
|
convert(amount: number, fromCurrency: string, toCurrency: string, date?: Date): number;
|
|
getUSDEquivalent(amount: number, currency: string, date?: Date): number;
|
|
getRate(fromCurrency: string, toCurrency: string, date?: Date): number | null;
|
|
}
|
|
|
|
/**
|
|
* Simple in-memory currency converter with configurable rates
|
|
* In production, this would integrate with a real-time FX rate service
|
|
*/
|
|
export class SimpleCurrencyConverter implements CurrencyConverter {
|
|
private rates: Map<string, ExchangeRate> = new Map();
|
|
private defaultUSDRates: Record<string, number> = {
|
|
USD: 1.0,
|
|
BRL: 0.2,
|
|
EUR: 1.1,
|
|
GBP: 1.27,
|
|
};
|
|
|
|
constructor(initialRates?: ExchangeRate[]) {
|
|
if (initialRates) {
|
|
initialRates.forEach((rate) => this.addRate(rate));
|
|
}
|
|
this.initializeDefaultRates();
|
|
}
|
|
|
|
private initializeDefaultRates(): void {
|
|
const now = new Date();
|
|
Object.entries(this.defaultUSDRates).forEach(([currency, rate]) => {
|
|
if (currency !== 'USD') {
|
|
this.addRate({
|
|
fromCurrency: currency,
|
|
toCurrency: 'USD',
|
|
rate,
|
|
effectiveDate: now,
|
|
source: 'default',
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
addRate(rate: ExchangeRate): void {
|
|
const key = this.getRateKey(rate.fromCurrency, rate.toCurrency);
|
|
this.rates.set(key, rate);
|
|
const inverseKey = this.getRateKey(rate.toCurrency, rate.fromCurrency);
|
|
this.rates.set(inverseKey, {
|
|
...rate,
|
|
fromCurrency: rate.toCurrency,
|
|
toCurrency: rate.fromCurrency,
|
|
rate: 1 / rate.rate,
|
|
});
|
|
}
|
|
|
|
private getRateKey(fromCurrency: string, toCurrency: string): string {
|
|
return `${fromCurrency}:${toCurrency}`;
|
|
}
|
|
|
|
getRate(fromCurrency: string, toCurrency: string, date?: Date): number | null {
|
|
if (fromCurrency === toCurrency) {
|
|
return 1.0;
|
|
}
|
|
|
|
const key = this.getRateKey(fromCurrency, toCurrency);
|
|
const rate = this.rates.get(key);
|
|
|
|
if (!rate) {
|
|
if (fromCurrency !== 'USD' && toCurrency !== 'USD') {
|
|
const fromToUSD = this.getRate(fromCurrency, 'USD', date);
|
|
const usdToTo = this.getRate('USD', toCurrency, date);
|
|
if (fromToUSD && usdToTo) {
|
|
return fromToUSD * usdToTo;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
return rate.rate;
|
|
}
|
|
|
|
convert(amount: number, fromCurrency: string, toCurrency: string, date?: Date): number {
|
|
if (fromCurrency === toCurrency) {
|
|
return amount;
|
|
}
|
|
|
|
const rate = this.getRate(fromCurrency, toCurrency, date);
|
|
if (rate === null) {
|
|
throw new Error(
|
|
`No exchange rate available for ${fromCurrency} to ${toCurrency}`
|
|
);
|
|
}
|
|
|
|
const amountDecimal = new Decimal(amount);
|
|
const rateDecimal = new Decimal(rate);
|
|
return amountDecimal.mul(rateDecimal).toNumber();
|
|
}
|
|
|
|
getUSDEquivalent(amount: number, currency: string, date?: Date): number {
|
|
if (currency === 'USD') {
|
|
return amount;
|
|
}
|
|
return this.convert(amount, currency, 'USD', date);
|
|
}
|
|
}
|
|
|
|
let defaultConverter: CurrencyConverter | null = null;
|
|
|
|
export function getDefaultConverter(): CurrencyConverter {
|
|
if (!defaultConverter) {
|
|
defaultConverter = new SimpleCurrencyConverter();
|
|
}
|
|
return defaultConverter;
|
|
}
|
|
|
|
export function setDefaultConverter(converter: CurrencyConverter): void {
|
|
defaultConverter = converter;
|
|
}
|