Cómo crear un conversor de monedas con Python

Publicado el: 11/07/2026
Tempo de leitura: 5 minutos
Conversor de moedas desenvolvido com Python

Un conversor de monedas es un proyecto excelente para practicar entrada de datos, funciones, solicitudes HTTP, validación y manejo de errores. La aplicación recibe un importe, una moneda de origen y otra de destino, consulta una tasa actual y devuelve el valor convertido. Aunque el cálculo es sencillo, un programa confiable debe gestionar códigos inválidos, fallos de red, datos incompletos y fechas de actualización.

Antes de comenzar, revisa la biblioteca Requests en Python, el manejo de excepciones, las funciones, las variables de entorno y el trabajo con diccionarios.

Cómo funciona la conversión

La fórmula básica es:

resultado = importe * tasa

Si un euro equivale a 1,08 dólares, convertir 100 EUR produce 108 USD. La dificultad está en obtener una tasa adecuada y saber qué representa. Algunas APIs devuelven tasas respecto a una moneda base; otras permiten solicitar directamente el par deseado.

El Banco Central Europeo publica tipos de referencia para varias monedas. Para un proyecto educativo también puede utilizarse la documentación de la API Frankfurter, que ofrece datos basados en fuentes públicas. Ninguna tasa de referencia garantiza el importe exacto que cobrará un banco, una tarjeta o una casa de cambio.

Preparar el entorno

python -m venv .venv
.venv\Scripts\activate
python -m pip install requests

En macOS o Linux activa el entorno con source .venv/bin/activate. Evita instalar dependencias globalmente, porque distintos proyectos pueden requerir versiones diferentes.

Primera consulta a la API

import requests

url = "https://api.frankfurter.app/latest"
parametros = {
    "amount": 100,
    "from": "EUR",
    "to": "USD",
}

respuesta = requests.get(url, params=parametros, timeout=10)
respuesta.raise_for_status()
datos = respuesta.json()
print(datos)

El parámetro timeout evita que el programa espere indefinidamente. raise_for_status() transforma respuestas HTTP de error en excepciones que pueden manejarse.

Extraer el resultado

resultado = datos["rates"]["USD"]
fecha = datos["date"]
print(f"100 EUR = {resultado:.2f} USD")
print(f"Tasa de referencia: {fecha}")

No asumas que todas las claves existen. Una respuesta de error puede tener una estructura distinta. Utiliza acceso seguro y valida tipos.

Crear una función reutilizable

from decimal import Decimal, InvalidOperation
import requests

API_URL = "https://api.frankfurter.app/latest"


def convertir_moneda(importe, origen, destino):
    origen = origen.strip().upper()
    destino = destino.strip().upper()

    if len(origen) != 3 or len(destino) != 3:
        raise ValueError("Los códigos deben tener tres letras")

    if origen == destino:
        return {
            "resultado": Decimal(str(importe)),
            "fecha": None,
            "origen": origen,
            "destino": destino,
        }

    parametros = {
        "amount": str(importe),
        "from": origen,
        "to": destino,
    }

    respuesta = requests.get(API_URL, params=parametros, timeout=10)
    respuesta.raise_for_status()
    datos = respuesta.json()

    tasas = datos.get("rates", {})
    if destino not in tasas:
        raise ValueError("La respuesta no contiene la moneda solicitada")

    return {
        "resultado": Decimal(str(tasas[destino])),
        "fecha": datos.get("date"),
        "origen": origen,
        "destino": destino,
    }

Decimal ayuda a conservar una representación decimal controlada. Aun así, la precisión final depende de la tasa proporcionada por el servicio.

Validar la entrada del usuario

def leer_importe():
    while True:
        texto = input("Importe: ").strip().replace(",", ".")
        try:
            valor = Decimal(texto)
            if valor < 0:
                print("El importe no puede ser negativo")
                continue
            return valor
        except InvalidOperation:
            print("Introduce un número válido")

En una aplicación real debes decidir si el valor cero es aceptable y qué límites aplicar. Los códigos de moneda deben compararse con una lista admitida, no solo por longitud.

Obtener las monedas disponibles

def obtener_monedas():
    respuesta = requests.get(
        "https://api.frankfurter.app/currencies",
        timeout=10,
    )
    respuesta.raise_for_status()
    datos = respuesta.json()
    if not isinstance(datos, dict):
        raise ValueError("Formato inesperado")
    return datos

Esta información puede almacenarse temporalmente porque no cambia con frecuencia. Así evitas una solicitud adicional en cada conversión.

Programa de terminal completo

def main():
    print("Conversor de monedas")
    importe = leer_importe()
    origen = input("Moneda de origen (EUR): ").strip().upper()
    destino = input("Moneda de destino (USD): ").strip().upper()

    try:
        datos = convertir_moneda(importe, origen, destino)
    except requests.Timeout:
        print("La consulta tardó demasiado")
        return
    except requests.ConnectionError:
        print("No hay conexión con el servicio")
        return
    except requests.HTTPError as error:
        print(f"El servicio devolvió un error: {error.response.status_code}")
        return
    except (ValueError, KeyError) as error:
        print(f"Datos inválidos: {error}")
        return

    resultado = datos["resultado"]
    print(
        f"{importe:.2f} {datos['origen']} = "
        f"{resultado:.2f} {datos['destino']}"
    )
    if datos["fecha"]:
        print(f"Fecha de referencia: {datos['fecha']}")


