Skip to main content

🏦 BCC Rates

Python 3.12+ License: MIT

BCC Rates is a Python library and command-line tool for fetching real-time currency exchange rates from multiple sources including the Banque Centrale du Congo (BCC) and Open Exchange Rates (OXR). It provides both synchronous and asynchronous APIs for seamless integration into your applications.

🌟 Features

  • 📊 Multiple data sources: BCC official website and Open Exchange Rates API
  • 🔄 Synchronous and asynchronous API support
  • 💱 Currency conversion with precise calculations
  • 🔀 Backend comparison - Compare rates from different sources
  • 🖥️ Command-line interface for quick conversions
  • 🎯 Interactive mode for multiple conversions
  • ⚡ Async mode for better performance
  • 🔧 Type hints for better development experience

🚀 Installation

From PyPI (recommended)

pip install bcc-rates

From GitHub

pip install git+https://github.com/oxiliere/bcc_rates.git

From source (development)

git clone https://github.com/oxiliere/bcc_rates.git
cd bcc_rates
pip install -e .

Using uv (recommended for development)

git clone https://github.com/oxiliere/bcc_rates.git
cd bcc_rates
uv sync

📖 Quick Start

Command Line Usage

After installation, use the bcc_exchange command:

# Show all available exchange rates (BCC by default)
bcc_exchange --list

# Convert currencies
bcc_exchange 100 USD EUR

# Use OXR backend
bcc_exchange --backend oxr 100 USD EUR

# Compare rates from both sources
bcc_exchange --compare

# Interactive mode
bcc_exchange --interactive

# Async mode for better performance
bcc_exchange --async-mode 100 USD EUR

# Quiet mode (result only)
bcc_exchange --quiet 1000 EUR CDF

Python API

Synchronous Usage

from bcc_rates import BCCBankSource, OXRBankSource
from dinero import Dinero, currencies

# Initialize the BCC source
bcc = BCCBankSource()

# Get all exchange rates
rates = bcc.sync()
print(f"Found {len(rates)} exchange rates")

# Get specific currency rate
usd_rate = bcc.get_value("USD")
print(f"1 USD = {usd_rate.amount} CDF")

# Currency conversion
amount = Dinero(100, currencies.USD)
converted = bcc.to(amount, "EUR")
print(f"100 USD = {converted.amount} EUR")

# Using OXR backend
import os
os.environ['OXR_API_KEY'] = 'your_api_key_here'

oxr = OXRBankSource()
rates = oxr.sync()
oxr.set_cdf_as_base()  # Convert to CDF base
usd_rate = oxr.get_value("USD")
print(f"1 USD = {usd_rate.amount} CDF (from OXR)")

Asynchronous Usage

import asyncio
from bcc_rates import AsyncBCCBankSource, AsyncOXRBankSource
from dinero import Dinero, currencies

async def main():
    # Initialize async BCC source
    bcc = AsyncBCCBankSource()
    
    # Get all exchange rates
    rates = await bcc.sync()
    print(f"Found {len(rates)} exchange rates")
    
    # Get specific currency rate
    eur_rate = await bcc.get_value("EUR")
    print(f"1 EUR = {eur_rate.amount} CDF")
    
    # Currency conversion
    amount = Dinero(50, currencies.GBP)
    converted = await bcc.to(amount, "USD")
    print(f"50 GBP = {converted.amount} USD")
    
    # Parallel fetching from multiple sources
    oxr = AsyncOXRBankSource()
    bcc_rates, oxr_rates = await asyncio.gather(
        bcc.sync(),
        oxr.sync()
    )
    print(f"BCC: {len(bcc_rates)} rates, OXR: {len(oxr_rates)} rates")

# Run async function
asyncio.run(main())

🛠️ Command Line Interface

The bcc_exchange command provides a powerful CLI for currency operations:

Basic Commands

# Show help
bcc_exchange --help

# List all available currencies and rates
bcc_exchange --list

# Convert 100 USD to EUR
bcc_exchange 100 USD EUR

# Convert 1000 EUR to CDF (Congolese Franc)
bcc_exchange 1000 EUR CDF

# Use async mode for better performance
bcc_exchange --async-mode 50 GBP USD

Backend Selection

# Use BCC backend (default)
bcc_exchange --backend bcc --list
bcc_exchange -b bcc 100 USD EUR

# Use OXR backend (requires API key)
export OXR_API_KEY="your_api_key_here"
bcc_exchange --backend oxr --list
bcc_exchange -b oxr 100 USD CDF

# Compare rates from both sources
bcc_exchange --compare
bcc_exchange -c

# Compare with async mode (faster)
bcc_exchange --compare --async-mode
bcc_exchange -c -a

Interactive Mode

