Skill: darbling/currency-converter-pro (version 1.0.2)

--- name: currency-converter-pro description: 实时汇率换算专家。支持150+货币实时汇率、批量换算、多货币对比、历史汇率查询。零API Key，免费数据源。When user asks about currency exchange, conversion rates, USD to CNY, forex, or money conversion. --- # Currency Converter Pro **实时汇率换算专家** | Author: Lin Hui | Version 1.0.0 | MIT License 支持150+货币实时汇率查询、批量换算、历史汇率对比。零API Key，免费数据源。 ## 核心功能 - ✅ 实时汇率查询（150+货币） - ✅ 任意金额多货币换算 - ✅ 多货币横向对比（1000美元能换多少各货币） - ✅ 历史汇率查询 - ✅ 零API Key，免费数据源 - ✅ 支持主要货币：CNY、USD、EUR、GBP、JPY、KRW、HKD、TWD、SGD、AUD、CAD、CHF、INR等 ## 数据来源 - **open.er-api.com** — 免费汇率API，无需注册，无需Key - 数据更新：每日多次自动更新 - 覆盖范围：150+全球主流货币 ## 触发词 > "100美元换多少人民币" / "今日汇率" / "美元兑日元" / "1万港币值多少人民币" / "EUR to USD" / "exchange rate" / "汇率换算" / "人民币贬值了吗" / "1000块能换多少美元" / "历史汇率" ## 使用示例 ### 货币换算 **输入：** 100 USD → CNY **输出：** ```json { "from": "USD", "to": "CNY", "amount": 100, "rate": 6.841274, "result": 684.13, "timestamp": "Mon, 27 Apr 2026", "provider": "open.er-api.com" } ``` ### 多货币横向对比 **输入：** 1000 USD 换所有主流货币 **输出：** ```json { "from": "USD", "amount": 1000, "conversions": [ {"currency": "CNY", "amount": 6841.27}, {"currency": "EUR", "amount": 854.23}, {"currency": "GBP", "amount": 740.22}, {"currency": "JPY", "amount": 159540.6}, ... ] } ``` ### 历史汇率 **输入：** 100 USD → CNY，2024-01-01 **输出：** 当天的美元兑人民币汇率（可用于对比汇率变化） ## 技术实现 ```bash # 单币种换算 python3 scripts/currency.py convert <金额> <源货币> <目标货币> # 汇率列表 python3 scripts/currency.py rates <基准货币> # 多货币横向对比 python3 scripts/currency.py top <金额> <源货币> # 历史汇率 python3 scripts/currency.py historical <金额> <源货币> <目标货币> <日期YYYY-MM-DD> ``` ## 支持货币（部分） | 货币代码 | 名称 | |---------|------| | CNY | 人民币 | | USD | 美元 | | EUR | 欧元 | | GBP | 英镑 | | JPY | 日元 | | KRW | 韩元 | | HKD | 港币 | | TWD | 新台币 | | SGD | 新加坡元 | | AUD | 澳元 | | CAD | 加元 | | CHF | 瑞士法郎 | | INR | 印度卢比 | | THB | 泰铢 | | MYR | 林吉特 | | PHP | 菲律宾比索 | | VND | 越南盾 | | IDR | 印尼盾 | | AED | 阿联酋迪拉姆 | | SAR | 沙特里亚尔 | ## 常见场景 | 场景 | 命令 | |------|------| | 海淘价格换算 | `convert 100 USD CNY` | | 出国前准备 | `top 10000 CNY` | | 汇率对比 | `rates USD` | | 保值分析 | `historical 1000 USD CNY 2024-01-01` | ## 更新日志 ### v1.0.0 (2026-04) - 首发版本 - 150+货币实时汇率 - 零API Key，免费数据源 - 支持历史汇率查询 ## ⚠️ Disclaimer This tool is provided "as is" for informational purposes only. Data accuracy is not guaranteed. Not financial, legal, or professional advice. Always verify critical information from official sources. 本工具仅供信息参考，不保证数据完全准确，不构成任何金融/法律/专业建议。请以官方来源为准。

path: scripts/currency.py
content: #!/usr/bin/env python3
"""
Currency Converter Pro
Author: Lin Hui
Real-time exchange rates with multi-currency support.
Uses open.er-api.com (free, no API key required).
"""

import sys
import json
import subprocess
import urllib.request
import urllib.error

API_BASE = "https://open.er-api.com/v6"


def fetch_rates(base="USD"):
    """Fetch latest exchange rates from open.er-api.com"""
    url = f"{API_BASE}/latest/{base}"
    try:
        req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
        with urllib.request.urlopen(req, timeout=10) as resp:
            data = json.loads(resp.read().decode())
        if data.get("result") == "success":
            return data
        else:
            return {"error": "API error: " + str(data)}
    except urllib.error.URLError as e:
        return {"error": "Network error: " + str(e)}
    except Exception as e:
        return {"error": str(e)}