if __name__ == "__main__":
    main()

Calcular la tasa implícita

tasa = resultado / importe if importe else Decimal("0")
print(f"1 {origen} = {tasa:.6f} {destino}")

No calcules la tasa cuando el importe sea cero. La cantidad de decimales visible depende del uso: dos pueden ser suficientes para el resultado monetario, pero una tasa suele necesitar más.

Separar lógica, red e interfaz

Un diseño mantenible divide el proyecto:

conversor/
├── api.py
├── servicio.py
├── validacion.py
├── main.py
└── tests/

api.py consulta el servicio. servicio.py aplica reglas. validacion.py comprueba entradas. main.py conversa con el usuario. Esta separación permite probar el cálculo sin realizar solicitudes reales.

Usar caché

Si muchas personas consultan el mismo par, guarda la tasa durante un período corto:

from datetime import datetime, timedelta, timezone

cache = {}


def guardar_tasa(clave, valor):
    cache[clave] = {
        "valor": valor,
        "expira": datetime.now(timezone.utc) + timedelta(minutes=30),
    }

Antes de reutilizarla, confirma que no haya expirado. Una caché reduce llamadas y mantiene el programa funcional ante interrupciones breves, pero debes mostrar la fecha para no presentar un valor antiguo como actual.

Conversión sin conexión

Puedes guardar la última respuesta en JSON y usarla como respaldo:

import json
from pathlib import Path

RUTA_CACHE = Path("tasas_cache.json")


def guardar_cache(datos):
    RUTA_CACHE.write_text(
        json.dumps(datos, ensure_ascii=False, indent=2),
        encoding="utf-8",
    )

Al utilizar datos guardados, informa claramente que son tasas anteriores. No ocultes la falta de conexión.

Claves de API y seguridad

Algunos proveedores requieren una clave. Nunca la escribas directamente en el repositorio:

import os

api_key = os.getenv("EXCHANGE_API_KEY")
if not api_key:
    raise RuntimeError("Falta EXCHANGE_API_KEY")

Usa variables de entorno, limita los permisos y rota la clave si se publica accidentalmente.

Probar sin depender de Internet

Simula la respuesta HTTP con un mock. Prueba un resultado correcto, timeout, código 500, JSON inválido, moneda ausente y origen igual a destino. También prueba importes con coma, valores negativos y números muy grandes.

Crear una interfaz gráfica

Cuando la versión de terminal funcione, puedes añadir Tkinter. La interfaz debe llamar a la misma función de conversión en lugar de duplicar el cálculo. Realiza la solicitud fuera del hilo principal para que la ventana no se congele y desactiva el botón mientras la consulta está en curso.

Limitaciones importantes

Las tasas de referencia no incluyen comisiones, margen comercial, impuestos ni diferencias entre compra y venta. Tampoco representan necesariamente cotizaciones en tiempo real. Muestra la fuente, la fecha y una advertencia cuando el resultado se utilice para planificación financiera.

Errores frecuentes

No hagas solicitudes sin timeout. No confíes ciegamente en el JSON. No uses una clave pública dentro del código. No redondees antes de terminar el cálculo y no confundas el símbolo con el código ISO. Evita consultar la API en cada pulsación del teclado y respeta los límites del proveedor.

Conclusión

Un conversor de monedas combina una operación sencilla con prácticas reales de software: validación, HTTP, JSON, precisión decimal, caché y manejo de fallos. Separa la lógica de la interfaz, utiliza una fuente confiable, conserva la fecha de referencia y comunica las limitaciones. Con esta base puedes crear una herramienta de terminal, una aplicación gráfica o un pequeño servicio web sin duplicar la lógica principal.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    texto Tkinter com uma interface gráfica dele ao lado
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear tu primera aplicación con Tkinter

    Crea tu primera aplicación con Tkinter: ventanas, ttk, formularios, grid, eventos, archivos, threads, estilos y separación de lógica.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Sistema de lembretes e alarmes desenvolvido com Python
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un sistema de recordatorios con alarma en Python

    Crea recordatorios con alarma en Python usando datetime, JSON, threads, zonas horarias, sonidos, recurrencia y pruebas controladas.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Foto de uma pessoa usando uma calculadora
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear una calculadora en Python paso a paso

    Crea una calculadora en Python con funciones, menú, validación, Decimal, historial, pruebas y una base segura para añadir Tkinter.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Landing page simples criada com Python e Tailwind CSS
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear una landing page con Python y Tailwind CSS

    Crea una landing page con Flask y Tailwind CSS: diseño responsivo, formularios, validación, SQLite, seguridad, SEO y despliegue.

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Extração de dados de tabelas de sites usando Python e pandas
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo extraer tablas de sitios web con Python y Pandas

    Extrae tablas de sitios web con Pandas, Requests y Beautiful Soup, limpia columnas, pagina resultados y exporta datos de forma

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026
    Integração de bots Discord com Python para automação
    Proyectos
    Foto de perfil de Leandro Hirt da Academify

    Cómo crear un bot de Discord con Python

    Crea un bot de Discord con Python y discord.py: comandos, slash commands, permisos, intents, Cogs, tareas, logs y seguridad del

    Ler mais

    Tempo de leitura: 4 minutos
    11/07/2026