返回博客

如何在 Excel 中获取实时汇率:Power Query、WEBSERVICE 与货币 API

V
Vlado Grigirov
August 18, 2026
Currency API Exchange Rates Excel Power Query Tutorial Finexly

每一篇讲在 Excel 中获取实时汇率的教程都承诺同一件事,然后悄悄给你另一样东西。你照着步骤操作,单元格里出现了一个数字,看上去是实时的。通常并不是。它可能是一天只发布一次的参考汇率,可能是延迟报价,也可能是从网页抓取来的 HTML 表格——下次刷新时,它会不声不响地返回错误的货币。

本指南覆盖四种真正可用的方法——Excel 内置的货币数据类型、WEBSERVICE 函数、Power Query,以及可复用的 LAMBDA——更重要的是,它会告诉你哪一种能在你的 Excel 版本里跑起来、每一种的数据到底有多新,以及每一种会在什么地方给出错误却不报错的数字。

下面的每一条公式、每一个查询,都是针对 Finexly API 文档中记录的响应结构编写的,并在发布前验证过正确性。

四种方法,以及你实际能用哪一种

Excel 的货币功能对版本的依赖程度异常高。关于这个话题的教程有一半推荐的方法,在读者的机器上根本不存在。请从这里开始。

方法可运行环境实际更新频率能否安全传送 API 密钥?最适合
货币数据类型Microsoft 365(Windows 与 Mac)、Excel 网页版。不支持 2016/2019/2021/2024延迟,未公布刷新间隔;手动刷新或打开时刷新不适用 —— 不涉及 API快速查一下,少量几个货币对
WEBSERVICE仅限 Windows 桌面版:M365、2024、2021、2019、2016。不支持 Mac、网页版和移动端取决于你的 API 返回什么 —— 但这个函数是易失性的❌ 不能。密钥必须放进 URL一两个单元格,快速原型
Power QueryWindows 上的 Excel 2016 及以上。Mac 版 M365 有 Power Query,但没有 Web 连接器取决于你的 API 返回什么,刷新时更新✅ 可以,通过 M 中的 Headers汇率表、批量换算、生产环境
LAMBDA 封装Windows 上的 Excel 2021+/M365(继承 WEBSERVICE 的限制)WEBSERVICE 相同❌ 不能给表格使用者一个干净的 =FXRATE()
从这张表可以直接推出两个结论:

  1. 如果你用的是 Mac,Power Query 的 Web 连接器不会出现在可用数据源里,而 WEBSERVICE 则完全无法工作。 微软对此说得很明确:WEBSERVICE"可能会出现在 Excel for Mac 的函数库中,但它依赖 Windows 操作系统的功能,因此在 Mac 上不会返回结果"。现实地讲,使用 Microsoft 365 的 Mac 用户只能用货币数据类型。
  2. 如果你用的是永久授权版的 Excel 2019、2021 或 2024,货币数据类型对你不可用 —— 链接数据类型仅限 Microsoft 365 和 Excel 网页版。你的出路是 WEBSERVICE 或 Power Query。

方法一:Excel 内置的货币数据类型

这是零代码的方案,也是大多数文章开篇就讲的那一种。

  1. 在一列中输入货币对,使用 ISO 4217 代码,中间用斜杠或冒号分隔——USD/EURGBP:JPY。(如果你不确定该用哪个代码,我们的 ISO 4217 代码参考列出了全部代码。)
  2. 选中这些单元格,然后依次点击 数据 → 数据类型 → 货币
  3. 每个单元格都会变成带有小货币图标的链接记录。点击该图标,或使用插入数据按钮,选择价格,把汇率溢出到相邻单元格。
  4. 数据 → 全部刷新 来刷新。

微软实际承诺了什么

这是教程们跳过的部分。微软自己的文档在货币页面上带有一条警告:"货币信息按'原样'提供,可能存在延迟。因此,这些数据不应用于交易目的或作为投资建议。" 货币对没有任何已公布的刷新间隔。 底层金融数据来自 LSEG Data & Analytics(原 Refinitiv),通过 Bing 呈现。