def fetch_historical(base, date_str):
    """Fetch historical exchange rates (date format: YYYY-MM-DD)"""
    url = f"{API_BASE}/historical/{date_str}?base={base}"
    try:
        req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
        with urllib.request.urlopen(req, timeout=10) as resp:
            return json.loads(resp.read().decode())
    except Exception as e:
        return {"error": str(e)}


def cmd_convert(args):
    """Convert amount from one currency to another"""
    # args: [amount, from_currency, to_currency]
    if len(args) < 3:
        print(json.dumps({"error": "Usage: convert <amount> <from_currency> <to_currency>"}))
        return
    try:
        amount = float(args[0])
        from_curr = args[1].upper()
        to_curr = args[2].upper()
    except ValueError:
        print(json.dumps({"error": "Invalid amount"}))
        return

    data = fetch_rates(from_curr)
    if "error" in data:
        print(json.dumps(data))
        return

    rates = data.get("rates", {})
    if to_curr not in rates:
        print(json.dumps({"error": f"Currency {to_curr} not found in rates"}))
        return

    rate = rates[to_curr]
    converted = amount * rate
    print(json.dumps({
        "from": from_curr,
        "to": to_curr,
        "amount": amount,
        "rate": round(rate, 6),
        "result": round(converted, 2),
        "timestamp": data.get("time_last_update_utc", ""),
        "provider": "open.er-api.com"
    }, ensure_ascii=False, indent=2))


def cmd_rates(args):
    """Show all rates for a base currency"""
    base = args[0].upper() if args else "USD"
    data = fetch_rates(base)
    if "error" in data:
        print(json.dumps(data))
        return

    rates = data.get("rates", {})
    sorted_rates = dict(sorted(rates.items()))

    # Format nicely
    print(json.dumps({
        "base": base,
        "timestamp": data.get("time_last_update_utc", ""),
        "rates": sorted_rates
    }, ensure_ascii=False, indent=2))


def cmd_top(args):
    """Show top currencies by conversion value"""
    if len(args) < 2:
        print(json.dumps({"error": "Usage: top <amount> <from_currency>"}))
        return
    try:
        amount = float(args[0])
        from_curr = args[1].upper()
    except ValueError:
        print(json.dumps({"error": "Invalid amount"}))
        return

    data = fetch_rates(from_curr)
    if "error" in data:
        print(json.dumps(data))
        return

    rates = data.get("rates", {})
    # Common currencies to show
    common = ["CNY", "HKD", "TWD", "JPY", "KRW", "EUR", "GBP", "SGD", "AUD", "CAD",
              "CHF", "JPY", "INR", "THB", "MYR", "PHP", "VND", "IDR", "AED", "SAR",
              "USD"]
    converted = []
    for curr in common:
        if curr in rates:
            converted.append((curr, round(amount * rates[curr], 2)))

    print(json.dumps({
        "from": from_curr,
        "amount": amount,
        "conversions": [{"currency": c, "amount": a} for c, a in converted]
    }, ensure_ascii=False, indent=2))


def cmd_historical(args):
    """Show historical rate between two currencies on a specific date"""
    if len(args) < 3:
        print(json.dumps({"error": "Usage: historical <amount> <from_currency> <to_currency> <date(YYYY-MM-DD)>"}))
        return
    try:
        amount = float(args[0])
        from_curr = args[1].upper()
        to_curr = args[2].upper()
        date_str = args[3] if len(args) > 3 else "2024-01-01"
    except ValueError:
        print(json.dumps({"error": "Invalid amount"}))
        return

    data = fetch_historical(from_curr, date_str)
    if "error" in data:
        print(json.dumps(data))
        return

    rates = data.get("rates", {})
    if to_curr not in rates:
        print(json.dumps({"error": f"Currency {to_curr} not found"}))
        return

    rate = rates[to_curr]
    converted = amount * rate
    print(json.dumps({
        "from": from_curr,
        "to": to_curr,
        "amount": amount,
        "date": date_str,
        "rate": round(rate, 6),
        "result": round(converted, 2),
        "timestamp": data.get("time_last_update_utc", "")
    }, ensure_ascii=False, indent=2))


def main():
    if len(sys.argv) < 2:
        print("Usage: currency.py <command> [args...]")
        print("Commands: convert, rates, top, historical")
        sys.exit(1)

    cmd = sys.argv[1]
    args = sys.argv[2:]

    if cmd == "convert":
        cmd_convert(args)
    elif cmd == "rates":
        cmd_rates(args)
    elif cmd == "top":
        cmd_top(args)
    elif cmd == "historical":
        cmd_historical(args)
    else:
        print(f"Unknown command: {cmd}")


if __name__ == "__main__":
    main()


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)