Python Currency Converter Project

Python project 12

Python Currency Converter Project

Create a currency converter that retrieves current reference rates from the public Frankfurter v2 API. It validates three-letter currency codes, uses Decimal for money-safe arithmetic, handles network failures, and shows the date of the rate used.

Learn Python with mentor-guided projectsView all project ideas

What you will build

The user enters a base currency, target currency, and amount. The program retrieves one current rate, calculates the converted value, rounds it to two decimal places, and clearly labels the result as a reference rate rather than a bank quote.

Skills practised

  • HTTPS API requests
  • JSON response handling
  • Decimal arithmetic
  • Network and input errors

Requirements

  • Python 3.10 or later
  • An internet connection
  • No API key or external package
  • About 35 minutes to build

Full Python code

Save this code as currency_converter.py, then follow the run instructions below.

"""Convert currencies with the public Frankfurter v2 exchange-rate API."""

from __future__ import annotations

import json
from decimal import Decimal, InvalidOperation, ROUND_HALF_UP
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen


API_ROOT = "https://api.frankfurter.dev/v2"


def read_currency(prompt: str) -> str:
    while True:
        code = input(prompt).strip().upper()
        if len(code) == 3 and code.isascii() and code.isalpha():
            return code
        print("Enter a three-letter currency code such as INR, USD, or EUR.")


def read_amount() -> Decimal:
    while True:
        try:
            amount = Decimal(input("Amount: ").strip())
            if not amount.is_finite() or amount < 0:
                raise InvalidOperation
            return amount
        except InvalidOperation:
            print("Enter a valid zero or positive amount.")


def fetch_rate(base: str, quote: str) -> tuple[Decimal, str]:
    """Return the latest rate and provider date for one currency pair."""
    if base == quote:
        return Decimal("1"), "same currency"

    url = f"{API_ROOT}/rate/{base}/{quote}"
    request = Request(url, headers={"User-Agent": "SoftenantCurrencyProject/1.0"})
    try:
        with urlopen(request, timeout=10) as response:
            data = json.loads(response.read().decode("utf-8"), parse_float=Decimal)
        return Decimal(data["rate"]), str(data["date"])
    except HTTPError as error:
        if error.code == 422:
            raise ValueError("The API did not recognise one of those currency codes.") from error
        raise ConnectionError(f"The rate service returned HTTP {error.code}.") from error
    except (URLError, TimeoutError) as error:
        raise ConnectionError("Could not reach the exchange-rate service.") from error
    except (json.JSONDecodeError, KeyError, TypeError, InvalidOperation) as error:
        raise ConnectionError("The rate service returned an unexpected response.") from error


def convert(amount: Decimal, rate: Decimal) -> Decimal:
    return (amount * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)


def main() -> None:
    print("Python Currency Converter")
    print("Rates are reference rates, not bank or card transaction quotes.\n")

    base = read_currency("From currency: ")
    quote = read_currency("To currency: ")
    amount = read_amount()

    try:
        rate, rate_date = fetch_rate(base, quote)
    except (ValueError, ConnectionError) as error:
        print(f"Conversion failed: {error}")
        return

    result = convert(amount, rate)
    print(f"\n{amount:.2f} {base} = {result:.2f} {quote}")
    print(f"Reference rate: 1 {base} = {rate} {quote} ({rate_date})")


if __name__ == "__main__":
    main()

How the project works

fetch_rate() calls the documented /v2/rate/BASE/QUOTE endpoint and parses JSON floating-point values directly as Decimal. A timeout prevents the program from waiting indefinitely.

convert() multiplies the user amount by the reference rate and applies explicit two-decimal, half-up rounding. Currency markets and retail providers differ, so the displayed result should not be presented as a guaranteed card, bank, or cash-exchange price.

Run the project

  1. Run python currency_converter.py.
  2. Enter codes such as INR, USD, or EUR.
  3. Enter a zero or positive amount.
  4. Read the converted result, rate, and provider date.

Accuracy and safety notes

  • Source: Frankfurter aggregates reference-rate providers and requires no API key.
  • Precision: Decimal avoids common binary floating-point surprises.
  • Timing: reference rates update when providers publish; they are not tick-by-tick trading prices.

Ways to extend it

Add a currency list, historical-date input, cached rates, a Tkinter interface, or a comparison between several target currencies. Read the official Frankfurter Python guide before extending the API calls.

Continue learning Python

Build the next project, return to the Softenant project library, or explore the Python programming course in Vizag for structured lessons, mentor feedback, and portfolio practice.