feat(currencies): add automatic exchange rate fetching

Closes #123
This commit is contained in:
Herculino Trotta
2025-02-05 10:16:04 -03:00
parent 80edf557cb
commit d207760ae9
18 changed files with 1244 additions and 343 deletions
@@ -6,7 +6,8 @@ from django.utils import timezone
from apps.currencies.exchange_rates.providers import (
SynthFinanceProvider,
CoinGeckoProvider,
CoinGeckoFreeProvider,
CoinGeckoProProvider,
)
from apps.currencies.models import ExchangeRateService, ExchangeRate, Currency
@@ -16,7 +17,8 @@ logger = logging.getLogger(__name__)
# Map service types to provider classes
PROVIDER_MAPPING = {
"synth_finance": SynthFinanceProvider,
"coingecko": CoinGeckoProvider,
"coingecko_free": CoinGeckoFreeProvider,
"coingecko_pro": CoinGeckoProProvider,
}
@@ -31,7 +33,7 @@ class ExchangeRateFetcher:
If False, only fetches services that are due according to their interval.
"""
services = ExchangeRateService.objects.filter(is_active=True)
current_time = timezone.now()
current_time = timezone.now().replace(minute=0, second=0, microsecond=0)
for service in services:
try:
@@ -47,9 +49,9 @@ class ExchangeRateFetcher:
continue
# Calculate when the next fetch should occur
next_fetch_due = service.last_fetch + timedelta(
hours=service.fetch_interval_hours
)
next_fetch_due = (
service.last_fetch + timedelta(hours=service.fetch_interval_hours)
).replace(minute=0, second=0, microsecond=0)
# Check if it's time for the next fetch
if current_time >= next_fetch_due:
@@ -77,8 +77,8 @@ class SynthFinanceProvider(ExchangeRateProvider):
return results
class CoinGeckoProvider(ExchangeRateProvider):
"""Implementation for CoinGecko API"""
class CoinGeckoFreeProvider(ExchangeRateProvider):
"""Implementation for CoinGecko Free API"""
BASE_URL = "https://api.coingecko.com/api/v3"
rates_inverted = True
@@ -138,3 +138,15 @@ class CoinGeckoProvider(ExchangeRateProvider):
logger.error(f"Error fetching rates from CoinGecko API: {e}")
return results
class CoinGeckoProProvider(CoinGeckoFreeProvider):
"""Implementation for CoinGecko Pro API"""
BASE_URL = "https://pro-api.coingecko.com/api/v3/simple/price"
rates_inverted = True
def __init__(self, api_key: str):
super().__init__(api_key)
self.session = requests.Session()
self.session.headers.update({"x-cg-pro-api-key": api_key})