如果你要做的是真正上线的东西,还有三条限制值得注意:

  • 可用性按租户划分。 微软说明"货币对仅对 Microsoft 365 账户(全球多租户客户)可用"。如果你所在的组织使用的是主权云或政府云,货币按钮会是灰色的,再怎么排查也改不了。
  • 没有服务端刷新。 链接数据类型只有在工作簿于 Excel 中打开时才会刷新。五分钟自动刷新的选项确实存在,但目前仅限 Insiders 计划,而且微软指出"某些链接数据类型只能手动刷新"。
  • 货币对是个黑箱。 你只拿到一个数字。你看不到时间戳、数据来源,也看不到点差。做开票或做报表,你需要的是带日期、可审计的汇率——那是完全不同的另一个问题

用这个方法随手看一眼汇率可以。不要把它当成任何日后需要你解释和辩护的数据的输入。

方法二:WEBSERVICE 加上一个货币 API

WEBSERVICE(url) 执行一次 HTTP GET,并把响应正文以文本形式返回。它只接受一个参数——一个 URL。这一个事实决定了这个方法的其他一切。

为什么你的 API 密钥不得不放进 URL

因为 WEBSERVICE 没有请求头参数,你无法发送 Authorization: Bearer …。任何要从 WEBSERVICE 调用的 API,都必须接受把密钥作为查询参数传入。Finexly 两种方式都支持:

# Recommended everywhere else — but impossible from WEBSERVICE
curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://api.finexly.com/v1/rate?from=USD&to=EUR"

# The query-parameter form, which is what WEBSERVICE needs
https://api.finexly.com/v1/rate?from=USD&to=EUR&api_key=YOUR_API_KEY

对这个取舍要诚实。放在 URL 里的密钥会被写进服务器访问日志,也可能通过 HTTP referrer 请求头泄露;而且密钥是以明文形式存在工作簿里的——你把文件邮件发给谁,谁就拿到了你的密钥。给表格单独准备一把低配额的密钥,绝不要把含有生产密钥的 WEBSERVICE 工作簿分发出去。

一条能用的公式

把 URL 放进 A1,把原始响应放进 A2

A1:  ="https://api.finexly.com/v1/rate?from="&B1&"&to="&C1&"&api_key="&$D$1
A2:  =WEBSERVICE(A1)

现在 A2 里是响应的原始文本:

{"pair":"USD_EUR","rate":0.9215}

接下来提取数字。几乎所有同类教程都是按位置来取的——INDEX(TEXTSPLIT(...), 1, 6)——只要 API 加了一个字段,或者你换了 endpoint,这种写法就会悄无声息地失效。改成锚定键名:

