Skip to main content

No project description provided

Project description

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

twrate-0.5.1.tar.gz (63.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

twrate-0.5.1-py3-none-any.whl (28.8 kB view details)

Uploaded Python 3

File details

Details for the file twrate-0.5.1.tar.gz.

File metadata

  • Download URL: twrate-0.5.1.tar.gz
  • Upload date:
  • Size: 63.3 kB
  • Tags: Source
  • Uploaded using 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}

File hashes

Hashes for twrate-0.5.1.tar.gz
Algorithm Hash digest
SHA256 a056e80952f7b463b3fa256a733962580c6b278e1815df7d38b6cbc0deb5fdd7
MD5 4686bb9e0b4167d8806fa5af6d2a790b
BLAKE2b-256 1d3a5efdb63b9c90e136f7af0d6390d9d7397187032007375fef14701356066b

See more details on using hashes here.

File details

Details for the file twrate-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: twrate-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 28.8 kB
  • Tags: Python 3
  • Uploaded using 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}

File hashes

Hashes for twrate-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 09de6409795c5cffbd0eaa00e4790a222558c5715baed9e0daf5da77e52997cc
MD5 1f9a4c48f4002168b69c44cd621fb84d
BLAKE2b-256 ee2475506b15ca0a5a696c53f7dde8675629f2dc7962b4776b0ddf1895d02c9c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page