# Interactive mode with BCC
bcc_exchange --interactive

# Interactive mode with OXR
bcc_exchange --backend oxr --interactive

This starts an interactive session where you can perform multiple conversions:

🔄 Interactive Currency Converter (BCC)
Enter 'quit' to exit
------------------------------
Available currencies: AOA, AUD, BIF, CAD, CDF, CHF, CNY, EUR, GBP, JPY, RWF, TZS, UGX, USD, XAF, XDR, ZAR, ZMW

Enter amount (or 'quit'): 100
From currency: USD
To currency: EUR
✅ 100.00 USD = 86.15 EUR

Enter amount (or 'quit'): quit

Quiet Mode

For scripting and automation:

# Returns only the conversion result
bcc_exchange --quiet 100 USD EUR
# Output: 86.1487

📚 API Reference

Classes

BCCBankSource (Synchronous)

class BCCBankSource:
    def __init__(self, url: str = "https://www.bcc.cd/"):
        """Initialize BCC source with optional custom URL."""
    
    def sync(self, cache: bool = True) -> List[SourceValue]:
        """Fetch all exchange rates from BCC."""
    
    def get_value(self, currency: str) -> SourceValue:
        """Get exchange rate for specific currency."""
    
    def get_values(self, currencies: List[str] = None) -> List[SourceValue]:
        """Get exchange rates for multiple currencies."""
    
    def to(self, base: Dinero, target: str | Currency) -> Dinero:
        """Convert currency amount to target currency."""

OXRBankSource (Synchronous)

class OXRBankSource:
    def __init__(self, api_key: str = None):
        """Initialize OXR source with API key (or from OXR_API_KEY env var)."""
    
    def sync(self, cache: bool = True) -> List[SourceValue]:
        """Fetch all exchange rates from OXR API."""
    
    def set_cdf_as_base(self):
        """Convert rates to use CDF as base currency (same format as BCC)."""
    
    def get_value(self, currency: str) -> SourceValue:
        """Get exchange rate for specific currency."""
    
    def get_values(self, currencies: List[str] = None) -> List[SourceValue]:
        """Get exchange rates for multiple currencies."""
    
    def to(self, base: Dinero, target: str | Currency) -> Dinero:
        """Convert currency amount to target currency."""

AsyncBCCBankSource (Asynchronous)

class AsyncBCCBankSource:
    def __init__(self, url: str = "https://www.bcc.cd/"):
        """Initialize async BCC source with optional custom URL."""
    
    async def sync(self, cache: bool = True) -> List[SourceValue]:
        """Fetch all exchange rates from BCC."""
    
    async def get_value(self, currency: str) -> SourceValue:
        """Get exchange rate for specific currency."""
    
    async def get_values(self, currencies: List[str] = None) -> List[SourceValue]:
        """Get exchange rates for multiple currencies."""
    
    async def to(self, base: Dinero, target: str | Currency) -> Dinero:
        """Convert currency amount to target currency."""

AsyncOXRBankSource (Asynchronous)

class AsyncOXRBankSource:
    def __init__(self, api_key: str = None):
        """Initialize async OXR source with API key (or from OXR_API_KEY env var)."""
    
    async def sync(self, cache: bool = True) -> List[SourceValue]:
        """Fetch all exchange rates from OXR API."""
    
    def set_cdf_as_base(self):
        """Convert rates to use CDF as base currency (same format as BCC)."""
    
    async def get_value(self, currency: str) -> SourceValue:
        """Get exchange rate for specific currency."""
    
    async def get_values(self, currencies: List[str] = None) -> List[SourceValue]:
        """Get exchange rates for multiple currencies."""
    
    async def to(self, base: Dinero, target: str | Currency) -> Dinero:
        """Convert currency amount to target currency."""

SourceValue

@dataclass
class SourceValue:
    currency: str  # Currency code (e.g., "USD", "EUR")
    amount: Decimal  # Exchange rate in CDF

Supported Currencies

BCC Backend

Supports all currencies available on the BCC website (~17 currencies):

  • USD - US Dollar
  • EUR - Euro
  • GBP - British Pound
  • CAD - Canadian Dollar
  • CHF - Swiss Franc
  • JPY - Japanese Yen
  • CNY - Chinese Yuan
  • AUD - Australian Dollar
  • ZAR - South African Rand
  • CDF - Congolese Franc (base currency)
  • And more...

OXR Backend

Supports 170+ currencies from Open Exchange Rates API, including all major world currencies.

Note: OXR requires an API key. Get one free at openexchangerates.org

🧪 Development

Setting up Development Environment

# Clone the repository
git clone https://github.com/oxiliere/bcc_rates.git
cd bcc_rates

# Install with uv (recommended)
uv sync

# Or with pip
pip install -e ".[dev]"