=LET(
   raw,  A2,
   p,    FIND("""rate"":", raw) + 7,
   e,    MIN(IFERROR(FIND(",", raw, p), 9999), IFERROR(FIND("}", raw, p), 9999)),
   IFERROR(VALUE(MID(raw, p, e - p)), NA())
 )

它会找到字面量 "rate":,跳过这七个字符,然后一直读到逗号或右花括号中先出现的那一个为止。无论是 /v1/rate 的双字段响应,还是 /v1/convert-amount 的四字段响应,它都返回 0.9215;调用失败时它返回 #N/A,而不是一个错误的数字。LET 需要 Excel 2021 或 Microsoft 365;在 Excel 2016/2019 上,你可以把同样的 FIND 调用内联展开,代价是可读性。

易失性陷阱

WEBSERVICE 是易失性函数。基本上工作表一有改动它就重算,而不只是在你按 F9 时才算。做一个 40 行的换算器,每行一个 WEBSERVICE,那么敲一下键盘就会触发 40 个 HTTP 请求。

按每月 1,000 次请求的免费额度算,大约敲 25 下键盘配额就用完了。两种防御手段:把 WEBSERVICE 限制在单个单元格里,其他地方一律引用那个单元格;或者在搭建期间把计算方式切换为手动(公式 → 计算选项 → 手动)。更好的做法是改用 Power Query,它不是易失性的。

方法三:Power Query —— 唯一能扩展的那一个

Power Query 是这里唯一能发送 Authorization 请求头、能按计划刷新、能扛住五万行表格而不崩的方法。它同时也是所有教程都只用图形界面点击来演示的方法,因此真正的 M 代码在网上根本找不到。这里给你。

依次打开 数据 → 获取数据 → 启动 Power Query 编辑器,然后 新建源 → 空查询,再 主页 → 高级编辑器,粘贴:

let
    ApiKey = "YOUR_API_KEY",
    Pairs  = "USD_EUR,USD_GBP,USD_JPY,USD_CHF",
    Source = Json.Document(
        Web.Contents(
            "https://api.finexly.com",
            [
                RelativePath = "v1/convert",
                Query        = [ q = Pairs ],
                Headers      = [ #"Authorization" = "Bearer " & ApiKey ]
            ]
        )
    ),
    ToTable  = Record.ToTable(Source),
    Expanded = Table.ExpandRecordColumn(ToTable, "Value", {"rate"}, {"rate"}),
    Split    = Table.SplitColumn(
                   Expanded, "Name",
                   Splitter.SplitTextByDelimiter("_", QuoteStyle.None),
                   {"Base", "Quote"}
               ),
    Typed    = Table.TransformColumnTypes(
                   Split,
                   {{"Base", type text}, {"Quote", type text}, {"rate", type number}}
               )
in
    Typed

把它命名为 FxRates 并加载到工作表。你会得到一张干净的三列表:BaseQuoterate

这个查询里有三个细节在真正起作用,而这三点在所有图形界面教程中都是缺失的:

  • Headers 让密钥不出现在 URL 里。 这是 Power Query 相对 WEBSERVICE 最大的安全优势。
  • RelativePathQuery 是有意从基础 URL 中拆出来的。 如果你把整个 URL 拼成一个字符串,Power Query 会把它归类为动态数据源,而动态数据源在 Power BI 服务中无法无人值守刷新。把路径和查询参数分开传,数据源就保持为静态且可刷新。
  • 一次请求,多个货币对。 /v1/convert 会在一次调用中返回你要的所有货币对。一个工作簿在每天八小时内每小时刷新一次、跨 22 个工作日,用这种方式每月发出 176 次请求。同样频率下,三十个独立的 /v1/rate 调用会发出 5,280 次——是免费月度额度的五倍,数据却完全一样。

一个可复用的汇率函数

如果只需要按需查询单个货币对,把它封装成一个 M 函数:

let
    FxRate = (baseCode as text, quoteCode as text) as number =>
        let
            ApiKey = "YOUR_API_KEY",
            Source = Json.Document(
                Web.Contents(
                    "https://api.finexly.com",
                    [
                        RelativePath = "v1/rate",
                        Query        = [ from = baseCode, to = quoteCode ],
                        Headers      = [ #"Authorization" = "Bearer " & ApiKey ]
                    ]
                )
            )
        in
            Source[rate]
in
    FxRate

在任何其他查询里用 FxRate("USD", "EUR") 调用它。

换算 50,000 行,而不做 50,000 次查找

在大表上往下拖 XLOOKUP 既慢又脆弱——而且如果查询输出在刷新后尺寸变了,F:F 这类整列引用会悄悄错位。请改在 Power Query 内部做联接:

  1. 把你的交易表加载进 Power Query。
  2. 主页 → 合并查询,用你的 Currency 列匹配 FxRates[Quote]
  3. 展开合并出来的列,只保留 rate
  4. 添加列 → 自定义列 写换算公式。

这样整张表只做一次联接,每次刷新只求值一次,整个工作簿里没有任何易失性公式。

方法四:可复用的 =FXRATE() LAMBDA

如果使用这个工作簿的人是表格用户而不是查询作者,就把上面这些全部藏到一个函数背后。打开 公式 → 名称管理器 → 新建,命名为 FXRATE,并把引用位置设为:

=LAMBDA(from_code, to_code, key,
   LET(
     url,  "https://api.finexly.com/v1/rate?from=" & from_code &
           "&to=" & to_code & "&api_key=" & key,
     raw,  WEBSERVICE(url),
     p,    FIND("""rate"":", raw) + 7,
     e,    MIN(IFERROR(FIND(",", raw, p), 9999), IFERROR(FIND("}", raw, p), 9999)),
     IFERROR(VALUE(MID(raw, p, e - p)), NA())
   )
 )

