Skip to main content

twrate 🇹🇼 — Taiwan Exchange Rate API and CLI for Python

twrate is a Python package and command-line tool for querying live foreign exchange rates from Taiwanese banks. It fetches TWD exchange-rate board data from multiple bank sources concurrently, so you can compare spot rates, cash rates, mid-rates, and spreads for currencies such as USD/TWD, JPY/TWD, EUR/TWD, and more.

Use twrate when you need a lightweight Taiwan exchange rate API for scripts, data pipelines, dashboards, or terminal-based rate checks.

✨ Features

  • 🏦 Taiwan bank exchange rates from 17 supported banks.
  • ⚡ Async Python API built for concurrent fan-out with asyncio and httpx.
  • 💱 CLI for quick lookup: run twrate USD to compare USD/TWD rates across banks.
  • 📊 Normalized Rate model with spot buy/sell, cash buy/sell, mid-rate, spread, currency pair, and fetch timestamp.
  • ✅ Typed package with Pydantic validation and py.typed support.
  • 🧩 Bank-specific fetchers that keep each source isolated and easy to maintain.

🏦 Supported Taiwanese banks

Bank Chinese name Exchange enum
Bank of Taiwan 台灣銀行 Exchange.BOT
DBS Bank Taiwan 星展銀行 Exchange.DBS
SinoPac Bank 永豐銀行 Exchange.SINOPAC
E.SUN Bank 玉山銀行 Exchange.ESUN
LINE Bank LINE Bank Exchange.LINE
HSBC Bank Taiwan 匯豐銀行 Exchange.HSBC
Next Bank 將來銀行 Exchange.NEXT
KGI Bank 凱基銀行 Exchange.KGI
Cathay United Bank 國泰世華銀行 Exchange.CATHAY
Mega International Commercial Bank 兆豐銀行 Exchange.MEGABANK
First Bank 第一銀行 Exchange.FIRSTBANK
Land Bank of Taiwan 土地銀行 Exchange.LANDBANK
Yuanta Bank 元大銀行 Exchange.YUANTA
Taishin Bank 台新銀行 Exchange.TAISHIN
Taichung Bank 台中銀行 Exchange.TAICHUNG
Taiwan Cooperative Bank 合作金庫 Exchange.COOPERATIVE
Fubon Bank 台北富邦銀行 Exchange.FUBON

Availability depends on each bank's public website or API. Some banks may publish only spot rates, only selected currencies, or temporarily unavailable data.

📦 Installation

twrate requires Python 3.12 or later.

pip install twrate

For local development, use uv:

uv sync
uv run twrate USD

You can also run the CLI without installing it into the current environment:

uvx twrate USD

🚀 Quick start

💱 Compare USD/TWD rates in the terminal

twrate USD

Example output:

                            USD 各行即時牌價
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━┓
┃ 銀行                ┃ 即期買進 ┃ 即期賣出 ┃ 即期點差 ┃ 現鈔買進 ┃ 現鈔賣出 ┃ 現鈔點差 ┃
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━┩
│ 台灣銀行 (Bank ... │ 30.0950  │ 30.2450  │ 0.50%    │ 29.7700  │ 30.4400  │ 2.22%    │
│ 星展銀行 (DBS ...  │ 30.0760  │ 30.2790  │ 0.67%    │ 29.8630  │ 30.4700  │ 2.01%    │
└─────────────────────┴──────────┴──────────┴──────────┴──────────┴──────────┴──────────┘

🐍 Fetch rates from one bank in Python

import asyncio

from twrate import Exchange, fetch_rates


async def main() -> None:
    rates = await fetch_rates(Exchange.BOT)

    usd_rates = [rate for rate in rates if rate.source == "USD"]
    for rate in usd_rates:
        print(rate.symbol, rate.spot_buy, rate.spot_sell, rate.spot_spread)


if __name__ == "__main__":
    asyncio.run(main())

⚡ Fetch all banks concurrently

import asyncio

from twrate import Exchange, Rate, fetch_rates


async def fetch_all_rates() -> list[Rate]:
    tasks = [fetch_rates(exchange) for exchange in Exchange]
    results = await asyncio.gather(*tasks, return_exceptions=True)

    rates: list[Rate] = []
    for exchange, result in zip(Exchange, results, strict=False):
        if isinstance(result, Exception):
            print(f"Failed to fetch {exchange.value}: {result}")
            continue

        rates.extend(result)

    return rates


if __name__ == "__main__":
    all_rates = asyncio.run(fetch_all_rates())
    usd_rates = [rate for rate in all_rates if rate.source == "USD"]
    print(usd_rates)

📊 Rate model

Each fetcher returns a list of normalized Rate objects:

Field or property Description
exchange Bank identifier, such as Exchange.BOT or Exchange.DBS.
source Source currency code, such as USD, JPY, or EUR.
target Target currency code. For this package, it is usually TWD.
spot_buy Bank spot buying rate.
spot_sell Bank spot selling rate.
cash_buy Bank cash buying rate, if available.
cash_sell Bank cash selling rate, if available.
fetched_at Timestamp generated when the Rate object is created.
spot_mid Mid-rate calculated from spot_buy and spot_sell.
cash_mid Mid-rate calculated from cash_buy and cash_sell.
spot_spread Relative spread for spot transactions.
cash_spread Relative spread for cash transactions.
symbol Currency pair string, for example USD/TWD.

Missing or zero bank values are normalized to None.

🛠️ Development

Install dependencies and run commands through uv:

uv sync
uv run pytest
uv run twrate USD

Run the full test suite with coverage:

uv run pytest -v -s --cov=src tests

🤝 Contributing

Contributions are welcome. Good first issues include:

  • Fixing a bank fetcher when a public page or API changes.
  • Adding tests and sample fixtures for existing fetchers.
  • Improving parsing for currencies with partial spot or cash data.
  • Adding a new Taiwanese bank source while preserving the shared Rate model.

When adding or updating a fetcher, keep it bank-specific, async-first, and covered by tests where possible.

📄 License

twrate is released under the terms in LICENSE.

Metadata

Release files for twrate 0.5.2

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

Source distribution (sdist)

Source distribution for twrate 0.5.2
File Size Uploaded
twrate-0.5.2.tar.gz 67.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for twrate 0.5.2
File Interpreter ABI Platform
twrate-0.5.2-py3-none-any.whl Python 3 none any Details

Total release size: 98.4 kB

Release files / twrate-0.5.2.tar.gz

Download URL twrate-0.5.2.tar.gz
Size 67.0 kB
Tags Source
SHA-256 checksum
How to use checksums
589fa5f997d50ebcf2521cdb3eb782e5bd610387fe667327f1b1d7c0393873e9
BLAKE2b-256 checksum
How to use checksums
f005fb90447b84c64874d4834bca2bdd097b69c0ed33131dd0255bb7d03614d0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / twrate-0.5.2-py3-none-any.whl

Download URL twrate-0.5.2-py3-none-any.whl
Size 31.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
04884f10989ae910c676beb6358bcd8efa05a49b4625f571b709436d2c379231
BLAKE2b-256 checksum
How to use checksums
1b7add2f71a07ad05861bf3b4428ef61db6f30159e8fe356d673e7b14ea4c5be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.5.2 This release

2 release files

0.5.1

2 release files

0.5.0

1 release file

0.4.0

1 release file

0.3.0

1 release file

0.2.1

1 release file

0.2.0

1 release file

0.1.5

1 release file

0.1.4

1 release file

0.1.3

1 release file

0.1.2

1 release file

0.1.1

1 release file

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