你可以通过 Narwhal API 把节假日、发布日期、经济数据、大宗商品现货价格、汇率和预测市场概率拉取到 Google 表格。用 Apps Script 把数据写入不同的标签页,再添加基于时间的触发器,就能按计划刷新。
你将完成的设置
Apps Script 通过 UrlFetchApp 把你的表格连接到 API。你会得到每个数据领域各一个标签页,以及用同一个 API 密钥填充它们的 pullAll 函数。密钥保存在脚本属性中,脚本发出请求时读取它。REST 和 MCP 在各个数据 API 中共用该密钥。基础 URL 为 https://api.narwhalapi.com,每个数据调用都使用 GET。
设置你的 API 密钥
- 创建免费密钥 获取一个免费的 Narwhal API 密钥。请保留好这个密钥,用于稍后在编辑器中添加的脚本属性;切勿把它写进表格单元格。
- 打开 Apps Script 在 Google 表格中打开“扩展程序”菜单,选择 Apps Script。你将在这里添加脚本,并设置它对密钥的访问。
- 把密钥存入脚本属性 在“项目设置”中,添加一个名为
NARWHAL_API_KEY的脚本属性,并把值设为你的密钥。脚本通过PropertiesService.getScriptProperties()读取它,并放在Authorization请求头中发送,格式为Bearer YOUR_KEY。
用 Apps Script 获取数据
- 创建数据标签页 创建名为
Holidays、Releases、CPI、Brent、FX和Fed的标签页。脚本靠这些名称找到每个响应的写入位置,所以请完全按原样命名。 - 添加脚本 把这段代码粘贴到 Apps Script 中。共用的
pull辅助函数会读取每次调用指定的响应字段,并把行写入对应的标签页。Brent 的价格不在列表里,所以直接使用响应对象。const API = "https://api.narwhalapi.com"; function pull(sheetName, path, listKey) { const key = PropertiesService.getScriptProperties().getProperty("NARWHAL_API_KEY"); const res = UrlFetchApp.fetch(API + path, { headers: { Authorization: "Bearer " + key }, }); const body = JSON.parse(res.getContentText()); const rows = listKey ? body[listKey] : [body]; if (!rows || rows.length === 0) return; // an empty list writes nothing const columns = []; rows.forEach((row) => Object.keys(row).forEach((name) => { // every row, so a null first value cannot hide a column if ( !columns.includes(name) && (row[name] === null || typeof row[name] !== "object") ) columns.push(name); }), ); const values = [columns].concat( rows.map((row) => columns.map((name) => row[name] === undefined || row[name] === null ? "" : row[name], ), ), ); const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName); sheet.clear(); // Text columns (dates, periods like 2026-09) stay plain text so Sheets does not // turn them into dates. // Decimal strings such as "1.0823" stay numbers. columns.forEach((name, index) => { const sample = rows.find( (row) => typeof row[name] === "string" && row[name] !== "", ); if (sample && !/^-?\d+(\.\d+)?$/.test(sample[name])) sheet.getRange(1, index + 1, values.length, 1).setNumberFormat("@"); }); sheet.getRange(1, 1, values.length, columns.length).setValues(values); } function pullAll() { pull("Holidays", "/v1/calendars/holidays/USA/2026", "holidays"); pull( "Releases", "/v1/economics/calendar?countries=USA&start_date=2026-11-01" + "&end_date=2026-11-30&limit=100", "releases", ); pull("CPI", "/v1/economics/USA/cpi/observations?start=2025-09", "observations"); pull("Brent", "/v1/commodities/spot/BRENT/USD", null); pull("FX", "/v1/fx/rates/USD?currencies=EUR,IDR", "rates"); pull("Fed", "/v1/predictions/policy-paths/federal-reserve", "meetings"); } - 运行 pullAll 在编辑器中运行
pullAll来填充各标签页。对于非空响应,辅助函数会先清空目标标签页,再写入标题行和其后的数据,所以请把公式放在这些标签页之外。空列表不会写入任何内容。它会从每一行中读取列名,因此第一个值为 null 也不会让某一列消失。
包含日期以及 2026-09 这类期间的文本列会保持为纯文本,这样表格就不会把它们转成日期。以字符串形式传来的小数,如 1.0823,则保持为数字。下面的调用使用同样的辅助函数、API 基础 URL 和脚本属性,各自指定目标标签页、请求路径和响应字段。
按计划定时运行
- 打开触发器 使用 Apps Script 编辑器中的时钟图标打开触发器。
- 添加基于时间的触发器 为
pullAll添加一个基于时间的触发器,例如每天运行一次。它调用的函数,与你在编辑器中填充数据标签页时调用的是同一个。
自定义函数也可以调用 URL Fetch,但每次表格重新计算时它们都会重新运行,每次都会消耗一次请求;通过菜单项或基于时间的触发器运行的函数,则只写入一次值。
在 Google 表格中查询节假日
把美国 2026 年的节假日拉取到 Holidays。响应列表是 holidays,每个条目都有 date 和 name。辅助函数把这两个字段写成列,并保持日期文本不变。如果想让假日行单独放在一个标签页,就把这个调用和共用脚本一起使用。
pull(
"Holidays", "/v1/calendars/holidays/USA/2026", "holidays"
);
// Read date and name in the Holidays tab.在 Google 表格中查询发布日期
把美国 2026 年 11 月的经济数据发布日历拉取到 Releases。从响应中读取 releases,每个条目都有 at、period、topic 和 status。这个请求针对的是发布日期;要获取各期间对应的经济数值,请使用 CPI 观测值的调用。
pull(
"Releases",
"/v1/economics/calendar?countries=USA&start_date=2026-11-01" +
"&end_date=2026-11-30&limit=100",
"releases",
);
// Read at, period, topic and status in the Releases tab.在 Google 表格中查询经济数据
把请求起点设为 2025 年 9 月,将美国 CPI 观测值拉取到 CPI。响应列表是 observations,标签页的列是 period 和 value。第一次拉取后,请查看标题行。做环比计算时,按期间文本查找每个月,这样缺了某个月也不会让公式错位。
pull(
"CPI", "/v1/economics/USA/cpi/observations?start=2025-09", "observations"
);
// Read period and value in the CPI tab.要比较 2026 年 9 月与 2026 年 8 月,请在 CPI 标签页之外使用下面的公式。每个 VLOOKUP 在 CPI!A:B 中查找指定的月份;计算是用 9 月的值除以 8 月的值,再减去 1。
=VLOOKUP("2026-09",CPI!A:B,2,FALSE)/VLOOKUP("2026-08",CPI!A:B,2,FALSE)-1在 Google 表格中查询大宗商品现货价格
把以 USD 计价的 Brent 现货价格拉取到 Brent。price 字段从响应对象中读取。这个调用给列表键传入 null,所以辅助函数把整个对象当作一行,并把各字段写在对应的列名下。
pull(
"Brent", "/v1/commodities/spot/BRENT/USD", null
);
// Read price in the Brent tab.在 Google 表格中查询汇率
把以 USD 为基础的 EUR 和 IDR 汇率拉取到 FX。rates 列表的每个条目都有 currency 和 rate。读取该标签页时,请把这两列放在一起,让每个汇率都对应着它的货币。
pull(
"FX", "/v1/fx/rates/USD?currencies=EUR,IDR", "rates"
);
// Read currency and rate in the FX tab.在 Google 表格中查询预测市场概率
把美联储政策路径拉取到 Fed。响应列表是 meetings,每个条目都有 resolves_at、p_cut、p_hold 和 p_hike。请把结算时间和概率一起读取,让降息、维持不变和加息的概率都对应着各自的会议。
pull(
"Fed", "/v1/predictions/policy-paths/federal-reserve", "meetings"
);
// Read resolves_at, p_cut, p_hold and p_hike in the Fed tab.为什么不用 IMPORTDATA 或 IMPORTXML?
IMPORTDATA 和 IMPORTXML 无法发送 Authorization 请求头。Narwhal API 请求需要 Bearer 请求头,所以要用带 UrlFetchApp 的 Apps Script 来发请求。辅助函数从脚本属性中读取密钥,并在获取响应之前加上请求头。
可以把节假日数据用于 NETWORKDAYS 吗?
可以。把 Holidays 标签页的 date 列用作 NETWORKDAYS 的假日参数。请使用该列的日期,而不是假日名称。此脚本中的假日请求提供的是美国 2026 年的假日日期。
为什么 CPI 响应的起始期间可能晚于请求的期间?
所有账户都可读取完整历史。如果序列在请求的开始日期之后才开始,响应将从其第一个观测值开始。
发布于。