现在任何人都可以写 =FXRATE("USD","EUR",$D$1) 拿到 0.9215。把密钥在 D1 里存一次,保护该单元格,工作簿的其余部分就再也不会碰到它。注意,它继承了 WEBSERVICE 的全部限制——仅限 Windows、易失性、密钥在 URL 里——所以这是易用性上的胜利,不是安全性或可扩展性上的胜利。

Excel 货币换算悄悄出错的五种方式

这些是正确性缺陷,而不是错误提示。没有任何东西会变红。数字只是单纯地不是你以为的那个值。

1. 该除的时候却乘了

这是已发布的 Excel 货币教程中最常见的错误,值得把它造成的损害说清楚。USD_EUR 汇率 0.9215 是把 USD 换算成 EUR。反过来——EUR 换成 USD——要用除法。

  • 正确:100 / 0.9215 = 108.52 USD
  • 错误:100 × 0.9215 = 92.15 USD

结果偏离的幅度是汇率的平方,0.9215² = 0.8492——低估 15.1%,而这个数在报表上看起来完全合理。把方向写进列标题(写 USD→EUR rate,而不是 Rate),这个错误就很难再犯。

2. 按位置解析 JSON

INDEX(TEXTSPLIT(response, ":", "}"), 1, 6) 一直好用,直到 API 加了一个字段——从那一刻起,索引 6 会返回另一个值,而且不报任何错。请像上面的 LET 公式那样锚定键名,或者使用 Power Query 的 Json.Document,它会做真正的解析。

3. 把所有金额都四舍五入到两位小数

Excel 默认两位小数;ISO 4217 可不是这样。JPY、KRW 和 VND 没有辅币单位——¥250.75 不是一个合法金额。BHD、KWD、OMR 和 TND 有三位小数。 把 JPY 合计先舍入到两位小数,下游再舍入一次,对账结果就是这样差出几个单位的。完整的规则我们在货币舍入与小数位数指南中做了介绍。

4. 把中间价当成你实际会被收取的汇率

本文中的每一个汇率——以及所有免费 API 给出的汇率——都是中间价:买价与卖价的中点。它不是你的银行、卡组织或支付服务商给你的价格。真实点差大约从 0.5% 到百分之几不等。如果你在给商品定价或给客户报价,请加一个显式的加价列,而不是假装中间价就是结算汇率。我们关于汇率 API 的数据从哪里来的解读,讲清楚了这些数据源代表什么、不代表什么。

5. 让实时工作簿改写上个月的数字

这一条后果严重,却几乎没人提。如果你的汇率单元格是实时刷新的,那么每当有人打开文件,工作簿里每一行历史数据都会按今天的汇率重估一遍。三月的收入到了四月就变了。你的对账永远不会两次对上同一个数。

一笔交易一旦发生,它的汇率就是关于那个日期的事实,而不是一个实时值。把它冻结住:换算一次,把结果连同所用的汇率和日期一起粘贴为数值,实时查询只留给新增的行。多币种开票费用管理系统在数据库层面执行的,正是同一套纪律。

补充:交叉汇率

如果你的 API 全部以单一基准货币返回数据,那么把 EUR→GBP 换算出来就意味着用一个汇率除以另一个:

EUR→GBP  =  USD_GBP / USD_EUR  =  0.7892 / 0.9215  =  0.856430
1,000 EUR  =  856.43 GBP

只在最后一步舍入。把中间的交叉汇率先舍入到四位小数再相乘,会引入在大表中不断累积的误差。更多细节见我们的交叉汇率指南。

自动刷新、速率限制,以及如何留在免费额度内

要让 Power Query 汇率表自己更新:在 查询和连接 → 属性 中右键点击该查询,然后勾选打开文件时刷新数据和/或每隔 N 分钟刷新一次

有两件事没人会提醒你:

  • 打开时刷新会触发 Excel 的外部数据安全提示。 用户会看到一条黄色横幅,在他们点击"启用"之前,那个"自动"刷新什么也不做。把文件夹添加到 信任中心 → 受信任位置 可以避免这个问题。
  • 对一天只发布一次的汇率每 15 分钟刷新一次,纯属浪费。 让刷新间隔匹配数据源真正变化的频率。对大多数开票和报表工作来说,打开时刷新一次就足够了。

