feat: show rate freshness and card network spread

This commit is contained in:
2026-09-15 07:59:50 +08:00
parent d2697221d1
commit 2834f765a9
+70 -9
View File
@@ -4,10 +4,11 @@ import os
import re
import subprocess
import sys
from datetime import datetime, timezone
from datetime import datetime, timezone, timedelta
import requests
CACHE = "/root/.openclaw/workspace/fx_realtime.json"
REPORT_TZ = timezone(timedelta(hours=8))
FETCH = "/root/.openclaw/workspace/web_tasks/fx_fetch_real.js"
PAIRS = {"USD/CNY", "EUR/CNY", "SGD/CNY", "GBP/CNY", "USD/EUR", "GBP/EUR"}
PAT = re.compile(r'\[\[(20\d{2}),(\d{1,2}),(\d{1,2}),(\d{1,2}),(\d{1,2}),null,null,\[\]\],\[([0-9]+\.[0-9]+),')
@@ -63,23 +64,83 @@ def network_rates(raw, base, quote):
try: yield "Mastercard", 1/float(data["data"]["data"]["conversionRate"]), data["data"]["data"].get("fxDate", "")
except Exception: pass
def parse_date(value):
if not value:
return None
for fmt in ("%Y-%m-%d", "%m/%d/%Y", "%Y/%m/%d"):
try:
return datetime.strptime(value[:10], fmt).date()
except ValueError:
continue
return None
def age_label(date_text):
d = parse_date(date_text)
if not d:
return ""
days = (datetime.now(REPORT_TZ).date() - d).days
if days <= 0:
return "🟢 最新"
if days == 1:
return "🟢 1天前"
if days <= 3:
return f"🟠 {days}天前"
return f"🔴 {days}天前"
def fmt_date(date_text):
d = parse_date(date_text)
return d.isoformat() if d else (date_text or "未知日期")
def main():
if len(sys.argv) != 4: raise SystemExit("usage: rate_query.py AMOUNT BASE QUOTE")
amount = float(sys.argv[1]); base = sys.argv[2].upper(); quote = sys.argv[3].upper()
g, gt = google_rate(base, quote)
raw = ensure_real() if f"{base}/{quote}" in PAIRS or f"{quote}/{base}" in PAIRS else None
lines = [f"💱 {amount:g} {base} → {quote}", ""]
rates = []
if g is not None:
lines += [f"Google 1 {base} = {g:.6f} {quote}", f" {amount:g} {base} = {amount*g:.2f} {quote}"]
else: lines.append("Google 暂时无法获取")
seen = set()
lines += ["市场参考", f"Google 1 {base} = {g:.6f} {quote}", f" {amount:g} {base} = {amount*g:.2f} {quote}"]
rates.append(("Google", g))
else:
lines += ["市场参考", "Google 暂时无法获取"]
network = []
if raw:
for name, rate, date in network_rates(raw, base, quote):
if name in seen: continue
seen.add(name)
lines += [f"{name:<12}1 {base} = {rate:.6f} {quote}", f" {amount:g} {base} = {amount*rate:.2f} {quote} ({date})"]
if not seen: lines.append("Visa/MC 暂无最新官方结算数据")
lines += ["", "Google 为参考市场价;Visa/万事达为官方计算器结算汇率。"]
if any(n == name for n, _, _ in network):
continue
network.append((name, rate, date))
lines += ["", "卡组织汇率"]
if network:
for name, rate, date in network:
freshness = age_label(date)
date_part = f"📅 {fmt_date(date)}"
if freshness:
date_part += f" · {freshness}"
lines += [f"{name:<12}1 {base} = {rate:.6f} {quote}", f" {amount:g} {base} = {amount*rate:.2f} {quote}", f" {date_part}"]
rates.append((name, rate))
else:
lines.append("Visa/MC 暂无最新官方结算数据")
if network and g is not None:
lines += ["", "📊 相对 Google"]
for name, rate, _ in network:
diff = (rate / g - 1.0) * 100.0
sign = "+" if diff >= 0 else ""
lines.append(f"{name:<12}{sign}{diff:.3f}%")
if len(network) >= 1:
card_rates = [r for _, r, _ in network]
lo, hi = min(card_rates), max(card_rates)
if len(card_rates) == 1:
lines += ["", f"💳 卡组织参考:{amount*lo:.2f} {quote}"]
else:
lines += ["", f"💳 卡组织参考区间:{amount*lo:.2f}–{amount*hi:.2f} {quote}"]
stale = [(n, d) for n, _, d in network if parse_date(d) and (datetime.now(timezone.utc).date() - parse_date(d)).days >= 2]
if stale:
lines += ["", "⚠️ " + ";".join(f"{n} 数据距今天 {(datetime.now(REPORT_TZ).date()-parse_date(d)).days} 天" for n, d in stale) + ",不要将其视为当前实时市场价。"]
lines += ["", "Google 为当前市场参考价;Visa/万事达为官方卡组织结算汇率。实际扣款还可能受发卡行费用、入账时间等影响。"]
print("\n".join(lines))
if __name__ == "__main__":