银行汇率查询:企业汇率看板的落库与走势实现

约 11 分钟 进阶银行汇率查询汇率看板历史走势定时拉取
# 银行汇率查询:企业汇率看板的落库与走势实现 接口:银行汇率查询(apiCode=105)· 接入点:币种列表 / 汇率查询 / 历史汇率 · 免费接口(L0 基础版 100 次/天、1 QPS)· 适用人群:财务、企业 IT、数据团队 · 阅读时间:约 7 分钟 · 最后实测核对:2026-09-18 ## 核心要点 - 看板由三块拼成:货币下拉框取币种列表,当下牌价取汇率查询,走势线取历史汇率。 - 架构上采用「后端定时拉取 + 落库 + 前端只读自己的库」,前端不直连接口,调用量可控。 - 实时与历史两套字段名不同、口径也不同,落库时先映射到统一列再给前端。 ## 从一张需求清单说起 财务提的需求通常是这样的:打开页面能看到今天主流货币的牌价,选中一个货币能拉出近几个月的走势,数据要能导出给审计。这三个需求对应三种取数方式,如果让前端每个标签都直连接口,页面一多调用量就失控,而且当日数据还容易和历史数据对不上。 把取数收到后端,前端只读自己库里的表,问题就变成两个纯工程问题:多久拉一次、字段怎么对齐。 ## 看板的三块拼图 | 模块 | 使用的接入点 | 路径 | 职责 | |------|--------------|------|------| | 货币选择 | 外汇牌价币种列表 | `105-35` | 渲染看板的货币下拉框 | | 当前牌价 | 汇率查询 | `105-30` | 提供当日牌价表 | | 历史走势 | 查询历史汇率 | `105-34` | 提供逐日历史点,用于画线 | | 调度 | 由你的定时任务实现 | — | 按固定间隔拉取并落库 | ## 后端定时拉取与落库 ```python import time import requests import pymysql APPKEY = "YOUR_APPKEY" BASE = "https://route.showapi.com" def fetch_all_rates(): """105-30 不传 code,一次拿到全部货币的牌价。""" js = requests.post(f"{BASE}/105-30", params={"appKey": APPKEY}, data={}, timeout=15).json() if js.get("showapi_res_code") != 0 or js["showapi_res_body"].get("ret_code") != 0: raise RuntimeError(f"取牌价失败:{js}") return js["showapi_res_body"] def save_snapshot(body, conn): rows = body.get("list") or [] if not rows: return 0 # 同一批返回共用同一个 day / time,整体作为一次快照写入 day, ts = rows[0]["day"], rows[0]["time"] with conn.cursor() as cur: cur.executemany( """INSERT INTO fx_rate_snapshot (snapshot_day, snapshot_time, code, name, hui_in, chao_in, hui_out, chao_out, zhesuan, fetched_at) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,NOW()) ON DUPLICATE KEY UPDATE fetched_at = NOW()""", [(day, ts, r["code"], r["name"], r["hui_in"] or None, r["chao_in"] or None, r["hui_out"] or None, r["chao_out"] or None, r["zhesuan"] or None) for r in rows] ) conn.commit() return len(rows) if __name__ == "__main__": conn = pymysql.connect(host="localhost", user="app", password="***", database="fx") while True: n = save_snapshot(fetch_all_rates(), conn) print(f"{time.strftime('%H:%M:%S')} 写入 {n} 条牌价") time.sleep(300) # 5 分钟一次;牌价为延迟数据,分钟级间隔足够 ``` 空字符串要转成 `NULL` 再入库,否则 `DECIMAL` 列会写入失败。落库用 `ON DUPLICATE KEY UPDATE` 是为了让同一天同一时间戳重复拉取时不产生重复行。 ## 历史走势的取数与分段 画走势线只用到历史接入点的两个字段:`publish_time` 与 `middle_rate`。 ```python def fetch_history(code: str, month: str): """按月份取一个整月的逐日牌价。""" js = requests.post( f"{BASE}/105-34", params={"appKey": APPKEY}, data={"code": code, "month": month}, timeout=15 ).json() body = js.get("showapi_res_body") or {} if js.get("showapi_res_code") != 0 or body.get("ret_code") != 0: raise RuntimeError(f"取历史牌价失败:{body.get('remark')}") # 接口按 publish_time 倒序返回,先排成时间正序再交给图表 return sorted(body["list"], key=lambda r: r["publish_time"]) ``` 按区间取数时有个行为需要记住。2026-09-18 实测:`startDate=20260101&endDate=20260401`(91 天)返回 90 条,日期为 2026-01-01 到 2026-03-31;而 `startDate=20260101&endDate=20260901`(244 天)同样只返回 90 条,日期落在 2026-02-13 到 2026-05-13,与请求的 `startDate` 起点并不一致,复测两次结果相同。接口在这两种情况下 `ret_code` 都是 0、`remark` 都是「查询成功!」。 所以跨季度取数时按 90 天为单位分段请求,每段落库后以 `list` 首尾的 `publish_time` 作为该段的真实区间。 ## 两套字段名的统一映射 实时接入点与历史接入点的字段名不同,落库或写接口时先映射,前端只认一套列名。 | 统一列名 | 汇率查询(105-30) | 查询历史汇率(105-34) | |----------|--------------------|------------------------| | `rate_in_spot` | `hui_in` | `buying_rate` | | `rate_in_cash` | `chao_in` | `cash_buying_rate` | | `rate_out_spot` | `hui_out` | `selling_rate` | | `rate_out_cash` | `chao_out` | `cash_selling_rate` | | `rate_base` | `zhesuan` | `middle_rate` | | `rate_at` | `day` + `time` | `publish_time` | | 口径 | 货币简码 | 100 外币兑人民币 | 口径也要一起对齐。历史接入点按「100 外币兑人民币」返回,实时接入点没有这层声明,两者混在同一张走势图上时,先按同一个口径归一化再画。 ## 前端只看自己的库 看板页面读的是你落库的表和一个只读接口。这样做的好处是页面响应不受外部接口影响,外部接口异常时看板还能用上一次成功的数据。调用量也集中在后端定时任务里,数量可预期。 ## FAQ **Q1:前端能直接调接口吗?** 技术上可以,接口支持浏览器端调用。企业看板更建议走后端拉取 + 落库 + 前端只读,调用量集中可控,页面体验也更稳定。 **Q2:为什么历史走势里没有今天的数据?** 历史接入点返回的是已发布的历史牌价。当日走势用汇率查询(105-30)定时落库的点来拼,不要指望历史接入点提供当天数据。 **Q3:实时和历史字段对不上怎么办?** 两者字段名与口径都不同,落库时按统一列名映射即可,参考上一节的对照表。 **Q4:拉取频率设成多少合适?** 牌价是延迟数据,分钟级间隔已经足够,例如 5 分钟一次。间隔越短占用档位额度越多,L0 档位每天 100 次,需要按 100 次的总量反推间隔。 **Q5:看板上要不要加免责说明?** 要。数据为延迟数据、仅供参考,实际交易汇率以当地银行为准。 ## 下一步阅读 - [银行汇率查询:L0 档位每天 100 次,缓存该缓存什么](https://www.showapi.com/guides/exchange-rate-cache-105):拉取频率与缓存键的设计依据。 - [银行汇率查询:跨境电商与留学缴费的多币种牌价管理](https://www.showapi.com/guides/exchange-rate-crossborder-105):落库表结构与换算流水的完整设计。 - [银行汇率查询历史汇率:按月取还是按区间取](https://www.showapi.com/guides/exchange-rate-history-guide-105):区间参数与 90 天分段的具体行为。 - **本系列共 13 篇**:查看[银行汇率查询指南总目录](https://www.showapi.com/guides/exchange-rate-guides-105)
加载中...