用 Finexly 返回的响应头监控你的消耗量——X-RateLimit-LimitX-RateLimit-UsedX-RateLimit-Units。免费方案提供每月 1,000 次请求,无需信用卡,对于打开时刷新一次的工作簿相当宽裕,对于易失性的 WEBSERVICE 网格则相当吃紧。如果你总是逼近上限,解决办法几乎总是把请求合并到 /v1/convert,而不是升级到付费方案。我们的缓存与错误处理指南在 Excel 之外讲的是同样的原则。

疑难排查

症状原因解决办法
WEBSERVICE 返回 #VALUE!协议不受支持、URL 超过 2,048 个字符,或响应超过单元格 32,767 字符的上限使用 https,缩短查询串,每次调用少请求几个货币对
WEBSERVICE 在 Mac 上什么也不返回Windows 桌面版之外不受支持改用货币数据类型,或把工作簿挪到 Windows 上
货币按钮是灰色的不是 Microsoft 365,或账户不属于多租户检查你的授权;永久授权版 Excel 没有链接数据类型
#BUSY!#CONNECT!链接数据类型仍在解析中,或没有网络连接等一会儿,然后 数据 → 全部刷新
Power Query 刷新时报"动态数据源"整个 URL 被拼成了一个字符串按上文所示拆成 RelativePathQuery
刷新后出现 #N/A响应中没有该货币代码,或查找区域发生了偏移IFNA 包一层,并使用结构化表引用代替 F:F
401 UNAUTHORIZED密钥缺失、格式不对,或在需要查询参数的地方以请求头方式发送确认该方法支持哪种认证方式

常见问题

Excel 能获取真正实时的汇率吗? 不能做到真正的实时。货币数据类型的文档明确写明是延迟的,且没有公布刷新间隔;而大多数免费 API 每个工作日只发布一次。你能拿到的是当前汇率——从实时数据源按需刷新的汇率,这正是货币 API 提供的东西。要做真正的逐笔级 FX,你需要的是流式数据源,而不是电子表格。

没有 API 密钥,怎么在 Excel 里获取汇率? 货币数据类型不需要密钥,但它要求 Microsoft 365,而且不给你时间戳,也没有审计追踪。凡是日后需要对账的场景,带密钥的 API 都是更好的答案——而且免费货币 API 的免费档位不要钱。

为什么 WEBSERVICE 在 Excel for Mac 里不起作用? 微软的文档指出,WEBSERVICE 依赖 Windows 操作系统的功能,因此即便它出现在函数库中,在 Mac 上也不会返回结果。FILTERXML 同理。Mac 用户应尽可能使用 Power Query,或者使用货币数据类型。

怎么在 Excel 里获取某个特定日期的历史汇率? 建一张汇率表,每个日期一行,数据来自历史汇率数据源,然后用 XLOOKUP 以匹配模式 -1 去查它,这样周末和节假日会回退到最近一个可用的工作日。绝不要用今天的汇率重估过去的交易。

我能用 Power Query 一次性换算整张交易表吗? 能,而且你应该这么做。把交易查询按货币代码与汇率查询合并,展开汇率列,再添加一个自定义列计算换算后的金额。一次联接就取代了数以万计的易失性公式,并且一趟刷新就能完成。

我该选哪种方法? 只有一个货币对、偶尔看一眼:货币数据类型。在 Windows 上做原型:WEBSERVICE。任何有别人依赖的东西:一律用 Power Query。


准备好把当前汇率正确地放进你的表格了吗?免费获取 Finexly API 密钥——无需信用卡。你可以获得每月 1,000 次请求、覆盖 170 多种货币,以及让 WEBSERVICE 成为可能的 api_key 查询参数,还有供 Power Query 使用的请求头认证。完整的 endpoint 说明见 API 文档;如果你还在评估方案,可以对比各家货币 API

Vlado Grigirov

Senior Currency Markets Analyst & Financial Strategist

Vlado Grigirov is a senior currency markets analyst and financial strategist with over 14 years of experience in foreign exchange markets, cross-border finance, and currency risk management. He has wo...

View full profile →