Running Tests

# Run all tests
uv run python -m pytest

# Run with coverage
uv run python -m pytest --cov=bcc_rates

# Run specific test file
uv run python src/tests.py

Running CLI in Development

# Using uv (recommended)
uv run python -m bcc_rates --help
uv run python -m bcc_rates 100 USD EUR

# Direct execution
uv run python src/bcc_rates/cli.py --help

Code Quality

# Format code
uv run black src/

# Type checking
uv run mypy src/

# Linting
uv run flake8 src/

📋 Examples

Basic Currency Conversion

from bcc_rates import BCCBankSource
from dinero import currencies, Dinero

bcc = BCCBankSource()

# Convert 100 USD to EUR
usd_amount = Dinero(100, currencies.USD)
eur_amount = bcc.to(usd_amount, "EUR")
print(f"100 USD = {eur_amount.amount:.2f} EUR")

# Convert 1000 EUR to CDF
eur_amount = Dinero(1000, currencies.EUR)
cdf_amount = bcc.to(eur_amount, "CDF")
print(f"1000 EUR = {cdf_amount.amount:,.2f} CDF")

Batch Processing

from bcc_rates import BCCBankSource

bcc = BCCBankSource()

# Get rates for specific currencies
currencies_of_interest = ["USD", "EUR", "GBP", "CAD"]
rates = bcc.get_values(currencies_of_interest)

for rate in rates:
    print(f"1 {rate.currency} = {rate.amount:,.4f} CDF")

Async Batch Processing

import asyncio
from bcc_rates import AsyncBCCBankSource

async def get_multiple_rates():
    bcc = AsyncBCCBankSource()
    
    # Fetch all rates
    rates = await bcc.sync()
    
    # Process rates
    major_currencies = ["USD", "EUR", "GBP", "JPY"]
    for currency in major_currencies:
        try:
            rate = await bcc.get_value(currency)
            print(f"1 {currency} = {rate.amount:,.4f} CDF")
        except ValueError:
            print(f"{currency} not available")

asyncio.run(get_multiple_rates())

Comparing Multiple Sources

import asyncio
from bcc_rates import AsyncBCCBankSource, AsyncOXRBankSource

async def compare_sources():
    bcc = AsyncBCCBankSource()
    oxr = AsyncOXRBankSource()
    
    # Fetch from both sources in parallel
    bcc_rates, oxr_rates = await asyncio.gather(
        bcc.sync(),
        oxr.sync()
    )
    
    # Convert OXR to CDF base
    oxr.set_cdf_as_base()
    
    # Compare USD rates
    bcc_usd = await bcc.get_value("USD")
    oxr_usd = await oxr.get_value("USD")
    
    print(f"BCC: 1 USD = {bcc_usd.amount:,.4f} CDF")
    print(f"OXR: 1 USD = {oxr_usd.amount:,.4f} CDF")
    print(f"Difference: {abs(bcc_usd.amount - oxr_usd.amount):,.4f} CDF")

asyncio.run(compare_sources())

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

Development Guidelines

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

  • Banque Centrale du Congo (BCC) for providing the exchange rate data
  • Open Exchange Rates for their comprehensive currency API
  • Dinero library for currency handling
  • BeautifulSoup for HTML parsing
  • aiohttp for async HTTP requests
  • requests for synchronous HTTP requests

📞 Support

If you encounter any issues or have questions:

  1. Check the Issues page
  2. Create a new issue if your problem isn't already reported
  3. Provide detailed information about your environment and the issue

🔗 Links


Made with ❤️ for the Congolese developer community

Metadata

Release files for bcc-rates 1.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bcc-rates 1.1.1
File Size Uploaded Provenance
bcc_rates-1.1.1.tar.gz 11.2 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for bcc-rates 1.1.1
File Interpreter ABI Platform
bcc_rates-1.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 26.2 kB

Release files / bcc_rates-1.1.1.tar.gz

Download URL bcc_rates-1.1.1.tar.gz
Size 11.2 kB
Tags Source
SHA-256 checksum
How to use checksums
1d7ef4595b93f078ce8934f282a30e263f4df6a55cd98475d6fb0d70c59b9889
BLAKE2b-256 checksum
How to use checksums
aaab5118d9adb05a41f96c73a0779bd1cbdf173c842fd25dda228eca18ce1850
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / bcc_rates-1.1.1-py3-none-any.whl

Download URL bcc_rates-1.1.1-py3-none-any.whl
Size 15.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
08285a233e403abaeda19ba09fc226994218e902c1f20d32fc5a5fb9080449a0
BLAKE2b-256 checksum
How to use checksums
a83cb1347f4849b4143eed247f7945007cc2bf42092450493884233dababa3fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for bcc-rates 1.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page