from typing import Dict from django.db.models import Func, F, Value from django.db.models.functions import Extract from django.utils import timezone from apps.currencies.models import ExchangeRate def get_currency_exchange_map(date=None) -> Dict[str, dict]: """ Creates a nested dictionary of exchange rates and currency information. Returns: { 'BTC': { 'decimal_places': 8, 'prefix': '₿', 'suffix': '', 'rates': {'USD': Decimal('34000.00'), 'EUR': Decimal('31000.00')} }, 'USD': { 'decimal_places': 2, 'prefix': '$', 'suffix': '', 'rates': {'BTC': Decimal('0.0000294'), 'EUR': Decimal('0.91')} }, ... } """ if date is None: date = timezone.localtime(timezone.now()) # Get all exchange rates for the closest date exchange_rates = ( ExchangeRate.objects.select_related( "from_currency", "to_currency" ) # Optimize currency queries .annotate( date_diff=Func(Extract(F("date") - Value(date), "epoch"), function="ABS"), effective_rate=F("rate"), ) .order_by("from_currency", "to_currency", "-date_diff") .distinct() ) # Initialize the result dictionary rate_map = {} # Build the exchange rate mapping with currency info for rate in exchange_rates: # Add from_currency info if not exists if rate.from_currency.name not in rate_map: rate_map[rate.from_currency.name] = { "decimal_places": rate.from_currency.decimal_places, "prefix": rate.from_currency.prefix, "suffix": rate.from_currency.suffix, "rates": {}, } # Add to_currency info if not exists if rate.to_currency.name not in rate_map: rate_map[rate.to_currency.name] = { "decimal_places": rate.to_currency.decimal_places, "prefix": rate.to_currency.prefix, "suffix": rate.to_currency.suffix, "rates": {}, } # Add direct rate rate_map[rate.from_currency.name]["rates"][rate.to_currency.name] = { "rate": rate.rate, "decimal_places": rate.to_currency.decimal_places, "prefix": rate.to_currency.prefix, "suffix": rate.to_currency.suffix, } # Add inverse rate rate_map[rate.to_currency.name]["rates"][rate.from_currency.name] = { "rate": 1 / rate.rate, "decimal_places": rate.from_currency.decimal_places, "prefix": rate.from_currency.prefix, "suffix": rate.from_currency.suffix, } return rate_map