import requests
import json
import os
from datetime import datetime, timedelta
from typing import Dict, Optional
class CurrencyConverter:
def __init__(self, api_key: str, cache_duration_hours: int = 1):
"""
Initialize the CurrencyConverter with API key and cache settings.
Args:
api_key (str): Your ExchangeRate-API key
cache_duration_hours (int): How long to cache exchange rates (default: 1 hour)
"""
self.api_key = api_key
self.cache_duration = timedelta(hours=cache_duration_hours)
self.cache_file = "exchange_rates_cache.json"
self.base_url = f"https://v6.exchangerate-api.com/v6/{api_key}/latest/USD"
def _load_cache(self) -> Dict:
"""Load exchange rates from cache file if it exists and is valid."""
if not os.path.exists(self.cache_file):
return {}
try:
with open(self.cache_file, 'r') as f:
cache_data = json.load(f)
# Check if cache is still valid
cache_time = datetime.fromisoformat(cache_data.get('timestamp', '2000-01-01T00:00:00'))
if datetime.now() - cache_time < self.cache_duration:
return cache_data
else:
return {}
except (json.JSONDecodeError, KeyError):
return {}
def _save_cache(self, data: Dict):
"""Save exchange rates to cache file with timestamp."""
data['timestamp'] = datetime.now().isoformat()
with open(self.cache_file, 'w') as f:
json.dump(data, f)
def _fetch_exchange_rates(self) -> Dict:
"""Fetch latest exchange rates from API."""
try:
response = requests.get(self.base_url)
response.raise_for_status()
data = response.json()
if data.get('result') == 'success':
# Save to cache
self._save_cache(data)
return data
else:
raise Exception(f"API Error: {data.get('error-type', 'Unknown error')}")
except requests.RequestException as e:
raise Exception(f"Network error: {str(e)}")
def get_exchange_rates(self) -> Dict:
"""Get exchange rates, either from cache or API."""
# Try to load from cache first
cached_data = self._load_cache()
if cached_data:
return cached_data
# If cache is invalid/expired, fetch from API
return self._fetch_exchange_rates()
def convert(self, amount: float, from_currency: str, to_currency: str) -> float:
"""
Convert amount from one currency to another.
Args:
amount (float): Amount to convert
from_currency (str): Source currency code (e.g., 'USD')
to_currency (str): Target currency code (e.g., 'EUR')
Returns:
float: Converted amount
"""
rates_data = self.get_exchange_rates()
rates = rates_data.get('conversion_rates', {})
# Validate currencies
if from_currency not in rates:
raise ValueError(f"Unsupported currency: {from_currency}")
if to_currency not in rates:
raise ValueError(f"Unsupported currency: {to_currency}")
# Convert to USD first (base currency)
usd_amount = amount / rates[from_currency]
# Convert from USD to target currency
result = usd_amount * rates[to_currency]
return round(result, 2)
# Example usage
if __name__ == "__main__":
# Replace with your actual API key from https://www.exchangerate-api.com/
API_KEY = "your_api_key_here"
converter = CurrencyConverter(API_KEY)
try:
# Convert 100 USD to EUR
result = converter.convert(100, 'USD', 'EUR')
print(f"100 USD = {result} EUR")
# Convert 50 EUR to GBP
result = converter.convert(50, 'EUR', 'GBP')
print(f"50 EUR = {result} GBP")
# Get all available exchange rates
rates = converter.get_exchange_rates()
print(f"Available currencies: {len(rates['conversion_rates'])}")
except Exception as e:
print(f"Error: {e}")
This Python snippet creates a CurrencyConverter class that handles real-time currency conversion with intelligent caching. It connects to the ExchangeRate-API service to fetch current exchange rates and automatically caches them locally to minimize API calls and improve performance.
your_api_key_here in the example with your actual API keypip install requestsThe converter can handle conversions between any supported currencies:
The cache file automatically stores exchange rates in a JSON file, which persists between runs and invalidates itself after the specified duration.